Skip to content

Commit 67be485

Browse files
committed
Docking: Fixed losing tab bar selection when extracting a whole docked node + reusing existing dock node when possible.
1 parent fda57f4 commit 67be485

File tree

1 file changed

+66
-35
lines changed

1 file changed

+66
-35
lines changed

imgui.cpp

+66-35
Original file line numberDiff line numberDiff line change
@@ -9648,7 +9648,7 @@ namespace ImGui
96489648
static void DockContextBuildAddWindowsToNodes(ImGuiContext* ctx, ImGuiID root_id); // Use root_id==0 to add all
96499649

96509650
// ImGuiDockNode
9651-
static void DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window);
9651+
static void DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window, bool add_to_tab_bar);
96529652
static void DockNodeMoveWindows(ImGuiDockNode* dst_node, ImGuiDockNode* src_node);
96539653
static void DockNodeMoveChildNodes(ImGuiDockNode* dst_node, ImGuiDockNode* src_node);
96549654
static void DockNodeApplyPosSizeToWindows(ImGuiDockNode* node);
@@ -10012,7 +10012,7 @@ void ImGui::DockContextBuildAddWindowsToNodes(ImGuiContext* ctx, ImGuiID root_id
1001210012
ImGuiDockNode* dock_node = DockContextFindNodeByID(ctx, window->DockId);
1001310013
IM_ASSERT(dock_node != NULL); // This should have been called after DockContextBuildNodesFromSettings()
1001410014
if (root_id == 0 || DockNodeGetRootNode(dock_node)->ID == root_id)
10015-
DockNodeAddWindow(dock_node, window);
10015+
DockNodeAddWindow(dock_node, window, true);
1001610016
}
1001710017
}
1001810018

@@ -10095,7 +10095,7 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req)
1009510095
target_node->Size = target_window->Size;
1009610096
if (target_window->DockNodeAsHost == NULL)
1009710097
{
10098-
DockNodeAddWindow(target_node, target_window);
10098+
DockNodeAddWindow(target_node, target_window, true);
1009910099
target_window->DockIsActive = true;
1010010100
}
1010110101
}
@@ -10167,7 +10167,7 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req)
1016710167
{
1016810168
// Transfer single window
1016910169
target_node->VisibleWindow = payload_window;
10170-
DockNodeAddWindow(target_node, payload_window);
10170+
DockNodeAddWindow(target_node, payload_window, true);
1017110171
}
1017210172
}
1017310173

@@ -10196,20 +10196,26 @@ void ImGui::DockContextProcessUndockNode(ImGuiContext* ctx, ImGuiDockNode* node)
1019610196
IM_ASSERT(!node->IsSplitNode());
1019710197
IM_ASSERT(node->Windows.Size >= 1);
1019810198

10199-
ImGuiDockNode* new_node = DockContextAddNode(ctx, (ImGuiID)-1);
10200-
DockNodeMoveWindows(new_node, node);
10201-
for (int n = 0; n < new_node->Windows.Size; n++)
10202-
UpdateWindowParentAndRootLinks(new_node->Windows[n], new_node->Windows[n]->Flags, NULL);
10203-
new_node->WantMouseMove = true;
10204-
1020510199
// In the case of a root node, a node will have to stay in place. Create a new node for this purpose.
1020610200
// Otherwise delete the previous node by merging the other sibling back into the parent node.
10207-
// FIXME-DOCK: Transition persistent DockId for all non-active windows
10208-
if (!node->IsRootNode())
10201+
if (node->IsRootNode())
10202+
{
10203+
// FIXME-DOCK: Transition persistent DockId for all non-active windows
10204+
ImGuiDockNode* new_node = DockContextAddNode(ctx, (ImGuiID)-1);
10205+
DockNodeMoveWindows(new_node, node);
10206+
for (int n = 0; n < new_node->Windows.Size; n++)
10207+
UpdateWindowParentAndRootLinks(new_node->Windows[n], new_node->Windows[n]->Flags, NULL);
10208+
new_node->WantMouseMove = true;
10209+
}
10210+
else
1020910211
{
1021010212
IM_ASSERT(node->ParentNode->ChildNodes[0] == node || node->ParentNode->ChildNodes[1] == node);
10211-
ImGuiDockNode* lead_sibling = node->ParentNode->ChildNodes[(node->ParentNode->ChildNodes[0] == node) ? 1 : 0];
10212-
DockNodeTreeMerge(ctx, node->ParentNode, lead_sibling);
10213+
int index_in_parent = (node->ParentNode->ChildNodes[0] == node) ? 0 : 1;
10214+
node->ParentNode->ChildNodes[index_in_parent] = NULL;
10215+
DockNodeTreeMerge(ctx, node->ParentNode, node->ParentNode->ChildNodes[index_in_parent ^ 1]);
10216+
node->ParentNode = NULL;
10217+
node->InitFromFirstWindow = true;
10218+
node->WantMouseMove = true;
1021310219
}
1021410220
MarkIniSettingsDirty();
1021510221
}
@@ -10252,7 +10258,7 @@ int ImGui::DockNodeGetTabOrder(ImGuiWindow* window)
1025210258
return tab ? tab_bar->GetTabOrder(tab) : -1;
1025310259
}
1025410260

