use winapi::shared::windef::HFONT;
use winapi::um::winnt::HANDLE;
use crate::win32::resources_helper as rh;
use crate::win32::base_helper::{to_utf16, from_utf16};
use crate::NwgError;
use std::ptr;
use std::sync::Mutex;
lazy_static! {
static ref DEFAULT_FONT: Mutex<Option<Font>> = {
Mutex::new(None)
};
}
pub struct MemFont(pub HANDLE);
#[derive(Debug, Clone)]
pub struct FontInfo {
pub point_size: u32,
pub height: i32,
pub width: i32,
pub escapement: i32,
pub orientation: i32,
pub weight: i32,
pub italic: bool,
pub underline: bool,
pub strike_out: bool,
pub char_set: u8,
pub out_precision: u8,
pub clip_precision: u8,
pub quality: u8,
pub pitch_and_family: u8,
pub name: String
}
#[derive(PartialEq, Eq, Debug)]
pub struct Font {
pub handle: HFONT
}
impl Font {
pub fn builder<'a>() -> FontBuilder<'a> {
FontBuilder::new()
}
pub fn set_global_default(font: Option<Font>) -> Option<Font> {
let mut global_font = DEFAULT_FONT.lock().unwrap();
let old = global_font.take();
*global_font = font;
old
}
pub fn set_global_family(family: &str) -> Result<Option<Font>, NwgError> {
let mut font = Font::default();
Font::builder()
.family(family)
.build(&mut font)?;
Ok(Font::set_global_default(Some(font)))
}
pub fn global_default() -> Option<Font> {
DEFAULT_FONT.lock()
.unwrap()
.as_ref()
.map(|f| Font { handle: f.handle } )
}
pub fn add_font(path: &str) -> bool {
use winapi::um::wingdi::AddFontResourceW;
unsafe {
let path = to_utf16(path);
AddFontResourceW(path.as_ptr()) > 0
}
}
pub fn remove_font(path: &str) {
use winapi::um::wingdi::RemoveFontResourceW;
unsafe {
let path = to_utf16(path);
RemoveFontResourceW(path.as_ptr());
}
}
pub fn add_memory_font(bin: &mut [u8]) -> Result<MemFont, ()> {
use winapi::um::wingdi::AddFontMemResourceEx;
let bin_len = bin.len();
let mut num_fonts = 0;
let handle = unsafe {
AddFontMemResourceEx(
bin.as_mut_ptr() as _,
bin_len as _,
ptr::null_mut(),
&mut num_fonts,
)
};
if num_fonts > 0 {
Ok(MemFont(handle))
} else {
Err(())
}
}
pub fn remove_memory_font(font: MemFont) {
use winapi::um::wingdi::RemoveFontMemResourceEx;
unsafe {
RemoveFontMemResourceEx(font.0);
}
}
pub fn families() -> Vec<String> {
use winapi::um::wingdi::{LOGFONTW, TEXTMETRICW, DEFAULT_CHARSET, EnumFontFamiliesExW};
use winapi::um::winuser::GetDC;
use winapi::shared::minwindef::{DWORD, LPARAM};
use std::mem;
let mut families = Vec::with_capacity(16);
unsafe extern "system" fn callback(font_ptr: *const LOGFONTW, _txt: *const TEXTMETRICW, _font_type: DWORD, lparam: LPARAM) -> i32 {
let families_ptr = lparam as *mut Vec<String>;
let families = &mut *families_ptr;
let font = &*font_ptr;
let family_text = from_utf16(&font.lfFaceName);
if !families.iter().any(|f| f == &family_text) {
families.push(family_text);
}
1
}
unsafe {
let hdc = GetDC(ptr::null_mut());
let mut font: LOGFONTW = mem::zeroed();
font.lfCharSet = DEFAULT_CHARSET as u8;
EnumFontFamiliesExW(hdc, &mut font, Some(callback), (&mut families as *mut Vec<String>) as _, 0);
}
families.shrink_to_fit();
families
}
}
impl Default for Font {
fn default() -> Font {
Font { handle: ptr::null_mut() }
}
}
pub struct FontBuilder<'a> {
size: Option<i32>,
weight: u32,
family: Option<&'a str>
}
impl<'a> FontBuilder<'a> {
pub fn new() -> FontBuilder<'a> {
FontBuilder {
size: None,
weight: 0,
family: None,
}
}
pub fn size(mut self, size: u32) -> FontBuilder<'a> {
self.size = Some(size as i32);
self
}
pub fn size_absolute(mut self, size: u32) -> FontBuilder<'a> {
self.size = Some(-(size as i32));
self
}
pub fn weight(mut self, weight: u32) -> FontBuilder<'a> {
self.weight = weight;
self
}
pub fn family(mut self, fam: &'a str) -> FontBuilder<'a> {
self.family = Some(fam);
self
}
pub fn build(self, font: &mut Font) -> Result<(), NwgError> {
font.handle = unsafe { rh::build_font(
self.size.unwrap_or(0),
self.weight,
[false, false, false],
self.family
) }?;
Ok(())
}
}
unsafe impl Send for Font {}
unsafe impl Sync for Font {}
unsafe impl Send for MemFont {}
unsafe impl Sync for MemFont {}