Docking: Some DockBuilder functions are applied on settings data if windows are not present. Added DockBuilderCreateNode which needs a size else if we can't split properly. DockNodeTreeSplit() doesn't clamp SizeRef. (+1 squashed commits)
This commit is contained in:
parent
2a5ce1849a
commit
fa0ce4b7d5
82
imgui.cpp
82
imgui.cpp
@ -9641,7 +9641,6 @@ struct ImGuiDockContext
|
||||
namespace ImGui
|
||||
{
|
||||
// ImGuiDockContext
|
||||
static ImGuiDockNode* DockContextFindNodeByID(ImGuiContext* ctx, ImGuiID id);
|
||||
static ImGuiDockNode* DockContextAddNode(ImGuiContext* ctx, ImGuiID id);
|
||||
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);
|
||||
@ -9815,7 +9814,7 @@ void ImGui::DockContextEndFrame(ImGuiContext* ctx)
|
||||
(void)ctx;
|
||||
}
|
||||
|
||||
static ImGuiDockNode* ImGui::DockContextFindNodeByID(ImGuiContext* ctx, ImGuiID id)
|
||||
ImGuiDockNode* ImGui::DockContextFindNodeByID(ImGuiContext* ctx, ImGuiID id)
|
||||
{
|
||||
return (ImGuiDockNode*)ctx->DockContext->Nodes.GetVoidPtr(id);
|
||||
}
|
||||
@ -9884,6 +9883,7 @@ void ImGui::DockBuilderRemoveNodeChildNodes(ImGuiContext* ctx, ImGuiID root_id)
|
||||
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)
|
||||
@ -9901,6 +9901,16 @@ void ImGui::DockBuilderRemoveNodeChildNodes(ImGuiContext* ctx, ImGuiID root_id)
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
@ -9920,8 +9930,24 @@ void ImGui::DockBuilderRemoveNodeChildNodes(ImGuiContext* ctx, ImGuiID root_id)
|
||||
|
||||
void ImGui::DockBuilderRemoveNodeDockedWindows(ImGuiContext* ctx, ImGuiID root_id, bool clear_persistent_docking_references)
|
||||
{
|
||||
// Clear references in windows
|
||||
// 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];
|
||||
@ -9957,6 +9983,7 @@ static void ImGui::DockContextGcUnusedSettingsNodes(ImGuiContext* ctx)
|
||||
is_parent_map.SetInt(dc->SettingsNodes[settings_n].ParentID, 1);
|
||||
|
||||
// If a root node has only 1 reference in window settings we clear it
|
||||
// FIXME-DOCK: We should be able to merge unused nodes as well.
|
||||
for (int settings_n = 0; settings_n < dc->SettingsNodes.Size; settings_n++)
|
||||
{
|
||||
ImGuiDockNodeSettings* settings = &dc->SettingsNodes[settings_n];
|
||||
@ -10813,7 +10840,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
|
||||
// Begin tab bar
|
||||
ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_NoTabListPopupButton;// | ImGuiTabBarFlags_NoTabListScrollingButtons);
|
||||
tab_bar_flags |= ImGuiTabBarFlags_SaveSettings;
|
||||
tab_bar_flags |= ImGuiTabBarFlags_DockNode | (node->IsDockSpace ? ImGuiTabBarFlags_DockNodeExplicitRoot : 0);
|
||||
tab_bar_flags |= ImGuiTabBarFlags_DockNode | (node->IsDockSpace ? ImGuiTabBarFlags_DockNodeIsDockSpace : 0);
|
||||
if (!host_window->Collapsed && is_focused)
|
||||
tab_bar_flags |= ImGuiTabBarFlags_IsFocused;
|
||||
BeginTabBarEx(node->TabBar, tab_bar_rect, tab_bar_flags, node);
|
||||
@ -11203,7 +11230,6 @@ static void ImGui::DockNodePreviewDockRender(ImGuiWindow* host_window, ImGuiDock
|
||||
|
||||
void ImGui::DockNodeTreeSplit(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImGuiAxis split_axis, int split_inheritor_child_idx, float split_ratio, ImGuiDockNode* new_node)
|
||||
{
|
||||
ImGuiContext& g = *ctx;
|
||||
IM_ASSERT(split_axis != ImGuiAxis_None);
|
||||
|
||||
ImGuiDockNode* child_0 = (new_node && split_inheritor_child_idx != 0) ? new_node : DockContextAddNode(ctx, (ImGuiID)-1);
|
||||
@ -11221,9 +11247,10 @@ void ImGui::DockNodeTreeSplit(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImG
|
||||
parent_node->VisibleWindow = NULL;
|
||||
|
||||
float size_avail = (parent_node->Size[split_axis] - IMGUI_DOCK_SPLITTER_SIZE);
|
||||
IM_ASSERT(size_avail > 0.0f);
|
||||
child_0->SizeRef = child_1->SizeRef = parent_node->Size;
|
||||
child_0->SizeRef[split_axis] = ImMax(g.Style.WindowMinSize[split_axis], ImFloor(size_avail * split_ratio));
|
||||
child_1->SizeRef[split_axis] = ImMax(g.Style.WindowMinSize[split_axis], ImFloor(size_avail - child_0->SizeRef[split_axis]));
|
||||
child_0->SizeRef[split_axis] = ImFloor(size_avail * split_ratio);
|
||||
child_1->SizeRef[split_axis] = ImFloor(size_avail - child_0->SizeRef[split_axis]);
|
||||
|
||||
DockNodeMoveWindows(parent_node->ChildNodes[split_inheritor_child_idx], parent_node);
|
||||
DockNodeTreeUpdatePosSize(parent_node, parent_node->Pos, parent_node->Size);
|
||||
@ -11517,7 +11544,7 @@ void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags doc
|
||||
|
||||
// When a Dockspace transitioned form implicit to explicit this may be called a second time
|
||||
// It is possible that the node has already been claimed by a docked window which appeared before the DockSpace() node, so we overwrite IsDockSpace again.
|
||||
if (node->LastFrameActive == g.FrameCount)
|
||||
if (node->LastFrameActive == g.FrameCount && !(dock_space_flags & ImGuiDockNodeFlags_KeepAliveOnly))
|
||||
{
|
||||
IM_ASSERT(node->IsDockSpace == false && "Cannot call DockSpace() twice a frame with the same ID");
|
||||
node->IsDockSpace = true;
|
||||
@ -11593,13 +11620,25 @@ void ImGui::DockBuilderDockWindow(ImGuiContext*, const char* window_name, ImGuiI
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure a node is created
|
||||
void ImGui::DockBuilderCreateNode(ImGuiContext* ctx, ImGuiID id, ImVec2 ref_size, ImGuiDockNodeFlags flags)
|
||||
{
|
||||
DockSpace(id, ImVec2(0,0), flags | ImGuiDockNodeFlags_KeepAliveOnly);
|
||||
ImGuiDockNode* node = DockContextFindNodeByID(ctx, id);
|
||||
node->SizeRef = node->Size = ref_size;
|
||||
node->LastFrameAlive = -1;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
IM_ASSERT(node != NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
IM_ASSERT(!node->IsSplitNode()); // Already Split
|
||||
|
||||
@ -11886,7 +11925,7 @@ static void ImGui::DockSettingsHandler_ReadLine(ImGuiContext* ctx, ImGuiSettings
|
||||
if (sscanf(line, " SizeRef=%i,%i%n", &x, &y, &r) == 2) { line += r; node.SizeRef = ImVec2ih((short)x, (short)y); }
|
||||
}
|
||||
if (sscanf(line, " Split=%c%n", &c, &r) == 1) { line += r; if (c == 'X') node.SplitAxis = ImGuiAxis_X; else if (c == 'Y') node.SplitAxis = ImGuiAxis_Y; }
|
||||
if (sscanf(line, " ExplicitRoot=%d%n", &x, &r) == 1) { line += r; node.IsDockSpace = (x != 0); }
|
||||
if (sscanf(line, " DockSpace=%d%n", &x, &r) == 1) { line += r; node.IsDockSpace = (x != 0); }
|
||||
if (sscanf(line, " DocumentRoot=%d%n", &x, &r) == 1) { line += r; node.IsDocumentRoot = (x != 0); }
|
||||
if (sscanf(line, " SelectedTab=0x%08X%n", &node.SelectedTabID,&r) == 1) { line += r; }
|
||||
//if (node.ParentID == 0 && node.SplitAxis == ImGuiAxis_None)
|
||||
@ -11939,6 +11978,7 @@ static void ImGui::DockSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettings
|
||||
buf->appendf("[%s][Data]\n", handler->TypeName);
|
||||
for (int node_n = 0; node_n < dc->SettingsNodes.Size; node_n++)
|
||||
{
|
||||
//const int line_start_pos = buf->size();
|
||||
const ImGuiDockNodeSettings* node_settings = &dc->SettingsNodes[node_n];
|
||||
buf->appendf("%*sDockNode%*s", node_settings->Depth * 2, "", (max_depth - node_settings->Depth) * 2, ""); // Text align nodes to facilitate looking at .ini file
|
||||
buf->appendf(" ID=0x%08X", node_settings->ID);
|
||||
@ -11949,20 +11989,28 @@ static void ImGui::DockSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettings
|
||||
if (node_settings->SplitAxis != ImGuiAxis_None)
|
||||
buf->appendf(" Split=%c", (node_settings->SplitAxis == ImGuiAxis_X) ? 'X' : 'Y');
|
||||
if (node_settings->IsDockSpace)
|
||||
buf->appendf(" ExplicitRoot=%d", node_settings->IsDockSpace);
|
||||
buf->appendf(" DockSpace=%d", node_settings->IsDockSpace);
|
||||
if (node_settings->IsDocumentRoot)
|
||||
buf->appendf(" DocumentRoot=%d", node_settings->IsDocumentRoot);
|
||||
if (node_settings->SelectedTabID)
|
||||
buf->appendf(" SelectedTab=0x%08X", node_settings->SelectedTabID);
|
||||
|
||||
#if 0 // [DEBUG] Include windows names in the .ini file
|
||||
#if 0 // [DEBUG] Include comments in the .ini file to ease debugging
|
||||
if (ImGuiDockNode* node = DockContextFindNodeByID(ctx, node_settings->ID))
|
||||
if (node->Windows.Size > 0)
|
||||
{
|
||||
buf->appendf("%*s; recently: %d %s (", 15, "", node->Windows.Size, node->Windows.Size == 1 ? "window " : "windows");
|
||||
for (int window_n = 0; window_n < node->Windows.Size; window_n++)
|
||||
buf->appendf("\"%s\"%s", node->Windows[window_n]->Name, (window_n + 1 < node->Windows.Size) ? ", " : ")");
|
||||
}
|
||||
{
|
||||
buf->appendf("%*s", ImMax(2, (line_start_pos + 90) - buf->size()), ""); // Align everything
|
||||
if (node->IsDockSpace && node->HostWindow && node->HostWindow->ParentWindow)
|
||||
buf->appendf(" ; in '%s'", node->HostWindow->ParentWindow->Name);
|
||||
|
||||
int contains_window = 0;
|
||||
for (int window_n = 0; window_n < ctx->SettingsWindows.Size; window_n++)
|
||||
if (ctx->SettingsWindows[window_n].DockId == node_settings->ID)
|
||||
{
|
||||
if (contains_window++ == 0)
|
||||
buf->appendf(" ; contains ");
|
||||
buf->appendf("'%s' ", ctx->SettingsWindows[window_n].Name);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
buf->appendf("\n");
|
||||
}
|
||||
|
@ -1296,7 +1296,7 @@ struct ImGuiItemHoveredDataBackup
|
||||
enum ImGuiTabBarFlagsPrivate_
|
||||
{
|
||||
ImGuiTabBarFlags_DockNode = 1 << 20, // Part of a dock node
|
||||
ImGuiTabBarFlags_DockNodeExplicitRoot = 1 << 21, // Part of an explicit dock node
|
||||
ImGuiTabBarFlags_DockNodeIsDockSpace = 1 << 21, // Part of an explicit dockspace node node
|
||||
ImGuiTabBarFlags_IsFocused = 1 << 22,
|
||||
ImGuiTabBarFlags_SaveSettings = 1 << 23 // FIXME: Settings are handled by the docking system, this only request the tab bar to mark settings dirty when reordering tabs
|
||||
};
|
||||
@ -1472,6 +1472,7 @@ namespace ImGui
|
||||
IMGUI_API void DockContextEndFrame(ImGuiContext* ctx);
|
||||
IMGUI_API void DockContextQueueUndockWindow(ImGuiContext* ctx, ImGuiWindow* window);
|
||||
IMGUI_API void DockContextQueueUndockNode(ImGuiContext* ctx, ImGuiDockNode* node);
|
||||
IMGUI_API ImGuiDockNode*DockContextFindNodeByID(ImGuiContext* ctx, ImGuiID id);
|
||||
inline ImGuiDockNode* DockNodeGetRootNode(ImGuiDockNode* node) { while (node->ParentNode) node = node->ParentNode; return node; }
|
||||
IMGUI_API void BeginDocked(ImGuiWindow* window, bool* p_open);
|
||||
IMGUI_API void BeginAsDockableDragDropSource(ImGuiWindow* window);
|
||||
@ -1479,11 +1480,13 @@ namespace ImGui
|
||||
IMGUI_API void SetWindowDock(ImGuiWindow* window, ImGuiID dock_id, ImGuiCond cond);
|
||||
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);
|
||||
// Docking - Builder function needs to be generally called before the DockSpace() node is submitted.
|
||||
IMGUI_API void DockBuilderRemoveNodeDockedWindows(ImGuiContext* ctx, ImGuiID root_node_id, bool clear_persistent_docking_references = true);
|
||||
IMGUI_API void DockBuilderRemoveNodeChildNodes(ImGuiContext* ctx, ImGuiID root_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 id, ImVec2 ref_size, ImGuiDockNodeFlags flags = 0);
|
||||
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);
|
||||
IMGUI_API void DockBuilderFinish(ImGuiContext* ctx, ImGuiID root_node_id);
|
||||
|
||||
// Drag and Drop
|
||||
IMGUI_API bool BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id);
|
||||
|
@ -5871,8 +5871,8 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG
|
||||
}
|
||||
else
|
||||
{
|
||||
const float separator_min_x = tab_bar->BarRect.Min.x - ((flags & ImGuiTabBarFlags_DockNodeExplicitRoot) ? 0.0f : window->WindowPadding.x);
|
||||
const float separator_max_x = tab_bar->BarRect.Max.x + ((flags & ImGuiTabBarFlags_DockNodeExplicitRoot) ? 0.0f : window->WindowPadding.x);
|
||||
const float separator_min_x = tab_bar->BarRect.Min.x - ((flags & ImGuiTabBarFlags_DockNodeIsDockSpace) ? 0.0f : window->WindowPadding.x);
|
||||
const float separator_max_x = tab_bar->BarRect.Max.x + ((flags & ImGuiTabBarFlags_DockNodeIsDockSpace) ? 0.0f : window->WindowPadding.x);
|
||||
window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f);
|
||||
}
|
||||
return true;
|
||||
|
Loading…
Reference in New Issue
Block a user