Skip to main content

native_windows_gui/resources/
font.rs

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