dear_imgui_rs/window/
mod.rs

1//! Windows and window utilities
2//!
3//! This module exposes the `Window` builder and related flags for creating
4//! top-level Dear ImGui windows. It also houses helpers for child windows,
5//! querying content-region size, and controlling window scrolling.
6//!
7//! Basic usage:
8//! ```no_run
9//! # use dear_imgui_rs::*;
10//! # let mut ctx = Context::create();
11//! # let ui = ctx.frame();
12//! ui.window("Hello")
13//!     .size([320.0, 240.0], Condition::FirstUseEver)
14//!     .position([60.0, 60.0], Condition::FirstUseEver)
15//!     .build(|| {
16//!         ui.text("Window contents go here");
17//!     });
18//! ```
19//!
20//! See also:
21//! - `child_window` for scoped child areas
22//! - `content_region` for available size queries
23//! - `scroll` for reading and setting scroll positions
24//!
25//! Quick example (flags + size/pos conditions):
26//! ```no_run
27//! # use dear_imgui_rs::*;
28//! # let mut ctx = Context::create();
29//! # let ui = ctx.frame();
30//! use dear_imgui_rs::WindowFlags;
31//! ui.window("Tools")
32//!     .flags(WindowFlags::NO_RESIZE | WindowFlags::NO_COLLAPSE)
33//!     .size([300.0, 200.0], Condition::FirstUseEver)
34//!     .position([50.0, 60.0], Condition::FirstUseEver)
35//!     .build(|| {
36//!         ui.text("Toolbox contents...");
37//!     });
38//! ```
39//!
40#![allow(
41    clippy::cast_possible_truncation,
42    clippy::cast_sign_loss,
43    clippy::as_conversions
44)]
45use bitflags::bitflags;
46use std::f32;
47
48use crate::sys;
49use crate::{Condition, Ui};
50
51pub(crate) mod child_window;
52pub(crate) mod content_region;
53pub(crate) mod scroll;
54
55// Window-focused/hovered helpers are available via utils.rs variants.
56// Window hovered/focused flag helpers are provided by crate::utils::HoveredFlags.
57
58bitflags! {
59    /// Configuration flags for windows
60    #[repr(transparent)]
61    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
62    pub struct WindowFlags: i32 {
63        /// Disable title-bar
64        const NO_TITLE_BAR = sys::ImGuiWindowFlags_NoTitleBar as i32;
65        /// Disable user resizing with the lower-right grip
66        const NO_RESIZE = sys::ImGuiWindowFlags_NoResize as i32;
67        /// Disable user moving the window
68        const NO_MOVE = sys::ImGuiWindowFlags_NoMove as i32;
69        /// Disable scrollbars (window can still scroll with mouse or programmatically)
70        const NO_SCROLLBAR = sys::ImGuiWindowFlags_NoScrollbar as i32;
71        /// Disable user vertically scrolling with mouse wheel
72        const NO_SCROLL_WITH_MOUSE = sys::ImGuiWindowFlags_NoScrollWithMouse as i32;
73        /// Disable user collapsing window by double-clicking on it
74        const NO_COLLAPSE = sys::ImGuiWindowFlags_NoCollapse as i32;
75        /// Resize every window to its content every frame
76        const ALWAYS_AUTO_RESIZE = sys::ImGuiWindowFlags_AlwaysAutoResize as i32;
77        /// Disable drawing background color (WindowBg, etc.) and outside border
78        const NO_BACKGROUND = sys::ImGuiWindowFlags_NoBackground as i32;
79        /// Never load/save settings in .ini file
80        const NO_SAVED_SETTINGS = sys::ImGuiWindowFlags_NoSavedSettings as i32;
81        /// Disable catching mouse, hovering test with pass through
82        const NO_MOUSE_INPUTS = sys::ImGuiWindowFlags_NoMouseInputs as i32;
83        /// Has a menu-bar
84        const MENU_BAR = sys::ImGuiWindowFlags_MenuBar as i32;
85        /// Allow horizontal scrollbar to appear (off by default)
86        const HORIZONTAL_SCROLLBAR = sys::ImGuiWindowFlags_HorizontalScrollbar as i32;
87        /// Disable taking focus when transitioning from hidden to visible state
88        const NO_FOCUS_ON_APPEARING = sys::ImGuiWindowFlags_NoFocusOnAppearing as i32;
89        /// Disable bringing window to front when taking focus (e.g. clicking on it or programmatically giving it focus)
90        const NO_BRING_TO_FRONT_ON_FOCUS = sys::ImGuiWindowFlags_NoBringToFrontOnFocus as i32;
91        /// Always show vertical scrollbar (even if ContentSize.y < Size.y)
92        const ALWAYS_VERTICAL_SCROLLBAR = sys::ImGuiWindowFlags_AlwaysVerticalScrollbar as i32;
93        /// Always show horizontal scrollbar (even if ContentSize.x < Size.x)
94        const ALWAYS_HORIZONTAL_SCROLLBAR = sys::ImGuiWindowFlags_AlwaysHorizontalScrollbar as i32;
95        /// No gamepad/keyboard navigation within the window
96        const NO_NAV_INPUTS = sys::ImGuiWindowFlags_NoNavInputs as i32;
97        /// No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by CTRL+TAB)
98        const NO_NAV_FOCUS = sys::ImGuiWindowFlags_NoNavFocus as i32;
99        /// Display a dot next to the title. When used in a tab/docking context, tab is selected when clicking the X + closure is not assumed (will wait for user to stop submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar.
100        const UNSAVED_DOCUMENT = sys::ImGuiWindowFlags_UnsavedDocument as i32;
101        /// Disable gamepad/keyboard navigation and focusing
102        const NO_NAV = Self::NO_NAV_INPUTS.bits() | Self::NO_NAV_FOCUS.bits();
103        /// Disable all window decorations
104        const NO_DECORATION = Self::NO_TITLE_BAR.bits() | Self::NO_RESIZE.bits() | Self::NO_SCROLLBAR.bits() | Self::NO_COLLAPSE.bits();
105        /// Disable all user interactions
106        const NO_INPUTS = Self::NO_MOUSE_INPUTS.bits() | Self::NO_NAV_INPUTS.bits();
107    }
108}
109
110/// Represents a window that can be built
111pub struct Window<'ui> {
112    ui: &'ui Ui,
113    name: String,
114    flags: WindowFlags,
115    size: Option<[f32; 2]>,
116    size_condition: Condition,
117    pos: Option<[f32; 2]>,
118    pos_condition: Condition,
119    content_size: Option<[f32; 2]>,
120    content_size_condition: Condition,
121    collapsed: Option<bool>,
122    collapsed_condition: Condition,
123    focused: Option<bool>,
124    bg_alpha: Option<f32>,
125}
126
127impl<'ui> Window<'ui> {
128    /// Creates a new window builder
129    pub fn new(ui: &'ui Ui, name: impl Into<String>) -> Self {
130        Self {
131            ui,
132            name: name.into(),
133            flags: WindowFlags::empty(),
134            size: None,
135            size_condition: Condition::Always,
136            pos: None,
137            pos_condition: Condition::Always,
138            content_size: None,
139            content_size_condition: Condition::Always,
140            collapsed: None,
141            collapsed_condition: Condition::Always,
142            focused: None,
143            bg_alpha: None,
144        }
145    }
146
147    /// Sets window flags
148    pub fn flags(mut self, flags: WindowFlags) -> Self {
149        self.flags = flags;
150        self
151    }
152
153    /// Sets window size
154    pub fn size(mut self, size: [f32; 2], condition: Condition) -> Self {
155        self.size = Some(size);
156        self.size_condition = condition;
157        self
158    }
159
160    /// Sets window position
161    pub fn position(mut self, pos: [f32; 2], condition: Condition) -> Self {
162        self.pos = Some(pos);
163        self.pos_condition = condition;
164        self
165    }
166
167    /// Sets window content size
168    pub fn content_size(mut self, size: [f32; 2], condition: Condition) -> Self {
169        self.content_size = Some(size);
170        self.content_size_condition = condition;
171        self
172    }
173
174    /// Sets window collapsed state
175    pub fn collapsed(mut self, collapsed: bool, condition: Condition) -> Self {
176        self.collapsed = Some(collapsed);
177        self.collapsed_condition = condition;
178        self
179    }
180
181    /// Sets window focused state
182    pub fn focused(mut self, focused: bool) -> Self {
183        self.focused = Some(focused);
184        self
185    }
186
187    /// Sets window background alpha
188    pub fn bg_alpha(mut self, alpha: f32) -> Self {
189        self.bg_alpha = Some(alpha);
190        self
191    }
192
193    /// Builds the window and calls the provided closure
194    pub fn build<F, R>(self, f: F) -> Option<R>
195    where
196        F: FnOnce() -> R,
197    {
198        let _token = self.begin()?;
199        Some(f())
200    }
201
202    /// Begins the window and returns a token
203    fn begin(self) -> Option<WindowToken<'ui>> {
204        use std::ffi::CString;
205
206        let name_cstr = CString::new(self.name).ok()?;
207
208        // Set window properties before beginning
209        if let Some(size) = self.size {
210            unsafe {
211                let size_vec = crate::sys::ImVec2 {
212                    x: size[0],
213                    y: size[1],
214                };
215                crate::sys::igSetNextWindowSize(size_vec, self.size_condition as i32);
216            }
217        }
218
219        if let Some(pos) = self.pos {
220            unsafe {
221                let pos_vec = crate::sys::ImVec2 {
222                    x: pos[0],
223                    y: pos[1],
224                };
225                let pivot_vec = crate::sys::ImVec2 { x: 0.0, y: 0.0 };
226                crate::sys::igSetNextWindowPos(pos_vec, self.pos_condition as i32, pivot_vec);
227            }
228        }
229
230        if let Some(content_size) = self.content_size {
231            unsafe {
232                let content_size_vec = crate::sys::ImVec2 {
233                    x: content_size[0],
234                    y: content_size[1],
235                };
236                crate::sys::igSetNextWindowContentSize(content_size_vec);
237            }
238        }
239
240        if let Some(collapsed) = self.collapsed {
241            unsafe {
242                crate::sys::igSetNextWindowCollapsed(collapsed, self.collapsed_condition as i32);
243            }
244        }
245
246        if let Some(focused) = self.focused
247            && focused
248        {
249            unsafe {
250                crate::sys::igSetNextWindowFocus();
251            }
252        }
253
254        if let Some(alpha) = self.bg_alpha {
255            unsafe {
256                crate::sys::igSetNextWindowBgAlpha(alpha);
257            }
258        }
259
260        // Begin the window
261        let mut open = true;
262        let result =
263            unsafe { crate::sys::igBegin(name_cstr.as_ptr(), &mut open, self.flags.bits()) };
264
265        // IMPORTANT: According to ImGui documentation, Begin/End calls must be balanced.
266        // If Begin returns false, we need to call End immediately and return None.
267        if result && open {
268            Some(WindowToken {
269                _phantom: std::marker::PhantomData,
270            })
271        } else {
272            // If Begin returns false, call End immediately and return None
273            unsafe {
274                crate::sys::igEnd();
275            }
276            None
277        }
278    }
279}
280
281/// Token representing an active window
282pub struct WindowToken<'ui> {
283    _phantom: std::marker::PhantomData<&'ui ()>,
284}
285
286impl<'ui> Drop for WindowToken<'ui> {
287    fn drop(&mut self) {
288        unsafe {
289            crate::sys::igEnd();
290        }
291    }
292}