use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
use crate::{validate_dimensions, RenderMode, StyleFlags};
pub const FONT_ATLAS_VERSION: u8 = 1;
pub const FONT_ATLAS_MIN_SUPPORTED: u8 = 1;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct FontAtlas {
pub version: u8,
pub meta: FontMeta,
pub glyphs: BTreeMap<char, GlyphVariants>,
pub line_height: u32,
pub mode: RenderMode,
pub available_styles: StyleFlags,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct FontMeta {
pub font_name: String,
pub font_size: f32,
pub created_at: u64,
pub editor_version: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct GlyphVariants {
pub base: GlyphData,
pub bold: Option<GlyphData>,
pub italic: Option<GlyphData>,
pub bold_italic: Option<GlyphData>,
pub reverse: Option<GlyphData>,
}
impl GlyphVariants {
pub fn validate(&self) -> Result<(), String> {
self.base.validate()?;
if let Some(glyph) = &self.bold {
glyph.validate()?;
}
if let Some(glyph) = &self.italic {
glyph.validate()?;
}
if let Some(glyph) = &self.bold_italic {
glyph.validate()?;
}
if let Some(glyph) = &self.reverse {
glyph.validate()?;
}
Ok(())
}
pub fn select(&self, bold: bool, italic: bool, reverse: bool) -> &GlyphData {
if reverse {
if let Some(glyph) = &self.reverse {
return glyph;
}
}
if bold && italic {
if let Some(glyph) = &self.bold_italic {
return glyph;
}
}
if bold {
if let Some(glyph) = &self.bold {
return glyph;
}
}
if italic {
if let Some(glyph) = &self.italic {
return glyph;
}
}
&self.base
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct GlyphData {
pub chars: String,
pub width: u32,
pub height: u32,
pub opacity: Option<Vec<u8>>,
}
impl GlyphData {
pub fn validate(&self) -> Result<(), String> {
let cells = validate_dimensions(self.width, self.height)?;
let char_count = self.chars.chars().count();
if char_count != cells {
return Err(format!(
"Glyph char count {} does not match {}x{}",
char_count, self.width, self.height
));
}
if let Some(opacity) = &self.opacity {
if opacity.len() != cells {
return Err(format!(
"Glyph opacity length {} does not match {}x{}",
opacity.len(),
self.width,
self.height
));
}
}
Ok(())
}
}