From 511e32e8ca7dcae9fbca4bf3a899597a13bfbf59 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 27 May 2019 12:12:11 +0200 Subject: [PATCH] Docking: Clarified terminology of docking/tablist/collapse button into Window Menu button matching master. Added private ImGuiDockNodeFlags_NoWindowMenuButton, ImGuiDockNodeFlags_NoCloseButton flags. (#2583, #2109) --- imgui.cpp | 86 ++++++++++++++++++++++++++++-------------------- imgui.h | 3 +- imgui_internal.h | 7 ++-- 3 files changed, 58 insertions(+), 38 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index cde3c4ab1..62bf4d94b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5438,6 +5438,7 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar } // Render title text, collapse button, close button +// When inside a dock node, this is handled in DockNodeUpdateTabBar() instead. void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open) { ImGuiContext& g = *GImGui; @@ -5447,7 +5448,7 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl const bool has_close_button = (p_open != NULL); const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse); - // Close & collapse button are on the Menu NavLayer and don't default focus (unless there's nothing else on that layer) + // Close & Collapse button are on the Menu NavLayer and don't default focus (unless there's nothing else on that layer) const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags; window->DC.ItemFlags |= ImGuiItemFlags_NoNavDefaultFocus; window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; @@ -11119,13 +11120,13 @@ namespace ImGui static void DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_window); static void DockNodeAddTabBar(ImGuiDockNode* node); static void DockNodeRemoveTabBar(ImGuiDockNode* node); - static ImGuiID DockNodeUpdateTabListMenu(ImGuiDockNode* node, ImGuiTabBar* tab_bar); + static ImGuiID DockNodeUpdateWindowMenu(ImGuiDockNode* node, ImGuiTabBar* tab_bar); static void DockNodeUpdateVisibleFlag(ImGuiDockNode* node); static void DockNodeStartMouseMovingWindow(ImGuiDockNode* node, ImGuiWindow* window); static bool DockNodeIsDropAllowed(ImGuiWindow* host_window, ImGuiWindow* payload_window); static void DockNodePreviewDockCalc(ImGuiWindow* host_window, ImGuiDockNode* host_node, ImGuiWindow* payload_window, ImGuiDockPreviewData* preview_data, bool is_explicit_target, bool is_outer_docking); static void DockNodePreviewDockRender(ImGuiWindow* host_window, ImGuiDockNode* host_node, ImGuiWindow* payload_window, const ImGuiDockPreviewData* preview_data); - static void DockNodeCalcTabBarLayout(const ImGuiDockNode* node, ImRect* out_title_rect, ImRect* out_tab_bar_rect, ImVec2* out_collapse_button_pos); + static void DockNodeCalcTabBarLayout(const ImGuiDockNode* node, ImRect* out_title_rect, ImRect* out_tab_bar_rect, ImVec2* out_window_menu_button_pos); static void DockNodeCalcSplitRects(ImVec2& pos_old, ImVec2& size_old, ImVec2& pos_new, ImVec2& size_new, ImGuiDir dir, ImVec2 size_new_desired); static bool DockNodeCalcDropRectsAndTestMousePos(const ImRect& parent, ImGuiDir dir, ImRect& out_draw, bool outer_docking, ImVec2* test_mouse_pos); static const char* DockNodeGetHostWindowTitle(ImGuiDockNode* node, char* buf, int buf_size) { ImFormatString(buf, buf_size, "##DockNode_%02X", node->ID); return buf; } @@ -11713,7 +11714,7 @@ ImGuiDockNode::ImGuiDockNode(ImGuiID id) AuthorityForPos = AuthorityForSize = ImGuiDataAuthority_DockNode; AuthorityForViewport = ImGuiDataAuthority_Auto; IsVisible = true; - IsFocused = HasCloseButton = HasCollapseButton = false; + IsFocused = HasCloseButton = HasWindowMenuButton = EnableCloseButton = false; WantCloseAll = WantLockSizeOnce = WantMouseMove = WantHiddenTabBarUpdate = WantHiddenTabBarToggle = false; } @@ -12112,7 +12113,7 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node) DockNodeHideHostWindow(node); node->WantCloseAll = false; node->WantCloseTabID = 0; - node->HasCloseButton = node->HasCollapseButton = false; + node->HasCloseButton = node->HasWindowMenuButton = node->EnableCloseButton = false; node->LastFrameActive = g.FrameCount; if (node->WantMouseMove && node->Windows.Size == 1) @@ -12120,27 +12121,31 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node) return; } + const ImGuiDockNodeFlags node_flags = node->GetMergedFlags(); + ImGuiWindow* host_window = NULL; bool beginned_into_host_window = false; if (node->IsDockSpace()) { // [Explicit root dockspace node] IM_ASSERT(node->HostWindow); - node->HasCloseButton = false; - node->HasCollapseButton = true; + node->EnableCloseButton = false; + node->HasCloseButton = (node_flags & ImGuiDockNodeFlags_NoCloseButton) == 0; + node->HasWindowMenuButton = (node_flags & ImGuiDockNodeFlags_NoWindowMenuButton) == 0; host_window = node->HostWindow; } else { // [Automatic root or child nodes] - node->HasCloseButton = false; - node->HasCollapseButton = (node->Windows.Size > 0); + node->EnableCloseButton = false; + node->HasCloseButton = (node->Windows.Size > 0) && (node_flags & ImGuiDockNodeFlags_NoWindowMenuButton) == 0; + node->HasWindowMenuButton = (node->Windows.Size > 0) && (node_flags & ImGuiDockNodeFlags_NoWindowMenuButton) == 0; for (int window_n = 0; window_n < node->Windows.Size; window_n++) { // FIXME-DOCK: Setting DockIsActive here means that for single active window in a leaf node, DockIsActive will be cleared until the next Begin() call. ImGuiWindow* window = node->Windows[window_n]; window->DockIsActive = (node->Windows.Size > 1); - node->HasCloseButton |= window->HasCloseButton; + node->EnableCloseButton |= window->HasCloseButton; } if (node->IsRootNode() && node->IsVisible) @@ -12217,7 +12222,6 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node) // 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 ImGuiDockNodeFlags node_flags = node->GetMergedFlags(); const bool render_dockspace_bg = node->IsRootNode() && host_window && (node_flags & ImGuiDockNodeFlags_PassthruCentralNode) != 0; if (render_dockspace_bg) { @@ -12319,7 +12323,7 @@ static int IMGUI_CDECL TabItemComparerByDockOrder(const void* lhs, const void* r return (a->BeginOrderWithinContext - b->BeginOrderWithinContext); } -static ImGuiID ImGui::DockNodeUpdateTabListMenu(ImGuiDockNode* node, ImGuiTabBar* tab_bar) +static ImGuiID ImGui::DockNodeUpdateWindowMenu(ImGuiDockNode* node, ImGuiTabBar* tab_bar) { // Try to position the menu so it is more likely to stays within the same viewport ImGuiContext& g = *GImGui; @@ -12328,7 +12332,7 @@ static ImGuiID ImGui::DockNodeUpdateTabListMenu(ImGuiDockNode* node, ImGuiTabBar SetNextWindowPos(ImVec2(node->Pos.x, node->Pos.y + GetFrameHeight()), ImGuiCond_Always, ImVec2(0.0f, 0.0f)); else SetNextWindowPos(ImVec2(node->Pos.x + node->Size.x, node->Pos.y + GetFrameHeight()), ImGuiCond_Always, ImVec2(1.0f, 0.0f)); - if (BeginPopup("#TabListMenu")) + if (BeginPopup("#WindowMenu")) { node->IsFocused = true; if (tab_bar->Tabs.Size == 1) @@ -12414,19 +12418,23 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w ImGuiID focus_tab_id = 0; node->IsFocused = is_focused; - // Collapse button changes shape and display a list - // FIXME-DOCK: Could we recycle popups id? - if (IsPopupOpen("#TabListMenu")) + const ImGuiDockNodeFlags node_flags = node->GetMergedFlags(); + const bool has_window_menu_button = (node_flags & ImGuiDockNodeFlags_NoWindowMenuButton) == 0; + const bool has_close_button = (node_flags & ImGuiDockNodeFlags_NoCloseButton) == 0; + + // In a dock node, the Collapse Button turns into the Window Menu button. + // FIXME-DOCK FIXME-OPT: Could we recycle popups id accross multiple dock nodes? + if (has_window_menu_button && IsPopupOpen("#WindowMenu")) { - if (ImGuiID tab_id = DockNodeUpdateTabListMenu(node, tab_bar)) + if (ImGuiID tab_id = DockNodeUpdateWindowMenu(node, tab_bar)) focus_tab_id = tab_bar->NextSelectedTabId = tab_id; is_focused |= node->IsFocused; } // Layout ImRect title_bar_rect, tab_bar_rect; - ImVec2 collapse_button_pos; - DockNodeCalcTabBarLayout(node, &title_bar_rect, &tab_bar_rect, &collapse_button_pos); + ImVec2 window_menu_button_pos; + DockNodeCalcTabBarLayout(node, &title_bar_rect, &tab_bar_rect, &window_menu_button_pos); // Title bar if (is_focused) @@ -12434,11 +12442,14 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w ImU32 title_bar_col = GetColorU32(host_window->Collapsed ? ImGuiCol_TitleBgCollapsed : is_focused ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg); host_window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, host_window->WindowRounding, ImDrawCornerFlags_Top); - // Collapse button - if (CollapseButton(host_window->GetID("#COLLAPSE"), collapse_button_pos, node)) - OpenPopup("#TabListMenu"); - if (IsItemActive()) - focus_tab_id = tab_bar->SelectedTabId; + // Docking/Collapse button + if (has_window_menu_button) + { + if (CollapseButton(host_window->GetID("#COLLAPSE"), window_menu_button_pos, node)) + OpenPopup("#WindowMenu"); + if (IsItemActive()) + focus_tab_id = tab_bar->SelectedTabId; + } // Submit new tabs and apply NavWindow focus back to the tab bar. They will be added as Unsorted and sorted below based on relative DockOrder value. const int tabs_count_old = tab_bar->Tabs.Size; @@ -12515,7 +12526,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w // Close button (after VisibleWindow was updated) // Note that VisibleWindow may have been overrided by CTRL+Tabbing, so VisibleWindow->ID may be != from tab_bar->SelectedTabId - if (node->VisibleWindow) + if (has_close_button && node->VisibleWindow) { if (!node->VisibleWindow->HasCloseButton) { @@ -12628,27 +12639,32 @@ static bool ImGui::DockNodeIsDropAllowed(ImGuiWindow* host_window, ImGuiWindow* return false; } +// window menu button == collapse button when not in a dock node. // FIXME: This is similar to RenderWindowTitleBarContents, may want to share code. -static void ImGui::DockNodeCalcTabBarLayout(const ImGuiDockNode* node, ImRect* out_title_rect, ImRect* out_tab_bar_rect, ImVec2* out_collapse_button_pos) +static void ImGui::DockNodeCalcTabBarLayout(const ImGuiDockNode* node, ImRect* out_title_rect, ImRect* out_tab_bar_rect, ImVec2* out_window_menu_button_pos) { ImGuiContext& g = *GImGui; ImRect r = ImRect(node->Pos.x, node->Pos.y, node->Pos.x + node->Size.x, node->Pos.y + g.FontSize + g.Style.FramePadding.y * 2.0f); if (out_title_rect) { *out_title_rect = r; } - ImVec2 collapse_button_pos = r.Min; - r.Max.x -= g.Style.FramePadding.x + g.FontSize;// +1.0f; // In DockNodeUpdateTabBar() we currently display a disabled close button even if there is none. - if (node->HasCollapseButton && g.Style.WindowMenuButtonPosition == ImGuiDir_Left) + ImVec2 window_menu_button_pos = r.Min; + r.Min.x += g.Style.FramePadding.x; + r.Max.x -= g.Style.FramePadding.x; + if (node->HasCloseButton) { - r.Min.x += g.Style.FramePadding.x + g.FontSize; // + g.Style.ItemInnerSpacing.x; // <-- Adding ItemInnerSpacing makes the title text moves slightly when in a docking tab bar. Instead we adjusted RenderArrowDockMenu() + r.Max.x -= g.FontSize;// +1.0f; // In DockNodeUpdateTabBar() we currently display a disabled close button even if there is none. } - else if (node->HasCollapseButton && g.Style.WindowMenuButtonPosition == ImGuiDir_Right) + if (node->HasWindowMenuButton && g.Style.WindowMenuButtonPosition == ImGuiDir_Left) + { + r.Min.x += g.FontSize; // + g.Style.ItemInnerSpacing.x; // <-- Adding ItemInnerSpacing makes the title text moves slightly when in a docking tab bar. Instead we adjusted RenderArrowDockMenu() + } + else if (node->HasWindowMenuButton && g.Style.WindowMenuButtonPosition == ImGuiDir_Right) { - r.Min.x += g.Style.FramePadding.x; r.Max.x -= g.FontSize + g.Style.FramePadding.x; - collapse_button_pos = ImVec2(r.Max.x, r.Min.y); + window_menu_button_pos = ImVec2(r.Max.x, r.Min.y); } if (out_tab_bar_rect) { *out_tab_bar_rect = r; } - if (out_collapse_button_pos) { *out_collapse_button_pos = collapse_button_pos; } + if (out_window_menu_button_pos) { *out_window_menu_button_pos = window_menu_button_pos; } } void ImGui::DockNodeCalcSplitRects(ImVec2& pos_old, ImVec2& size_old, ImVec2& pos_new, ImVec2& size_new, ImGuiDir dir, ImVec2 size_new_desired) @@ -12751,7 +12767,7 @@ static void ImGui::DockNodePreviewDockCalc(ImGuiWindow* host_window, ImGuiDockNo // Build a tentative future node (reuse same structure because it is practical) data->FutureNode.HasCloseButton = (host_node ? host_node->HasCloseButton : host_window->HasCloseButton) || (root_payload->HasCloseButton); - data->FutureNode.HasCollapseButton = host_node ? true : ((host_window->Flags & ImGuiWindowFlags_NoCollapse) == 0); + data->FutureNode.HasWindowMenuButton = host_node ? true : ((host_window->Flags & ImGuiWindowFlags_NoCollapse) == 0); data->FutureNode.Pos = host_node ? ref_node_for_rect->Pos : host_window->Pos; data->FutureNode.Size = host_node ? ref_node_for_rect->Size : host_window->Size; diff --git a/imgui.h b/imgui.h index 506b8977b..ecd425a2f 100644 --- a/imgui.h +++ b/imgui.h @@ -745,7 +745,7 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_NoMove = 1 << 2, // Disable user moving the window ImGuiWindowFlags_NoScrollbar = 1 << 3, // Disable scrollbars (window can still scroll with mouse or programmatically) ImGuiWindowFlags_NoScrollWithMouse = 1 << 4, // Disable user vertically scrolling with mouse wheel. On child window, mouse wheel will be forwarded to the parent unless NoScrollbar is also set. - ImGuiWindowFlags_NoCollapse = 1 << 5, // Disable user collapsing window by double-clicking on it + ImGuiWindowFlags_NoCollapse = 1 << 5, // Disable user collapsing window by double-clicking on it. Also referred to as "window menu button" within a docking node. ImGuiWindowFlags_AlwaysAutoResize = 1 << 6, // Resize every window to its content every frame ImGuiWindowFlags_NoBackground = 1 << 7, // Disable drawing background color (WindowBg, etc.) and outside border. Similar as using SetNextWindowBgAlpha(0.0f). ImGuiWindowFlags_NoSavedSettings = 1 << 8, // Never load/save settings in .ini file @@ -886,6 +886,7 @@ enum ImGuiTabItemFlags_ // Flags for ImGui::DockSpace(), shared/inherited by child nodes. // (Some flags can be applied to individual nodes directly) +// FIXME-DOCK: Also see ImGuiDockNodeFlagsPrivate_ which may involve using the WIP and internal DockBuilder api. enum ImGuiDockNodeFlags_ { ImGuiDockNodeFlags_None = 0, diff --git a/imgui_internal.h b/imgui_internal.h index 783b3b0ff..68dc280eb 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -891,8 +891,10 @@ enum ImGuiDockNodeFlagsPrivate_ ImGuiDockNodeFlags_CentralNode = 1 << 11, // Local ImGuiDockNodeFlags_NoTabBar = 1 << 12, // Local // Tab bar is completely unavailable. No triangle in the corner to enable it back. ImGuiDockNodeFlags_HiddenTabBar = 1 << 13, // Local // Tab bar is hidden, with a triangle in the corner to show it again (NB: actual tab-bar instance may be destroyed as this is only used for single-window tab bar) + ImGuiDockNodeFlags_NoWindowMenuButton = 1 << 14, // Local // Disable window/docking menu (that one that appears instead of the collapse button) + ImGuiDockNodeFlags_NoCloseButton = 1 << 15, // Local ImGuiDockNodeFlags_SharedFlagsInheritMask_ = ~0, - ImGuiDockNodeFlags_LocalFlagsMask_ = ImGuiDockNodeFlags_NoSplit | ImGuiDockNodeFlags_NoResize | ImGuiDockNodeFlags_AutoHideTabBar | ImGuiDockNodeFlags_DockSpace | ImGuiDockNodeFlags_CentralNode | ImGuiDockNodeFlags_NoTabBar | ImGuiDockNodeFlags_HiddenTabBar, + ImGuiDockNodeFlags_LocalFlagsMask_ = ImGuiDockNodeFlags_NoSplit | ImGuiDockNodeFlags_NoResize | ImGuiDockNodeFlags_AutoHideTabBar | ImGuiDockNodeFlags_DockSpace | ImGuiDockNodeFlags_CentralNode | ImGuiDockNodeFlags_NoTabBar | ImGuiDockNodeFlags_HiddenTabBar | ImGuiDockNodeFlags_NoWindowMenuButton | ImGuiDockNodeFlags_NoCloseButton, ImGuiDockNodeFlags_LocalFlagsTransferMask_ = ImGuiDockNodeFlags_LocalFlagsMask_ & ~ImGuiDockNodeFlags_DockSpace // When splitting those flags are moved to the inheriting child, never duplicated }; @@ -936,7 +938,8 @@ struct ImGuiDockNode bool IsVisible :1; // Set to false when the node is hidden (usually disabled as it has no active window) bool IsFocused :1; bool HasCloseButton :1; - bool HasCollapseButton :1; + bool HasWindowMenuButton :1; + bool EnableCloseButton :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 host window