@@ -4528,6 +4528,8 @@ static void AddWindowToDrawData(ImGuiWindow* window, int layer)
4528
4528
ImGuiContext& g = *GImGui;
4529
4529
ImGuiViewportP* viewport = window->Viewport;
4530
4530
g.IO.MetricsRenderWindows++;
4531
+ if (window->Flags & ImGuiWindowFlags_DockNodeHost)
4532
+ window->DrawList->ChannelsMerge();
4531
4533
AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[layer], window->DrawList);
4532
4534
for (int i = 0; i < window->DC.ChildWindows.Size; i++)
4533
4535
{
@@ -4709,6 +4711,9 @@ void ImGui::EndFrame()
4709
4711
// Update navigation: CTRL+Tab, wrap-around requests
4710
4712
NavEndFrame();
4711
4713
4714
+ // Update docking
4715
+ DockContextEndFrame(&g);
4716
+
4712
4717
SetCurrentViewport(NULL, NULL);
4713
4718
4714
4719
// Drag and Drop: Elapse payload (if delivered, or if source stops being submitted)
@@ -5653,11 +5658,11 @@ ImVec2 ImGui::CalcWindowNextAutoFitSize(ImGuiWindow* window)
5653
5658
return size_final;
5654
5659
}
5655
5660
5656
- static ImGuiCol GetWindowBgColorIdxFromFlags(ImGuiWindowFlags flags )
5661
+ static ImGuiCol GetWindowBgColorIdx(ImGuiWindow* window )
5657
5662
{
5658
- if (flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup))
5663
+ if (window->Flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup))
5659
5664
return ImGuiCol_PopupBg;
5660
- if (flags & ImGuiWindowFlags_ChildWindow)
5665
+ if ((window->Flags & ImGuiWindowFlags_ChildWindow) && !window->DockIsActive )
5661
5666
return ImGuiCol_ChildBg;
5662
5667
return ImGuiCol_WindowBg;
5663
5668
}
@@ -5950,7 +5955,7 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar
5950
5955
if (g.DragDropPayload.IsDataType(IMGUI_PAYLOAD_TYPE_WINDOW) && *(ImGuiWindow**)g.DragDropPayload.Data == window)
5951
5956
is_docking_transparent_payload = true;
5952
5957
5953
- ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags ));
5958
+ ImU32 bg_col = GetColorU32(GetWindowBgColorIdx(window ));
5954
5959
if (window->ViewportOwned)
5955
5960
{
5956
5961
// No alpha
@@ -5976,8 +5981,21 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar
5976
5981
if (override_alpha)
5977
5982
bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(alpha) << IM_COL32_A_SHIFT);
5978
5983
}
5979
- window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? 0 : ImDrawFlags_RoundCornersBottom);
5984
+
5985
+ // Render, for docked windows and host windows we ensure bg goes before decorations
5986
+ ImDrawList* bg_draw_list = window->DockIsActive ? window->DockNode->HostWindow->DrawList : window->DrawList;
5987
+ if (window->DockIsActive || (flags & ImGuiWindowFlags_DockNodeHost))
5988
+ bg_draw_list->ChannelsSetCurrent(0);
5989
+ if (window->DockIsActive)
5990
+ window->DockNode->LastBgColor = bg_col;
5991
+
5992
+ bg_draw_list->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? 0 : ImDrawFlags_RoundCornersBottom);
5993
+
5994
+ if (window->DockIsActive || (flags & ImGuiWindowFlags_DockNodeHost))
5995
+ bg_draw_list->ChannelsSetCurrent(1);
5980
5996
}
5997
+ if (window->DockIsActive)
5998
+ window->DockNode->IsBgDrawnThisFrame = true;
5981
5999
5982
6000
// Title bar
5983
6001
// (when docked, DockNode are drawing their own title bar. Individual windows however do NOT set the _NoTitleBar flag,
@@ -6346,6 +6364,11 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
6346
6364
window->IDStack.resize(1);
6347
6365
window->DrawList->_ResetForNewFrame();
6348
6366
window->DC.CurrentTableIdx = -1;
6367
+ if (flags & ImGuiWindowFlags_DockNodeHost)
6368
+ {
6369
+ window->DrawList->ChannelsSplit(2);
6370
+ window->DrawList->ChannelsSetCurrent(1); // Render decorations on channel 1 as we will render the backgrounds manually later
6371
+ }
6349
6372
6350
6373
// Restore buffer capacity when woken from a compacted state, to avoid
6351
6374
if (window->MemoryCompacted)
@@ -12786,6 +12809,9 @@ void ImGui::DestroyPlatformWindows()
12786
12809
// | BeginDockableDragDropTarget()
12787
12810
// | - DockNodePreviewDockRender()
12788
12811
//-----------------------------------------------------------------------------
12812
+ // - EndFrame()
12813
+ // | DockContextEndFrame()
12814
+ //-----------------------------------------------------------------------------
12789
12815
12790
12816
//-----------------------------------------------------------------------------
12791
12817
// Docking: Internal Types
@@ -12940,6 +12966,7 @@ namespace ImGui
12940
12966
// - DockContextRebuildNodes()
12941
12967
// - DockContextNewFrameUpdateUndocking()
12942
12968
// - DockContextNewFrameUpdateDocking()
12969
+ // - DockContextEndFrame()
12943
12970
// - DockContextFindNodeByID()
12944
12971
// - DockContextBindNodeToWindow()
12945
12972
// - DockContextGenNodeID()
@@ -13075,6 +13102,22 @@ void ImGui::DockContextNewFrameUpdateDocking(ImGuiContext* ctx)
13075
13102
DockNodeUpdate(node);
13076
13103
}
13077
13104
13105
+ void ImGui::DockContextEndFrame(ImGuiContext* ctx)
13106
+ {
13107
+ // Draw backgrounds of node missing their window
13108
+ ImGuiContext& g = *ctx;
13109
+ ImGuiDockContext* dc = &g.DockContext;
13110
+ for (int n = 0; n < dc->Nodes.Data.Size; n++)
13111
+ if (ImGuiDockNode* node = (ImGuiDockNode*)dc->Nodes.Data[n].val_p)
13112
+ if (node->LastFrameActive == g.FrameCount && node->IsVisible && node->HostWindow && node->IsLeafNode() && !node->IsBgDrawnThisFrame)
13113
+ {
13114
+ ImRect bg_rect(node->Pos + ImVec2(0.0f, GetFrameHeight()), node->Pos + node->Size);
13115
+ ImDrawFlags bg_rounding_flags = CalcRoundingFlagsForRectInRect(bg_rect, node->HostWindow->Rect(), DOCKING_SPLITTER_SIZE);
13116
+ node->HostWindow->DrawList->ChannelsSetCurrent(0);
13117
+ node->HostWindow->DrawList->AddRectFilled(bg_rect.Min, bg_rect.Max, node->LastBgColor, node->HostWindow->WindowRounding, bg_rounding_flags);
13118
+ }
13119
+ }
13120
+
13078
13121
static ImGuiDockNode* ImGui::DockContextFindNodeByID(ImGuiContext* ctx, ImGuiID id)
13079
13122
{
13080
13123
return (ImGuiDockNode*)ctx->DockContext.Nodes.GetVoidPtr(id);
@@ -13592,6 +13635,7 @@ ImGuiDockNode::ImGuiDockNode(ImGuiID id)
13592
13635
SplitAxis = ImGuiAxis_None;
13593
13636
13594
13637
State = ImGuiDockNodeState_Unknown;
13638
+ LastBgColor = IM_COL32_WHITE;
13595
13639
HostWindow = VisibleWindow = NULL;
13596
13640
CentralNode = OnlyNodeWithWindows = NULL;
13597
13641
CountNodeWithWindows = 0;
@@ -13603,6 +13647,7 @@ ImGuiDockNode::ImGuiDockNode(ImGuiID id)
13603
13647
AuthorityForViewport = ImGuiDataAuthority_Auto;
13604
13648
IsVisible = true;
13605
13649
IsFocused = HasCloseButton = HasWindowMenuButton = HasCentralNodeChild = false;
13650
+ IsBgDrawnThisFrame = false;
13606
13651
WantCloseAll = WantLockSizeOnce = WantMouseMove = WantHiddenTabBarUpdate = WantHiddenTabBarToggle = false;
13607
13652
}
13608
13653
@@ -14044,6 +14089,7 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node)
14044
14089
ImGuiContext& g = *GImGui;
14045
14090
IM_ASSERT(node->LastFrameActive != g.FrameCount);
14046
14091
node->LastFrameAlive = g.FrameCount;
14092
+ node->IsBgDrawnThisFrame = false;
14047
14093
14048
14094
node->CentralNode = node->OnlyNodeWithWindows = NULL;
14049
14095
if (node->IsRootNode())
@@ -14186,6 +14232,7 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node)
14186
14232
window_flags |= ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoCollapse;
14187
14233
window_flags |= ImGuiWindowFlags_NoTitleBar;
14188
14234
14235
+ SetNextWindowBgAlpha(0.0f); // Don't set ImGuiWindowFlags_NoBackground because it disables borders
14189
14236
PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
14190
14237
Begin(window_label, NULL, window_flags);
14191
14238
PopStyleVar();
@@ -14224,15 +14271,6 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node)
14224
14271
if (g.NavWindow && g.NavWindow->RootWindow->DockNode && g.NavWindow->RootWindow->ParentWindow == host_window)
14225
14272
node->LastFocusedNodeId = g.NavWindow->RootWindow->DockNode->ID;
14226
14273
14227
- // We need to draw a background at the root level if requested by ImGuiDockNodeFlags_PassthruCentralNode, but we will only know the correct pos/size
14228
- // _after_ processing the resizing splitters. So we are using the DrawList channel splitting facility to submit drawing primitives out of order!
14229
- const bool render_dockspace_bg = node->IsRootNode() && host_window && (node_flags & ImGuiDockNodeFlags_PassthruCentralNode) != 0;
14230
- if (render_dockspace_bg)
14231
- {
14232
- host_window->DrawList->ChannelsSplit(2);
14233
- host_window->DrawList->ChannelsSetCurrent(1);
14234
- }
14235
-
14236
14274
// Register a hit-test hole in the window unless we are currently dragging a window that is compatible with our dockspace
14237
14275
ImGuiDockNode* central_node = node->CentralNode;
14238
14276
const bool central_node_hole = node->IsRootNode() && host_window && (node_flags & ImGuiDockNodeFlags_PassthruCentralNode) != 0 && central_node != NULL && central_node->IsEmpty();
@@ -14265,26 +14303,37 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node)
14265
14303
// Update position/size, process and draw resizing splitters
14266
14304
if (node->IsRootNode() && host_window)
14267
14305
{
14306
+ host_window->DrawList->ChannelsSetCurrent(1);
14268
14307
DockNodeTreeUpdatePosSize(node, host_window->Pos, host_window->Size);
14269
14308
DockNodeTreeUpdateSplitter(node);
14270
14309
}
14271
14310
14272
14311
// Draw empty node background (currently can only be the Central Node)
14273
- if (host_window && node->IsEmpty() && node->IsVisible && !(node_flags & ImGuiDockNodeFlags_PassthruCentralNode))
14274
- host_window->DrawList->AddRectFilled(node->Pos, node->Pos + node->Size, GetColorU32(ImGuiCol_DockingEmptyBg));
14312
+ if (host_window && node->IsEmpty() && node->IsVisible)
14313
+ {
14314
+ host_window->DrawList->ChannelsSetCurrent(0);
14315
+ node->LastBgColor = (node_flags & ImGuiDockNodeFlags_PassthruCentralNode) ? 0 : GetColorU32(ImGuiCol_DockingEmptyBg);
14316
+ if (node->LastBgColor != 0)
14317
+ host_window->DrawList->AddRectFilled(node->Pos, node->Pos + node->Size, node->LastBgColor);
14318
+ node->IsBgDrawnThisFrame = true;
14319
+ }
14275
14320
14276
14321
// Draw whole dockspace background if ImGuiDockNodeFlags_PassthruCentralNode if set.
14322
+ // We need to draw a background at the root level if requested by ImGuiDockNodeFlags_PassthruCentralNode, but we will only know the correct pos/size
14323
+ // _after_ processing the resizing splitters. So we are using the DrawList channel splitting facility to submit drawing primitives out of order!
14324
+ const bool render_dockspace_bg = node->IsRootNode() && host_window && (node_flags & ImGuiDockNodeFlags_PassthruCentralNode) != 0;
14277
14325
if (render_dockspace_bg && node->IsVisible)
14278
14326
{
14279
14327
host_window->DrawList->ChannelsSetCurrent(0);
14280
14328
if (central_node_hole)
14281
14329
RenderRectFilledWithHole(host_window->DrawList, node->Rect(), central_node->Rect(), GetColorU32(ImGuiCol_WindowBg), 0.0f);
14282
14330
else
14283
14331
host_window->DrawList->AddRectFilled(node->Pos, node->Pos + node->Size, GetColorU32(ImGuiCol_WindowBg), 0.0f);
14284
- host_window->DrawList->ChannelsMerge();
14285
14332
}
14286
14333
14287
14334
// Draw and populate Tab Bar
14335
+ if (host_window)
14336
+ host_window->DrawList->ChannelsSetCurrent(1);
14288
14337
if (host_window && node->Windows.Size > 0)
14289
14338
{
14290
14339
DockNodeUpdateTabBar(node, host_window);
@@ -14319,7 +14368,13 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node)
14319
14368
14320
14369
// Render outer borders last (after the tab bar)
14321
14370
if (node->IsRootNode())
14371
+ {
14372
+ host_window->DrawList->ChannelsSetCurrent(1);
14322
14373
RenderWindowOuterBorders(host_window);
14374
+ }
14375
+
14376
+ // Further rendering (= hosted windows background) will be drawn on layer 0
14377
+ host_window->DrawList->ChannelsSetCurrent(0);
14323
14378
}
14324
14379
14325
14380
// End host window
@@ -15330,7 +15385,8 @@ void ImGui::DockNodeTreeUpdateSplitter(ImGuiDockNode* node)
15330
15385
float cur_size_1 = child_1->Size[axis];
15331
15386
float min_size_0 = resize_limits[0] - child_0->Pos[axis];
15332
15387
float min_size_1 = child_1->Pos[axis] + child_1->Size[axis] - resize_limits[1];
15333
- if (SplitterBehavior(bb, GetID("##Splitter"), axis, &cur_size_0, &cur_size_1, min_size_0, min_size_1, WINDOWS_HOVER_PADDING, WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER))
15388
+ ImU32 bg_col = GetColorU32(ImGuiCol_WindowBg);
15389
+ if (SplitterBehavior(bb, GetID("##Splitter"), axis, &cur_size_0, &cur_size_1, min_size_0, min_size_1, WINDOWS_HOVER_PADDING, WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER, bg_col))
15334
15390
{
15335
15391
if (touching_nodes[0].Size > 0 && touching_nodes[1].Size > 0)
15336
15392
{
@@ -16061,7 +16117,9 @@ static ImGuiDockNode* ImGui::DockContextBindNodeToWindow(ImGuiContext* ctx, ImGu
16061
16117
}
16062
16118
16063
16119
// Add window to node
16120
+ bool node_was_visible = node->IsVisible;
16064
16121
DockNodeAddWindow(node, window, true);
16122
+ node->IsVisible = node_was_visible; // Don't mark visible right away (so DockContextEndFrame() doesn't render it, maybe other side effects? will see)
16065
16123
IM_ASSERT(node == window->DockNode);
16066
16124
return node;
16067
16125
}
0 commit comments