use std::path::Path;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum FontWeight {
Thin,
ExtraLight,
Light,
#[default]
Regular,
Medium,
SemiBold,
Bold,
ExtraBold,
Black,
}
impl FontWeight {
pub fn value(&self) -> u16 {
match self {
FontWeight::Thin => 100,
FontWeight::ExtraLight => 200,
FontWeight::Light => 300,
FontWeight::Regular => 400,
FontWeight::Medium => 500,
FontWeight::SemiBold => 600,
FontWeight::Bold => 700,
FontWeight::ExtraBold => 800,
FontWeight::Black => 900,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum FontStyle {
#[default]
Normal,
Italic,
Oblique,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum FontStretch {
UltraCondensed,
ExtraCondensed,
Condensed,
SemiCondensed,
#[default]
Normal,
SemiExpanded,
Expanded,
ExtraExpanded,
UltraExpanded,
}
#[derive(Debug, Clone)]
pub struct Font {
family: String,
weight: FontWeight,
style: FontStyle,
stretch: FontStretch,
}
impl Font {
pub fn new(family: impl Into<String>) -> Self {
Self {
family: family.into(),
weight: FontWeight::default(),
style: FontStyle::default(),
stretch: FontStretch::default(),
}
}
pub fn sans_serif() -> Self {
Self::new("sans-serif")
}
pub fn serif() -> Self {
Self::new("serif")
}
pub fn monospace() -> Self {
Self::new("monospace")
}
pub fn family(&self) -> &str {
&self.family
}
pub fn weight(&self) -> FontWeight {
self.weight
}
pub fn with_weight(mut self, weight: FontWeight) -> Self {
self.weight = weight;
self
}
pub fn style(&self) -> FontStyle {
self.style
}
pub fn with_style(mut self, style: FontStyle) -> Self {
self.style = style;
self
}
pub fn stretch(&self) -> FontStretch {
self.stretch
}
pub fn with_stretch(mut self, stretch: FontStretch) -> Self {
self.stretch = stretch;
self
}
pub fn bold(self) -> Self {
self.with_weight(FontWeight::Bold)
}
pub fn italic(self) -> Self {
self.with_style(FontStyle::Italic)
}
}
impl Default for Font {
fn default() -> Self {
Self::sans_serif()
}
}
pub struct FontDatabase {
db: fontdb::Database,
}
impl FontDatabase {
pub fn new() -> Self {
Self {
db: fontdb::Database::new(),
}
}
pub fn with_system_fonts() -> Self {
let mut db = fontdb::Database::new();
db.load_system_fonts();
Self { db }
}
pub fn load_font_file(&mut self, path: impl AsRef<Path>) -> Result<(), std::io::Error> {
let data = std::fs::read(path)?;
self.db.load_font_data(data);
Ok(())
}
pub fn load_font_data(&mut self, data: Vec<u8>) {
self.db.load_font_data(data);
}
pub fn len(&self) -> usize {
self.db.len()
}
pub fn is_empty(&self) -> bool {
self.db.is_empty()
}
pub fn inner(&self) -> &fontdb::Database {
&self.db
}
pub fn inner_mut(&mut self) -> &mut fontdb::Database {
&mut self.db
}
}
impl Default for FontDatabase {
fn default() -> Self {
Self::with_system_fonts()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_font_creation() {
let font = Font::new("Helvetica").bold().italic();
assert_eq!(font.family(), "Helvetica");
assert_eq!(font.weight(), FontWeight::Bold);
assert_eq!(font.style(), FontStyle::Italic);
}
#[test]
fn test_font_weight_values() {
assert_eq!(FontWeight::Regular.value(), 400);
assert_eq!(FontWeight::Bold.value(), 700);
}
}