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}