Fixed _ChildWindows from leaking docking hierarchy. Added ImGuiFocusedFlags_DockHierarchy and ImGuiHoveredFlags_DockHierarchy.

This commit is contained in:
ocornut 2021-09-08 16:49:35 +02:00
parent cfb837203c
commit 6b1e094cfb
5 changed files with 32 additions and 12 deletions

View File

@ -108,6 +108,10 @@ Breaking Changes:
- Removed GetWindowContentRegionWidth() function. keep inline redirection helper. - Removed GetWindowContentRegionWidth() function. keep inline redirection helper.
Can use 'GetWindowContentRegionMax().x - GetWindowContentRegionMin().x' instead but it's not Can use 'GetWindowContentRegionMax().x - GetWindowContentRegionMin().x' instead but it's not
very useful in practice, and the only use of it in the demo was illfit. very useful in practice, and the only use of it in the demo was illfit.
- (Docking branch) IsWindowFocused() and IsWindowHovered() with only the _ChildWindows flag
and without the _RootWindow flag used to leak docking hierarchy, so a docked window would
return as the child of the window hosting the dockspace. This was inconsistent and incorrect
with other behaviors so we fixed it. Added a new _DockHierarchy flag to opt-in this behavior.
Other Changes: Other Changes:
@ -137,6 +141,10 @@ Other Changes:
Docking+Viewports Branch: Docking+Viewports Branch:
- IsWindowFocused: Fixed using ImGuiFocusedFlags_ChildWindows (without _RootWindow) from leaking the
docking hierarchy. Added ImGuiFocusedFlags_DockHierarchy flag to consider docking hierarchy in the test.
- IsWindowHovered: Fixed using ImGuiHoveredFlags_ChildWindows (without _RootWindow) from leaking the
docking hierarchy. Added ImGuiHoveredFlags_DockHierarchy flag to consider docking hierarchy in the test.
- Docking: fixed settings load issue when mouse wheeling. (#4310) - Docking: fixed settings load issue when mouse wheeling. (#4310)
- Drag and Drop: Fixed using BeginDragDropSource() or BeginDragDropTarget() inside a Begin() that - Drag and Drop: Fixed using BeginDragDropSource() or BeginDragDropTarget() inside a Begin() that
returned false because the window is docked. (#4515) returned false because the window is docked. (#4515)

View File

@ -4024,7 +4024,7 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags()
// Modal windows prevents mouse from hovering behind them. // Modal windows prevents mouse from hovering behind them.
ImGuiWindow* modal_window = GetTopMostPopupModal(); ImGuiWindow* modal_window = GetTopMostPopupModal();
if (modal_window && g.HoveredWindow && !IsWindowChildOf(g.HoveredWindow->RootWindowDockTree, modal_window)) if (modal_window && g.HoveredWindow && !IsWindowChildOf(g.HoveredWindow->RootWindowDockTree, modal_window, true))
clear_hovered_windows = true; clear_hovered_windows = true;
// Disabled mouse? // Disabled mouse?
@ -7254,15 +7254,16 @@ void ImGui::PopTextWrapPos()
window->DC.TextWrapPosStack.pop_back(); window->DC.TextWrapPosStack.pop_back();
} }
// FIXME: We are exposing the docking hierarchy to end-user here (via IsWindowHovered, IsWindowFocused) which is unusual. bool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent, bool dock_hierarchy)
bool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent)
{ {
if (window->RootWindowDockTree == potential_parent) if ((dock_hierarchy ? window->RootWindowDockTree : window->RootWindow) == potential_parent)
return true; return true;
while (window != NULL) while (window != NULL)
{ {
if (window == potential_parent) if (window == potential_parent)
return true; return true;
if (window == (dock_hierarchy ? window->RootWindowDockTree : window->RootWindow))
return false;
window = window->ParentWindow; window = window->ParentWindow;
} }
return false; return false;
@ -7294,13 +7295,14 @@ bool ImGui::IsWindowHovered(ImGuiHoveredFlags flags)
if ((flags & ImGuiHoveredFlags_AnyWindow) == 0) if ((flags & ImGuiHoveredFlags_AnyWindow) == 0)
{ {
IM_ASSERT(cur_window); // Not inside a Begin()/End() IM_ASSERT(cur_window); // Not inside a Begin()/End()
const bool dock_hierarchy = (flags & ImGuiHoveredFlags_DockHierarchy) != 0;
if (flags & ImGuiHoveredFlags_RootWindow) if (flags & ImGuiHoveredFlags_RootWindow)
cur_window = cur_window->RootWindow; cur_window = dock_hierarchy ? cur_window->RootWindowDockTree : cur_window->RootWindow;
bool result; bool result;
if (flags & ImGuiHoveredFlags_ChildWindows) if (flags & ImGuiHoveredFlags_ChildWindows)
result = IsWindowChildOf(ref_window, cur_window); result = IsWindowChildOf(ref_window, cur_window, dock_hierarchy);
else else
result = (ref_window == cur_window); result = (ref_window == cur_window);
if (!result) if (!result)
@ -7325,13 +7327,15 @@ bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags)
return false; return false;
if (flags & ImGuiFocusedFlags_AnyWindow) if (flags & ImGuiFocusedFlags_AnyWindow)
return true; return true;
IM_ASSERT(cur_window); // Not inside a Begin()/End() IM_ASSERT(cur_window); // Not inside a Begin()/End()
const bool dock_hierarchy = (flags & ImGuiHoveredFlags_DockHierarchy) != 0;
if (flags & ImGuiHoveredFlags_RootWindow) if (flags & ImGuiHoveredFlags_RootWindow)
cur_window = cur_window->RootWindow; cur_window = dock_hierarchy ? cur_window->RootWindowDockTree : cur_window->RootWindow;
if (flags & ImGuiHoveredFlags_ChildWindows) if (flags & ImGuiHoveredFlags_ChildWindows)
return IsWindowChildOf(ref_window, cur_window); return IsWindowChildOf(ref_window, cur_window, dock_hierarchy);
else else
return (ref_window == cur_window); return (ref_window == cur_window);
} }

View File

@ -1312,7 +1312,7 @@ enum ImGuiFocusedFlags_
ImGuiFocusedFlags_ChildWindows = 1 << 0, // Return true if any children of the window is focused ImGuiFocusedFlags_ChildWindows = 1 << 0, // Return true if any children of the window is focused
ImGuiFocusedFlags_RootWindow = 1 << 1, // Test from root window (top most parent of the current hierarchy) ImGuiFocusedFlags_RootWindow = 1 << 1, // Test from root window (top most parent of the current hierarchy)
ImGuiFocusedFlags_AnyWindow = 1 << 2, // Return true if any window is focused. Important: If you are trying to tell how to dispatch your low-level inputs, do NOT use this. Use 'io.WantCaptureMouse' instead! Please read the FAQ! ImGuiFocusedFlags_AnyWindow = 1 << 2, // Return true if any window is focused. Important: If you are trying to tell how to dispatch your low-level inputs, do NOT use this. Use 'io.WantCaptureMouse' instead! Please read the FAQ!
//ImGuiFocusedFlags_DockHierarchy = 1 << 3, // Consider docking hierarchy (treat dockspace host as parent of docked window) ImGuiFocusedFlags_DockHierarchy = 1 << 3, // Consider docking hierarchy (treat dockspace host as parent of docked window)
ImGuiFocusedFlags_RootAndChildWindows = ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows ImGuiFocusedFlags_RootAndChildWindows = ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows
}; };
@ -1325,7 +1325,7 @@ enum ImGuiHoveredFlags_
ImGuiHoveredFlags_ChildWindows = 1 << 0, // IsWindowHovered() only: Return true if any children of the window is hovered ImGuiHoveredFlags_ChildWindows = 1 << 0, // IsWindowHovered() only: Return true if any children of the window is hovered
ImGuiHoveredFlags_RootWindow = 1 << 1, // IsWindowHovered() only: Test from root window (top most parent of the current hierarchy) ImGuiHoveredFlags_RootWindow = 1 << 1, // IsWindowHovered() only: Test from root window (top most parent of the current hierarchy)
ImGuiHoveredFlags_AnyWindow = 1 << 2, // IsWindowHovered() only: Return true if any window is hovered ImGuiHoveredFlags_AnyWindow = 1 << 2, // IsWindowHovered() only: Return true if any window is hovered
//ImGuiHoveredFlags_DockHierarchy = 1 << 3, // IsWindowHovered() only: Consider docking hierarchy (treat dockspace host as parent of docked window) ImGuiHoveredFlags_DockHierarchy = 1 << 3, // IsWindowHovered() only: Consider docking hierarchy (treat dockspace host as parent of docked window)
ImGuiHoveredFlags_AllowWhenBlockedByPopup = 1 << 4, // Return true even if a popup window is normally blocking access to this item/window ImGuiHoveredFlags_AllowWhenBlockedByPopup = 1 << 4, // Return true even if a popup window is normally blocking access to this item/window
//ImGuiHoveredFlags_AllowWhenBlockedByModal = 1 << 4, // Return true even if a modal popup window is normally blocking access to this item/window. FIXME-TODO: Unavailable yet. //ImGuiHoveredFlags_AllowWhenBlockedByModal = 1 << 4, // Return true even if a modal popup window is normally blocking access to this item/window. FIXME-TODO: Unavailable yet.
ImGuiHoveredFlags_AllowWhenBlockedByActiveItem = 1 << 5, // Return true even if an active item is blocking access to this item/window. Useful for Drag and Drop patterns. ImGuiHoveredFlags_AllowWhenBlockedByActiveItem = 1 << 5, // Return true even if an active item is blocking access to this item/window. Useful for Drag and Drop patterns.
@ -1346,7 +1346,7 @@ enum ImGuiDockNodeFlags_
ImGuiDockNodeFlags_NoDockingInCentralNode = 1 << 2, // Shared // Disable docking inside the Central Node, which will be always kept empty. ImGuiDockNodeFlags_NoDockingInCentralNode = 1 << 2, // Shared // Disable docking inside the Central Node, which will be always kept empty.
ImGuiDockNodeFlags_PassthruCentralNode = 1 << 3, // Shared // 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_PassthruCentralNode = 1 << 3, // Shared // 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_NoSplit = 1 << 4, // Shared/Local // 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_NoSplit = 1 << 4, // Shared/Local // 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 << 5, // Shared/Local // Disable resizing node using the splitter/separators. Useful with programatically setup dockspaces. ImGuiDockNodeFlags_NoResize = 1 << 5, // Shared/Local // Disable resizing node using the splitter/separators. Useful with programmatically setup dockspaces.
ImGuiDockNodeFlags_AutoHideTabBar = 1 << 6 // Shared/Local // Tab bar will automatically hide when there is a single window in the dock node. ImGuiDockNodeFlags_AutoHideTabBar = 1 << 6 // Shared/Local // Tab bar will automatically hide when there is a single window in the dock node.
}; };

