diff --git a/imgui.cpp b/imgui.cpp index 094e1198e..64945f2a6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9874,94 +9874,6 @@ static int IMGUI_CDECL DockNodeComparerDepthMostFirst(const void* lhs, const voi return ImGui::DockNodeGetDepth(b) - ImGui::DockNodeGetDepth(a); } -void ImGui::DockBuilderRemoveNodeChildNodes(ImGuiContext* ctx, ImGuiID root_id) -{ - ImGuiDockContext* dc = ctx->DockContext; - - ImGuiDockNode* root_node = root_id ? DockContextFindNodeByID(ctx, root_id) : NULL; - if (root_id && root_node == NULL) - return; - bool has_document_root = false; - - // Process active windows - ImVector nodes_to_remove; - for (int n = 0; n < dc->Nodes.Data.Size; n++) - if (ImGuiDockNode* node = (ImGuiDockNode*)dc->Nodes.Data[n].val_p) - { - bool want_removal = (root_id == 0) || (node->ID != root_id && DockNodeGetRootNode(node)->ID == root_id); - if (want_removal) - { - if (node->IsDocumentRoot) - has_document_root = true; - if (root_id != 0) - DockContextQueueNotifyRemovedNode(ctx, node); - if (root_node) - DockNodeMoveWindows(root_node, node); - nodes_to_remove.push_back(node); - } - } - - // Apply to settings - for (int settings_n = 0; settings_n < ctx->SettingsWindows.Size; settings_n++) - if (ImGuiID window_settings_dock_id = ctx->SettingsWindows[settings_n].DockId) - for (int n = 0; n < nodes_to_remove.Size; n++) - if (nodes_to_remove[n]->ID == window_settings_dock_id) - { - ctx->SettingsWindows[settings_n].DockId = root_id; - break; - } - - // Not really efficient, but easier to destroy a whole hierarchy considering DockContextRemoveNode is attempting to merge nodes - if (nodes_to_remove.Size > 1) - ImQsort(nodes_to_remove.Data, nodes_to_remove.Size, sizeof(ImGuiDockNode*), DockNodeComparerDepthMostFirst); - for (int n = 0; n < nodes_to_remove.Size; n++) - DockContextRemoveNode(ctx, nodes_to_remove[n], false); - - if (root_id == 0) - { - dc->Nodes.Clear(); - dc->Requests.clear(); - } - else if (has_document_root) - { - root_node->IsDocumentRoot = true; - } -} - -void ImGui::DockBuilderRemoveNodeDockedWindows(ImGuiContext* ctx, ImGuiID root_id, bool clear_persistent_docking_references) -{ - // Clear references in settings - ImGuiContext& g = *ctx; - if (clear_persistent_docking_references) - { - for (int n = 0; n < g.SettingsWindows.Size; n++) - { - ImGuiWindowSettings* settings = &g.SettingsWindows[n]; - bool want_removal = (root_id == 0) || (settings->DockId == root_id); - if (!want_removal && settings->DockId != 0) - if (ImGuiDockNode* node = DockContextFindNodeByID(ctx, settings->DockId)) - if (DockNodeGetRootNode(node)->ID == root_id) - want_removal = true; - if (want_removal) - settings->DockId = 0; - } - } - - // Clear references in windows - for (int n = 0; n < g.Windows.Size; n++) - { - ImGuiWindow* window = g.Windows[n]; - bool want_removal = (root_id == 0) || (window->DockNode && DockNodeGetRootNode(window->DockNode)->ID == root_id) || (window->DockNodeAsHost && window->DockNodeAsHost->ID == root_id); - if (want_removal) - { - ImGuiID backup_dock_id = window->DockId; - DockContextProcessUndockWindow(ctx, window); - if (!clear_persistent_docking_references) - window->DockId = backup_dock_id; - } - } -} - static void ImGui::DockContextGcUnusedSettingsNodes(ImGuiContext* ctx) { ImGuiContext& g = *ctx; @@ -11488,22 +11400,21 @@ ImGuiDockNode* ImGui::DockNodeTreeFindNodeByPos(ImGuiDockNode* node, ImVec2 pos) { if (!node->IsVisible) return NULL; - if (node->IsSplitNode()) - { - if (ImGuiDockNode* hovered_node = DockNodeTreeFindNodeByPos(node->ChildNodes[0], pos)) - return hovered_node; - if (ImGuiDockNode* hovered_node = DockNodeTreeFindNodeByPos(node->ChildNodes[1], pos)) - return hovered_node; - } - else - { - ImGuiContext& g = *GImGui; - const float dock_spacing = g.Style.ItemInnerSpacing.x; - ImRect r(node->Pos, node->Pos + node->Size); - r.Expand(dock_spacing * 0.5f); - if (r.Contains(pos)) - return node; - } + + ImGuiContext& g = *GImGui; + const float dock_spacing = g.Style.ItemInnerSpacing.x; + ImRect r(node->Pos, node->Pos + node->Size); + r.Expand(dock_spacing * 0.5f); + bool inside = r.Contains(pos); + if (!inside) + return NULL; + + if (!node->IsSplitNode()) + return node; + if (ImGuiDockNode* hovered_node = DockNodeTreeFindNodeByPos(node->ChildNodes[0], pos)) + return hovered_node; + if (ImGuiDockNode* hovered_node = DockNodeTreeFindNodeByPos(node->ChildNodes[1], pos)) + return hovered_node; return NULL; } @@ -11601,6 +11512,7 @@ void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags doc // Docking: Builder Functions //----------------------------------------------------------------------------- // Very early end-user API to manipulate dock nodes. +// It is expected that those functions are all called _before_ the dockspace node submission. //----------------------------------------------------------------------------- void ImGui::DockBuilderDockWindow(ImGuiContext*, const char* window_name, ImGuiID node_id) @@ -11621,8 +11533,7 @@ void ImGui::DockBuilderDockWindow(ImGuiContext*, const char* window_name, ImGuiI } } -// Ensure a node is created -void ImGui::DockBuilderCreateNode(ImGuiContext* ctx, ImGuiID id, ImVec2 ref_size, ImGuiDockNodeFlags flags) +void ImGui::DockBuilderAddNode(ImGuiContext* ctx, ImGuiID id, ImVec2 ref_size, ImGuiDockNodeFlags flags) { DockSpace(id, ImVec2(0,0), flags | ImGuiDockNodeFlags_KeepAliveOnly); ImGuiDockNode* node = DockContextFindNodeByID(ctx, id); @@ -11630,6 +11541,106 @@ void ImGui::DockBuilderCreateNode(ImGuiContext* ctx, ImGuiID id, ImVec2 ref_size node->LastFrameAlive = -1; } +void ImGui::DockBuilderRemoveNode(ImGuiContext* ctx, ImGuiID node_id) +{ + ImGuiDockNode* node = DockContextFindNodeByID(ctx, node_id); + if (node == NULL) + return; + DockBuilderRemoveNodeDockedWindows(ctx, node_id, true); + DockBuilderRemoveNodeChildNodes(ctx, node_id); + if (node->IsDocumentRoot && node->ParentNode) + node->ParentNode->IsDocumentRoot = true; + DockContextRemoveNode(ctx, node, true); +} + +void ImGui::DockBuilderRemoveNodeChildNodes(ImGuiContext* ctx, ImGuiID root_id) +{ + ImGuiDockContext* dc = ctx->DockContext; + + ImGuiDockNode* root_node = root_id ? DockContextFindNodeByID(ctx, root_id) : NULL; + if (root_id && root_node == NULL) + return; + bool has_document_root = false; + + // Process active windows + ImVector nodes_to_remove; + for (int n = 0; n < dc->Nodes.Data.Size; n++) + if (ImGuiDockNode* node = (ImGuiDockNode*)dc->Nodes.Data[n].val_p) + { + bool want_removal = (root_id == 0) || (node->ID != root_id && DockNodeGetRootNode(node)->ID == root_id); + if (want_removal) + { + if (node->IsDocumentRoot) + has_document_root = true; + if (root_id != 0) + DockContextQueueNotifyRemovedNode(ctx, node); + if (root_node) + DockNodeMoveWindows(root_node, node); + nodes_to_remove.push_back(node); + } + } + + // Apply to settings + for (int settings_n = 0; settings_n < ctx->SettingsWindows.Size; settings_n++) + if (ImGuiID window_settings_dock_id = ctx->SettingsWindows[settings_n].DockId) + for (int n = 0; n < nodes_to_remove.Size; n++) + if (nodes_to_remove[n]->ID == window_settings_dock_id) + { + ctx->SettingsWindows[settings_n].DockId = root_id; + break; + } + + // Not really efficient, but easier to destroy a whole hierarchy considering DockContextRemoveNode is attempting to merge nodes + if (nodes_to_remove.Size > 1) + ImQsort(nodes_to_remove.Data, nodes_to_remove.Size, sizeof(ImGuiDockNode*), DockNodeComparerDepthMostFirst); + for (int n = 0; n < nodes_to_remove.Size; n++) + DockContextRemoveNode(ctx, nodes_to_remove[n], false); + + if (root_id == 0) + { + dc->Nodes.Clear(); + dc->Requests.clear(); + } + else if (has_document_root) + { + root_node->IsDocumentRoot = true; + } +} + +void ImGui::DockBuilderRemoveNodeDockedWindows(ImGuiContext* ctx, ImGuiID root_id, bool clear_persistent_docking_references) +{ + // Clear references in settings + ImGuiContext& g = *ctx; + if (clear_persistent_docking_references) + { + for (int n = 0; n < g.SettingsWindows.Size; n++) + { + ImGuiWindowSettings* settings = &g.SettingsWindows[n]; + bool want_removal = (root_id == 0) || (settings->DockId == root_id); + if (!want_removal && settings->DockId != 0) + if (ImGuiDockNode* node = DockContextFindNodeByID(ctx, settings->DockId)) + if (DockNodeGetRootNode(node)->ID == root_id) + want_removal = true; + if (want_removal) + settings->DockId = 0; + } + } + + // Clear references in windows + for (int n = 0; n < g.Windows.Size; n++) + { + ImGuiWindow* window = g.Windows[n]; + bool want_removal = (root_id == 0) || (window->DockNode && DockNodeGetRootNode(window->DockNode)->ID == root_id) || (window->DockNodeAsHost && window->DockNodeAsHost->ID == root_id); + if (want_removal) + { + ImGuiID backup_dock_id = window->DockId; + DockContextProcessUndockWindow(ctx, window); + if (!clear_persistent_docking_references) + window->DockId = backup_dock_id; + } + } +} + ImGuiID ImGui::DockBuilderSplitNode(ImGuiContext* ctx, ImGuiID id, ImGuiDir split_dir, float size_ratio_for_node_at_dir, ImGuiID* out_id_at_dir, ImGuiID* out_id_other) { IM_ASSERT(split_dir != ImGuiDir_None); diff --git a/imgui_internal.h b/imgui_internal.h index 55c29b6d4..4727564f6 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1481,10 +1481,11 @@ namespace ImGui IMGUI_API void ShowDockingDebug(); // Docking - Builder function needs to be generally called before the DockSpace() node is submitted. + IMGUI_API void DockBuilderDockWindow(ImGuiContext* ctx, const char* window_name, ImGuiID node_id); + IMGUI_API void DockBuilderAddNode(ImGuiContext* ctx, ImGuiID node_id, ImVec2 ref_size, ImGuiDockNodeFlags flags = 0); + IMGUI_API void DockBuilderRemoveNode(ImGuiContext* ctx, ImGuiID node_id); IMGUI_API void DockBuilderRemoveNodeDockedWindows(ImGuiContext* ctx, ImGuiID node_id, bool clear_persistent_docking_references = true); IMGUI_API void DockBuilderRemoveNodeChildNodes(ImGuiContext* ctx, ImGuiID node_id); // Remove all split/hierarchy. All remaining docked windows will be re-docked to the root. - IMGUI_API void DockBuilderDockWindow(ImGuiContext* ctx, const char* window_name, ImGuiID node_id); - IMGUI_API void DockBuilderCreateNode(ImGuiContext* ctx, ImGuiID node_id, ImVec2 ref_size, ImGuiDockNodeFlags flags = 0); IMGUI_API ImGuiID DockBuilderSplitNode(ImGuiContext* ctx, ImGuiID node_id, ImGuiDir split_dir, float size_ratio_for_node_at_dir, ImGuiID* out_id_dir, ImGuiID* out_id_other); IMGUI_API void DockBuilderFinish(ImGuiContext* ctx, ImGuiID node_id); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 299b0d644..827eb9ad5 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -704,7 +704,9 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos, ImGuiDockNode* dock_no } else { + ImVec2 backup_active_click_offset = g.ActiveIdClickOffset; StartMouseMovingWindow(window); + g.ActiveIdClickOffset = backup_active_click_offset; } }