Docking: Fix so that an appearing window making a dock node reappear won't have a zero-size on its first frame (because dock node ->Size was 0.0 unlike ->SizeRef) (#2109)
Docking: Added ImGuiDockNode to .natvis file.
diff --git a/imgui.cpp b/imgui.cpp
index 2751c76..aa5a31f 100644
--- a/imgui.cpp
+++ b/imgui.cpp
@@ -11373,7 +11373,7 @@
     // ImGuiDockNode tree manipulations
     static void             DockNodeTreeSplit(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImGuiAxis split_axis, int split_first_child, float split_ratio, ImGuiDockNode* new_node);
     static void             DockNodeTreeMerge(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImGuiDockNode* merge_lead_child);
-    static void             DockNodeTreeUpdatePosSize(ImGuiDockNode* node, ImVec2 pos, ImVec2 size);
+    static void             DockNodeTreeUpdatePosSize(ImGuiDockNode* node, ImVec2 pos, ImVec2 size, bool only_write_to_marked_nodes = false);
     static void             DockNodeTreeUpdateSplitter(ImGuiDockNode* node);
     static ImGuiDockNode*   DockNodeTreeFindNodeByPos(ImGuiDockNode* node, ImVec2 pos);
     static ImGuiDockNode*   DockNodeTreeFindFallbackLeafNode(ImGuiDockNode* node);
@@ -11953,6 +11953,7 @@
     IsVisible = true;
     IsFocused = HasCloseButton = HasWindowMenuButton = EnableCloseButton = false;
     WantCloseAll = WantLockSizeOnce = WantMouseMove = WantHiddenTabBarUpdate = WantHiddenTabBarToggle = false;
+    MarkedForPosSizeWrite = false;
 }
 
 ImGuiDockNode::~ImGuiDockNode()
@@ -12286,6 +12287,7 @@
     ImGuiContext& g = *GImGui;
     IM_ASSERT(node->LastFrameActive != g.FrameCount);
     node->LastFrameAlive = g.FrameCount;
+    node->MarkedForPosSizeWrite = false;
 
     node->CentralNode = node->OnlyNodeWithWindows = NULL;
     if (node->IsRootNode())
@@ -12533,6 +12535,7 @@
     node->LastFrameActive = g.FrameCount;
 
     // Recurse into children
+    // FIXME-DOCK FIXME-OPT: Should not need to recurse into children
     if (host_window)
     {
         if (node->ChildNodes[0])
@@ -13265,10 +13268,17 @@
 }
 
 // Update Pos/Size for a node hierarchy (don't affect child Windows yet)
-void ImGui::DockNodeTreeUpdatePosSize(ImGuiDockNode* node, ImVec2 pos, ImVec2 size)
+void ImGui::DockNodeTreeUpdatePosSize(ImGuiDockNode* node, ImVec2 pos, ImVec2 size, bool only_write_to_marked_nodes)
 {
-    node->Pos = pos;
-    node->Size = size;
+    // During the regular dock node update we write to all nodes.
+    // 'only_write_to_marked_nodes' is only set when turning a node visible mid-frame and we need its size right-away.
+    const bool write_to_node = (only_write_to_marked_nodes == false) || (node->MarkedForPosSizeWrite);
+    if (write_to_node)
+    {
+        node->Pos = pos;
+        node->Size = size;
+    }
+
     if (node->IsLeafNode())
         return;
 
@@ -14082,6 +14092,25 @@
                 node->LastFrameAlive = g.FrameCount;
         }
 
+        // If the node just turned visible, it doesn't have a Size assigned by DockNodeTreeUpdatePosSize() yet,
+        // so we're forcing a Pos/Size update from the first ancestor that is already visible (often it will be the root node).
+        // If we don't do this, the window will be assigned a zero-size on its first frame, which won't ideally warm up the layout.
+        // This is a little wonky because we don't normally update the Pos/Size of visible node mid-frame.
+        if (!node->IsVisible)
+        {
+            ImGuiDockNode* ancestor_node = node;
+            while (!ancestor_node->IsVisible)
+            {
+                ancestor_node->IsVisible = true;
+                ancestor_node->MarkedForPosSizeWrite = true;
+                if (ancestor_node->ParentNode)
+                    ancestor_node = ancestor_node->ParentNode;
+            }
+            IM_ASSERT(ancestor_node->Size.x > 0.0f && ancestor_node->Size.y > 0.0f);
+            DockNodeTreeUpdatePosSize(ancestor_node, ancestor_node->Pos, ancestor_node->Size, true);
+        }
+
+        // Add window to node
         DockNodeAddWindow(node, window, true);
         IM_ASSERT(node == window->DockNode);
     }
@@ -14128,6 +14157,7 @@
     }
     IM_ASSERT(node->HostWindow);
     IM_ASSERT(node->IsLeafNode());
+    IM_ASSERT(node->Size.x > 0.0f && node->Size.y > 0.0f);
 
     // Position window
     SetNextWindowPos(node->Pos);
diff --git a/imgui_internal.h b/imgui_internal.h
index 265292a..44dff1e 100644
--- a/imgui_internal.h
+++ b/imgui_internal.h
@@ -956,6 +956,7 @@
     bool                    WantMouseMove           :1; // After a node extraction we need to transition toward moving the newly created host window
     bool                    WantHiddenTabBarUpdate  :1;
     bool                    WantHiddenTabBarToggle  :1;
+    bool                    MarkedForPosSizeWrite   :1; // Update by DockNodeTreeUpdatePosSize() write-filtering
 
     ImGuiDockNode(ImGuiID id);
     ~ImGuiDockNode();
diff --git a/misc/natvis/imgui.natvis b/misc/natvis/imgui.natvis
index cc768bf..f1082a8 100644
--- a/misc/natvis/imgui.natvis
+++ b/misc/natvis/imgui.natvis
@@ -35,5 +35,9 @@
 <Type Name="ImGuiWindow">
   <DisplayString>{{Name {Name,s} Active {(Active||WasActive)?1:0,d} Child {(Flags &amp; 0x01000000)?1:0,d} Popup {(Flags &amp; 0x04000000)?1:0,d} Hidden {(Hidden)?1:0,d}}</DisplayString>
 </Type>
+
+<Type Name="ImGuiDockNode">
+  <DisplayString>{{ID {ID,x} Pos=({Pos.x,g} {Pos.y,g}) Size=({Size.x,g} {Size.y,g}) Parent {(ParentNode==0)?0:ParentNode->ID,x} Childs {(ChildNodes[0] != 0)+(ChildNodes[1] != 0)} Windows {Windows.Size}  }</DisplayString>
+</Type>
   
 </AutoVisualizer>
\ No newline at end of file