10255-
static void ImGui::DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window)
10261+
static void ImGui::DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window, bool add_to_tab_bar)
1025610262
{
1025710263
ImGuiContext& g = *GImGui; (void)g;
1025810264
if (window->DockNode)
@@ -10281,12 +10287,16 @@ static void ImGui::DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window)
1028110287
if (node->Windows.Size == 2 && !node->IsDockSpace)
1028210288
node->InitFromFirstWindow = true;
1028310289

10284-
if (node->TabBar == NULL)
10290+
// Add to tab bar if requested
10291+
if (add_to_tab_bar)
1028510292
{
10286-
node->TabBar = IM_NEW(ImGuiTabBar)();
10287-
node->TabBar->SelectedTabId = node->TabBar->NextSelectedTabId = node->SelectedTabID;
10293+
if (node->TabBar == NULL)
10294+
{
10295+
node->TabBar = IM_NEW(ImGuiTabBar)();
10296+
node->TabBar->SelectedTabId = node->TabBar->NextSelectedTabId = node->SelectedTabID;
10297+
}
10298+
TabBarAddTab(node->TabBar, window);
1028810299
}
10289-
TabBarAddTab(node->TabBar, window);
1029010300

1029110301
DockNodeUpdateVisibleFlag(node);
1029210302

@@ -10376,19 +10386,31 @@ static void ImGui::DockNodeMoveWindows(ImGuiDockNode* dst_node, ImGuiDockNode* s
1037610386
ImGuiTabBar* src_tab_bar = src_node->TabBar;
1037710387
if (src_tab_bar != NULL)
1037810388
IM_ASSERT(src_node->Windows.Size == src_node->TabBar->Tabs.Size);
10389+
10390+
// If the dst_node is empty we can just move the entire tab bar (to preserve selection, scrolling, etc.)
10391+
bool move_tab_bar = (src_tab_bar != NULL) && (dst_node->TabBar == NULL);
10392+
if (move_tab_bar)
10393+
{
10394+
dst_node->TabBar = src_node->TabBar;
10395+
src_node->TabBar = NULL;
10396+
}
10397+
1037910398
for (int n = 0; n < src_node->Windows.Size; n++)
1038010399
{
1038110400
ImGuiWindow* window = src_tab_bar ? src_tab_bar->Tabs[n].Window : src_node->Windows[n];
1038210401
window->DockNode = NULL;
1038310402
window->DockIsActive = false;
10384-
DockNodeAddWindow(dst_node, window);
10403+
DockNodeAddWindow(dst_node, window, move_tab_bar ? false : true);
1038510404
}
10386-
if (dst_node->TabBar == NULL)
10387-
dst_node->TabBar = src_node->TabBar;
10388-
else
10389-
IM_DELETE(src_node->TabBar);
10390-
src_node->TabBar = NULL;
1039110405
src_node->Windows.clear();
10406+
10407+
if (!move_tab_bar && src_node->TabBar)
10408+
{
10409+
if (dst_node->TabBar)
10410+
dst_node->TabBar->SelectedTabId = src_node->TabBar->SelectedTabId;
10411+
IM_DELETE(src_node->TabBar);
10412+
src_node->TabBar = NULL;
10413+
}
1039210414
}
1039310415

