소스 검색

Docking: Better tracking of current dock id for inactive and uncreated windows (in settings etc.). + Fixed assert when docking a single-visible leaf node of a hierarchy into another

omar 7 년 전
부모
커밋
b48ed9ebc0
2개의 변경된 파일57개의 추가작업 그리고 26개의 파일을 삭제
  1. 1 0
      docs/TODO.txt
  2. 56 26
      imgui.cpp

+ 1 - 0
docs/TODO.txt

@@ -148,6 +148,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
  - dock: B- reintroduce collapsing a floating dock node. also collapsing a docked dock node!
  - dock: B- reintroduce collapsing a floating dock node. also collapsing a docked dock node!
  - dock: B- allow dragging a non-floating dock node by clicking on the title-bar-looking section (not just the collapse/menu button)
  - dock: B- allow dragging a non-floating dock node by clicking on the title-bar-looking section (not just the collapse/menu button)
  - dock: C- nav: CTRL+TAB highlighting tabs shows the mismatch between focus-stack and tab-order (not visible in VS because it doesn't highlight the tabs)
  - dock: C- nav: CTRL+TAB highlighting tabs shows the mismatch between focus-stack and tab-order (not visible in VS because it doesn't highlight the tabs)
+ - dock: C- after a dock/undock, the Scrollbar Status update in Begin() should use an updated e.g. size_y_for_scrollbars to avoid a 1 frame scrollbar flicker.
 
 
  - tabs: re-ordering, close buttons, context menu, persistent order (#261, #351)
  - tabs: re-ordering, close buttons, context menu, persistent order (#261, #351)
 
 

+ 56 - 26
imgui.cpp

@@ -3819,7 +3819,8 @@ void ImGui::EndFrame()
         AddWindowToSortBuffer(&g.WindowsSortBuffer, window);
         AddWindowToSortBuffer(&g.WindowsSortBuffer, window);
     }
     }
 
 
-    IM_ASSERT(g.Windows.Size == g.WindowsSortBuffer.Size);  // we done something wrong
+    // This usually assert if there is a mismatch between the ImGuiWindowFlags_ChildWindow / ParentWindow values and DC.ChildWindows[] in parents, aka we've done something wrong.
+    IM_ASSERT(g.Windows.Size == g.WindowsSortBuffer.Size);
     g.Windows.swap(g.WindowsSortBuffer);
     g.Windows.swap(g.WindowsSortBuffer);
     g.IO.MetricsActiveWindows = g.WindowsActiveCount;
     g.IO.MetricsActiveWindows = g.WindowsActiveCount;
 
 
@@ -9677,6 +9678,7 @@ namespace ImGui
     static ImGuiDockNode*   DockNodeTreeFindNodeByPos(ImGuiDockNode* node, ImVec2 pos);
     static ImGuiDockNode*   DockNodeTreeFindNodeByPos(ImGuiDockNode* node, ImVec2 pos);
 
 
     // Settings
     // Settings
+    static void             DockSettingsMoveDockReferencesInInactiveWindow(ImGuiID old_dock_id, ImGuiID new_dock_id);
     static void             DockSettingsRemoveReferencesToNodes(ImGuiID* node_ids, int node_ids_count);
     static void             DockSettingsRemoveReferencesToNodes(ImGuiID* node_ids, int node_ids_count);
     static ImGuiDockNodeSettings*   DockSettingsFindNodeSettings(ImGuiContext* ctx, ImGuiID node_id);
     static ImGuiDockNodeSettings*   DockSettingsFindNodeSettings(ImGuiContext* ctx, ImGuiID node_id);
     static void*            DockSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name);
     static void*            DockSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name);
