diff --git a/imgui.cpp b/imgui.cpp index 5409d56..eefb6c5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5616,7 +5616,7 @@ // Docking: report contents sizes to parent to allow for auto-resize if (window->DockNode && window->DockTabIsVisible) - if (ImGuiWindow* host_window = window->DockNode->HostWindow) // FIXME-DOCKSPACE + if (ImGuiWindow* host_window = window->DockNode->HostWindow) // FIXME-DOCK host_window->DC.CursorMaxPos = window->DC.CursorMaxPos + window->WindowPadding - host_window->WindowPadding; // Pop from window stack @@ -9517,7 +9517,7 @@ // Docking: ImGuiDockContext Docking/Undocking functions // Docking: ImGuiDockNode // Docking: ImGuiDockNode Tree manipulation functions -// Docking: Public Functions (Dockspace, SetWindowDock) +// Docking: Public Functions (SetWindowDock, DockSpace) // Docking: Public Builder Functions // Docking: Begin/End Functions (called from Begin/End) // Docking: Settings @@ -9606,12 +9606,12 @@ ImGuiID SelectedTabID; char SplitAxis; char Depth; - char IsExplicitRoot; + char IsDockSpace; char IsDocumentRoot; ImVec2ih Pos; ImVec2ih Size; ImVec2ih SizeRef; - ImGuiDockNodeSettings() { ID = ParentID = SelectedTabID = 0; SplitAxis = ImGuiAxis_None; Depth = 0; IsExplicitRoot = IsDocumentRoot = 0; } + ImGuiDockNodeSettings() { ID = ParentID = SelectedTabID = 0; SplitAxis = ImGuiAxis_None; Depth = 0; IsDockSpace = IsDocumentRoot = 0; } }; struct ImGuiDockContext @@ -9794,7 +9794,7 @@ // 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->IsExplicitRoot && node->IsRootNode()) + if (!node->IsDockSpace && node->IsRootNode()) DockNodeUpdate(node); } @@ -9983,7 +9983,7 @@ node->ParentNode->ChildNodes[1] = node; node->SelectedTabID = node_settings->SelectedTabID; node->SplitAxis = node_settings->SplitAxis; - node->IsExplicitRoot = node_settings->IsExplicitRoot != 0; + node->IsDockSpace = node_settings->IsDockSpace != 0; node->IsDocumentRoot = node_settings->IsDocumentRoot != 0; // Bind host window immediately if it already exist (in case of a rebuild) @@ -10218,7 +10218,7 @@ SelectedTabID = 0; WantCloseTabID = 0; IsVisible = true; - InitFromFirstWindow = IsExplicitRoot = IsDocumentRoot = HasCloseButton = HasCollapseButton = WantCloseAll = WantLockSizeOnce = WantMouseMove = false; + InitFromFirstWindow = IsDockSpace = IsDocumentRoot = HasCloseButton = HasCollapseButton = WantCloseAll = WantLockSizeOnce = WantMouseMove = false; } ImGuiDockNode::~ImGuiDockNode() @@ -10242,7 +10242,7 @@ ImGuiContext& g = *GImGui; (void)g; if (window->DockNode) { - // Can overwrite an existing window->DockNode (e.g. pointing to a disabled DockSpace) + // Can overwrite an existing window->DockNode (e.g. pointing to a disabled DockSpace node) IM_ASSERT(window->DockNode->ID != node->ID); DockNodeRemoveWindow(window->DockNode, window, 0); } @@ -10264,7 +10264,7 @@ } // When reactivating a node from two loose window, the target window pos/size are authoritative - if (node->Windows.Size == 2 && !node->IsExplicitRoot) + if (node->Windows.Size == 2 && !node->IsDockSpace) node->InitFromFirstWindow = true; if (node->TabBar == NULL) @@ -10470,7 +10470,7 @@ static void ImGui::DockNodeUpdateVisibleFlag(ImGuiDockNode* node) { // Update visibility flag - bool is_visible = (node->ParentNode == 0) ? node->IsExplicitRoot : node->IsDocumentRoot; + bool is_visible = (node->ParentNode == 0) ? node->IsDockSpace : node->IsDocumentRoot; is_visible |= (node->Windows.Size > 0); is_visible |= (node->ChildNodes[0] && node->ChildNodes[0]->IsVisible); is_visible |= (node->ChildNodes[1] && node->ChildNodes[1]->IsVisible); @@ -10498,7 +10498,7 @@ DockNodeUpdateVisibleFlagAndInactiveChilds(node); // Find if there's only a single visible window in the hierarchy (in which case we need to display a regular title bar, FIXME-DOCK: Not done yet!) - if (!node->IsExplicitRoot) + if (!node->IsDockSpace) { int count = 0; ImGuiDockNode* first_node_with_windows = NULL; @@ -10512,7 +10512,7 @@ } // 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->IsExplicitRoot) + if (node->IsRootNode() && node->Windows.Size == 1 && !node->IsDockSpace) { // Floating window pos/size is authoritative node->Pos = node->Windows[0]->Pos; @@ -10536,9 +10536,9 @@ ImGuiWindow* host_window = NULL; bool beginned_into_host_window = false; - if (node->IsExplicitRoot) + if (node->IsDockSpace) { - // [Explicit root node] + // [Explicit root dockspace node] IM_ASSERT(node->HostWindow); node->HasCloseButton = false; node->HasCollapseButton = true; @@ -10674,9 +10674,9 @@ node->WantCloseAll = false; node->WantCloseTabID = 0; - // Move ourselves to the Menu layer + Undo SkipItems flag in order to draw over the title bar (even if the window is collapsed) + // 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->IsExplicitRoot) + if (!node->IsDockSpace) { host_window->SkipItems = false; host_window->DC.NavLayerCurrent++; @@ -10761,7 +10761,7 @@ // Begin tab bar ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_NoTabListPopupButton;// | ImGuiTabBarFlags_NoTabListScrollingButtons); tab_bar_flags |= ImGuiTabBarFlags_SaveSettings; - tab_bar_flags |= ImGuiTabBarFlags_DockNode | (node->IsExplicitRoot ? ImGuiTabBarFlags_DockNodeExplicitRoot : 0); + tab_bar_flags |= ImGuiTabBarFlags_DockNode | (node->IsDockSpace ? ImGuiTabBarFlags_DockNodeExplicitRoot : 0); if (!host_window->Collapsed && is_focused) tab_bar_flags |= ImGuiTabBarFlags_IsFocused; BeginTabBarEx(node->TabBar, tab_bar_rect, tab_bar_flags, node); @@ -10789,6 +10789,7 @@ if (tab_bar->VisibleTabId == window->ID) node->VisibleWindow = window; + // Store last item data so it can be queried with IsItemXXX functions after the user Begin() call window->DockTabItemStatusFlags = host_window->DC.LastItemStatusFlags; window->DockTabItemRect = host_window->DC.LastItemRect; @@ -10853,7 +10854,7 @@ PopID(); // Restore SkipItems flag - if (!node->IsExplicitRoot) + if (!node->IsDockSpace) { host_window->DC.NavLayerCurrent--; host_window->DC.NavLayerCurrentMask >>= 1; @@ -10863,7 +10864,7 @@ static bool DockNodeIsDropAllowedOne(ImGuiWindow* payload, ImGuiWindow* host_window) { - if ((host_window->Flags & ImGuiWindowFlags_DockNodeHost) && host_window->DockNodeAsHost->IsExplicitRoot && payload->BeginOrderWithinContext < host_window->BeginOrderWithinContext) + if ((host_window->Flags & ImGuiWindowFlags_DockNodeHost) && host_window->DockNodeAsHost->IsDockSpace && payload->BeginOrderWithinContext < host_window->BeginOrderWithinContext) return false; ImGuiID host_user_type_id = host_window->DockNodeAsHost ? host_window->DockNodeAsHost->UserTypeIdFilter : host_window->UserTypeId; @@ -10999,7 +11000,7 @@ data->IsCenterAvailable = false; data->IsSidesAvailable = true; - if (host_node && (host_node->Flags & ImGuiDockSpaceFlags_NoSplit)) + if (host_node && (host_node->Flags & ImGuiDockNodeFlags_NoSplit)) data->IsSidesAvailable = false; if (!is_outer_docking && host_node && host_node->ParentNode == NULL && host_node->IsDocumentRoot) data->IsSidesAvailable = false; @@ -11139,7 +11140,7 @@ } // Stop after ImGuiDir_None - if (host_node && (host_node->Flags & ImGuiDockSpaceFlags_NoSplit)) + if (host_node && (host_node->Flags & ImGuiDockNodeFlags_NoSplit)) return; } } @@ -11418,7 +11419,7 @@ } //----------------------------------------------------------------------------- -// Docking: Public Functions (SetWindowDock, Dockspace) +// Docking: Public Functions (SetWindowDock, DockSpace) //----------------------------------------------------------------------------- void ImGui::SetWindowDock(ImGuiWindow* window, ImGuiID dock_id, ImGuiCond cond) @@ -11436,14 +11437,14 @@ window->DockId = dock_id; } -void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockSpaceFlags dock_space_flags, ImGuiID user_type_filter) +// Create an explicit dockspace node within an existing window. Also expose dock node flags and creates a DocumentRoot node by default. +// The DocumentRoot node is always displayed even when empty and shrink/extend according to the requested size of its neighbors. +void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags dock_space_flags, ImGuiID user_type_filter) { ImGuiContext* ctx = GImGui; ImGuiContext& g = *ctx; - ImGuiWindow* window = GetCurrentWindow(); - // It is possible that the node has already been claimed by a docked window which appeared before the DockSpace(), so we overwrite IsExplicit again. ImGuiDockNode* node = DockContextFindNodeByID(ctx, id); if (!node) { @@ -11452,14 +11453,19 @@ } node->Flags = dock_space_flags; node->UserTypeIdFilter = user_type_filter; - node->IsExplicitRoot = true; // When a Dockspace transitioned form implicit to explicit this may be called a second time + // 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) + { + IM_ASSERT(node->IsDockSpace == false && "Cannot call DockSpace() twice a frame with the same ID"); + node->IsDockSpace = true; return; + } + node->IsDockSpace = true; // Keep alive mode, this is allow windows docked into this node so stay docked even if they are not visible - if (dock_space_flags & ImGuiDockSpaceFlags_KeepAliveOnly) + if (dock_space_flags & ImGuiDockNodeFlags_KeepAliveOnly) { node->LastFrameAlive = g.FrameCount; return; @@ -11512,11 +11518,18 @@ { ImGuiID window_id = ImHash(window_name, 0); if (ImGuiWindow* window = FindWindowByID(window_id)) + { + // Apply to created window SetWindowDock(window, node_id, ImGuiCond_Always); - else if (ImGuiWindowSettings* settings = FindWindowSettings(window_id)) + } + else + { + // Apply to settings + ImGuiWindowSettings* settings = FindWindowSettings(window_id); + if (settings == NULL) + settings = CreateNewWindowSettings(window_name); settings->DockId = node_id; - else if (ImGuiWindowSettings* settings = CreateNewWindowSettings(window_name)) - settings->DockId = node_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) @@ -11597,11 +11610,11 @@ g.NextWindowData.PosUndock = false; } - // Undock if our dockspace disappeared - // Note how we are testing for LastFrameAlive and NOT LastFrameActive. A DockSpace can be maintained alive while being inactive with ImGuiDockSpaceFlags_KeepAliveOnly. + // Undock if our dockspace node disappeared + // Note how we are testing for LastFrameAlive and NOT LastFrameActive. A DockSpace node can be maintained alive while being inactive with ImGuiDockNodeFlags_KeepAliveOnly. if (dock_node->LastFrameAlive < g.FrameCount) { - // If the window has been orphaned (lost its dockspace), transition the docknode to an implicit node processed in DockContextUpdateDocking() + // If the window has been orphaned, transition the docknode to an implicit node processed in DockContextUpdateDocking() ImGuiDockNode* root_node = DockNodeGetRootNode(dock_node); if (root_node->LastFrameAlive < g.FrameCount) { @@ -11622,7 +11635,7 @@ return; } - // FIXME-DOCKSPACE: 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 (dock_node->HostWindow == NULL) { window->DockTabIsVisible = false; @@ -11639,7 +11652,7 @@ window->DockIsActive = true; window->DockTabIsVisible = false; - if (dock_node->Flags & ImGuiDockSpaceFlags_KeepAliveOnly) + if (dock_node->Flags & ImGuiDockNodeFlags_KeepAliveOnly) return; if (dock_node->TabBar && dock_node->TabBar->VisibleTabId == window->ID) @@ -11812,7 +11825,7 @@ if (sscanf(line, " SizeRef=%i,%i%n", &x, &y, &r) == 2) { line += r; node.SizeRef = ImVec2ih((short)x, (short)y); } } if (sscanf(line, " Split=%c%n", &c, &r) == 1) { line += r; if (c == 'X') node.SplitAxis = ImGuiAxis_X; else if (c == 'Y') node.SplitAxis = ImGuiAxis_Y; } - if (sscanf(line, " ExplicitRoot=%d%n", &x, &r) == 1) { line += r; node.IsExplicitRoot = (x != 0); } + if (sscanf(line, " ExplicitRoot=%d%n", &x, &r) == 1) { line += r; node.IsDockSpace = (x != 0); } if (sscanf(line, " DocumentRoot=%d%n", &x, &r) == 1) { line += r; node.IsDocumentRoot = (x != 0); } if (sscanf(line, " SelectedTab=0x%08X%n", &node.SelectedTabID,&r) == 1) { line += r; } //if (node.ParentID == 0 && node.SplitAxis == ImGuiAxis_None) @@ -11833,7 +11846,7 @@ node_settings.SelectedTabID = node->SelectedTabID; node_settings.SplitAxis = node->IsSplitNode() ? (char)node->SplitAxis : ImGuiAxis_None; node_settings.Depth = (char)depth; - node_settings.IsExplicitRoot = (char)node->IsExplicitRoot; + node_settings.IsDockSpace = (char)node->IsDockSpace; node_settings.IsDocumentRoot = (char)node->IsDocumentRoot; node_settings.Pos = ImVec2ih((short)node->Pos.x, (short)node->Pos.y); node_settings.Size = ImVec2ih((short)node->Size.x, (short)node->Size.y); @@ -11874,8 +11887,8 @@ buf->appendf(" Pos=%d,%d Size=%d,%d", node_settings->Pos.x, node_settings->Pos.y, node_settings->Size.x, node_settings->Size.y); if (node_settings->SplitAxis != ImGuiAxis_None) buf->appendf(" Split=%c", (node_settings->SplitAxis == ImGuiAxis_X) ? 'X' : 'Y'); - if (node_settings->IsExplicitRoot) - buf->appendf(" ExplicitRoot=%d", node_settings->IsExplicitRoot); + if (node_settings->IsDockSpace) + buf->appendf(" ExplicitRoot=%d", node_settings->IsDockSpace); if (node_settings->IsDocumentRoot) buf->appendf(" DocumentRoot=%d", node_settings->IsDocumentRoot); if (node_settings->SelectedTabID) @@ -12729,7 +12742,7 @@ node->Pos.x, node->Pos.y, node->Size.x, node->Size.y, node->SizeRef.x, node->SizeRef.y); ImGui::BulletText("Flags %02X%s%s%s%s", - node->Flags, node->IsExplicitRoot ? ", IsExplicitRoot" : "", node->IsDocumentRoot ? ", IsDocumentRoot" : "", + node->Flags, node->IsDockSpace ? ", IsDockSpace" : "", node->IsDocumentRoot ? ", IsDocumentRoot" : "", (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.cpp b/imgui.cpp index 5409d56..eefb6c5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5616,7 +5616,7 @@ // Docking: report contents sizes to parent to allow for auto-resize if (window->DockNode && window->DockTabIsVisible) - if (ImGuiWindow* host_window = window->DockNode->HostWindow) // FIXME-DOCKSPACE + if (ImGuiWindow* host_window = window->DockNode->HostWindow) // FIXME-DOCK host_window->DC.CursorMaxPos = window->DC.CursorMaxPos + window->WindowPadding - host_window->WindowPadding; // Pop from window stack @@ -9517,7 +9517,7 @@ // Docking: ImGuiDockContext Docking/Undocking functions // Docking: ImGuiDockNode // Docking: ImGuiDockNode Tree manipulation functions -// Docking: Public Functions (Dockspace, SetWindowDock) +// Docking: Public Functions (SetWindowDock, DockSpace) // Docking: Public Builder Functions // Docking: Begin/End Functions (called from Begin/End) // Docking: Settings @@ -9606,12 +9606,12 @@ ImGuiID SelectedTabID; char SplitAxis; char Depth; - char IsExplicitRoot; + char IsDockSpace; char IsDocumentRoot; ImVec2ih Pos; ImVec2ih Size; ImVec2ih SizeRef; - ImGuiDockNodeSettings() { ID = ParentID = SelectedTabID = 0; SplitAxis = ImGuiAxis_None; Depth = 0; IsExplicitRoot = IsDocumentRoot = 0; } + ImGuiDockNodeSettings() { ID = ParentID = SelectedTabID = 0; SplitAxis = ImGuiAxis_None; Depth = 0; IsDockSpace = IsDocumentRoot = 0; } }; struct ImGuiDockContext @@ -9794,7 +9794,7 @@ // 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->IsExplicitRoot && node->IsRootNode()) + if (!node->IsDockSpace && node->IsRootNode()) DockNodeUpdate(node); } @@ -9983,7 +9983,7 @@ node->ParentNode->ChildNodes[1] = node; node->SelectedTabID = node_settings->SelectedTabID; node->SplitAxis = node_settings->SplitAxis; - node->IsExplicitRoot = node_settings->IsExplicitRoot != 0; + node->IsDockSpace = node_settings->IsDockSpace != 0; node->IsDocumentRoot = node_settings->IsDocumentRoot != 0; // Bind host window immediately if it already exist (in case of a rebuild) @@ -10218,7 +10218,7 @@ SelectedTabID = 0; WantCloseTabID = 0; IsVisible = true; - InitFromFirstWindow = IsExplicitRoot = IsDocumentRoot = HasCloseButton = HasCollapseButton = WantCloseAll = WantLockSizeOnce = WantMouseMove = false; + InitFromFirstWindow = IsDockSpace = IsDocumentRoot = HasCloseButton = HasCollapseButton = WantCloseAll = WantLockSizeOnce = WantMouseMove = false; } ImGuiDockNode::~ImGuiDockNode() @@ -10242,7 +10242,7 @@ ImGuiContext& g = *GImGui; (void)g; if (window->DockNode) { - // Can overwrite an existing window->DockNode (e.g. pointing to a disabled DockSpace) + // Can overwrite an existing window->DockNode (e.g. pointing to a disabled DockSpace node) IM_ASSERT(window->DockNode->ID != node->ID); DockNodeRemoveWindow(window->DockNode, window, 0); } @@ -10264,7 +10264,7 @@ } // When reactivating a node from two loose window, the target window pos/size are authoritative - if (node->Windows.Size == 2 && !node->IsExplicitRoot) + if (node->Windows.Size == 2 && !node->IsDockSpace) node->InitFromFirstWindow = true; if (node->TabBar == NULL) @@ -10470,7 +10470,7 @@ static void ImGui::DockNodeUpdateVisibleFlag(ImGuiDockNode* node) { // Update visibility flag - bool is_visible = (node->ParentNode == 0) ? node->IsExplicitRoot : node->IsDocumentRoot; + bool is_visible = (node->ParentNode == 0) ? node->IsDockSpace : node->IsDocumentRoot; is_visible |= (node->Windows.Size > 0); is_visible |= (node->ChildNodes[0] && node->ChildNodes[0]->IsVisible); is_visible |= (node->ChildNodes[1] && node->ChildNodes[1]->IsVisible); @@ -10498,7 +10498,7 @@ DockNodeUpdateVisibleFlagAndInactiveChilds(node); // Find if there's only a single visible window in the hierarchy (in which case we need to display a regular title bar, FIXME-DOCK: Not done yet!) - if (!node->IsExplicitRoot) + if (!node->IsDockSpace) { int count = 0; ImGuiDockNode* first_node_with_windows = NULL; @@ -10512,7 +10512,7 @@ } // 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->IsExplicitRoot) + if (node->IsRootNode() && node->Windows.Size == 1 && !node->IsDockSpace) { // Floating window pos/size is authoritative node->Pos = node->Windows[0]->Pos; @@ -10536,9 +10536,9 @@ ImGuiWindow* host_window = NULL; bool beginned_into_host_window = false; - if (node->IsExplicitRoot) + if (node->IsDockSpace) { - // [Explicit root node] + // [Explicit root dockspace node] IM_ASSERT(node->HostWindow); node->HasCloseButton = false; node->HasCollapseButton = true; @@ -10674,9 +10674,9 @@ node->WantCloseAll = false; node->WantCloseTabID = 0; - // Move ourselves to the Menu layer + Undo SkipItems flag in order to draw over the title bar (even if the window is collapsed) + // 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->IsExplicitRoot) + if (!node->IsDockSpace) { host_window->SkipItems = false; host_window->DC.NavLayerCurrent++; @@ -10761,7 +10761,7 @@ // Begin tab bar ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_NoTabListPopupButton;// | ImGuiTabBarFlags_NoTabListScrollingButtons); tab_bar_flags |= ImGuiTabBarFlags_SaveSettings; - tab_bar_flags |= ImGuiTabBarFlags_DockNode | (node->IsExplicitRoot ? ImGuiTabBarFlags_DockNodeExplicitRoot : 0); + tab_bar_flags |= ImGuiTabBarFlags_DockNode | (node->IsDockSpace ? ImGuiTabBarFlags_DockNodeExplicitRoot : 0); if (!host_window->Collapsed && is_focused) tab_bar_flags |= ImGuiTabBarFlags_IsFocused; BeginTabBarEx(node->TabBar, tab_bar_rect, tab_bar_flags, node); @@ -10789,6 +10789,7 @@ if (tab_bar->VisibleTabId == window->ID) node->VisibleWindow = window; + // Store last item data so it can be queried with IsItemXXX functions after the user Begin() call window->DockTabItemStatusFlags = host_window->DC.LastItemStatusFlags; window->DockTabItemRect = host_window->DC.LastItemRect; @@ -10853,7 +10854,7 @@ PopID(); // Restore SkipItems flag - if (!node->IsExplicitRoot) + if (!node->IsDockSpace) { host_window->DC.NavLayerCurrent--; host_window->DC.NavLayerCurrentMask >>= 1; @@ -10863,7 +10864,7 @@ static bool DockNodeIsDropAllowedOne(ImGuiWindow* payload, ImGuiWindow* host_window) { - if ((host_window->Flags & ImGuiWindowFlags_DockNodeHost) && host_window->DockNodeAsHost->IsExplicitRoot && payload->BeginOrderWithinContext < host_window->BeginOrderWithinContext) + if ((host_window->Flags & ImGuiWindowFlags_DockNodeHost) && host_window->DockNodeAsHost->IsDockSpace && payload->BeginOrderWithinContext < host_window->BeginOrderWithinContext) return false; ImGuiID host_user_type_id = host_window->DockNodeAsHost ? host_window->DockNodeAsHost->UserTypeIdFilter : host_window->UserTypeId; @@ -10999,7 +11000,7 @@ data->IsCenterAvailable = false; data->IsSidesAvailable = true; - if (host_node && (host_node->Flags & ImGuiDockSpaceFlags_NoSplit)) + if (host_node && (host_node->Flags & ImGuiDockNodeFlags_NoSplit)) data->IsSidesAvailable = false; if (!is_outer_docking && host_node && host_node->ParentNode == NULL && host_node->IsDocumentRoot) data->IsSidesAvailable = false; @@ -11139,7 +11140,7 @@ } // Stop after ImGuiDir_None - if (host_node && (host_node->Flags & ImGuiDockSpaceFlags_NoSplit)) + if (host_node && (host_node->Flags & ImGuiDockNodeFlags_NoSplit)) return; } } @@ -11418,7 +11419,7 @@ } //----------------------------------------------------------------------------- -// Docking: Public Functions (SetWindowDock, Dockspace) +// Docking: Public Functions (SetWindowDock, DockSpace) //----------------------------------------------------------------------------- void ImGui::SetWindowDock(ImGuiWindow* window, ImGuiID dock_id, ImGuiCond cond) @@ -11436,14 +11437,14 @@ window->DockId = dock_id; } -void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockSpaceFlags dock_space_flags, ImGuiID user_type_filter) +// Create an explicit dockspace node within an existing window. Also expose dock node flags and creates a DocumentRoot node by default. +// The DocumentRoot node is always displayed even when empty and shrink/extend according to the requested size of its neighbors. +void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags dock_space_flags, ImGuiID user_type_filter) { ImGuiContext* ctx = GImGui; ImGuiContext& g = *ctx; - ImGuiWindow* window = GetCurrentWindow(); - // It is possible that the node has already been claimed by a docked window which appeared before the DockSpace(), so we overwrite IsExplicit again. ImGuiDockNode* node = DockContextFindNodeByID(ctx, id); if (!node) { @@ -11452,14 +11453,19 @@ } node->Flags = dock_space_flags; node->UserTypeIdFilter = user_type_filter; - node->IsExplicitRoot = true; // When a Dockspace transitioned form implicit to explicit this may be called a second time + // 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) + { + IM_ASSERT(node->IsDockSpace == false && "Cannot call DockSpace() twice a frame with the same ID"); + node->IsDockSpace = true; return; + } + node->IsDockSpace = true; // Keep alive mode, this is allow windows docked into this node so stay docked even if they are not visible - if (dock_space_flags & ImGuiDockSpaceFlags_KeepAliveOnly) + if (dock_space_flags & ImGuiDockNodeFlags_KeepAliveOnly) { node->LastFrameAlive = g.FrameCount; return; @@ -11512,11 +11518,18 @@ { ImGuiID window_id = ImHash(window_name, 0); if (ImGuiWindow* window = FindWindowByID(window_id)) + { + // Apply to created window SetWindowDock(window, node_id, ImGuiCond_Always); - else if (ImGuiWindowSettings* settings = FindWindowSettings(window_id)) + } + else + { + // Apply to settings + ImGuiWindowSettings* settings = FindWindowSettings(window_id); + if (settings == NULL) + settings = CreateNewWindowSettings(window_name); settings->DockId = node_id; - else if (ImGuiWindowSettings* settings = CreateNewWindowSettings(window_name)) - settings->DockId = node_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) @@ -11597,11 +11610,11 @@ g.NextWindowData.PosUndock = false; } - // Undock if our dockspace disappeared - // Note how we are testing for LastFrameAlive and NOT LastFrameActive. A DockSpace can be maintained alive while being inactive with ImGuiDockSpaceFlags_KeepAliveOnly. + // Undock if our dockspace node disappeared + // Note how we are testing for LastFrameAlive and NOT LastFrameActive. A DockSpace node can be maintained alive while being inactive with ImGuiDockNodeFlags_KeepAliveOnly. if (dock_node->LastFrameAlive < g.FrameCount) { - // If the window has been orphaned (lost its dockspace), transition the docknode to an implicit node processed in DockContextUpdateDocking() + // If the window has been orphaned, transition the docknode to an implicit node processed in DockContextUpdateDocking() ImGuiDockNode* root_node = DockNodeGetRootNode(dock_node); if (root_node->LastFrameAlive < g.FrameCount) { @@ -11622,7 +11635,7 @@ return; } - // FIXME-DOCKSPACE: 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 (dock_node->HostWindow == NULL) { window->DockTabIsVisible = false; @@ -11639,7 +11652,7 @@ window->DockIsActive = true; window->DockTabIsVisible = false; - if (dock_node->Flags & ImGuiDockSpaceFlags_KeepAliveOnly) + if (dock_node->Flags & ImGuiDockNodeFlags_KeepAliveOnly) return; if (dock_node->TabBar && dock_node->TabBar->VisibleTabId == window->ID) @@ -11812,7 +11825,7 @@ if (sscanf(line, " SizeRef=%i,%i%n", &x, &y, &r) == 2) { line += r; node.SizeRef = ImVec2ih((short)x, (short)y); } } if (sscanf(line, " Split=%c%n", &c, &r) == 1) { line += r; if (c == 'X') node.SplitAxis = ImGuiAxis_X; else if (c == 'Y') node.SplitAxis = ImGuiAxis_Y; } - if (sscanf(line, " ExplicitRoot=%d%n", &x, &r) == 1) { line += r; node.IsExplicitRoot = (x != 0); } + if (sscanf(line, " ExplicitRoot=%d%n", &x, &r) == 1) { line += r; node.IsDockSpace = (x != 0); } if (sscanf(line, " DocumentRoot=%d%n", &x, &r) == 1) { line += r; node.IsDocumentRoot = (x != 0); } if (sscanf(line, " SelectedTab=0x%08X%n", &node.SelectedTabID,&r) == 1) { line += r; } //if (node.ParentID == 0 && node.SplitAxis == ImGuiAxis_None) @@ -11833,7 +11846,7 @@ node_settings.SelectedTabID = node->SelectedTabID; node_settings.SplitAxis = node->IsSplitNode() ? (char)node->SplitAxis : ImGuiAxis_None; node_settings.Depth = (char)depth; - node_settings.IsExplicitRoot = (char)node->IsExplicitRoot; + node_settings.IsDockSpace = (char)node->IsDockSpace; node_settings.IsDocumentRoot = (char)node->IsDocumentRoot; node_settings.Pos = ImVec2ih((short)node->Pos.x, (short)node->Pos.y); node_settings.Size = ImVec2ih((short)node->Size.x, (short)node->Size.y); @@ -11874,8 +11887,8 @@ buf->appendf(" Pos=%d,%d Size=%d,%d", node_settings->Pos.x, node_settings->Pos.y, node_settings->Size.x, node_settings->Size.y); if (node_settings->SplitAxis != ImGuiAxis_None) buf->appendf(" Split=%c", (node_settings->SplitAxis == ImGuiAxis_X) ? 'X' : 'Y'); - if (node_settings->IsExplicitRoot) - buf->appendf(" ExplicitRoot=%d", node_settings->IsExplicitRoot); + if (node_settings->IsDockSpace) + buf->appendf(" ExplicitRoot=%d", node_settings->IsDockSpace); if (node_settings->IsDocumentRoot) buf->appendf(" DocumentRoot=%d", node_settings->IsDocumentRoot); if (node_settings->SelectedTabID) @@ -12729,7 +12742,7 @@ node->Pos.x, node->Pos.y, node->Size.x, node->Size.y, node->SizeRef.x, node->SizeRef.y); ImGui::BulletText("Flags %02X%s%s%s%s", - node->Flags, node->IsExplicitRoot ? ", IsExplicitRoot" : "", node->IsDocumentRoot ? ", IsDocumentRoot" : "", + node->Flags, node->IsDockSpace ? ", IsDockSpace" : "", node->IsDocumentRoot ? ", IsDocumentRoot" : "", (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.h b/imgui.h index cdb2b3b..0c13859 100644 --- a/imgui.h +++ b/imgui.h @@ -111,7 +111,7 @@ typedef int ImGuiColumnsFlags; // -> enum ImGuiColumnsFlags_ // Flags: for Columns(), BeginColumns() typedef int ImGuiConfigFlags; // -> enum ImGuiConfigFlags_ // Flags: for io.ConfigFlags typedef int ImGuiComboFlags; // -> enum ImGuiComboFlags_ // Flags: for BeginCombo() -typedef int ImGuiDockSpaceFlags; // -> enum ImGuiDockSpaceFlags_ // Flags: for DockSpace() +typedef int ImGuiDockNodeFlags; // -> enum ImGuiDockNodeFlags_ // Flags: for DockSpace() typedef int ImGuiDragDropFlags; // -> enum ImGuiDragDropFlags_ // Flags: for *DragDrop*() typedef int ImGuiFocusedFlags; // -> enum ImGuiFocusedFlags_ // Flags: for IsWindowFocused() typedef int ImGuiHoveredFlags; // -> enum ImGuiHoveredFlags_ // Flags: for IsItemHovered(), IsWindowHovered() etc. @@ -517,8 +517,9 @@ // Docking // [BETA API] Enable with io.ConfigFlags |= ImGuiConfigFlags_DockingEnable. - // Note: you DO NOT need to call DockSpace() to use most Docking facilities! You can hold SHIFT anywhere while moving windows. Use DockSpace() if you need to create an explicit docking space _within_ an existing window. See Docking demo for details) - IMGUI_API void DockSpace(ImGuiID id, const ImVec2& size = ImVec2(0, 0), ImGuiDockSpaceFlags flags = 0, ImGuiID user_type_filter = 0); + // Note: you DO NOT need to call DockSpace() to use most Docking facilities! You can hold SHIFT anywhere while moving windows. + // Use DockSpace() to create an explicit dock node _within_ an existing window. See Docking demo for details. + IMGUI_API void DockSpace(ImGuiID id, const ImVec2& size = ImVec2(0, 0), ImGuiDockNodeFlags flags = 0, ImGuiID user_type_filter = 0); IMGUI_API void SetNextWindowDock(ImGuiID dock_id, ImGuiCond cond = 0); // set next window dock id (FIXME-DOCK) IMGUI_API void SetNextWindowUserType(ImGuiID user_type); // FIXME-DOCK: set next window user type (docking filters by same user_type) IMGUI_API bool IsWindowDocked(); // is current window docked into another window? @@ -782,11 +783,11 @@ }; // Flags for ImGui::DockSpace() -enum ImGuiDockSpaceFlags_ +enum ImGuiDockNodeFlags_ { - ImGuiDockSpaceFlags_None = 0, - ImGuiDockSpaceFlags_KeepAliveOnly = 1 << 0, // Don't create/display the dockspace but keep it alive. Windows docked into this dockspace won't be undocked. - ImGuiDockSpaceFlags_NoSplit = 1 << 1 // Disable splitting the dockspace into smaller nodes. Useful e.g. when embedding dockspaces into a main root one. + ImGuiDockNodeFlags_None = 0, + ImGuiDockNodeFlags_KeepAliveOnly = 1 << 0, // Don't display the dockspace node but keep it alive. Windows docked into this dockspace node won't be undocked. + ImGuiDockNodeFlags_NoSplit = 1 << 1 // Disable splitting the node into smaller nodes. Useful e.g. when embedding dockspaces into a main root one (the root one may have splitting disableed to reduce confusion) }; // Flags for ImGui::IsWindowFocused() diff --git a/imgui.cpp b/imgui.cpp index 5409d56..eefb6c5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5616,7 +5616,7 @@ // Docking: report contents sizes to parent to allow for auto-resize if (window->DockNode && window->DockTabIsVisible) - if (ImGuiWindow* host_window = window->DockNode->HostWindow) // FIXME-DOCKSPACE + if (ImGuiWindow* host_window = window->DockNode->HostWindow) // FIXME-DOCK host_window->DC.CursorMaxPos = window->DC.CursorMaxPos + window->WindowPadding - host_window->WindowPadding; // Pop from window stack @@ -9517,7 +9517,7 @@ // Docking: ImGuiDockContext Docking/Undocking functions // Docking: ImGuiDockNode // Docking: ImGuiDockNode Tree manipulation functions -// Docking: Public Functions (Dockspace, SetWindowDock) +// Docking: Public Functions (SetWindowDock, DockSpace) // Docking: Public Builder Functions // Docking: Begin/End Functions (called from Begin/End) // Docking: Settings @@ -9606,12 +9606,12 @@ ImGuiID SelectedTabID; char SplitAxis; char Depth; - char IsExplicitRoot; + char IsDockSpace; char IsDocumentRoot; ImVec2ih Pos; ImVec2ih Size; ImVec2ih SizeRef; - ImGuiDockNodeSettings() { ID = ParentID = SelectedTabID = 0; SplitAxis = ImGuiAxis_None; Depth = 0; IsExplicitRoot = IsDocumentRoot = 0; } + ImGuiDockNodeSettings() { ID = ParentID = SelectedTabID = 0; SplitAxis = ImGuiAxis_None; Depth = 0; IsDockSpace = IsDocumentRoot = 0; } }; struct ImGuiDockContext @@ -9794,7 +9794,7 @@ // 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->IsExplicitRoot && node->IsRootNode()) + if (!node->IsDockSpace && node->IsRootNode()) DockNodeUpdate(node); } @@ -9983,7 +9983,7 @@ node->ParentNode->ChildNodes[1] = node; node->SelectedTabID = node_settings->SelectedTabID; node->SplitAxis = node_settings->SplitAxis; - node->IsExplicitRoot = node_settings->IsExplicitRoot != 0; + node->IsDockSpace = node_settings->IsDockSpace != 0; node->IsDocumentRoot = node_settings->IsDocumentRoot != 0; // Bind host window immediately if it already exist (in case of a rebuild) @@ -10218,7 +10218,7 @@ SelectedTabID = 0; WantCloseTabID = 0; IsVisible = true; - InitFromFirstWindow = IsExplicitRoot = IsDocumentRoot = HasCloseButton = HasCollapseButton = WantCloseAll = WantLockSizeOnce = WantMouseMove = false; + InitFromFirstWindow = IsDockSpace = IsDocumentRoot = HasCloseButton = HasCollapseButton = WantCloseAll = WantLockSizeOnce = WantMouseMove = false; } ImGuiDockNode::~ImGuiDockNode() @@ -10242,7 +10242,7 @@ ImGuiContext& g = *GImGui; (void)g; if (window->DockNode) { - // Can overwrite an existing window->DockNode (e.g. pointing to a disabled DockSpace) + // Can overwrite an existing window->DockNode (e.g. pointing to a disabled DockSpace node) IM_ASSERT(window->DockNode->ID != node->ID); DockNodeRemoveWindow(window->DockNode, window, 0); } @@ -10264,7 +10264,7 @@ } // When reactivating a node from two loose window, the target window pos/size are authoritative - if (node->Windows.Size == 2 && !node->IsExplicitRoot) + if (node->Windows.Size == 2 && !node->IsDockSpace) node->InitFromFirstWindow = true; if (node->TabBar == NULL) @@ -10470,7 +10470,7 @@ static void ImGui::DockNodeUpdateVisibleFlag(ImGuiDockNode* node) { // Update visibility flag - bool is_visible = (node->ParentNode == 0) ? node->IsExplicitRoot : node->IsDocumentRoot; + bool is_visible = (node->ParentNode == 0) ? node->IsDockSpace : node->IsDocumentRoot; is_visible |= (node->Windows.Size > 0); is_visible |= (node->ChildNodes[0] && node->ChildNodes[0]->IsVisible); is_visible |= (node->ChildNodes[1] && node->ChildNodes[1]->IsVisible); @@ -10498,7 +10498,7 @@ DockNodeUpdateVisibleFlagAndInactiveChilds(node); // Find if there's only a single visible window in the hierarchy (in which case we need to display a regular title bar, FIXME-DOCK: Not done yet!) - if (!node->IsExplicitRoot) + if (!node->IsDockSpace) { int count = 0; ImGuiDockNode* first_node_with_windows = NULL; @@ -10512,7 +10512,7 @@ } // 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->IsExplicitRoot) + if (node->IsRootNode() && node->Windows.Size == 1 && !node->IsDockSpace) { // Floating window pos/size is authoritative node->Pos = node->Windows[0]->Pos; @@ -10536,9 +10536,9 @@ ImGuiWindow* host_window = NULL; bool beginned_into_host_window = false; - if (node->IsExplicitRoot) + if (node->IsDockSpace) { - // [Explicit root node] + // [Explicit root dockspace node] IM_ASSERT(node->HostWindow); node->HasCloseButton = false; node->HasCollapseButton = true; @@ -10674,9 +10674,9 @@ node->WantCloseAll = false; node->WantCloseTabID = 0; - // Move ourselves to the Menu layer + Undo SkipItems flag in order to draw over the title bar (even if the window is collapsed) + // 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->IsExplicitRoot) + if (!node->IsDockSpace) { host_window->SkipItems = false; host_window->DC.NavLayerCurrent++; @@ -10761,7 +10761,7 @@ // Begin tab bar ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_NoTabListPopupButton;// | ImGuiTabBarFlags_NoTabListScrollingButtons); tab_bar_flags |= ImGuiTabBarFlags_SaveSettings; - tab_bar_flags |= ImGuiTabBarFlags_DockNode | (node->IsExplicitRoot ? ImGuiTabBarFlags_DockNodeExplicitRoot : 0); + tab_bar_flags |= ImGuiTabBarFlags_DockNode | (node->IsDockSpace ? ImGuiTabBarFlags_DockNodeExplicitRoot : 0); if (!host_window->Collapsed && is_focused) tab_bar_flags |= ImGuiTabBarFlags_IsFocused; BeginTabBarEx(node->TabBar, tab_bar_rect, tab_bar_flags, node); @@ -10789,6 +10789,7 @@ if (tab_bar->VisibleTabId == window->ID) node->VisibleWindow = window; + // Store last item data so it can be queried with IsItemXXX functions after the user Begin() call window->DockTabItemStatusFlags = host_window->DC.LastItemStatusFlags; window->DockTabItemRect = host_window->DC.LastItemRect; @@ -10853,7 +10854,7 @@ PopID(); // Restore SkipItems flag - if (!node->IsExplicitRoot) + if (!node->IsDockSpace) { host_window->DC.NavLayerCurrent--; host_window->DC.NavLayerCurrentMask >>= 1; @@ -10863,7 +10864,7 @@ static bool DockNodeIsDropAllowedOne(ImGuiWindow* payload, ImGuiWindow* host_window) { - if ((host_window->Flags & ImGuiWindowFlags_DockNodeHost) && host_window->DockNodeAsHost->IsExplicitRoot && payload->BeginOrderWithinContext < host_window->BeginOrderWithinContext) + if ((host_window->Flags & ImGuiWindowFlags_DockNodeHost) && host_window->DockNodeAsHost->IsDockSpace && payload->BeginOrderWithinContext < host_window->BeginOrderWithinContext) return false; ImGuiID host_user_type_id = host_window->DockNodeAsHost ? host_window->DockNodeAsHost->UserTypeIdFilter : host_window->UserTypeId; @@ -10999,7 +11000,7 @@ data->IsCenterAvailable = false; data->IsSidesAvailable = true; - if (host_node && (host_node->Flags & ImGuiDockSpaceFlags_NoSplit)) + if (host_node && (host_node->Flags & ImGuiDockNodeFlags_NoSplit)) data->IsSidesAvailable = false; if (!is_outer_docking && host_node && host_node->ParentNode == NULL && host_node->IsDocumentRoot) data->IsSidesAvailable = false; @@ -11139,7 +11140,7 @@ } // Stop after ImGuiDir_None - if (host_node && (host_node->Flags & ImGuiDockSpaceFlags_NoSplit)) + if (host_node && (host_node->Flags & ImGuiDockNodeFlags_NoSplit)) return; } } @@ -11418,7 +11419,7 @@ } //----------------------------------------------------------------------------- -// Docking: Public Functions (SetWindowDock, Dockspace) +// Docking: Public Functions (SetWindowDock, DockSpace) //----------------------------------------------------------------------------- void ImGui::SetWindowDock(ImGuiWindow* window, ImGuiID dock_id, ImGuiCond cond) @@ -11436,14 +11437,14 @@ window->DockId = dock_id; } -void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockSpaceFlags dock_space_flags, ImGuiID user_type_filter) +// Create an explicit dockspace node within an existing window. Also expose dock node flags and creates a DocumentRoot node by default. +// The DocumentRoot node is always displayed even when empty and shrink/extend according to the requested size of its neighbors. +void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags dock_space_flags, ImGuiID user_type_filter) { ImGuiContext* ctx = GImGui; ImGuiContext& g = *ctx; - ImGuiWindow* window = GetCurrentWindow(); - // It is possible that the node has already been claimed by a docked window which appeared before the DockSpace(), so we overwrite IsExplicit again. ImGuiDockNode* node = DockContextFindNodeByID(ctx, id); if (!node) { @@ -11452,14 +11453,19 @@ } node->Flags = dock_space_flags; node->UserTypeIdFilter = user_type_filter; - node->IsExplicitRoot = true; // When a Dockspace transitioned form implicit to explicit this may be called a second time + // 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) + { + IM_ASSERT(node->IsDockSpace == false && "Cannot call DockSpace() twice a frame with the same ID"); + node->IsDockSpace = true; return; + } + node->IsDockSpace = true; // Keep alive mode, this is allow windows docked into this node so stay docked even if they are not visible - if (dock_space_flags & ImGuiDockSpaceFlags_KeepAliveOnly) + if (dock_space_flags & ImGuiDockNodeFlags_KeepAliveOnly) { node->LastFrameAlive = g.FrameCount; return; @@ -11512,11 +11518,18 @@ { ImGuiID window_id = ImHash(window_name, 0); if (ImGuiWindow* window = FindWindowByID(window_id)) + { + // Apply to created window SetWindowDock(window, node_id, ImGuiCond_Always); - else if (ImGuiWindowSettings* settings = FindWindowSettings(window_id)) + } + else + { + // Apply to settings + ImGuiWindowSettings* settings = FindWindowSettings(window_id); + if (settings == NULL) + settings = CreateNewWindowSettings(window_name); settings->DockId = node_id; - else if (ImGuiWindowSettings* settings = CreateNewWindowSettings(window_name)) - settings->DockId = node_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) @@ -11597,11 +11610,11 @@ g.NextWindowData.PosUndock = false; } - // Undock if our dockspace disappeared - // Note how we are testing for LastFrameAlive and NOT LastFrameActive. A DockSpace can be maintained alive while being inactive with ImGuiDockSpaceFlags_KeepAliveOnly. + // Undock if our dockspace node disappeared + // Note how we are testing for LastFrameAlive and NOT LastFrameActive. A DockSpace node can be maintained alive while being inactive with ImGuiDockNodeFlags_KeepAliveOnly. if (dock_node->LastFrameAlive < g.FrameCount) { - // If the window has been orphaned (lost its dockspace), transition the docknode to an implicit node processed in DockContextUpdateDocking() + // If the window has been orphaned, transition the docknode to an implicit node processed in DockContextUpdateDocking() ImGuiDockNode* root_node = DockNodeGetRootNode(dock_node); if (root_node->LastFrameAlive < g.FrameCount) { @@ -11622,7 +11635,7 @@ return; } - // FIXME-DOCKSPACE: 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 (dock_node->HostWindow == NULL) { window->DockTabIsVisible = false; @@ -11639,7 +11652,7 @@ window->DockIsActive = true; window->DockTabIsVisible = false; - if (dock_node->Flags & ImGuiDockSpaceFlags_KeepAliveOnly) + if (dock_node->Flags & ImGuiDockNodeFlags_KeepAliveOnly) return; if (dock_node->TabBar && dock_node->TabBar->VisibleTabId == window->ID) @@ -11812,7 +11825,7 @@ if (sscanf(line, " SizeRef=%i,%i%n", &x, &y, &r) == 2) { line += r; node.SizeRef = ImVec2ih((short)x, (short)y); } } if (sscanf(line, " Split=%c%n", &c, &r) == 1) { line += r; if (c == 'X') node.SplitAxis = ImGuiAxis_X; else if (c == 'Y') node.SplitAxis = ImGuiAxis_Y; } - if (sscanf(line, " ExplicitRoot=%d%n", &x, &r) == 1) { line += r; node.IsExplicitRoot = (x != 0); } + if (sscanf(line, " ExplicitRoot=%d%n", &x, &r) == 1) { line += r; node.IsDockSpace = (x != 0); } if (sscanf(line, " DocumentRoot=%d%n", &x, &r) == 1) { line += r; node.IsDocumentRoot = (x != 0); } if (sscanf(line, " SelectedTab=0x%08X%n", &node.SelectedTabID,&r) == 1) { line += r; } //if (node.ParentID == 0 && node.SplitAxis == ImGuiAxis_None) @@ -11833,7 +11846,7 @@ node_settings.SelectedTabID = node->SelectedTabID; node_settings.SplitAxis = node->IsSplitNode() ? (char)node->SplitAxis : ImGuiAxis_None; node_settings.Depth = (char)depth; - node_settings.IsExplicitRoot = (char)node->IsExplicitRoot; + node_settings.IsDockSpace = (char)node->IsDockSpace; node_settings.IsDocumentRoot = (char)node->IsDocumentRoot; node_settings.Pos = ImVec2ih((short)node->Pos.x, (short)node->Pos.y); node_settings.Size = ImVec2ih((short)node->Size.x, (short)node->Size.y); @@ -11874,8 +11887,8 @@ buf->appendf(" Pos=%d,%d Size=%d,%d", node_settings->Pos.x, node_settings->Pos.y, node_settings->Size.x, node_settings->Size.y); if (node_settings->SplitAxis != ImGuiAxis_None) buf->appendf(" Split=%c", (node_settings->SplitAxis == ImGuiAxis_X) ? 'X' : 'Y'); - if (node_settings->IsExplicitRoot) - buf->appendf(" ExplicitRoot=%d", node_settings->IsExplicitRoot); + if (node_settings->IsDockSpace) + buf->appendf(" ExplicitRoot=%d", node_settings->IsDockSpace); if (node_settings->IsDocumentRoot) buf->appendf(" DocumentRoot=%d", node_settings->IsDocumentRoot); if (node_settings->SelectedTabID) @@ -12729,7 +12742,7 @@ node->Pos.x, node->Pos.y, node->Size.x, node->Size.y, node->SizeRef.x, node->SizeRef.y); ImGui::BulletText("Flags %02X%s%s%s%s", - node->Flags, node->IsExplicitRoot ? ", IsExplicitRoot" : "", node->IsDocumentRoot ? ", IsDocumentRoot" : "", + node->Flags, node->IsDockSpace ? ", IsDockSpace" : "", node->IsDocumentRoot ? ", IsDocumentRoot" : "", (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.h b/imgui.h index cdb2b3b..0c13859 100644 --- a/imgui.h +++ b/imgui.h @@ -111,7 +111,7 @@ typedef int ImGuiColumnsFlags; // -> enum ImGuiColumnsFlags_ // Flags: for Columns(), BeginColumns() typedef int ImGuiConfigFlags; // -> enum ImGuiConfigFlags_ // Flags: for io.ConfigFlags typedef int ImGuiComboFlags; // -> enum ImGuiComboFlags_ // Flags: for BeginCombo() -typedef int ImGuiDockSpaceFlags; // -> enum ImGuiDockSpaceFlags_ // Flags: for DockSpace() +typedef int ImGuiDockNodeFlags; // -> enum ImGuiDockNodeFlags_ // Flags: for DockSpace() typedef int ImGuiDragDropFlags; // -> enum ImGuiDragDropFlags_ // Flags: for *DragDrop*() typedef int ImGuiFocusedFlags; // -> enum ImGuiFocusedFlags_ // Flags: for IsWindowFocused() typedef int ImGuiHoveredFlags; // -> enum ImGuiHoveredFlags_ // Flags: for IsItemHovered(), IsWindowHovered() etc. @@ -517,8 +517,9 @@ // Docking // [BETA API] Enable with io.ConfigFlags |= ImGuiConfigFlags_DockingEnable. - // Note: you DO NOT need to call DockSpace() to use most Docking facilities! You can hold SHIFT anywhere while moving windows. Use DockSpace() if you need to create an explicit docking space _within_ an existing window. See Docking demo for details) - IMGUI_API void DockSpace(ImGuiID id, const ImVec2& size = ImVec2(0, 0), ImGuiDockSpaceFlags flags = 0, ImGuiID user_type_filter = 0); + // Note: you DO NOT need to call DockSpace() to use most Docking facilities! You can hold SHIFT anywhere while moving windows. + // Use DockSpace() to create an explicit dock node _within_ an existing window. See Docking demo for details. + IMGUI_API void DockSpace(ImGuiID id, const ImVec2& size = ImVec2(0, 0), ImGuiDockNodeFlags flags = 0, ImGuiID user_type_filter = 0); IMGUI_API void SetNextWindowDock(ImGuiID dock_id, ImGuiCond cond = 0); // set next window dock id (FIXME-DOCK) IMGUI_API void SetNextWindowUserType(ImGuiID user_type); // FIXME-DOCK: set next window user type (docking filters by same user_type) IMGUI_API bool IsWindowDocked(); // is current window docked into another window? @@ -782,11 +783,11 @@ }; // Flags for ImGui::DockSpace() -enum ImGuiDockSpaceFlags_ +enum ImGuiDockNodeFlags_ { - ImGuiDockSpaceFlags_None = 0, - ImGuiDockSpaceFlags_KeepAliveOnly = 1 << 0, // Don't create/display the dockspace but keep it alive. Windows docked into this dockspace won't be undocked. - ImGuiDockSpaceFlags_NoSplit = 1 << 1 // Disable splitting the dockspace into smaller nodes. Useful e.g. when embedding dockspaces into a main root one. + ImGuiDockNodeFlags_None = 0, + ImGuiDockNodeFlags_KeepAliveOnly = 1 << 0, // Don't display the dockspace node but keep it alive. Windows docked into this dockspace node won't be undocked. + ImGuiDockNodeFlags_NoSplit = 1 << 1 // Disable splitting the node into smaller nodes. Useful e.g. when embedding dockspaces into a main root one (the root one may have splitting disableed to reduce confusion) }; // Flags for ImGui::IsWindowFocused() diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 6cbf0cd..b199701 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -175,7 +175,7 @@ static bool show_app_window_titles = false; static bool show_app_custom_rendering = false; - if (show_app_dockspace) ShowExampleAppDockSpace(&show_app_dockspace); // Process the Docking app first, as explicit DockSpace() needs to be submitted early (read comments near the DockSpace function) + if (show_app_dockspace) ShowExampleAppDockSpace(&show_app_dockspace); // Process the Docking app first, as explicit DockSpace() nodes needs to be submitted early (read comments near the DockSpace function) if (show_app_documents) ShowExampleAppDocuments(&show_app_documents); // Process the Document app next, as it may also use a DockSpace() if (show_app_main_menu_bar) ShowExampleAppMainMenuBar(); if (show_app_console) ShowExampleAppConsole(&show_app_console); @@ -3692,7 +3692,7 @@ // [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace() //----------------------------------------------------------------------------- -// Demonstrate using DockSpace() to create an explicit docking spacing within an existing window. +// Demonstrate using DockSpace() to create an explicit docking node within an existing window. // Note that you already dock windows into each others _without_ a DockSpace() by just holding SHIFT when moving a window. // DockSpace() is only useful to construct to a central location for your application. void ShowExampleAppDockSpace(bool* p_open) @@ -3702,7 +3702,7 @@ // We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into. // Because 1) it would be confusing to have two docking targets within each others. - // and 2) we want our main DockSpace to always be visible (never hidden within a tab bar): if the DockSpace disappear its child windows will be orphaned. + // and 2) we want our main DockSpace node to always be visible (never hidden within a tab bar): if the DockSpace node disappear its child windows will be orphaned. ImGuiWindowFlags flags = ImGuiWindowFlags_MenuBar; flags |= ImGuiWindowFlags_NoDocking; if (opt_fullscreen) @@ -3737,9 +3737,9 @@ ShowHelpMarker( "You can _always_ dock _any_ window into another by holding the SHIFT key while moving a window. Try it now!" "\n" "This demo app has nothing to do with it!" "\n\n" - "This demo app only demonstrate the use of ImGui::DockSpace() which allows you to specify a docking spot _within_ another window. This is useful so you can decorate your main application window (e.g. with a menu bar)." "\n\n" + "This demo app only demonstrate the use of ImGui::DockSpace() which allows you to manually create a docking node _within_ another window. This is useful so you can decorate your main application window (e.g. with a menu bar)." "\n\n" "ImGui::DockSpace() comes with one hard constraint: it needs to be submitted _before_ any window which may be docked into it. Therefore, if you use a dock spot as the central point of your application, you'll probably want it to be part of the very first window you are submitting to imgui every frame." "\n\n" - "(NB: because of this constraint, the implicit \"Debug\" window can not be docked into an explicit DockSpace(), because that window is submitted as part of the NewFrame() call. An easy workaround is that you can create your own implicit \"Debug##2\" window after calling DockSpace() and leave it in the window stack for anyone to use.)" + "(NB: because of this constraint, the implicit \"Debug\" window can not be docked into an explicit DockSpace() node, because that window is submitted as part of the NewFrame() call. An easy workaround is that you can create your own implicit \"Debug##2\" window after calling DockSpace() and leave it in the window stack for anyone to use.)" ); ImGui::EndMenuBar(); @@ -3959,7 +3959,7 @@ { NotifyOfDocumentsClosedElsewhere(app); - // Create a DockSpace where any window can be docked + // Create a DockSpace node where any window can be docked ImGuiID dockspace_id = ImGui::GetID("MyDockSpace"); ImGui::DockSpace(dockspace_id); diff --git a/imgui.cpp b/imgui.cpp index 5409d56..eefb6c5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5616,7 +5616,7 @@ // Docking: report contents sizes to parent to allow for auto-resize if (window->DockNode && window->DockTabIsVisible) - if (ImGuiWindow* host_window = window->DockNode->HostWindow) // FIXME-DOCKSPACE + if (ImGuiWindow* host_window = window->DockNode->HostWindow) // FIXME-DOCK host_window->DC.CursorMaxPos = window->DC.CursorMaxPos + window->WindowPadding - host_window->WindowPadding; // Pop from window stack @@ -9517,7 +9517,7 @@ // Docking: ImGuiDockContext Docking/Undocking functions // Docking: ImGuiDockNode // Docking: ImGuiDockNode Tree manipulation functions -// Docking: Public Functions (Dockspace, SetWindowDock) +// Docking: Public Functions (SetWindowDock, DockSpace) // Docking: Public Builder Functions // Docking: Begin/End Functions (called from Begin/End) // Docking: Settings @@ -9606,12 +9606,12 @@ ImGuiID SelectedTabID; char SplitAxis; char Depth; - char IsExplicitRoot; + char IsDockSpace; char IsDocumentRoot; ImVec2ih Pos; ImVec2ih Size; ImVec2ih SizeRef; - ImGuiDockNodeSettings() { ID = ParentID = SelectedTabID = 0; SplitAxis = ImGuiAxis_None; Depth = 0; IsExplicitRoot = IsDocumentRoot = 0; } + ImGuiDockNodeSettings() { ID = ParentID = SelectedTabID = 0; SplitAxis = ImGuiAxis_None; Depth = 0; IsDockSpace = IsDocumentRoot = 0; } }; struct ImGuiDockContext @@ -9794,7 +9794,7 @@ // 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->IsExplicitRoot && node->IsRootNode()) + if (!node->IsDockSpace && node->IsRootNode()) DockNodeUpdate(node); } @@ -9983,7 +9983,7 @@ node->ParentNode->ChildNodes[1] = node; node->SelectedTabID = node_settings->SelectedTabID; node->SplitAxis = node_settings->SplitAxis; - node->IsExplicitRoot = node_settings->IsExplicitRoot != 0; + node->IsDockSpace = node_settings->IsDockSpace != 0; node->IsDocumentRoot = node_settings->IsDocumentRoot != 0; // Bind host window immediately if it already exist (in case of a rebuild) @@ -10218,7 +10218,7 @@ SelectedTabID = 0; WantCloseTabID = 0; IsVisible = true; - InitFromFirstWindow = IsExplicitRoot = IsDocumentRoot = HasCloseButton = HasCollapseButton = WantCloseAll = WantLockSizeOnce = WantMouseMove = false; + InitFromFirstWindow = IsDockSpace = IsDocumentRoot = HasCloseButton = HasCollapseButton = WantCloseAll = WantLockSizeOnce = WantMouseMove = false; } ImGuiDockNode::~ImGuiDockNode() @@ -10242,7 +10242,7 @@ ImGuiContext& g = *GImGui; (void)g; if (window->DockNode) { - // Can overwrite an existing window->DockNode (e.g. pointing to a disabled DockSpace) + // Can overwrite an existing window->DockNode (e.g. pointing to a disabled DockSpace node) IM_ASSERT(window->DockNode->ID != node->ID); DockNodeRemoveWindow(window->DockNode, window, 0); } @@ -10264,7 +10264,7 @@ } // When reactivating a node from two loose window, the target window pos/size are authoritative - if (node->Windows.Size == 2 && !node->IsExplicitRoot) + if (node->Windows.Size == 2 && !node->IsDockSpace) node->InitFromFirstWindow = true; if (node->TabBar == NULL) @@ -10470,7 +10470,7 @@ static void ImGui::DockNodeUpdateVisibleFlag(ImGuiDockNode* node) { // Update visibility flag - bool is_visible = (node->ParentNode == 0) ? node->IsExplicitRoot : node->IsDocumentRoot; + bool is_visible = (node->ParentNode == 0) ? node->IsDockSpace : node->IsDocumentRoot; is_visible |= (node->Windows.Size > 0); is_visible |= (node->ChildNodes[0] && node->ChildNodes[0]->IsVisible); is_visible |= (node->ChildNodes[1] && node->ChildNodes[1]->IsVisible); @@ -10498,7 +10498,7 @@ DockNodeUpdateVisibleFlagAndInactiveChilds(node); // Find if there's only a single visible window in the hierarchy (in which case we need to display a regular title bar, FIXME-DOCK: Not done yet!) - if (!node->IsExplicitRoot) + if (!node->IsDockSpace) { int count = 0; ImGuiDockNode* first_node_with_windows = NULL; @@ -10512,7 +10512,7 @@ } // 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->IsExplicitRoot) + if (node->IsRootNode() && node->Windows.Size == 1 && !node->IsDockSpace) { // Floating window pos/size is authoritative node->Pos = node->Windows[0]->Pos; @@ -10536,9 +10536,9 @@ ImGuiWindow* host_window = NULL; bool beginned_into_host_window = false; - if (node->IsExplicitRoot) + if (node->IsDockSpace) { - // [Explicit root node] + // [Explicit root dockspace node] IM_ASSERT(node->HostWindow); node->HasCloseButton = false; node->HasCollapseButton = true; @@ -10674,9 +10674,9 @@ node->WantCloseAll = false; node->WantCloseTabID = 0; - // Move ourselves to the Menu layer + Undo SkipItems flag in order to draw over the title bar (even if the window is collapsed) + // 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->IsExplicitRoot) + if (!node->IsDockSpace) { host_window->SkipItems = false; host_window->DC.NavLayerCurrent++; @@ -10761,7 +10761,7 @@ // Begin tab bar ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_NoTabListPopupButton;// | ImGuiTabBarFlags_NoTabListScrollingButtons); tab_bar_flags |= ImGuiTabBarFlags_SaveSettings; - tab_bar_flags |= ImGuiTabBarFlags_DockNode | (node->IsExplicitRoot ? ImGuiTabBarFlags_DockNodeExplicitRoot : 0); + tab_bar_flags |= ImGuiTabBarFlags_DockNode | (node->IsDockSpace ? ImGuiTabBarFlags_DockNodeExplicitRoot : 0); if (!host_window->Collapsed && is_focused) tab_bar_flags |= ImGuiTabBarFlags_IsFocused; BeginTabBarEx(node->TabBar, tab_bar_rect, tab_bar_flags, node); @@ -10789,6 +10789,7 @@ if (tab_bar->VisibleTabId == window->ID) node->VisibleWindow = window; + // Store last item data so it can be queried with IsItemXXX functions after the user Begin() call window->DockTabItemStatusFlags = host_window->DC.LastItemStatusFlags; window->DockTabItemRect = host_window->DC.LastItemRect; @@ -10853,7 +10854,7 @@ PopID(); // Restore SkipItems flag - if (!node->IsExplicitRoot) + if (!node->IsDockSpace) { host_window->DC.NavLayerCurrent--; host_window->DC.NavLayerCurrentMask >>= 1; @@ -10863,7 +10864,7 @@ static bool DockNodeIsDropAllowedOne(ImGuiWindow* payload, ImGuiWindow* host_window) { - if ((host_window->Flags & ImGuiWindowFlags_DockNodeHost) && host_window->DockNodeAsHost->IsExplicitRoot && payload->BeginOrderWithinContext < host_window->BeginOrderWithinContext) + if ((host_window->Flags & ImGuiWindowFlags_DockNodeHost) && host_window->DockNodeAsHost->IsDockSpace && payload->BeginOrderWithinContext < host_window->BeginOrderWithinContext) return false; ImGuiID host_user_type_id = host_window->DockNodeAsHost ? host_window->DockNodeAsHost->UserTypeIdFilter : host_window->UserTypeId; @@ -10999,7 +11000,7 @@ data->IsCenterAvailable = false; data->IsSidesAvailable = true; - if (host_node && (host_node->Flags & ImGuiDockSpaceFlags_NoSplit)) + if (host_node && (host_node->Flags & ImGuiDockNodeFlags_NoSplit)) data->IsSidesAvailable = false; if (!is_outer_docking && host_node && host_node->ParentNode == NULL && host_node->IsDocumentRoot) data->IsSidesAvailable = false; @@ -11139,7 +11140,7 @@ } // Stop after ImGuiDir_None - if (host_node && (host_node->Flags & ImGuiDockSpaceFlags_NoSplit)) + if (host_node && (host_node->Flags & ImGuiDockNodeFlags_NoSplit)) return; } } @@ -11418,7 +11419,7 @@ } //----------------------------------------------------------------------------- -// Docking: Public Functions (SetWindowDock, Dockspace) +// Docking: Public Functions (SetWindowDock, DockSpace) //----------------------------------------------------------------------------- void ImGui::SetWindowDock(ImGuiWindow* window, ImGuiID dock_id, ImGuiCond cond) @@ -11436,14 +11437,14 @@ window->DockId = dock_id; } -void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockSpaceFlags dock_space_flags, ImGuiID user_type_filter) +// Create an explicit dockspace node within an existing window. Also expose dock node flags and creates a DocumentRoot node by default. +// The DocumentRoot node is always displayed even when empty and shrink/extend according to the requested size of its neighbors. +void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags dock_space_flags, ImGuiID user_type_filter) { ImGuiContext* ctx = GImGui; ImGuiContext& g = *ctx; - ImGuiWindow* window = GetCurrentWindow(); - // It is possible that the node has already been claimed by a docked window which appeared before the DockSpace(), so we overwrite IsExplicit again. ImGuiDockNode* node = DockContextFindNodeByID(ctx, id); if (!node) { @@ -11452,14 +11453,19 @@ } node->Flags = dock_space_flags; node->UserTypeIdFilter = user_type_filter; - node->IsExplicitRoot = true; // When a Dockspace transitioned form implicit to explicit this may be called a second time + // 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) + { + IM_ASSERT(node->IsDockSpace == false && "Cannot call DockSpace() twice a frame with the same ID"); + node->IsDockSpace = true; return; + } + node->IsDockSpace = true; // Keep alive mode, this is allow windows docked into this node so stay docked even if they are not visible - if (dock_space_flags & ImGuiDockSpaceFlags_KeepAliveOnly) + if (dock_space_flags & ImGuiDockNodeFlags_KeepAliveOnly) { node->LastFrameAlive = g.FrameCount; return; @@ -11512,11 +11518,18 @@ { ImGuiID window_id = ImHash(window_name, 0); if (ImGuiWindow* window = FindWindowByID(window_id)) + { + // Apply to created window SetWindowDock(window, node_id, ImGuiCond_Always); - else if (ImGuiWindowSettings* settings = FindWindowSettings(window_id)) + } + else + { + // Apply to settings + ImGuiWindowSettings* settings = FindWindowSettings(window_id); + if (settings == NULL) + settings = CreateNewWindowSettings(window_name); settings->DockId = node_id; - else if (ImGuiWindowSettings* settings = CreateNewWindowSettings(window_name)) - settings->DockId = node_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) @@ -11597,11 +11610,11 @@ g.NextWindowData.PosUndock = false; } - // Undock if our dockspace disappeared - // Note how we are testing for LastFrameAlive and NOT LastFrameActive. A DockSpace can be maintained alive while being inactive with ImGuiDockSpaceFlags_KeepAliveOnly. + // Undock if our dockspace node disappeared + // Note how we are testing for LastFrameAlive and NOT LastFrameActive. A DockSpace node can be maintained alive while being inactive with ImGuiDockNodeFlags_KeepAliveOnly. if (dock_node->LastFrameAlive < g.FrameCount) { - // If the window has been orphaned (lost its dockspace), transition the docknode to an implicit node processed in DockContextUpdateDocking() + // If the window has been orphaned, transition the docknode to an implicit node processed in DockContextUpdateDocking() ImGuiDockNode* root_node = DockNodeGetRootNode(dock_node); if (root_node->LastFrameAlive < g.FrameCount) { @@ -11622,7 +11635,7 @@ return; } - // FIXME-DOCKSPACE: 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 (dock_node->HostWindow == NULL) { window->DockTabIsVisible = false; @@ -11639,7 +11652,7 @@ window->DockIsActive = true; window->DockTabIsVisible = false; - if (dock_node->Flags & ImGuiDockSpaceFlags_KeepAliveOnly) + if (dock_node->Flags & ImGuiDockNodeFlags_KeepAliveOnly) return; if (dock_node->TabBar && dock_node->TabBar->VisibleTabId == window->ID) @@ -11812,7 +11825,7 @@ if (sscanf(line, " SizeRef=%i,%i%n", &x, &y, &r) == 2) { line += r; node.SizeRef = ImVec2ih((short)x, (short)y); } } if (sscanf(line, " Split=%c%n", &c, &r) == 1) { line += r; if (c == 'X') node.SplitAxis = ImGuiAxis_X; else if (c == 'Y') node.SplitAxis = ImGuiAxis_Y; } - if (sscanf(line, " ExplicitRoot=%d%n", &x, &r) == 1) { line += r; node.IsExplicitRoot = (x != 0); } + if (sscanf(line, " ExplicitRoot=%d%n", &x, &r) == 1) { line += r; node.IsDockSpace = (x != 0); } if (sscanf(line, " DocumentRoot=%d%n", &x, &r) == 1) { line += r; node.IsDocumentRoot = (x != 0); } if (sscanf(line, " SelectedTab=0x%08X%n", &node.SelectedTabID,&r) == 1) { line += r; } //if (node.ParentID == 0 && node.SplitAxis == ImGuiAxis_None) @@ -11833,7 +11846,7 @@ node_settings.SelectedTabID = node->SelectedTabID; node_settings.SplitAxis = node->IsSplitNode() ? (char)node->SplitAxis : ImGuiAxis_None; node_settings.Depth = (char)depth; - node_settings.IsExplicitRoot = (char)node->IsExplicitRoot; + node_settings.IsDockSpace = (char)node->IsDockSpace; node_settings.IsDocumentRoot = (char)node->IsDocumentRoot; node_settings.Pos = ImVec2ih((short)node->Pos.x, (short)node->Pos.y); node_settings.Size = ImVec2ih((short)node->Size.x, (short)node->Size.y); @@ -11874,8 +11887,8 @@ buf->appendf(" Pos=%d,%d Size=%d,%d", node_settings->Pos.x, node_settings->Pos.y, node_settings->Size.x, node_settings->Size.y); if (node_settings->SplitAxis != ImGuiAxis_None) buf->appendf(" Split=%c", (node_settings->SplitAxis == ImGuiAxis_X) ? 'X' : 'Y'); - if (node_settings->IsExplicitRoot) - buf->appendf(" ExplicitRoot=%d", node_settings->IsExplicitRoot); + if (node_settings->IsDockSpace) + buf->appendf(" ExplicitRoot=%d", node_settings->IsDockSpace); if (node_settings->IsDocumentRoot) buf->appendf(" DocumentRoot=%d", node_settings->IsDocumentRoot); if (node_settings->SelectedTabID) @@ -12729,7 +12742,7 @@ node->Pos.x, node->Pos.y, node->Size.x, node->Size.y, node->SizeRef.x, node->SizeRef.y); ImGui::BulletText("Flags %02X%s%s%s%s", - node->Flags, node->IsExplicitRoot ? ", IsExplicitRoot" : "", node->IsDocumentRoot ? ", IsDocumentRoot" : "", + node->Flags, node->IsDockSpace ? ", IsDockSpace" : "", node->IsDocumentRoot ? ", IsDocumentRoot" : "", (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.h b/imgui.h index cdb2b3b..0c13859 100644 --- a/imgui.h +++ b/imgui.h @@ -111,7 +111,7 @@ typedef int ImGuiColumnsFlags; // -> enum ImGuiColumnsFlags_ // Flags: for Columns(), BeginColumns() typedef int ImGuiConfigFlags; // -> enum ImGuiConfigFlags_ // Flags: for io.ConfigFlags typedef int ImGuiComboFlags; // -> enum ImGuiComboFlags_ // Flags: for BeginCombo() -typedef int ImGuiDockSpaceFlags; // -> enum ImGuiDockSpaceFlags_ // Flags: for DockSpace() +typedef int ImGuiDockNodeFlags; // -> enum ImGuiDockNodeFlags_ // Flags: for DockSpace() typedef int ImGuiDragDropFlags; // -> enum ImGuiDragDropFlags_ // Flags: for *DragDrop*() typedef int ImGuiFocusedFlags; // -> enum ImGuiFocusedFlags_ // Flags: for IsWindowFocused() typedef int ImGuiHoveredFlags; // -> enum ImGuiHoveredFlags_ // Flags: for IsItemHovered(), IsWindowHovered() etc. @@ -517,8 +517,9 @@ // Docking // [BETA API] Enable with io.ConfigFlags |= ImGuiConfigFlags_DockingEnable. - // Note: you DO NOT need to call DockSpace() to use most Docking facilities! You can hold SHIFT anywhere while moving windows. Use DockSpace() if you need to create an explicit docking space _within_ an existing window. See Docking demo for details) - IMGUI_API void DockSpace(ImGuiID id, const ImVec2& size = ImVec2(0, 0), ImGuiDockSpaceFlags flags = 0, ImGuiID user_type_filter = 0); + // Note: you DO NOT need to call DockSpace() to use most Docking facilities! You can hold SHIFT anywhere while moving windows. + // Use DockSpace() to create an explicit dock node _within_ an existing window. See Docking demo for details. + IMGUI_API void DockSpace(ImGuiID id, const ImVec2& size = ImVec2(0, 0), ImGuiDockNodeFlags flags = 0, ImGuiID user_type_filter = 0); IMGUI_API void SetNextWindowDock(ImGuiID dock_id, ImGuiCond cond = 0); // set next window dock id (FIXME-DOCK) IMGUI_API void SetNextWindowUserType(ImGuiID user_type); // FIXME-DOCK: set next window user type (docking filters by same user_type) IMGUI_API bool IsWindowDocked(); // is current window docked into another window? @@ -782,11 +783,11 @@ }; // Flags for ImGui::DockSpace() -enum ImGuiDockSpaceFlags_ +enum ImGuiDockNodeFlags_ { - ImGuiDockSpaceFlags_None = 0, - ImGuiDockSpaceFlags_KeepAliveOnly = 1 << 0, // Don't create/display the dockspace but keep it alive. Windows docked into this dockspace won't be undocked. - ImGuiDockSpaceFlags_NoSplit = 1 << 1 // Disable splitting the dockspace into smaller nodes. Useful e.g. when embedding dockspaces into a main root one. + ImGuiDockNodeFlags_None = 0, + ImGuiDockNodeFlags_KeepAliveOnly = 1 << 0, // Don't display the dockspace node but keep it alive. Windows docked into this dockspace node won't be undocked. + ImGuiDockNodeFlags_NoSplit = 1 << 1 // Disable splitting the node into smaller nodes. Useful e.g. when embedding dockspaces into a main root one (the root one may have splitting disableed to reduce confusion) }; // Flags for ImGui::IsWindowFocused() diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 6cbf0cd..b199701 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -175,7 +175,7 @@ static bool show_app_window_titles = false; static bool show_app_custom_rendering = false; - if (show_app_dockspace) ShowExampleAppDockSpace(&show_app_dockspace); // Process the Docking app first, as explicit DockSpace() needs to be submitted early (read comments near the DockSpace function) + if (show_app_dockspace) ShowExampleAppDockSpace(&show_app_dockspace); // Process the Docking app first, as explicit DockSpace() nodes needs to be submitted early (read comments near the DockSpace function) if (show_app_documents) ShowExampleAppDocuments(&show_app_documents); // Process the Document app next, as it may also use a DockSpace() if (show_app_main_menu_bar) ShowExampleAppMainMenuBar(); if (show_app_console) ShowExampleAppConsole(&show_app_console); @@ -3692,7 +3692,7 @@ // [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace() //----------------------------------------------------------------------------- -// Demonstrate using DockSpace() to create an explicit docking spacing within an existing window. +// Demonstrate using DockSpace() to create an explicit docking node within an existing window. // Note that you already dock windows into each others _without_ a DockSpace() by just holding SHIFT when moving a window. // DockSpace() is only useful to construct to a central location for your application. void ShowExampleAppDockSpace(bool* p_open) @@ -3702,7 +3702,7 @@ // We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into. // Because 1) it would be confusing to have two docking targets within each others. - // and 2) we want our main DockSpace to always be visible (never hidden within a tab bar): if the DockSpace disappear its child windows will be orphaned. + // and 2) we want our main DockSpace node to always be visible (never hidden within a tab bar): if the DockSpace node disappear its child windows will be orphaned. ImGuiWindowFlags flags = ImGuiWindowFlags_MenuBar; flags |= ImGuiWindowFlags_NoDocking; if (opt_fullscreen) @@ -3737,9 +3737,9 @@ ShowHelpMarker( "You can _always_ dock _any_ window into another by holding the SHIFT key while moving a window. Try it now!" "\n" "This demo app has nothing to do with it!" "\n\n" - "This demo app only demonstrate the use of ImGui::DockSpace() which allows you to specify a docking spot _within_ another window. This is useful so you can decorate your main application window (e.g. with a menu bar)." "\n\n" + "This demo app only demonstrate the use of ImGui::DockSpace() which allows you to manually create a docking node _within_ another window. This is useful so you can decorate your main application window (e.g. with a menu bar)." "\n\n" "ImGui::DockSpace() comes with one hard constraint: it needs to be submitted _before_ any window which may be docked into it. Therefore, if you use a dock spot as the central point of your application, you'll probably want it to be part of the very first window you are submitting to imgui every frame." "\n\n" - "(NB: because of this constraint, the implicit \"Debug\" window can not be docked into an explicit DockSpace(), because that window is submitted as part of the NewFrame() call. An easy workaround is that you can create your own implicit \"Debug##2\" window after calling DockSpace() and leave it in the window stack for anyone to use.)" + "(NB: because of this constraint, the implicit \"Debug\" window can not be docked into an explicit DockSpace() node, because that window is submitted as part of the NewFrame() call. An easy workaround is that you can create your own implicit \"Debug##2\" window after calling DockSpace() and leave it in the window stack for anyone to use.)" ); ImGui::EndMenuBar(); @@ -3959,7 +3959,7 @@ { NotifyOfDocumentsClosedElsewhere(app); - // Create a DockSpace where any window can be docked + // Create a DockSpace node where any window can be docked ImGuiID dockspace_id = ImGui::GetID("MyDockSpace"); ImGui::DockSpace(dockspace_id); diff --git a/imgui_internal.h b/imgui_internal.h index 03d9011..8be1a1b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -743,7 +743,7 @@ { ImGuiID ID; ImGuiID UserTypeIdFilter; - ImGuiDockSpaceFlags Flags; + ImGuiDockNodeFlags Flags; ImGuiDockNode* ParentNode; ImGuiDockNode* ChildNodes[2]; // [Split node only] Child nodes (left/right or top/bottom). Consider switching to an array. ImVector Windows; // Note: unordered list! Iterate TabBar->Tabs for user-order. @@ -756,20 +756,20 @@ ImGuiWindow* HostWindow; ImGuiWindow* VisibleWindow; ImGuiDockNode* OnlyNodeWithWindows; // [Root node only] Set when there is a single visible node within the hierarchy - int LastFrameAlive; // Last frame number the node was updated or kept alive explicitly with DockSpace() + mGuiDockSpaceFlags_KeepAliveOnly + int LastFrameAlive; // Last frame number the node was updated or kept alive explicitly with DockSpace() + ImGuiDockNodeFlags_KeepAliveOnly int LastFrameActive; // Last frame number the node was updated. ImGuiID LastFocusedNodeID; // [Root node only] Which of our child node (any ancestor in the hierarchy) was last focused. ImGuiID SelectedTabID; // [Tab node only] Which of our tab is selected. ImGuiID WantCloseTabID; // [Tab node only] Set when closing a specific tab. bool InitFromFirstWindow :1; bool IsVisible :1; // Set to false when the node is hidden (usually disabled as it has no active window) - bool IsExplicitRoot :1; // Mark root node as explicit when created from a DockSpace() + bool IsDockSpace :1; // Root node was created by a DockSpace() call. bool IsDocumentRoot :1; bool HasCloseButton :1; bool HasCollapseButton :1; bool WantCloseAll :1; // Set when closing all tabs at once. bool WantLockSizeOnce :1; - bool WantMouseMove :1; // After a node extraction we need to transition toward moving the newly created hode window + bool WantMouseMove :1; // After a node extraction we need to transition toward moving the newly created host window ImGuiDockNode(ImGuiID id); ~ImGuiDockNode();