use bevy::{
ecs::system::SystemParam,
prelude::*,
text::{FontCx, FontSource},
};
pub use smol_str::SmolStr;
#[must_use]
pub fn font_family(name: impl AsRef<str>) -> FontSource {
FontSource::Family(SmolStr::new(name.as_ref()))
}
#[derive(SystemParam)]
pub struct TerminalFonts<'w> {
font_cx: ResMut<'w, FontCx>,
}
impl TerminalFonts<'_> {
pub fn has_family(&mut self, name: &str) -> bool {
self.font_cx.collection.family_by_name(name).is_some()
}
pub fn resolve_family(&mut self, preferred: &[&str]) -> Option<FontSource> {
preferred
.iter()
.find(|name| self.has_family(name))
.map(font_family)
}
pub fn families(&mut self) -> Vec<String> {
self.font_cx
.collection
.family_names()
.map(str::to_owned)
.collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn font_family_accepts_any_string_type() {
assert_eq!(font_family("A"), FontSource::Family(SmolStr::new("A")));
assert_eq!(
font_family(String::from("B")),
FontSource::Family("B".into())
);
}
#[test]
fn registered_font_assets_are_discoverable_by_family() {
let mut app = App::new();
app.add_plugins((
MinimalPlugins,
bevy::asset::AssetPlugin::default(),
bevy::text::TextPlugin,
));
let bytes =
include_bytes!("../../../../assets/fonts/jetbrains-mono/JetBrainsMono-Regular.ttf");
let font = bevy::text::Font::from_bytes(bytes.to_vec());
let handle = app.world_mut().resource_mut::<Assets<Font>>().add(font);
app.update();
let mut state = bevy::ecs::system::SystemState::<TerminalFonts>::new(app.world_mut());
let mut fonts = state.get_mut(app.world_mut()).expect("FontCx exists");
assert!(fonts.has_family("JetBrains Mono"), "{:?}", fonts.families());
assert!(fonts.has_family("jetbrains mono"));
assert_eq!(
fonts.resolve_family(&["No Such Family", "JetBrains Mono"]),
Some(font_family("JetBrains Mono"))
);
assert_eq!(fonts.resolve_family(&["No Such Family"]), None);
drop(handle);
}
}