From bdd868704f8cf92384847f98a5e354f511a296e1 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 1 Feb 2018 00:50:42 +0100 Subject: [PATCH] Nav: Child window is restored on focus when returning to layer 0 or refocusing. This is a little experimental and potentially error-prone right now. (#787, vaguely relate to ~#727) Ideally we should maintain a non-sorted last-focused list that include childs windows. --- TODO.txt | 1 - imgui.cpp | 46 ++++++++++++++++++++++++++++++++++++++-------- imgui_internal.h | 1 + 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/TODO.txt b/TODO.txt index 05a8875ed..a483594f6 100644 --- a/TODO.txt +++ b/TODO.txt @@ -230,7 +230,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - font: (api breaking) removed "TTF" from symbol names. also because it now supports OTF. - nav: integrate navigation branch into master. (#787) - - nav: Menu/Esc on a menu restore layer 0 but lose child window position. - nav: Esc on a flattened child - nav: menus: allow pressing Menu to leave a sub-menu. - nav: integrate/design keyboard controls. diff --git a/imgui.cpp b/imgui.cpp index ebbd75225..fc4e04203 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1919,6 +1919,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) NavRootWindow = NULL; NavLastIds[0] = NavLastIds[1] = 0; NavRectRel[0] = NavRectRel[1] = ImRect(); + NavLastChildNavWindow = NULL; FocusIdxAllCounter = FocusIdxTabCounter = -1; FocusIdxAllRequestCurrent = FocusIdxTabRequestCurrent = INT_MAX; @@ -1983,7 +1984,7 @@ static void SetNavID(ImGuiID id, int nav_layer) IM_ASSERT(g.NavWindow); IM_ASSERT(nav_layer == 0 || nav_layer == 1); g.NavId = id; - g.NavWindow->NavLastIds[nav_layer] = g.NavId; + g.NavWindow->NavLastIds[nav_layer] = id; } static void SetNavIDAndMoveMouse(ImGuiID id, int nav_layer, const ImRect& rect_rel) @@ -2248,10 +2249,22 @@ static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand) return new_best; } +// Call when we are expected to land on Layer 0 after FocusWindow() +static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window) +{ + ImGuiWindow* child_window = window->NavLastChildNavWindow; + if (child_window == NULL) + return window; + window->NavLastChildNavWindow = NULL; + return child_window; +} + static void NavRestoreLayer(int layer) { ImGuiContext& g = *GImGui; g.NavLayer = layer; + if (layer == 0) + g.NavWindow = NavRestoreLastChildNavWindow(g.NavWindow); if (layer == 0 && g.NavWindow->NavLastIds[0] != 0) SetNavIDAndMoveMouse(g.NavWindow->NavLastIds[0], layer, g.NavWindow->NavRectRel[0]); else @@ -2819,6 +2832,7 @@ static void ImGui::NavUpdateWindowing() { g.NavDisableHighlight = false; g.NavDisableMouseHover = true; + apply_focus_window = NavRestoreLastChildNavWindow(apply_focus_window); FocusWindow(apply_focus_window); if (apply_focus_window->NavLastIds[0] == 0) NavInitWindow(apply_focus_window, false); @@ -2833,8 +2847,14 @@ static void ImGui::NavUpdateWindowing() // Apply menu/layer toggle if (apply_toggle_layer && g.NavWindow) { + // FIXME-NAV: Iterate parent windows to find first one with an active menu layer, instead of aiming at root window immediately if ((g.NavWindow->DC.NavLayerActiveMask & (1 << 1)) == 0 && (g.NavWindow->RootWindow->DC.NavLayerActiveMask & (1 << 1)) != 0) - FocusWindow(g.NavWindow->RootWindow); + { + ImGuiWindow* old_nav_window = g.NavWindow; + ImGuiWindow* new_nav_window = g.NavWindow->RootWindow; + FocusWindow(new_nav_window); + new_nav_window->NavLastChildNavWindow = old_nav_window; + } g.NavDisableHighlight = false; g.NavDisableMouseHover = true; NavRestoreLayer((g.NavWindow->DC.NavLayerActiveMask & (1 << 1)) ? (g.NavLayer ^ 1) : 0); @@ -2945,6 +2965,12 @@ static void ImGui::NavUpdate() g.NavJustTabbedId = 0; IM_ASSERT(g.NavLayer == 0 || g.NavLayer == 1); + // Store our return window (for returning from Layer 1 to Layer 0) and clear it as soon as we step back in our own Layer 0 + if (g.NavWindow && g.NavWindow != g.NavWindow->RootWindow) + g.NavWindow->RootWindow->NavLastChildNavWindow = g.NavWindow; + if (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == 0) + g.NavWindow->NavLastChildNavWindow = NULL; + NavUpdateWindowing(); // Set output flags for user application @@ -4731,10 +4757,10 @@ static ImGuiWindow* GetFrontMostModalRootWindow() static void ClosePopupToLevel(int remaining) { ImGuiContext& g = *GImGui; - if (remaining > 0) - ImGui::FocusWindow(g.OpenPopupStack[remaining-1].Window); - else - ImGui::FocusWindow(g.OpenPopupStack[0].ParentWindow); + ImGuiWindow* focus_window = (remaining > 0) ? g.OpenPopupStack[remaining-1].Window : g.OpenPopupStack[0].ParentWindow; + if (g.NavLayer == 0) + focus_window = NavRestoreLastChildNavWindow(focus_window); + ImGui::FocusWindow(focus_window); g.OpenPopupStack.resize(remaining); } @@ -6210,9 +6236,11 @@ void ImGui::FocusWindow(ImGuiWindow* window) g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId g.NavIdIsAlive = false; g.NavLayer = 0; + g.NavWindow = window; if (window && g.NavDisableMouseHover) g.NavMousePosDirty = true; - g.NavWindow = window; + if (window && window->NavLastChildNavWindow != NULL) + window->NavLastChildNavWindow = NULL; } // Passing NULL allow to disable keyboard focus @@ -6239,7 +6267,8 @@ void ImGui::FocusFrontMostActiveWindow(ImGuiWindow* ignore_window) for (int i = g.Windows.Size - 1; i >= 0; i--) if (g.Windows[i] != ignore_window && g.Windows[i]->WasActive && !(g.Windows[i]->Flags & ImGuiWindowFlags_ChildWindow)) { - FocusWindow(g.Windows[i]); + ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(g.Windows[i]); + FocusWindow(focus_window); return; } } @@ -12994,6 +13023,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImGui::BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f)", window->Scroll.x, GetScrollMaxX(window), window->Scroll.y, GetScrollMaxY(window)); ImGui::BulletText("Active: %d, WriteAccessed: %d", window->Active, window->WriteAccessed); ImGui::BulletText("NavLastIds: 0x%08X,0x%08X, NavLayerActiveMask: %X", window->NavLastIds[0], window->NavLastIds[1], window->DC.NavLayerActiveMask); + ImGui::BulletText("NavLastChildNavWindow: %s", window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL"); ImGui::BulletText("NavRectRel[0]: (%.1f,%.1f)(%.1f,%.1f)", window->NavRectRel[0].Min.x, window->NavRectRel[0].Min.y, window->NavRectRel[0].Max.x, window->NavRectRel[0].Max.y); if (window->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow"); if (window->DC.ChildWindows.Size > 0) NodeWindows(window->DC.ChildWindows, "ChildWindows"); diff --git a/imgui_internal.h b/imgui_internal.h index 7a691cb74..23e6cfc02 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -940,6 +940,7 @@ struct IMGUI_API ImGuiWindow ImGuiWindow* RootNonPopupWindow; // Generally point to ourself. Used to display TitleBgActive color and for selecting which window to use for NavWindowing ImGuiWindow* NavRootWindow; // Generally point to ourself. If we are a child window with the NavFlattened flag, point to a parent window. + ImGuiWindow* NavLastChildNavWindow; // When going to the menu bar, we remember the child window we came from. (This could probably be made implicit if we kept g.Windows sorted by last focused including child window.) ImGuiID NavLastIds[2]; // Last known NavId for this window, per layer (0/1) ImRect NavRectRel[2]; // Reference rectangle, in window relative space