dear_imgui_rs/fonts/
mod.rs1pub mod atlas;
7pub mod font;
8pub mod glyph;
9#[deprecated(
16 since = "0.2.0",
17 note = "ImGui 1.92+ recommends dynamic fonts with on-demand glyph loading; glyph ranges are kept for legacy compatibility"
18)]
19pub mod glyph_ranges;
20
21pub use atlas::*;
22pub use font::*;
23pub use glyph::*;
24#[allow(deprecated)]
25pub use glyph_ranges::*;
26
27use crate::Ui;
28
29fn assert_non_negative_finite_f32(caller: &str, name: &str, value: f32) {
30 assert!(value.is_finite(), "{caller} {name} must be finite");
31 assert!(value >= 0.0, "{caller} {name} must be non-negative");
32}
33
34fn assert_positive_finite_f32(caller: &str, name: &str, value: f32) {
35 assert!(value.is_finite(), "{caller} {name} must be finite");
36 assert!(value > 0.0, "{caller} {name} must be positive");
37}
38
39impl Ui {
41 #[doc(alias = "GetFont")]
43 pub fn current_font(&self) -> &Font {
44 unsafe { Font::from_raw(crate::sys::igGetFont() as *const _) }
45 }
46
47 #[doc(alias = "GetFontSize")]
49 pub fn current_font_size(&self) -> f32 {
50 unsafe { crate::sys::igGetFontSize() }
51 }
52
53 pub fn push_font_with_size(&self, font: Option<&Font>, size: f32) {
58 assert_non_negative_finite_f32("Ui::push_font_with_size()", "size", size);
59 unsafe {
60 let font_ptr = font.map_or(std::ptr::null_mut(), |f| {
61 crate::fonts::validate_font_for_current_context(f, "Ui::push_font_with_size()")
62 });
63 crate::sys::igPushFont(font_ptr, size);
64 }
65 }
66
67 pub fn with_font_and_size<F, R>(&self, font: Option<&Font>, size: f32, f: F) -> R
69 where
70 F: FnOnce() -> R,
71 {
72 self.push_font_with_size(font, size);
73 let _token = crate::FontStackToken::new(self);
74 f()
75 }
76
77 #[doc(alias = "GetFontTexUvWhitePixel")]
81 pub fn font_tex_uv_white_pixel(&self) -> [f32; 2] {
82 unsafe {
83 let uv = crate::sys::igGetFontTexUvWhitePixel();
84 [uv.x, uv.y]
85 }
86 }
87
88 #[doc(alias = "SetWindowFontScale")]
92 pub fn set_window_font_scale(&self, scale: f32) {
93 assert_positive_finite_f32("Ui::set_window_font_scale()", "scale", scale);
94
95 unsafe {
96 let window = crate::sys::igGetCurrentWindow();
97 if window.is_null() {
98 return;
99 }
100 (*window).FontWindowScale = scale;
101 crate::sys::igUpdateCurrentFontSize(0.0);
102 }
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 fn setup_context() -> crate::Context {
109 let mut ctx = crate::Context::create();
110 let _ = ctx.font_atlas_mut().build();
111 ctx.io_mut().set_display_size([128.0, 128.0]);
112 ctx.io_mut().set_delta_time(1.0 / 60.0);
113 ctx
114 }
115
116 #[test]
117 fn set_window_font_scale_updates_current_window_state() {
118 let mut ctx = setup_context();
119 let ui = ctx.frame();
120
121 ui.window("font_scale_test").build(|| {
122 let window = unsafe { crate::sys::igGetCurrentWindowRead() };
123 assert!(!window.is_null());
124 assert_eq!(unsafe { (*window).FontWindowScale }, 1.0);
125
126 ui.set_window_font_scale(1.5);
127
128 assert_eq!(unsafe { (*window).FontWindowScale }, 1.5);
129 });
130 }
131
132 #[test]
133 fn font_runtime_size_setters_validate_before_ffi() {
134 let mut ctx = setup_context();
135 let raw_ctx = ctx.as_raw();
136 let ui = ctx.frame();
137
138 let initial_stack_size = unsafe { (*raw_ctx).FontStack.Size };
139 ui.with_font_and_size(None, 0.0, || {});
140 assert_eq!(unsafe { (*raw_ctx).FontStack.Size }, initial_stack_size);
141
142 assert!(
143 std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
144 ui.push_font_with_size(None, -1.0);
145 }))
146 .is_err()
147 );
148 assert_eq!(unsafe { (*raw_ctx).FontStack.Size }, initial_stack_size);
149
150 ui.window("font_scale_invalid").build(|| {
151 let window = unsafe { crate::sys::igGetCurrentWindowRead() };
152 assert_eq!(unsafe { (*window).FontWindowScale }, 1.0);
153
154 assert!(
155 std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
156 ui.set_window_font_scale(f32::INFINITY);
157 }))
158 .is_err()
159 );
160 assert_eq!(unsafe { (*window).FontWindowScale }, 1.0);
161 });
162 }
163
164 #[test]
165 fn with_font_and_size_pops_after_panic() {
166 let mut ctx = setup_context();
167 let raw_ctx = ctx.as_raw();
168 let ui = ctx.frame();
169
170 let initial_stack_size = unsafe { (*raw_ctx).FontStack.Size };
171 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
172 ui.with_font_and_size(None, 18.0, || {
173 assert_eq!(unsafe { (*raw_ctx).FontStack.Size }, initial_stack_size + 1);
174 panic!("forced panic while font is pushed");
175 });
176 }));
177
178 assert!(result.is_err());
179 assert_eq!(unsafe { (*raw_ctx).FontStack.Size }, initial_stack_size);
180 }
181}