1039410416
static void ImGui::DockNodeApplyPosSizeToWindows(ImGuiDockNode* node)
@@ -11192,30 +11214,39 @@ void ImGui::DockNodeTreeSplit(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImG
1119211214

1119311215
void ImGui::DockNodeTreeMerge(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImGuiDockNode* merge_lead_child)
1119411216
{
11217+
// When called from DockContextProcessUndockNode() it is possible that one of the child is NULL.
1119511218
ImGuiDockNode* child_0 = parent_node->ChildNodes[0];
1119611219
ImGuiDockNode* child_1 = parent_node->ChildNodes[1];
11197-
IM_ASSERT(child_0 && child_1);
11220+
IM_ASSERT(child_0 || child_1);
1119811221
IM_ASSERT(merge_lead_child == child_0 || merge_lead_child == child_1);
11199-
if (child_0->Windows.Size > 0 || child_1->Windows.Size > 0)
11222+
if ((child_0 && child_0->Windows.Size > 0) || (child_1 && child_1->Windows.Size > 0))
1120011223
{
1120111224
IM_ASSERT(parent_node->TabBar == NULL);
1120211225
IM_ASSERT(parent_node->Windows.Size == 0);
1120311226
}
1120411227

1120511228
ImVec2 backup_last_explicit_size = parent_node->SizeRef;
1120611229
DockNodeMoveChildNodes(parent_node, merge_lead_child);
11207-
DockNodeMoveWindows(parent_node, child_0); // Generally only 1 of the 2 child node will have windows
11208-
DockNodeMoveWindows(parent_node, child_1);
11230+
if (child_0)
11231+
DockNodeMoveWindows(parent_node, child_0); // Generally only 1 of the 2 child node will have windows
11232+
if (child_1)
11233+
DockNodeMoveWindows(parent_node, child_1);
1120911234
DockNodeApplyPosSizeToWindows(parent_node);
1121011235
parent_node->InitFromFirstWindow = false;
1121111236
parent_node->VisibleWindow = merge_lead_child->VisibleWindow;
11212-
parent_node->IsDocumentRoot = child_0->IsDocumentRoot || child_1->IsDocumentRoot;
11237+
parent_node->IsDocumentRoot = (child_0 && child_0->IsDocumentRoot) || (child_1 && child_1->IsDocumentRoot);
1121311238
parent_node->SizeRef = backup_last_explicit_size;
1121411239

11215-
ctx->DockContext->Nodes.SetVoidPtr(child_0->ID, NULL);
11216-
ctx->DockContext->Nodes.SetVoidPtr(child_1->ID, NULL);
11217-
IM_DELETE(child_0);
11218-
IM_DELETE(child_1);
11240+
if (child_0)
11241+
{
11242+
ctx->DockContext->Nodes.SetVoidPtr(child_0->ID, NULL);
11243+
IM_DELETE(child_0);
11244+
}
11245+
if (child_1)
11246+
{
11247+
ctx->DockContext->Nodes.SetVoidPtr(child_1->ID, NULL);
11248+
IM_DELETE(child_1);
11249+
}
1121911250
}
1122011251

1122111252
// Update Pos/Size for a node hierarchy (don't affect child Windows yet)
@@ -11613,7 +11644,7 @@ void ImGui::BeginDocked(ImGuiWindow* window, bool* p_open)
1161311644
return;
1161411645
}
1161511646

11616-
DockNodeAddWindow(dock_node, window);
11647+
DockNodeAddWindow(dock_node, window, true);
1161711648
IM_ASSERT(dock_node == window->DockNode);
1161811649

1161911650
// Fix an edge case with auto-resizing windows: if they are created on the same frame they are creating their dock node,

0 commit comments

Comments
 (0)