mirror of
				https://github.com/Drezil/imgui.git
				synced 2025-10-31 13:11:05 +01:00 
			
		
		
		
	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:
		
							
								
								
									
										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; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user