dear_imgui_rs/window/
child_window.rs1#![allow(
22 clippy::cast_possible_truncation,
23 clippy::cast_sign_loss,
24 clippy::as_conversions
25)]
26use super::validate_window_flags;
30use crate::sys;
31use crate::{Ui, WindowFlags};
32use std::borrow::Cow;
33
34bitflags::bitflags! {
35 #[repr(transparent)]
37 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
38 pub struct ChildFlags: u32 {
39 const NONE = 0;
41 const BORDERS = sys::ImGuiChildFlags_Borders as u32;
43 const ALWAYS_USE_WINDOW_PADDING = sys::ImGuiChildFlags_AlwaysUseWindowPadding as u32;
45 const RESIZE_X = sys::ImGuiChildFlags_ResizeX as u32;
47 const RESIZE_Y = sys::ImGuiChildFlags_ResizeY as u32;
49 const AUTO_RESIZE_X = sys::ImGuiChildFlags_AutoResizeX as u32;
51 const AUTO_RESIZE_Y = sys::ImGuiChildFlags_AutoResizeY as u32;
53 const ALWAYS_AUTO_RESIZE = sys::ImGuiChildFlags_AlwaysAutoResize as u32;
55 const FRAME_STYLE = sys::ImGuiChildFlags_FrameStyle as u32;
57 const NAV_FLATTENED = sys::ImGuiChildFlags_NavFlattened as u32;
59 }
60}
61
62fn validate_child_flags(caller: &str, child_flags: ChildFlags, window_flags: WindowFlags) {
63 let unsupported = child_flags.bits() & !ChildFlags::all().bits();
64 assert!(
65 unsupported == 0,
66 "{caller} received unsupported ImGuiChildFlags bits: 0x{unsupported:X}"
67 );
68 validate_window_flags(caller, window_flags);
69 assert!(
70 !window_flags.contains(WindowFlags::ALWAYS_AUTO_RESIZE),
71 "{caller} cannot use WindowFlags::ALWAYS_AUTO_RESIZE; use ChildFlags::ALWAYS_AUTO_RESIZE"
72 );
73 if child_flags.contains(ChildFlags::ALWAYS_AUTO_RESIZE) {
74 assert!(
75 !child_flags.intersects(ChildFlags::RESIZE_X | ChildFlags::RESIZE_Y),
76 "{caller} cannot combine ALWAYS_AUTO_RESIZE with RESIZE_X or RESIZE_Y"
77 );
78 assert!(
79 child_flags.intersects(ChildFlags::AUTO_RESIZE_X | ChildFlags::AUTO_RESIZE_Y),
80 "{caller} requires AUTO_RESIZE_X or AUTO_RESIZE_Y when using ALWAYS_AUTO_RESIZE"
81 );
82 }
83}
84
85pub struct ChildWindow<'ui> {
87 name: Cow<'ui, str>,
88 size: [f32; 2],
89 child_flags: ChildFlags,
90 flags: WindowFlags,
91 _phantom: std::marker::PhantomData<&'ui ()>,
92}
93
94impl<'ui> ChildWindow<'ui> {
95 pub fn new(name: impl Into<Cow<'ui, str>>) -> Self {
97 Self {
98 name: name.into(),
99 size: [0.0, 0.0],
100 child_flags: ChildFlags::NONE,
101 flags: WindowFlags::empty(),
102 _phantom: std::marker::PhantomData,
103 }
104 }
105
106 pub fn size(mut self, size: [f32; 2]) -> Self {
108 self.size = size;
109 self
110 }
111
112 pub fn border(mut self, border: bool) -> Self {
114 self.child_flags.set(ChildFlags::BORDERS, border);
115 self
116 }
117
118 pub fn child_flags(mut self, child_flags: ChildFlags) -> Self {
120 self.child_flags = child_flags;
121 self
122 }
123
124 pub fn flags(mut self, flags: WindowFlags) -> Self {
126 self.flags = flags;
127 self
128 }
129
130 pub fn build<F, R>(self, ui: &'ui Ui, f: F) -> Option<R>
132 where
133 F: FnOnce() -> R,
134 {
135 let token = self.begin(ui)?;
136 let result = f();
137 drop(token); Some(result)
139 }
140
141 fn begin(self, ui: &'ui Ui) -> Option<ChildWindowToken<'ui>> {
143 let name_ptr = ui.scratch_txt(self.name);
144 validate_child_flags("ChildWindow::begin()", self.child_flags, self.flags);
145 assert!(
146 self.size[0].is_finite() && self.size[1].is_finite(),
147 "ChildWindow::begin() size must contain finite values"
148 );
149
150 let result = unsafe {
151 let size_vec = sys::ImVec2 {
152 x: self.size[0],
153 y: self.size[1],
154 };
155 sys::igBeginChild_Str(
156 name_ptr,
157 size_vec,
158 self.child_flags.bits() as i32,
159 self.flags.bits(),
160 )
161 };
162
163 if result {
168 Some(ChildWindowToken {
169 _phantom: std::marker::PhantomData,
170 })
171 } else {
172 unsafe {
174 sys::igEndChild();
175 }
176 None
177 }
178 }
179}
180
181pub struct ChildWindowToken<'ui> {
183 _phantom: std::marker::PhantomData<&'ui ()>,
184}
185
186impl<'ui> Drop for ChildWindowToken<'ui> {
187 fn drop(&mut self) {
188 unsafe {
189 sys::igEndChild();
190 }
191 }
192}
193
194impl Ui {
195 pub fn child_window<'ui>(&'ui self, name: impl Into<Cow<'ui, str>>) -> ChildWindow<'ui> {
197 ChildWindow::new(name)
198 }
199}