Docking: Added DockBuilderRemoveNode() + various tweaks. Fixed dragging/undocking dock node from CollapseButton.

This commit is contained in:
omar 2018-09-24 23:16:19 +02:00
parent 4021776d0f
commit 9960ccddb2
3 changed files with 122 additions and 108 deletions

213
imgui.cpp
View File

@ -9874,94 +9874,6 @@ static int IMGUI_CDECL DockNodeComparerDepthMostFirst(const void* lhs, const voi
return ImGui::DockNodeGetDepth(b) - ImGui::DockNodeGetDepth(a); return ImGui::DockNodeGetDepth(b) - ImGui::DockNodeGetDepth(a);
} }
void ImGui::DockBuilderRemoveNodeChildNodes(ImGuiContext* ctx, ImGuiID root_id)
{
ImGuiDockContext* dc = ctx->DockContext;
ImGuiDockNode* root_node = root_id ? DockContextFindNodeByID(ctx, root_id) : NULL;
if (root_id && root_node == NULL)
return;
bool has_document_root = false;
// Process active windows
ImVector<ImGuiDockNode*> nodes_to_remove;
for (int n = 0; n < dc->Nodes.Data.Size; n++)
if (ImGuiDockNode* node = (ImGuiDockNode*)dc->Nodes.Data[n].val_p)
{
bool want_removal = (root_id == 0) || (node->ID != root_id && DockNodeGetRootNode(node)->ID == root_id);
if (want_removal)
{
if (node->IsDocumentRoot)
has_document_root = true;
if (root_id != 0)
DockContextQueueNotifyRemovedNode(ctx, node);
if (root_node)
DockNodeMoveWindows(root_node, node);
nodes_to_remove.push_back(node);
}
}
// Apply to settings
for (int settings_n = 0; settings_n < ctx->SettingsWindows.Size; settings_n++)
if (ImGuiID window_settings_dock_id = ctx->SettingsWindows[settings_n].DockId)
for (int n = 0; n < nodes_to_remove.Size; n++)
if (nodes_to_remove[n]->ID == window_settings_dock_id)
{
ctx->SettingsWindows[settings_n].DockId = root_id;
break;
}
// Not really efficient, but easier to destroy a whole hierarchy considering DockContextRemoveNode is attempting to merge nodes
if (nodes_to_remove.Size > 1)
ImQsort(nodes_to_remove.Data, nodes_to_remove.Size, sizeof(ImGuiDockNode*), DockNodeComparerDepthMostFirst);
for (int n = 0; n < nodes_to_remove.Size; n++)
DockContextRemoveNode(ctx, nodes_to_remove[n], false);
if (root_id == 0)
{
dc->Nodes.Clear();
dc->Requests.clear();
}
else if (has_document_root)
{
root_node->IsDocumentRoot = true;
}
}
void ImGui::DockBuilderRemoveNodeDockedWindows(ImGuiContext* ctx, ImGuiID root_id, bool clear_persistent_docking_references)
{
// Clear references in settings
ImGuiContext& g = *ctx;
if (clear_persistent_docking_references)
{
for (int n = 0; n < g.SettingsWindows.Size; n++)
{
ImGuiWindowSettings* settings = &g.SettingsWindows[n];
bool want_removal = (root_id == 0) || (settings->DockId == root_id);
if (!want_removal && settings->DockId != 0)
if (ImGuiDockNode* node = DockContextFindNodeByID(ctx, settings->DockId))
if (DockNodeGetRootNode(node)->ID == root_id)
want_removal = true;
if (want_removal)
settings->DockId = 0;
}
}
// Clear references in windows
for (int n = 0; n < g.Windows.Size; n++)
{
ImGuiWindow* window = g.Windows[n];
bool want_removal = (root_id == 0) || (window->DockNode && DockNodeGetRootNode(window->DockNode)->ID == root_id) || (window->DockNodeAsHost && window->DockNodeAsHost->ID == root_id);
if (want_removal)
{
ImGuiID backup_dock_id = window->DockId;
DockContextProcessUndockWindow(ctx, window);
if (!clear_persistent_docking_references)
window->DockId = backup_dock_id;
}
}
}
static void ImGui::DockContextGcUnusedSettingsNodes(ImGuiContext* ctx) static void ImGui::DockContextGcUnusedSettingsNodes(ImGuiContext* ctx)
{ {
ImGuiContext& g = *ctx; ImGuiContext& g = *ctx;
@ -11488,22 +11400,21 @@ ImGuiDockNode* ImGui::DockNodeTreeFindNodeByPos(ImGuiDockNode* node, ImVec2 pos)
{ {
if (!node->IsVisible) if (!node->IsVisible)
return NULL; return NULL;
if (node->IsSplitNode())
{
if (ImGuiDockNode* hovered_node = DockNodeTreeFindNodeByPos(node->ChildNodes[0], pos))
return hovered_node;
if (ImGuiDockNode* hovered_node = DockNodeTreeFindNodeByPos(node->ChildNodes[1], pos))
return hovered_node;
}
else
{
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
const float dock_spacing = g.Style.ItemInnerSpacing.x; const float dock_spacing = g.Style.ItemInnerSpacing.x;
ImRect r(node->Pos, node->Pos + node->Size); ImRect r(node->Pos, node->Pos + node->Size);
r.Expand(dock_spacing * 0.5f); r.Expand(dock_spacing * 0.5f);
if (r.Contains(pos)) bool inside = r.Contains(pos);
if (!inside)
return NULL;
if (!node->IsSplitNode())
return node; return node;
} if (ImGuiDockNode* hovered_node = DockNodeTreeFindNodeByPos(node->ChildNodes[0], pos))
return hovered_node;
if (ImGuiDockNode* hovered_node = DockNodeTreeFindNodeByPos(node->ChildNodes[1], pos))
return hovered_node;
return NULL; return NULL;
} }
@ -11601,6 +11512,7 @@ void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags doc
// Docking: Builder Functions // Docking: Builder Functions
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Very early end-user API to manipulate dock nodes. // Very early end-user API to manipulate dock nodes.
// It is expected that those functions are all called _before_ the dockspace node submission.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void ImGui::DockBuilderDockWindow(ImGuiContext*, const char* window_name, ImGuiID node_id) void ImGui::DockBuilderDockWindow(ImGuiContext*, const char* window_name, ImGuiID node_id)
@ -11621,8 +11533,7 @@ void ImGui::DockBuilderDockWindow(ImGuiContext*, const char* window_name, ImGuiI
} }
} }
// Ensure a node is created void ImGui::DockBuilderAddNode(ImGuiContext* ctx, ImGuiID id, ImVec2 ref_size, ImGuiDockNodeFlags flags)
void ImGui::DockBuilderCreateNode(ImGuiContext* ctx, ImGuiID id, ImVec2 ref_size, ImGuiDockNodeFlags flags)
{ {
DockSpace(id, ImVec2(0,0), flags | ImGuiDockNodeFlags_KeepAliveOnly); DockSpace(id, ImVec2(0,0), flags | ImGuiDockNodeFlags_KeepAliveOnly);
ImGuiDockNode* node = DockContextFindNodeByID(ctx, id); ImGuiDockNode* node = DockContextFindNodeByID(ctx, id);
@ -11630,6 +11541,106 @@ void ImGui::DockBuilderCreateNode(ImGuiContext* ctx, ImGuiID id, ImVec2 ref_size
node->LastFrameAlive = -1; node->LastFrameAlive = -1;
} }
void ImGui::DockBuilderRemoveNode(ImGuiContext* ctx, ImGuiID node_id)
{
ImGuiDockNode* node = DockContextFindNodeByID(ctx, node_id);
if (node == NULL)
return;
DockBuilderRemoveNodeDockedWindows(ctx, node_id, true);
DockBuilderRemoveNodeChildNodes(ctx, node_id);
if (node->IsDocumentRoot && node->ParentNode)
node->ParentNode->IsDocumentRoot = true;
DockContextRemoveNode(ctx, node, true);
}
void ImGui::DockBuilderRemoveNodeChildNodes(ImGuiContext* ctx, ImGuiID root_id)
{
ImGuiDockContext* dc = ctx->DockContext;
ImGuiDockNode* root_node = root_id ? DockContextFindNodeByID(ctx, root_id) : NULL;
if (root_id && root_node == NULL)
return;
bool has_document_root = false;
// Process active windows
ImVector<ImGuiDockNode*> nodes_to_remove;
for (int n = 0; n < dc->Nodes.Data.Size; n++)
if (ImGuiDockNode* node = (ImGuiDockNode*)dc->Nodes.Data[n].val_p)
{
bool want_removal = (root_id == 0) || (node->ID != root_id && DockNodeGetRootNode(node)->ID == root_id);
if (want_removal)
{
if (node->IsDocumentRoot)
has_document_root = true;
if (root_id != 0)
DockContextQueueNotifyRemovedNode(ctx, node);
if (root_node)
DockNodeMoveWindows(root_node, node);
nodes_to_remove.push_back(node);
}
}
// Apply to settings
for (int settings_n = 0; settings_n < ctx->SettingsWindows.Size; settings_n++)
if (ImGuiID window_settings_dock_id = ctx->SettingsWindows[settings_n].DockId)
for (int n = 0; n < nodes_to_remove.Size; n++)
if (nodes_to_remove[n]->ID == window_settings_dock_id)
{
ctx->SettingsWindows[settings_n].DockId = root_id;
break;
}
// Not really efficient, but easier to destroy a whole hierarchy considering DockContextRemoveNode is attempting to merge nodes
if (nodes_to_remove.Size > 1)
ImQsort(nodes_to_remove.Data, nodes_to_remove.Size, sizeof(ImGuiDockNode*), DockNodeComparerDepthMostFirst);
for (int n = 0; n < nodes_to_remove.Size; n++)
DockContextRemoveNode(ctx, nodes_to_remove[n], false);
if (root_id == 0)
{
dc->Nodes.Clear();
dc->Requests.clear();
}
else if (has_document_root)
{
root_node->IsDocumentRoot = true;
}
}
void ImGui::DockBuilderRemoveNodeDockedWindows(ImGuiContext* ctx, ImGuiID root_id, bool clear_persistent_docking_references)
{
// Clear references in settings
ImGuiContext& g = *ctx;
if (clear_persistent_docking_references)
{
for (int n = 0; n < g.SettingsWindows.Size; n++)
{
ImGuiWindowSettings* settings = &g.SettingsWindows[n];
bool want_removal = (root_id == 0) || (settings->DockId == root_id);
if (!want_removal && settings->DockId != 0)
if (ImGuiDockNode* node = DockContextFindNodeByID(ctx, settings->DockId))
if (DockNodeGetRootNode(node)->ID == root_id)
want_removal = true;
if (want_removal)
settings->DockId = 0;
}
}
// Clear references in windows
for (int n = 0; n < g.Windows.Size; n++)
{
ImGuiWindow* window = g.Windows[n];
bool want_removal = (root_id == 0) || (window->DockNode && DockNodeGetRootNode(window->DockNode)->ID == root_id) || (window->DockNodeAsHost && window->DockNodeAsHost->ID == root_id);
if (want_removal)
{
ImGuiID backup_dock_id = window->DockId;
DockContextProcessUndockWindow(ctx, window);
if (!clear_persistent_docking_references)
window->DockId = backup_dock_id;
}
}
}
ImGuiID ImGui::DockBuilderSplitNode(ImGuiContext* ctx, ImGuiID id, ImGuiDir split_dir, float size_ratio_for_node_at_dir, ImGuiID* out_id_at_dir, ImGuiID* out_id_other) ImGuiID ImGui::DockBuilderSplitNode(ImGuiContext* ctx, ImGuiID id, ImGuiDir split_dir, float size_ratio_for_node_at_dir, ImGuiID* out_id_at_dir, ImGuiID* out_id_other)
{ {
IM_ASSERT(split_dir != ImGuiDir_None); IM_ASSERT(split_dir != ImGuiDir_None);

View File

@ -1481,10 +1481,11 @@ namespace ImGui
IMGUI_API void ShowDockingDebug(); IMGUI_API void ShowDockingDebug();
// Docking - Builder function needs to be generally called before the DockSpace() node is submitted. // Docking - Builder function needs to be generally called before the DockSpace() node is submitted.
IMGUI_API void DockBuilderDockWindow(ImGuiContext* ctx, const char* window_name, ImGuiID node_id);
IMGUI_API void DockBuilderAddNode(ImGuiContext* ctx, ImGuiID node_id, ImVec2 ref_size, ImGuiDockNodeFlags flags = 0);
IMGUI_API void DockBuilderRemoveNode(ImGuiContext* ctx, ImGuiID node_id);
IMGUI_API void DockBuilderRemoveNodeDockedWindows(ImGuiContext* ctx, ImGuiID node_id, bool clear_persistent_docking_references = true); IMGUI_API void DockBuilderRemoveNodeDockedWindows(ImGuiContext* ctx, ImGuiID node_id, bool clear_persistent_docking_references = true);
IMGUI_API void DockBuilderRemoveNodeChildNodes(ImGuiContext* ctx, ImGuiID node_id); // Remove all split/hierarchy. All remaining docked windows will be re-docked to the root. IMGUI_API void DockBuilderRemoveNodeChildNodes(ImGuiContext* ctx, ImGuiID node_id); // Remove all split/hierarchy. All remaining docked windows will be re-docked to the root.
IMGUI_API void DockBuilderDockWindow(ImGuiContext* ctx, const char* window_name, ImGuiID node_id);
IMGUI_API void DockBuilderCreateNode(ImGuiContext* ctx, ImGuiID node_id, ImVec2 ref_size, ImGuiDockNodeFlags flags = 0);
IMGUI_API ImGuiID DockBuilderSplitNode(ImGuiContext* ctx, ImGuiID node_id, ImGuiDir split_dir, float size_ratio_for_node_at_dir, ImGuiID* out_id_dir, ImGuiID* out_id_other); IMGUI_API ImGuiID DockBuilderSplitNode(ImGuiContext* ctx, ImGuiID node_id, ImGuiDir split_dir, float size_ratio_for_node_at_dir, ImGuiID* out_id_dir, ImGuiID* out_id_other);
IMGUI_API void DockBuilderFinish(ImGuiContext* ctx, ImGuiID node_id); IMGUI_API void DockBuilderFinish(ImGuiContext* ctx, ImGuiID node_id);

View File

@ -704,7 +704,9 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos, ImGuiDockNode* dock_no
} }
else else
{ {
ImVec2 backup_active_click_offset = g.ActiveIdClickOffset;
StartMouseMovingWindow(window); StartMouseMovingWindow(window);
g.ActiveIdClickOffset = backup_active_click_offset;
} }
} }