dear_imgui/dock_builder.rs
1//! DockBuilder API for programmatic dock layout creation
2//!
3//! This module provides the DockBuilder API which allows you to programmatically
4//! create and manage dock layouts. This is useful for creating complex docking
5//! layouts that would be difficult to achieve through manual docking.
6//!
7//! # Notes
8//!
9//! Docking is always enabled in this crate; no feature flag required.
10//!
11//! # Basic Usage
12//!
13//! ```no_run
14//! # use dear_imgui::*;
15//! # let mut ctx = Context::create();
16//! # let ui = ctx.frame();
17//! // Create a dockspace
18//! let dockspace_id = ui.dockspace_over_main_viewport();
19//!
20//! // Use DockBuilder to create a layout
21//! let left_id = DockBuilder::split_node(dockspace_id, SplitDirection::Left, 0.3, None);
22//! let right_id = DockBuilder::split_node(dockspace_id, SplitDirection::Right, 0.7, None);
23//!
24//! // Dock windows to specific nodes
25//! DockBuilder::dock_window("Tool Panel", left_id);
26//! DockBuilder::dock_window("Main View", right_id);
27//!
28//! // Finish the layout
29//! DockBuilder::finish(dockspace_id);
30//! ```
31
32use crate::sys;
33use std::ffi::CString;
34use std::ptr;
35
36/// Direction for splitting dock nodes
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub enum SplitDirection {
39 /// Split to the left
40 Left,
41 /// Split to the right
42 Right,
43 /// Split upward
44 Up,
45 /// Split downward
46 Down,
47}
48
49impl From<SplitDirection> for sys::ImGuiDir {
50 fn from(dir: SplitDirection) -> Self {
51 match dir {
52 SplitDirection::Left => sys::ImGuiDir_Left,
53 SplitDirection::Right => sys::ImGuiDir_Right,
54 SplitDirection::Up => sys::ImGuiDir_Up,
55 SplitDirection::Down => sys::ImGuiDir_Down,
56 }
57 }
58}
59
60/// DockBuilder API for programmatic dock layout creation
61pub struct DockBuilder;
62
63impl DockBuilder {
64 /// Gets a dock node by its ID
65 ///
66 /// # Parameters
67 ///
68 /// * `node_id` - The ID of the dock node to retrieve
69 ///
70 /// # Returns
71 ///
72 /// A pointer to the dock node, or null if not found
73 ///
74 /// # Safety
75 ///
76 /// The returned pointer is only valid until the next ImGui frame.
77 /// Do not store this pointer across frames.
78 #[doc(alias = "DockBuilderGetNode")]
79 pub fn get_node(node_id: sys::ImGuiID) -> *mut sys::ImGuiDockNode {
80 unsafe { sys::igDockBuilderGetNode(node_id) }
81 }
82
83 /// Adds a new dock node
84 ///
85 /// # Parameters
86 ///
87 /// * `node_id` - The ID for the new dock node (use 0 to auto-generate)
88 /// * `flags` - Dock node flags
89 ///
90 /// # Returns
91 ///
92 /// The ID of the created dock node
93 ///
94 /// # Example
95 ///
96 /// ```no_run
97 /// # use dear_imgui::*;
98 /// let node_id = DockBuilder::add_node(0, DockNodeFlags::NO_RESIZE);
99 /// ```
100 #[doc(alias = "DockBuilderAddNode")]
101 pub fn add_node(node_id: sys::ImGuiID, flags: crate::DockNodeFlags) -> sys::ImGuiID {
102 unsafe { sys::igDockBuilderAddNode(node_id, flags.bits()) }
103 }
104
105 /// Removes a dock node
106 ///
107 /// # Parameters
108 ///
109 /// * `node_id` - The ID of the dock node to remove
110 ///
111 /// # Example
112 ///
113 /// ```no_run
114 /// # use dear_imgui::*;
115 /// DockBuilder::remove_node(123);
116 /// ```
117 #[doc(alias = "DockBuilderRemoveNode")]
118 pub fn remove_node(node_id: sys::ImGuiID) {
119 unsafe { sys::igDockBuilderRemoveNode(node_id) }
120 }
121
122 /// Removes all docked windows from a node
123 ///
124 /// # Parameters
125 ///
126 /// * `node_id` - The ID of the dock node
127 /// * `clear_settings_refs` - Whether to clear settings references
128 ///
129 /// # Example
130 ///
131 /// ```no_run
132 /// # use dear_imgui::*;
133 /// DockBuilder::remove_node_docked_windows(123, true);
134 /// ```
135 #[doc(alias = "DockBuilderRemoveNodeDockedWindows")]
136 pub fn remove_node_docked_windows(node_id: sys::ImGuiID, clear_settings_refs: bool) {
137 unsafe { sys::igDockBuilderRemoveNodeDockedWindows(node_id, clear_settings_refs) }
138 }
139
140 /// Removes all child nodes from a dock node
141 ///
142 /// # Parameters
143 ///
144 /// * `node_id` - The ID of the dock node
145 ///
146 /// # Example
147 ///
148 /// ```no_run
149 /// # use dear_imgui::*;
150 /// DockBuilder::remove_node_child_nodes(123);
151 /// ```
152 #[doc(alias = "DockBuilderRemoveNodeChildNodes")]
153 pub fn remove_node_child_nodes(node_id: sys::ImGuiID) {
154 unsafe { sys::igDockBuilderRemoveNodeChildNodes(node_id) }
155 }
156
157 /// Sets the position of a dock node
158 ///
159 /// # Parameters
160 ///
161 /// * `node_id` - The ID of the dock node
162 /// * `pos` - The position in pixels
163 ///
164 /// # Example
165 ///
166 /// ```no_run
167 /// # use dear_imgui::*;
168 /// DockBuilder::set_node_pos(123, [100.0, 50.0]);
169 /// ```
170 #[doc(alias = "DockBuilderSetNodePos")]
171 pub fn set_node_pos(node_id: sys::ImGuiID, pos: [f32; 2]) {
172 unsafe {
173 let pos_vec = sys::ImVec2 {
174 x: pos[0],
175 y: pos[1],
176 };
177 sys::igDockBuilderSetNodePos(node_id, pos_vec)
178 }
179 }
180
181 /// Sets the size of a dock node
182 ///
183 /// # Parameters
184 ///
185 /// * `node_id` - The ID of the dock node
186 /// * `size` - The size in pixels
187 ///
188 /// # Example
189 ///
190 /// ```no_run
191 /// # use dear_imgui::*;
192 /// DockBuilder::set_node_size(123, [800.0, 600.0]);
193 /// ```
194 #[doc(alias = "DockBuilderSetNodeSize")]
195 pub fn set_node_size(node_id: sys::ImGuiID, size: [f32; 2]) {
196 unsafe {
197 let size_vec = sys::ImVec2 {
198 x: size[0],
199 y: size[1],
200 };
201 sys::igDockBuilderSetNodeSize(node_id, size_vec)
202 }
203 }
204
205 /// Splits a dock node into two nodes
206 ///
207 /// # Parameters
208 ///
209 /// * `node_id` - The ID of the dock node to split
210 /// * `split_dir` - The direction to split
211 /// * `size_ratio_for_node_at_dir` - The size ratio for the new node (0.0 to 1.0)
212 /// * `out_id_at_dir` - Optional output for the ID of the new node in the split direction
213 ///
214 /// # Returns
215 ///
216 /// The ID of the remaining node (opposite to the split direction)
217 ///
218 /// # Example
219 ///
220 /// ```no_run
221 /// # use dear_imgui::*;
222 /// let dockspace_id = 1;
223 /// let left_id = DockBuilder::split_node(dockspace_id, SplitDirection::Left, 0.3, None);
224 /// ```
225 #[doc(alias = "DockBuilderSplitNode")]
226 pub fn split_node(
227 node_id: sys::ImGuiID,
228 split_dir: SplitDirection,
229 size_ratio_for_node_at_dir: f32,
230 out_id_at_dir: Option<&mut sys::ImGuiID>,
231 ) -> sys::ImGuiID {
232 unsafe {
233 let out_ptr = if let Some(out) = out_id_at_dir {
234 out as *mut _
235 } else {
236 ptr::null_mut()
237 };
238 sys::igDockBuilderSplitNode(
239 node_id,
240 split_dir.into(),
241 size_ratio_for_node_at_dir,
242 out_ptr,
243 ptr::null_mut(),
244 )
245 }
246 }
247
248 /// Docks a window to a specific dock node
249 ///
250 /// # Parameters
251 ///
252 /// * `window_name` - The name of the window to dock
253 /// * `node_id` - The ID of the dock node to dock the window to
254 ///
255 /// # Example
256 ///
257 /// ```no_run
258 /// # use dear_imgui::*;
259 /// DockBuilder::dock_window("My Tool", 123);
260 /// ```
261 #[doc(alias = "DockBuilderDockWindow")]
262 pub fn dock_window(window_name: &str, node_id: sys::ImGuiID) {
263 let c_name = CString::new(window_name).expect("Window name contained null byte");
264 unsafe { sys::igDockBuilderDockWindow(c_name.as_ptr(), node_id) }
265 }
266
267 /// Finishes the dock builder operations
268 ///
269 /// This function should be called after all dock builder operations are complete
270 /// to finalize the layout.
271 ///
272 /// # Parameters
273 ///
274 /// * `node_id` - The root node ID of the dock layout
275 ///
276 /// # Example
277 ///
278 /// ```no_run
279 /// # use dear_imgui::*;
280 /// // ... create layout ...
281 /// let dockspace_id = 1; // placeholder dockspace id for example
282 /// DockBuilder::finish(dockspace_id);
283 /// ```
284 #[doc(alias = "DockBuilderFinish")]
285 pub fn finish(node_id: sys::ImGuiID) {
286 unsafe { sys::igDockBuilderFinish(node_id) }
287 }
288}