Docking: Better tracking of current dock id for inactive and uncreated windows (in settings etc.). + Fixed assert when docking a single-visible leaf node of a hierarchy into another

This commit is contained in:
omar 2018-10-01 11:56:26 +02:00
parent 4e717b524c
commit b48ed9ebc0
2 changed files with 57 additions and 26 deletions

View File

@ -148,6 +148,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- dock: B- reintroduce collapsing a floating dock node. also collapsing a docked dock node! - dock: B- reintroduce collapsing a floating dock node. also collapsing a docked dock node!
- dock: B- allow dragging a non-floating dock node by clicking on the title-bar-looking section (not just the collapse/menu button) - dock: B- allow dragging a non-floating dock node by clicking on the title-bar-looking section (not just the collapse/menu button)
- dock: C- nav: CTRL+TAB highlighting tabs shows the mismatch between focus-stack and tab-order (not visible in VS because it doesn't highlight the tabs) - dock: C- nav: CTRL+TAB highlighting tabs shows the mismatch between focus-stack and tab-order (not visible in VS because it doesn't highlight the tabs)
- dock: C- after a dock/undock, the Scrollbar Status update in Begin() should use an updated e.g. size_y_for_scrollbars to avoid a 1 frame scrollbar flicker.
- tabs: re-ordering, close buttons, context menu, persistent order (#261, #351) - tabs: re-ordering, close buttons, context menu, persistent order (#261, #351)

View File

@ -3819,7 +3819,8 @@ void ImGui::EndFrame()
AddWindowToSortBuffer(&g.WindowsSortBuffer, window); AddWindowToSortBuffer(&g.WindowsSortBuffer, window);
} }
IM_ASSERT(g.Windows.Size == g.WindowsSortBuffer.Size); // we done something wrong // This usually assert if there is a mismatch between the ImGuiWindowFlags_ChildWindow / ParentWindow values and DC.ChildWindows[] in parents, aka we've done something wrong.
IM_ASSERT(g.Windows.Size == g.WindowsSortBuffer.Size);
g.Windows.swap(g.WindowsSortBuffer); g.Windows.swap(g.WindowsSortBuffer);
g.IO.MetricsActiveWindows = g.WindowsActiveCount; g.IO.MetricsActiveWindows = g.WindowsActiveCount;
@ -9677,6 +9678,7 @@ namespace ImGui
static ImGuiDockNode* DockNodeTreeFindNodeByPos(ImGuiDockNode* node, ImVec2 pos); static ImGuiDockNode* DockNodeTreeFindNodeByPos(ImGuiDockNode* node, ImVec2 pos);
// Settings // Settings
static void DockSettingsMoveDockReferencesInInactiveWindow(ImGuiID old_dock_id, ImGuiID new_dock_id);
static void DockSettingsRemoveReferencesToNodes(ImGuiID* node_ids, int node_ids_count); static void DockSettingsRemoveReferencesToNodes(ImGuiID* node_ids, int node_ids_count);
static ImGuiDockNodeSettings* DockSettingsFindNodeSettings(ImGuiContext* ctx, ImGuiID node_id); static ImGuiDockNodeSettings* DockSettingsFindNodeSettings(ImGuiContext* ctx, ImGuiID node_id);
static void* DockSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name); static void* DockSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name);
@ -9951,7 +9953,7 @@ static void ImGui::DockContextBuildNodesFromSettings(ImGuiContext* ctx, ImGuiDoc
// Bind host window immediately if it already exist (in case of a rebuild) // Bind host window immediately if it already exist (in case of a rebuild)
// This is useful as the RootWindowForTitleBarHighlight links necessary to highlight the currently focused node requires node->HostWindow to be set. // This is useful as the RootWindowForTitleBarHighlight links necessary to highlight the currently focused node requires node->HostWindow to be set.
char host_window_title[32]; char host_window_title[20];
ImGuiDockNode* root_node = DockNodeGetRootNode(node); ImGuiDockNode* root_node = DockNodeGetRootNode(node);
node->HostWindow = FindWindowByName(DockNodeGetHostWindowTitle(root_node, host_window_title, IM_ARRAYSIZE(host_window_title))); node->HostWindow = FindWindowByName(DockNodeGetHostWindowTitle(root_node, host_window_title, IM_ARRAYSIZE(host_window_title)));
} }
@ -10090,25 +10092,24 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req)
TabBarAddTab(target_node->TabBar, target_node->Windows[n], ImGuiTabItemFlags_None); TabBarAddTab(target_node->TabBar, target_node->Windows[n], ImGuiTabItemFlags_None);
} }
const ImGuiID payload_node_id = payload_node ? payload_node->ID : payload_window->DockId;
if (payload_node != NULL) if (payload_node != NULL)
{ {
// Transfer full payload node (with 1+ child windows or child nodes) // Transfer full payload node (with 1+ child windows or child nodes)
// FIXME-DOCK: Transition persistent DockId for all non-active windows
if (payload_node->IsSplitNode()) if (payload_node->IsSplitNode())
{ {
if (target_node->Windows.Size > 0) if (target_node->Windows.Size > 0)
{ {
// We can dock into a node that already has windows _only_ if our payload is a node tree with a single visible node. // We can dock into a node that already has windows _only_ if our payload is a node tree with a single visible node.
// In this situation, we move the windows of the target node into the currently visible node of the payload. // In this situation, we move the windows of the target node into the currently visible node of the payload.
// This allows us to preserve some of the underlying settings nicely. // This allows us to preserve some of the underlying dock tree settings nicely.
IM_ASSERT(payload_node->OnlyNodeWithWindows != NULL); IM_ASSERT(payload_node->OnlyNodeWithWindows != NULL); // The docking should have been blocked by DockNodePreviewDockCalc() early on and never submitted.
ImGuiDockNode* visible_node = payload_node->OnlyNodeWithWindows; ImGuiDockNode* visible_node = payload_node->OnlyNodeWithWindows;
if (visible_node->TabBar) if (visible_node->TabBar)
IM_ASSERT(visible_node->TabBar->Tabs.Size > 0); IM_ASSERT(visible_node->TabBar->Tabs.Size > 0);
for (int n = 0; n < visible_node->Windows.Size; n++)
TabBarAddTab(target_node->TabBar, visible_node->Windows[n], ImGuiTabItemFlags_None);
DockNodeMoveWindows(target_node, visible_node); DockNodeMoveWindows(target_node, visible_node);
DockNodeMoveWindows(visible_node, target_node); DockNodeMoveWindows(visible_node, target_node);
DockSettingsMoveDockReferencesInInactiveWindow(target_node->ID, visible_node->ID);
} }
IM_ASSERT(target_node->Windows.Size == 0); IM_ASSERT(target_node->Windows.Size == 0);
DockNodeMoveChildNodes(target_node, payload_node); DockNodeMoveChildNodes(target_node, payload_node);
@ -10116,6 +10117,7 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req)
else else
{ {
DockNodeMoveWindows(target_node, payload_node); DockNodeMoveWindows(target_node, payload_node);
DockSettingsMoveDockReferencesInInactiveWindow(payload_node_id, target_node->ID);
} }
DockContextRemoveNode(ctx, payload_node, true); DockContextRemoveNode(ctx, payload_node, true);
} }
@ -10124,6 +10126,8 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req)
// Transfer single window // Transfer single window
target_node->VisibleWindow = payload_window; target_node->VisibleWindow = payload_window;
DockNodeAddWindow(target_node, payload_window, true); DockNodeAddWindow(target_node, payload_window, true);
if (payload_node_id != 0)
DockSettingsMoveDockReferencesInInactiveWindow(payload_node_id, target_node->ID);
} }
} }
@ -10156,9 +10160,9 @@ void ImGui::DockContextProcessUndockNode(ImGuiContext* ctx, ImGuiDockNode* node)
// Otherwise delete the previous node by merging the other sibling back into the parent node. // Otherwise delete the previous node by merging the other sibling back into the parent node.
if (node->IsRootNode() || node->IsDocumentRoot) if (node->IsRootNode() || node->IsDocumentRoot)
{ {
// FIXME-DOCK: Transition persistent DockId for all non-active windows
ImGuiDockNode* new_node = DockContextAddNode(ctx, 0); ImGuiDockNode* new_node = DockContextAddNode(ctx, 0);
DockNodeMoveWindows(new_node, node); DockNodeMoveWindows(new_node, node);
DockSettingsMoveDockReferencesInInactiveWindow(node->ID, new_node->ID);
for (int n = 0; n < new_node->Windows.Size; n++) for (int n = 0; n < new_node->Windows.Size; n++)
UpdateWindowParentAndRootLinks(new_node->Windows[n], new_node->Windows[n]->Flags, NULL); UpdateWindowParentAndRootLinks(new_node->Windows[n], new_node->Windows[n]->Flags, NULL);
new_node->WantMouseMove = true; new_node->WantMouseMove = true;
@ -10516,8 +10520,10 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node)
} }
} }
// Early out for standalone floating window that are holding on a DockId (with an invisible dock node) // Early out for hidden root dock nodes (when all DockId references are in inactive windows, or there is only 1 floating window holding on the DockId)
if (node->IsRootNode() && node->Windows.Size == 1 && !node->IsDockSpace) if (node->IsRootNode() && !node->IsSplitNode() && node->Windows.Size <= 1 && !node->IsDockSpace)
{
if (node->Windows.Size == 1)
{ {
// Floating window pos/size is authoritative // Floating window pos/size is authoritative
ImGuiWindow* single_window = node->Windows[0]; ImGuiWindow* single_window = node->Windows[0];
@ -10537,6 +10543,7 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node)
single_window->ViewportOwned = true; single_window->ViewportOwned = true;
} }
} }
}
DockNodeHideHostWindow(node); DockNodeHideHostWindow(node);
node->InitFromFirstWindowPosSize = node->InitFromFirstWindowViewport = false; node->InitFromFirstWindowPosSize = node->InitFromFirstWindowViewport = false;
@ -10545,8 +10552,8 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node)
node->HasCloseButton = node->HasCollapseButton = false; node->HasCloseButton = node->HasCollapseButton = false;
node->LastFrameActive = g.FrameCount; node->LastFrameActive = g.FrameCount;
if (node->WantMouseMove) if (node->WantMouseMove && node->Windows.Size == 1)
DockNodeStartMouseMovingWindow(node, single_window); DockNodeStartMouseMovingWindow(node, node->Windows[0]);
return; return;
} }
@ -11222,9 +11229,15 @@ void ImGui::DockNodeTreeMerge(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImG
ImVec2 backup_last_explicit_size = parent_node->SizeRef; ImVec2 backup_last_explicit_size = parent_node->SizeRef;
DockNodeMoveChildNodes(parent_node, merge_lead_child); DockNodeMoveChildNodes(parent_node, merge_lead_child);
if (child_0) if (child_0)
{
DockNodeMoveWindows(parent_node, child_0); // Generally only 1 of the 2 child node will have windows DockNodeMoveWindows(parent_node, child_0); // Generally only 1 of the 2 child node will have windows
DockSettingsMoveDockReferencesInInactiveWindow(child_0->ID, parent_node->ID);
}
if (child_1) if (child_1)
{
DockNodeMoveWindows(parent_node, child_1); DockNodeMoveWindows(parent_node, child_1);
DockSettingsMoveDockReferencesInInactiveWindow(child_1->ID, parent_node->ID);
}
DockNodeApplyPosSizeToWindows(parent_node); DockNodeApplyPosSizeToWindows(parent_node);
parent_node->InitFromFirstWindowPosSize = parent_node->InitFromFirstWindowViewport = false; parent_node->InitFromFirstWindowPosSize = parent_node->InitFromFirstWindowViewport = false;
parent_node->VisibleWindow = merge_lead_child->VisibleWindow; parent_node->VisibleWindow = merge_lead_child->VisibleWindow;
@ -12065,6 +12078,23 @@ void ImGui::BeginAsDockableDragDropTarget(ImGuiWindow* window)
// Docking: Settings // Docking: Settings
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static void ImGui::DockSettingsMoveDockReferencesInInactiveWindow(ImGuiID old_dock_id, ImGuiID new_dock_id)
{
ImGuiContext& g = *GImGui;
for (int window_n = 0; window_n < g.Windows.Size; window_n++)
{
ImGuiWindow* window = g.Windows[window_n];
if (window->DockId == old_dock_id && window->DockNode == NULL)
window->DockId = new_dock_id;
}
for (int settings_n = 0; settings_n < g.SettingsWindows.Size; settings_n++) // FIXME-OPT: We could remove this loop by storing the index in the map
{
ImGuiWindowSettings* window_settings = &g.SettingsWindows[settings_n];
if (window_settings->DockId == old_dock_id)
window_settings->DockId = new_dock_id;
}
}
// Remove references stored in ImGuiWindowSettings to the given ImGuiDockNodeSettings // Remove references stored in ImGuiWindowSettings to the given ImGuiDockNodeSettings
static void ImGui::DockSettingsRemoveReferencesToNodes(ImGuiID* node_ids, int node_ids_count) static void ImGui::DockSettingsRemoveReferencesToNodes(ImGuiID* node_ids, int node_ids_count)
{ {