From aa668c410a020e6cb40dbdd66620df1f8c7daa3c Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 15 Nov 2018 13:53:53 +0100 Subject: [PATCH] Nav: Fixed an assert in certain circumstance (mostly when using popups) when mouse positions stop being valid. (#2168) + adding a else block to make NavCalcPreferredRefPos() more explicit. --- docs/CHANGELOG.txt | 1 + imgui.cpp | 25 ++++++++++++++++--------- imgui_internal.h | 4 +++- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 9126cfd1..c7603717 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -46,6 +46,7 @@ Other Changes: accidental alteration of window position. We now round the provided size. (#2067) - Nav, Focus: Fixed ImGuiWindowFlags_NoBringToFrontOnFocus windows not being restoring focus properly after the main menu bar or last focused window is deactivated. +- Nav: Fixed an assert in certain circumstance (mostly when using popups) when mouse positions stop being valid. (#2168) - DragFloat: Fixed a situation where dragging with value rounding enabled or with a power curve erroneously wrapped the value to one of the min/max edge. (#2024, #708, #320, #2075). - DragFloat: Disabled using power curve when one edge is FLT_MAX (broken in 1.61). (#2024) diff --git a/imgui.cpp b/imgui.cpp index 54fac2cb..c6452b97 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2966,7 +2966,7 @@ static void ImGui::UpdateMouseInputs() // Round mouse position to avoid spreading non-rounded position (e.g. UpdateManualResize doesn't support them well) if (IsMousePosValid(&g.IO.MousePos)) - g.IO.MousePos = ImFloor(g.IO.MousePos); + g.IO.MousePos = g.LastValidMousePos = ImFloor(g.IO.MousePos); // If mouse just appeared or disappeared (usually denoted by -FLT_MAX components) we cancel out movement in MouseDelta if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MousePosPrev)) @@ -6415,8 +6415,8 @@ void ImGui::OpenPopupEx(ImGuiID id) popup_ref.ParentWindow = parent_window; popup_ref.OpenFrameCount = g.FrameCount; popup_ref.OpenParentId = parent_window->IDStack.back(); - popup_ref.OpenMousePos = g.IO.MousePos; popup_ref.OpenPopupPos = NavCalcPreferredRefPos(); + popup_ref.OpenMousePos = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : popup_ref.OpenPopupPos; //printf("[%05d] OpenPopupEx(0x%08X)\n", g.FrameCount, id); if (g.OpenPopupStack.Size < current_stack_size + 1) @@ -7093,13 +7093,20 @@ static ImVec2 ImGui::NavCalcPreferredRefPos() { ImGuiContext& g = *GImGui; if (g.NavDisableHighlight || !g.NavDisableMouseHover || !g.NavWindow) - return ImFloor(g.IO.MousePos); - - // When navigation is active and mouse is disabled, decide on an arbitrary position around the bottom left of the currently navigated item - const ImRect& rect_rel = g.NavWindow->NavRectRel[g.NavLayer]; - ImVec2 pos = g.NavWindow->Pos + ImVec2(rect_rel.Min.x + ImMin(g.Style.FramePadding.x*4, rect_rel.GetWidth()), rect_rel.Max.y - ImMin(g.Style.FramePadding.y, rect_rel.GetHeight())); - ImRect visible_rect = GetViewportRect(); - return ImFloor(ImClamp(pos, visible_rect.Min, visible_rect.Max)); // ImFloor() is important because non-integer mouse position application in back-end might be lossy and result in undesirable non-zero delta. + { + // Mouse (we need a fallback in case the mouse becomes invalid after being used) + if (IsMousePosValid(&g.IO.MousePos)) + return g.IO.MousePos; + return g.LastValidMousePos; + } + else + { + // When navigation is active and mouse is disabled, decide on an arbitrary position around the bottom left of the currently navigated item. + const ImRect& rect_rel = g.NavWindow->NavRectRel[g.NavLayer]; + ImVec2 pos = g.NavWindow->Pos + ImVec2(rect_rel.Min.x + ImMin(g.Style.FramePadding.x * 4, rect_rel.GetWidth()), rect_rel.Max.y - ImMin(g.Style.FramePadding.y, rect_rel.GetHeight())); + ImRect visible_rect = GetViewportRect(); + return ImFloor(ImClamp(pos, visible_rect.Min, visible_rect.Max)); // ImFloor() is important because non-integer mouse position application in back-end might be lossy and result in undesirable non-zero delta. + } } float ImGui::GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode) diff --git a/imgui_internal.h b/imgui_internal.h index b31aed4b..f3385d85 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -687,8 +687,9 @@ struct ImGuiContext ImGuiInputSource ActiveIdSource; // Activating with mouse or nav (gamepad/keyboard) ImGuiID LastActiveId; // Store the last non-zero ActiveId, useful for animation. float LastActiveIdTimer; // Store the last non-zero ActiveId timer since the beginning of activation, useful for animation. + ImVec2 LastValidMousePos; ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actually window that is moved is generally MovingWindow->RootWindow. - ImVector ColorModifiers; // Stack for PushStyleColor()/PopStyleColor() + ImVector ColorModifiers; // Stack for PushStyleColor()/PopStyleColor() ImVector StyleModifiers; // Stack for PushStyleVar()/PopStyleVar() ImVector FontStack; // Stack for PushFont()/PopFont() ImVector OpenPopupStack; // Which popups are open (persistent) @@ -833,6 +834,7 @@ struct ImGuiContext ActiveIdSource = ImGuiInputSource_None; LastActiveId = 0; LastActiveIdTimer = 0.0f; + LastValidMousePos = ImVec2(0.0f, 0.0f); MovingWindow = NULL; NextTreeNodeOpenVal = false; NextTreeNodeOpenCond = 0;