diff --git a/imgui.cpp b/imgui.cpp index e2f515f8e..cfa2d8e7d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2132,7 +2132,7 @@ static float NavScoreItemDistInterval(float a0, float a1, float b0, float b1) } // Scoring function for directional navigation. Based on https://gist.github.com/rygorous/6981057 -static bool NavScoreItem(ImRect cand) +static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.NavWindow; @@ -2207,21 +2207,21 @@ static bool NavScoreItem(ImRect cand) if (quadrant == g.NavMoveDir) { // Does it beat the current best candidate? - if (dist_box < g.NavMoveResultDistBox) + if (dist_box < result->DistBox) { - g.NavMoveResultDistBox = dist_box; - g.NavMoveResultDistCenter = dist_center; + result->DistBox = dist_box; + result->DistCenter = dist_center; return true; } - if (dist_box == g.NavMoveResultDistBox) + if (dist_box == result->DistBox) { // Try using distance between center points to break ties - if (dist_center < g.NavMoveResultDistCenter) + if (dist_center < result->DistCenter) { - g.NavMoveResultDistCenter = dist_center; + result->DistCenter = dist_center; new_best = true; } - else if (dist_center == g.NavMoveResultDistCenter) + else if (dist_center == result->DistCenter) { // Still tied! we need to be extra-careful to make sure everything gets linked properly. We consistently break ties by symbolically moving "later" items // (with higher index) to the right/downwards by an infinitesimal amount since we the current "best" button already (so it must have a lower index), @@ -2237,11 +2237,11 @@ static bool NavScoreItem(ImRect cand) // This is just to avoid buttons having no links in a particular direction when there's a suitable neighbor. you get good graphs without this too. // 2017/09/29: FIXME: This now currently only enabled inside menubars, ideally we'd disable it everywhere. Menus in particular need to catch failure. For general navigation it feels awkward. // Disabling it may however lead to disconnected graphs when nodes are very spaced out on different axis. Perhaps consider offering this as an option? - if (g.NavMoveResultDistBox == FLT_MAX && dist_axial < g.NavMoveResultDistAxial) // Check axial match + if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial) // Check axial match if (g.NavLayer == 1 && !(g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) if ((g.NavMoveDir == ImGuiDir_Left && dax < 0.0f) || (g.NavMoveDir == ImGuiDir_Right && dax > 0.0f) || (g.NavMoveDir == ImGuiDir_Up && day < 0.0f) || (g.NavMoveDir == ImGuiDir_Down && day > 0.0f)) { - g.NavMoveResultDistAxial = dist_axial; + result->DistAxial = dist_axial; new_best = true; } @@ -2288,19 +2288,21 @@ static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, con // Scoring for navigation if (g.NavId != id && !(item_flags & ImGuiItemFlags_NoNav)) { + ImGuiNavMoveResult* result = &g.NavMoveResult; #if IMGUI_DEBUG_NAV_SCORING // [DEBUG] Score all items in NavWindow at all times if (!g.NavMoveRequest) g.NavMoveDir = g.NavMoveDirLast; - bool new_best = NavScoreItem(nav_bb) && g.NavMoveRequest; + bool new_best = NavScoreItem(result, nav_bb) && g.NavMoveRequest; #else - bool new_best = g.NavMoveRequest && NavScoreItem(nav_bb); + bool new_best = g.NavMoveRequest && NavScoreItem(result, nav_bb); #endif if (new_best) { - g.NavMoveResultId = id; - g.NavMoveResultParentId = window->IDStack.back(); - g.NavMoveResultRectRel = nav_bb_rel; + result->ID = id; + result->ParentID = window->IDStack.back(); + result->Window = window; + result->RectRel = nav_bb_rel; } } @@ -2881,17 +2883,18 @@ static void ImGui::NavUpdate() g.NavJustMovedToId = 0; // Process navigation move request - if (g.NavMoveRequest && g.NavMoveResultId != 0) + if (g.NavMoveRequest && g.NavMoveResult.ID != 0) { // Scroll to keep newly navigated item fully into view - IM_ASSERT(g.NavWindow); + ImGuiNavMoveResult* result = &g.NavMoveResult; + IM_ASSERT(g.NavWindow && result->Window); if (g.NavLayer == 0) - NavScrollToBringItemIntoView(g.NavWindow, g.NavMoveResultRectRel); + NavScrollToBringItemIntoView(result->Window, result->RectRel); // Apply result from previous frame navigation directional move request ClearActiveID(); - SetNavIDAndMoveMouse(g.NavMoveResultId, g.NavLayer, g.NavMoveResultRectRel); - g.NavJustMovedToId = g.NavMoveResultId; + SetNavIDAndMoveMouse(result->ID, g.NavLayer, result->RectRel); + g.NavJustMovedToId = result->ID; g.NavMoveFromClampedRefRect = false; } @@ -2899,7 +2902,7 @@ static void ImGui::NavUpdate() if (g.NavMoveRequestForward == ImGuiNavForward_ForwardActive) { IM_ASSERT(g.NavMoveRequest); - if (g.NavMoveResultId == 0) + if (g.NavMoveResult.ID == 0) g.NavDisableHighlight = false; g.NavMoveRequestForward = ImGuiNavForward_None; } @@ -3058,9 +3061,10 @@ static void ImGui::NavUpdate() } // Reset search - g.NavMoveResultId = 0; - g.NavMoveResultParentId = 0; - g.NavMoveResultDistAxial = g.NavMoveResultDistBox = g.NavMoveResultDistCenter = FLT_MAX; + ImGuiNavMoveResult* result = &g.NavMoveResult; + result->ID = result->ParentID = 0; + result->Window = NULL; + result->DistAxial = result->DistBox = result->DistCenter = FLT_MAX; // When we have manually scrolled (without using navigation) and NavId becomes out of bounds, we project its bounding box to the visible area to restart navigation within visible items if (g.NavMoveRequest && g.NavMoveFromClampedRefRect && g.NavLayer == 0) @@ -4821,7 +4825,7 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla static void NavProcessMoveRequestWrapAround(ImGuiWindow* window) { ImGuiContext& g = *GImGui; - if (g.NavMoveRequest && g.NavWindow == window && g.NavMoveResultId == 0) + if (g.NavMoveRequest && g.NavWindow == window && g.NavMoveResult.ID == 0) if ((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) && g.NavMoveRequestForward == ImGuiNavForward_None && g.NavLayer == 0) { g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued; @@ -10856,7 +10860,7 @@ void ImGui::EndMenuBar() ImGuiContext& g = *GImGui; // Nav: When a move request within one of our child menu failed, capture the request to navigate among our siblings. - if (g.NavMoveRequest && g.NavMoveResultId == 0 && (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) && (g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) + if (g.NavMoveRequest && g.NavMoveResult.ID == 0 && (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) && (g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) { ImGuiWindow* nav_earliest_child = g.NavWindow; while (nav_earliest_child->ParentWindow && (nav_earliest_child->ParentWindow->Flags & ImGuiWindowFlags_ChildMenu)) @@ -11024,7 +11028,7 @@ void ImGui::EndMenu() // Nav: When a left move request within our child menu failed, close the menu ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - if (g.NavWindow && g.NavWindow->ParentWindow == window && g.NavMoveRequest && g.NavMoveResultId == 0 && g.NavMoveDir == ImGuiDir_Left && window->DC.LayoutType == ImGuiLayoutType_Vertical) + if (g.NavWindow && g.NavWindow->ParentWindow == window && g.NavMoveRequest && g.NavMoveResult.ID == 0 && g.NavMoveDir == ImGuiDir_Left && window->DC.LayoutType == ImGuiLayoutType_Vertical) { ClosePopupToLevel(g.OpenPopupStack.Size - 1); g.NavMoveRequest = false; diff --git a/imgui_internal.h b/imgui_internal.h index 2713aa56d..f277882cd 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -504,6 +504,19 @@ struct ImDrawDataBuilder IMGUI_API void FlattenIntoSingleLayer(); }; +struct ImGuiNavMoveResult +{ + ImGuiID ID; // Best candidate + ImGuiID ParentID; // Best candidate window->IDStack.back() - to compare context + ImGuiWindow* Window; // Best candidate window + float DistBox; // Best candidate box distance to current NavId + float DistCenter; // Best candidate center distance to current NavId + float DistAxial; // Best candidate selected distance (box/center) to current NavId + ImRect RectRel; // Best candidate bounding box in window relative space + + ImGuiNavMoveResult() { ID = ParentID = 0; Window = NULL; DistBox = DistCenter = DistAxial = 0.0f; } +}; + // Storage for SetNexWindow** functions struct ImGuiNextWindowData { @@ -620,12 +633,7 @@ struct ImGuiContext ImGuiNavForward NavMoveRequestForward; // None / ForwardQueued / ForwardActive (this is used to navigate sibling parent menus from a child menu) ImGuiDir NavMoveDir; // Direction of the move request (left/right/up/down) ImGuiDir NavMoveDirLast; // Direction of the previous move request - ImGuiID NavMoveResultId; // Best move request candidate - ImGuiID NavMoveResultParentId; // Best move request candidate window->IDStack.back() - to compare context - float NavMoveResultDistBox; // Best move request candidate box distance to current NavId - float NavMoveResultDistCenter; // Best move request candidate center distance to current NavId - float NavMoveResultDistAxial; - ImRect NavMoveResultRectRel; // Best move request candidate bounding box in window relative space + ImGuiNavMoveResult NavMoveResult; // Best move request candidate // Render ImDrawData DrawData; // Main ImDrawData instance to pass render information to the user @@ -738,9 +746,6 @@ struct ImGuiContext NavMoveRequest = false; NavMoveRequestForward = ImGuiNavForward_None; NavMoveDir = NavMoveDirLast = ImGuiDir_None; - NavMoveResultId = 0; - NavMoveResultParentId = 0; - NavMoveResultDistBox = NavMoveResultDistCenter = NavMoveResultDistAxial = 0.0f; ModalWindowDarkeningRatio = 0.0f; OverlayDrawList._Data = &DrawListSharedData;