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 {}