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:
omar 2018-09-24 11:06:31 +02:00
parent 2a5ce1849a
commit fa0ce4b7d5
3 changed files with 74 additions and 23 deletions

View File

@ -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,19 +11989,27 @@ 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");

View File

@ -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);

View File

@ -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;