dear_imgui/
ui.rs

1use crate::draw::DrawListMut;
2use crate::input::MouseCursor;
3use crate::internal::RawWrapper;
4use crate::string::UiBuffer;
5use crate::sys;
6use crate::texture::TextureRef;
7use std::cell::UnsafeCell;
8
9/// Represents the Dear ImGui user interface for one frame
10#[derive(Debug)]
11pub struct Ui {
12    /// Internal buffer for string operations
13    buffer: UnsafeCell<UiBuffer>,
14}
15
16impl Ui {
17    /// Returns a reference to the main Dear ImGui viewport (safe wrapper)
18    ///
19    /// Same viewport used by `dockspace_over_main_viewport()`.
20    #[doc(alias = "GetMainViewport")]
21    pub fn main_viewport(&self) -> &'static crate::platform_io::Viewport {
22        crate::platform_io::Viewport::main()
23    }
24    /// Creates a new Ui instance
25    ///
26    /// This should only be called by Context::create()
27    pub(crate) fn new() -> Self {
28        Ui {
29            buffer: UnsafeCell::new(UiBuffer::new(1024)),
30        }
31    }
32
33    /// Returns an immutable reference to the inputs/outputs object
34    #[doc(alias = "GetIO")]
35    pub fn io(&self) -> &crate::io::Io {
36        unsafe { &*(sys::igGetIO_Nil() as *const crate::io::Io) }
37    }
38
39    /// Internal method to push a single text to our scratch buffer.
40    pub(crate) fn scratch_txt(&self, txt: impl AsRef<str>) -> *const std::os::raw::c_char {
41        unsafe {
42            let handle = &mut *self.buffer.get();
43            handle.scratch_txt(txt)
44        }
45    }
46
47    /// Internal method to push an option text to our scratch buffer.
48    pub(crate) fn scratch_txt_opt(
49        &self,
50        txt: Option<impl AsRef<str>>,
51    ) -> *const std::os::raw::c_char {
52        unsafe {
53            let handle = &mut *self.buffer.get();
54            handle.scratch_txt_opt(txt)
55        }
56    }
57
58    /// Helper method for two strings
59    pub(crate) fn scratch_txt_two(
60        &self,
61        txt_0: impl AsRef<str>,
62        txt_1: impl AsRef<str>,
63    ) -> (*const std::os::raw::c_char, *const std::os::raw::c_char) {
64        unsafe {
65            let handle = &mut *self.buffer.get();
66            handle.scratch_txt_two(txt_0, txt_1)
67        }
68    }
69
70    /// Helper method with one optional value
71    pub(crate) fn scratch_txt_with_opt(
72        &self,
73        txt_0: impl AsRef<str>,
74        txt_1: Option<impl AsRef<str>>,
75    ) -> (*const std::os::raw::c_char, *const std::os::raw::c_char) {
76        unsafe {
77            let handle = &mut *self.buffer.get();
78            handle.scratch_txt_with_opt(txt_0, txt_1)
79        }
80    }
81
82    /// Get access to the scratch buffer for complex string operations
83    pub(crate) fn scratch_buffer(&self) -> &UnsafeCell<UiBuffer> {
84        &self.buffer
85    }
86
87    /// Display text
88    #[doc(alias = "TextUnformatted")]
89    pub fn text<T: AsRef<str>>(&self, text: T) {
90        let s = text.as_ref();
91        unsafe {
92            let start = s.as_ptr();
93            let end = start.add(s.len());
94            crate::sys::igTextUnformatted(
95                start as *const std::os::raw::c_char,
96                end as *const std::os::raw::c_char,
97            );
98        }
99    }
100
101    /// Access to the current window's draw list
102    #[doc(alias = "GetWindowDrawList")]
103    pub fn get_window_draw_list(&self) -> DrawListMut<'_> {
104        DrawListMut::window(self)
105    }
106
107    /// Access to the background draw list
108    #[doc(alias = "GetBackgroundDrawList")]
109    pub fn get_background_draw_list(&self) -> DrawListMut<'_> {
110        DrawListMut::background(self)
111    }
112
113    /// Access to the foreground draw list
114    #[doc(alias = "GetForegroundDrawList")]
115    pub fn get_foreground_draw_list(&self) -> DrawListMut<'_> {
116        DrawListMut::foreground(self)
117    }
118
119    /// Creates a window builder
120    pub fn window(&self, name: impl Into<String>) -> crate::window::Window<'_> {
121        crate::window::Window::new(self, name)
122    }
123
124    /// Renders a demo window (previously called a test window), which demonstrates most
125    /// Dear ImGui features.
126    #[doc(alias = "ShowDemoWindow")]
127    pub fn show_demo_window(&self, opened: &mut bool) {
128        unsafe {
129            crate::sys::igShowDemoWindow(opened);
130        }
131    }
132
133    /// Convenience: draw an image with background and tint (ImGui 1.92+)
134    ///
135    /// Equivalent to using `image_config(...).build_with_bg(bg, tint)` but in one call.
136    #[doc(alias = "ImageWithBg")]
137    pub fn image_with_bg(
138        &self,
139        texture: impl Into<TextureRef>,
140        size: [f32; 2],
141        bg_color: [f32; 4],
142        tint_color: [f32; 4],
143    ) {
144        crate::widget::image::Image::new(self, texture, size).build_with_bg(bg_color, tint_color)
145    }
146
147    /// Renders an about window.
148    ///
149    /// Displays the Dear ImGui version/credits, and build/system information.
150    #[doc(alias = "ShowAboutWindow")]
151    pub fn show_about_window(&self, opened: &mut bool) {
152        unsafe {
153            crate::sys::igShowAboutWindow(opened);
154        }
155    }
156
157    /// Renders a metrics/debug window.
158    ///
159    /// Displays Dear ImGui internals: draw commands (with individual draw calls and vertices),
160    /// window list, basic internal state, etc.
161    #[doc(alias = "ShowMetricsWindow")]
162    pub fn show_metrics_window(&self, opened: &mut bool) {
163        unsafe {
164            crate::sys::igShowMetricsWindow(opened);
165        }
166    }
167
168    /// Renders a style editor block (not a window) for the given `Style` structure
169    #[doc(alias = "ShowStyleEditor")]
170    pub fn show_style_editor(&self, style: &mut crate::style::Style) {
171        unsafe {
172            crate::sys::igShowStyleEditor(style.raw_mut());
173        }
174    }
175
176    /// Renders a style editor block (not a window) for the currently active style
177    #[doc(alias = "ShowStyleEditor")]
178    pub fn show_default_style_editor(&self) {
179        unsafe {
180            crate::sys::igShowStyleEditor(std::ptr::null_mut());
181        }
182    }
183
184    /// Renders a basic help/info block (not a window)
185    #[doc(alias = "ShowUserGuide")]
186    pub fn show_user_guide(&self) {
187        unsafe {
188            crate::sys::igShowUserGuide();
189        }
190    }
191
192    // Drag widgets
193
194    /// Creates a drag float slider
195    #[doc(alias = "DragFloat")]
196    pub fn drag_float(&self, label: impl AsRef<str>, value: &mut f32) -> bool {
197        crate::widget::drag::Drag::new(label).build(self, value)
198    }
199
200    /// Creates a drag float slider with configuration
201    #[doc(alias = "DragFloat")]
202    pub fn drag_float_config<L: AsRef<str>>(&self, label: L) -> crate::widget::drag::Drag<f32, L> {
203        crate::widget::drag::Drag::new(label)
204    }
205
206    /// Creates a drag int slider
207    #[doc(alias = "DragInt")]
208    pub fn drag_int(&self, label: impl AsRef<str>, value: &mut i32) -> bool {
209        crate::widget::drag::Drag::new(label).build(self, value)
210    }
211
212    /// Creates a drag int slider with configuration
213    #[doc(alias = "DragInt")]
214    pub fn drag_int_config<L: AsRef<str>>(&self, label: L) -> crate::widget::drag::Drag<i32, L> {
215        crate::widget::drag::Drag::new(label)
216    }
217
218    /// Creates a drag float range slider
219    #[doc(alias = "DragFloatRange2")]
220    pub fn drag_float_range2(&self, label: impl AsRef<str>, min: &mut f32, max: &mut f32) -> bool {
221        crate::widget::drag::DragRange::<f32, _>::new(label).build(self, min, max)
222    }
223
224    /// Creates a drag float range slider with configuration
225    #[doc(alias = "DragFloatRange2")]
226    pub fn drag_float_range2_config<L: AsRef<str>>(
227        &self,
228        label: L,
229    ) -> crate::widget::drag::DragRange<f32, L> {
230        crate::widget::drag::DragRange::new(label)
231    }
232
233    /// Creates a drag int range slider
234    #[doc(alias = "DragIntRange2")]
235    pub fn drag_int_range2(&self, label: impl AsRef<str>, min: &mut i32, max: &mut i32) -> bool {
236        crate::widget::drag::DragRange::<i32, _>::new(label).build(self, min, max)
237    }
238
239    /// Creates a drag int range slider with configuration
240    #[doc(alias = "DragIntRange2")]
241    pub fn drag_int_range2_config<L: AsRef<str>>(
242        &self,
243        label: L,
244    ) -> crate::widget::drag::DragRange<i32, L> {
245        crate::widget::drag::DragRange::new(label)
246    }
247
248    /// Returns the currently desired mouse cursor type
249    ///
250    /// Returns `None` if no cursor should be displayed
251    #[doc(alias = "GetMouseCursor")]
252    pub fn mouse_cursor(&self) -> Option<MouseCursor> {
253        unsafe {
254            match sys::igGetMouseCursor() {
255                sys::ImGuiMouseCursor_Arrow => Some(MouseCursor::Arrow),
256                sys::ImGuiMouseCursor_TextInput => Some(MouseCursor::TextInput),
257                sys::ImGuiMouseCursor_ResizeAll => Some(MouseCursor::ResizeAll),
258                sys::ImGuiMouseCursor_ResizeNS => Some(MouseCursor::ResizeNS),
259                sys::ImGuiMouseCursor_ResizeEW => Some(MouseCursor::ResizeEW),
260                sys::ImGuiMouseCursor_ResizeNESW => Some(MouseCursor::ResizeNESW),
261                sys::ImGuiMouseCursor_ResizeNWSE => Some(MouseCursor::ResizeNWSE),
262                sys::ImGuiMouseCursor_Hand => Some(MouseCursor::Hand),
263                sys::ImGuiMouseCursor_NotAllowed => Some(MouseCursor::NotAllowed),
264                _ => None,
265            }
266        }
267    }
268
269    /// Sets the desired mouse cursor type
270    ///
271    /// Passing `None` hides the mouse cursor
272    #[doc(alias = "SetMouseCursor")]
273    pub fn set_mouse_cursor(&self, cursor_type: Option<MouseCursor>) {
274        unsafe {
275            let val: sys::ImGuiMouseCursor = cursor_type
276                .map(|x| x as sys::ImGuiMouseCursor)
277                .unwrap_or(sys::ImGuiMouseCursor_None);
278            sys::igSetMouseCursor(val);
279        }
280    }
281
282    // ============================================================================
283    // Focus and Navigation
284    // ============================================================================
285
286    /// Focuses keyboard on the next widget.
287    ///
288    /// This is the equivalent to [set_keyboard_focus_here_with_offset](Self::set_keyboard_focus_here_with_offset)
289    /// with `offset` set to 0.
290    #[doc(alias = "SetKeyboardFocusHere")]
291    pub fn set_keyboard_focus_here(&self) {
292        self.set_keyboard_focus_here_with_offset(0);
293    }
294
295    /// Focuses keyboard on a widget relative to current position.
296    ///
297    /// Use positive offset to focus on next widgets, negative offset to focus on previous widgets.
298    #[doc(alias = "SetKeyboardFocusHere")]
299    pub fn set_keyboard_focus_here_with_offset(&self, offset: i32) {
300        unsafe {
301            sys::igSetKeyboardFocusHere(offset);
302        }
303    }
304
305    /// Set next item to be open by default.
306    ///
307    /// This is useful for tree nodes, collapsing headers, etc.
308    #[doc(alias = "SetNextItemOpen")]
309    pub fn set_next_item_open(&self, is_open: bool) {
310        unsafe {
311            sys::igSetNextItemOpen(is_open, 0); // 0 = ImGuiCond_Always
312        }
313    }
314
315    /// Set next item to be open by default with condition.
316    #[doc(alias = "SetNextItemOpen")]
317    pub fn set_next_item_open_with_cond(&self, is_open: bool, cond: crate::Condition) {
318        unsafe { sys::igSetNextItemOpen(is_open, cond as sys::ImGuiCond) }
319    }
320
321    /// Set next item width.
322    ///
323    /// Set to 0.0 for default width, >0.0 for explicit width, <0.0 for relative width.
324    #[doc(alias = "SetNextItemWidth")]
325    pub fn set_next_item_width(&self, item_width: f32) {
326        unsafe {
327            sys::igSetNextItemWidth(item_width);
328        }
329    }
330
331    // ============================================================================
332    // Style Access
333    // ============================================================================
334
335    /// Returns a shared reference to the current [`Style`].
336    ///
337    /// ## Safety
338    ///
339    /// This function is tagged as `unsafe` because pushing via
340    /// [`push_style_color`](crate::Ui::push_style_color) or
341    /// [`push_style_var`](crate::Ui::push_style_var) or popping via
342    /// [`ColorStackToken::pop`](crate::ColorStackToken::pop) or
343    /// [`StyleStackToken::pop`](crate::StyleStackToken::pop) will modify the values in the returned
344    /// shared reference. Therefore, you should not retain this reference across calls to push and
345    /// pop. The [`clone_style`](Ui::clone_style) version may instead be used to avoid `unsafe`.
346    #[doc(alias = "GetStyle")]
347    pub unsafe fn style(&self) -> &crate::Style {
348        unsafe {
349            // safe because Style is a transparent wrapper around sys::ImGuiStyle
350            &*(sys::igGetStyle() as *const crate::Style)
351        }
352    }
353
354    /// Returns a copy of the current style.
355    ///
356    /// This is a safe alternative to [`style`](Self::style) that avoids the lifetime issues.
357    #[doc(alias = "GetStyle")]
358    pub fn clone_style(&self) -> crate::Style {
359        unsafe { self.style().clone() }
360    }
361
362    /// Apply the built-in Dark style to the current style.
363    #[doc(alias = "StyleColorsDark")]
364    pub fn style_colors_dark(&self) {
365        unsafe { sys::igStyleColorsDark(std::ptr::null_mut()) }
366    }
367
368    /// Apply the built-in Light style to the current style.
369    #[doc(alias = "StyleColorsLight")]
370    pub fn style_colors_light(&self) {
371        unsafe { sys::igStyleColorsLight(std::ptr::null_mut()) }
372    }
373
374    /// Apply the built-in Classic style to the current style.
375    #[doc(alias = "StyleColorsClassic")]
376    pub fn style_colors_classic(&self) {
377        unsafe { sys::igStyleColorsClassic(std::ptr::null_mut()) }
378    }
379
380    /// Write the Dark style values into the provided [`Style`] object.
381    #[doc(alias = "StyleColorsDark")]
382    pub fn style_colors_dark_into(&self, dst: &mut crate::Style) {
383        unsafe { sys::igStyleColorsDark(dst as *mut _ as *mut sys::ImGuiStyle) }
384    }
385
386    /// Write the Light style values into the provided [`Style`] object.
387    #[doc(alias = "StyleColorsLight")]
388    pub fn style_colors_light_into(&self, dst: &mut crate::Style) {
389        unsafe { sys::igStyleColorsLight(dst as *mut _ as *mut sys::ImGuiStyle) }
390    }
391
392    /// Write the Classic style values into the provided [`Style`] object.
393    #[doc(alias = "StyleColorsClassic")]
394    pub fn style_colors_classic_into(&self, dst: &mut crate::Style) {
395        unsafe { sys::igStyleColorsClassic(dst as *mut _ as *mut sys::ImGuiStyle) }
396    }
397
398    /// Returns DPI scale currently associated to the current window's viewport.
399    #[doc(alias = "GetWindowDpiScale")]
400    pub fn window_dpi_scale(&self) -> f32 {
401        unsafe { sys::igGetWindowDpiScale() }
402    }
403
404    /// Display a text label with a boolean value (for quick debug UIs).
405    #[doc(alias = "Value")]
406    pub fn value_bool(&self, prefix: impl AsRef<str>, v: bool) {
407        unsafe { sys::igValue_Bool(self.scratch_txt(prefix), v) }
408    }
409
410    /// Get current window width (shortcut for `GetWindowSize().x`).
411    #[doc(alias = "GetWindowWidth")]
412    pub fn window_width(&self) -> f32 {
413        unsafe { sys::igGetWindowWidth() }
414    }
415
416    /// Get current window height (shortcut for `GetWindowSize().y`).
417    #[doc(alias = "GetWindowHeight")]
418    pub fn window_height(&self) -> f32 {
419        unsafe { sys::igGetWindowHeight() }
420    }
421
422    /// Get current window position in screen space.
423    #[doc(alias = "GetWindowPos")]
424    pub fn window_pos(&self) -> [f32; 2] {
425        unsafe {
426            let mut v = sys::ImVec2 { x: 0.0, y: 0.0 };
427            sys::igGetWindowPos(&mut v);
428            [v.x, v.y]
429        }
430    }
431
432    /// Get current window size.
433    #[doc(alias = "GetWindowSize")]
434    pub fn window_size(&self) -> [f32; 2] {
435        unsafe {
436            let mut v = sys::ImVec2 { x: 0.0, y: 0.0 };
437            sys::igGetWindowSize(&mut v);
438            [v.x, v.y]
439        }
440    }
441
442    // ============================================================================
443    // Additional Demo, Debug, Information (non-duplicate methods)
444    // ============================================================================
445
446    /// Renders a debug log window.
447    ///
448    /// Displays a simplified log of important dear imgui events.
449    #[doc(alias = "ShowDebugLogWindow")]
450    pub fn show_debug_log_window(&self, opened: &mut bool) {
451        unsafe {
452            sys::igShowDebugLogWindow(opened);
453        }
454    }
455
456    /// Renders an ID stack tool window.
457    ///
458    /// Hover items with mouse to query information about the source of their unique ID.
459    #[doc(alias = "ShowIDStackToolWindow")]
460    pub fn show_id_stack_tool_window(&self, opened: &mut bool) {
461        unsafe {
462            sys::igShowIDStackToolWindow(opened);
463        }
464    }
465
466    /// Renders a style selector combo box.
467    ///
468    /// Returns true when a different style was selected.
469    #[doc(alias = "ShowStyleSelector")]
470    pub fn show_style_selector(&self, label: impl AsRef<str>) -> bool {
471        unsafe { sys::igShowStyleSelector(self.scratch_txt(label)) }
472    }
473
474    /// Renders a font selector combo box.
475    #[doc(alias = "ShowFontSelector")]
476    pub fn show_font_selector(&self, label: impl AsRef<str>) {
477        unsafe {
478            sys::igShowFontSelector(self.scratch_txt(label));
479        }
480    }
481
482    /// Returns the Dear ImGui version string
483    #[doc(alias = "GetVersion")]
484    pub fn get_version(&self) -> &str {
485        unsafe {
486            let version_ptr = sys::igGetVersion();
487            let c_str = std::ffi::CStr::from_ptr(version_ptr);
488            c_str.to_str().unwrap_or("Unknown")
489        }
490    }
491}