From 4e30698706e5c0b6cae5bd45d633de15d98ea445 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 3 Oct 2018 22:32:23 +0200 Subject: [PATCH] Docking: Added ImGuiDockNodeFlags_PassthruDockspace mode (subdivided in three flags: ImGuiDockNodeFlags_NoDockingInCentralNode, ImGuiDockNodeFlags_PassthruInEmptyNodes, ImGuiDockNodeFlags_RenderWindowBg). Added internal facility for register a rectangular hit-test hole in window. Updated DockSpace demo accordingly. (#2109) --- docs/CHANGELOG.txt | 40 ++++++------ imgui.cpp | 151 +++++++++++++++++++++++++++++++++------------ imgui.h | 8 ++- imgui_demo.cpp | 51 ++++++++------- imgui_internal.h | 1 + 5 files changed, 166 insertions(+), 85 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 21a7ae8b5..e1f5e30c8 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -33,25 +33,27 @@ HOW TO UPDATE? DOCKING BRANCH (In Progress) ----------------------------------------------------------------------- -- Added ImGuiConfigFlags_DockingEnable flag to enable Docking. [BETA] - Set with `io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;`. -- Added BeginTabBar(), EndTabBar(), BeginTabItem(), EndTabItem(), SetTabItemClosed() API. (#261, #351) -- Added ImGuiTabBarFlags flags for BeginTabBar(). -- Added ImGuiTabItemFlags flags for BeginTabItem(). -- Added DockSpace() API. (#351) -- Added ImGuiDockNodeFlags flags for DockSpace(). -- Added SetNextWindowDock(), SetNextWindowDockFamily() API. (#351) -- Added GetWindowDockId(), IsWindowDocked() API. (#351) -- Added ImGuiWindowFlags_NoDocking window flag to disable the possibility for a window to be docked. - Popup, Menu and Child windows always have the ImGuiWindowFlags_NoDocking flag set. (#351) -- Added ImGuiWindowFlags_UnsavedDocument window flag to append '*' to title without altering the ID, - as a convenience to avoid using the ### operator. -- Added io.ConfigDockingWithShift option to configure docking mode. -- Style: Added ImGuiCol_DockingPreview, ImGuiCol_DockingEmptyBg colors. (#351) -- Style: Added ImGuiCol_Tab, ImGuiCol_TabHovered, ImGuiCol_TabActive, ImGuiCol_TabUnfocused, ImGuiCol_TabUnfocusedActive colors. (#261, #351) -- Demo: Added Layout->Tabs demo code. (#261, #351) -- Demo: Added "Documents" example app showcasing possible use for tabs. (#261, #351) -- Demo: Added "DockSpace" example app showcasing use of explicit dockspace nodes. (#351) +- Added Docking system: [BETA] (#2109, #351) + - Added ImGuiConfigFlags_DockingEnable flag to enable Docking. + Set with `io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;`. + - Added DockSpace() API. + - Added ImGuiDockNodeFlags flags for DockSpace(). + - Added SetNextWindowDock(), SetNextWindowDockFamily() API. + - Added GetWindowDockId(), IsWindowDocked() API. + - Added ImGuiWindowFlags_NoDocking window flag to disable the possibility for a window to be docked. + Popup, Menu and Child windows always have the ImGuiWindowFlags_NoDocking flag set. + - Added io.ConfigDockingWithShift option to configure docking mode. + - Style: Added ImGuiCol_DockingPreview, ImGuiCol_DockingEmptyBg colors. + - Demo: Added "DockSpace" example app showcasing use of explicit dockspace nodes. +- Added Tab Bar/Tabs widgets: (#261, #351) + - Added BeginTabBar(), EndTabBar(), BeginTabItem(), EndTabItem(), SetTabItemClosed() API. + - Added ImGuiTabBarFlags flags for BeginTabBar(). + - Added ImGuiTabItemFlags flags for BeginTabItem(). + - Style: Added ImGuiCol_Tab, ImGuiCol_TabHovered, ImGuiCol_TabActive, ImGuiCol_TabUnfocused, ImGuiCol_TabUnfocusedActive colors. + - Demo: Added Layout->Tabs demo code. + - Demo: Added "Documents" example app showcasing possible use for tabs. +- Added ImGuiWindowFlags_UnsavedDocument window flag to append '*' to title without altering + the ID, as a convenience to avoid using the ### operator. ----------------------------------------------------------------------- diff --git a/imgui.cpp b/imgui.cpp index d6582a936..c453acad1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -918,6 +918,7 @@ static void SetCurrentWindow(ImGuiWindow* window); static void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond); static void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond); static void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond); +static void SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size); static void FindHoveredWindow(); static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags); static void CheckStacksSize(ImGuiWindow* window, bool write); @@ -4002,6 +4003,15 @@ static void FindHoveredWindow() bb.Expand(padding_for_resize_from_edges); if (!bb.Contains(g.IO.MousePos)) continue; + + if (window->HitTestHoleSize.x != 0) + { + // FIXME: Consider generalizing hit-testing override (with more generic data, callback, etc.) (#1512) + ImRect hole_bb((float)(window->HitTestHoleOffset.x), (float)(window->HitTestHoleOffset.y), + (float)(window->HitTestHoleOffset.x + window->HitTestHoleSize.x), (float)(window->HitTestHoleOffset.y + window->HitTestHoleSize.y)); + if (hole_bb.Contains(g.IO.MousePos - window->Pos)) + continue; + } if (hovered_window == NULL) hovered_window = window; @@ -5501,6 +5511,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) } } + // Clear hit test shape every frame + window->HitTestHoleSize.x = window->HitTestHoleSize.y = 0; + // Save clipped aabb so we can access it in constant-time in FindHoveredWindow() window->OuterRectClipped = window->Rect(); if (window->DockIsActive) @@ -6271,6 +6284,13 @@ static void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond co window->Collapsed = collapsed; } +static void SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size) +{ + IM_ASSERT(window->HitTestHoleSize.x == 0); // We don't support multiple holes/hit test filters + window->HitTestHoleSize = ImVec2ih((short)size.x, (short)size.y); + window->HitTestHoleOffset = ImVec2ih((short)(pos.x - window->Pos.x), (short)(pos.y - window->Pos.y)); +} + void ImGui::SetWindowCollapsed(bool collapsed, ImGuiCond cond) { SetWindowCollapsed(GImGui->CurrentWindow, collapsed, cond); @@ -10430,20 +10450,35 @@ static void ImGui::DockNodeHideHostWindow(ImGuiDockNode* node) } } -static void DockNodeUpdateFindOnlyNodeWithWindowsRec(ImGuiDockNode* node, int* p_count, ImGuiDockNode** p_first_node_with_windows) +struct ImGuiDockNodeUpdateScanResults +{ + ImGuiDockNode* CentralNode; + ImGuiDockNode* FirstNodeWithWindows; + int CountNodesWithWindows; + ImGuiDockFamily DockFamilyForMerges; + + ImGuiDockNodeUpdateScanResults() { CentralNode = FirstNodeWithWindows = NULL; CountNodesWithWindows = 0; } +}; + +static void DockNodeUpdateScanRec(ImGuiDockNode* node, ImGuiDockNodeUpdateScanResults* results) { if (node->Windows.Size > 0) { - if (*p_first_node_with_windows == NULL) - *p_first_node_with_windows = node; - (*p_count)++; + if (results->FirstNodeWithWindows == NULL) + results->FirstNodeWithWindows = node; + results->CountNodesWithWindows++; } - if (*p_count > 1) + if (node->IsCentralNode) + { + IM_ASSERT(results->CentralNode == NULL); // Should be only one + results->CentralNode = node; + } + if (results->CountNodesWithWindows > 1 && results->CentralNode != NULL) return; if (node->ChildNodes[0]) - DockNodeUpdateFindOnlyNodeWithWindowsRec(node->ChildNodes[0], p_count, p_first_node_with_windows); + DockNodeUpdateScanRec(node->ChildNodes[0], results); if (node->ChildNodes[1]) - DockNodeUpdateFindOnlyNodeWithWindowsRec(node->ChildNodes[1], p_count, p_first_node_with_windows); + DockNodeUpdateScanRec(node->ChildNodes[1], results); } static void ImGui::DockNodeUpdateVisibleFlagAndInactiveChilds(ImGuiDockNode* node) @@ -10519,32 +10554,31 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node) IM_ASSERT(node->LastFrameActive != g.FrameCount); node->LastFrameAlive = g.FrameCount; + ImGuiDockNode* central_node = NULL; if (node->IsRootNode()) { 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: that last part is not done yet!) - if (!node->IsDockSpace) - { - 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); - if (node->LastFocusedNodeID == 0 && first_node_with_windows != NULL) - node->LastFocusedNodeID = first_node_with_windows->ID; + ImGuiDockNodeUpdateScanResults results; + DockNodeUpdateScanRec(node, &results); + node->OnlyNodeWithWindows = (results.CountNodesWithWindows == 1 ? results.FirstNodeWithWindows : NULL); + if (node->LastFocusedNodeID == 0 && results.FirstNodeWithWindows != NULL) + node->LastFocusedNodeID = results.FirstNodeWithWindows->ID; + central_node = results.CentralNode; - // Copy the dock family from of our window so it can be used for proper dock filtering. - // When node has mixed windows, prioritize the family with the most constraint (CompatibleWithNeutral = false) as the reference to copy. - if (first_node_with_windows) - { - node->DockFamily = first_node_with_windows->Windows[0]->DockFamily; - for (int n = 1; n < first_node_with_windows->Windows.Size; n++) - if (first_node_with_windows->Windows[n]->DockFamily.CompatibleWithFamilyZero == false) - { - node->DockFamily = first_node_with_windows->Windows[n]->DockFamily; - break; - } - } + // Copy the dock family from of our window so it can be used for proper dock filtering. + // When node has mixed windows, prioritize the family with the most constraint (CompatibleWithNeutral = false) as the reference to copy. + // FIXME-DOCK: We don't recurse properly, this code could be reworked to work from DockNodeUpdateScanRec. + if (ImGuiDockNode* first_node_with_windows = results.FirstNodeWithWindows) + { + node->DockFamily = first_node_with_windows->Windows[0]->DockFamily; + for (int n = 1; n < first_node_with_windows->Windows.Size; n++) + if (first_node_with_windows->Windows[n]->DockFamily.CompatibleWithFamilyZero == false) + { + node->DockFamily = first_node_with_windows->Windows[n]->DockFamily; + break; + } } } @@ -10660,6 +10694,35 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node) if (g.NavWindow && g.NavWindow->RootWindowDockStop->DockNode && g.NavWindow->RootWindowDockStop->ParentWindow == host_window) node->LastFocusedNodeID = g.NavWindow->RootWindowDockStop->DockNode->ID; + // We need to draw a background if requested by ImGuiDockNodeFlags_RenderWindowBg, but we will only know the correct pos/size after + // processing the resizing splitters. So we are using the DrawList channel splitting facility to submit drawing primitives out of order! + const bool render_dockspace_bg = node->IsRootNode() && host_window && (node->Flags & ImGuiDockNodeFlags_RenderWindowBg) != 0; + if (render_dockspace_bg) + { + host_window->DrawList->ChannelsSplit(2); + host_window->DrawList->ChannelsSetCurrent(1); + } + + // Register a hit-test hole in the window unless we are currently dragging a window that is compatible our dockspace + bool central_node_hole = node->IsRootNode() && host_window && (node->Flags & ImGuiDockNodeFlags_PassthruInEmptyNodes) != 0 && central_node != NULL && central_node->IsEmpty(); + bool central_node_hole_register_hit_test_hole = central_node_hole; + if (central_node_hole) + if (const ImGuiPayload* payload = ImGui::GetDragDropPayload()) + if (payload->IsDataType(IMGUI_PAYLOAD_TYPE_WINDOW) && DockNodeIsDropAllowed(host_window, *(ImGuiWindow**)payload->Data)) + central_node_hole_register_hit_test_hole = false; + if (central_node_hole_register_hit_test_hole) + { + // Add a little padding to match the "resize from edges" behavior and allow grabbing the splitter easily. + IM_ASSERT(node->IsDockSpace); // We cannot pass this flag without the DockSpace() api. Testing this because we also setup the hole in host_window->ParentNode + ImRect central_hole(central_node->Pos, central_node->Pos + central_node->Size); + central_hole.Expand(ImVec2(-RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS, -RESIZE_WINDOWS_FROM_EDGES_HALF_THICKNESS)); + if (central_node_hole && !central_hole.IsInverted()) + { + SetWindowHitTestHole(host_window, central_hole.Min, central_hole.Max - central_hole.Min); + SetWindowHitTestHole(host_window->ParentWindow, central_hole.Min, central_hole.Max - central_hole.Min); + } + } + // Update position/size, process and draw resizing splitters if (node->IsRootNode() && host_window) { @@ -10667,6 +10730,21 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node) DockNodeTreeUpdateSplitter(node); } + // Draw empty node background (currently can only be the Central Node) + if (host_window && node->IsEmpty() && node->IsVisible && !(node->Flags & ImGuiDockNodeFlags_PassthruInEmptyNodes)) + host_window->DrawList->AddRectFilled(node->Pos, node->Pos + node->Size, GetColorU32(ImGuiCol_DockingEmptyBg)); + + // Draw whole dockspace background if ImGuiDockNodeFlags_RenderWindowBg if set. + if (render_dockspace_bg && node->IsVisible) + { + host_window->DrawList->ChannelsSetCurrent(0); + if (central_node_hole) + RenderRectFilledWithHole(host_window->DrawList, node->Rect(), central_node->Rect(), GetColorU32(ImGuiCol_WindowBg), 0.0f); + else + host_window->DrawList->AddRectFilled(node->Pos, node->Pos + node->Size, GetColorU32(ImGuiCol_WindowBg), 0.0f); + host_window->DrawList->ChannelsMerge(); + } + // Draw and populate Tab Bar if (host_window && node->Windows.Size > 0) { @@ -10681,16 +10759,11 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node) if (node->Windows.Size > 0) node->SelectedTabID = node->Windows[0]->ID; } - if (host_window && node->IsVisible) - { - // Background for empty nodes - if (node->Windows.Size == 0 && !node->IsSplitNode()) - host_window->DrawList->AddRectFilled(node->Pos, node->Pos + node->Size, GetColorU32(ImGuiCol_DockingEmptyBg)); - // Draw drop target + // Draw payload drop target + if (host_window && node->IsVisible) if (node->IsRootNode() && (g.MovingWindow == NULL || g.MovingWindow->RootWindow != host_window)) BeginAsDockableDragDropTarget(host_window); - } node->LastFrameActive = g.FrameCount; @@ -11060,7 +11133,7 @@ static bool ImGui::DockNodePreviewDockCalc(ImGuiWindow* host_window, ImGuiDockNo data->IsCenterAvailable = !is_outer_docking; if (src_is_visibly_splitted && (!host_node || !host_node->IsEmpty())) data->IsCenterAvailable = false; - if (host_node && (host_node->Flags & ImGuiDockNodeFlags_NoDockingInsideCentralNode) && host_node->IsCentralNode) + if (host_node && (host_node->Flags & ImGuiDockNodeFlags_NoDockingInCentralNode) && host_node->IsCentralNode) data->IsCenterAvailable = false; data->IsSidesAvailable = true; @@ -11568,11 +11641,9 @@ void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags doc if (node->Windows.Size > 0 || node->IsSplitNode()) PushStyleColor(ImGuiCol_ChildBg, IM_COL32(0, 0, 0, 0)); - if (dockspace_flags & ImGuiDockNodeFlags_NoOuterBorder) - PushStyleVar(ImGuiStyleVar_ChildBorderSize, 0.0f); + PushStyleVar(ImGuiStyleVar_ChildBorderSize, 0.0f); Begin(title, NULL, window_flags); - if (dockspace_flags & ImGuiDockNodeFlags_NoOuterBorder) - PopStyleVar(); + PopStyleVar(); if (node->Windows.Size > 0 || node->IsSplitNode()) PopStyleColor(); @@ -11953,7 +12024,7 @@ void ImGui::BeginDocked(ImGuiWindow* window, bool* p_open) } // Undock if the ImGuiDockNodeFlags_NoDockingInCentralNode got set - if (dock_node->IsCentralNode && (dock_node->Flags & ImGuiDockNodeFlags_NoDockingInsideCentralNode)) + if (dock_node->IsCentralNode && (dock_node->Flags & ImGuiDockNodeFlags_NoDockingInCentralNode)) { DockContextProcessUndockWindow(ctx, window); return; diff --git a/imgui.h b/imgui.h index 730b856de..4299af319 100644 --- a/imgui.h +++ b/imgui.h @@ -798,8 +798,12 @@ enum ImGuiDockNodeFlags_ 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 disabled to reduce confusion) - ImGuiDockNodeFlags_NoOuterBorder = 1 << 2, // Disable outer border on a DockSpace() node. - ImGuiDockNodeFlags_NoDockingInsideCentralNode = 1 << 3 // Disable docking inside the central node (which can stay empty). Useful if it is kept empty and invisible. + //ImGuiDockNodeFlags_NoCentralNode = 1 << 2, // Disable Central Node (the node which can stay empty) + //ImGuiDockNodeFlags_NoOuterBorder = 1 << 3, // Disable outer border on a DockSpace() node. + ImGuiDockNodeFlags_NoDockingInCentralNode = 1 << 4, // Disable docking inside the Central Node, which will be always kept empty. + ImGuiDockNodeFlags_PassthruInEmptyNodes = 1 << 5, // When Central Node is empty: let inputs pass-through + won't display a DockingEmptyBg background. + ImGuiDockNodeFlags_RenderWindowBg = 1 << 6, // DockSpace() will render a ImGuiCol_WindowBg background covering everything excepted the Central Node (when empty). Meaning the host window should properly use SetNextWindowBgAlpha(0.0f) + ImGuiDockNodeFlags_NoOuterBorder prior to Begin() when using this. + ImGuiDockNodeFlags_PassthruDockspace = ImGuiDockNodeFlags_NoDockingInCentralNode | ImGuiDockNodeFlags_RenderWindowBg | ImGuiDockNodeFlags_PassthruInEmptyNodes }; // Flags for ImGui::IsWindowFocused() diff --git a/imgui_demo.cpp b/imgui_demo.cpp index d7ab5caa7..b8aac46bd 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -3715,13 +3715,12 @@ static void ShowExampleAppCustomRendering(bool* p_open) void ShowExampleAppDockSpace(bool* p_open) { static bool opt_fullscreen_persistant = true; + static ImGuiDockNodeFlags opt_flags = ImGuiDockNodeFlags_None; bool opt_fullscreen = opt_fullscreen_persistant; - // 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 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; + // We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into, + // because it would be confusing to have two docking targets within each others. + ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking; if (opt_fullscreen) { ImGuiViewport* viewport = ImGui::GetMainViewport(); @@ -3729,22 +3728,28 @@ void ShowExampleAppDockSpace(bool* p_open) ImGui::SetNextWindowSize(viewport->Size); ImGui::SetNextWindowViewport(viewport->ID); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); - flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove; - flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus; + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove; + window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus; } - static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_None; + // When using ImGuiDockNodeFlags_RenderWindowBg or ImGuiDockNodeFlags_InvisibleDockspace, DockSpace() will render our background and handle the pass-thru hole, so we ask Begin() to not render a background. + if (opt_flags & ImGuiDockNodeFlags_RenderWindowBg) + ImGui::SetNextWindowBgAlpha(0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); - ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); - ImGui::Begin("DockSpace Demo", p_open, flags); - ImGui::PopStyleVar(2); + ImGui::Begin("DockSpace Demo", p_open, window_flags); + ImGui::PopStyleVar(); + + if (opt_fullscreen) + ImGui::PopStyleVar(2); // Dockspace ImGuiIO& io = ImGui::GetIO(); if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable) { ImGuiID dockspace_id = ImGui::GetID("MyDockspace"); - ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags | ImGuiDockNodeFlags_NoOuterBorder); + ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), opt_flags); } else { @@ -3753,21 +3758,21 @@ void ShowExampleAppDockSpace(bool* p_open) if (ImGui::BeginMenuBar()) { - if (ImGui::BeginMenu("Options")) + if (ImGui::BeginMenu("Docking")) { - if (ImGui::MenuItem("Remove DockSpace", NULL, false, p_open != NULL)) - *p_open = false; - ImGui::Separator(); - // Disabling fullscreen would allow the window to be moved to the front of other windows, // which we can't undo at the moment without finer window depth/z control. //ImGui::MenuItem("Fullscreen", NULL, &opt_fullscreen_persistant); - if (ImGui::MenuItem("Flag: NoSplit", "", (dockspace_flags & ImGuiDockNodeFlags_NoSplit) != 0)) - dockspace_flags ^= ImGuiDockNodeFlags_NoSplit; - if (ImGui::MenuItem("Flag: NoDockingInsideCentralNode", "", (dockspace_flags & ImGuiDockNodeFlags_NoDockingInsideCentralNode) != 0)) - dockspace_flags ^= ImGuiDockNodeFlags_NoDockingInsideCentralNode; - + if (ImGui::MenuItem("Flag: NoSplit", "", (opt_flags & ImGuiDockNodeFlags_NoSplit) != 0)) opt_flags ^= ImGuiDockNodeFlags_NoSplit; + if (ImGui::MenuItem("Flag: NoDockingInCentralNode", "", (opt_flags & ImGuiDockNodeFlags_NoDockingInCentralNode) != 0)) opt_flags ^= ImGuiDockNodeFlags_NoDockingInCentralNode; + if (ImGui::MenuItem("Flag: PassthruInEmptyNodes", "", (opt_flags & ImGuiDockNodeFlags_PassthruInEmptyNodes) != 0)) opt_flags ^= ImGuiDockNodeFlags_PassthruInEmptyNodes; + if (ImGui::MenuItem("Flag: RenderWindowBg", "", (opt_flags & ImGuiDockNodeFlags_RenderWindowBg) != 0)) opt_flags ^= ImGuiDockNodeFlags_RenderWindowBg; + if (ImGui::MenuItem("Flag: PassthruDockspace (all 3 above)", "", (opt_flags & ImGuiDockNodeFlags_PassthruDockspace) == ImGuiDockNodeFlags_PassthruDockspace)) + opt_flags = (opt_flags & ~ImGuiDockNodeFlags_PassthruDockspace) | ((opt_flags & ImGuiDockNodeFlags_PassthruDockspace) == ImGuiDockNodeFlags_PassthruDockspace) ? 0 : ImGuiDockNodeFlags_PassthruDockspace; + ImGui::Separator(); + if (ImGui::MenuItem("Close DockSpace", NULL, false, p_open != NULL)) + *p_open = false; ImGui::EndMenu(); } ShowHelpMarker( @@ -3782,8 +3787,6 @@ void ShowExampleAppDockSpace(bool* p_open) } ImGui::End(); - if (opt_fullscreen) - ImGui::PopStyleVar(); } //----------------------------------------------------------------------------- diff --git a/imgui_internal.h b/imgui_internal.h index 5dcaf2212..e958102ad 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1218,6 +1218,7 @@ struct IMGUI_API ImGuiWindow ImRect ClipRect; // Current clipping rectangle. = DrawList->clip_rect_stack.back(). Scissoring / clipping rectangle. x1, y1, x2, y2. ImRect OuterRectClipped; // = WindowRect just after setup in Begin(). == window->Rect() for root window. ImRect InnerMainRect, InnerClipRect; + ImVec2ih HitTestHoleSize, HitTestHoleOffset; ImRect ContentsRegionRect; // FIXME: This is currently confusing/misleading. Maximum visible content position ~~ Pos + (SizeContentsExplicit ? SizeContentsExplicit : Size - ScrollbarSizes) - CursorStartPos, per axis int LastFrameActive; // Last frame number the window was Active. float ItemWidthDefault;