Before the query feature got replaced with DragRect, ImPlot had seemed to allow the user to draw the query rect - either with QueryButton, or by using box-select with QueryToggleMod. With DragRect, it's not clear how to let the user draw the query area.
I don't really like the solution used in the ImPlot demo, where the user needs to click SelectCancel during selection in order to create a DragRect. This gesture is not very intuitive, and might even be difficult for some users. Holding a modifier key during a regular selection would be much easier IMHO.
I'm trying to mimick QueryToggleMod on the latest version of ImPlot and I can't figure out a good way to make it work. The main problem is that I cannot handle the mouse-up event before ImPlot does the same, and cancel the selection before ImPlot zooms in.
I tried to check ImGui::IsMouseReleased() on the box-selection button (at the same time checking for the modifier key). If the mouse gets released in the current frame, I save the current selection to a DragRect and call ImPlot::CancelPlotSelection() to prevent ImPlot from zooming in.
If I call ImPlot::GetPlotSelection() to retrieve the selection rect, it locks the plot setup. This in turn calls SetupFinish(), and finally goes to UpdateInput(). The latter sees that the mouse has been released, and zooms in and sets plot.Selected = false. As a result, GetPlotSelection()returns an empty rect.
As a workaround, I can use a cached selection rect saved on the previous frame - it's not perfect (because the mouse might have moved), but better than nothing. But yeah, it's only a clumsy workaround.
When I try to cancel the selection on IsMouseReleased(), ImPlot::CancelPlotSelection() follows the same pattern as ImPlot::GetPlotSelection(): it goes to UpdateInput() which handles mouse-up on its own, and commits the selection before CancelPlotSelection() gets a chance to cancel it. Basically CancelPlotSelection() doesn't work in the mouse-up frame, and there's no good solution for that.
I tried to block UpdateInput() by temporarily setting OverrideMod to my QueryToggleMod so that on the mouse-up frame, ImPlot ignores all user input. This way CancelPlotSelection() works if there's a selection rect.
This is a dirty hack rather than a workaround, and I'd prefer to avoid it.
In case of plot.Selecting == true and plot.Selected == false (which occurs when the user hasn't dragged the mouse farther than the threshold), CancelPlotSelection() thinks there's no selection and nothing to cancel. As a result, the mouse-up event is totally missed by ImPlot, and it remains in the selection mode even though the mouse button is up. More hacks could probably fix this too, but I decided to draw a line here.
IMHO, inability of CancelPlotSelection() is either a bug that needs to be fixed or, if it's the intended behavior, it should be documented in implot.h.
So what would be the recommended way to create DragRects from user input? If clicking SelectCancel is the only way, can we modify ImPlot to provide some other ways (like QueryToggleMod), or to provide some means to implement other ways on the application side?
Before the query feature got replaced with DragRect, ImPlot had seemed to allow the user to draw the query rect - either with
QueryButton
, or by using box-select withQueryToggleMod
. With DragRect, it's not clear how to let the user draw the query area.I don't really like the solution used in the ImPlot demo, where the user needs to click SelectCancel during selection in order to create a DragRect. This gesture is not very intuitive, and might even be difficult for some users. Holding a modifier key during a regular selection would be much easier IMHO.
I'm trying to mimick
QueryToggleMod
on the latest version of ImPlot and I can't figure out a good way to make it work. The main problem is that I cannot handle the mouse-up event before ImPlot does the same, and cancel the selection before ImPlot zooms in.ImGui::IsMouseReleased()
on the box-selection button (at the same time checking for the modifier key). If the mouse gets released in the current frame, I save the current selection to a DragRect and callImPlot::CancelPlotSelection()
to prevent ImPlot from zooming in.ImPlot::GetPlotSelection()
to retrieve the selection rect, it locks the plot setup. This in turn callsSetupFinish()
, and finally goes toUpdateInput()
. The latter sees that the mouse has been released, and zooms in and setsplot.Selected = false
. As a result,GetPlotSelection()
returns an empty rect.IsMouseReleased()
,ImPlot::CancelPlotSelection()
follows the same pattern asImPlot::GetPlotSelection()
: it goes toUpdateInput()
which handles mouse-up on its own, and commits the selection beforeCancelPlotSelection()
gets a chance to cancel it. BasicallyCancelPlotSelection()
doesn't work in the mouse-up frame, and there's no good solution for that.UpdateInput()
by temporarily settingOverrideMod
to myQueryToggleMod
so that on the mouse-up frame, ImPlot ignores all user input. This wayCancelPlotSelection()
works if there's a selection rect.plot.Selecting == true
andplot.Selected == false
(which occurs when the user hasn't dragged the mouse farther than the threshold),CancelPlotSelection()
thinks there's no selection and nothing to cancel. As a result, the mouse-up event is totally missed by ImPlot, and it remains in the selection mode even though the mouse button is up. More hacks could probably fix this too, but I decided to draw a line here.CancelPlotSelection()
is either a bug that needs to be fixed or, if it's the intended behavior, it should be documented in implot.h.So what would be the recommended way to create DragRects from user input? If clicking SelectCancel is the only way, can we modify ImPlot to provide some other ways (like
QueryToggleMod
), or to provide some means to implement other ways on the application side?