From 9e294be5c56848b9da7d55d67228edbe602affc0 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 21 Aug 2019 15:07:28 +0200 Subject: [PATCH] Docking: Fix for node created at the same time as windows that are still resizing (typically with io.ConfigDockingAlwaysTabBar) to not be zero/min sized. (#2109) The fix delay their visibility by one frame, which is not ideal but not very problematic as the .ini data gets populated after that --- imgui.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ imgui_internal.h | 9 +++++++++ 2 files changed, 50 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index f2f4f3fd..4b324a67 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -11206,6 +11206,7 @@ namespace ImGui static void DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window, bool add_to_tab_bar); static void DockNodeMoveWindows(ImGuiDockNode* dst_node, ImGuiDockNode* src_node); static void DockNodeMoveChildNodes(ImGuiDockNode* dst_node, ImGuiDockNode* src_node); + static ImGuiWindow* DockNodeFindWindowByID(ImGuiDockNode* node, ImGuiID id); static void DockNodeApplyPosSizeToWindows(ImGuiDockNode* node); static void DockNodeRemoveWindow(ImGuiDockNode* node, ImGuiWindow* window, ImGuiID save_dock_id); static void DockNodeHideHostWindow(ImGuiDockNode* node); @@ -11846,6 +11847,7 @@ bool ImGui::DockContextCalcDropPosForDocking(ImGuiWindow* target, ImGuiDockNode* // - DockNodeHideHostWindow() // - ImGuiDockNodeFindInfoResults // - DockNodeFindInfo() +// - DockNodeFindWindowByID() // - DockNodeUpdateVisibleFlagAndInactiveChilds() // - DockNodeUpdateVisibleFlag() // - DockNodeStartMouseMovingWindow() @@ -11871,6 +11873,7 @@ ImGuiDockNode::ImGuiDockNode(ImGuiID id) TabBar = NULL; SplitAxis = ImGuiAxis_None; + State = ImGuiDockNodeState_Unknown; HostWindow = VisibleWindow = NULL; CentralNode = OnlyNodeWithWindows = NULL; LastFrameAlive = LastFrameActive = LastFrameFocused = -1; @@ -12131,6 +12134,15 @@ static void DockNodeFindInfo(ImGuiDockNode* node, ImGuiDockNodeFindInfoResults* DockNodeFindInfo(node->ChildNodes[1], results); } +static ImGuiWindow* ImGui::DockNodeFindWindowByID(ImGuiDockNode* node, ImGuiID id) +{ + IM_ASSERT(id != 0); + for (int n = 0; n < node->Windows.Size; n++) + if (node->Windows[n]->ID == id) + return node->Windows[n]; + return NULL; +} + // - Remove inactive windows/nodes. // - Update visibility flag. static void ImGui::DockNodeUpdateVisibleFlagAndInactiveChilds(ImGuiDockNode* node) @@ -12169,6 +12181,7 @@ static void ImGui::DockNodeUpdateVisibleFlagAndInactiveChilds(ImGuiDockNode* nod if (node->Windows.Size == 1 && !node->IsCentralNode()) { DockNodeHideHostWindow(node); + node->State = ImGuiDockNodeState_HostWindowHiddenBecauseSingleWindow; DockNodeRemoveWindow(node, window, node->ID); // Will delete the node so it'll be invalid on return return; } @@ -12285,6 +12298,7 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node) } DockNodeHideHostWindow(node); + node->State = ImGuiDockNodeState_HostWindowHiddenBecauseSingleWindow; node->WantCloseAll = false; node->WantCloseTabID = 0; node->HasCloseButton = node->HasWindowMenuButton = node->EnableCloseButton = false; @@ -12295,6 +12309,31 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node) return; } + // In some circumstance we will defer creating the host window (so everything will be kept hidden), + // while the expected visible window is resizing itself. + // This is important for first-time (no ini settings restored) single window when io.ConfigDockingAlwaysTabBar is enabled, + // otherwise the node ends up using the minimum window size. Effectively those windows will take an extra frame to show up: + // N+0: Begin(): window created (with no known size), node is created + // N+1: DockNodeUpdate(): node skip creating host window / Begin(): window size applied, not visible + // N+2: DockNodeUpdate(): node can create host window / Begin(): window becomes visible + // We could remove this frame if we could reliably calculate the expected window size during node update, before the Begin() code. + // It would require a generalization of CalcWindowExpectedSize(), probably extracting code away from Begin(). + // In reality it isn't very important as user quickly ends up with size data in .ini file. + if (node->IsVisible && node->HostWindow == NULL && node->IsFloatingNode() && node->IsLeafNode()) + { + IM_ASSERT(node->Windows.Size > 0); + ImGuiWindow* ref_window = NULL; + if (node->SelectedTabID != 0) // Note that we prune single-window-node settings on .ini loading, so this is generally 0 for them! + ref_window = DockNodeFindWindowByID(node, node->SelectedTabID); + if (ref_window == NULL) + ref_window = node->Windows[0]; + if (ref_window->AutoFitFramesX > 0 || ref_window->AutoFitFramesY > 0) + { + node->State = ImGuiDockNodeState_HostWindowHiddenBecauseWindowsAreResizing; + return; + } + } + const ImGuiDockNodeFlags node_flags = node->GetMergedFlags(); // Bind or create host window @@ -14161,6 +14200,7 @@ void ImGui::BeginDocked(ImGuiWindow* window, bool* p_open) // FIXME-DOCK: replace ->HostWindow NULL compare with something more explicit (~was initially intended as a first frame test) if (node->HostWindow == NULL) { + window->DockIsActive = (node->State == ImGuiDockNodeState_HostWindowHiddenBecauseWindowsAreResizing); window->DockTabIsVisible = false; return; } @@ -14168,6 +14208,7 @@ void ImGui::BeginDocked(ImGuiWindow* window, bool* p_open) IM_ASSERT(node->HostWindow); IM_ASSERT(node->IsLeafNode()); IM_ASSERT(node->Size.x > 0.0f && node->Size.y > 0.0f); + node->State = ImGuiDockNodeState_HostWindowVisible; // Undock if we are submitted earlier than the host window if (window->BeginOrderWithinContext < node->HostWindow->BeginOrderWithinContext) diff --git a/imgui_internal.h b/imgui_internal.h index aad0bb77..54c5bc51 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -929,6 +929,14 @@ enum ImGuiDataAuthority_ ImGuiDataAuthority_Window }; +enum ImGuiDockNodeState +{ + ImGuiDockNodeState_Unknown, + ImGuiDockNodeState_HostWindowHiddenBecauseSingleWindow, + ImGuiDockNodeState_HostWindowHiddenBecauseWindowsAreResizing, + ImGuiDockNodeState_HostWindowVisible +}; + // sizeof() 116~160 struct ImGuiDockNode { @@ -945,6 +953,7 @@ struct ImGuiDockNode int SplitAxis; // [Split node only] Split axis (X or Y) ImGuiWindowClass WindowClass; + ImGuiDockNodeState State; ImGuiWindow* HostWindow; ImGuiWindow* VisibleWindow; // Generally point to window which is ID is == SelectedTabID, but when CTRL+Tabbing this can be a different window. ImGuiDockNode* CentralNode; // [Root node only] Pointer to central node.