@@ -9951,7 +9953,7 @@ static void ImGui::DockContextBuildNodesFromSettings(ImGuiContext* ctx, ImGuiDoc
 
 
         // Bind host window immediately if it already exist (in case of a rebuild)
         // Bind host window immediately if it already exist (in case of a rebuild)
         // This is useful as the RootWindowForTitleBarHighlight links necessary to highlight the currently focused node requires node->HostWindow to be set.
         // This is useful as the RootWindowForTitleBarHighlight links necessary to highlight the currently focused node requires node->HostWindow to be set.
-        char host_window_title[32];
+        char host_window_title[20];
         ImGuiDockNode* root_node = DockNodeGetRootNode(node);
         ImGuiDockNode* root_node = DockNodeGetRootNode(node);
         node->HostWindow = FindWindowByName(DockNodeGetHostWindowTitle(root_node, host_window_title, IM_ARRAYSIZE(host_window_title)));
         node->HostWindow = FindWindowByName(DockNodeGetHostWindowTitle(root_node, host_window_title, IM_ARRAYSIZE(host_window_title)));
     }
     }
@@ -10090,25 +10092,24 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req)
                 TabBarAddTab(target_node->TabBar, target_node->Windows[n], ImGuiTabItemFlags_None);
                 TabBarAddTab(target_node->TabBar, target_node->Windows[n], ImGuiTabItemFlags_None);
         }
         }
 
 
+        const ImGuiID payload_node_id = payload_node ? payload_node->ID : payload_window->DockId;
         if (payload_node != NULL)
         if (payload_node != NULL)
         {
         {
             // Transfer full payload node (with 1+ child windows or child nodes)
             // Transfer full payload node (with 1+ child windows or child nodes)
-            // FIXME-DOCK: Transition persistent DockId for all non-active windows
             if (payload_node->IsSplitNode())
             if (payload_node->IsSplitNode())
             {
             {
                 if (target_node->Windows.Size > 0)
                 if (target_node->Windows.Size > 0)
                 {
                 {
                     // We can dock into a node that already has windows _only_ if our payload is a node tree with a single visible node.
                     // We can dock into a node that already has windows _only_ if our payload is a node tree with a single visible node.
                     // In this situation, we move the windows of the target node into the currently visible node of the payload.
                     // In this situation, we move the windows of the target node into the currently visible node of the payload.
-                    // This allows us to preserve some of the underlying settings nicely.
-                    IM_ASSERT(payload_node->OnlyNodeWithWindows != NULL);
+                    // This allows us to preserve some of the underlying dock tree settings nicely.
+                    IM_ASSERT(payload_node->OnlyNodeWithWindows != NULL); // The docking should have been blocked by DockNodePreviewDockCalc() early on and never submitted.
                     ImGuiDockNode* visible_node = payload_node->OnlyNodeWithWindows;
                     ImGuiDockNode* visible_node = payload_node->OnlyNodeWithWindows;
                     if (visible_node->TabBar)
                     if (visible_node->TabBar)
                         IM_ASSERT(visible_node->TabBar->Tabs.Size > 0);
                         IM_ASSERT(visible_node->TabBar->Tabs.Size > 0);
-                    for (int n = 0; n < visible_node->Windows.Size; n++)
-                        TabBarAddTab(target_node->TabBar, visible_node->Windows[n], ImGuiTabItemFlags_None);
                     DockNodeMoveWindows(target_node, visible_node);
                     DockNodeMoveWindows(target_node, visible_node);
                     DockNodeMoveWindows(visible_node, target_node);
                     DockNodeMoveWindows(visible_node, target_node);
+                    DockSettingsMoveDockReferencesInInactiveWindow(target_node->ID, visible_node->ID);
                 }
                 }
                 IM_ASSERT(target_node->Windows.Size == 0);
                 IM_ASSERT(target_node->Windows.Size == 0);
                 DockNodeMoveChildNodes(target_node, payload_node);
                 DockNodeMoveChildNodes(target_node, payload_node);
@@ -10116,6 +10117,7 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req)
             else
             else
             {
             {
                 DockNodeMoveWindows(target_node, payload_node);
                 DockNodeMoveWindows(target_node, payload_node);
+                DockSettingsMoveDockReferencesInInactiveWindow(payload_node_id, target_node->ID);
             }
             }
             DockContextRemoveNode(ctx, payload_node, true);
             DockContextRemoveNode(ctx, payload_node, true);
         }
         }
@@ -10124,6 +10126,8 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req)
             // Transfer single window
             // Transfer single window
             target_node->VisibleWindow = payload_window;
             target_node->VisibleWindow = payload_window;
             DockNodeAddWindow(target_node, payload_window, true);
             DockNodeAddWindow(target_node, payload_window, true);
