Docking: Revised undocking logic to reduce accidental whole-node undocking:

Amend bb2aa5e77.
Revert to normal threshold in StartMouseMovingWindowOrNode().
Added tooltip when hovering the collapse/window menu button.
features/sdl_renderer3_multiviewports
ocornut ago%!(EXTRA string=2 years)
parent 4521dec85d
commit 51d1a72e9b
  1. 8
      docs/CHANGELOG.txt
  2. 26
      imgui.cpp
  3. 3
      imgui_internal.h
  4. 2
      imgui_widgets.cpp

@ -157,6 +157,14 @@ Docking+Viewports Branch:
- Viewports: Fixed window inner clipping rectangle off by one when window is located on a monitor - Viewports: Fixed window inner clipping rectangle off by one when window is located on a monitor
with negative coordinates. While it is expected that other small issues with arise from this with negative coordinates. While it is expected that other small issues with arise from this
situation, at the moment we are fixing the most noticeable one. (#6861, #2884) [@Vuhdo, @alektron] situation, at the moment we are fixing the most noticeable one. (#6861, #2884) [@Vuhdo, @alektron]
- Docking: revised undocking to reduce accidental whole-node undocking:
- cannot undock a whole node by dragging from empty space in tab-bar.
- can undock whole node by dragging from window/collapse menu button.
- can undock single window by dragging from its tab.
- can still move (but not undock) whole node or whole hierarchy when node is part of a
floating hierarchy.
- added tooltip when hovering the collapse/window menu button, to faciliate understanding
that whole dock node may be undocked or grabbed from here.
- Docking: Fixed an issue leading to incorrect restoration of selected tab in dock nodes that - Docking: Fixed an issue leading to incorrect restoration of selected tab in dock nodes that
don't carry the currently focused window. (#2304) don't carry the currently focused window. (#2304)
- Docking: added ImGuiDockNodeFlags_NoUndocking. (#2999, #6823, #6780, #3492) - Docking: added ImGuiDockNodeFlags_NoUndocking. (#2999, #6823, #6780, #3492)

@ -3657,7 +3657,8 @@ static const ImGuiLocEntry GLocalizationEntriesEnUS[] =
{ ImGuiLocKey_WindowingPopup, "(Popup)" }, { ImGuiLocKey_WindowingPopup, "(Popup)" },
{ ImGuiLocKey_WindowingUntitled, "(Untitled)" }, { ImGuiLocKey_WindowingUntitled, "(Untitled)" },
{ ImGuiLocKey_DockingHideTabBar, "Hide tab bar###HideTabBar" }, { ImGuiLocKey_DockingHideTabBar, "Hide tab bar###HideTabBar" },
{ ImGuiLocKey_DockingHoldShiftToDock, "Hold SHIFT to enable Docking window."}, { ImGuiLocKey_DockingHoldShiftToDock, "Hold SHIFT to enable Docking window." },
{ ImGuiLocKey_DockingDragToUndockOrMoveNode,"Click and drag to move or undock whole node." },
}; };
void ImGui::Initialize() void ImGui::Initialize()
@ -4489,26 +4490,23 @@ void ImGui::StartMouseMovingWindow(ImGuiWindow* window)
g.MovingWindow = window; g.MovingWindow = window;
} }
// We use 'undock_floating_node == false' when dragging from title bar to allow moving groups of floating nodes without undocking them. // We use 'undock == false' when dragging from title bar to allow moving groups of floating nodes without undocking them.
// - undock_floating_node == true: when dragging from a floating node within a hierarchy, always undock the node. void ImGui::StartMouseMovingWindowOrNode(ImGuiWindow* window, ImGuiDockNode* node, bool undock)
// - undock_floating_node == false: when dragging from a floating node within a hierarchy, move root window.
void ImGui::StartMouseMovingWindowOrNode(ImGuiWindow* window, ImGuiDockNode* node, bool undock_floating_node)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
bool can_undock_node = false; bool can_undock_node = false;
if (node != NULL && node->VisibleWindow && (node->VisibleWindow->Flags & ImGuiWindowFlags_NoMove) == 0 && (node->MergedFlags & ImGuiDockNodeFlags_NoUndocking) == 0) if (undock && node != NULL && node->VisibleWindow && (node->VisibleWindow->Flags & ImGuiWindowFlags_NoMove) == 0 && (node->MergedFlags & ImGuiDockNodeFlags_NoUndocking) == 0)
{ {
// Can undock if: // Can undock if:
// - part of a floating node hierarchy with more than one visible node (if only one is visible, we'll just move the whole hierarchy) // - part of a hierarchy with more than one visible node (if only one is visible, we'll just move the root window)
// - part of a dockspace node hierarchy (trivia: undocking from a fixed/central node will create a new node and copy windows) // - part of a dockspace node hierarchy: so we can undock the last single visible node too (trivia: undocking from a fixed/central node will create a new node and copy windows)
ImGuiDockNode* root_node = DockNodeGetRootNode(node); ImGuiDockNode* root_node = DockNodeGetRootNode(node);
if (root_node->OnlyNodeWithWindows != node || root_node->CentralNode != NULL) // -V1051 PVS-Studio thinks node should be root_node and is wrong about that. if (root_node->OnlyNodeWithWindows != node || root_node->CentralNode != NULL) // -V1051 PVS-Studio thinks node should be root_node and is wrong about that.
if (undock_floating_node || root_node->IsDockSpace())
can_undock_node = true; can_undock_node = true;
} }
const bool clicked = IsMouseClicked(0); const bool clicked = IsMouseClicked(0);
const bool dragging = IsMouseDragging(0, g.IO.MouseDragThreshold * 1.70f); const bool dragging = IsMouseDragging(0);
if (can_undock_node && dragging) if (can_undock_node && dragging)
DockContextQueueUndockNode(&g, node); // Will lead to DockNodeStartMouseMovingWindow() -> StartMouseMovingWindow() being called next frame DockContextQueueUndockNode(&g, node); // Will lead to DockNodeStartMouseMovingWindow() -> StartMouseMovingWindow() being called next frame
else if (!can_undock_node && (clicked || dragging) && g.MovingWindow != window) else if (!can_undock_node && (clicked || dragging) && g.MovingWindow != window)
@ -6445,7 +6443,7 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar
if (ButtonBehavior(r, unhide_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren)) if (ButtonBehavior(r, unhide_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren))
node->WantHiddenTabBarToggle = true; node->WantHiddenTabBarToggle = true;
else if (held && IsMouseDragging(0)) else if (held && IsMouseDragging(0))
StartMouseMovingWindowOrNode(window, node, true); StartMouseMovingWindowOrNode(window, node, true); // Undock from tab-bar triangle = same as window/collapse menu button
// FIXME-DOCK: Ideally we'd use ImGuiCol_TitleBgActive/ImGuiCol_TitleBg here, but neither is guaranteed to be visible enough at this sort of size.. // FIXME-DOCK: Ideally we'd use ImGuiCol_TitleBgActive/ImGuiCol_TitleBg here, but neither is guaranteed to be visible enough at this sort of size..
ImU32 col = GetColorU32(((held && hovered) || (node->IsFocused && !hovered)) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); ImU32 col = GetColorU32(((held && hovered) || (node->IsFocused && !hovered)) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
@ -16887,6 +16885,8 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
OpenPopup("#WindowMenu"); OpenPopup("#WindowMenu");
if (IsItemActive()) if (IsItemActive())
focus_tab_id = tab_bar->SelectedTabId; focus_tab_id = tab_bar->SelectedTabId;
if (IsItemHovered(ImGuiHoveredFlags_ForTooltip | ImGuiHoveredFlags_DelayNormal) && g.HoveredIdTimer > 0.5f)
SetTooltip("%s", LocalizeGetMsg(ImGuiLocKey_DockingDragToUndockOrMoveNode));
} }
// If multiple tabs are appearing on the same frame, sort them based on their persistent DockOrder value // If multiple tabs are appearing on the same frame, sort them based on their persistent DockOrder value
@ -17015,7 +17015,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
ImGuiID title_bar_id = host_window->GetID("#TITLEBAR"); ImGuiID title_bar_id = host_window->GetID("#TITLEBAR");
if (g.HoveredId == 0 || g.HoveredId == title_bar_id || g.ActiveId == title_bar_id) if (g.HoveredId == 0 || g.HoveredId == title_bar_id || g.ActiveId == title_bar_id)
{ {
// AllowItem mode required for appending into dock node tab bar, // AllowOverlap mode required for appending into dock node tab bar,
// otherwise dragging window will steal HoveredId and amended tabs cannot get them. // otherwise dragging window will steal HoveredId and amended tabs cannot get them.
bool held; bool held;
KeepAliveID(title_bar_id); KeepAliveID(title_bar_id);
@ -17031,7 +17031,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
// Forward moving request to selected window // Forward moving request to selected window
if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_bar->SelectedTabId)) if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_bar->SelectedTabId))
StartMouseMovingWindowOrNode(tab->Window ? tab->Window : node->HostWindow, node, false); StartMouseMovingWindowOrNode(tab->Window ? tab->Window : node->HostWindow, node, false); // Undock from tab bar empty space
} }
} }

