mirror of
https://github.com/Drezil/imgui.git
synced 2024-12-20 23:06:36 +00:00
Docking: work to allow programmatic control of dock nodes, various refactor + assert fix. Probably broke something (but I haven't found what yet!)
This commit is contained in:
parent
35032d41fa
commit
291bfe6841
241
imgui.cpp
241
imgui.cpp
@ -9518,6 +9518,7 @@ void ImGui::EndDragDropTarget()
|
|||||||
// Docking: ImGuiDockNode
|
// Docking: ImGuiDockNode
|
||||||
// Docking: ImGuiDockNode Tree manipulation functions
|
// Docking: ImGuiDockNode Tree manipulation functions
|
||||||
// Docking: Public Functions (Dockspace, SetWindowDock)
|
// Docking: Public Functions (Dockspace, SetWindowDock)
|
||||||
|
// Docking: Public Builder Functions
|
||||||
// Docking: Begin/End Functions (called from Begin/End)
|
// Docking: Begin/End Functions (called from Begin/End)
|
||||||
// Docking: Settings
|
// Docking: Settings
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -9553,15 +9554,16 @@ enum ImGuiDockRequestType
|
|||||||
{
|
{
|
||||||
ImGuiDockRequestType_None = 0,
|
ImGuiDockRequestType_None = 0,
|
||||||
ImGuiDockRequestType_Dock,
|
ImGuiDockRequestType_Dock,
|
||||||
ImGuiDockRequestType_Undock
|
ImGuiDockRequestType_Undock,
|
||||||
|
ImGuiDockRequestType_Split // Split is the same as Dock but without a DockPayload
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ImGuiDockRequest
|
struct ImGuiDockRequest
|
||||||
{
|
{
|
||||||
ImGuiDockRequestType Type;
|
ImGuiDockRequestType Type;
|
||||||
ImGuiWindow* DockTarget; // Destination/Target window to dock into (may be a loose window or a DockNode)
|
ImGuiWindow* DockTargetWindow; // Destination/Target Window to dock into (may be a loose window or a DockNode, might be NULL in which case DockTargetNode cannot be NULL)
|
||||||
ImGuiDockNode* DockTargetNode;
|
ImGuiDockNode* DockTargetNode; // Destination/Target Node to dock into
|
||||||
ImGuiWindow* DockPayload; // Source/Payload window to dock (may be a loose window or a DockNode)
|
ImGuiWindow* DockPayload; // Source/Payload window to dock (may be a loose window or a DockNode), [Optional]
|
||||||
ImGuiDir DockSplitDir;
|
ImGuiDir DockSplitDir;
|
||||||
float DockSplitRatio;
|
float DockSplitRatio;
|
||||||
bool DockSplitOuter;
|
bool DockSplitOuter;
|
||||||
@ -9570,7 +9572,7 @@ struct ImGuiDockRequest
|
|||||||
ImGuiDockRequest()
|
ImGuiDockRequest()
|
||||||
{
|
{
|
||||||
Type = ImGuiDockRequestType_None;
|
Type = ImGuiDockRequestType_None;
|
||||||
DockTarget = DockPayload = UndockTarget = NULL;
|
DockTargetWindow = DockPayload = UndockTarget = NULL;
|
||||||
DockTargetNode = NULL;
|
DockTargetNode = NULL;
|
||||||
DockSplitDir = ImGuiDir_None;
|
DockSplitDir = ImGuiDir_None;
|
||||||
DockSplitRatio = 0.5f;
|
DockSplitRatio = 0.5f;
|
||||||
@ -9627,8 +9629,9 @@ namespace ImGui
|
|||||||
// ImGuiDockContext
|
// ImGuiDockContext
|
||||||
static ImGuiDockNode* DockContextFindNodeByID(ImGuiContext* ctx, ImGuiID id);
|
static ImGuiDockNode* DockContextFindNodeByID(ImGuiContext* ctx, ImGuiID id);
|
||||||
static ImGuiDockNode* DockContextAddNode(ImGuiContext* ctx, ImGuiID id);
|
static ImGuiDockNode* DockContextAddNode(ImGuiContext* ctx, ImGuiID id);
|
||||||
static void DockContextRemoveNode(ImGuiContext* ctx, ImGuiDockNode* node);
|
static void DockContextRemoveNode(ImGuiContext* ctx, ImGuiDockNode* node, bool merge_sibling_into_parent_node);
|
||||||
static void DockContextQueueDock(ImGuiContext* ctx, ImGuiWindow* target, ImGuiDockNode* target_node, ImGuiWindow* payload, ImGuiDir split_dir, float split_ratio, bool split_outer);
|
static void DockContextQueueDock(ImGuiContext* ctx, ImGuiWindow* target, ImGuiDockNode* target_node, ImGuiWindow* payload, ImGuiDir split_dir, float split_ratio, bool split_outer);
|
||||||
|
static void DockContextQueueNotifyRemovedNode(ImGuiContext* ctx, ImGuiDockNode* node);
|
||||||
static void DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req);
|
static void DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req);
|
||||||
static void DockContextProcessUndock(ImGuiContext* ctx, ImGuiWindow* window);
|
static void DockContextProcessUndock(ImGuiContext* ctx, ImGuiWindow* window);
|
||||||
static void DockContextGcUnusedSettingsNodes(ImGuiContext* ctx);
|
static void DockContextGcUnusedSettingsNodes(ImGuiContext* ctx);
|
||||||
@ -9654,7 +9657,7 @@ namespace ImGui
|
|||||||
static void DockNodeCalcSplitRects(ImVec2& pos_old, ImVec2& size_old, ImVec2& pos_new, ImVec2& size_new, ImGuiDir dir, ImVec2 size_new_desired);
|
static void DockNodeCalcSplitRects(ImVec2& pos_old, ImVec2& size_old, ImVec2& pos_new, ImVec2& size_new, ImGuiDir dir, ImVec2 size_new_desired);
|
||||||
static bool DockNodeCalcDropRects(const ImRect& parent, ImGuiDir dir, ImRect& out_draw, bool outer_docking);
|
static bool DockNodeCalcDropRects(const ImRect& parent, ImGuiDir dir, ImRect& out_draw, bool outer_docking);
|
||||||
static ImGuiDockNode* DockNodeGetRootNode(ImGuiDockNode* node) { while (node->ParentNode) node = node->ParentNode; return node; }
|
static ImGuiDockNode* DockNodeGetRootNode(ImGuiDockNode* node) { while (node->ParentNode) node = node->ParentNode; return node; }
|
||||||
static int DockNodeGetDepth(ImGuiDockNode* node) { int depth = 0; while (node->ParentNode) { node = node->ParentNode; depth++; } return depth; }
|
static int DockNodeGetDepth(const ImGuiDockNode* node) { int depth = 0; while (node->ParentNode) { node = node->ParentNode; depth++; } return depth; }
|
||||||
static int DockNodeGetTabOrder(ImGuiWindow* window);
|
static int DockNodeGetTabOrder(ImGuiWindow* window);
|
||||||
|
|
||||||
// ImGuiDockNode tree manipulations
|
// ImGuiDockNode tree manipulations
|
||||||
@ -9717,6 +9720,12 @@ void ImGui::DockContextOnLoadSettings(ImGuiContext* ctx)
|
|||||||
DockContextBuildNodesFromSettings(ctx, dc->SettingsNodes.Data, dc->SettingsNodes.Size);
|
DockContextBuildNodesFromSettings(ctx, dc->SettingsNodes.Data, dc->SettingsNodes.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ImGui::DockContextClearNodes(ImGuiContext* ctx, ImGuiID root_id, bool clear_persistent_docking_references)
|
||||||
|
{
|
||||||
|
DockBuilderRemoveNodeDockedWindows(ctx, root_id, clear_persistent_docking_references);
|
||||||
|
DockBuilderRemoveNodeChildNodes(ctx, root_id);
|
||||||
|
}
|
||||||
|
|
||||||
// This function also acts as a de-facto test to make sure we can rebuild from scratch without a glitch
|
// This function also acts as a de-facto test to make sure we can rebuild from scratch without a glitch
|
||||||
void ImGui::DockContextRebuild(ImGuiContext* ctx)
|
void ImGui::DockContextRebuild(ImGuiContext* ctx)
|
||||||
{
|
{
|
||||||
@ -9807,7 +9816,7 @@ static ImGuiDockNode* ImGui::DockContextAddNode(ImGuiContext* ctx, ImGuiID id)
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ImGui::DockContextRemoveNode(ImGuiContext* ctx, ImGuiDockNode* node)
|
static void ImGui::DockContextRemoveNode(ImGuiContext* ctx, ImGuiDockNode* node, bool merge_sibling_into_parent_node)
|
||||||
{
|
{
|
||||||
ImGuiContext& g = *ctx;
|
ImGuiContext& g = *ctx;
|
||||||
ImGuiDockContext* dc = ctx->DockContext;
|
ImGuiDockContext* dc = ctx->DockContext;
|
||||||
@ -9815,12 +9824,14 @@ static void ImGui::DockContextRemoveNode(ImGuiContext* ctx, ImGuiDockNode* node)
|
|||||||
//printf("[%05d] RemoveNode 0x%04X\n", node->ID);
|
//printf("[%05d] RemoveNode 0x%04X\n", node->ID);
|
||||||
IM_ASSERT(DockContextFindNodeByID(ctx, node->ID) == node);
|
IM_ASSERT(DockContextFindNodeByID(ctx, node->ID) == node);
|
||||||
IM_ASSERT(node->ChildNodes[0] == NULL && node->ChildNodes[1] == NULL);
|
IM_ASSERT(node->ChildNodes[0] == NULL && node->ChildNodes[1] == NULL);
|
||||||
IM_ASSERT(node->Windows.Size == 1 || node->HostWindow->DockNodeAsHost == node);
|
IM_ASSERT(node->Windows.Size == 0);
|
||||||
|
|
||||||
if (node->HostWindow)
|
if (node->HostWindow)
|
||||||
node->HostWindow->DockNodeAsHost = NULL;
|
node->HostWindow->DockNodeAsHost = NULL;
|
||||||
|
|
||||||
if (ImGuiDockNode* parent_node = node->ParentNode)
|
ImGuiDockNode* parent_node = node->ParentNode;
|
||||||
|
const bool merge = (merge_sibling_into_parent_node && parent_node != NULL);
|
||||||
|
if (merge)
|
||||||
{
|
{
|
||||||
IM_ASSERT(parent_node->ChildNodes[0] == node || parent_node->ChildNodes[1] == node);
|
IM_ASSERT(parent_node->ChildNodes[0] == node || parent_node->ChildNodes[1] == node);
|
||||||
ImGuiDockNode* sibling_node = (parent_node->ChildNodes[0] == node ? parent_node->ChildNodes[1] : parent_node->ChildNodes[0]);
|
ImGuiDockNode* sibling_node = (parent_node->ChildNodes[0] == node ? parent_node->ChildNodes[1] : parent_node->ChildNodes[0]);
|
||||||
@ -9828,45 +9839,80 @@ static void ImGui::DockContextRemoveNode(ImGuiContext* ctx, ImGuiDockNode* node)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
for (int n = 0; parent_node && n < IM_ARRAYSIZE(parent_node->ChildNodes); n++)
|
||||||
|
if (parent_node->ChildNodes[n] == node)
|
||||||
|
node->ParentNode->ChildNodes[n] = NULL;
|
||||||
dc->Nodes.SetVoidPtr(node->ID, NULL);
|
dc->Nodes.SetVoidPtr(node->ID, NULL);
|
||||||
IM_DELETE(node);
|
IM_DELETE(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui::DockContextClearNodes(ImGuiContext* ctx, ImGuiID root_id, bool clear_persistent_docking_references)
|
static int IMGUI_CDECL DockNodeComparerDepthMostFirst(const void* lhs, const void* rhs)
|
||||||
|
{
|
||||||
|
const ImGuiDockNode* a = *(const ImGuiDockNode* const*)lhs;
|
||||||
|
const ImGuiDockNode* b = *(const ImGuiDockNode* const*)rhs;
|
||||||
|
return ImGui::DockNodeGetDepth(b) - ImGui::DockNodeGetDepth(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui::DockBuilderRemoveNodeChildNodes(ImGuiContext* ctx, ImGuiID root_id)
|
||||||
{
|
{
|
||||||
ImGuiContext& g = *ctx;
|
|
||||||
ImGuiDockContext* dc = ctx->DockContext;
|
ImGuiDockContext* dc = ctx->DockContext;
|
||||||
SaveIniSettingsToMemory(NULL);
|
|
||||||
|
|
||||||
// Clear references in windows
|
ImGuiDockNode* root_node = root_id ? DockContextFindNodeByID(ctx, root_id) : NULL;
|
||||||
for (int n = 0; n < g.Windows.Size; n++)
|
if (root_id && root_node == NULL)
|
||||||
{
|
return;
|
||||||
ImGuiWindow* window = g.Windows[n];
|
bool has_document_root = false;
|
||||||
bool want_removal = root_id == 0 || (window->DockNode && DockNodeGetRootNode(window->DockNode)->ID == root_id) || (window->DockNodeAsHost && window->DockNodeAsHost->ID == root_id);
|
|
||||||
if (want_removal)
|
|
||||||
{
|
|
||||||
window->DockNode = window->DockNodeAsHost = NULL;
|
|
||||||
window->DockIsActive = false;
|
|
||||||
if (clear_persistent_docking_references)
|
|
||||||
window->DockId = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear nodes
|
ImVector<ImGuiDockNode*> nodes_to_remove;
|
||||||
for (int n = 0; n < dc->Nodes.Data.Size; n++)
|
for (int n = 0; n < dc->Nodes.Data.Size; n++)
|
||||||
if (ImGuiDockNode* node = (ImGuiDockNode*)dc->Nodes.Data[n].val_p)
|
if (ImGuiDockNode* node = (ImGuiDockNode*)dc->Nodes.Data[n].val_p)
|
||||||
{
|
{
|
||||||
bool want_removal = (root_id == 0 || DockNodeGetRootNode(node)->ID == root_id);
|
bool want_removal = (root_id == 0) || (node->ID != root_id && DockNodeGetRootNode(node)->ID == root_id);
|
||||||
if (want_removal)
|
if (want_removal)
|
||||||
{
|
{
|
||||||
IM_DELETE(node);
|
if (node->IsDocumentRoot)
|
||||||
dc->Nodes.Data[n].val_p = NULL;
|
has_document_root = true;
|
||||||
|
if (root_id != 0)
|
||||||
|
DockContextQueueNotifyRemovedNode(ctx, node);
|
||||||
|
if (root_node)
|
||||||
|
DockNodeMoveWindows(root_node, node);
|
||||||
|
nodes_to_remove.push_back(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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)
|
if (root_id == 0)
|
||||||
|
{
|
||||||
dc->Nodes.Clear();
|
dc->Nodes.Clear();
|
||||||
dc->Requests.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 windows
|
||||||
|
ImGuiContext& g = *ctx;
|
||||||
|
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;
|
||||||
|
DockContextProcessUndock(ctx, window);
|
||||||
|
if (!clear_persistent_docking_references)
|
||||||
|
window->DockId = backup_dock_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ImGui::DockContextGcUnusedSettingsNodes(ImGuiContext* ctx)
|
static void ImGui::DockContextGcUnusedSettingsNodes(ImGuiContext* ctx)
|
||||||
@ -9959,7 +10005,7 @@ void ImGui::DockContextQueueDock(ImGuiContext* ctx, ImGuiWindow* target, ImGuiDo
|
|||||||
{
|
{
|
||||||
ImGuiDockRequest req;
|
ImGuiDockRequest req;
|
||||||
req.Type = ImGuiDockRequestType_Dock;
|
req.Type = ImGuiDockRequestType_Dock;
|
||||||
req.DockTarget = target;
|
req.DockTargetWindow = target;
|
||||||
req.DockTargetNode = target_node;
|
req.DockTargetNode = target_node;
|
||||||
req.DockPayload = payload;
|
req.DockPayload = payload;
|
||||||
req.DockSplitDir = split_dir;
|
req.DockSplitDir = split_dir;
|
||||||
@ -9976,26 +10022,41 @@ void ImGui::DockContextQueueUndock(ImGuiContext* ctx, ImGuiWindow* window)
|
|||||||
ctx->DockContext->Requests.push_back(req);
|
ctx->DockContext->Requests.push_back(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ImGui::DockContextQueueNotifyRemovedNode(ImGuiContext* ctx, ImGuiDockNode* node)
|
||||||
|
{
|
||||||
|
ImGuiDockContext* dc = ctx->DockContext;
|
||||||
|
for (int n = 0; n < dc->Requests.Size; n++)
|
||||||
|
if (dc->Requests[n].DockTargetNode == node)
|
||||||
|
dc->Requests[n].Type = ImGuiDockRequestType_None;
|
||||||
|
}
|
||||||
|
|
||||||
void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req)
|
void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req)
|
||||||
{
|
{
|
||||||
|
IM_ASSERT((req->Type == ImGuiDockRequestType_Dock && req->DockPayload != NULL) || (req->Type == ImGuiDockRequestType_Split && req->DockPayload == NULL));
|
||||||
|
IM_ASSERT(req->DockTargetWindow != NULL || req->DockTargetNode != NULL);
|
||||||
|
|
||||||
ImGuiContext& g = *ctx;
|
ImGuiContext& g = *ctx;
|
||||||
ImGuiWindow* payload_window = req->DockPayload;
|
ImGuiWindow* payload_window = req->DockPayload; // Optional
|
||||||
ImGuiWindow* target_window = req->DockTarget;
|
ImGuiWindow* target_window = req->DockTargetWindow;
|
||||||
ImGuiDockNode* target_node = req->DockTargetNode;
|
ImGuiDockNode* target_node = req->DockTargetNode;
|
||||||
|
|
||||||
// Decide which Tab will be selected at the end of the operation
|
// Decide which Tab will be selected at the end of the operation
|
||||||
ImGuiID next_selected_id = 0;
|
ImGuiID next_selected_id = 0;
|
||||||
ImGuiDockNode* payload_node = payload_window->DockNodeAsHost;
|
ImGuiDockNode* payload_node = NULL;
|
||||||
if (payload_node && !payload_node->IsSplitNode())
|
if (payload_window)
|
||||||
next_selected_id = payload_node->TabBar->NextSelectedTabId ? payload_node->TabBar->NextSelectedTabId : payload_node->TabBar->SelectedTabId;
|
{
|
||||||
if (payload_node == NULL)
|
payload_node = payload_window->DockNodeAsHost;
|
||||||
next_selected_id = payload_window->ID;
|
if (payload_node && !payload_node->IsSplitNode())
|
||||||
|
next_selected_id = payload_node->TabBar->NextSelectedTabId ? payload_node->TabBar->NextSelectedTabId : payload_node->TabBar->SelectedTabId;
|
||||||
|
if (payload_node == NULL)
|
||||||
|
next_selected_id = payload_window->ID;
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME-DOCK: When we are trying to dock an existing single-window node into a loose window, transfer Node ID as well
|
// FIXME-DOCK: When we are trying to dock an existing single-window node into a loose window, transfer Node ID as well
|
||||||
|
|
||||||
if (target_node)
|
if (target_node)
|
||||||
IM_ASSERT(target_node->LastFrameAlive < g.FrameCount);
|
IM_ASSERT(target_node->LastFrameAlive < g.FrameCount);
|
||||||
if (target_node && target_node == target_window->DockNodeAsHost)
|
if (target_node && target_window && target_node == target_window->DockNodeAsHost)
|
||||||
IM_ASSERT(target_node->Windows.Size > 1 || target_node->IsSplitNode() || target_node->IsDocumentRoot);
|
IM_ASSERT(target_node->Windows.Size > 1 || target_node->IsSplitNode() || target_node->IsDocumentRoot);
|
||||||
|
|
||||||
// Create new node and add existing window to it
|
// Create new node and add existing window to it
|
||||||
@ -10037,7 +10098,7 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req)
|
|||||||
|
|
||||||
if (target_node != payload_node)
|
if (target_node != payload_node)
|
||||||
{
|
{
|
||||||
// Create tab bar before we call DockNoveMoveWindows (which would attempt to move the old tab-bar, which would lead us to payload tabs wrongly appearing before target tabs!)
|
// Create tab bar before we call DockNodeMoveWindows (which would attempt to move the old tab-bar, which would lead us to payload tabs wrongly appearing before target tabs!)
|
||||||
if (target_node->Windows.Size > 0 && target_node->TabBar == NULL)
|
if (target_node->Windows.Size > 0 && target_node->TabBar == NULL)
|
||||||
{
|
{
|
||||||
target_node->TabBar = IM_NEW(ImGuiTabBar)();
|
target_node->TabBar = IM_NEW(ImGuiTabBar)();
|
||||||
@ -10072,9 +10133,9 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req)
|
|||||||
{
|
{
|
||||||
DockNodeMoveWindows(target_node, payload_node);
|
DockNodeMoveWindows(target_node, payload_node);
|
||||||
}
|
}
|
||||||
DockContextRemoveNode(ctx, payload_node);
|
DockContextRemoveNode(ctx, payload_node, true);
|
||||||
}
|
}
|
||||||
else
|
else if (payload_window)
|
||||||
{
|
{
|
||||||
// Transfer single window
|
// Transfer single window
|
||||||
target_node->VisibleWindow = payload_window;
|
target_node->VisibleWindow = payload_window;
|
||||||
@ -10089,8 +10150,7 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req)
|
|||||||
|
|
||||||
void ImGui::DockContextProcessUndock(ImGuiContext* ctx, ImGuiWindow* window)
|
void ImGui::DockContextProcessUndock(ImGuiContext* ctx, ImGuiWindow* window)
|
||||||
{
|
{
|
||||||
ImGuiContext& g = *ctx;
|
(void)ctx;
|
||||||
IM_ASSERT(window->LastFrameActive < g.FrameCount);
|
|
||||||
if (window->DockNode)
|
if (window->DockNode)
|
||||||
DockNodeRemoveWindow(window->DockNode, window, 0);
|
DockNodeRemoveWindow(window->DockNode, window, 0);
|
||||||
else
|
else
|
||||||
@ -10192,24 +10252,25 @@ static void ImGui::DockNodeRemoveWindow(ImGuiDockNode* node, ImGuiWindow* window
|
|||||||
UpdateWindowParentAndRootLinks(window, window->Flags & ~ImGuiWindowFlags_ChildWindow, NULL); // Update immediately
|
UpdateWindowParentAndRootLinks(window, window->Flags & ~ImGuiWindowFlags_ChildWindow, NULL); // Update immediately
|
||||||
MarkIniSettingsDirty();
|
MarkIniSettingsDirty();
|
||||||
|
|
||||||
if (node->Windows.Size == 1 && !node->IsDocumentRoot && window->DockId != node->ID)
|
|
||||||
{
|
|
||||||
// Automatic dock node delete themselves if they are not holding at least one tab
|
|
||||||
IM_ASSERT(node->Windows[0] == window);
|
|
||||||
DockContextRemoveNode(&g, node);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool erased = false;
|
bool erased = false;
|
||||||
for (int n = 0; n < node->Windows.Size; n++)
|
for (int n = 0; n < node->Windows.Size; n++)
|
||||||
if (node->Windows[n] == window)
|
if (node->Windows[n] == window)
|
||||||
{
|
{
|
||||||
node->Windows.erase(node->Windows.Data + n);
|
node->Windows.erase(node->Windows.Data + n);
|
||||||
|
if (node->TabBar)
|
||||||
|
TabBarRemoveTab(node->TabBar, window->ID);
|
||||||
erased = true;
|
erased = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
IM_ASSERT(erased);
|
IM_ASSERT(erased);
|
||||||
|
|
||||||
|
if (node->Windows.Size == 0 && !node->IsDocumentRoot && window->DockId != node->ID)
|
||||||
|
{
|
||||||
|
// Automatic dock node delete themselves if they are not holding at least one tab
|
||||||
|
DockContextRemoveNode(&g, node, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (node->TabBar)
|
if (node->TabBar)
|
||||||
TabBarRemoveTab(node->TabBar, window->ID);
|
TabBarRemoveTab(node->TabBar, window->ID);
|
||||||
|
|
||||||
@ -10254,7 +10315,7 @@ static void ImGui::DockNodeMoveChildNodes(ImGuiDockNode* dst_node, ImGuiDockNode
|
|||||||
static void ImGui::DockNodeMoveWindows(ImGuiDockNode* dst_node, ImGuiDockNode* src_node)
|
static void ImGui::DockNodeMoveWindows(ImGuiDockNode* dst_node, ImGuiDockNode* src_node)
|
||||||
{
|
{
|
||||||
// Insert tabs in the same orders as currently ordered (node->Windows isn't ordered)
|
// Insert tabs in the same orders as currently ordered (node->Windows isn't ordered)
|
||||||
IM_ASSERT(dst_node != src_node);
|
IM_ASSERT(src_node && dst_node && dst_node != src_node);
|
||||||
ImGuiTabBar* src_tab_bar = src_node->TabBar;
|
ImGuiTabBar* src_tab_bar = src_node->TabBar;
|
||||||
if (src_tab_bar != NULL)
|
if (src_tab_bar != NULL)
|
||||||
IM_ASSERT(src_node->Windows.Size == src_node->TabBar->Tabs.Size);
|
IM_ASSERT(src_node->Windows.Size == src_node->TabBar->Tabs.Size);
|
||||||
@ -11060,12 +11121,16 @@ void ImGui::DockNodeTreeMerge(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImG
|
|||||||
ImGuiDockNode* child_1 = parent_node->ChildNodes[1];
|
ImGuiDockNode* child_1 = parent_node->ChildNodes[1];
|
||||||
IM_ASSERT(child_0 && child_1);
|
IM_ASSERT(child_0 && child_1);
|
||||||
IM_ASSERT(merge_lead_child == child_0 || merge_lead_child == child_1);
|
IM_ASSERT(merge_lead_child == child_0 || merge_lead_child == child_1);
|
||||||
IM_ASSERT(parent_node->TabBar == NULL);
|
if (child_0->Windows.Size > 0 || child_1->Windows.Size > 0)
|
||||||
IM_ASSERT(parent_node->Windows.Size == 0);
|
{
|
||||||
|
IM_ASSERT(parent_node->TabBar == NULL);
|
||||||
|
IM_ASSERT(parent_node->Windows.Size == 0);
|
||||||
|
}
|
||||||
|
|
||||||
ImVec2 backup_last_explicit_size = parent_node->LastExplicitSize;
|
ImVec2 backup_last_explicit_size = parent_node->LastExplicitSize;
|
||||||
DockNodeMoveChildNodes(parent_node, merge_lead_child);
|
DockNodeMoveChildNodes(parent_node, merge_lead_child);
|
||||||
DockNodeMoveWindows(parent_node, merge_lead_child);
|
DockNodeMoveWindows(parent_node, child_0); // Generally only 1 of the 2 child node will have windows
|
||||||
|
DockNodeMoveWindows(parent_node, child_1);
|
||||||
DockNodeApplyPosSizeToWindows(parent_node);
|
DockNodeApplyPosSizeToWindows(parent_node);
|
||||||
parent_node->InitFromFirstWindow = false;
|
parent_node->InitFromFirstWindow = false;
|
||||||
parent_node->VisibleWindow = merge_lead_child->VisibleWindow;
|
parent_node->VisibleWindow = merge_lead_child->VisibleWindow;
|
||||||
@ -11376,6 +11441,57 @@ void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockSpaceFlags do
|
|||||||
End();
|
End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Docking: Builder Functions
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Very early end-user API to manipulate dock nodes.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void ImGui::DockBuilderDockWindow(ImGuiContext*, const char* window_name, ImGuiID node_id)
|
||||||
|
{
|
||||||
|
ImGuiID window_id = ImHash(window_name, 0);
|
||||||
|
if (ImGuiWindow* window = FindWindowByID(window_id))
|
||||||
|
SetWindowDock(window, node_id, ImGuiCond_Always);
|
||||||
|
else if (ImGuiWindowSettings* settings = FindWindowSettings(window_id))
|
||||||
|
settings->DockId = node_id;
|
||||||
|
else if (ImGuiWindowSettings* settings = CreateNewWindowSettings(window_name))
|
||||||
|
settings->DockId = node_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)
|
||||||
|
{
|
||||||
|
IM_ASSERT(split_dir != ImGuiDir_None);
|
||||||
|
|
||||||
|
ImGuiDockNode* node = DockContextFindNodeByID(ctx, id);
|
||||||
|
if (node == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
IM_ASSERT(!node->IsSplitNode()); // Already Split
|
||||||
|
|
||||||
|
ImGuiDockRequest req;
|
||||||
|
req.Type = ImGuiDockRequestType_Split;
|
||||||
|
req.DockTargetWindow = NULL;
|
||||||
|
req.DockTargetNode = node;
|
||||||
|
req.DockPayload = NULL;
|
||||||
|
req.DockSplitDir = split_dir;
|
||||||
|
req.DockSplitRatio = ImSaturate((split_dir == ImGuiDir_Left || split_dir == ImGuiDir_Up) ? size_ratio_for_node_at_dir : 1.0f - size_ratio_for_node_at_dir);
|
||||||
|
req.DockSplitOuter = false;
|
||||||
|
DockContextProcessDock(ctx, &req);
|
||||||
|
|
||||||
|
ImGuiID id_at_dir = node->ChildNodes[(split_dir == ImGuiDir_Left || split_dir == ImGuiDir_Up) ? 0 : 1]->ID;
|
||||||
|
ImGuiID id_other = node->ChildNodes[(split_dir == ImGuiDir_Left || split_dir == ImGuiDir_Up) ? 1 : 0]->ID;
|
||||||
|
if (out_id_at_dir)
|
||||||
|
*out_id_at_dir = id_at_dir;
|
||||||
|
if (out_id_other)
|
||||||
|
*out_id_other = id_other;
|
||||||
|
return id_at_dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui::DockBuilderFinish(ImGuiContext* ctx, ImGuiID root_id)
|
||||||
|
{
|
||||||
|
DockContextBuildAddWindowsToNodes(ctx, root_id);
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Docking: Begin/End Functions (called from Begin/End)
|
// Docking: Begin/End Functions (called from Begin/End)
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -11654,7 +11770,7 @@ static void DockSettingsHandler_DockNodeToSettings(ImGuiDockContext* dc, ImGuiDo
|
|||||||
node_settings.ID = node->ID;
|
node_settings.ID = node->ID;
|
||||||
node_settings.ParentID = node->ParentNode ? node->ParentNode->ID : 0;
|
node_settings.ParentID = node->ParentNode ? node->ParentNode->ID : 0;
|
||||||
node_settings.SelectedTabID = node->SelectedTabID;
|
node_settings.SelectedTabID = node->SelectedTabID;
|
||||||
node_settings.SplitAxis = (char)node->SplitAxis;
|
node_settings.SplitAxis = node->IsSplitNode() ? (char)node->SplitAxis : ImGuiAxis_None;
|
||||||
node_settings.Depth = (char)depth;
|
node_settings.Depth = (char)depth;
|
||||||
node_settings.IsExplicitRoot = (char)node->IsExplicitRoot;
|
node_settings.IsExplicitRoot = (char)node->IsExplicitRoot;
|
||||||
node_settings.IsDocumentRoot = (char)node->IsDocumentRoot;
|
node_settings.IsDocumentRoot = (char)node->IsDocumentRoot;
|
||||||
@ -11917,7 +12033,7 @@ void ImGui::MarkIniSettingsDirty(ImGuiWindow* window)
|
|||||||
g.SettingsDirtyTimer = g.IO.IniSavingRate;
|
g.SettingsDirtyTimer = g.IO.IniSavingRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ImGuiWindowSettings* CreateNewWindowSettings(const char* name)
|
ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name)
|
||||||
{
|
{
|
||||||
ImGuiContext& g = *GImGui;
|
ImGuiContext& g = *GImGui;
|
||||||
g.SettingsWindows.push_back(ImGuiWindowSettings());
|
g.SettingsWindows.push_back(ImGuiWindowSettings());
|
||||||
@ -12056,7 +12172,7 @@ static void* SettingsHandlerWindow_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*
|
|||||||
{
|
{
|
||||||
ImGuiWindowSettings* settings = ImGui::FindWindowSettings(ImHash(name, 0));
|
ImGuiWindowSettings* settings = ImGui::FindWindowSettings(ImHash(name, 0));
|
||||||
if (!settings)
|
if (!settings)
|
||||||
settings = CreateNewWindowSettings(name);
|
settings = ImGui::CreateNewWindowSettings(name);
|
||||||
return (void*)settings;
|
return (void*)settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -12091,7 +12207,7 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext* imgui_ctx, ImGuiSetting
|
|||||||
ImGuiWindowSettings* settings = (window->SettingsIdx != -1) ? &g.SettingsWindows[window->SettingsIdx] : ImGui::FindWindowSettings(window->ID);
|
ImGuiWindowSettings* settings = (window->SettingsIdx != -1) ? &g.SettingsWindows[window->SettingsIdx] : ImGui::FindWindowSettings(window->ID);
|
||||||
if (!settings)
|
if (!settings)
|
||||||
{
|
{
|
||||||
settings = CreateNewWindowSettings(window->Name);
|
settings = ImGui::CreateNewWindowSettings(window->Name);
|
||||||
window->SettingsIdx = g.SettingsWindows.index_from_pointer(settings);
|
window->SettingsIdx = g.SettingsWindows.index_from_pointer(settings);
|
||||||
}
|
}
|
||||||
IM_ASSERT(settings->ID == window->ID);
|
IM_ASSERT(settings->ID == window->ID);
|
||||||
@ -12121,7 +12237,8 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext* imgui_ctx, ImGuiSetting
|
|||||||
}
|
}
|
||||||
if (settings->Pos.x != 0.0f || settings->Pos.y != 0.0f || settings->ViewportId == ImGui::IMGUI_VIEWPORT_DEFAULT_ID)
|
if (settings->Pos.x != 0.0f || settings->Pos.y != 0.0f || settings->ViewportId == ImGui::IMGUI_VIEWPORT_DEFAULT_ID)
|
||||||
buf->appendf("Pos=%d,%d\n", (int)settings->Pos.x, (int)settings->Pos.y);
|
buf->appendf("Pos=%d,%d\n", (int)settings->Pos.x, (int)settings->Pos.y);
|
||||||
buf->appendf("Size=%d,%d\n", (int)settings->Size.x, (int)settings->Size.y);
|
if (settings->Size.x != 0.0f || settings->Size.y != 0.0f)
|
||||||
|
buf->appendf("Size=%d,%d\n", (int)settings->Size.x, (int)settings->Size.y);
|
||||||
buf->appendf("Collapsed=%d\n", settings->Collapsed);
|
buf->appendf("Collapsed=%d\n", settings->Collapsed);
|
||||||
if (settings->DockId != 0)
|
if (settings->DockId != 0)
|
||||||
{
|
{
|
||||||
|
@ -3821,7 +3821,7 @@ struct ExampleAppDocuments
|
|||||||
|
|
||||||
ExampleAppDocuments()
|
ExampleAppDocuments()
|
||||||
{
|
{
|
||||||
Documents.push_back(MyDocument("Radish", true, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)));
|
Documents.push_back(MyDocument("Lettuce", true, ImVec4(0.4f, 0.8f, 0.4f, 1.0f)));
|
||||||
Documents.push_back(MyDocument("Eggplant", true, ImVec4(0.8f, 0.5f, 1.0f, 1.0f)));
|
Documents.push_back(MyDocument("Eggplant", true, ImVec4(0.8f, 0.5f, 1.0f, 1.0f)));
|
||||||
Documents.push_back(MyDocument("Carrot", true, ImVec4(1.0f, 0.8f, 0.5f, 1.0f)));
|
Documents.push_back(MyDocument("Carrot", true, ImVec4(1.0f, 0.8f, 0.5f, 1.0f)));
|
||||||
Documents.push_back(MyDocument("Tomato", false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f)));
|
Documents.push_back(MyDocument("Tomato", false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f)));
|
||||||
|
@ -1474,6 +1474,12 @@ namespace ImGui
|
|||||||
IMGUI_API void SetWindowDock(ImGuiWindow* window, ImGuiID dock_id, ImGuiCond cond);
|
IMGUI_API void SetWindowDock(ImGuiWindow* window, ImGuiID dock_id, ImGuiCond cond);
|
||||||
IMGUI_API void ShowDockingDebug();
|
IMGUI_API void ShowDockingDebug();
|
||||||
|
|
||||||
|
IMGUI_API void DockBuilderRemoveNodeDockedWindows(ImGuiContext* ctx, ImGuiID root_id, bool clear_persistent_docking_references = true);
|
||||||
|
IMGUI_API void DockBuilderRemoveNodeChildNodes(ImGuiContext* ctx, ImGuiID root_id);
|
||||||
|
IMGUI_API void DockBuilderDockWindow(ImGuiContext* ctx, const char* window_name, ImGuiID node_id);
|
||||||
|
IMGUI_API ImGuiID DockBuilderSplitNode(ImGuiContext* ctx, ImGuiID 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 root_id);
|
||||||
|
|
||||||
// Drag and Drop
|
// Drag and Drop
|
||||||
IMGUI_API bool BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id);
|
IMGUI_API bool BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id);
|
||||||
IMGUI_API void ClearDragDrop();
|
IMGUI_API void ClearDragDrop();
|
||||||
|
Loading…
Reference in New Issue
Block a user