diff --git a/docs/TODO.txt b/docs/TODO.txt index be4ef7cce..b911e9c89 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -9,6 +9,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - doc/test: checklist app to verify binding/integration of imgui (test inputs, rendering, callback, etc.). - doc/tips: tips of the day: website? applet in imgui_club? + - window: preserve/restore relative focus ordering (persistent or not) (#2304) -> also see docking reference to same #. - window: calling SetNextWindowSize() every frame with <= 0 doesn't do anything, may be useful to allow (particularly when used for a single axis). (#690) - window: add a way for very transient windows (non-saved, temporary overlay over hundreds of objects) to "clean" up from the global window list. perhaps a lightweight explicit cleanup pass. - window: auto-fit feedback loop when user relies on any dynamic layout (window width multiplier, column) appears weird to end-user. clarify. @@ -130,6 +131,8 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - splitter/separator: formalize the splitter idiom into an official api (we want to handle n-way split) (#319) - dock: merge docking branch (#2109) + - dock: B: ordering currently held in tab bar should be implicitly held by windows themselves (also see #2304) + - dock: B- tab bar: the order/focus restoring code could be part of TabBar and not DockNode? (#8) - dock: B~ rework code to be able to lazily create tab bar instance in a single place. The _Unsorted tab flag could be replacing a trailing-counter in DockNode? - dock: B~ fully track windows/settings reference in dock nodes. perhaps find a representation that allows facilitate use of dock builder functions. - dock: B~ Unreal style document system (requires low-level controls of dockspace serialization fork/copy/delete). this is mostly working but the DockBuilderXXX api are not exposed/finished. @@ -148,7 +151,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - dock: B- dpi: look at interaction with the hi-dpi and multi-dpi stuff. - dock: B- tab bar: appearing on first frame with a dumb layout would do less harm that not appearing? (when behind dynamic branch) or store titles + render in EndTabBar() - dock: B- tab bar: make selected tab always shows its full title? - - dock: B- tab bar: the order/focus restoring code could be part of TabBar and not DockNode? (#8) - dock: B- nav: design interactions so nav controls can dock/undock - dock: B- dockspace: flag to lock the dock tree and/or sizes (ImGuiDockNodeFlags_Locked?) - dock: B- reintroduce collapsing a floating dock node. also collapsing a docked dock node! diff --git a/imgui.cpp b/imgui.cpp index e54f8e3c4..8d3364b01 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1040,7 +1040,7 @@ static float NavUpdatePageUpPageDown(int allowed_dir_flags); static inline void NavUpdateAnyRequestFlag(); static void NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, ImGuiID id); static ImVec2 NavCalcPreferredRefPos(); -static void NavSaveLastChildNavWindow(ImGuiWindow* nav_window); +static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window); static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window); // Misc @@ -8143,7 +8143,9 @@ void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags mov } } -static void ImGui::NavSaveLastChildNavWindow(ImGuiWindow* nav_window) +// FIXME: This could be replaced by updating a frame number in each window when (window == NavWindow) and (NavLayer == 0). +// This way we could find the last focused window among our children. It would be much less confusing this way? +static void ImGui::NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window) { ImGuiWindow* parent_window = nav_window; while (parent_window && (parent_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (parent_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) @@ -8152,10 +8154,16 @@ static void ImGui::NavSaveLastChildNavWindow(ImGuiWindow* nav_window) parent_window->NavLastChildNavWindow = nav_window; } -// Call when we are expected to land on Layer 0 after FocusWindow() +// Restore the last focused child. +// Call when we are expected to land on the Main Layer (0) after FocusWindow() static ImGuiWindow* ImGui::NavRestoreLastChildNavWindow(ImGuiWindow* window) { - return window->NavLastChildNavWindow ? window->NavLastChildNavWindow : window; + if (window->NavLastChildNavWindow && window->NavLastChildNavWindow->WasActive) + return window->NavLastChildNavWindow; + if (window->DockNodeAsHost && window->DockNodeAsHost->TabBar) + if (ImGuiTabItem* tab = TabBarFindMostRecentlySelectedTabForActiveWindow(window->DockNodeAsHost->TabBar)) + return tab->Window; + return window; } static void NavRestoreLayer(ImGuiNavLayer layer) @@ -8380,7 +8388,7 @@ static void ImGui::NavUpdate() // 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) - NavSaveLastChildNavWindow(g.NavWindow); + NavSaveLastChildNavWindowIntoParent(g.NavWindow); if (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == 0) g.NavWindow->NavLastChildNavWindow = NULL; @@ -8833,7 +8841,7 @@ static void ImGui::NavUpdateWindowing() // Move to parent menu if necessary ImGuiWindow* new_nav_window = g.NavWindow; while (new_nav_window->ParentWindow - && (new_nav_window->DC.NavLayerActiveMask & (1 << 1)) == 0 + && (new_nav_window->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) == 0 && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0) new_nav_window = new_nav_window->ParentWindow; diff --git a/imgui_internal.h b/imgui_internal.h index 89d0df5b8..68c803445 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1707,6 +1707,7 @@ namespace ImGui // Tab Bars IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags, ImGuiDockNode* dock_node); IMGUI_API ImGuiTabItem* TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id); + IMGUI_API ImGuiTabItem* TabBarFindMostRecentlySelectedTabForActiveWindow(ImGuiTabBar* tab_bar); IMGUI_API void TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiTabItemFlags tab_flags, ImGuiWindow* window); IMGUI_API void TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id); IMGUI_API void TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 031a9fd84..3dcb50967 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6455,6 +6455,20 @@ ImGuiTabItem* ImGui::TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id) return NULL; } +// FIXME: See references to #2304 in TODO.txt +ImGuiTabItem* ImGui::TabBarFindMostRecentlySelectedTabForActiveWindow(ImGuiTabBar* tab_bar) +{ + ImGuiTabItem* most_recently_selected_tab = NULL; + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) + { + ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; + if (most_recently_selected_tab == NULL || most_recently_selected_tab->LastFrameSelected < tab->LastFrameSelected) + if (tab->Window && tab->Window->WasActive) + most_recently_selected_tab = tab; + } + return most_recently_selected_tab; +} + // The purpose of this call is to register tab in advance so we can control their order at the time they appear. // Otherwise calling this is unnecessary as tabs are appending as needed by the BeginTabItem() function. void ImGui::TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiTabItemFlags tab_flags, ImGuiWindow* window)