dear_imgui_rs/
ui.rs

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