use std::collections::BTreeMap;
use std::path::Path;
use rocketsplash_formats::{FontMeta, RenderMode, StyleFlags};
use crate::font::load_font_from_bytes;
use crate::{Error, TextBuilder, TextStyle};
#[derive(Clone, Debug)]
pub struct Font {
pub meta: FontMeta,
pub line_height: u32,
pub mode: RenderMode,
pub available_styles: StyleFlags,
pub(crate) glyphs: BTreeMap<char, RuntimeGlyphVariants>,
}
impl Font {
pub fn load(path: impl AsRef<Path>) -> Result<Self, Error> {
let bytes = std::fs::read(path)?;
load_font_from_bytes(&bytes)
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
load_font_from_bytes(bytes)
}
pub fn render<'a>(&'a self, text: &str) -> TextBuilder<'a> {
TextBuilder::new(self, text)
}
pub fn available_chars(&self) -> impl Iterator<Item = char> + '_ {
self.glyphs.keys().copied()
}
pub fn has_glyph(&self, ch: char) -> bool {
self.glyphs.contains_key(&ch)
}
pub fn has_style(&self, style: TextStyle) -> bool {
let bold = style.contains(TextStyle::BOLD);
let italic = style.contains(TextStyle::ITALIC);
if bold && italic && !self.available_styles.contains(StyleFlags::BOLD_ITALIC) {
return false;
}
if bold && !italic && !self.available_styles.contains(StyleFlags::BOLD) {
return false;
}
if italic && !bold && !self.available_styles.contains(StyleFlags::ITALIC) {
return false;
}
if style.contains(TextStyle::REVERSE)
&& !self.available_styles.contains(StyleFlags::REVERSE)
{
return false;
}
true
}
pub fn mode(&self) -> RenderMode {
self.mode
}
pub fn line_height(&self) -> usize {
self.line_height as usize
}
}
#[derive(Clone, Debug)]
pub(crate) struct RuntimeGlyph {
pub width: usize,
pub height: usize,
pub chars: Vec<char>,
pub opacity: Option<Vec<u8>>,
}
impl RuntimeGlyph {
pub fn char_at(&self, x: usize, y: usize) -> Option<char> {
if x >= self.width || y >= self.height {
return None;
}
let idx = y * self.width + x;
self.chars.get(idx).copied()
}
}
#[derive(Clone, Debug)]
pub(crate) struct RuntimeGlyphVariants {
pub base: RuntimeGlyph,
pub bold: Option<RuntimeGlyph>,
pub italic: Option<RuntimeGlyph>,
pub bold_italic: Option<RuntimeGlyph>,
pub reverse: Option<RuntimeGlyph>,
}
impl RuntimeGlyphVariants {
pub fn select(&self, style: TextStyle) -> &RuntimeGlyph {
if style.contains(TextStyle::REVERSE) {
if let Some(glyph) = &self.reverse {
return glyph;
}
}
let bold = style.contains(TextStyle::BOLD);
let italic = style.contains(TextStyle::ITALIC);
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
}
}