From 04a9ce3a1818aa2b9cf1bb068ef33debbba8f15b Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 27 Mar 2019 15:34:02 +0100 Subject: [PATCH] Docking: Renamed ImGuiDockNodeFlags_PassthruDockspace to ImGuiDockNodeFlags_PassthruCentralNode. + Comments, shallow tweaks. (#2109) --- docs/TODO.txt | 1 - imgui.cpp | 28 ++++++++++++++++------------ imgui.h | 16 ++++++++-------- imgui_demo.cpp | 14 +++++++++----- imgui_internal.h | 12 ++++++------ 5 files changed, 39 insertions(+), 32 deletions(-) diff --git a/docs/TODO.txt b/docs/TODO.txt index 83795ef36..d227a92a1 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -133,7 +133,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - dock: A~ Unreal style document system (requires low-level controls of dockspace serialization fork/copy/delete). this is mostly working but the DockBuilderXXX api are not exposed/finished. - dock: B: when docking outer, perform size locking on neighbors nodes the same way we do it with splitters, so other nodes are not resized. - dock: B~ central node resizing behavior incorrect. - - dock: B~ central node ID retrieval API? - dock: B: changing title font/style per-window is not supported as dock nodes are created in NewFrame. - dock: B- dock node inside its own viewports creates 1 temporary viewport per window on startup before ditching them (doesn't affect the user nor request platform windows to be created, but unnecessary) - dock: B- resize sibling locking behavior may be less desirable if we merged same-axis sibling in a same node level? diff --git a/imgui.cpp b/imgui.cpp index d3c915377..a9fed610a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2605,7 +2605,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) DockNode = DockNodeAsHost = NULL; DockId = 0; - DockTabItemStatusFlags = 0; + DockTabItemStatusFlags = ImGuiItemStatusFlags_None; DockOrder = -1; DockIsActive = DockTabIsVisible = DockTabWantClose = false; } @@ -11343,7 +11343,7 @@ void ImGui::DockContextProcessUndockNode(ImGuiContext* ctx, ImGuiDockNode* node) ImGuiDockNode::ImGuiDockNode(ImGuiID id) { ID = id; - Flags = 0; + Flags = ImGuiDockNodeFlags_None; ParentNode = ChildNodes[0] = ChildNodes[1] = NULL; TabBar = NULL; SplitAxis = ImGuiAxis_None; @@ -11613,7 +11613,7 @@ static void ImGui::DockNodeUpdateVisibleFlagAndInactiveChilds(ImGuiDockNode* nod IM_ASSERT(node->ParentNode == NULL || node->ParentNode->ChildNodes[0] == node || node->ParentNode->ChildNodes[1] == node); // Inherit most flags - ImGuiDockNodeFlags flags_to_inherit = ~0 & ~ImGuiDockNodeFlags_Dockspace; + ImGuiDockNodeFlags flags_to_inherit = ~ImGuiDockNodeFlags_Dockspace; if (node->ParentNode) node->Flags = node->ParentNode->Flags & flags_to_inherit; @@ -11854,9 +11854,9 @@ 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_PassthruDockspace, but we will only know the correct pos/size after + // We need to draw a background at the root level if requested by ImGuiDockNodeFlags_PassthruCentralNode, 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_PassthruDockspace) != 0; + const bool render_dockspace_bg = node->IsRootNode() && host_window && (node->Flags & ImGuiDockNodeFlags_PassthruCentralNode) != 0; if (render_dockspace_bg) { host_window->DrawList->ChannelsSplit(2); @@ -11865,7 +11865,7 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node) // Register a hit-test hole in the window unless we are currently dragging a window that is compatible with our dockspace const ImGuiDockNode* central_node = node->CentralNode; - const bool central_node_hole = node->IsRootNode() && host_window && (node->Flags & ImGuiDockNodeFlags_PassthruDockspace) != 0 && central_node != NULL && central_node->IsEmpty(); + const bool central_node_hole = node->IsRootNode() && host_window && (node->Flags & ImGuiDockNodeFlags_PassthruCentralNode) != 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()) @@ -11892,10 +11892,10 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node) } // Draw empty node background (currently can only be the Central Node) - if (host_window && node->IsEmpty() && node->IsVisible && !(node->Flags & ImGuiDockNodeFlags_PassthruDockspace)) + if (host_window && node->IsEmpty() && node->IsVisible && !(node->Flags & ImGuiDockNodeFlags_PassthruCentralNode)) host_window->DrawList->AddRectFilled(node->Pos, node->Pos + node->Size, GetColorU32(ImGuiCol_DockingEmptyBg)); - // Draw whole dockspace background if ImGuiDockNodeFlags_PassthruDockspace if set. + // Draw whole dockspace background if ImGuiDockNodeFlags_PassthruCentralNode if set. if (render_dockspace_bg && node->IsVisible) { host_window->DrawList->ChannelsSetCurrent(0); @@ -12566,6 +12566,7 @@ void ImGui::DockNodeTreeSplit(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImG DockNodeMoveWindows(parent_node->ChildNodes[split_inheritor_child_idx], parent_node); DockNodeTreeUpdatePosSize(parent_node, parent_node->Pos, parent_node->Size); + // Flags transfer child_inheritor->IsCentralNode = parent_node->IsCentralNode; child_inheritor->IsHiddenTabBar = parent_node->IsHiddenTabBar; parent_node->IsCentralNode = false; @@ -12599,9 +12600,11 @@ void ImGui::DockNodeTreeMerge(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImG DockNodeApplyPosSizeToWindows(parent_node); parent_node->AutorityForPos = parent_node->AutorityForSize = parent_node->AutorityForViewport = ImGuiDataAutority_Auto; parent_node->VisibleWindow = merge_lead_child->VisibleWindow; + parent_node->SizeRef = backup_last_explicit_size; + + // Flags transfer parent_node->IsCentralNode = (child_0 && child_0->IsCentralNode) || (child_1 && child_1->IsCentralNode); parent_node->IsHiddenTabBar = merge_lead_child->IsHiddenTabBar; - parent_node->SizeRef = backup_last_explicit_size; if (child_0) { @@ -12961,7 +12964,7 @@ void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags fla End(); } -// Tips: Use with ImGuiDockNodeFlags_PassthruDockspace! +// Tips: Use with ImGuiDockNodeFlags_PassthruCentralNode! // The limitation with this call is that your window won't have a menu bar. // Even though we could pass window flags, it would also require the user to be able to call BeginMenuBar() somehow meaning we can't Begin/End in a single function. // So if you want a menu bar you need to repeat this code manually ourselves. As with advanced other Docking API, we may change this function signature. @@ -12977,7 +12980,7 @@ ImGuiID ImGui::DockSpaceOverViewport(ImGuiViewport* viewport, ImGuiDockNodeFlags ImGuiWindowFlags host_window_flags = 0; host_window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDocking; host_window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus; - if (dockspace_flags & ImGuiDockNodeFlags_PassthruDockspace) + if (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode) host_window_flags |= ImGuiWindowFlags_NoBackground; char label[32]; @@ -14186,6 +14189,7 @@ void ImGui::ShowDockingDebug() { static void NodeDockNode(ImGuiDockNode* node, const char* label) { + ImGuiContext& g = *GImGui; ImGui::SetNextTreeNodeOpen(true, ImGuiCond_Once); bool open; if (node->Windows.Size > 0) @@ -14203,7 +14207,7 @@ void ImGui::ShowDockingDebug() ImGui::BulletText("LastFocusedNodeID: 0x%08X", node->LastFocusedNodeID); ImGui::BulletText("Flags 0x%02X%s%s%s%s", node->Flags, node->IsDockSpace() ? ", IsDockSpace" : "", node->IsCentralNode ? ", IsCentralNode" : "", - (GImGui->FrameCount - node->LastFrameAlive < 2) ? ", IsAlive" : "", (GImGui->FrameCount - node->LastFrameActive < 2) ? ", IsActive" : ""); + (g.FrameCount - node->LastFrameAlive < 2) ? ", IsAlive" : "", (g.FrameCount - node->LastFrameActive < 2) ? ", IsActive" : ""); if (node->ChildNodes[0]) NodeDockNode(node->ChildNodes[0], "Child[0]"); if (node->ChildNodes[1]) diff --git a/imgui.h b/imgui.h index a7aff0bad..123d395d2 100644 --- a/imgui.h +++ b/imgui.h @@ -591,7 +591,8 @@ namespace ImGui // Docking // [BETA API] Enable with io.ConfigFlags |= ImGuiConfigFlags_DockingEnable. // Note: you DO NOT need to call DockSpace() to use most Docking facilities! - // To dock windows: hold SHIFT anywhere while moving windows (if io.ConfigDockingWithShift == true) or drag windows from their title bar (if io.ConfigDockingWithShift = false) + // To dock windows: if io.ConfigDockingWithShift == false: drag window from their title bar. + // To dock windows: if io.ConfigDockingWithShift == true: 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, const ImGuiWindowClass* window_class = NULL); IMGUI_API ImGuiID DockSpaceOverViewport(ImGuiViewport* viewport = NULL, ImGuiDockNodeFlags flags = 0, const ImGuiWindowClass* window_class = NULL); @@ -882,13 +883,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). Note: when turned off, existing splits will be preserved. - //ImGuiDockNodeFlags_NoCentralNode = 1 << 2, // Disable Central Node (the node which can stay empty) - ImGuiDockNodeFlags_NoDockingInCentralNode = 1 << 3, // Disable docking inside the Central Node, which will be always kept empty. Note: when turned off, existing docked nodes will be preserved. - //ImGuiDockNodeFlags_NoLayoutChanges = 1 << 4, // Disable adding/removing nodes interactively. Useful with programatically setup dockspaces. - ImGuiDockNodeFlags_NoResize = 1 << 5, // Disable resizing child nodes using the splitter/separators. Useful with programatically setup dockspaces. - ImGuiDockNodeFlags_PassthruDockspace = 1 << 6, // Enable passthru dockspace: 1) DockSpace() will render a ImGuiCol_WindowBg background covering everything excepted the Central Node when empty. Meaning the host window should probably use SetNextWindowBgAlpha(0.0f) prior to Begin() when using this. 2) When Central Node is empty: let inputs pass-through + won't display a DockingEmptyBg background. - ImGuiDockNodeFlags_AutoHideTabBar = 1 << 7 // Tab bar will automatically hide when there is a single window in the dock node. + //ImGuiDockNodeFlags_NoCentralNode = 1 << 1, // Disable Central Node (the node which can stay empty) + ImGuiDockNodeFlags_NoDockingInCentralNode = 1 << 2, // Disable docking inside the Central Node, which will be always kept empty. Note: when turned off, existing docked nodes will be preserved. + ImGuiDockNodeFlags_NoSplit = 1 << 3, // 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). Note: when turned off, existing splits will be preserved. + ImGuiDockNodeFlags_NoResize = 1 << 4, // Disable resizing child nodes using the splitter/separators. Useful with programatically setup dockspaces. + ImGuiDockNodeFlags_PassthruCentralNode = 1 << 5, // Enable passthru dockspace: 1) DockSpace() will render a ImGuiCol_WindowBg background covering everything excepted the Central Node when empty. Meaning the host window should probably use SetNextWindowBgAlpha(0.0f) prior to Begin() when using this. 2) When Central Node is empty: let inputs pass-through + won't display a DockingEmptyBg background. See demo for details. + ImGuiDockNodeFlags_AutoHideTabBar = 1 << 6 // Tab bar will automatically hide when there is a single window in the dock node. }; // Flags for ImGui::IsWindowFocused() diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 3de9826fa..130d6d520 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -4259,8 +4259,8 @@ void ShowExampleAppDockSpace(bool* p_open) window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus; } - // When using ImGuiDockNodeFlags_PassthruDockspace, DockSpace() will render our background and handle the pass-thru hole, so we ask Begin() to not render a background. - if (dockspace_flags & ImGuiDockNodeFlags_PassthruDockspace) + // When using ImGuiDockNodeFlags_PassthruCentralNode, DockSpace() will render our background and handle the pass-thru hole, so we ask Begin() to not render a background. + if (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode) window_flags |= ImGuiWindowFlags_NoBackground; ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); @@ -4291,9 +4291,9 @@ void ShowExampleAppDockSpace(bool* p_open) //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: NoDockingInCentralNode", "", (dockspace_flags & ImGuiDockNodeFlags_NoDockingInCentralNode) != 0)) dockspace_flags ^= ImGuiDockNodeFlags_NoDockingInCentralNode; if (ImGui::MenuItem("Flag: NoResize", "", (dockspace_flags & ImGuiDockNodeFlags_NoResize) != 0)) dockspace_flags ^= ImGuiDockNodeFlags_NoResize; - if (ImGui::MenuItem("Flag: PassthruDockspace", "", (dockspace_flags & ImGuiDockNodeFlags_PassthruDockspace) != 0)) dockspace_flags ^= ImGuiDockNodeFlags_PassthruDockspace; + if (ImGui::MenuItem("Flag: NoDockingInCentralNode", "", (dockspace_flags & ImGuiDockNodeFlags_NoDockingInCentralNode) != 0)) dockspace_flags ^= ImGuiDockNodeFlags_NoDockingInCentralNode; + if (ImGui::MenuItem("Flag: PassthruCentralNode", "", (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode) != 0)) dockspace_flags ^= ImGuiDockNodeFlags_PassthruCentralNode; if (ImGui::MenuItem("Flag: AutoHideTabBar", "", (dockspace_flags & ImGuiDockNodeFlags_AutoHideTabBar) != 0)) dockspace_flags ^= ImGuiDockNodeFlags_AutoHideTabBar; ImGui::Separator(); if (ImGui::MenuItem("Close DockSpace", NULL, false, p_open != NULL)) @@ -4301,7 +4301,11 @@ void ShowExampleAppDockSpace(bool* p_open) ImGui::EndMenu(); } HelpMarker( - "You can _always_ dock _any_ window into another by holding the SHIFT key while moving a window. Try it now!" "\n" + "When docking is enabled, you can ALWAYS dock MOST window into another! Try it now!" "\n\n" + " > if io.ConfigDockingWithShift==false (default):" "\n" + " drag windows from title bar to dock" "\n" + " > if io.ConfigDockingWithShift==true:" "\n" + " drag windows from anywhere and hold Shift to dock" "\n\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 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" diff --git a/imgui_internal.h b/imgui_internal.h index 19128ad5f..3c2d87975 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -903,12 +903,12 @@ struct ImGuiDockNode ImGuiDockNode(ImGuiID id); ~ImGuiDockNode(); - bool IsRootNode() const { return ParentNode == NULL; } - bool IsDockSpace() const { return (Flags & ImGuiDockNodeFlags_Dockspace) != 0; } - bool IsSplitNode() const { return ChildNodes[0] != NULL; } - bool IsLeafNode() const { return ChildNodes[0] == NULL; } - bool IsEmpty() const { return ChildNodes[0] == NULL && Windows.Size == 0; } - ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } + bool IsRootNode() const { return ParentNode == NULL; } + bool IsDockSpace() const { return (Flags & ImGuiDockNodeFlags_Dockspace) != 0; } + bool IsSplitNode() const { return ChildNodes[0] != NULL; } + bool IsLeafNode() const { return ChildNodes[0] == NULL; } + bool IsEmpty() const { return ChildNodes[0] == NULL && Windows.Size == 0; } + ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } }; //-----------------------------------------------------------------------------