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