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