Browse Source

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

omar 6 years ago
parent
commit
9e294be5c5
2 changed files with 50 additions and 0 deletions
  1. 41 0
      imgui.cpp
  2. 9 0
      imgui_internal.h

+ 41 - 0
imgui.cpp

@@ -11206,6 +11206,7 @@ namespace ImGui
     static void             DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window, bool add_to_tab_bar);
     static void             DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window, bool add_to_tab_bar);
     static void             DockNodeMoveWindows(ImGuiDockNode* dst_node, ImGuiDockNode* src_node);
     static void             DockNodeMoveWindows(ImGuiDockNode* dst_node, ImGuiDockNode* src_node);
     static void             DockNodeMoveChildNodes(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             DockNodeApplyPosSizeToWindows(ImGuiDockNode* node);
     static void             DockNodeRemoveWindow(ImGuiDockNode* node, ImGuiWindow* window, ImGuiID save_dock_id);
     static void             DockNodeRemoveWindow(ImGuiDockNode* node, ImGuiWindow* window, ImGuiID save_dock_id);
     static void             DockNodeHideHostWindow(ImGuiDockNode* node);
     static void             DockNodeHideHostWindow(ImGuiDockNode* node);
@@ -11846,6 +11847,7 @@ bool ImGui::DockContextCalcDropPosForDocking(ImGuiWindow* target, ImGuiDockNode*
 // - DockNodeHideHostWindow()
 // - DockNodeHideHostWindow()
 // - ImGuiDockNodeFindInfoResults
 // - ImGuiDockNodeFindInfoResults
 // - DockNodeFindInfo()
 // - DockNodeFindInfo()
+// - DockNodeFindWindowByID()
 // - DockNodeUpdateVisibleFlagAndInactiveChilds()
 // - DockNodeUpdateVisibleFlagAndInactiveChilds()
 // - DockNodeUpdateVisibleFlag()
 // - DockNodeUpdateVisibleFlag()
 // - DockNodeStartMouseMovingWindow()
 // - DockNodeStartMouseMovingWindow()
@@ -11871,6 +11873,7 @@ ImGuiDockNode::ImGuiDockNode(ImGuiID id)
     TabBar = NULL;
     TabBar = NULL;
     SplitAxis = ImGuiAxis_None;
     SplitAxis = ImGuiAxis_None;
 
 
+    State = ImGuiDockNodeState_Unknown;
     HostWindow = VisibleWindow = NULL;
     HostWindow = VisibleWindow = NULL;
     CentralNode = OnlyNodeWithWindows = NULL;
     CentralNode = OnlyNodeWithWindows = NULL;
     LastFrameAlive = LastFrameActive = LastFrameFocused = -1;
     LastFrameAlive = LastFrameActive = LastFrameFocused = -1;
@@ -12131,6 +12134,15 @@ static void DockNodeFindInfo(ImGuiDockNode* node, ImGuiDockNodeFindInfoResults*
         DockNodeFindInfo(node->ChildNodes[1], results);
         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.
 // - Remove inactive windows/nodes.
 // - Update visibility flag.
 // - Update visibility flag.
 static void ImGui::DockNodeUpdateVisibleFlagAndInactiveChilds(ImGuiDockNode* node)
 static void ImGui::DockNodeUpdateVisibleFlagAndInactiveChilds(ImGuiDockNode* node)
@@ -12169,6 +12181,7 @@ static void ImGui::DockNodeUpdateVisibleFlagAndInactiveChilds(ImGuiDockNode* nod
         if (node->Windows.Size == 1 && !node->IsCentralNode())
         if (node->Windows.Size == 1 && !node->IsCentralNode())
         {
         {
             DockNodeHideHostWindow(node);
             DockNodeHideHostWindow(node);
+            node->State = ImGuiDockNodeState_HostWindowHiddenBecauseSingleWindow;
             DockNodeRemoveWindow(node, window, node->ID); // Will delete the node so it'll be invalid on return
             DockNodeRemoveWindow(node, window, node->ID); // Will delete the node so it'll be invalid on return
             return;
             return;
         }
         }
@@ -12285,6 +12298,7 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node)
         }
         }
 
 
         DockNodeHideHostWindow(node);
         DockNodeHideHostWindow(node);
+        node->State = ImGuiDockNodeState_HostWindowHiddenBecauseSingleWindow;
         node->WantCloseAll = false;
         node->WantCloseAll = false;
         node->WantCloseTabID = 0;
         node->WantCloseTabID = 0;
         node->HasCloseButton = node->HasWindowMenuButton = node->EnableCloseButton = false;
         node->HasCloseButton = node->HasWindowMenuButton = node->EnableCloseButton = false;
@@ -12295,6 +12309,31 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node)
         return;
         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();
     const ImGuiDockNodeFlags node_flags = node->GetMergedFlags();
 
 
     // Bind or create host window
     // 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)
     // FIXME-DOCK: replace ->HostWindow NULL compare with something more explicit (~was initially intended as a first frame test)
     if (node->HostWindow == NULL)
     if (node->HostWindow == NULL)
     {
     {
+        window->DockIsActive = (node->State == ImGuiDockNodeState_HostWindowHiddenBecauseWindowsAreResizing);
         window->DockTabIsVisible = false;
         window->DockTabIsVisible = false;
         return;
         return;
     }
     }
@@ -14168,6 +14208,7 @@ void ImGui::BeginDocked(ImGuiWindow* window, bool* p_open)
     IM_ASSERT(node->HostWindow);
     IM_ASSERT(node->HostWindow);
     IM_ASSERT(node->IsLeafNode());
     IM_ASSERT(node->IsLeafNode());
     IM_ASSERT(node->Size.x > 0.0f && node->Size.y > 0.0f);
     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
     // Undock if we are submitted earlier than the host window
     if (window->BeginOrderWithinContext < node->HostWindow->BeginOrderWithinContext)
     if (window->BeginOrderWithinContext < node->HostWindow->BeginOrderWithinContext)

+ 9 - 0
imgui_internal.h

@@ -929,6 +929,14 @@ enum ImGuiDataAuthority_
     ImGuiDataAuthority_Window
     ImGuiDataAuthority_Window
 };
 };
 
 
+enum ImGuiDockNodeState
+{
+    ImGuiDockNodeState_Unknown,
+    ImGuiDockNodeState_HostWindowHiddenBecauseSingleWindow,
+    ImGuiDockNodeState_HostWindowHiddenBecauseWindowsAreResizing,
+    ImGuiDockNodeState_HostWindowVisible
+};
+
 // sizeof() 116~160
 // sizeof() 116~160
 struct ImGuiDockNode
 struct ImGuiDockNode
 {
 {
@@ -945,6 +953,7 @@ struct ImGuiDockNode
     int                     SplitAxis;                  // [Split node only] Split axis (X or Y)
     int                     SplitAxis;                  // [Split node only] Split axis (X or Y)
     ImGuiWindowClass        WindowClass;
     ImGuiWindowClass        WindowClass;
 
 
+    ImGuiDockNodeState      State;
     ImGuiWindow*            HostWindow;
     ImGuiWindow*            HostWindow;
     ImGuiWindow*            VisibleWindow;              // Generally point to window which is ID is == SelectedTabID, but when CTRL+Tabbing this can be a different window.
     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.
     ImGuiDockNode*          CentralNode;                // [Root node only] Pointer to central node.