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