arcdps_imgui\window/
mod.rs

1use bitflags::bitflags;
2use std::f32;
3use std::ptr;
4
5use crate::sys;
6use crate::{Condition, Ui};
7
8pub(crate) mod child_window;
9pub(crate) mod content_region;
10pub(crate) mod scroll;
11
12bitflags! {
13    /// Window hover check option flags
14    #[repr(transparent)]
15    pub struct WindowHoveredFlags: u32 {
16        /// Return true if any child of the window is hovered
17        const CHILD_WINDOWS = sys::ImGuiHoveredFlags_ChildWindows;
18        /// Test from root window (top-most parent of the current hierarchy)
19        const ROOT_WINDOW = sys::ImGuiHoveredFlags_RootWindow;
20        /// Return true if any window is hovered
21        const ANY_WINDOW = sys::ImGuiHoveredFlags_AnyWindow;
22        /// Return true even if a popup window is blocking access to this window
23        const ALLOW_WHEN_BLOCKED_BY_POPUP = sys::ImGuiHoveredFlags_AllowWhenBlockedByPopup;
24        /// Return true even if an active item is blocking access to this window
25        const ALLOW_WHEN_BLOCKED_BY_ACTIVE_ITEM = sys::ImGuiHoveredFlags_AllowWhenBlockedByActiveItem;
26        /// Test from root window, and return true if any child is hovered
27        const ROOT_AND_CHILD_WINDOWS = Self::ROOT_WINDOW.bits | Self::CHILD_WINDOWS.bits;
28    }
29}
30
31bitflags! {
32    /// Window focus check option flags
33    #[repr(transparent)]
34    pub struct WindowFocusedFlags: u32 {
35        /// Return true if any child of the window is focused
36        const CHILD_WINDOWS = sys::ImGuiFocusedFlags_ChildWindows;
37        /// Test from root window (top-most parent of the current hierarchy)
38        const ROOT_WINDOW = sys::ImGuiFocusedFlags_RootWindow;
39        /// Return true if any window is focused
40        const ANY_WINDOW = sys::ImGuiFocusedFlags_AnyWindow;
41        /// Test from root window, and return true if any child is focused
42        const ROOT_AND_CHILD_WINDOWS = Self::ROOT_WINDOW.bits | Self::CHILD_WINDOWS.bits;
43    }
44}
45
46bitflags! {
47    /// Configuration flags for windows
48    #[repr(transparent)]
49    pub struct WindowFlags: u32 {
50        /// Disable the title bar
51        const NO_TITLE_BAR = sys::ImGuiWindowFlags_NoTitleBar;
52        /// Disable resizing with the lower-right grip
53        const NO_RESIZE = sys::ImGuiWindowFlags_NoResize;
54        /// Disable moving the window
55        const NO_MOVE = sys::ImGuiWindowFlags_NoMove;
56        /// Disable scrollbars (scrolling is still possible with the mouse or programmatically)
57        const NO_SCROLLBAR = sys::ImGuiWindowFlags_NoScrollbar;
58        /// Disable vertical scrolling with the mouse wheel.
59        ///
60        /// On child window, the mouse wheel will be forwarded to the parent unless `NO_SCROLLBAR`
61        /// is also set.
62        const NO_SCROLL_WITH_MOUSE = sys::ImGuiWindowFlags_NoScrollWithMouse;
63        /// Disable collapsing the window by double-clicking it
64        const NO_COLLAPSE = sys::ImGuiWindowFlags_NoCollapse;
65        /// Resize the window to its content on every frame
66        const ALWAYS_AUTO_RESIZE = sys::ImGuiWindowFlags_AlwaysAutoResize;
67        /// Disable drawing of background color and outside border
68        const NO_BACKGROUND = sys::ImGuiWindowFlags_NoBackground;
69        /// Never load/save settings
70        const NO_SAVED_SETTINGS = sys::ImGuiWindowFlags_NoSavedSettings;
71        /// Disable catching mouse input. Hovering test will pass through
72        const NO_MOUSE_INPUTS = sys::ImGuiWindowFlags_NoMouseInputs;
73        /// Show a menu bar
74        const MENU_BAR = sys::ImGuiWindowFlags_MenuBar;
75        /// Allow horizontal scrollbar to appear
76        const HORIZONTAL_SCROLLBAR = sys::ImGuiWindowFlags_HorizontalScrollbar;
77        /// Disable taking focus when transitioning from hidden to visible state
78        const NO_FOCUS_ON_APPEARING = sys::ImGuiWindowFlags_NoFocusOnAppearing;
79        /// Disable bringing window to front when taking focus (e.g. clicking it or
80        /// programmatically giving it focus)
81        const NO_BRING_TO_FRONT_ON_FOCUS = sys::ImGuiWindowFlags_NoBringToFrontOnFocus;
82        /// Always show vertical scrollbar
83        const ALWAYS_VERTICAL_SCROLLBAR = sys::ImGuiWindowFlags_AlwaysVerticalScrollbar;
84        /// Always show horizontal scrollbar
85        const ALWAYS_HORIZONTAL_SCROLLBAR = sys::ImGuiWindowFlags_AlwaysHorizontalScrollbar;
86        /// Ensure child windows without border use `style.window_padding`
87        const ALWAYS_USE_WINDOW_PADDING = sys::ImGuiWindowFlags_AlwaysUseWindowPadding;
88        /// Disable gamepad/keyboard navigation within the window
89        const NO_NAV_INPUTS = sys::ImGuiWindowFlags_NoNavInputs;
90        /// No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by
91        /// CTRL+TAB)
92        const NO_NAV_FOCUS = sys::ImGuiWindowFlags_NoNavFocus;
93        /// Append '*' to title without affecting the ID, as a convenience
94        const UNSAVED_DOCUMENT = sys::ImGuiWindowFlags_UnsavedDocument;
95        /// Disable gamepad/keyboard navigation and focusing.
96        ///
97        /// Shorthand for `WindowFlags::NO_NAV_INPUTS | WindowFlags::NO_NAV_FOCUS`.
98        const NO_NAV = sys::ImGuiWindowFlags_NoNav;
99        /// Disable all window decorations.
100        ///
101        /// Shorthand for `WindowFlags::NO_TITLE_BAR | WindowFlags::NO_RESIZE |
102        /// WindowFlags::NO_SCROLLBAR | WindowFlags::NO_COLLAPSE`.
103        const NO_DECORATION = sys::ImGuiWindowFlags_NoDecoration;
104        /// Don't handle input.
105        ///
106        /// Shorthand for `WindowFlags::NO_MOUSE_INPUTS | WindowFlags::NO_NAV_INPUTS |
107        /// WindowFlags::NO_NAV_FOCUS`.
108        const NO_INPUTS = sys::ImGuiWindowFlags_NoInputs;
109    }
110}
111
112/// # Window utilities
113impl<'ui> Ui<'ui> {
114    /// Returns true if the current window appeared during this frame
115    #[doc(alias = "IsWindowAppearing")]
116    pub fn is_window_appearing(&self) -> bool {
117        unsafe { sys::igIsWindowAppearing() }
118    }
119    /// Returns true if the current window is in collapsed state (= only the title bar is visible)
120    #[doc(alias = "IsWindowCollapsed")]
121    pub fn is_window_collapsed(&self) -> bool {
122        unsafe { sys::igIsWindowCollapsed() }
123    }
124    /// Returns true if the current window is focused
125    #[doc(alias = "IsWindowFocused")]
126    pub fn is_window_focused(&self) -> bool {
127        unsafe { sys::igIsWindowFocused(0) }
128    }
129    /// Returns true if the current window is focused based on the given flags
130    #[doc(alias = "IsWindowFocused")]
131    pub fn is_window_focused_with_flags(&self, flags: WindowFocusedFlags) -> bool {
132        unsafe { sys::igIsWindowFocused(flags.bits() as i32) }
133    }
134    /// Returns true if the current window is hovered
135    #[doc(alias = "IsWindowHovered")]
136    pub fn is_window_hovered(&self) -> bool {
137        unsafe { sys::igIsWindowHovered(0) }
138    }
139    /// Returns true if the current window is hovered based on the given flags
140    #[doc(alias = "IsWindowHovered")]
141    pub fn is_window_hovered_with_flags(&self, flags: WindowHoveredFlags) -> bool {
142        unsafe { sys::igIsWindowHovered(flags.bits() as i32) }
143    }
144    /// Returns the position of the current window (in screen space)
145    #[doc(alias = "GetWindowPos")]
146    pub fn window_pos(&self) -> [f32; 2] {
147        let mut out = sys::ImVec2::zero();
148        unsafe { sys::igGetWindowPos(&mut out) };
149        out.into()
150    }
151    /// Returns the size of the current window
152    #[doc(alias = "GetWindowPos")]
153    pub fn window_size(&self) -> [f32; 2] {
154        let mut out = sys::ImVec2::zero();
155        unsafe { sys::igGetWindowSize(&mut out) };
156        out.into()
157    }
158}
159
160/// Builder for a window
161#[derive(Debug)]
162#[must_use]
163pub struct Window<'a, T> {
164    name: T,
165    opened: Option<&'a mut bool>,
166    flags: WindowFlags,
167    pos: [f32; 2],
168    pos_cond: Condition,
169    pos_pivot: [f32; 2],
170    size: [f32; 2],
171    size_cond: Condition,
172    size_constraints: Option<([f32; 2], [f32; 2])>,
173    content_size: [f32; 2],
174    collapsed: bool,
175    collapsed_cond: Condition,
176    focused: bool,
177    bg_alpha: f32,
178}
179
180impl<'a, T: AsRef<str>> Window<'a, T> {
181    /// Creates a new window builder with the given name
182    pub fn new(name: T) -> Self {
183        Window {
184            name,
185            opened: None,
186            flags: WindowFlags::empty(),
187            pos: [0.0, 0.0],
188            pos_cond: Condition::Never,
189            pos_pivot: [0.0, 0.0],
190            size: [0.0, 0.0],
191            size_cond: Condition::Never,
192            size_constraints: None,
193            content_size: [0.0, 0.0],
194            collapsed: false,
195            collapsed_cond: Condition::Never,
196            focused: false,
197            bg_alpha: f32::NAN,
198        }
199    }
200    /// Enables the window close button, which sets the passed boolean to false when clicked
201    #[inline]
202    pub fn opened(mut self, opened: &'a mut bool) -> Self {
203        self.opened = Some(opened);
204        self
205    }
206    /// Replace current window flags with the given value
207    #[inline]
208    pub fn flags(mut self, flags: WindowFlags) -> Self {
209        self.flags = flags;
210        self
211    }
212    /// Sets the window position, which is applied based on the given condition value
213    #[inline]
214    pub fn position(mut self, position: [f32; 2], condition: Condition) -> Self {
215        self.pos = position;
216        self.pos_cond = condition;
217        self
218    }
219    /// Sets the window position pivot, which can be used to adjust the alignment of the window
220    /// relative to the position.
221    ///
222    /// For example, pass [0.5, 0.5] to center the window on the position.
223    /// Does nothing if window position is not also set with `position()`.
224    #[inline]
225    pub fn position_pivot(mut self, pivot: [f32; 2]) -> Self {
226        self.pos_pivot = pivot;
227        self
228    }
229    /// Sets the window size, which is applied based on the given condition value
230    #[inline]
231    pub fn size(mut self, size: [f32; 2], condition: Condition) -> Self {
232        self.size = size;
233        self.size_cond = condition;
234        self
235    }
236    /// Sets window size constraints.
237    ///
238    /// Use -1.0, -1.0 on either X or Y axis to preserve current size.
239    #[inline]
240    pub fn size_constraints(mut self, size_min: [f32; 2], size_max: [f32; 2]) -> Self {
241        self.size_constraints = Some((size_min, size_max));
242        self
243    }
244    /// Sets the window content size, which can be used to enforce scrollbars.
245    ///
246    /// Does not include window decorations (title bar, menu bar, etc.). Set one of the values to
247    /// 0.0 to leave the size automatic.
248    #[inline]
249    pub fn content_size(mut self, size: [f32; 2]) -> Self {
250        self.content_size = size;
251        self
252    }
253    /// Sets the window collapse state, which is applied based on the given condition value
254    #[inline]
255    pub fn collapsed(mut self, collapsed: bool, condition: Condition) -> Self {
256        self.collapsed = collapsed;
257        self.collapsed_cond = condition;
258        self
259    }
260    /// Sets the window focused state, which can be used to bring the window to front
261    #[inline]
262    pub fn focused(mut self, focused: bool) -> Self {
263        self.focused = focused;
264        self
265    }
266    /// Sets the background color alpha value.
267    ///
268    /// See also `draw_background`
269    #[inline]
270    pub fn bg_alpha(mut self, bg_alpha: f32) -> Self {
271        self.bg_alpha = bg_alpha;
272        self
273    }
274    /// Enables/disables the title bar.
275    ///
276    /// Enabled by default.
277    #[inline]
278    pub fn title_bar(mut self, value: bool) -> Self {
279        self.flags.set(WindowFlags::NO_TITLE_BAR, !value);
280        self
281    }
282    /// Enables/disables resizing with the lower-right grip.
283    ///
284    /// Enabled by default.
285    #[inline]
286    pub fn resizable(mut self, value: bool) -> Self {
287        self.flags.set(WindowFlags::NO_RESIZE, !value);
288        self
289    }
290    /// Enables/disables moving the window.
291    ///
292    /// Enabled by default.
293    #[inline]
294    pub fn movable(mut self, value: bool) -> Self {
295        self.flags.set(WindowFlags::NO_MOVE, !value);
296        self
297    }
298    /// Enables/disables scrollbars (scrolling is still possible with the mouse or
299    /// programmatically).
300    ///
301    /// Enabled by default.
302    #[inline]
303    pub fn scroll_bar(mut self, value: bool) -> Self {
304        self.flags.set(WindowFlags::NO_SCROLLBAR, !value);
305        self
306    }
307    /// Enables/disables vertical scrolling with the mouse wheel.
308    ///
309    /// Enabled by default.
310    /// When enabled, child windows forward the mouse wheel to the parent unless `NO_SCROLLBAR`
311    /// is also set.
312    #[inline]
313    pub fn scrollable(mut self, value: bool) -> Self {
314        self.flags.set(WindowFlags::NO_SCROLL_WITH_MOUSE, !value);
315        self
316    }
317    /// Enables/disables collapsing the window by double-clicking it.
318    ///
319    /// Enabled by default.
320    #[inline]
321    pub fn collapsible(mut self, value: bool) -> Self {
322        self.flags.set(WindowFlags::NO_COLLAPSE, !value);
323        self
324    }
325    /// Enables/disables resizing the window to its content on every frame.
326    ///
327    /// Disabled by default.
328    #[inline]
329    pub fn always_auto_resize(mut self, value: bool) -> Self {
330        self.flags.set(WindowFlags::ALWAYS_AUTO_RESIZE, value);
331        self
332    }
333    /// Enables/disables drawing of background color and outside border.
334    ///
335    /// Enabled by default.
336    #[inline]
337    pub fn draw_background(mut self, value: bool) -> Self {
338        self.flags.set(WindowFlags::NO_BACKGROUND, !value);
339        self
340    }
341    /// Enables/disables loading and saving of settings (e.g. from/to an .ini file).
342    ///
343    /// Enabled by default.
344    #[inline]
345    pub fn save_settings(mut self, value: bool) -> Self {
346        self.flags.set(WindowFlags::NO_SAVED_SETTINGS, !value);
347        self
348    }
349    /// Enables/disables catching mouse input.
350    ///
351    /// Enabled by default.
352    /// Note: Hovering test will pass through when disabled
353    #[inline]
354    pub fn mouse_inputs(mut self, value: bool) -> Self {
355        self.flags.set(WindowFlags::NO_MOUSE_INPUTS, !value);
356        self
357    }
358    /// Enables/disables the menu bar.
359    ///
360    /// Disabled by default.
361    #[inline]
362    pub fn menu_bar(mut self, value: bool) -> Self {
363        self.flags.set(WindowFlags::MENU_BAR, value);
364        self
365    }
366    /// Enables/disables the horizontal scrollbar.
367    ///
368    /// Disabled by default.
369    #[inline]
370    pub fn horizontal_scrollbar(mut self, value: bool) -> Self {
371        self.flags.set(WindowFlags::HORIZONTAL_SCROLLBAR, value);
372        self
373    }
374    /// Enables/disables taking focus when transitioning from hidden to visible state.
375    ///
376    /// Enabled by default.
377    #[inline]
378    pub fn focus_on_appearing(mut self, value: bool) -> Self {
379        self.flags.set(WindowFlags::NO_FOCUS_ON_APPEARING, !value);
380        self
381    }
382    /// Enables/disables bringing the window to front when taking focus (e.g. clicking it or
383    /// programmatically giving it focus).
384    ///
385    /// Enabled by default.
386    #[inline]
387    pub fn bring_to_front_on_focus(mut self, value: bool) -> Self {
388        self.flags
389            .set(WindowFlags::NO_BRING_TO_FRONT_ON_FOCUS, !value);
390        self
391    }
392    /// When enabled, forces the vertical scrollbar to render regardless of the content size.
393    ///
394    /// Disabled by default.
395    #[inline]
396    pub fn always_vertical_scrollbar(mut self, value: bool) -> Self {
397        self.flags
398            .set(WindowFlags::ALWAYS_VERTICAL_SCROLLBAR, value);
399        self
400    }
401    /// When enabled, forces the horizontal scrollbar to render regardless of the content size.
402    ///
403    /// Disabled by default.
404    #[inline]
405    pub fn always_horizontal_scrollbar(mut self, value: bool) -> Self {
406        self.flags
407            .set(WindowFlags::ALWAYS_HORIZONTAL_SCROLLBAR, value);
408        self
409    }
410    /// When enabled, ensures child windows without border use `style.window_padding`.
411    ///
412    /// Disabled by default.
413    #[inline]
414    pub fn always_use_window_padding(mut self, value: bool) -> Self {
415        self.flags
416            .set(WindowFlags::ALWAYS_USE_WINDOW_PADDING, value);
417        self
418    }
419    /// Enables/disables gamepad/keyboard navigation within the window.
420    ///
421    /// Enabled by default.
422    #[inline]
423    pub fn nav_inputs(mut self, value: bool) -> Self {
424        self.flags.set(WindowFlags::NO_NAV_INPUTS, !value);
425        self
426    }
427    /// Enables/disables focusing toward this window with gamepad/keyboard navigation (e.g.
428    /// CTRL+TAB).
429    ///
430    /// Enabled by default.
431    #[inline]
432    pub fn nav_focus(mut self, value: bool) -> Self {
433        self.flags.set(WindowFlags::NO_NAV_FOCUS, !value);
434        self
435    }
436    /// When enabled, appends '*' to title without affecting the ID, as a convenience.
437    ///
438    /// Disabled by default.
439    #[inline]
440    pub fn unsaved_document(mut self, value: bool) -> Self {
441        self.flags.set(WindowFlags::UNSAVED_DOCUMENT, value);
442        self
443    }
444    /// Disable gamepad/keyboard navigation and focusing.
445    ///
446    /// Shorthand for
447    /// ```text
448    /// .nav_inputs(false)
449    /// .nav_focus(false)
450    /// ```
451    #[inline]
452    pub fn no_nav(mut self) -> Self {
453        self.flags |= WindowFlags::NO_NAV;
454        self
455    }
456    /// Disable all window decorations.
457    ///
458    /// Shorthand for
459    /// ```text
460    /// .title_bar(false)
461    /// .resizable(false)
462    /// .scroll_bar(false)
463    /// .collapsible(false)
464    /// ```
465    #[inline]
466    pub fn no_decoration(mut self) -> Self {
467        self.flags |= WindowFlags::NO_DECORATION;
468        self
469    }
470    /// Don't handle input.
471    ///
472    /// Shorthand for
473    /// ```text
474    /// .mouse_inputs(false)
475    /// .nav_inputs(false)
476    /// .nav_focus(false)
477    /// ```
478    #[inline]
479    pub fn no_inputs(mut self) -> Self {
480        self.flags |= WindowFlags::NO_INPUTS;
481        self
482    }
483    /// Creates a window and starts appending to it.
484    ///
485    /// Returns `Some(WindowToken)` if the window is visible. After content has been
486    /// rendered, the token must be ended by calling `.end()`.
487    ///
488    /// Returns `None` if the window is not visible and no content should be rendered.
489    #[must_use]
490    pub fn begin<'ui>(self, ui: &Ui<'ui>) -> Option<WindowToken<'ui>> {
491        if self.pos_cond != Condition::Never {
492            unsafe {
493                sys::igSetNextWindowPos(
494                    self.pos.into(),
495                    self.pos_cond as i32,
496                    self.pos_pivot.into(),
497                )
498            };
499        }
500        if self.size_cond != Condition::Never {
501            unsafe { sys::igSetNextWindowSize(self.size.into(), self.size_cond as i32) };
502        }
503        if let Some((size_min, size_max)) = self.size_constraints {
504            // TODO: callback support
505            unsafe {
506                sys::igSetNextWindowSizeConstraints(
507                    size_min.into(),
508                    size_max.into(),
509                    None,
510                    ptr::null_mut(),
511                )
512            };
513        }
514        if self.content_size[0] != 0.0 || self.content_size[1] != 0.0 {
515            unsafe { sys::igSetNextWindowContentSize(self.content_size.into()) };
516        }
517        if self.collapsed_cond != Condition::Never {
518            unsafe { sys::igSetNextWindowCollapsed(self.collapsed, self.collapsed_cond as i32) };
519        }
520        if self.focused {
521            unsafe { sys::igSetNextWindowFocus() };
522        }
523        if self.bg_alpha.is_finite() {
524            unsafe { sys::igSetNextWindowBgAlpha(self.bg_alpha) };
525        }
526        let should_render = unsafe {
527            sys::igBegin(
528                ui.scratch_txt(self.name),
529                self.opened
530                    .map(|x| x as *mut bool)
531                    .unwrap_or(ptr::null_mut()),
532                self.flags.bits() as i32,
533            )
534        };
535        if should_render {
536            Some(WindowToken::new(ui))
537        } else {
538            unsafe { sys::igEnd() };
539            None
540        }
541    }
542    /// Creates a window and runs a closure to construct the contents.
543    /// Returns the result of the closure, if it is called.
544    ///
545    /// Note: the closure is not called if no window content is visible (e.g. window is collapsed
546    /// or fully clipped).
547    pub fn build<R, F: FnOnce() -> R>(self, ui: &Ui<'_>, f: F) -> Option<R> {
548        self.begin(ui).map(|_window| f())
549    }
550}
551
552create_token!(
553    /// Tracks a window that can be ended by calling `.end()`
554    /// or by dropping.
555    pub struct WindowToken<'ui>;
556
557    /// Ends a window
558    drop { sys::igEnd() }
559);