+            if (payload_node_id != 0)
+                DockSettingsMoveDockReferencesInInactiveWindow(payload_node_id, target_node->ID);
         }
         }
     }
     }
 
 
@@ -10156,9 +10160,9 @@ void ImGui::DockContextProcessUndockNode(ImGuiContext* ctx, ImGuiDockNode* node)
     // Otherwise delete the previous node by merging the other sibling back into the parent node.
     // Otherwise delete the previous node by merging the other sibling back into the parent node.
     if (node->IsRootNode() || node->IsDocumentRoot)
     if (node->IsRootNode() || node->IsDocumentRoot)
     {
     {
-        // FIXME-DOCK: Transition persistent DockId for all non-active windows
         ImGuiDockNode* new_node = DockContextAddNode(ctx, 0);
         ImGuiDockNode* new_node = DockContextAddNode(ctx, 0);
         DockNodeMoveWindows(new_node, node);
         DockNodeMoveWindows(new_node, node);
+        DockSettingsMoveDockReferencesInInactiveWindow(node->ID, new_node->ID);
         for (int n = 0; n < new_node->Windows.Size; n++)
         for (int n = 0; n < new_node->Windows.Size; n++)
             UpdateWindowParentAndRootLinks(new_node->Windows[n], new_node->Windows[n]->Flags, NULL);
             UpdateWindowParentAndRootLinks(new_node->Windows[n], new_node->Windows[n]->Flags, NULL);
         new_node->WantMouseMove = true;
         new_node->WantMouseMove = true;
@@ -10516,25 +10520,28 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node)
         }
         }
     }
     }
 
 
-    // Early out for standalone floating window that are holding on a DockId (with an invisible dock node)
-    if (node->IsRootNode() && node->Windows.Size == 1 && !node->IsDockSpace)
+    // Early out for hidden root dock nodes (when all DockId references are in inactive windows, or there is only 1 floating window holding on the DockId)
+    if (node->IsRootNode() && !node->IsSplitNode() && node->Windows.Size <= 1 && !node->IsDockSpace)
     {
     {
-        // Floating window pos/size is authoritative
-        ImGuiWindow* single_window = node->Windows[0];
-        node->Pos = single_window->Pos;
-        node->Size = single_window->SizeFull;
-
-        // Transfer focus immediately so when we revert to a regular window it is immediately selected
-        if (node->HostWindow && g.NavWindow == node->HostWindow)
-            FocusWindow(single_window);
-        if (node->HostWindow)
+        if (node->Windows.Size == 1)
         {
         {
-            single_window->Viewport = node->HostWindow->Viewport;
-            single_window->ViewportId = node->HostWindow->ViewportId;
-            if (node->HostWindow->ViewportOwned)
+            // Floating window pos/size is authoritative
+            ImGuiWindow* single_window = node->Windows[0];
+            node->Pos = single_window->Pos;
+            node->Size = single_window->SizeFull;
+
+            // Transfer focus immediately so when we revert to a regular window it is immediately selected
+            if (node->HostWindow && g.NavWindow == node->HostWindow)
+                FocusWindow(single_window);
+            if (node->HostWindow)
             {
             {
-                single_window->Viewport->Window = single_window;
-                single_window->ViewportOwned = true;
+                single_window->Viewport = node->HostWindow->Viewport;
+                single_window->ViewportId = node->HostWindow->ViewportId;
+                if (node->HostWindow->ViewportOwned)
+                {
+                    single_window->Viewport->Window = single_window;
+                    single_window->ViewportOwned = true;
+                }
             }
             }
         }
         }
 
 
@@ -10545,8 +10552,8 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node)
         node->HasCloseButton = node->HasCollapseButton = false;
         node->HasCloseButton = node->HasCollapseButton = false;
         node->LastFrameActive = g.FrameCount;
         node->LastFrameActive = g.FrameCount;
 
 
-        if (node->WantMouseMove)
-            DockNodeStartMouseMovingWindow(node, single_window);
+        if (node->WantMouseMove && node->Windows.Size == 1)
+            DockNodeStartMouseMovingWindow(node, node->Windows[0]);
         return;
         return;
     }
     }
 
 