@ -1929,6 +1929,7 @@ enum ImGuiLocKey : int
ImGuiLocKey_WindowingUntitled, ImGuiLocKey_WindowingUntitled,
ImGuiLocKey_DockingHideTabBar, ImGuiLocKey_DockingHideTabBar,
ImGuiLocKey_DockingHoldShiftToDock, ImGuiLocKey_DockingHoldShiftToDock,
ImGuiLocKey_DockingDragToUndockOrMoveNode,
ImGuiLocKey_COUNT ImGuiLocKey_COUNT
}; };
@ -3162,7 +3163,7 @@ namespace ImGui
IMGUI_API void UpdateInputEvents(bool trickle_fast_inputs); IMGUI_API void UpdateInputEvents(bool trickle_fast_inputs);
IMGUI_API void UpdateHoveredWindowAndCaptureFlags(); IMGUI_API void UpdateHoveredWindowAndCaptureFlags();
IMGUI_API void StartMouseMovingWindow(ImGuiWindow* window); IMGUI_API void StartMouseMovingWindow(ImGuiWindow* window);
IMGUI_API void StartMouseMovingWindowOrNode(ImGuiWindow* window, ImGuiDockNode* node, bool undock_floating_node); IMGUI_API void StartMouseMovingWindowOrNode(ImGuiWindow* window, ImGuiDockNode* node, bool undock);
IMGUI_API void UpdateMouseMovingWindowNewFrame(); IMGUI_API void UpdateMouseMovingWindowNewFrame();
IMGUI_API void UpdateMouseMovingWindowEndFrame(); IMGUI_API void UpdateMouseMovingWindowEndFrame();

@ -862,7 +862,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 // Switch to moving the window after mouse is moved beyond the initial drag threshold
if (IsItemActive() && IsMouseDragging(0)) if (IsItemActive() && IsMouseDragging(0))
StartMouseMovingWindowOrNode(window, dock_node, true); StartMouseMovingWindowOrNode(window, dock_node, true); // Undock from window/collapse menu button
return pressed; return pressed;
} }

Loading…
Cancel
Save