Skip to main content

dear_imgui_rs/stacks/
font.rs

1use crate::fonts::FontId;
2use crate::{Ui, sys};
3
4/// # Parameter stacks (shared)
5impl Ui {
6    /// Switches to the given font at its configured reference size.
7    ///
8    /// Dear ImGui 1.92 can rasterize a font at multiple sizes. This convenience
9    /// method preserves the pre-1.92 behavior by using the reference size
10    /// supplied when the font was added. Use [`Ui::push_font_with_size`] to
11    /// preserve the current size or select another runtime size explicitly.
12    /// A font without a reference size also preserves the current size.
13    ///
14    /// Returns a `FontStackToken` that must be popped by calling `.pop()`
15    ///
16    /// # Panics
17    ///
18    /// Panics before calling Dear ImGui if the `FontId` came from a different atlas,
19    /// was invalidated by font atlas mutation, or is no longer present in the
20    /// current context's atlas.
21    ///
22    /// # Examples
23    ///
24    /// ```no_run
25    /// # use dear_imgui_rs::*;
26    /// # let mut ctx = Context::create();
27    /// # let font_data_sources = [];
28    /// // At initialization time
29    /// let my_custom_font = ctx.font_atlas().add_font(&font_data_sources);
30    /// # let ui = ctx.frame();
31    /// // During UI construction
32    /// let font = ui.push_font(my_custom_font);
33    /// ui.text("I use the custom font!");
34    /// font.pop();
35    /// ```
36    #[doc(alias = "PushFont")]
37    pub fn push_font(&self, id: FontId) -> FontStackToken<'_> {
38        self.run_with_bound_context(|| unsafe {
39            let font_ptr =
40                crate::fonts::validate_font_id_for_current_context(id, "Ui::push_font()");
41            sys::igPushFont(font_ptr, (*font_ptr).LegacySize);
42        });
43        FontStackToken::new(self)
44    }
45}
46
47create_token!(
48    /// Tracks a font pushed to the font stack that can be popped by calling `.end()`
49    /// or by dropping.
50    #[doc(alias = "PopFont")]
51    pub struct FontStackToken<'ui>;
52
53    pop crate::scope::NativeScopePop::PopFont;
54
55    /// Pops a change from the font stack.
56    drop { unsafe { sys::igPopFont() } }
57);
58
59impl FontStackToken<'_> {
60    /// Pops a change from the font stack.
61    ///
62    /// # Panics
63    ///
64    /// Panics under the same conditions as [`Self::end`].
65    pub fn pop(self) {
66        self.end()
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    const ROBOTO_MEDIUM: &[u8] = include_bytes!(concat!(
73        env!("CARGO_MANIFEST_DIR"),
74        "/../dear-imgui-sys/third-party/cimgui/imgui/misc/fonts/Roboto-Medium.ttf"
75    ));
76
77    #[test]
78    fn push_font_uses_the_size_supplied_when_the_font_was_added() {
79        let mut ctx = crate::Context::create();
80        let small = ctx
81            .font_atlas()
82            .add_font(&[crate::FontSource::default_font_with_size(13.0)]);
83        let large = ctx
84            .font_atlas()
85            .add_font(&[crate::FontSource::default_font_with_size(29.0)]);
86        assert_eq!(small.reference_size(), Some(13.0));
87        assert_eq!(large.reference_size(), Some(29.0));
88        ctx.font_atlas()
89            .try_claim_legacy_renderer()
90            .expect("legacy renderer font atlas should be available")
91            .build();
92        ctx.io_mut().set_display_size([128.0, 128.0]);
93        ctx.io_mut().set_delta_time(1.0 / 60.0);
94
95        let ui = ctx.frame();
96        assert_eq!(ui.current_font(), small);
97        assert_eq!(ui.current_font_size(), 13.0);
98
99        {
100            let _font = ui.push_font(large);
101            assert_eq!(ui.current_font(), large);
102            assert_eq!(ui.current_font_size(), 29.0);
103        }
104
105        assert_eq!(ui.current_font(), small);
106        assert_eq!(ui.current_font_size(), 13.0);
107    }
108
109    #[test]
110    fn push_font_preserves_current_size_without_a_reference_size() {
111        let mut ctx = crate::Context::create();
112        let _consumer = ctx
113            .create_synchronous_renderer_consumer()
114            .expect("the managed renderer consumer should attach");
115        let small = ctx
116            .font_atlas()
117            .add_font(&[crate::FontSource::default_font_with_size(13.0)]);
118        // SAFETY: the vendored bytes contain the complete, unmodified Roboto Medium TTF.
119        let dynamic = ctx
120            .font_atlas()
121            .add_font(&[unsafe { crate::FontSource::ttf_data(ROBOTO_MEDIUM) }]);
122        assert_eq!(dynamic.reference_size(), None);
123        ctx.io_mut().set_display_size([128.0, 128.0]);
124        ctx.io_mut().set_delta_time(1.0 / 60.0);
125        ctx.io_mut()
126            .set_backend_flags(crate::BackendFlags::RENDERER_HAS_TEXTURES);
127
128        let ui = ctx.frame();
129        assert_eq!(ui.current_font(), small);
130        assert_eq!(ui.current_font_size(), 13.0);
131
132        let _font = ui.push_font(dynamic);
133        assert_eq!(ui.current_font(), dynamic);
134        assert_eq!(ui.current_font_size(), 13.0);
135    }
136}