dear_imgui/fonts/
font.rs

1//! Font runtime data and operations
2//!
3//! This module provides the Font type which represents a single font instance
4//! with its associated runtime data and rendering operations.
5
6use super::FontId;
7use crate::sys;
8
9/// A font instance with runtime data
10///
11/// This represents a single font that can be used for text rendering.
12/// Fonts are managed by the FontAtlas and should not be created directly.
13///
14/// TODO: Currently using pointer wrapper approach for simplicity.
15/// Future improvement: Implement complete field mapping like imgui-rs for better type safety.
16///
17/// Note: Our dear-imgui-sys uses newer ImGui version with ImFontBaked architecture,
18/// while imgui-rs uses older version with direct field mapping. This difference
19/// requires careful consideration when implementing full mapping.
20#[repr(transparent)]
21#[derive(Debug)]
22pub struct Font(sys::ImFont);
23
24impl Font {
25    /// Constructs a shared reference from a raw pointer.
26    ///
27    /// Safety: caller guarantees the pointer is valid for the returned lifetime.
28    pub(crate) unsafe fn from_raw<'a>(raw: *const sys::ImFont) -> &'a Self {
29        unsafe { &*(raw as *const Self) }
30    }
31
32    /// Constructs a mutable reference from a raw pointer.
33    ///
34    /// Safety: caller guarantees the pointer is valid and uniquely borrowed for the returned lifetime.
35    pub(crate) unsafe fn from_raw_mut<'a>(raw: *mut sys::ImFont) -> &'a mut Self {
36        unsafe { &mut *(raw as *mut Self) }
37    }
38
39    /// Returns the identifier of this font
40    pub fn id(&self) -> FontId {
41        FontId(self.raw() as *const sys::ImFont)
42    }
43
44    /// Returns the raw ImFont pointer
45    pub fn raw(&self) -> *mut sys::ImFont {
46        self as *const Self as *mut sys::ImFont
47    }
48
49    /// Check if a glyph is available in this font
50    #[doc(alias = "IsGlyphInFont")]
51    pub fn is_glyph_in_font(&self, c: char) -> bool {
52        unsafe { sys::ImFont_IsGlyphInFont(self.raw(), c as u16) }
53    }
54
55    /// Calculate text size for the given text
56    #[doc(alias = "CalcTextSizeA")]
57    pub fn calc_text_size(
58        &self,
59        size: f32,
60        max_width: f32,
61        wrap_width: f32,
62        text: &str,
63    ) -> [f32; 2] {
64        unsafe {
65            let text_start = text.as_ptr() as *const std::os::raw::c_char;
66            let text_end = text_start.add(text.len());
67            let mut out = sys::ImVec2 { x: 0.0, y: 0.0 };
68            let mut out_remaining: *const std::os::raw::c_char = std::ptr::null();
69            sys::ImFont_CalcTextSizeA(
70                &mut out,
71                self.raw(),
72                size,
73                max_width,
74                wrap_width,
75                text_start,
76                text_end,
77                &mut out_remaining,
78            );
79            [out.x, out.y]
80        }
81    }
82
83    /// Calculate word wrap position for the given text
84    #[doc(alias = "CalcWordWrapPosition")]
85    pub fn calc_word_wrap_position(&self, size: f32, text: &str, wrap_width: f32) -> usize {
86        unsafe {
87            let text_start = text.as_ptr() as *const std::os::raw::c_char;
88            let text_end = text_start.add(text.len());
89            let wrap_pos = sys::ImFont_CalcWordWrapPosition(
90                self.raw(),
91                size,
92                text_start,
93                text_end,
94                wrap_width,
95            );
96            wrap_pos.offset_from(text_start) as usize
97        }
98    }
99
100    /// Clear output data (glyphs storage, UV coordinates)
101    #[doc(alias = "ClearOutputData")]
102    pub fn clear_output_data(&mut self) {
103        unsafe { sys::ImFont_ClearOutputData(self.raw()) }
104    }
105
106    /// Add character remapping
107    #[doc(alias = "AddRemapChar")]
108    pub fn add_remap_char(&mut self, from: char, to: char) {
109        unsafe { sys::ImFont_AddRemapChar(self.raw(), from as u16, to as u16) }
110    }
111
112    /// Check if a glyph range is unused
113    #[doc(alias = "IsGlyphRangeUnused")]
114    pub fn is_glyph_range_unused(&self, c_begin: u32, c_last: u32) -> bool {
115        unsafe { sys::ImFont_IsGlyphRangeUnused(self.raw(), c_begin, c_last) }
116    }
117}
118
119// NOTE: Do not mark Font as Send/Sync. It refers to memory owned by ImGui
120// context and is not thread-safe to move/share across threads.