diff --git a/imgui.cpp b/imgui.cpp index 28f74c6..f4f56a8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10065,7 +10065,7 @@ OnlyNodeWithWindows = NULL; SelectedTabID = 0; LastFocusedNodeID = 0; - LastFrameActive = -1; + LastFrameAlive = LastFrameActive = -1; WantCloseOne = 0; IsVisible = true; InitFromFirstWindow = IsExplicitRoot = IsDocumentRoot = HasCloseButton = HasCollapseButton = WantCloseAll = WantLockSizeOnce = false; @@ -10327,6 +10327,7 @@ { ImGuiContext& g = *GImGui; IM_ASSERT(node->LastFrameActive != g.FrameCount); + node->LastFrameAlive = g.FrameCount; if (node->IsRootNode()) { @@ -10829,7 +10830,7 @@ data->IsCenterAvailable = false; data->IsSidesAvailable = true; - if (host_node && (host_node->Flags & ImGuiDockFlags_NoSplit)) + if (host_node && (host_node->Flags & ImGuiDockSpaceFlags_NoSplit)) data->IsSidesAvailable = false; if (!is_outer_docking && host_node && host_node->ParentNode == NULL && host_node->IsDocumentRoot) data->IsSidesAvailable = false; @@ -10946,7 +10947,7 @@ } } - if (host_node && (host_node->Flags & ImGuiDockFlags_NoSplit)) + if (host_node && (host_node->Flags & ImGuiDockSpaceFlags_NoSplit)) return; // Display drop boxes @@ -11267,7 +11268,7 @@ window->DockId = dock_id; } -void ImGui::DockSpace(const char* str_id, const ImVec2& size_arg, ImGuiDockFlags dock_flags, ImGuiID user_type_filter) +void ImGui::DockSpace(const char* str_id, const ImVec2& size_arg, ImGuiDockSpaceFlags dock_space_flags, ImGuiID user_type_filter) { ImGuiContext& g = *GImGui; ImGuiDockContext* ctx = g.DockContext; @@ -11282,13 +11283,21 @@ node = DockContextAddNode(ctx, id); node->IsDocumentRoot = true; } - node->Flags = dock_flags; + 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 if (node->LastFrameActive == g.FrameCount) return; + // 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) + { + node->LastFrameAlive = g.FrameCount; + return; + } + const ImVec2 content_avail = GetContentRegionAvail(); ImVec2 size = ImFloor(size_arg); if (size.x <= 0.0f) @@ -11370,13 +11379,16 @@ } // Undock if our dockspace disappeared - if (dock_node->LastFrameActive < g.FrameCount) + // Note how we are testing for LastFrameAlive and NOT LastFrameActive. A DockSpace can be maintained alive while being inactive with ImGuiDockSpaceFlags_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() ImGuiDockNode* root_node = DockNodeGetRootNode(dock_node); - if (root_node->IsExplicitRoot && root_node->LastFrameActive < g.FrameCount) + if (root_node->LastFrameAlive < g.FrameCount) + { root_node->IsExplicitRoot = false; - window->DockIsActive = false; + window->DockIsActive = false; + } return; } @@ -11396,7 +11408,19 @@ IM_ASSERT(dock_node->HostWindow); IM_ASSERT(!dock_node->IsParent()); + + // Position window + SetNextWindowPos(dock_node->Pos); + SetNextWindowSize(dock_node->Size); + g.NextWindowData.PosUndock = false; // Cancel implicit undocking of SetNextWindowPos() + window->DockIsActive = true; + if (dock_node->Flags & ImGuiDockSpaceFlags_KeepAliveOnly) + { + window->DockTabIsVisible = false; + return; + } + window->DockTabIsVisible = (dock_node->TabBar && dock_node->TabBar->VisibleTabId == window->ID); // Update window flag @@ -11404,11 +11428,6 @@ window->Flags |= ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_NoResize; window->Flags &= ~ImGuiWindowFlags_NoTitleBar; // Clear the NoTitleBar flag in case the user set it: confusingly enough we need a title bar height so we are correctly offset, but it won't be displayed! - // Position window - SetNextWindowPos(dock_node->Pos); - SetNextWindowSize(dock_node->Size); - g.NextWindowData.PosUndock = false; - // Save new dock order only if the tab bar is active if (dock_node->TabBar) window->DockOrder = (short)DockNodeGetTabOrder(window); diff --git a/imgui.cpp b/imgui.cpp index 28f74c6..f4f56a8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10065,7 +10065,7 @@ OnlyNodeWithWindows = NULL; SelectedTabID = 0; LastFocusedNodeID = 0; - LastFrameActive = -1; + LastFrameAlive = LastFrameActive = -1; WantCloseOne = 0; IsVisible = true; InitFromFirstWindow = IsExplicitRoot = IsDocumentRoot = HasCloseButton = HasCollapseButton = WantCloseAll = WantLockSizeOnce = false; @@ -10327,6 +10327,7 @@ { ImGuiContext& g = *GImGui; IM_ASSERT(node->LastFrameActive != g.FrameCount); + node->LastFrameAlive = g.FrameCount; if (node->IsRootNode()) { @@ -10829,7 +10830,7 @@ data->IsCenterAvailable = false; data->IsSidesAvailable = true; - if (host_node && (host_node->Flags & ImGuiDockFlags_NoSplit)) + if (host_node && (host_node->Flags & ImGuiDockSpaceFlags_NoSplit)) data->IsSidesAvailable = false; if (!is_outer_docking && host_node && host_node->ParentNode == NULL && host_node->IsDocumentRoot) data->IsSidesAvailable = false; @@ -10946,7 +10947,7 @@ } } - if (host_node && (host_node->Flags & ImGuiDockFlags_NoSplit)) + if (host_node && (host_node->Flags & ImGuiDockSpaceFlags_NoSplit)) return; // Display drop boxes @@ -11267,7 +11268,7 @@ window->DockId = dock_id; } -void ImGui::DockSpace(const char* str_id, const ImVec2& size_arg, ImGuiDockFlags dock_flags, ImGuiID user_type_filter) +void ImGui::DockSpace(const char* str_id, const ImVec2& size_arg, ImGuiDockSpaceFlags dock_space_flags, ImGuiID user_type_filter) { ImGuiContext& g = *GImGui; ImGuiDockContext* ctx = g.DockContext; @@ -11282,13 +11283,21 @@ node = DockContextAddNode(ctx, id); node->IsDocumentRoot = true; } - node->Flags = dock_flags; + 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 if (node->LastFrameActive == g.FrameCount) return; + // 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) + { + node->LastFrameAlive = g.FrameCount; + return; + } + const ImVec2 content_avail = GetContentRegionAvail(); ImVec2 size = ImFloor(size_arg); if (size.x <= 0.0f) @@ -11370,13 +11379,16 @@ } // Undock if our dockspace disappeared - if (dock_node->LastFrameActive < g.FrameCount) + // Note how we are testing for LastFrameAlive and NOT LastFrameActive. A DockSpace can be maintained alive while being inactive with ImGuiDockSpaceFlags_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() ImGuiDockNode* root_node = DockNodeGetRootNode(dock_node); - if (root_node->IsExplicitRoot && root_node->LastFrameActive < g.FrameCount) + if (root_node->LastFrameAlive < g.FrameCount) + { root_node->IsExplicitRoot = false; - window->DockIsActive = false; + window->DockIsActive = false; + } return; } @@ -11396,7 +11408,19 @@ IM_ASSERT(dock_node->HostWindow); IM_ASSERT(!dock_node->IsParent()); + + // Position window + SetNextWindowPos(dock_node->Pos); + SetNextWindowSize(dock_node->Size); + g.NextWindowData.PosUndock = false; // Cancel implicit undocking of SetNextWindowPos() + window->DockIsActive = true; + if (dock_node->Flags & ImGuiDockSpaceFlags_KeepAliveOnly) + { + window->DockTabIsVisible = false; + return; + } + window->DockTabIsVisible = (dock_node->TabBar && dock_node->TabBar->VisibleTabId == window->ID); // Update window flag @@ -11404,11 +11428,6 @@ window->Flags |= ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_NoResize; window->Flags &= ~ImGuiWindowFlags_NoTitleBar; // Clear the NoTitleBar flag in case the user set it: confusingly enough we need a title bar height so we are correctly offset, but it won't be displayed! - // Position window - SetNextWindowPos(dock_node->Pos); - SetNextWindowSize(dock_node->Size); - g.NextWindowData.PosUndock = false; - // Save new dock order only if the tab bar is active if (dock_node->TabBar) window->DockOrder = (short)DockNodeGetTabOrder(window); diff --git a/imgui.h b/imgui.h index 528d6a5..47df5b2 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 ImGuiDockFlags; // -> enum ImGuiDockFlags_ // Flags: for DockSpace() +typedef int ImGuiDockSpaceFlags; // -> enum ImGuiDockSpaceFlags_ // 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. @@ -520,7 +520,7 @@ // 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(const char* str_id, const ImVec2& size = ImVec2(0, 0), ImGuiDockFlags flags = 0, ImGuiID user_type_filter = 0); + IMGUI_API void DockSpace(const char* str_id, const ImVec2& size = ImVec2(0, 0), ImGuiDockSpaceFlags flags = 0, ImGuiID user_type_filter = 0); IMGUI_API void SetNextWindowUserType(ImGuiID user_type); // FIXME-DOCK: set next window user type (docking filters by same user_type) // Logging/Capture: all text output from interface is captured to tty/file/clipboard. By default, tree nodes are automatically opened during logging. @@ -782,10 +782,11 @@ }; // Flags for ImGui::DockSpace() -enum ImGuiDockFlags_ +enum ImGuiDockSpaceFlags_ { - ImGuiDockFlags_None = 0, - ImGuiDockFlags_NoSplit = 1 << 0 + 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. }; // Flags for ImGui::IsWindowFocused() diff --git a/imgui.cpp b/imgui.cpp index 28f74c6..f4f56a8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10065,7 +10065,7 @@ OnlyNodeWithWindows = NULL; SelectedTabID = 0; LastFocusedNodeID = 0; - LastFrameActive = -1; + LastFrameAlive = LastFrameActive = -1; WantCloseOne = 0; IsVisible = true; InitFromFirstWindow = IsExplicitRoot = IsDocumentRoot = HasCloseButton = HasCollapseButton = WantCloseAll = WantLockSizeOnce = false; @@ -10327,6 +10327,7 @@ { ImGuiContext& g = *GImGui; IM_ASSERT(node->LastFrameActive != g.FrameCount); + node->LastFrameAlive = g.FrameCount; if (node->IsRootNode()) { @@ -10829,7 +10830,7 @@ data->IsCenterAvailable = false; data->IsSidesAvailable = true; - if (host_node && (host_node->Flags & ImGuiDockFlags_NoSplit)) + if (host_node && (host_node->Flags & ImGuiDockSpaceFlags_NoSplit)) data->IsSidesAvailable = false; if (!is_outer_docking && host_node && host_node->ParentNode == NULL && host_node->IsDocumentRoot) data->IsSidesAvailable = false; @@ -10946,7 +10947,7 @@ } } - if (host_node && (host_node->Flags & ImGuiDockFlags_NoSplit)) + if (host_node && (host_node->Flags & ImGuiDockSpaceFlags_NoSplit)) return; // Display drop boxes @@ -11267,7 +11268,7 @@ window->DockId = dock_id; } -void ImGui::DockSpace(const char* str_id, const ImVec2& size_arg, ImGuiDockFlags dock_flags, ImGuiID user_type_filter) +void ImGui::DockSpace(const char* str_id, const ImVec2& size_arg, ImGuiDockSpaceFlags dock_space_flags, ImGuiID user_type_filter) { ImGuiContext& g = *GImGui; ImGuiDockContext* ctx = g.DockContext; @@ -11282,13 +11283,21 @@ node = DockContextAddNode(ctx, id); node->IsDocumentRoot = true; } - node->Flags = dock_flags; + 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 if (node->LastFrameActive == g.FrameCount) return; + // 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) + { + node->LastFrameAlive = g.FrameCount; + return; + } + const ImVec2 content_avail = GetContentRegionAvail(); ImVec2 size = ImFloor(size_arg); if (size.x <= 0.0f) @@ -11370,13 +11379,16 @@ } // Undock if our dockspace disappeared - if (dock_node->LastFrameActive < g.FrameCount) + // Note how we are testing for LastFrameAlive and NOT LastFrameActive. A DockSpace can be maintained alive while being inactive with ImGuiDockSpaceFlags_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() ImGuiDockNode* root_node = DockNodeGetRootNode(dock_node); - if (root_node->IsExplicitRoot && root_node->LastFrameActive < g.FrameCount) + if (root_node->LastFrameAlive < g.FrameCount) + { root_node->IsExplicitRoot = false; - window->DockIsActive = false; + window->DockIsActive = false; + } return; } @@ -11396,7 +11408,19 @@ IM_ASSERT(dock_node->HostWindow); IM_ASSERT(!dock_node->IsParent()); + + // Position window + SetNextWindowPos(dock_node->Pos); + SetNextWindowSize(dock_node->Size); + g.NextWindowData.PosUndock = false; // Cancel implicit undocking of SetNextWindowPos() + window->DockIsActive = true; + if (dock_node->Flags & ImGuiDockSpaceFlags_KeepAliveOnly) + { + window->DockTabIsVisible = false; + return; + } + window->DockTabIsVisible = (dock_node->TabBar && dock_node->TabBar->VisibleTabId == window->ID); // Update window flag @@ -11404,11 +11428,6 @@ window->Flags |= ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_NoResize; window->Flags &= ~ImGuiWindowFlags_NoTitleBar; // Clear the NoTitleBar flag in case the user set it: confusingly enough we need a title bar height so we are correctly offset, but it won't be displayed! - // Position window - SetNextWindowPos(dock_node->Pos); - SetNextWindowSize(dock_node->Size); - g.NextWindowData.PosUndock = false; - // Save new dock order only if the tab bar is active if (dock_node->TabBar) window->DockOrder = (short)DockNodeGetTabOrder(window); diff --git a/imgui.h b/imgui.h index 528d6a5..47df5b2 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 ImGuiDockFlags; // -> enum ImGuiDockFlags_ // Flags: for DockSpace() +typedef int ImGuiDockSpaceFlags; // -> enum ImGuiDockSpaceFlags_ // 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. @@ -520,7 +520,7 @@ // 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(const char* str_id, const ImVec2& size = ImVec2(0, 0), ImGuiDockFlags flags = 0, ImGuiID user_type_filter = 0); + IMGUI_API void DockSpace(const char* str_id, const ImVec2& size = ImVec2(0, 0), ImGuiDockSpaceFlags flags = 0, ImGuiID user_type_filter = 0); IMGUI_API void SetNextWindowUserType(ImGuiID user_type); // FIXME-DOCK: set next window user type (docking filters by same user_type) // Logging/Capture: all text output from interface is captured to tty/file/clipboard. By default, tree nodes are automatically opened during logging. @@ -782,10 +782,11 @@ }; // Flags for ImGui::DockSpace() -enum ImGuiDockFlags_ +enum ImGuiDockSpaceFlags_ { - ImGuiDockFlags_None = 0, - ImGuiDockFlags_NoSplit = 1 << 0 + 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. }; // Flags for ImGui::IsWindowFocused() diff --git a/imgui_internal.h b/imgui_internal.h index d0505ff..2180935 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -738,12 +738,12 @@ float Width; }; -// sizeof() 88~124 +// sizeof() 92~128 struct ImGuiDockNode { ImGuiID ID; ImGuiID UserTypeIdFilter; - ImGuiDockFlags Flags; + ImGuiDockSpaceFlags Flags; ImGuiDockNode* ParentNode; ImGuiDockNode* ChildNodes[2]; ImVector Windows; // Note: unordered list! Iterate TabBar->Tabs for user-order. @@ -757,6 +757,7 @@ ImGuiWindow* VisibleWindow; ImGuiDockNode* OnlyNodeWithWindows; // Root node only, set when there is a single visible node within the hierarchy ImGuiID SelectedTabID; + int LastFrameAlive; int LastFrameActive; ImGuiID LastFocusedNodeID; ImGuiID WantCloseOne;