@@ -11222,9 +11229,15 @@ void ImGui::DockNodeTreeMerge(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImG
     ImVec2 backup_last_explicit_size = parent_node->SizeRef;
     ImVec2 backup_last_explicit_size = parent_node->SizeRef;
     DockNodeMoveChildNodes(parent_node, merge_lead_child);
     DockNodeMoveChildNodes(parent_node, merge_lead_child);
     if (child_0)
     if (child_0)
+    {
         DockNodeMoveWindows(parent_node, child_0); // Generally only 1 of the 2 child node will have windows
         DockNodeMoveWindows(parent_node, child_0); // Generally only 1 of the 2 child node will have windows
+        DockSettingsMoveDockReferencesInInactiveWindow(child_0->ID, parent_node->ID);
+    }
     if (child_1)
     if (child_1)
+    {
         DockNodeMoveWindows(parent_node, child_1);
         DockNodeMoveWindows(parent_node, child_1);
+        DockSettingsMoveDockReferencesInInactiveWindow(child_1->ID, parent_node->ID);
+    }
     DockNodeApplyPosSizeToWindows(parent_node);
     DockNodeApplyPosSizeToWindows(parent_node);
     parent_node->InitFromFirstWindowPosSize = parent_node->InitFromFirstWindowViewport = false;
     parent_node->InitFromFirstWindowPosSize = parent_node->InitFromFirstWindowViewport = false;
     parent_node->VisibleWindow = merge_lead_child->VisibleWindow;
     parent_node->VisibleWindow = merge_lead_child->VisibleWindow;
@@ -12065,6 +12078,23 @@ void ImGui::BeginAsDockableDragDropTarget(ImGuiWindow* window)
 // Docking: Settings
 // Docking: Settings
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
+static void ImGui::DockSettingsMoveDockReferencesInInactiveWindow(ImGuiID old_dock_id, ImGuiID new_dock_id)
+{
+    ImGuiContext& g = *GImGui;
+    for (int window_n = 0; window_n < g.Windows.Size; window_n++)
+    {
+        ImGuiWindow* window = g.Windows[window_n];
+        if (window->DockId == old_dock_id && window->DockNode == NULL)
+            window->DockId = new_dock_id;
+    }
+    for (int settings_n = 0; settings_n < g.SettingsWindows.Size; settings_n++)     // FIXME-OPT: We could remove this loop by storing the index in the map
+    {
+        ImGuiWindowSettings* window_settings = &g.SettingsWindows[settings_n];
+        if (window_settings->DockId == old_dock_id)
+            window_settings->DockId = new_dock_id;
+    }
+}
+
 // Remove references stored in ImGuiWindowSettings to the given ImGuiDockNodeSettings
 // Remove references stored in ImGuiWindowSettings to the given ImGuiDockNodeSettings
 static void ImGui::DockSettingsRemoveReferencesToNodes(ImGuiID* node_ids, int node_ids_count)
 static void ImGui::DockSettingsRemoveReferencesToNodes(ImGuiID* node_ids, int node_ids_count)
 {
 {