Docking: Fixed crash issues using DockBuilderRemoveNode() in some situations. (#3111, #3179, #3203, #4295)

If the deleted root node isn't part of a dockspace with a central node, it won't be "protected" but removed when last window gets removed.
This commit is contained in:
ocornut 2021-07-07 16:18:11 +02:00
parent 9e8e5ac363
commit cd4cc9ff0d
2 changed files with 10 additions and 3 deletions

View File

@ -144,6 +144,7 @@ Docking+Viewports Branch:
- Docking: Clicking on the right-most close button of a docking node closes all windows. (#4186) - Docking: Clicking on the right-most close button of a docking node closes all windows. (#4186)
- Docking: Fix IsWindowAppearing() and ImGuiCond_Appearing on docked windows. (#4177, #3982, #1497, #1061) - Docking: Fix IsWindowAppearing() and ImGuiCond_Appearing on docked windows. (#4177, #3982, #1497, #1061)
- Docking: Fix crash issues using DockBuilderRemoveNode() in some situations. (#3111, #3179, #3203, #4295) [@hsimyu]
- Docking: Reworked node flags saving/inheritance so that flags enforced by docked windows via the - Docking: Reworked node flags saving/inheritance so that flags enforced by docked windows via the
DockNodeFlagsOverrideSet mechanism are are not left in empty dockspace nodes once the windows gets undocked. DockNodeFlagsOverrideSet mechanism are are not left in empty dockspace nodes once the windows gets undocked.
(#4292, #3834, #3633, #3521, #3492, #3335, #2999, #2648) (#4292, #3834, #3633, #3521, #3492, #3335, #2999, #2648)

View File

@ -12617,7 +12617,8 @@ static ImGuiDockNode* ImGui::DockContextFindNodeByID(ImGuiContext* ctx, ImGuiID
ImGuiID ImGui::DockContextGenNodeID(ImGuiContext* ctx) ImGuiID ImGui::DockContextGenNodeID(ImGuiContext* ctx)
{ {
// Generate an ID for new node (the exact ID value doesn't matter as long as it is not already used) // Generate an ID for new node (the exact ID value doesn't matter as long as it is not already used)
// FIXME-OPT FIXME-DOCK: This is suboptimal, even if the node count is small enough not to be a worry. We should poke in ctx->Nodes to find a suitable ID faster. // FIXME-OPT FIXME-DOCK: This is suboptimal, even if the node count is small enough not to be a worry.0
// We should poke in ctx->Nodes to find a suitable ID faster. Even more so trivial that ctx->Nodes lookup is already sorted.
ImGuiID id = 0x0001; ImGuiID id = 0x0001;
while (DockContextFindNodeByID(ctx, id) != NULL) while (DockContextFindNodeByID(ctx, id) != NULL)
id++; id++;
@ -15125,11 +15126,11 @@ void ImGui::DockBuilderSetNodeSize(ImGuiID node_id, ImVec2 size)
ImGuiID ImGui::DockBuilderAddNode(ImGuiID id, ImGuiDockNodeFlags flags) ImGuiID ImGui::DockBuilderAddNode(ImGuiID id, ImGuiDockNodeFlags flags)
{ {
ImGuiContext* ctx = GImGui; ImGuiContext* ctx = GImGui;
ImGuiDockNode* node = NULL;
if (id != 0) if (id != 0)
DockBuilderRemoveNode(id); DockBuilderRemoveNode(id);
ImGuiDockNode* node = NULL;
if (flags & ImGuiDockNodeFlags_DockSpace) if (flags & ImGuiDockNodeFlags_DockSpace)
{ {
DockSpace(id, ImVec2(0, 0), (flags & ~ImGuiDockNodeFlags_DockSpace) | ImGuiDockNodeFlags_KeepAliveOnly); DockSpace(id, ImVec2(0, 0), (flags & ~ImGuiDockNodeFlags_DockSpace) | ImGuiDockNodeFlags_KeepAliveOnly);
@ -15152,6 +15153,10 @@ void ImGui::DockBuilderRemoveNode(ImGuiID node_id)
return; return;
DockBuilderRemoveNodeDockedWindows(node_id, true); DockBuilderRemoveNodeDockedWindows(node_id, true);
DockBuilderRemoveNodeChildNodes(node_id); DockBuilderRemoveNodeChildNodes(node_id);
// Node may have moved or deleted if e.g. any merge happened
node = DockContextFindNodeByID(ctx, node_id);
if (node == NULL)
return;
if (node->IsCentralNode() && node->ParentNode) if (node->IsCentralNode() && node->ParentNode)
node->ParentNode->SetLocalFlags(node->ParentNode->LocalFlags | ImGuiDockNodeFlags_CentralNode); node->ParentNode->SetLocalFlags(node->ParentNode->LocalFlags | ImGuiDockNodeFlags_CentralNode);
DockContextRemoveNode(ctx, node, true); DockContextRemoveNode(ctx, node, true);
@ -15334,11 +15339,12 @@ void ImGui::DockBuilderCopyNode(ImGuiID src_node_id, ImGuiID dst_node_id, ImVect
IM_ASSERT(dst_node_id != 0); IM_ASSERT(dst_node_id != 0);
IM_ASSERT(out_node_remap_pairs != NULL); IM_ASSERT(out_node_remap_pairs != NULL);
DockBuilderRemoveNode(dst_node_id);
ImGuiDockNode* src_node = DockContextFindNodeByID(ctx, src_node_id); ImGuiDockNode* src_node = DockContextFindNodeByID(ctx, src_node_id);
IM_ASSERT(src_node != NULL); IM_ASSERT(src_node != NULL);
out_node_remap_pairs->clear(); out_node_remap_pairs->clear();
DockBuilderRemoveNode(dst_node_id);
DockBuilderCopyNodeRec(src_node, dst_node_id, out_node_remap_pairs); DockBuilderCopyNodeRec(src_node, dst_node_id, out_node_remap_pairs);
IM_ASSERT((out_node_remap_pairs->Size % 2) == 0); IM_ASSERT((out_node_remap_pairs->Size % 2) == 0);