mirror of
https://github.com/ocornut/imgui.git
synced 2024-11-12 02:00:58 +01:00
Refactor: moved LockWheelingWindow(), FindBestWheelingWindow(), UpdateMouseWheel() to INPUTS section
This commit is contained in:
parent
f9ab2a0e9f
commit
f83da768b6
304
imgui.cpp
304
imgui.cpp
@ -4446,156 +4446,6 @@ static void ImGui::UpdateMouseInputs()
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
|
||||
// - GetMouseCursor()
|
||||
// - SetMouseCursor()
|
||||
//-----------------------------------------------------------------------------
|
||||
// - LockWheelingWindow [Internal]
|
||||
// - FindBestWheelingWindow [Internal]
|
||||
// - UpdateMouseWheel() [Internal]
|
||||
//-----------------------------------------------------------------------------
|
||||
// - SetNextFrameWantCaptureKeyboard()
|
||||
// - SetNextFrameWantCaptureMouse()
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -8506,6 +8360,156 @@ void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type)
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user