From 9f96fcff3c21c5a31bd01eb5f590465da5979f5b Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 23 Jan 2019 11:29:44 +0100 Subject: [PATCH] Docking: Added ImGuiDockNodeFlags_Dockspace instead of node internal IsDockspace toward allowing the DockBuilder API to create non-dockspace nodes. --- imgui.cpp | 44 ++++++++++++++++++++++---------------------- imgui_internal.h | 12 ++++++++---- imgui_widgets.cpp | 6 +++--- 3 files changed, 33 insertions(+), 29 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5519019a..54dbccb0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10292,7 +10292,7 @@ void ImGui::DockContextNewFrameUpdateDocking(ImGuiContext* ctx) // We can have NULL pointers when we delete nodes, but because ID are recycled this should amortize nicely (and our node count will never be very high) for (int n = 0; n < dc->Nodes.Data.Size; n++) if (ImGuiDockNode* node = (ImGuiDockNode*)dc->Nodes.Data[n].val_p) - if (!node->IsDockSpace && node->IsRootNode()) + if (node->IsRootNode() && !node->IsDockSpace()) DockNodeUpdate(node); } @@ -10440,7 +10440,8 @@ static void ImGui::DockContextBuildNodesFromSettings(ImGuiContext* ctx, ImGuiDoc node->ParentNode->ChildNodes[1] = node; node->SelectedTabID = node_settings->SelectedTabID; node->SplitAxis = node_settings->SplitAxis; - node->IsDockSpace = node_settings->IsDockSpace != 0; + if (node_settings->IsDockSpace) + node->Flags |= ImGuiDockNodeFlags_Dockspace; node->IsCentralNode = node_settings->IsCentralNode != 0; node->IsHiddenTabBar = node_settings->IsHiddenTabBar != 0; @@ -10703,7 +10704,7 @@ ImGuiDockNode::ImGuiDockNode(ImGuiID id) WantCloseTabID = 0; InitFromFirstWindowPosSize = InitFromFirstWindowViewport = false; IsVisible = true; - IsFocused = IsDockSpace = IsCentralNode = IsHiddenTabBar = HasCloseButton = HasCollapseButton = false; + IsFocused = IsCentralNode = IsHiddenTabBar = HasCloseButton = HasCollapseButton = false; WantCloseAll = WantLockSizeOnce = WantMouseMove = WantHiddenTabBarToggle = false; } @@ -10750,7 +10751,7 @@ static void ImGui::DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window, b // When reactivating a node with one or two loose window, the window pos/size/viewport are authoritative over the node storage. // In particular it is important we init the viewport from the first window so we don't create two viewports and drop one. - if (node->HostWindow == NULL && !node->IsDockSpace && node->IsRootNode()) + if (node->HostWindow == NULL && !node->IsDockSpace() && node->IsRootNode()) node->InitFromFirstWindowPosSize = node->InitFromFirstWindowViewport = true; // Add to tab bar if requested @@ -10956,9 +10957,10 @@ static void ImGui::DockNodeUpdateVisibleFlagAndInactiveChilds(ImGuiDockNode* nod IM_ASSERT(node->ParentNode == NULL || node->ParentNode->ChildNodes[0] == node || node->ParentNode->ChildNodes[1] == node); - // Inherit flags + // Inherit most flags + ImGuiDockNodeFlags flags_to_inherit = ~0 & ~ImGuiDockNodeFlags_Dockspace; if (node->ParentNode) - node->Flags = node->ParentNode->Flags; + node->Flags = node->ParentNode->Flags & flags_to_inherit; // Recurse into children // There is the possibility that one of our child becoming empty will delete itself and moving its sibling contents into 'node'. @@ -11006,7 +11008,7 @@ static void ImGui::DockNodeUpdateVisibleFlagAndInactiveChilds(ImGuiDockNode* nod static void ImGui::DockNodeUpdateVisibleFlag(ImGuiDockNode* node) { // Update visibility flag - bool is_visible = (node->ParentNode == 0) ? node->IsDockSpace : node->IsCentralNode; + bool is_visible = (node->ParentNode == 0) ? node->IsDockSpace() : node->IsCentralNode; is_visible |= (node->Windows.Size > 0); is_visible |= (node->ChildNodes[0] && node->ChildNodes[0]->IsVisible); is_visible |= (node->ChildNodes[1] && node->ChildNodes[1]->IsVisible); @@ -11061,7 +11063,7 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node) } // 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->Windows.Size <= 1 && node->IsRootNode() && node->IsLeafNode() && !node->IsDockSpace && !g.IO.ConfigDockingTabBarOnSingleWindows) + if (node->Windows.Size <= 1 && node->IsRootNode() && node->IsLeafNode() && !node->IsDockSpace() && !g.IO.ConfigDockingTabBarOnSingleWindows) { if (node->Windows.Size == 1) { @@ -11099,7 +11101,7 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node) ImGuiWindow* host_window = NULL; bool beginned_into_host_window = false; - if (node->IsDockSpace) + if (node->IsDockSpace()) { // [Explicit root dockspace node] IM_ASSERT(node->HostWindow); @@ -11202,7 +11204,7 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node) if (central_node_hole_register_hit_test_hole) { // Add a little padding to match the "resize from edges" behavior and allow grabbing the splitter easily. - IM_ASSERT(node->IsDockSpace); // We cannot pass this flag without the DockSpace() api. Testing this because we also setup the hole in host_window->ParentNode + IM_ASSERT(node->IsDockSpace()); // We cannot pass this flag without the DockSpace() api. Testing this because we also setup the hole in host_window->ParentNode ImRect central_hole(central_node->Pos, central_node->Pos + central_node->Size); central_hole.Expand(ImVec2(-WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS, -WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS)); if (central_node_hole && !central_hole.IsInverted()) @@ -11321,7 +11323,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w // Move ourselves to the Menu layer (so we can be accessed by tapping Alt) + undo SkipItems flag in order to draw over the title bar even if the window is collapsed bool backup_skip_item = host_window->SkipItems; - if (!node->IsDockSpace) + if (!node->IsDockSpace()) { host_window->SkipItems = false; host_window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; @@ -11411,8 +11413,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w // Begin tab bar const ImRect tab_bar_rect = DockNodeCalcTabBarRect(node); ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_NoTabListPopupButton;// | ImGuiTabBarFlags_NoTabListScrollingButtons); - tab_bar_flags |= ImGuiTabBarFlags_SaveSettings; - tab_bar_flags |= ImGuiTabBarFlags_DockNode | (node->IsDockSpace ? ImGuiTabBarFlags_DockNodeIsDockSpace : 0); + tab_bar_flags |= ImGuiTabBarFlags_SaveSettings | ImGuiTabBarFlags_DockNode; if (!host_window->Collapsed && is_focused) tab_bar_flags |= ImGuiTabBarFlags_IsFocused; BeginTabBarEx(tab_bar, tab_bar_rect, tab_bar_flags, node); @@ -11512,7 +11513,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w PopID(); // Restore SkipItems flag - if (!node->IsDockSpace) + if (!node->IsDockSpace()) { host_window->DC.NavLayerCurrent = ImGuiNavLayer_Main; host_window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main); @@ -11522,7 +11523,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w static bool DockNodeIsDropAllowedOne(ImGuiWindow* payload, ImGuiWindow* host_window) { - if (host_window->DockNodeAsHost && host_window->DockNodeAsHost->IsDockSpace && payload->BeginOrderWithinContext < host_window->BeginOrderWithinContext) + if (host_window->DockNodeAsHost && host_window->DockNodeAsHost->IsDockSpace() && payload->BeginOrderWithinContext < host_window->BeginOrderWithinContext) return false; ImGuiWindowClass* host_class = host_window->DockNodeAsHost ? &host_window->DockNodeAsHost->WindowClass : &host_window->WindowClass; @@ -12134,7 +12135,7 @@ ImGuiDockNode* ImGui::DockNodeTreeFindNodeByPos(ImGuiDockNode* node, ImVec2 pos) // There is an edge case when docking into a dockspace which only has inactive nodes (because none of the windows are active) // In this case we need to fallback into any leaf mode, possibly the central node. - if (node->IsDockSpace && node->IsRootNode()) + if (node->IsDockSpace() && node->IsRootNode()) { if (node->CentralNode && node->IsLeafNode()) // FIXME-20181220: We should not have to test for IsLeafNode() here but we have another bug to fix first. return node->CentralNode; @@ -12202,11 +12203,11 @@ void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags doc // It is possible that the node has already been claimed by a docked window which appeared before the DockSpace() node, so we overwrite IsDockSpace again. if (node->LastFrameActive == g.FrameCount && !(dockspace_flags & ImGuiDockNodeFlags_KeepAliveOnly)) { - IM_ASSERT(node->IsDockSpace == false && "Cannot call DockSpace() twice a frame with the same ID"); - node->IsDockSpace = true; + IM_ASSERT(node->IsDockSpace() == false && "Cannot call DockSpace() twice a frame with the same ID"); + node->Flags |= ImGuiDockNodeFlags_Dockspace; return; } - node->IsDockSpace = true; + node->Flags |= ImGuiDockNodeFlags_Dockspace; // Keep alive mode, this is allow windows docked into this node so stay docked even if they are not visible if (dockspace_flags & ImGuiDockNodeFlags_KeepAliveOnly) @@ -12480,7 +12481,6 @@ static ImGuiDockNode* DockBuilderCopyNodeRec(ImGuiDockNode* src_node, ImGuiID ds dst_node->Size = src_node->Size; dst_node->SizeRef = src_node->SizeRef; dst_node->SplitAxis = src_node->SplitAxis; - dst_node->IsDockSpace = src_node->IsDockSpace; dst_node->IsCentralNode = src_node->IsCentralNode; out_node_remap_pairs->push_back(src_node->ID); @@ -12955,7 +12955,7 @@ static void DockSettingsHandler_DockNodeToSettings(ImGuiDockContext* dc, ImGuiDo node_settings.SelectedTabID = node->SelectedTabID; node_settings.SplitAxis = node->IsSplitNode() ? (char)node->SplitAxis : ImGuiAxis_None; node_settings.Depth = (char)depth; - node_settings.IsDockSpace = (char)node->IsDockSpace; + node_settings.IsDockSpace = (char)node->IsDockSpace(); node_settings.IsCentralNode = (char)node->IsCentralNode; node_settings.IsHiddenTabBar = (char)node->IsHiddenTabBar; node_settings.Pos = ImVec2ih((short)node->Pos.x, (short)node->Pos.y); @@ -13871,7 +13871,7 @@ void ImGui::ShowDockingDebug() ImGui::BulletText("SelectedTabID: 0x%08X", node->SelectedTabID); ImGui::BulletText("LastFocusedNodeID: 0x%08X", node->LastFocusedNodeID); ImGui::BulletText("Flags 0x%02X%s%s%s%s", - node->Flags, node->IsDockSpace ? ", IsDockSpace" : "", node->IsCentralNode ? ", IsCentralNode" : "", + node->Flags, node->IsDockSpace() ? ", IsDockSpace" : "", node->IsCentralNode ? ", IsCentralNode" : "", (GImGui->FrameCount - node->LastFrameAlive < 2) ? ", IsAlive" : "", (GImGui->FrameCount - node->LastFrameActive < 2) ? ", IsActive" : ""); if (node->ChildNodes[0]) NodeDockNode(node->ChildNodes[0], "Child[0]"); diff --git a/imgui_internal.h b/imgui_internal.h index e609ed06..de762b52 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -813,6 +813,11 @@ struct ImGuiTabBarSortItem float Width; }; +enum ImGuiDockNodeFlagsPrivate_ +{ + ImGuiDockNodeFlags_Dockspace = 1 << 10 +}; + // sizeof() 116~160 struct ImGuiDockNode { @@ -842,7 +847,6 @@ struct ImGuiDockNode bool InitFromFirstWindowViewport :1; bool IsVisible :1; // Set to false when the node is hidden (usually disabled as it has no active window) bool IsFocused :1; - bool IsDockSpace :1; // Root node was created by a DockSpace() call. bool IsCentralNode :1; bool IsHiddenTabBar :1; bool HasCloseButton :1; @@ -855,6 +859,7 @@ struct ImGuiDockNode ImGuiDockNode(ImGuiID id); ~ImGuiDockNode(); bool IsRootNode() const { return ParentNode == NULL; } + bool IsDockSpace() const { return (Flags & ImGuiDockNodeFlags_Dockspace) != 0; } bool IsSplitNode() const { return ChildNodes[0] != NULL; } bool IsLeafNode() const { return ChildNodes[0] == NULL; } bool IsEmpty() const { return ChildNodes[0] == NULL && Windows.Size == 0; } @@ -1384,9 +1389,8 @@ struct ImGuiItemHoveredDataBackup enum ImGuiTabBarFlagsPrivate_ { ImGuiTabBarFlags_DockNode = 1 << 20, // Part of a dock node - ImGuiTabBarFlags_DockNodeIsDockSpace = 1 << 21, // Part of an explicit dockspace node node - ImGuiTabBarFlags_IsFocused = 1 << 22, - ImGuiTabBarFlags_SaveSettings = 1 << 23 // FIXME: Settings are handled by the docking system, this only request the tab bar to mark settings dirty when reordering tabs + ImGuiTabBarFlags_IsFocused = 1 << 21, + ImGuiTabBarFlags_SaveSettings = 1 << 22 // FIXME: Settings are handled by the docking system, this only request the tab bar to mark settings dirty when reordering tabs }; enum ImGuiTabItemFlagsPrivate_ diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index fa545290..17d87f48 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5937,8 +5937,8 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG } else { - const float separator_min_x = tab_bar->BarRect.Min.x - ((flags & ImGuiTabBarFlags_DockNodeIsDockSpace) ? 0.0f : window->WindowPadding.x); - const float separator_max_x = tab_bar->BarRect.Max.x + ((flags & ImGuiTabBarFlags_DockNodeIsDockSpace) ? 0.0f : window->WindowPadding.x); + const float separator_min_x = tab_bar->BarRect.Min.x - window->WindowPadding.x; + const float separator_max_x = tab_bar->BarRect.Max.x + window->WindowPadding.x; window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f); } return true; @@ -6497,7 +6497,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, // FIXME-DOCK: In theory we shouldn't test for the ConfigDockingNodifySingleWindows flag here. // When our single window node and OnlyNodeWithWindows are working properly we may remove this check here. ImGuiDockNode* node = docked_window ? docked_window->DockNode : NULL; - const bool single_floating_window_node = node && node->IsRootNode() && !node->IsDockSpace && node->Windows.Size == 1 && g.IO.ConfigDockingTabBarOnSingleWindows; + const bool single_floating_window_node = node && node->IsRootNode() && !node->IsDockSpace() && node->Windows.Size == 1 && g.IO.ConfigDockingTabBarOnSingleWindows; if (held && single_floating_window_node && IsMouseDragging(0, 0.0f)) { // Move