Skip to main content

dear_imgui_rs/ui/
debug_tools.rs

1use super::*;
2
3impl Ui {
4    /// Renders Dear ImGui's demo window without its destructive font-atlas debug controls.
5    ///
6    /// This preserves the ordinary demo, Metrics/Debugger, and Style Editor controls. Only the
7    /// panels backed by upstream `ShowFontAtlas()` are omitted, so the safe API does not bypass
8    /// Rust's font-atlas lifetime and generation tracking.
9    ///
10    /// Use [`show_upstream_demo_window`](Self::show_upstream_demo_window) to opt into the exact
11    /// upstream window, including its font-atlas controls.
12    #[doc(alias = "ShowDemoWindow")]
13    pub fn show_demo_window(&self, opened: &mut bool) {
14        self.run_with_bound_context(|| unsafe {
15            crate::sys::dear_imgui_rs_show_demo_window_without_font_atlas(opened);
16        });
17    }
18
19    /// Renders the exact upstream Dear ImGui demo window, including font-atlas debug controls.
20    ///
21    /// Prefer [`show_demo_window`](Self::show_demo_window) unless the application deliberately
22    /// owns the full font-atlas mutation contract.
23    ///
24    /// # Safety
25    ///
26    /// With `BackendFlags::RENDERER_HAS_TEXTURES`, the upstream Fonts panel can delete an
27    /// `ImFont` and continue reading it in the same native call. Other destructive controls also
28    /// bypass Rust's atlas-generation tracking. The caller must prevent those controls from being
29    /// activated or otherwise uphold the native font-atlas contract.
30    pub unsafe fn show_upstream_demo_window(&self, opened: &mut bool) {
31        self.run_with_bound_context(|| unsafe {
32            crate::sys::igShowDemoWindow(opened);
33        });
34    }
35
36    /// Renders an about window.
37    ///
38    /// Displays the Dear ImGui version/credits, and build/system information.
39    #[doc(alias = "ShowAboutWindow")]
40    pub fn show_about_window(&self, opened: &mut bool) {
41        self.run_with_bound_context(|| unsafe {
42            crate::sys::igShowAboutWindow(opened);
43        });
44    }
45
46    /// Renders a metrics/debug window without its destructive font-atlas tree.
47    ///
48    /// Displays Dear ImGui internals: draw commands (with individual draw calls and vertices),
49    /// window list, basic internal state, etc.
50    #[doc(alias = "ShowMetricsWindow")]
51    pub fn show_metrics_window(&self, opened: &mut bool) {
52        self.run_with_bound_context(|| unsafe {
53            crate::sys::dear_imgui_rs_show_metrics_window_without_font_atlas(opened);
54        });
55    }
56
57    /// Renders the exact upstream metrics/debug window, including its font-atlas tree.
58    ///
59    /// # Safety
60    ///
61    /// The upstream Fonts tree can mutate or destroy font-atlas data while Rust font handles and
62    /// renderer state are live. The caller must uphold the native font-atlas contract.
63    pub unsafe fn show_upstream_metrics_window(&self, opened: &mut bool) {
64        self.run_with_bound_context(|| unsafe {
65            crate::sys::igShowMetricsWindow(opened);
66        });
67    }
68
69    /// Renders upstream's internal Font Atlas debug panel for this context.
70    ///
71    /// This is the isolated font-specific part omitted from the safe demo, metrics, and style
72    /// editor APIs.
73    ///
74    /// # Safety
75    ///
76    /// The panel exposes destructive atlas operations and may continue using native font pointers
77    /// after a control mutates the atlas. The caller must uphold the native font-atlas contract.
78    #[doc(alias = "ShowFontAtlas")]
79    pub unsafe fn show_font_atlas_debug_panel(&self) {
80        self.run_with_bound_context(|| unsafe {
81            crate::sys::dear_imgui_rs_show_font_atlas_debug_panel();
82        });
83    }
84
85    /// Renders a basic help/info block (not a window)
86    #[doc(alias = "ShowUserGuide")]
87    pub fn show_user_guide(&self) {
88        self.run_with_bound_context(|| unsafe {
89            crate::sys::igShowUserGuide();
90        });
91    }
92
93    // ============================================================================
94    // Additional Demo, Debug, Information (non-duplicate methods)
95    // ============================================================================
96
97    /// Renders a debug log window.
98    ///
99    /// Displays a simplified log of important dear imgui events.
100    #[doc(alias = "ShowDebugLogWindow")]
101    pub fn show_debug_log_window(&self, opened: &mut bool) {
102        self.run_with_bound_context(|| unsafe {
103            sys::igShowDebugLogWindow(opened);
104        });
105    }
106
107    /// Renders an ID stack tool window.
108    ///
109    /// Hover items with mouse to query information about the source of their unique ID.
110    #[doc(alias = "ShowIDStackToolWindow")]
111    pub fn show_id_stack_tool_window(&self, opened: &mut bool) {
112        self.run_with_bound_context(|| unsafe {
113            sys::igShowIDStackToolWindow(opened);
114        });
115    }
116
117    /// Renders a table that breaks `text` down into UTF-8 bytes and codepoints.
118    ///
119    /// This is intended for diagnosing text encoding and missing-glyph issues.
120    ///
121    /// # Panics
122    ///
123    /// Panics if `text` contains an interior NUL byte, which the upstream
124    /// NUL-terminated API cannot represent.
125    #[doc(alias = "DebugTextEncoding")]
126    pub fn debug_text_encoding(&self, text: impl AsRef<str>) {
127        let text = text.as_ref();
128        assert!(
129            !text.contains('\0'),
130            "Ui::debug_text_encoding() text must not contain interior NUL bytes"
131        );
132        let text = self.scratch_txt(text);
133        self.run_with_bound_context(|| unsafe { sys::igDebugTextEncoding(text) });
134    }
135
136    /// Temporarily flashes a style color in Dear ImGui's debug tools.
137    #[doc(alias = "DebugFlashStyleColor")]
138    pub fn debug_flash_style_color(&self, color: crate::StyleColor) {
139        self.run_with_bound_context(|| unsafe { sys::igDebugFlashStyleColor(color as i32) });
140    }
141
142    /// Starts Dear ImGui's interactive item picker debug tool.
143    #[doc(alias = "DebugStartItemPicker")]
144    pub fn debug_start_item_picker(&self) {
145        self.run_with_bound_context(|| unsafe { sys::igDebugStartItemPicker() });
146    }
147
148    /// Returns the Dear ImGui version string
149    #[doc(alias = "GetVersion")]
150    pub fn get_version(&self) -> &str {
151        self.run_with_bound_context(|| unsafe {
152            let version_ptr = sys::igGetVersion();
153            if version_ptr.is_null() {
154                return "Unknown";
155            }
156            let c_str = std::ffi::CStr::from_ptr(version_ptr);
157            c_str.to_str().unwrap_or("Unknown")
158        })
159    }
160}
161
162#[cfg(test)]
163mod tests {
164    #[test]
165    fn safe_debug_windows_keep_font_atlas_controls_explicit() {
166        let _: fn(&crate::Ui, &mut bool) = crate::Ui::show_demo_window;
167        let _: fn(&crate::Ui, &mut bool) = crate::Ui::show_metrics_window;
168        let _: unsafe fn(&crate::Ui, &mut bool) = crate::Ui::show_upstream_demo_window;
169        let _: unsafe fn(&crate::Ui, &mut bool) = crate::Ui::show_upstream_metrics_window;
170        let _: unsafe fn(&crate::Ui) = crate::Ui::show_font_atlas_debug_panel;
171    }
172
173    #[test]
174    fn public_debug_helpers_are_safe_to_call_in_a_frame() {
175        let mut ctx = crate::Context::create();
176        ctx.io_mut().set_display_size([128.0, 128.0]);
177        ctx.io_mut().set_delta_time(1.0 / 60.0);
178        let _ = ctx.font_atlas().build();
179        let ui = ctx.frame();
180
181        let mut demo_open = true;
182        ui.show_demo_window(&mut demo_open);
183        let mut metrics_open = true;
184        ui.show_metrics_window(&mut metrics_open);
185
186        ui.window("debug_helpers").build(|| {
187            ui.show_default_style_editor();
188            let cursor_y = ui.cursor_pos_y();
189            ui.debug_text_encoding("A UTF-8 string: 界");
190            assert!(ui.cursor_pos_y() > cursor_y);
191
192            ui.debug_flash_style_color(crate::StyleColor::Text);
193            ui.debug_start_item_picker();
194        });
195
196        assert!(
197            std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
198                ui.debug_text_encoding("A\0B");
199            }))
200            .is_err()
201        );
202    }
203}