Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mousewheel handling / problem with widget (ImPlot) custom zoom #7235

Open
astotrzynascie opened this issue Jan 17, 2024 · 2 comments
Open

Mousewheel handling / problem with widget (ImPlot) custom zoom #7235

astotrzynascie opened this issue Jan 17, 2024 · 2 comments

Comments

@astotrzynascie
Copy link

Version/Branch of Dear ImGui:

Version 1.90.1, Branch: master

Back-ends:

imgui_impl_sdl2.cpp + imgui_impl_opengl3.cpp

Compiler, OS:

Windows 10 + MSVC 2022, VS 17.8.4

Full config/build information:

Dear ImGui 1.90.1 (19010)
--------------------------------

sizeof(size_t): 8, sizeof(ImDrawIdx): 4, sizeof(ImDrawVert): 20
define: __cplusplus=199711
define: _WIN32
define: _WIN64
define: _MSC_VER=1938
define: _MSVC_LANG=202002
--------------------------------

io.BackendPlatformName: imgui_impl_sdl2
io.BackendRendererName: imgui_impl_opengl3
io.ConfigFlags: 0x00000001
 NavEnableKeyboard
io.ConfigInputTextCursorBlink
io.ConfigWindowsResizeFromEdges
io.ConfigMemoryCompactTimer = 60.0
io.BackendFlags: 0x0000000E
 HasMouseCursors
 HasSetMousePos
 RendererHasVtxOffset
--------------------------------

io.Fonts: 50 fonts, Flags: 0x00000000, TexSize: 2048,4096
io.DisplaySize: 3072.00,1728.00
io.DisplayFramebufferScale: 1.00,1.00
--------------------------------

style.WindowPadding: 16.00,16.00
style.WindowBorderSize: 1.00
style.FramePadding: 8.00,6.00
style.FrameRounding: 8.00
style.FrameBorderSize: 1.00
style.ItemSpacing: 16.00,8.00
style.ItemInnerSpacing: 8.00,8.00

Details:

I'm using ImPlot in my aplication and because often during scrolling plots are 'catching' mouse focus
(and scrolling ends, plot starts to zoom), I decided to add an option: use ctrl to zoom plot.

  • If it's disabled, then wheel on plot should zoom it, and wheel on window should scroll it.
  • If it's enabled, then wheel should scroll window no matter where cursor is, and wheel on plot should zoom it only if ctrl is pressed.

Aditionally, I handle ctrl+wheel case on window independently, and the scroll on window also could be custom-made, but it makes no difference.
How am I supposed to handle these cases in proper fashion?

First, I disabled wheel handling in ImPlot:

ImPlot::GetInputMap().ZoomMod = 1 << 16; // btw. is there any value that will be safer?

(because of ImPlot's UpdateInput(ImPlotPlot& plot), section SCROLL INPUT: ImHasFlag(IO.KeyMods, gp.InputMap.ZoomMod)))

Then, I noticed that ImPlot::IsPlotHovered() is not always working (especially with custom drag from another widget),
and ImGuiHoveredFlags_AllowWhenBlockedByActiveItem could not be used with ImPlot::IsPlotHovered(),
so instead, in-between ImPlot begin-end I used:

ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)

And finally I do the check:

if ((ImGui::GetIO().MouseWheel != 0.0f) && (need_ctrl == ImGui::GetIO().KeyCtrl) && !ImGui::GetIO().KeyShift)

In addition, I handle different kinds of zooms (and keys combinations) outside the ImPlot, and different kinds of scroll (default/smooth/etc).

I noticed that scroll behaves very odd. Whole variety of cases:

  • not working, then suddenly flushing the events when mouse leaves plot;
  • plot zooms, but window scrolls;
  • plot zooms only when mouse finish move after scroll in plot area;
  • only window scroll works.

After an investigation I realized that there is no 'consume the event / notify' mechanism and
I just(?) need to set ownership of the mousewheel, so after few experiments following combination worked:

if (!using_ctrl_for_plot_zoom)
	{ ImGui::SetKeyOwner(ImGuiKey_MouseWheelY, ImPlot::GetCurrentPlot()->ID); }
if (plot_zoomed_successfully)
	{ ImGui::SetKeyOwner(ImGuiKey_MouseWheelY, ImPlot::GetCurrentPlot()->ID); }

Still, no idea why the first condition is needed, and without it I get problems
mentioned above. Also, explicitly setting the window as a key owner didn't work.
First condition looks like this: if the ctrl-option is not set, plot gets the mousewheel always;
Very redundant.

I tried to follow/debug how ImGui handles mousewheel, but it's somehow problematic.
All I get is, that in NewFrame() readings are updated in UpdateMouseWheel,
and in the very same function, below remark // Mouse wheel scrolling: find target and apply
there is SetScrollY applied to the window.
It is unclear to me, how the flow finally looks like and how am I supposed to control it.
If the wheel readings are done at the beginning and instantly applied, then how am I supposed
to control it regarding the widgets?
Without altering the widgets and without the need to use anything from ImGui internal stuff.

No additional example code as it would need ImPlot and my questions are more like
about the proper way of handling stuff than reporting the issue (maybe there is no issue...).

Screenshots/Video:

No response

Minimal, Complete and Verifiable Example code:

No response

@ocornut
Copy link
Owner

ocornut commented Jan 22, 2024

Thanks for your detailed issue!

I'm using ImPlot in my aplication and because often during scrolling plots are 'catching' mouse focus
(and scrolling ends, plot starts to zoom)

XY Problem detected :) This could be improved in implot.
Since 26f14e0 we have a g.WheelingWindow field used for wheeling lock. Bhavior has been tweaked/improved since initial commit. I believe ImPlot should check that along is IsWindowHovered() when handling mouse wheel.

About the remaining of the post: you are asking too many things and partly asking about ImPlot codebase which is not mine. If you ask precise ImGui issues I will try to answer them. It would probably helped you if you displayed the state of various data on the screen while debugging.

ImPlot::GetInputMap().ZoomMod = 1 << 16; // btw. is there any value that will be safer?

Probably would need a way to disable zooming in ImPlot (e.g: ZoomRate == 0.0f), but only if that's the best way to achieve your result, and right now I am not sure.

@astotrzynascie
Copy link
Author

Sorry for long pause, but I was dealing with so-called real life and my hobby had to wait.
Long story short:
ImGui::SetKeyOwner(ImGuiKey_MouseWheelY, ImPlot::GetCurrentPlot()->ID); wasn't always working as intended, especially when playing with mouse wheel (hand-made smooth scroll, etc);
The best behaviour I could get was that after ImGui noticed mouse scroll (and widget didn't) and moved the scrollbar / window content, event was triggered whenever the mouse cursor landed (by 'event was triggered' I mean: condition in ImPlot worked). So, when I had cursor hovering the ImPlot and used scroll, the window moved and plot was intact. But when I started from outside the plot and scrolled onto it, the plot noticed that there is mouse over (and is using the wheel).
The workaround was to completely disable scrolling window by mouse and do it manually (ImPlot is completely reworked anyway, but this problem also applies to other widgets).
However, when I read it now, it may sound like an XY problem, so all the more thanks for responding.
I'll be back with a more specific problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants