From 30f0900b1c5c840b817f73d0dadd1511e21f224c Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 25 Aug 2020 19:03:08 +0200 Subject: [PATCH] Docking: Fix honoring payload filter with overlapping nodes. (we incorrectly over-relied on g.HoveredDockNode when making change for #3398) Essentially undo part of 85a661d (#3398) + ref cf31254 (#3420) --- imgui.cpp | 28 ++++++++++++++++++---------- imgui_internal.h | 2 +- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 110b73d2..15749d3a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -14890,18 +14890,26 @@ void ImGui::BeginDockableDragDropTarget(ImGuiWindow* window) if (AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_WINDOW, ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect)) { // Select target node - // (we should not assume that g.HoveredDockNode is != NULL when window is a host dock node: it depends on padding/spacing handled by DockNodeTreeFindVisibleNodeByPos) - ImGuiDockNode* node = g.HoveredDockNode; - const bool allow_null_target_node = window->DockNode == NULL && window->DockNodeAsHost == NULL; + // (Important: we cannot use g.HoveredDockNode here! Because each of our target node have filters based on payload, each candidate drop target will do its own evaluation) + bool dock_into_floating_window = false; + ImGuiDockNode* node = NULL; + if (window->DockNodeAsHost) + { + // Cannot assume that node will != NULL even though we passed the rectangle test: it depends on padding/spacing handled by DockNodeTreeFindVisibleNodeByPos(). + node = DockNodeTreeFindVisibleNodeByPos(window->DockNodeAsHost, g.IO.MousePos); - // There is an edge case when docking into a dockspace which only has inactive nodes (because none of the windows are active) - // In this case we need to fallback into any leaf mode, possibly the central node. - if (window->DockNodeAsHost && node && node->IsDockSpace() && node->IsRootNode()) + // There is an edge case when docking into a dockspace which only has _inactive_ nodes (because none of the windows are active) + // In this case we need to fallback into any leaf mode, possibly the central node. + // FIXME-20181220: We should not have to test for IsLeafNode() here but we have another bug to fix first. + if (node && node->IsDockSpace() && node->IsRootNode()) + node = (node->CentralNode && node->IsLeafNode()) ? node->CentralNode : DockNodeTreeFindFallbackLeafNode(node); + } + else { - if (node->CentralNode && node->IsLeafNode()) // FIXME-20181220: We should not have to test for IsLeafNode() here but we have another bug to fix first. - node = node->CentralNode; + if (window->DockNode) + node = window->DockNode; else - node = DockNodeTreeFindFallbackLeafNode(node); + dock_into_floating_window = true; // Dock into a regular window } const ImRect explicit_target_rect = (node && node->TabBar && !node->IsHiddenTabBar() && !node->IsNoTabBar()) ? node->TabBar->BarRect : ImRect(window->Pos, window->Pos + ImVec2(window->Size.x, GetFrameHeight())); @@ -14910,7 +14918,7 @@ void ImGui::BeginDockableDragDropTarget(ImGuiWindow* window) // Preview docking request and find out split direction/ratio //const bool do_preview = true; // Ignore testing for payload->IsPreview() which removes one frame of delay, but breaks overlapping drop targets within the same window. const bool do_preview = payload->IsPreview() || payload->IsDelivery(); - if (do_preview && (node != NULL || allow_null_target_node)) + if (do_preview && (node != NULL || dock_into_floating_window)) { ImGuiDockPreviewData split_inner; ImGuiDockPreviewData split_outer; diff --git a/imgui_internal.h b/imgui_internal.h index 0105add4..5ccf0581 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1296,7 +1296,7 @@ struct ImGuiContext ImGuiWindow* HoveredWindow; // Window the mouse is hovering. Will typically catch mouse inputs. ImGuiWindow* HoveredRootWindow; // == HoveredWindow ? HoveredWindow->RootWindow : NULL, merely a shortcut to avoid null test in some situation. ImGuiWindow* HoveredWindowUnderMovingWindow; // Hovered window ignoring MovingWindow. Only set if MovingWindow is set. - ImGuiDockNode* HoveredDockNode; + ImGuiDockNode* HoveredDockNode; // Hovered dock node. ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actual window that is moved is generally MovingWindow->RootWindow. ImGuiWindow* WheelingWindow; // Track the window we started mouse-wheeling on. Until a timer elapse or mouse has moved, generally keep scrolling the same window even if during the course of scrolling the mouse ends up hovering a child window. ImVec2 WheelingWindowRefMousePos;