Refactor: moved LockWheelingWindow(), FindBestWheelingWindow(), UpdateMouseWheel() to INPUTS section
diff --git a/imgui.cpp b/imgui.cpp
index 4f71058..2808421 100644
--- a/imgui.cpp
+++ b/imgui.cpp
@@ -4446,156 +4446,6 @@
}
}
-static void LockWheelingWindow(ImGuiWindow* window, float wheel_amount)
-{
- ImGuiContext& g = *GImGui;
- if (window)
- g.WheelingWindowReleaseTimer = ImMin(g.WheelingWindowReleaseTimer + ImAbs(wheel_amount) * WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER, WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER);
- else
- g.WheelingWindowReleaseTimer = 0.0f;
- if (g.WheelingWindow == window)
- return;
- IMGUI_DEBUG_LOG_IO("LockWheelingWindow() \"%s\"\n", window ? window->Name : "NULL");
- g.WheelingWindow = window;
- g.WheelingWindowRefMousePos = g.IO.MousePos;
- if (window == NULL)
- {
- g.WheelingWindowStartFrame = -1;
- g.WheelingAxisAvg = ImVec2(0.0f, 0.0f);
- }
-}
-
-static ImGuiWindow* FindBestWheelingWindow(const ImVec2& wheel)
-{
- // For each axis, find window in the hierarchy that may want to use scrolling
- ImGuiContext& g = *GImGui;
- ImGuiWindow* windows[2] = { NULL, NULL };
- for (int axis = 0; axis < 2; axis++)
- if (wheel[axis] != 0.0f)
- for (ImGuiWindow* window = windows[axis] = g.HoveredWindow; window->Flags & ImGuiWindowFlags_ChildWindow; window = windows[axis] = window->ParentWindow)
- {
- // Bubble up into parent window if:
- // - a child window doesn't allow any scrolling.
- // - a child window has the ImGuiWindowFlags_NoScrollWithMouse flag.
- //// - a child window doesn't need scrolling because it is already at the edge for the direction we are going in (FIXME-WIP)
- const bool has_scrolling = (window->ScrollMax[axis] != 0.0f);
- const bool inputs_disabled = (window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs);
- //const bool scrolling_past_limits = (wheel_v < 0.0f) ? (window->Scroll[axis] <= 0.0f) : (window->Scroll[axis] >= window->ScrollMax[axis]);
- if (has_scrolling && !inputs_disabled) // && !scrolling_past_limits)
- break; // select this window
- }
- if (windows[0] == NULL && windows[1] == NULL)
- return NULL;
-
- // If there's only one window or only one axis then there's no ambiguity
- if (windows[0] == windows[1] || windows[0] == NULL || windows[1] == NULL)
- return windows[1] ? windows[1] : windows[0];
-
- // If candidate are different windows we need to decide which one to prioritize
- // - First frame: only find a winner if one axis is zero.
- // - Subsequent frames: only find a winner when one is more than the other.
- if (g.WheelingWindowStartFrame == -1)
- g.WheelingWindowStartFrame = g.FrameCount;
- if ((g.WheelingWindowStartFrame == g.FrameCount && wheel.x != 0.0f && wheel.y != 0.0f) || (g.WheelingAxisAvg.x == g.WheelingAxisAvg.y))
- {
- g.WheelingWindowWheelRemainder = wheel;
- return NULL;
- }
- return (g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? windows[0] : windows[1];
-}
-
-void ImGui::UpdateMouseWheel()
-{
- ImGuiContext& g = *GImGui;
-
- // Reset the locked window if we move the mouse or after the timer elapses.
- // FIXME: Ideally we could refactor to have one timer for "changing window w/ same axis" and a shorter timer for "changing window or axis w/ other axis" (#3795)
- if (g.WheelingWindow != NULL)
- {
- g.WheelingWindowReleaseTimer -= g.IO.DeltaTime;
- if (IsMousePosValid() && ImLengthSqr(g.IO.MousePos - g.WheelingWindowRefMousePos) > g.IO.MouseDragThreshold * g.IO.MouseDragThreshold)
- g.WheelingWindowReleaseTimer = 0.0f;
- if (g.WheelingWindowReleaseTimer <= 0.0f)
- LockWheelingWindow(NULL, 0.0f);
- }
-
- ImVec2 wheel;
- wheel.x = TestKeyOwner(ImGuiKey_MouseWheelX, ImGuiKeyOwner_None) ? g.IO.MouseWheelH : 0.0f;
- wheel.y = TestKeyOwner(ImGuiKey_MouseWheelY, ImGuiKeyOwner_None) ? g.IO.MouseWheel : 0.0f;
-
- //IMGUI_DEBUG_LOG("MouseWheel X:%.3f Y:%.3f\n", wheel_x, wheel_y);
- ImGuiWindow* mouse_window = g.WheelingWindow ? g.WheelingWindow : g.HoveredWindow;
- if (!mouse_window || mouse_window->Collapsed)
- return;
-
- // Zoom / Scale window
- // FIXME-OBSOLETE: This is an old feature, it still works but pretty much nobody is using it and may be best redesigned.
- if (wheel.y != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling)
- {
- LockWheelingWindow(mouse_window, wheel.y);
- ImGuiWindow* window = mouse_window;
- const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f);
- const float scale = new_font_scale / window->FontWindowScale;
- window->FontWindowScale = new_font_scale;
- if (window == window->RootWindow)
- {
- const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size;
- SetWindowPos(window, window->Pos + offset, 0);
- window->Size = ImFloor(window->Size * scale);
- window->SizeFull = ImFloor(window->SizeFull * scale);
- }
- return;
- }
- if (g.IO.KeyCtrl)
- return;
-
- // Mouse wheel scrolling
- // As a standard behavior holding SHIFT while using Vertical Mouse Wheel triggers Horizontal scroll instead
- // (we avoid doing it on OSX as it the OS input layer handles this already)
- const bool swap_axis = g.IO.KeyShift && !g.IO.ConfigMacOSXBehaviors;
- if (swap_axis)
- {
- wheel.x = wheel.y;
- wheel.y = 0.0f;
- }
-
- // Maintain a rough average of moving magnitude on both axises
- // FIXME: should by based on wall clock time rather than frame-counter
- g.WheelingAxisAvg.x = ImExponentialMovingAverage(g.WheelingAxisAvg.x, ImAbs(wheel.x), 30);
- g.WheelingAxisAvg.y = ImExponentialMovingAverage(g.WheelingAxisAvg.y, ImAbs(wheel.y), 30);
-
- // In the rare situation where FindBestWheelingWindow() had to defer first frame of wheeling due to ambiguous main axis, reinject it now.
- wheel += g.WheelingWindowWheelRemainder;
- g.WheelingWindowWheelRemainder = ImVec2(0.0f, 0.0f);
- if (wheel.x == 0.0f && wheel.y == 0.0f)
- return;
-
- // Mouse wheel scrolling: find target and apply
- // - don't renew lock if axis doesn't apply on the window.
- // - select a main axis when both axises are being moved.
- if (ImGuiWindow* window = (g.WheelingWindow ? g.WheelingWindow : FindBestWheelingWindow(wheel)))
- if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))
- {
- bool do_scroll[2] = { wheel.x != 0.0f && window->ScrollMax.x != 0.0f, wheel.y != 0.0f && window->ScrollMax.y != 0.0f };
- if (do_scroll[ImGuiAxis_X] && do_scroll[ImGuiAxis_Y])
- do_scroll[(g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? ImGuiAxis_Y : ImGuiAxis_X] = false;
- if (do_scroll[ImGuiAxis_X])
- {
- LockWheelingWindow(window, wheel.x);
- float max_step = window->InnerRect.GetWidth() * 0.67f;
- float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step));
- SetScrollX(window, window->Scroll.x - wheel.x * scroll_step);
- }
- if (do_scroll[ImGuiAxis_Y])
- {
- LockWheelingWindow(window, wheel.y);
- float max_step = window->InnerRect.GetHeight() * 0.67f;
- float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step));
- SetScrollY(window, window->Scroll.y - wheel.y * scroll_step);
- }
- }
-}
-
// The reason this is exposed in imgui_internal.h is: on touch-based system that don't have hovering, we want to dispatch inputs to the right target (imgui vs imgui+app)
void ImGui::UpdateHoveredWindowAndCaptureFlags()
{
@@ -7922,6 +7772,10 @@
// - GetMouseCursor()
// - SetMouseCursor()
//-----------------------------------------------------------------------------
+// - LockWheelingWindow [Internal]
+// - FindBestWheelingWindow [Internal]
+// - UpdateMouseWheel() [Internal]
+//-----------------------------------------------------------------------------
// - SetNextFrameWantCaptureKeyboard()
// - SetNextFrameWantCaptureMouse()
//-----------------------------------------------------------------------------
@@ -8506,6 +8360,156 @@
g.MouseCursor = cursor_type;
}
+static void LockWheelingWindow(ImGuiWindow* window, float wheel_amount)
+{
+ ImGuiContext& g = *GImGui;
+ if (window)
+ g.WheelingWindowReleaseTimer = ImMin(g.WheelingWindowReleaseTimer + ImAbs(wheel_amount) * WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER, WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER);
+ else
+ g.WheelingWindowReleaseTimer = 0.0f;
+ if (g.WheelingWindow == window)
+ return;
+ IMGUI_DEBUG_LOG_IO("LockWheelingWindow() \"%s\"\n", window ? window->Name : "NULL");
+ g.WheelingWindow = window;
+ g.WheelingWindowRefMousePos = g.IO.MousePos;
+ if (window == NULL)
+ {
+ g.WheelingWindowStartFrame = -1;
+ g.WheelingAxisAvg = ImVec2(0.0f, 0.0f);
+ }
+}
+
+static ImGuiWindow* FindBestWheelingWindow(const ImVec2& wheel)
+{
+ // For each axis, find window in the hierarchy that may want to use scrolling
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* windows[2] = { NULL, NULL };
+ for (int axis = 0; axis < 2; axis++)
+ if (wheel[axis] != 0.0f)
+ for (ImGuiWindow* window = windows[axis] = g.HoveredWindow; window->Flags & ImGuiWindowFlags_ChildWindow; window = windows[axis] = window->ParentWindow)
+ {
+ // Bubble up into parent window if:
+ // - a child window doesn't allow any scrolling.
+ // - a child window has the ImGuiWindowFlags_NoScrollWithMouse flag.
+ //// - a child window doesn't need scrolling because it is already at the edge for the direction we are going in (FIXME-WIP)
+ const bool has_scrolling = (window->ScrollMax[axis] != 0.0f);
+ const bool inputs_disabled = (window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs);
+ //const bool scrolling_past_limits = (wheel_v < 0.0f) ? (window->Scroll[axis] <= 0.0f) : (window->Scroll[axis] >= window->ScrollMax[axis]);
+ if (has_scrolling && !inputs_disabled) // && !scrolling_past_limits)
+ break; // select this window
+ }
+ if (windows[0] == NULL && windows[1] == NULL)
+ return NULL;
+
+ // If there's only one window or only one axis then there's no ambiguity
+ if (windows[0] == windows[1] || windows[0] == NULL || windows[1] == NULL)
+ return windows[1] ? windows[1] : windows[0];
+
+ // If candidate are different windows we need to decide which one to prioritize
+ // - First frame: only find a winner if one axis is zero.
+ // - Subsequent frames: only find a winner when one is more than the other.
+ if (g.WheelingWindowStartFrame == -1)
+ g.WheelingWindowStartFrame = g.FrameCount;
+ if ((g.WheelingWindowStartFrame == g.FrameCount && wheel.x != 0.0f && wheel.y != 0.0f) || (g.WheelingAxisAvg.x == g.WheelingAxisAvg.y))
+ {
+ g.WheelingWindowWheelRemainder = wheel;
+ return NULL;
+ }
+ return (g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? windows[0] : windows[1];
+}
+
+// Called by NewFrame()
+void ImGui::UpdateMouseWheel()
+{
+ // Reset the locked window if we move the mouse or after the timer elapses.
+ // FIXME: Ideally we could refactor to have one timer for "changing window w/ same axis" and a shorter timer for "changing window or axis w/ other axis" (#3795)
+ ImGuiContext& g = *GImGui;
+ if (g.WheelingWindow != NULL)
+ {
+ g.WheelingWindowReleaseTimer -= g.IO.DeltaTime;
+ if (IsMousePosValid() && ImLengthSqr(g.IO.MousePos - g.WheelingWindowRefMousePos) > g.IO.MouseDragThreshold * g.IO.MouseDragThreshold)
+ g.WheelingWindowReleaseTimer = 0.0f;
+ if (g.WheelingWindowReleaseTimer <= 0.0f)
+ LockWheelingWindow(NULL, 0.0f);
+ }
+
+ ImVec2 wheel;
+ wheel.x = TestKeyOwner(ImGuiKey_MouseWheelX, ImGuiKeyOwner_None) ? g.IO.MouseWheelH : 0.0f;
+ wheel.y = TestKeyOwner(ImGuiKey_MouseWheelY, ImGuiKeyOwner_None) ? g.IO.MouseWheel : 0.0f;
+
+ //IMGUI_DEBUG_LOG("MouseWheel X:%.3f Y:%.3f\n", wheel_x, wheel_y);
+ ImGuiWindow* mouse_window = g.WheelingWindow ? g.WheelingWindow : g.HoveredWindow;
+ if (!mouse_window || mouse_window->Collapsed)
+ return;
+
+ // Zoom / Scale window
+ // FIXME-OBSOLETE: This is an old feature, it still works but pretty much nobody is using it and may be best redesigned.
+ if (wheel.y != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling)
+ {
+ LockWheelingWindow(mouse_window, wheel.y);
+ ImGuiWindow* window = mouse_window;
+ const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f);
+ const float scale = new_font_scale / window->FontWindowScale;
+ window->FontWindowScale = new_font_scale;
+ if (window == window->RootWindow)
+ {
+ const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size;
+ SetWindowPos(window, window->Pos + offset, 0);
+ window->Size = ImFloor(window->Size * scale);
+ window->SizeFull = ImFloor(window->SizeFull * scale);
+ }
+ return;
+ }
+ if (g.IO.KeyCtrl)
+ return;
+
+ // Mouse wheel scrolling
+ // As a standard behavior holding SHIFT while using Vertical Mouse Wheel triggers Horizontal scroll instead
+ // (we avoid doing it on OSX as it the OS input layer handles this already)
+ const bool swap_axis = g.IO.KeyShift && !g.IO.ConfigMacOSXBehaviors;
+ if (swap_axis)
+ {
+ wheel.x = wheel.y;
+ wheel.y = 0.0f;
+ }
+
+ // Maintain a rough average of moving magnitude on both axises
+ // FIXME: should by based on wall clock time rather than frame-counter
+ g.WheelingAxisAvg.x = ImExponentialMovingAverage(g.WheelingAxisAvg.x, ImAbs(wheel.x), 30);
+ g.WheelingAxisAvg.y = ImExponentialMovingAverage(g.WheelingAxisAvg.y, ImAbs(wheel.y), 30);
+
+ // In the rare situation where FindBestWheelingWindow() had to defer first frame of wheeling due to ambiguous main axis, reinject it now.
+ wheel += g.WheelingWindowWheelRemainder;
+ g.WheelingWindowWheelRemainder = ImVec2(0.0f, 0.0f);
+ if (wheel.x == 0.0f && wheel.y == 0.0f)
+ return;
+
+ // Mouse wheel scrolling: find target and apply
+ // - don't renew lock if axis doesn't apply on the window.
+ // - select a main axis when both axises are being moved.
+ if (ImGuiWindow* window = (g.WheelingWindow ? g.WheelingWindow : FindBestWheelingWindow(wheel)))
+ if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))
+ {
+ bool do_scroll[2] = { wheel.x != 0.0f && window->ScrollMax.x != 0.0f, wheel.y != 0.0f && window->ScrollMax.y != 0.0f };
+ if (do_scroll[ImGuiAxis_X] && do_scroll[ImGuiAxis_Y])
+ do_scroll[(g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? ImGuiAxis_Y : ImGuiAxis_X] = false;
+ if (do_scroll[ImGuiAxis_X])
+ {
+ LockWheelingWindow(window, wheel.x);
+ float max_step = window->InnerRect.GetWidth() * 0.67f;
+ float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step));
+ SetScrollX(window, window->Scroll.x - wheel.x * scroll_step);
+ }
+ if (do_scroll[ImGuiAxis_Y])
+ {
+ LockWheelingWindow(window, wheel.y);
+ float max_step = window->InnerRect.GetHeight() * 0.67f;
+ float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step));
+ SetScrollY(window, window->Scroll.y - wheel.y * scroll_step);
+ }
+ }
+}
+
void ImGui::SetNextFrameWantCaptureKeyboard(bool want_capture_keyboard)
{
ImGuiContext& g = *GImGui;