diff --git a/imgui.cpp b/imgui.cpp index 4327ece..39b41b6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2371,6 +2371,7 @@ HiddenFramesRegular = HiddenFramesForResize = 0; SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = SetWindowDockAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing; SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX); + UserTypeId = 0; LastFrameActive = -1; ItemWidthDefault = 0.0f; @@ -3350,7 +3351,7 @@ // Undocking // (needs to be before UpdateMovingWindow so the window is already offset and following the mouse on the detaching frame) - DockContextUpdateUndocking(g.DockContext); + DockContextNewFrameUpdateUndocking(g.DockContext); // Find hovered window // (needs to be before UpdateMovingWindow so we fill HoveredWindowUnderMovingWindow on the mouse release frame) @@ -3404,7 +3405,7 @@ ClosePopupsOverWindow(g.NavWindow); // Docking - DockContextUpdateDocking(g.DockContext); + DockContextNewFrameUpdateDocking(g.DockContext); // Create implicit window - we will only render it if the user has added something to it. // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags. @@ -4954,6 +4955,7 @@ { window->SizeContentsExplicit = ImVec2(0.0f, 0.0f); } + window->UserTypeId = g.NextWindowData.UserTypeId; if (g.NextWindowData.CollapsedCond) SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond); if (g.NextWindowData.FocusCond) @@ -6320,6 +6322,12 @@ g.NextWindowData.DockId = id; } +void ImGui::SetNextWindowUserType(ImGuiID user_type) +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.UserTypeId = user_type; +} + // In window space (not screen space!) ImVec2 ImGui::GetContentRegionMax() { @@ -9580,7 +9588,6 @@ static void DockNodeRemoveWindow(ImGuiDockNode* node, ImGuiWindow* window, ImGuiID save_dock_id); static void DockNodeHideHostWindow(ImGuiDockNode* node); static void DockNodeUpdate(ImGuiDockNode* node); - static ImGuiDockNode* DockNodeUpdateFindOnlyNodeWithWindows(ImGuiDockNode* node); static void DockNodeUpdateVisibleFlagAndInactiveChilds(ImGuiDockNode* node); static void DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_window); static void DockNodeUpdateVisibleFlag(ImGuiDockNode* node); @@ -9656,7 +9663,7 @@ DockContextBuildAddWindowsToNodes(ctx); } -void ImGui::DockContextUpdateUndocking(ImGuiDockContext* ctx) +void ImGui::DockContextNewFrameUpdateUndocking(ImGuiDockContext* ctx) { ImGuiContext& g = *GImGui; if (!(g.IO.ConfigFlags & ImGuiConfigFlags_DockingEnable)) @@ -9682,7 +9689,7 @@ DockContextProcessUndock(ctx, ctx->Requests[n].WindowUndock); } -void ImGui::DockContextUpdateDocking(ImGuiDockContext* ctx) +void ImGui::DockContextNewFrameUpdateDocking(ImGuiDockContext* ctx) { ImGuiContext& g = *GImGui; if (!(g.IO.ConfigFlags & ImGuiConfigFlags_DockingEnable)) @@ -10000,6 +10007,8 @@ ImGuiDockNode::ImGuiDockNode(ImGuiID id) { ID = id; + UserTypeIdFilter = 0; + Flags = 0; ParentNode = ChildNodes[0] = ChildNodes[1] = NULL; TabBar = NULL; SplitAxis = ImGuiAxis_None; @@ -10197,28 +10206,20 @@ } } -static void DockNodeUpdateFindOnlyNodeWithWindowsRec(ImGuiDockNode* node, int* p_count, ImGuiDockNode** p_only_node_with_windows) +static void DockNodeUpdateFindOnlyNodeWithWindowsRec(ImGuiDockNode* node, int* p_count, ImGuiDockNode** p_first_node_with_windows) { if (node->Windows.Size > 0) { - if (*p_only_node_with_windows == NULL) - *p_only_node_with_windows = node; + if (*p_first_node_with_windows == NULL) + *p_first_node_with_windows = node; (*p_count)++; } if (*p_count > 1) return; if (node->ChildNodes[0]) - DockNodeUpdateFindOnlyNodeWithWindowsRec(node->ChildNodes[0], p_count, p_only_node_with_windows); + DockNodeUpdateFindOnlyNodeWithWindowsRec(node->ChildNodes[0], p_count, p_first_node_with_windows); if (node->ChildNodes[1]) - DockNodeUpdateFindOnlyNodeWithWindowsRec(node->ChildNodes[1], p_count, p_only_node_with_windows); -} - -static ImGuiDockNode* ImGui::DockNodeUpdateFindOnlyNodeWithWindows(ImGuiDockNode* node) -{ - int count = 0; - ImGuiDockNode* only_node_with_windows = NULL; - DockNodeUpdateFindOnlyNodeWithWindowsRec(node, &count, &only_node_with_windows); - return (count == 1 ? only_node_with_windows : NULL); + DockNodeUpdateFindOnlyNodeWithWindowsRec(node->ChildNodes[1], p_count, p_first_node_with_windows); } static void ImGui::DockNodeUpdateVisibleFlagAndInactiveChilds(ImGuiDockNode* node) @@ -10280,8 +10281,19 @@ if (node->IsRootNode()) { DockNodeUpdateVisibleFlagAndInactiveChilds(node); - ImGuiDockNode* only_node_with_windows = node->IsExplicitRoot ? NULL : DockNodeUpdateFindOnlyNodeWithWindows(node); - node->OnlyNodeWithWindows = only_node_with_windows; + + // 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) + { + int count = 0; + ImGuiDockNode* first_node_with_windows = NULL; + DockNodeUpdateFindOnlyNodeWithWindowsRec(node, &count, &first_node_with_windows); + node->OnlyNodeWithWindows = (count == 1 ? first_node_with_windows : NULL); + + // Copy the user type from _any_ of our window so it can be used for proper dock filtering. + if (first_node_with_windows) + node->UserTypeIdFilter = first_node_with_windows->Windows[0]->UserTypeId; + } } // Early out for standalone floating window that are holding on a DockId (with an invisible dock node) @@ -10640,6 +10652,11 @@ ImGuiWindow* payload = root_payload->DockNodeAsHost ? root_payload->DockNodeAsHost->Windows[payload_n] : root_payload; if ((host_window->Flags & ImGuiWindowFlags_DockNodeHost) && payload->BeginOrderWithinContext < host_window->BeginOrderWithinContext) continue; + + ImGuiID host_user_type_id = host_window->DockNodeAsHost ? host_window->DockNodeAsHost->UserTypeIdFilter : host_window->UserTypeId; + if (payload->UserTypeId != host_user_type_id) + return false; + return true; } return false; @@ -10756,6 +10773,8 @@ data->IsCenterAvailable = false; data->IsSidesAvailable = true; + if (host_node && (host_node->Flags & ImGuiDockFlags_NoSplit)) + data->IsSidesAvailable = false; if (!is_outer_docking && host_node && host_node->ParentNode == NULL && host_node->IsDocumentRoot) data->IsSidesAvailable = false; @@ -10871,6 +10890,9 @@ } } + if (host_node && (host_node->Flags & ImGuiDockFlags_NoSplit)) + return; + // Display drop boxes const float overlay_rounding = ImMax(3.0f, g.Style.FrameRounding); for (int dir = ImGuiDir_None; dir < ImGuiDir_COUNT; dir++) @@ -11189,7 +11211,7 @@ window->DockId = dock_id; } -void ImGui::DockSpace(const char* str_id, const ImVec2& size_arg) +void ImGui::DockSpace(const char* str_id, const ImVec2& size_arg, ImGuiDockFlags dock_flags, ImGuiID user_type_filter) { ImGuiContext& g = *GImGui; ImGuiDockContext* ctx = g.DockContext; @@ -11204,6 +11226,8 @@ node = DockContextAddNode(ctx, id); node->IsDocumentRoot = true; } + node->Flags = dock_flags; + node->UserTypeIdFilter = user_type_filter; node->IsExplicitRoot = true; const ImVec2 content_avail = GetContentRegionAvail(); @@ -11235,6 +11259,7 @@ host_window->DockNodeAsHost = node; host_window->ChildId = window->GetID(title); node->HostWindow = host_window; + node->OnlyNodeWithWindows = NULL; IM_ASSERT(node->IsRootNode()); DockNodeUpdate(node); @@ -11320,7 +11345,7 @@ 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 + // Position window SetNextWindowPos(dock_node->Pos); SetNextWindowSize(dock_node->Size); g.NextWindowData.PosUndock = false; diff --git a/imgui.cpp b/imgui.cpp index 4327ece..39b41b6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2371,6 +2371,7 @@ HiddenFramesRegular = HiddenFramesForResize = 0; SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = SetWindowDockAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing; SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX); + UserTypeId = 0; LastFrameActive = -1; ItemWidthDefault = 0.0f; @@ -3350,7 +3351,7 @@ // Undocking // (needs to be before UpdateMovingWindow so the window is already offset and following the mouse on the detaching frame) - DockContextUpdateUndocking(g.DockContext); + DockContextNewFrameUpdateUndocking(g.DockContext); // Find hovered window // (needs to be before UpdateMovingWindow so we fill HoveredWindowUnderMovingWindow on the mouse release frame) @@ -3404,7 +3405,7 @@ ClosePopupsOverWindow(g.NavWindow); // Docking - DockContextUpdateDocking(g.DockContext); + DockContextNewFrameUpdateDocking(g.DockContext); // Create implicit window - we will only render it if the user has added something to it. // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags. @@ -4954,6 +4955,7 @@ { window->SizeContentsExplicit = ImVec2(0.0f, 0.0f); } + window->UserTypeId = g.NextWindowData.UserTypeId; if (g.NextWindowData.CollapsedCond) SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond); if (g.NextWindowData.FocusCond) @@ -6320,6 +6322,12 @@ g.NextWindowData.DockId = id; } +void ImGui::SetNextWindowUserType(ImGuiID user_type) +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.UserTypeId = user_type; +} + // In window space (not screen space!) ImVec2 ImGui::GetContentRegionMax() { @@ -9580,7 +9588,6 @@ static void DockNodeRemoveWindow(ImGuiDockNode* node, ImGuiWindow* window, ImGuiID save_dock_id); static void DockNodeHideHostWindow(ImGuiDockNode* node); static void DockNodeUpdate(ImGuiDockNode* node); - static ImGuiDockNode* DockNodeUpdateFindOnlyNodeWithWindows(ImGuiDockNode* node); static void DockNodeUpdateVisibleFlagAndInactiveChilds(ImGuiDockNode* node); static void DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_window); static void DockNodeUpdateVisibleFlag(ImGuiDockNode* node); @@ -9656,7 +9663,7 @@ DockContextBuildAddWindowsToNodes(ctx); } -void ImGui::DockContextUpdateUndocking(ImGuiDockContext* ctx) +void ImGui::DockContextNewFrameUpdateUndocking(ImGuiDockContext* ctx) { ImGuiContext& g = *GImGui; if (!(g.IO.ConfigFlags & ImGuiConfigFlags_DockingEnable)) @@ -9682,7 +9689,7 @@ DockContextProcessUndock(ctx, ctx->Requests[n].WindowUndock); } -void ImGui::DockContextUpdateDocking(ImGuiDockContext* ctx) +void ImGui::DockContextNewFrameUpdateDocking(ImGuiDockContext* ctx) { ImGuiContext& g = *GImGui; if (!(g.IO.ConfigFlags & ImGuiConfigFlags_DockingEnable)) @@ -10000,6 +10007,8 @@ ImGuiDockNode::ImGuiDockNode(ImGuiID id) { ID = id; + UserTypeIdFilter = 0; + Flags = 0; ParentNode = ChildNodes[0] = ChildNodes[1] = NULL; TabBar = NULL; SplitAxis = ImGuiAxis_None; @@ -10197,28 +10206,20 @@ } } -static void DockNodeUpdateFindOnlyNodeWithWindowsRec(ImGuiDockNode* node, int* p_count, ImGuiDockNode** p_only_node_with_windows) +static void DockNodeUpdateFindOnlyNodeWithWindowsRec(ImGuiDockNode* node, int* p_count, ImGuiDockNode** p_first_node_with_windows) { if (node->Windows.Size > 0) { - if (*p_only_node_with_windows == NULL) - *p_only_node_with_windows = node; + if (*p_first_node_with_windows == NULL) + *p_first_node_with_windows = node; (*p_count)++; } if (*p_count > 1) return; if (node->ChildNodes[0]) - DockNodeUpdateFindOnlyNodeWithWindowsRec(node->ChildNodes[0], p_count, p_only_node_with_windows); + DockNodeUpdateFindOnlyNodeWithWindowsRec(node->ChildNodes[0], p_count, p_first_node_with_windows); if (node->ChildNodes[1]) - DockNodeUpdateFindOnlyNodeWithWindowsRec(node->ChildNodes[1], p_count, p_only_node_with_windows); -} - -static ImGuiDockNode* ImGui::DockNodeUpdateFindOnlyNodeWithWindows(ImGuiDockNode* node) -{ - int count = 0; - ImGuiDockNode* only_node_with_windows = NULL; - DockNodeUpdateFindOnlyNodeWithWindowsRec(node, &count, &only_node_with_windows); - return (count == 1 ? only_node_with_windows : NULL); + DockNodeUpdateFindOnlyNodeWithWindowsRec(node->ChildNodes[1], p_count, p_first_node_with_windows); } static void ImGui::DockNodeUpdateVisibleFlagAndInactiveChilds(ImGuiDockNode* node) @@ -10280,8 +10281,19 @@ if (node->IsRootNode()) { DockNodeUpdateVisibleFlagAndInactiveChilds(node); - ImGuiDockNode* only_node_with_windows = node->IsExplicitRoot ? NULL : DockNodeUpdateFindOnlyNodeWithWindows(node); - node->OnlyNodeWithWindows = only_node_with_windows; + + // 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) + { + int count = 0; + ImGuiDockNode* first_node_with_windows = NULL; + DockNodeUpdateFindOnlyNodeWithWindowsRec(node, &count, &first_node_with_windows); + node->OnlyNodeWithWindows = (count == 1 ? first_node_with_windows : NULL); + + // Copy the user type from _any_ of our window so it can be used for proper dock filtering. + if (first_node_with_windows) + node->UserTypeIdFilter = first_node_with_windows->Windows[0]->UserTypeId; + } } // Early out for standalone floating window that are holding on a DockId (with an invisible dock node) @@ -10640,6 +10652,11 @@ ImGuiWindow* payload = root_payload->DockNodeAsHost ? root_payload->DockNodeAsHost->Windows[payload_n] : root_payload; if ((host_window->Flags & ImGuiWindowFlags_DockNodeHost) && payload->BeginOrderWithinContext < host_window->BeginOrderWithinContext) continue; + + ImGuiID host_user_type_id = host_window->DockNodeAsHost ? host_window->DockNodeAsHost->UserTypeIdFilter : host_window->UserTypeId; + if (payload->UserTypeId != host_user_type_id) + return false; + return true; } return false; @@ -10756,6 +10773,8 @@ data->IsCenterAvailable = false; data->IsSidesAvailable = true; + if (host_node && (host_node->Flags & ImGuiDockFlags_NoSplit)) + data->IsSidesAvailable = false; if (!is_outer_docking && host_node && host_node->ParentNode == NULL && host_node->IsDocumentRoot) data->IsSidesAvailable = false; @@ -10871,6 +10890,9 @@ } } + if (host_node && (host_node->Flags & ImGuiDockFlags_NoSplit)) + return; + // Display drop boxes const float overlay_rounding = ImMax(3.0f, g.Style.FrameRounding); for (int dir = ImGuiDir_None; dir < ImGuiDir_COUNT; dir++) @@ -11189,7 +11211,7 @@ window->DockId = dock_id; } -void ImGui::DockSpace(const char* str_id, const ImVec2& size_arg) +void ImGui::DockSpace(const char* str_id, const ImVec2& size_arg, ImGuiDockFlags dock_flags, ImGuiID user_type_filter) { ImGuiContext& g = *GImGui; ImGuiDockContext* ctx = g.DockContext; @@ -11204,6 +11226,8 @@ node = DockContextAddNode(ctx, id); node->IsDocumentRoot = true; } + node->Flags = dock_flags; + node->UserTypeIdFilter = user_type_filter; node->IsExplicitRoot = true; const ImVec2 content_avail = GetContentRegionAvail(); @@ -11235,6 +11259,7 @@ host_window->DockNodeAsHost = node; host_window->ChildId = window->GetID(title); node->HostWindow = host_window; + node->OnlyNodeWithWindows = NULL; IM_ASSERT(node->IsRootNode()); DockNodeUpdate(node); @@ -11320,7 +11345,7 @@ 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 + // Position window SetNextWindowPos(dock_node->Pos); SetNextWindowSize(dock_node->Size); g.NextWindowData.PosUndock = false; diff --git a/imgui.h b/imgui.h index 53f1779..528d6a5 100644 --- a/imgui.h +++ b/imgui.h @@ -111,6 +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 ImGuiDragDropFlags; // -> enum ImGuiDragDropFlags_ // Flags: for *DragDrop*() typedef int ImGuiFocusedFlags; // -> enum ImGuiFocusedFlags_ // Flags: for IsWindowFocused() typedef int ImGuiHoveredFlags; // -> enum ImGuiHoveredFlags_ // Flags: for IsItemHovered(), IsWindowHovered() etc. @@ -519,7 +520,8 @@ // 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)); + 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 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. IMGUI_API void LogToTTY(int max_depth = -1); // start logging to tty @@ -779,6 +781,13 @@ ImGuiTabItemFlags_NoPushId = 1 << 3 // Don't call PushID(tab->ID)/PopID() on BeginTabItem()/EndTabItem() }; +// Flags for ImGui::DockSpace() +enum ImGuiDockFlags_ +{ + ImGuiDockFlags_None = 0, + ImGuiDockFlags_NoSplit = 1 << 0 +}; + // Flags for ImGui::IsWindowFocused() enum ImGuiFocusedFlags_ { diff --git a/imgui.cpp b/imgui.cpp index 4327ece..39b41b6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2371,6 +2371,7 @@ HiddenFramesRegular = HiddenFramesForResize = 0; SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = SetWindowDockAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing; SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX); + UserTypeId = 0; LastFrameActive = -1; ItemWidthDefault = 0.0f; @@ -3350,7 +3351,7 @@ // Undocking // (needs to be before UpdateMovingWindow so the window is already offset and following the mouse on the detaching frame) - DockContextUpdateUndocking(g.DockContext); + DockContextNewFrameUpdateUndocking(g.DockContext); // Find hovered window // (needs to be before UpdateMovingWindow so we fill HoveredWindowUnderMovingWindow on the mouse release frame) @@ -3404,7 +3405,7 @@ ClosePopupsOverWindow(g.NavWindow); // Docking - DockContextUpdateDocking(g.DockContext); + DockContextNewFrameUpdateDocking(g.DockContext); // Create implicit window - we will only render it if the user has added something to it. // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags. @@ -4954,6 +4955,7 @@ { window->SizeContentsExplicit = ImVec2(0.0f, 0.0f); } + window->UserTypeId = g.NextWindowData.UserTypeId; if (g.NextWindowData.CollapsedCond) SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond); if (g.NextWindowData.FocusCond) @@ -6320,6 +6322,12 @@ g.NextWindowData.DockId = id; } +void ImGui::SetNextWindowUserType(ImGuiID user_type) +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.UserTypeId = user_type; +} + // In window space (not screen space!) ImVec2 ImGui::GetContentRegionMax() { @@ -9580,7 +9588,6 @@ static void DockNodeRemoveWindow(ImGuiDockNode* node, ImGuiWindow* window, ImGuiID save_dock_id); static void DockNodeHideHostWindow(ImGuiDockNode* node); static void DockNodeUpdate(ImGuiDockNode* node); - static ImGuiDockNode* DockNodeUpdateFindOnlyNodeWithWindows(ImGuiDockNode* node); static void DockNodeUpdateVisibleFlagAndInactiveChilds(ImGuiDockNode* node); static void DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_window); static void DockNodeUpdateVisibleFlag(ImGuiDockNode* node); @@ -9656,7 +9663,7 @@ DockContextBuildAddWindowsToNodes(ctx); } -void ImGui::DockContextUpdateUndocking(ImGuiDockContext* ctx) +void ImGui::DockContextNewFrameUpdateUndocking(ImGuiDockContext* ctx) { ImGuiContext& g = *GImGui; if (!(g.IO.ConfigFlags & ImGuiConfigFlags_DockingEnable)) @@ -9682,7 +9689,7 @@ DockContextProcessUndock(ctx, ctx->Requests[n].WindowUndock); } -void ImGui::DockContextUpdateDocking(ImGuiDockContext* ctx) +void ImGui::DockContextNewFrameUpdateDocking(ImGuiDockContext* ctx) { ImGuiContext& g = *GImGui; if (!(g.IO.ConfigFlags & ImGuiConfigFlags_DockingEnable)) @@ -10000,6 +10007,8 @@ ImGuiDockNode::ImGuiDockNode(ImGuiID id) { ID = id; + UserTypeIdFilter = 0; + Flags = 0; ParentNode = ChildNodes[0] = ChildNodes[1] = NULL; TabBar = NULL; SplitAxis = ImGuiAxis_None; @@ -10197,28 +10206,20 @@ } } -static void DockNodeUpdateFindOnlyNodeWithWindowsRec(ImGuiDockNode* node, int* p_count, ImGuiDockNode** p_only_node_with_windows) +static void DockNodeUpdateFindOnlyNodeWithWindowsRec(ImGuiDockNode* node, int* p_count, ImGuiDockNode** p_first_node_with_windows) { if (node->Windows.Size > 0) { - if (*p_only_node_with_windows == NULL) - *p_only_node_with_windows = node; + if (*p_first_node_with_windows == NULL) + *p_first_node_with_windows = node; (*p_count)++; } if (*p_count > 1) return; if (node->ChildNodes[0]) - DockNodeUpdateFindOnlyNodeWithWindowsRec(node->ChildNodes[0], p_count, p_only_node_with_windows); + DockNodeUpdateFindOnlyNodeWithWindowsRec(node->ChildNodes[0], p_count, p_first_node_with_windows); if (node->ChildNodes[1]) - DockNodeUpdateFindOnlyNodeWithWindowsRec(node->ChildNodes[1], p_count, p_only_node_with_windows); -} - -static ImGuiDockNode* ImGui::DockNodeUpdateFindOnlyNodeWithWindows(ImGuiDockNode* node) -{ - int count = 0; - ImGuiDockNode* only_node_with_windows = NULL; - DockNodeUpdateFindOnlyNodeWithWindowsRec(node, &count, &only_node_with_windows); - return (count == 1 ? only_node_with_windows : NULL); + DockNodeUpdateFindOnlyNodeWithWindowsRec(node->ChildNodes[1], p_count, p_first_node_with_windows); } static void ImGui::DockNodeUpdateVisibleFlagAndInactiveChilds(ImGuiDockNode* node) @@ -10280,8 +10281,19 @@ if (node->IsRootNode()) { DockNodeUpdateVisibleFlagAndInactiveChilds(node); - ImGuiDockNode* only_node_with_windows = node->IsExplicitRoot ? NULL : DockNodeUpdateFindOnlyNodeWithWindows(node); - node->OnlyNodeWithWindows = only_node_with_windows; + + // 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) + { + int count = 0; + ImGuiDockNode* first_node_with_windows = NULL; + DockNodeUpdateFindOnlyNodeWithWindowsRec(node, &count, &first_node_with_windows); + node->OnlyNodeWithWindows = (count == 1 ? first_node_with_windows : NULL); + + // Copy the user type from _any_ of our window so it can be used for proper dock filtering. + if (first_node_with_windows) + node->UserTypeIdFilter = first_node_with_windows->Windows[0]->UserTypeId; + } } // Early out for standalone floating window that are holding on a DockId (with an invisible dock node) @@ -10640,6 +10652,11 @@ ImGuiWindow* payload = root_payload->DockNodeAsHost ? root_payload->DockNodeAsHost->Windows[payload_n] : root_payload; if ((host_window->Flags & ImGuiWindowFlags_DockNodeHost) && payload->BeginOrderWithinContext < host_window->BeginOrderWithinContext) continue; + + ImGuiID host_user_type_id = host_window->DockNodeAsHost ? host_window->DockNodeAsHost->UserTypeIdFilter : host_window->UserTypeId; + if (payload->UserTypeId != host_user_type_id) + return false; + return true; } return false; @@ -10756,6 +10773,8 @@ data->IsCenterAvailable = false; data->IsSidesAvailable = true; + if (host_node && (host_node->Flags & ImGuiDockFlags_NoSplit)) + data->IsSidesAvailable = false; if (!is_outer_docking && host_node && host_node->ParentNode == NULL && host_node->IsDocumentRoot) data->IsSidesAvailable = false; @@ -10871,6 +10890,9 @@ } } + if (host_node && (host_node->Flags & ImGuiDockFlags_NoSplit)) + return; + // Display drop boxes const float overlay_rounding = ImMax(3.0f, g.Style.FrameRounding); for (int dir = ImGuiDir_None; dir < ImGuiDir_COUNT; dir++) @@ -11189,7 +11211,7 @@ window->DockId = dock_id; } -void ImGui::DockSpace(const char* str_id, const ImVec2& size_arg) +void ImGui::DockSpace(const char* str_id, const ImVec2& size_arg, ImGuiDockFlags dock_flags, ImGuiID user_type_filter) { ImGuiContext& g = *GImGui; ImGuiDockContext* ctx = g.DockContext; @@ -11204,6 +11226,8 @@ node = DockContextAddNode(ctx, id); node->IsDocumentRoot = true; } + node->Flags = dock_flags; + node->UserTypeIdFilter = user_type_filter; node->IsExplicitRoot = true; const ImVec2 content_avail = GetContentRegionAvail(); @@ -11235,6 +11259,7 @@ host_window->DockNodeAsHost = node; host_window->ChildId = window->GetID(title); node->HostWindow = host_window; + node->OnlyNodeWithWindows = NULL; IM_ASSERT(node->IsRootNode()); DockNodeUpdate(node); @@ -11320,7 +11345,7 @@ 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 + // Position window SetNextWindowPos(dock_node->Pos); SetNextWindowSize(dock_node->Size); g.NextWindowData.PosUndock = false; diff --git a/imgui.h b/imgui.h index 53f1779..528d6a5 100644 --- a/imgui.h +++ b/imgui.h @@ -111,6 +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 ImGuiDragDropFlags; // -> enum ImGuiDragDropFlags_ // Flags: for *DragDrop*() typedef int ImGuiFocusedFlags; // -> enum ImGuiFocusedFlags_ // Flags: for IsWindowFocused() typedef int ImGuiHoveredFlags; // -> enum ImGuiHoveredFlags_ // Flags: for IsItemHovered(), IsWindowHovered() etc. @@ -519,7 +520,8 @@ // 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)); + 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 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. IMGUI_API void LogToTTY(int max_depth = -1); // start logging to tty @@ -779,6 +781,13 @@ ImGuiTabItemFlags_NoPushId = 1 << 3 // Don't call PushID(tab->ID)/PopID() on BeginTabItem()/EndTabItem() }; +// Flags for ImGui::DockSpace() +enum ImGuiDockFlags_ +{ + ImGuiDockFlags_None = 0, + ImGuiDockFlags_NoSplit = 1 << 0 +}; + // Flags for ImGui::IsWindowFocused() enum ImGuiFocusedFlags_ { diff --git a/imgui_internal.h b/imgui_internal.h index 19640bc..0d8fe56 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -704,6 +704,7 @@ float BgAlphaVal; ImGuiID ViewportId; ImGuiID DockId; + ImGuiID UserTypeId; ImVec2 MenuBarOffsetMinVal; // This is not exposed publicly, so we don't clear it. ImGuiNextWindowData() @@ -716,13 +717,14 @@ SizeCallback = NULL; SizeCallbackUserData = NULL; BgAlphaVal = FLT_MAX; - ViewportId = DockId = 0; + ViewportId = DockId = UserTypeId = 0; MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f); } void Clear() { PosCond = SizeCond = ContentSizeCond = CollapsedCond = SizeConstraintCond = FocusCond = BgAlphaCond = ViewportCond = DockCond = 0; + UserTypeId = 0; } }; @@ -740,6 +742,8 @@ struct ImGuiDockNode { ImGuiID ID; + ImGuiID UserTypeIdFilter; + ImGuiDockFlags Flags; ImGuiDockNode* ParentNode; ImGuiDockNode* ChildNodes[2]; ImVector Windows; // Note: unordered list! Iterate TabBar->Tabs for user-order. @@ -1200,6 +1204,7 @@ ImGuiCond SetWindowDockAllowFlags; // store acceptable condition flags for SetNextWindowDock() use. ImVec2 SetWindowPosVal; // store window position when using a non-zero Pivot (position set needs to be processed when we know the window size) ImVec2 SetWindowPosPivot; // store window pivot for positioning. ImVec2(0,0) when positioning from top-left corner; ImVec2(0.5f,0.5f) for centering; ImVec2(1,1) for bottom right. + ImGuiID UserTypeId; // user value set with SetNextWindowUserType(const char*) ImGuiWindowTempData DC; // Temporary per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the "DC" variable name. ImVector IDStack; // ID stack. ID are hashes seeded with the value at the top of the stack @@ -1457,8 +1462,8 @@ IMGUI_API void DockContextShutdown(ImGuiContext* imgui_context); IMGUI_API void DockContextOnLoadSettings(); IMGUI_API void DockContextRebuild(ImGuiDockContext* ctx); - IMGUI_API void DockContextUpdateUndocking(ImGuiDockContext* ctx); - IMGUI_API void DockContextUpdateDocking(ImGuiDockContext* ctx); + IMGUI_API void DockContextNewFrameUpdateUndocking(ImGuiDockContext* ctx); + IMGUI_API void DockContextNewFrameUpdateDocking(ImGuiDockContext* ctx); IMGUI_API void DockContextQueueUndock(ImGuiDockContext* ctx, ImGuiWindow* window); IMGUI_API void BeginDocked(ImGuiWindow* window, bool* p_open); IMGUI_API void BeginAsDockableDragDropSource(ImGuiWindow* window);