native_windows_gui2/resources/
font.rs

1use crate::NwgError;
2use crate::win32::base_helper::{from_utf16, to_utf16};
3use crate::win32::resources_helper as rh;
4use std::ptr;
5use winapi::shared::windef::HFONT;
6use winapi::um::winnt::HANDLE;
7
8use std::sync::Mutex;
9
10lazy_static! {
11    /// Default font to use when creating controls. Set using `Font::set_global_default` && get using `Font::global_default()`
12    static ref DEFAULT_FONT: Mutex<Option<Font>> = {
13        Mutex::new(None)
14    };
15}
16
17pub struct MemFont(pub HANDLE);
18
19/**
20Represent a font parameters. Returned by the font dialog when the user selected a font.
21Can also be used to create a Font resource using `Font::from_info`
22For more information on the parameters see: https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-logfonta
23*/
24#[derive(Debug, Clone)]
25pub struct FontInfo {
26    /// The size of the selected font, in units of 1/10 of a point
27    pub point_size: u32,
28    /// Specifies the height, in logical units, of the font's character cell or character.
29    pub height: i32,
30    /// Specifies the width, in logical units, of characters in the font.
31    pub width: i32,
32    /// Contains the angle, in tenths of degrees, between the escapement vector and the x-axis of the device. The escapement vector is parallel to the base line of a row of text.
33    pub escapement: i32,
34    /// Specifies the angle, in tenths of degrees, between each character's base line and the x-axis of the device.
35    pub orientation: i32,
36    /// Specifies the weight of the font in the range from 0 through 1000.
37    pub weight: i32,
38    /// Specifies an italic font if set to TRUE
39    pub italic: bool,
40    /// Specifies an underlined font if set to TRUE.
41    pub underline: bool,
42    /// Specifies a strikeout font if set to TRUE.
43    pub strike_out: bool,
44    /// Specifies the character set.
45    pub char_set: u8,
46    /// Specifies the output precision. The output precision defines how closely the output must match the requested font's height, width, character orientation, escapement, pitch, and font type.
47    pub out_precision: u8,
48    /// specifies the clipping precision. The clipping precision defines how to clip characters that are partially outside the clipping region.
49    pub clip_precision: u8,
50    /// specifies the output quality. The output quality defines how carefully the GDI must attempt to match the logical-font attributes to those of an actual physical font.
51    pub quality: u8,
52    /// Specifies the pitch and family of the font.
53    pub pitch_and_family: u8,
54    /// Contains a null-terminated string that specifies the typeface name of the font.
55    pub name: String,
56}
57
58/**
59
60Represent a system font.
61
62Can be used with any controls that draws text. Due to the very limited way win32 can draw text,
63only family, size and weight can be configured.
64
65Example:
66
67```rust
68use native_windows_gui2 as nwg;
69
70fn build_font() -> nwg::Font {
71    let mut font = nwg::Font::default();
72
73    nwg::Font::builder()
74        .size(16)
75        .family("Arial")
76        .weight(1000)
77        .build(&mut font);
78
79    font
80}
81
82```
83
84*/
85#[derive(PartialEq, Eq, Debug)]
86pub struct Font {
87    pub handle: HFONT,
88}
89
90impl Font {
91    pub fn builder<'a>() -> FontBuilder<'a> {
92        FontBuilder::new()
93    }
94
95    /// Set the default (application global!) font that will be used when creating controls and return the old one
96    pub fn set_global_default(font: Option<Font>) -> Option<Font> {
97        let mut global_font = DEFAULT_FONT.lock().unwrap();
98        let old = global_font.take();
99        *global_font = font;
100        old
101    }
102
103    /// Set the default (application global!) font that will be used when creating controls
104    /// This is a shortcut over `Font::set_global_default`
105    pub fn set_global_family(family: &str) -> Result<Option<Font>, NwgError> {
106        let mut font = Font::default();
107
108        Font::builder().family(family).build(&mut font)?;
109
110        Ok(Font::set_global_default(Some(font)))
111    }
112
113    /// Return the default font that was previously set using `Font::set_default`
114    pub fn global_default() -> Option<Font> {
115        DEFAULT_FONT
116            .lock()
117            .unwrap()
118            .as_ref()
119            .map(|f| Font { handle: f.handle })
120    }
121
122    /**
123        Add a font to the system font table. Don't forget to call `Font::remove_font(path)` once you're done.
124        Returns `false` if the font could not be added. Windows won't tell you why though.
125
126        Other info:
127        - The value of `path` can be a `ttf` or a `otf` font.
128        - Adding the same font multiple time increase the internal refcount
129        - Use `Font::families()` to return the available system font families
130    */
131    pub fn add_font(path: &str) -> bool {
132        use winapi::um::wingdi::AddFontResourceW;
133
134        unsafe {
135            let path = to_utf16(path);
136            AddFontResourceW(path.as_ptr()) > 0
137        }
138    }
139
140    /// Remove a font that was previously added by `Font::add_font`
141    pub fn remove_font(path: &str) {
142        use winapi::um::wingdi::RemoveFontResourceW;
143
144        unsafe {
145            let path = to_utf16(path);
146            RemoveFontResourceW(path.as_ptr());
147        }
148    }
149
150    /**
151        Add a font resource from a binary source. Returns a memory font handle if the font was loaded succesfully.
152        Send the handle to `remove_memory_font` at the end of your program to free the font from memory.
153    */
154    pub fn add_memory_font(bin: &mut [u8]) -> Result<MemFont, ()> {
155        use winapi::um::wingdi::AddFontMemResourceEx;
156
157        let bin_len = bin.len();
158        let mut num_fonts = 0;
159        let handle = unsafe {
160            AddFontMemResourceEx(
161                bin.as_mut_ptr() as _,
162                bin_len as _,
163                ptr::null_mut(),
164                &mut num_fonts,
165            )
166        };
167
168        if num_fonts > 0 {
169            Ok(MemFont(handle))
170        } else {
171            Err(())
172        }
173    }
174
175    /// Remove a font that was previously added by `Font::add_memory_font`
176    pub fn remove_memory_font(font: MemFont) {
177        use winapi::um::wingdi::RemoveFontMemResourceEx;
178
179        unsafe {
180            RemoveFontMemResourceEx(font.0);
181        }
182    }
183
184    /// Returns all the font families loaded on the OS.
185    /// Probably pretty slow, so cache the value if possible
186    pub fn families() -> Vec<String> {
187        use std::mem;
188        use winapi::shared::minwindef::{DWORD, LPARAM};
189        use winapi::um::wingdi::{DEFAULT_CHARSET, EnumFontFamiliesExW, LOGFONTW, TEXTMETRICW};
190        use winapi::um::winuser::GetDC;
191
192        let mut families = Vec::with_capacity(16);
193
194        extern "system" fn callback(
195            font_ptr: *const LOGFONTW,
196            _txt: *const TEXTMETRICW,
197            _font_type: DWORD,
198            lparam: LPARAM,
199        ) -> i32 {
200            let families_ptr = lparam as *mut Vec<String>;
201            let families = unsafe { &mut *families_ptr };
202
203            let font = &unsafe { *font_ptr };
204            let family_text = from_utf16(&font.lfFaceName);
205            if !families.iter().any(|f| f == &family_text) {
206                families.push(family_text);
207            }
208
209            1
210        }
211
212        unsafe {
213            let hdc = GetDC(ptr::null_mut());
214            let mut font: LOGFONTW = mem::zeroed();
215            font.lfCharSet = DEFAULT_CHARSET as u8;
216
217            EnumFontFamiliesExW(
218                hdc,
219                &mut font,
220                Some(callback),
221                (&mut families as *mut Vec<String>) as _,
222                0,
223            );
224        }
225
226        families.shrink_to_fit();
227        families
228    }
229}
230
231impl Default for Font {
232    fn default() -> Font {
233        Font {
234            handle: ptr::null_mut(),
235        }
236    }
237}
238
239/**
240Builds a font struct
241
242Parameters:
243    - size: Size of the font. The font mapper transforms this value into device units and matches it against the cell height of the available fonts.
244    - size_absolute:  Size of the font. The font mapper transforms this value into device units and matches its absolute value against the character height of the available fonts.
245    - weight: Weight of the font. A value betweem 0 and 1000. 0 use the system default, 100 is very thin, 1000 is very bold.
246    - family: Family name of the font (ex: Arial). Can be None to use the system default.
247*/
248pub struct FontBuilder<'a> {
249    size: Option<i32>,
250    weight: u32,
251    family: Option<&'a str>,
252}
253
254impl<'a> FontBuilder<'a> {
255    pub fn new() -> FontBuilder<'a> {
256        FontBuilder {
257            size: None,
258            weight: 0,
259            family: None,
260        }
261    }
262
263    pub fn size(mut self, size: u32) -> FontBuilder<'a> {
264        self.size = Some(size as i32);
265        self
266    }
267
268    pub fn size_absolute(mut self, size: u32) -> FontBuilder<'a> {
269        self.size = Some(-(size as i32));
270        self
271    }
272
273    pub fn weight(mut self, weight: u32) -> FontBuilder<'a> {
274        self.weight = weight;
275        self
276    }
277
278    pub fn family(mut self, fam: &'a str) -> FontBuilder<'a> {
279        self.family = Some(fam);
280        self
281    }
282
283    pub fn build(self, font: &mut Font) -> Result<(), NwgError> {
284        font.handle = rh::build_font(
285            self.size.unwrap_or(0),
286            self.weight,
287            [false, false, false],
288            self.family,
289        )?;
290
291        Ok(())
292    }
293}
294
295unsafe impl Send for Font {}
296unsafe impl Sync for Font {}
297
298unsafe impl Send for MemFont {}
299unsafe impl Sync for MemFont {}