View File

@ -2334,11 +2334,15 @@ static void ShowDemoWindowWidgets()
"IsWindowFocused() = %d\n" "IsWindowFocused() = %d\n"
"IsWindowFocused(_ChildWindows) = %d\n" "IsWindowFocused(_ChildWindows) = %d\n"
"IsWindowFocused(_ChildWindows|_RootWindow) = %d\n" "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n"
"IsWindowFocused(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n"
"IsWindowFocused(_RootWindow|_DockHierarchy) = %d\n"
"IsWindowFocused(_RootWindow) = %d\n" "IsWindowFocused(_RootWindow) = %d\n"
"IsWindowFocused(_AnyWindow) = %d\n", "IsWindowFocused(_AnyWindow) = %d\n",
ImGui::IsWindowFocused(), ImGui::IsWindowFocused(),
ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows), ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows),
ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow), ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow),
ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_DockHierarchy),
ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_DockHierarchy),
ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow), ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow),
ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow)); ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow));
@ -2350,6 +2354,8 @@ static void ShowDemoWindowWidgets()
"IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n" "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n"
"IsWindowHovered(_ChildWindows) = %d\n" "IsWindowHovered(_ChildWindows) = %d\n"
"IsWindowHovered(_ChildWindows|_RootWindow) = %d\n" "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n"
"IsWindowHovered(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n"
"IsWindowHovered(_RootWindow|_DockHierarchy) = %d\n"
"IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n" "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n"
"IsWindowHovered(_RootWindow) = %d\n" "IsWindowHovered(_RootWindow) = %d\n"
"IsWindowHovered(_AnyWindow) = %d\n", "IsWindowHovered(_AnyWindow) = %d\n",
@ -2358,6 +2364,8 @@ static void ShowDemoWindowWidgets()
ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows), ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows),
ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow), ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow),
ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_DockHierarchy),
ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_DockHierarchy),
ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup), ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup),
ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow), ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow),
ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)); ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow));

View File

@ -2557,7 +2557,7 @@ namespace ImGui
IMGUI_API ImGuiWindow* FindWindowByName(const char* name); IMGUI_API ImGuiWindow* FindWindowByName(const char* name);
IMGUI_API void UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window); IMGUI_API void UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window);
IMGUI_API ImVec2 CalcWindowNextAutoFitSize(ImGuiWindow* window); IMGUI_API ImVec2 CalcWindowNextAutoFitSize(ImGuiWindow* window);
IMGUI_API bool IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent); IMGUI_API bool IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent, bool dock_hierarchy);
IMGUI_API bool IsWindowAbove(ImGuiWindow* potential_above, ImGuiWindow* potential_below); IMGUI_API bool IsWindowAbove(ImGuiWindow* potential_above, ImGuiWindow* potential_below);
IMGUI_API bool IsWindowNavFocusable(ImGuiWindow* window); IMGUI_API bool IsWindowNavFocusable(ImGuiWindow* window);
IMGUI_API void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond = 0); IMGUI_API void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond = 0);