1#![allow(
2 clippy::cast_possible_truncation,
3 clippy::cast_sign_loss,
4 clippy::as_conversions
5)]
6use bitflags::bitflags;
7use std::f32;
8
9use crate::sys;
10use crate::{Condition, Ui};
11
12pub(crate) mod child_window;
13pub(crate) mod content_region;
14pub(crate) mod scroll;
15
16bitflags! {
20 #[repr(transparent)]
22 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
23 pub struct WindowFlags: i32 {
24 const NO_TITLE_BAR = sys::ImGuiWindowFlags_NoTitleBar as i32;
26 const NO_RESIZE = sys::ImGuiWindowFlags_NoResize as i32;
28 const NO_MOVE = sys::ImGuiWindowFlags_NoMove as i32;
30 const NO_SCROLLBAR = sys::ImGuiWindowFlags_NoScrollbar as i32;
32 const NO_SCROLL_WITH_MOUSE = sys::ImGuiWindowFlags_NoScrollWithMouse as i32;
34 const NO_COLLAPSE = sys::ImGuiWindowFlags_NoCollapse as i32;
36 const ALWAYS_AUTO_RESIZE = sys::ImGuiWindowFlags_AlwaysAutoResize as i32;
38 const NO_BACKGROUND = sys::ImGuiWindowFlags_NoBackground as i32;
40 const NO_SAVED_SETTINGS = sys::ImGuiWindowFlags_NoSavedSettings as i32;
42 const NO_MOUSE_INPUTS = sys::ImGuiWindowFlags_NoMouseInputs as i32;
44 const MENU_BAR = sys::ImGuiWindowFlags_MenuBar as i32;
46 const HORIZONTAL_SCROLLBAR = sys::ImGuiWindowFlags_HorizontalScrollbar as i32;
48 const NO_FOCUS_ON_APPEARING = sys::ImGuiWindowFlags_NoFocusOnAppearing as i32;
50 const NO_BRING_TO_FRONT_ON_FOCUS = sys::ImGuiWindowFlags_NoBringToFrontOnFocus as i32;
52 const ALWAYS_VERTICAL_SCROLLBAR = sys::ImGuiWindowFlags_AlwaysVerticalScrollbar as i32;
54 const ALWAYS_HORIZONTAL_SCROLLBAR = sys::ImGuiWindowFlags_AlwaysHorizontalScrollbar as i32;
56 const NO_NAV_INPUTS = sys::ImGuiWindowFlags_NoNavInputs as i32;
58 const NO_NAV_FOCUS = sys::ImGuiWindowFlags_NoNavFocus as i32;
60 const UNSAVED_DOCUMENT = sys::ImGuiWindowFlags_UnsavedDocument as i32;
62 const NO_NAV = Self::NO_NAV_INPUTS.bits() | Self::NO_NAV_FOCUS.bits();
64 const NO_DECORATION = Self::NO_TITLE_BAR.bits() | Self::NO_RESIZE.bits() | Self::NO_SCROLLBAR.bits() | Self::NO_COLLAPSE.bits();
66 const NO_INPUTS = Self::NO_MOUSE_INPUTS.bits() | Self::NO_NAV_INPUTS.bits();
68 }
69}
70
71pub struct Window<'ui> {
73 ui: &'ui Ui,
74 name: String,
75 flags: WindowFlags,
76 size: Option<[f32; 2]>,
77 size_condition: Condition,
78 pos: Option<[f32; 2]>,
79 pos_condition: Condition,
80 content_size: Option<[f32; 2]>,
81 content_size_condition: Condition,
82 collapsed: Option<bool>,
83 collapsed_condition: Condition,
84 focused: Option<bool>,
85 bg_alpha: Option<f32>,
86}
87
88impl<'ui> Window<'ui> {
89 pub fn new(ui: &'ui Ui, name: impl Into<String>) -> Self {
91 Self {
92 ui,
93 name: name.into(),
94 flags: WindowFlags::empty(),
95 size: None,
96 size_condition: Condition::Always,
97 pos: None,
98 pos_condition: Condition::Always,
99 content_size: None,
100 content_size_condition: Condition::Always,
101 collapsed: None,
102 collapsed_condition: Condition::Always,
103 focused: None,
104 bg_alpha: None,
105 }
106 }
107
108 pub fn flags(mut self, flags: WindowFlags) -> Self {
110 self.flags = flags;
111 self
112 }
113
114 pub fn size(mut self, size: [f32; 2], condition: Condition) -> Self {
116 self.size = Some(size);
117 self.size_condition = condition;
118 self
119 }
120
121 pub fn position(mut self, pos: [f32; 2], condition: Condition) -> Self {
123 self.pos = Some(pos);
124 self.pos_condition = condition;
125 self
126 }
127
128 pub fn content_size(mut self, size: [f32; 2], condition: Condition) -> Self {
130 self.content_size = Some(size);
131 self.content_size_condition = condition;
132 self
133 }
134
135 pub fn collapsed(mut self, collapsed: bool, condition: Condition) -> Self {
137 self.collapsed = Some(collapsed);
138 self.collapsed_condition = condition;
139 self
140 }
141
142 pub fn focused(mut self, focused: bool) -> Self {
144 self.focused = Some(focused);
145 self
146 }
147
148 pub fn bg_alpha(mut self, alpha: f32) -> Self {
150 self.bg_alpha = Some(alpha);
151 self
152 }
153
154 pub fn build<F, R>(self, f: F) -> Option<R>
156 where
157 F: FnOnce() -> R,
158 {
159 let _token = self.begin()?;
160 Some(f())
161 }
162
163 fn begin(self) -> Option<WindowToken<'ui>> {
165 use std::ffi::CString;
166
167 let name_cstr = CString::new(self.name).ok()?;
168
169 if let Some(size) = self.size {
171 unsafe {
172 let size_vec = crate::sys::ImVec2 {
173 x: size[0],
174 y: size[1],
175 };
176 crate::sys::igSetNextWindowSize(size_vec, self.size_condition as i32);
177 }
178 }
179
180 if let Some(pos) = self.pos {
181 unsafe {
182 let pos_vec = crate::sys::ImVec2 {
183 x: pos[0],
184 y: pos[1],
185 };
186 let pivot_vec = crate::sys::ImVec2 { x: 0.0, y: 0.0 };
187 crate::sys::igSetNextWindowPos(pos_vec, self.pos_condition as i32, pivot_vec);
188 }
189 }
190
191 if let Some(content_size) = self.content_size {
192 unsafe {
193 let content_size_vec = crate::sys::ImVec2 {
194 x: content_size[0],
195 y: content_size[1],
196 };
197 crate::sys::igSetNextWindowContentSize(content_size_vec);
198 }
199 }
200
201 if let Some(collapsed) = self.collapsed {
202 unsafe {
203 crate::sys::igSetNextWindowCollapsed(collapsed, self.collapsed_condition as i32);
204 }
205 }
206
207 if let Some(focused) = self.focused
208 && focused
209 {
210 unsafe {
211 crate::sys::igSetNextWindowFocus();
212 }
213 }
214
215 if let Some(alpha) = self.bg_alpha {
216 unsafe {
217 crate::sys::igSetNextWindowBgAlpha(alpha);
218 }
219 }
220
221 let mut open = true;
223 let result =
224 unsafe { crate::sys::igBegin(name_cstr.as_ptr(), &mut open, self.flags.bits()) };
225
226 if result && open {
229 Some(WindowToken {
230 _phantom: std::marker::PhantomData,
231 })
232 } else {
233 unsafe {
235 crate::sys::igEnd();
236 }
237 None
238 }
239 }
240}
241
242pub struct WindowToken<'ui> {
244 _phantom: std::marker::PhantomData<&'ui ()>,
245}
246
247impl<'ui> Drop for WindowToken<'ui> {
248 fn drop(&mut self) {
249 unsafe {
250 crate::sys::igEnd();
251 }
252 }
253}