From bb2aa5e77062e7e16c59741aab9c48eed1b6722f Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 17 Jul 2019 13:55:00 -0700 Subject: [PATCH] Docking: Making it possible to undock a node by clicking on the tab bar / title bar for the node. (#2645, #2109) --- imgui.cpp | 45 ++++++++++++++++++++++++++++++++++++++------- imgui_internal.h | 1 + imgui_widgets.cpp | 27 ++------------------------- 3 files changed, 41 insertions(+), 32 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 7ec5d599..ce7e3cc7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3403,6 +3403,32 @@ void ImGui::StartMouseMovingWindow(ImGuiWindow* window) g.MovingWindow = window; } +void ImGui::StartMouseDragFromTitleBar(ImGuiWindow* window, ImGuiDockNode* node, bool from_collapse_button) +{ + ImGuiContext& g = *GImGui; + bool can_extract_dock_node = false; + if (node != NULL && node->VisibleWindow && (node->VisibleWindow->Flags & ImGuiWindowFlags_NoMove) == 0) + { + ImGuiDockNode* root_node = DockNodeGetRootNode(node); + if (root_node->OnlyNodeWithWindows != node || (root_node->CentralNode != NULL)) + if (from_collapse_button || root_node->IsDockSpace()) + can_extract_dock_node = true; + } + + const bool clicked = IsMouseClicked(0); + const bool dragging = IsMouseDragging(0, g.IO.MouseDragThreshold * 1.70f); + if (can_extract_dock_node && dragging) + { + DockContextQueueUndockNode(&g, node); + g.ActiveIdClickOffset = g.IO.MouseClickedPos[0] - node->Pos; + } + else if (!can_extract_dock_node && (clicked || dragging) && g.MovingWindow != window) + { + StartMouseMovingWindow(window); + g.ActiveIdClickOffset = g.IO.MouseClickedPos[0] - window->RootWindow->Pos; + } +} + // Handle mouse moving window // Note: moving window with the navigation keys (Square + d-pad / CTRL+TAB + Arrows) are processed in NavUpdateWindowing() void ImGui::UpdateMouseMovingWindowNewFrame() @@ -12802,15 +12828,20 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w } // When clicking on the title bar outside of tabs, we still focus the selected tab for that node - if (g.HoveredWindow == host_window && g.HoveredId == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max)) + // FIXME: TabItem use AllowItemOverlap so we manually perform a more specific test for now (hovered || held) + ImGuiID title_bar_id = host_window->GetID("#TITLEBAR"); + if (g.HoveredId == 0 || g.HoveredId == title_bar_id || g.ActiveId == title_bar_id) { - if (IsMouseClicked(0)) + bool held; + ButtonBehavior(title_bar_rect, title_bar_id, NULL, &held); + if (held) { - focus_tab_id = tab_bar->SelectedTabId; + if (IsMouseClicked(0)) + focus_tab_id = tab_bar->SelectedTabId; // Forward moving request to selected window - if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, focus_tab_id)) - StartMouseMovingWindow(tab->Window); + if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_bar->SelectedTabId)) + StartMouseDragFromTitleBar(tab->Window, node, false); } } @@ -13418,7 +13449,7 @@ void ImGui::DockNodeTreeUpdateSplitter(ImGuiDockNode* node) /* // [DEBUG] Render limits - ImDrawList* draw_list = node->HostWindow ? GetOverlayDrawList(node->HostWindow) : GetOverlayDrawList((ImGuiViewportP*)GetMainViewport()); + ImDrawList* draw_list = node->HostWindow ? GetForegroundDrawList(node->HostWindow) : GetForegroundDrawList((ImGuiViewportP*)GetMainViewport()); for (int n = 0; n < 2; n++) if (axis == ImGuiAxis_X) draw_list->AddLine(ImVec2(resize_limits[n], node->ChildNodes[n]->Pos.y), ImVec2(resize_limits[n], node->ChildNodes[n]->Pos.y + node->ChildNodes[n]->Size.y), IM_COL32(255, 0, 255, 255), 3.0f); @@ -13446,7 +13477,7 @@ void ImGui::DockNodeTreeUpdateSplitter(ImGuiDockNode* node) for (int touching_node_n = 0; touching_node_n < touching_nodes[side_n].Size; touching_node_n++) { ImGuiDockNode* touching_node = touching_nodes[side_n][touching_node_n]; - //ImDrawList* draw_list = node->HostWindow ? GetOverlayDrawList(node->HostWindow) : GetOverlayDrawList((ImGuiViewportP*)GetMainViewport()); + //ImDrawList* draw_list = node->HostWindow ? GetForegroundDrawList(node->HostWindow) : GetForegroundDrawList((ImGuiViewportP*)GetMainViewport()); //draw_list->AddRect(touching_node->Pos, touching_node->Pos + touching_node->Size, IM_COL32(255, 128, 0, 255)); while (touching_node->ParentNode != node) { diff --git a/imgui_internal.h b/imgui_internal.h index e9907a96..6392ecf2 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1661,6 +1661,7 @@ namespace ImGui // NewFrame IMGUI_API void UpdateHoveredWindowAndCaptureFlags(); IMGUI_API void StartMouseMovingWindow(ImGuiWindow* window); + IMGUI_API void StartMouseDragFromTitleBar(ImGuiWindow* window, ImGuiDockNode* node, bool from_collapse_button); IMGUI_API void UpdateMouseMovingWindowNewFrame(); IMGUI_API void UpdateMouseMovingWindowEndFrame(); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 4de236d5..076b3e80 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -776,30 +776,7 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos, ImGuiDockNode* dock_no // Switch to moving the window after mouse is moved beyond the initial drag threshold if (IsItemActive() && IsMouseDragging(0)) - { - bool can_extract_dock_node = false; - if (dock_node != NULL && dock_node->VisibleWindow && !(dock_node->VisibleWindow->Flags & ImGuiWindowFlags_NoMove)) - { - ImGuiDockNode* root_node = DockNodeGetRootNode(dock_node); - if (root_node->OnlyNodeWithWindows != dock_node || (root_node->CentralNode != NULL)) - can_extract_dock_node = true; - } - if (can_extract_dock_node) - { - float threshold_base = g.FontSize; - float threshold_x = (threshold_base * 2.2f); - float threshold_y = (threshold_base * 1.5f); - IM_ASSERT(window->DockNodeAsHost != NULL); - if (g.IO.MouseDragMaxDistanceAbs[0].x > threshold_x || g.IO.MouseDragMaxDistanceAbs[0].y > threshold_y) - DockContextQueueUndockNode(&g, dock_node); - } - else - { - ImVec2 backup_active_click_offset = g.ActiveIdClickOffset + (pos - window->Pos); - StartMouseMovingWindow(window); - g.ActiveIdClickOffset = backup_active_click_offset; - } - } + StartMouseDragFromTitleBar(window, dock_node, true); return pressed; } @@ -7048,7 +7025,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, //float threshold_base = g.IO.ConfigDockingWithShift ? g.FontSize * 0.5f : g.FontSize; float threshold_x = (threshold_base * 2.2f); float threshold_y = (threshold_base * 1.5f) + ImClamp((ImFabs(g.IO.MouseDragMaxDistanceAbs[0].x) - threshold_base * 2.0f) * 0.20f, 0.0f, threshold_base * 4.0f); - //GetOverlayDrawList(window)->AddRect(ImVec2(bb.Min.x - threshold_x, bb.Min.y - threshold_y), ImVec2(bb.Max.x + threshold_x, bb.Max.y + threshold_y), IM_COL32_WHITE); // [DEBUG] + //GetForegroundDrawList()->AddRect(ImVec2(bb.Min.x - threshold_x, bb.Min.y - threshold_y), ImVec2(bb.Max.x + threshold_x, bb.Max.y + threshold_y), IM_COL32_WHITE); // [DEBUG] float distance_from_edge_y = ImMax(bb.Min.y - g.IO.MousePos.y, g.IO.MousePos.y - bb.Max.y); if (distance_from_edge_y >= threshold_y)