use std::sync::Arc;
use bevy::{
platform::collections::{HashMap, HashSet},
prelude::*,
};
use bevy_vello::{prelude::VelloFont, vello::peniko::Brush};
use crate::{
layout::{measure::LayoutMeasure, system::measure_text},
prelude::WidgetLayout,
styles::WoodpeckerStyle,
DefaultFont,
};
#[derive(Debug, Clone, Copy, Default, Reflect, PartialEq)]
pub enum TextAlign {
#[default]
Left,
Right,
Center,
Justified,
End,
}
#[derive(Resource)]
pub struct FontManager {
font_data: HashMap<Handle<VelloFont>, Vec<u8>>,
vello_to_family: HashMap<Handle<VelloFont>, String>,
fonts: HashSet<Handle<VelloFont>>,
pub font_cx: parley::FontContext,
pub layout_cx: parley::LayoutContext<Brush>,
}
impl Default for FontManager {
fn default() -> Self {
Self {
vello_to_family: Default::default(),
font_data: Default::default(),
fonts: HashSet::default(),
font_cx: parley::FontContext::new(),
layout_cx: parley::LayoutContext::new(),
}
}
}
impl FontManager {
pub fn driver<'a>(
&'a mut self,
engine: &'a mut parley::PlainEditor<Brush>,
) -> parley::PlainEditorDriver<'a, Brush> {
engine.driver(&mut self.font_cx, &mut self.layout_cx)
}
pub fn get_family(&self, vello_font: &AssetId<VelloFont>) -> String {
self.vello_to_family
.get(&Handle::Weak(*vello_font))
.unwrap()
.clone()
}
pub fn add(&mut self, handle: &Handle<VelloFont>) {
self.fonts.insert(handle.clone());
}
pub fn measure(
&mut self,
text: &str,
styles: &WoodpeckerStyle,
layout: &WidgetLayout,
default_font: &DefaultFont,
) -> Option<Vec2> {
measure_text(text, styles, self, default_font, layout, Vec2::splat(1.0)).and_then(|m| {
match m {
LayoutMeasure::Fixed(fixed) => Some(fixed.size),
_ => None,
}
})
}
}
pub(crate) fn load_fonts(
mut font_manager: ResMut<FontManager>,
mut event_reader: EventReader<AssetEvent<VelloFont>>,
assets: Res<Assets<VelloFont>>,
) {
for event in event_reader.read() {
if let AssetEvent::LoadedWithDependencies { id } = event {
let Some(font_asset) = assets.get(*id) else {
continue;
};
let font_data: &[u8] = &font_asset.bytes;
let font_data = font_data.to_vec();
let face = ttf_parser::Face::parse(&font_data, 0).unwrap();
let family = face
.names()
.into_iter()
.find(|name| name.name_id == ttf_parser::name_id::FAMILY)
.expect("Couldn't find font family.");
let font_family = if family.is_unicode() {
family
.to_string()
.expect("Couldn't get string from family name.")
} else {
String::from_utf8(family.name.to_vec())
.expect("Couldn't get string from family name.")
};
info!("Loaded font family: {}", font_family);
font_manager.font_cx.collection.register_fonts(
parley::fontique::Blob::new(Arc::new(font_data.clone())),
None,
);
font_manager
.vello_to_family
.insert(Handle::Weak(*id), font_family);
font_manager.font_data.insert(Handle::Weak(*id), font_data);
}
}
}