use std::ffi::{CStr, CString};
use nappgui_sys::{
font_ascent, font_copy, font_create, font_descent, font_destroy, font_equals,
font_exists_family, font_extents, font_family, font_height, font_installed_families,
font_installed_monospace, font_is_monospace, font_leading, font_mini_size, font_monospace,
font_regular_size, font_size, font_small_size, font_style, font_system, font_width,
font_with_style, font_with_width, font_with_xscale, font_xscale,
};
use crate::types::FontStyle;
pub struct Font {
pub(crate) inner: *mut nappgui_sys::Font,
}
impl Font {
pub(crate) fn new(ptr: *mut nappgui_sys::Font) -> Self {
if ptr.is_null() {
panic!("Font is NULL");
}
Font { inner: ptr }
}
pub fn create(family: &str, size: f32, style: FontStyle) -> Self {
let family = CString::new(family).unwrap();
let font = unsafe { font_create(family.as_ptr(), size, style.to_fstyle_t() as _) };
Font::new(font)
}
pub fn system(size: f32, style: FontStyle) -> Self {
let font = unsafe { font_system(size, style.to_fstyle_t() as _) };
Font::new(font)
}
pub fn monospace(size: f32, style: FontStyle) -> Self {
let font = unsafe { font_monospace(size, style.to_fstyle_t() as _) };
Font::new(font)
}
pub fn with_style(&self, style: FontStyle) -> Self {
let font = unsafe { font_with_style(self.inner, style.to_fstyle_t() as _) };
Font::new(font)
}
pub fn with_width(&self, width: f32) -> Self {
let font = unsafe { font_with_width(self.inner, width) };
Font::new(font)
}
pub fn with_xscale(&self, xscale: f32) -> Self {
let font = unsafe { font_with_xscale(self.inner, xscale) };
Font::new(font)
}
pub fn equals(&self, other: &Font) -> bool {
unsafe { font_equals(self.inner, other.inner) != 0 }
}
pub fn regular_size() -> f32 {
unsafe { font_regular_size() }
}
pub fn small_size() -> f32 {
unsafe { font_small_size() }
}
pub fn mini_size() -> f32 {
unsafe { font_mini_size() }
}
pub fn family(&self) -> String {
let family = unsafe { font_family(self.inner) };
let family = unsafe { std::ffi::CStr::from_ptr(family) };
family.to_string_lossy().into_owned()
}
pub fn size(&self) -> f32 {
unsafe { font_size(self.inner) }
}
pub fn height(&self) -> f32 {
unsafe { font_height(self.inner) }
}
pub fn width(&self) -> f32 {
unsafe { font_width(self.inner) }
}
pub fn xscale(&self) -> f32 {
unsafe { font_xscale(self.inner) }
}
pub fn ascent(&self) -> f32 {
unsafe { font_ascent(self.inner) }
}
pub fn descent(&self) -> f32 {
unsafe { font_descent(self.inner) }
}
pub fn leading(&self) -> f32 {
unsafe { font_leading(self.inner) }
}
pub fn is_monospace(&self) -> bool {
unsafe { font_is_monospace(self.inner) != 0 }
}
pub fn style(&self) -> u32 {
unsafe { font_style(self.inner) }
}
pub fn extents(&self, text: &str, refwidth: f32) -> (f32, f32) {
let text = CString::new(text).unwrap();
let mut width = 0f32;
let mut height = 0f32;
unsafe {
font_extents(self.inner, text.as_ptr(), refwidth, &mut width, &mut height);
};
(width, height)
}
pub fn exists_family(family: &str) -> bool {
let family = CString::new(family).unwrap();
unsafe { font_exists_family(family.as_ptr()) != 0 }
}
pub fn installed_families() -> Vec<String> {
let mut families = Vec::new();
unsafe {
let ptr = font_installed_families();
if ptr.is_null() {
return families;
}
let families_arr = *ptr;
let content = families_arr.content;
let elem = (*content).elem;
for i in 0..families_arr.size {
let family = *elem[i as usize];
let family = &family.data[0..family.size as usize];
let family = CStr::from_ptr(family.as_ptr());
families.push(family.to_string_lossy().to_string());
}
}
families
}
pub fn installed_monospace() -> Vec<String> {
let mut families = Vec::new();
unsafe {
let ptr = font_installed_monospace();
if ptr.is_null() {
return families;
}
let families_arr = *ptr;
let content = families_arr.content;
let elem = (*content).elem;
for i in 0..families_arr.size {
let family = *elem[i as usize];
let family = &family.data[0..family.size as usize];
let family = CStr::from_ptr(family.as_ptr());
families.push(family.to_string_lossy().to_string());
}
}
families
}
}
impl Clone for Font {
fn clone(&self) -> Self {
let font = unsafe { font_copy(self.inner) };
Font::new(font)
}
}
impl Drop for Font {
fn drop(&mut self) {
unsafe { font_destroy(&mut self.inner) };
}
}