dear_imgui_rs/dock_space/
window_class.rs1use super::flags::WindowClassDockNodeFlags;
2use super::validation::assert_nonzero_id;
3use crate::{Id, sys};
4use std::ptr;
5use thiserror::Error;
6
7#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
9pub enum WindowClassParentViewport {
10 #[default]
12 Default,
13 NoParent,
15 Parent(Id),
17}
18
19impl WindowClassParentViewport {
20 fn try_raw(self) -> Result<sys::ImGuiID, WindowClassError> {
21 match self {
22 Self::Default => Ok(!0),
23 Self::NoParent => Ok(0),
24 Self::Parent(id) if id.raw() != 0 => Ok(id.raw()),
25 Self::Parent(_) => Err(WindowClassError::ZeroParentViewportId),
26 }
27 }
28}
29
30#[derive(Clone, Debug, Error, PartialEq, Eq)]
32#[non_exhaustive]
33pub enum WindowClassError {
34 #[error("parent viewport ID must be non-zero")]
35 ZeroParentViewportId,
36 #[error("viewport overrides contain unsupported ImGuiViewportFlags bits: 0x{bits:X}")]
37 UnsupportedViewportFlags { bits: i32 },
38 #[error("viewport overrides set and clear the same ImGuiViewportFlags bits: 0x{bits:X}")]
39 OverlappingViewportFlags { bits: i32 },
40 #[error("tab overrides contain unsupported ImGuiTabItemFlags bits: 0x{bits:X}")]
41 UnsupportedTabItemFlags { bits: i32 },
42 #[error("dock-node overrides contain unsupported ImGuiDockNodeFlags bits: 0x{bits:X}")]
43 UnsupportedDockNodeFlags { bits: i32 },
44}
45
46#[derive(Debug, Clone)]
57pub struct WindowClass {
58 class_id: Option<Id>,
60 parent_viewport: WindowClassParentViewport,
62 focus_route_parent_window_id: Option<Id>,
64 viewport_flags_override_set: crate::WindowClassViewportFlags,
66 viewport_flags_override_clear: crate::WindowClassViewportFlags,
68 tab_item_flags_override_set: crate::widget::TabItemOptions,
70 dock_node_flags_override_set: WindowClassDockNodeFlags,
72 docking_always_tab_bar: bool,
74 docking_allow_unclassed: bool,
76 platform_icon_data: Option<ptr::NonNull<std::ffi::c_void>>,
81}
82
83impl Default for WindowClass {
84 fn default() -> Self {
85 Self {
86 class_id: None,
87 parent_viewport: WindowClassParentViewport::Default,
88 focus_route_parent_window_id: None,
89 viewport_flags_override_set: crate::WindowClassViewportFlags::empty(),
90 viewport_flags_override_clear: crate::WindowClassViewportFlags::empty(),
91 tab_item_flags_override_set: crate::widget::TabItemOptions::new(),
92 dock_node_flags_override_set: WindowClassDockNodeFlags::NONE,
93 docking_always_tab_bar: false,
94 docking_allow_unclassed: true,
95 platform_icon_data: None,
96 }
97 }
98}
99
100impl WindowClass {
101 pub fn new(class_id: Id) -> Self {
103 assert_nonzero_id("WindowClass::new()", "class_id", class_id);
104 Self {
105 class_id: Some(class_id),
106 ..Default::default()
107 }
108 }
109
110 pub fn class_id(&self) -> Option<Id> {
112 self.class_id
113 }
114
115 pub fn parent_viewport_policy(&self) -> WindowClassParentViewport {
117 self.parent_viewport
118 }
119
120 pub fn focus_route_parent_window_id_raw(&self) -> Option<Id> {
122 self.focus_route_parent_window_id
123 }
124
125 pub fn viewport_flags_to_set(&self) -> crate::WindowClassViewportFlags {
127 self.viewport_flags_override_set
128 }
129
130 pub fn viewport_flags_to_clear(&self) -> crate::WindowClassViewportFlags {
132 self.viewport_flags_override_clear
133 }
134
135 pub fn tab_item_options(&self) -> crate::widget::TabItemOptions {
137 self.tab_item_flags_override_set
138 }
139
140 pub fn dock_node_flags_to_set(&self) -> WindowClassDockNodeFlags {
142 self.dock_node_flags_override_set
143 }
144
145 pub fn always_tab_bar(&self) -> bool {
147 self.docking_always_tab_bar
148 }
149
150 pub fn allows_unclassed(&self) -> bool {
152 self.docking_allow_unclassed
153 }
154
155 pub unsafe fn parent_viewport(mut self, parent: WindowClassParentViewport) -> Self {
164 self.parent_viewport = parent;
165 self
166 }
167
168 pub fn no_parent_viewport(mut self) -> Self {
170 self.parent_viewport = WindowClassParentViewport::NoParent;
171 self
172 }
173
174 pub unsafe fn parent_viewport_id(mut self, id: Id) -> Self {
187 assert_nonzero_id("WindowClass::parent_viewport_id()", "id", id);
188 self.parent_viewport = WindowClassParentViewport::Parent(id);
189 self
190 }
191
192 pub unsafe fn focus_route_parent_window_id(mut self, id: Id) -> Self {
207 assert_nonzero_id("WindowClass::focus_route_parent_window_id()", "id", id);
208 self.focus_route_parent_window_id = Some(id);
209 self
210 }
211
212 pub fn viewport_flags_override_set(mut self, flags: crate::WindowClassViewportFlags) -> Self {
214 self.viewport_flags_override_set = flags;
215 self
216 }
217
218 pub fn viewport_flags_override_clear(mut self, flags: crate::WindowClassViewportFlags) -> Self {
220 self.viewport_flags_override_clear = flags;
221 self
222 }
223
224 pub fn viewport_flags_overrides(
226 mut self,
227 set: crate::WindowClassViewportFlags,
228 clear: crate::WindowClassViewportFlags,
229 ) -> Self {
230 self.viewport_flags_override_set = set;
231 self.viewport_flags_override_clear = clear;
232 self
233 }
234
235 pub fn tab_item_flags_override_set(
237 mut self,
238 options: impl Into<crate::widget::TabItemOptions>,
239 ) -> Self {
240 self.tab_item_flags_override_set = options.into();
241 self
242 }
243
244 pub fn dock_node_flags_override_set(mut self, flags: WindowClassDockNodeFlags) -> Self {
246 self.dock_node_flags_override_set = flags;
247 self
248 }
249
250 pub fn docking_always_tab_bar(mut self, enabled: bool) -> Self {
252 self.docking_always_tab_bar = enabled;
253 self
254 }
255
256 pub fn docking_allow_unclassed(mut self, enabled: bool) -> Self {
258 self.docking_allow_unclassed = enabled;
259 self
260 }
261
262 pub unsafe fn platform_icon_data_raw(mut self, data: *mut std::ffi::c_void) -> Self {
269 self.platform_icon_data = ptr::NonNull::new(data);
270 self
271 }
272
273 pub fn validate(&self) -> Result<(), WindowClassError> {
275 let viewport_bits =
276 (self.viewport_flags_override_set | self.viewport_flags_override_clear).bits();
277 let unsupported_viewport = viewport_bits & !crate::WindowClassViewportFlags::all().bits();
278 if unsupported_viewport != 0 {
279 return Err(WindowClassError::UnsupportedViewportFlags {
280 bits: unsupported_viewport,
281 });
282 }
283 let overlap =
284 self.viewport_flags_override_set.bits() & self.viewport_flags_override_clear.bits();
285 if overlap != 0 {
286 return Err(WindowClassError::OverlappingViewportFlags { bits: overlap });
287 }
288 let unsupported_tab =
289 self.tab_item_flags_override_set.flags.bits() & !crate::TabItemFlags::all().bits();
290 if unsupported_tab != 0 {
291 return Err(WindowClassError::UnsupportedTabItemFlags {
292 bits: unsupported_tab,
293 });
294 }
295 let unsupported_dock =
296 self.dock_node_flags_override_set.bits() & !WindowClassDockNodeFlags::all().bits();
297 if unsupported_dock != 0 {
298 return Err(WindowClassError::UnsupportedDockNodeFlags {
299 bits: unsupported_dock,
300 });
301 }
302 self.parent_viewport.try_raw()?;
303 Ok(())
304 }
305
306 pub(crate) fn try_to_imgui(&self) -> Result<sys::ImGuiWindowClass, WindowClassError> {
307 self.validate()?;
308 Ok(sys::ImGuiWindowClass {
309 ClassId: self.class_id.map_or(0, Id::raw),
310 ParentViewportId: self.parent_viewport.try_raw()?,
311 FocusRouteParentWindowId: self.focus_route_parent_window_id.map_or(0, Id::raw),
312 ViewportFlagsOverrideSet: self.viewport_flags_override_set.bits(),
313 ViewportFlagsOverrideClear: self.viewport_flags_override_clear.bits(),
314 TabItemFlagsOverrideSet: self.tab_item_flags_override_set.bits(),
315 DockNodeFlagsOverrideSet: self.dock_node_flags_override_set.bits(),
316 DockingAlwaysTabBar: self.docking_always_tab_bar,
317 DockingAllowUnclassed: self.docking_allow_unclassed,
318 PlatformIconData: self
319 .platform_icon_data
320 .map_or(ptr::null_mut(), ptr::NonNull::as_ptr),
321 })
322 }
323
324 pub(crate) fn to_imgui(&self, caller: &str) -> sys::ImGuiWindowClass {
326 self.try_to_imgui()
327 .unwrap_or_else(|error| panic!("{caller}: {error}"))
328 }
329}