@@ -4269,13 +4269,74 @@ static void LockWheelingWindow(ImGuiWindow* window)
4269
4269
{
4270
4270
ImGuiContext& g = *GImGui;
4271
4271
g.WheelingWindowReleaseTimer = window ? WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER : 0.0f;
4272
+ if (window == NULL)
4273
+ g.WheelingWindowStartFrame = -1;
4272
4274
if (g.WheelingWindow == window)
4273
4275
return;
4274
4276
IMGUI_DEBUG_LOG_IO("LockWheelingWindow() \"%s\"\n", window ? window->Name : "NULL");
4275
4277
g.WheelingWindow = window;
4276
4278
g.WheelingWindowRefMousePos = g.IO.MousePos;
4277
4279
}
4278
4280
4281
+ static ImGuiWindow* FindBestWheelingWindow(const ImVec2& wheel)
4282
+ {
4283
+ ImGuiContext& g = *GImGui;
4284
+ if (g.WheelingWindow != NULL)
4285
+ return g.WheelingWindow;
4286
+
4287
+ // For each axis, find window in the hierarchy that may want to use scrolling
4288
+ ImGuiWindow* candidates[2] = { NULL, NULL };
4289
+ for (int axis = 0; axis < 2; axis++)
4290
+ if (wheel[axis] != 0.0f)
4291
+ {
4292
+ // Bubble up into parent window if:
4293
+ // - a child window doesn't allow any scrolling.
4294
+ // - a child window doesn't need scrolling because it is already at the edge for the direction we are going in.
4295
+ // - a child window has the ImGuiWindowFlags_NoScrollWithMouse flag.
4296
+ ImGuiWindow* window = g.HoveredWindow;
4297
+ while (window->Flags & ImGuiWindowFlags_ChildWindow)
4298
+ {
4299
+ const bool has_scrolling = (window->ScrollMax[axis] != 0.0f);
4300
+ //const bool scrolling_past_limits = (wheel_v < 0.0f) ? (window->Scroll[axis] <= 0.0f) : (window->Scroll[axis] >= window->ScrollMax[axis]);
4301
+ const bool inputs_disabled = (window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs);
4302
+ if (has_scrolling && !inputs_disabled) // && !scrolling_past_limits)
4303
+ break; // select this window
4304
+ window = window->ParentWindow; // move up
4305
+ }
4306
+ candidates[axis] = window;
4307
+ }
4308
+ if (candidates[ImGuiAxis_X] == NULL && candidates[ImGuiAxis_Y] == NULL)
4309
+ return NULL;
4310
+
4311
+ // If there's only one window or only one axis then there's no ambiguity
4312
+ if (candidates[ImGuiAxis_X] == candidates[ImGuiAxis_Y] || candidates[ImGuiAxis_X] == NULL || candidates[ImGuiAxis_Y] == NULL)
4313
+ return candidates[ImGuiAxis_Y] ? candidates[ImGuiAxis_Y] : candidates[ImGuiAxis_X];
4314
+
4315
+ // If candidate are different windows we need to decide which one to prioritize
4316
+ IM_ASSERT(candidates[ImGuiAxis_X] != candidates[ImGuiAxis_Y]);
4317
+ if (g.WheelingWindowStartFrame == -1)
4318
+ {
4319
+ g.WheelingWindowStartFrame = g.FrameCount;
4320
+ g.WheelingWindowPerAxisData[ImGuiAxis_X] = g.WheelingWindowPerAxisData[ImGuiAxis_Y] = 0.0f;
4321
+ }
4322
+
4323
+ g.WheelingWindowPerAxisData[ImGuiAxis_X] += ImAbs(wheel.x);
4324
+ g.WheelingWindowPerAxisData[ImGuiAxis_Y] += ImAbs(wheel.y);
4325
+
4326
+ // First frame: only find a winner if one axis is zero.
4327
+ if (g.WheelingWindowStartFrame == g.FrameCount)
4328
+ if (wheel.x != 0.0f && wheel.y != 0.0f)
4329
+ return NULL;
4330
+
4331
+ // Subsequent frames: only find a winner when one is more than the other.
4332
+ if (g.WheelingWindowPerAxisData[ImGuiAxis_X] > g.WheelingWindowPerAxisData[ImGuiAxis_Y])
4333
+ return candidates[ImGuiAxis_X];
4334
+ if (g.WheelingWindowPerAxisData[ImGuiAxis_Y] > g.WheelingWindowPerAxisData[ImGuiAxis_X])
4335
+ return candidates[ImGuiAxis_Y];
4336
+
4337
+ return NULL;
4338
+ }
4339
+
4279
4340
void ImGui::UpdateMouseWheel()
4280
4341
{
4281
4342
ImGuiContext& g = *GImGui;
@@ -4336,39 +4397,26 @@ void ImGui::UpdateMouseWheel()
4336
4397
wheel.y = 0.0f;
4337
4398
}
4338
4399
4339
- // Vertical Mouse Wheel scrolling
4340
- // Bubble up into parent window if:
4341
- // - a child window doesn't allow any scrolling.
4342
- // - a child window doesn't need scrolling because it is already at the edge for the direction we are going in.
4343
- // - a child window has the ImGuiWindowFlags_NoScrollWithMouse flag.
4344
- if (wheel.y != 0.0f)
4345
- {
4346
- ImGuiWindow* window = mouse_window;
4347
- while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.y == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))))
4348
- window = window->ParentWindow;
4349
- if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))
4350
- {
4351
- LockWheelingWindow(mouse_window);
4352
- float max_step = window->InnerRect.GetHeight() * 0.67f;
4353
- float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step));
4354
- SetScrollY(window, window->Scroll.y - wheel.y * scroll_step);
4355
- }
4356
- }
4357
-
4358
- // Horizontal Mouse Wheel scrolling, or Vertical Mouse Wheel w/ Shift held
4359
- if (wheel.x != 0.0f)
4360
- {
4361
- ImGuiWindow* window = mouse_window;
4362
- while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.x == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))))
4363
- window = window->ParentWindow;
4400
+ // Mouse wheel scrolling: find target and apply
4401
+ // - Don't renew lock if axis doesn't apply on the window.
4402
+ if (ImGuiWindow* window = FindBestWheelingWindow(wheel))
4364
4403
if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))
4365
4404
{
4366
- LockWheelingWindow(mouse_window);
4367
- float max_step = window->InnerRect.GetWidth() * 0.67f;
4368
- float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step));
4369
- SetScrollX(window, window->Scroll.x - wheel.x * scroll_step);
4405
+ if (wheel.x != 0.0f && window->ScrollMax.x != 0.0f)
4406
+ {
4407
+ LockWheelingWindow(window);
4408
+ float max_step = window->InnerRect.GetWidth() * 0.67f;
4409
+ float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step));
4410
+ SetScrollX(window, window->Scroll.x - wheel.x * scroll_step);
4411
+ }
4412
+ if (wheel.y != 0.0f && window->ScrollMax.y != 0.0f)
4413
+ {
4414
+ LockWheelingWindow(window);
4415
+ float max_step = window->InnerRect.GetHeight() * 0.67f;
4416
+ float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step));
4417
+ SetScrollY(window, window->Scroll.y - wheel.y * scroll_step);
4418
+ }
4370
4419
}
4371
- }
4372
4420
}
4373
4421
4374
4422
// 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)
0 commit comments