use eframe::egui::{self, FontData, FontDefinitions, FontFamily, FontId, TextStyle};
use std::collections::BTreeMap;
use std::sync::Arc;
const GEIST_REGULAR: &[u8] = include_bytes!("fonts/Geist-Regular.ttf");
const GEIST_MEDIUM: &[u8] = include_bytes!("fonts/Geist-Medium.ttf");
const GEIST_SEMIBOLD: &[u8] = include_bytes!("fonts/Geist-SemiBold.ttf");
const GEIST_MONO_REGULAR: &[u8] = include_bytes!("fonts/GeistMono-Regular.ttf");
pub const FAMILY_GEIST_REGULAR: &str = "Geist-Regular";
pub const FAMILY_GEIST_MEDIUM: &str = "Geist-Medium";
pub const FAMILY_GEIST_SEMIBOLD: &str = "Geist-SemiBold";
pub const FAMILY_GEIST_MONO: &str = "Geist-Mono";
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum FontSize {
Caption,
Small,
Body,
Large,
Heading,
Title,
Display,
}
impl FontSize {
pub fn pixels(self) -> f32 {
match self {
FontSize::Caption => 10.0,
FontSize::Small => 12.0,
FontSize::Body => 14.0,
FontSize::Large => 16.0,
FontSize::Heading => 18.0,
FontSize::Title => 24.0,
FontSize::Display => 32.0,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum FontWeight {
Regular,
Medium,
SemiBold,
}
impl FontWeight {
pub fn family(self) -> FontFamily {
match self {
FontWeight::Regular => FontFamily::Name(FAMILY_GEIST_REGULAR.into()),
FontWeight::Medium => FontFamily::Name(FAMILY_GEIST_MEDIUM.into()),
FontWeight::SemiBold => FontFamily::Name(FAMILY_GEIST_SEMIBOLD.into()),
}
}
}
pub fn font(size: FontSize, weight: FontWeight) -> FontId {
FontId::new(size.pixels(), weight.family())
}
pub fn mono(size: FontSize) -> FontId {
FontId::new(size.pixels(), FontFamily::Name(FAMILY_GEIST_MONO.into()))
}
pub fn line_height(size: FontSize) -> f32 {
size.pixels() * 1.4
}
pub fn configure_fonts() -> FontDefinitions {
let mut fonts = FontDefinitions::default();
fonts.font_data.insert(
FAMILY_GEIST_REGULAR.to_owned(),
Arc::new(FontData::from_static(GEIST_REGULAR)),
);
fonts.font_data.insert(
FAMILY_GEIST_MEDIUM.to_owned(),
Arc::new(FontData::from_static(GEIST_MEDIUM)),
);
fonts.font_data.insert(
FAMILY_GEIST_SEMIBOLD.to_owned(),
Arc::new(FontData::from_static(GEIST_SEMIBOLD)),
);
fonts.font_data.insert(
FAMILY_GEIST_MONO.to_owned(),
Arc::new(FontData::from_static(GEIST_MONO_REGULAR)),
);
fonts.families.insert(
FontFamily::Name(FAMILY_GEIST_REGULAR.into()),
vec![FAMILY_GEIST_REGULAR.to_owned()],
);
fonts.families.insert(
FontFamily::Name(FAMILY_GEIST_MEDIUM.into()),
vec![FAMILY_GEIST_MEDIUM.to_owned()],
);
fonts.families.insert(
FontFamily::Name(FAMILY_GEIST_SEMIBOLD.into()),
vec![FAMILY_GEIST_SEMIBOLD.to_owned()],
);
fonts.families.insert(
FontFamily::Name(FAMILY_GEIST_MONO.into()),
vec![FAMILY_GEIST_MONO.to_owned()],
);
fonts
.families
.entry(FontFamily::Proportional)
.or_default()
.insert(0, FAMILY_GEIST_REGULAR.to_owned());
fonts
.families
.entry(FontFamily::Monospace)
.or_default()
.insert(0, FAMILY_GEIST_MONO.to_owned());
fonts
}
pub fn configure_text_styles(ctx: &egui::Context) {
let mut style = (*ctx.style()).clone();
let mut text_styles = BTreeMap::new();
text_styles.insert(
TextStyle::Small,
FontId::new(FontSize::Small.pixels(), FontFamily::Proportional),
);
text_styles.insert(
TextStyle::Body,
FontId::new(FontSize::Body.pixels(), FontFamily::Proportional),
);
text_styles.insert(
TextStyle::Button,
FontId::new(FontSize::Body.pixels(), FontWeight::Medium.family()),
);
text_styles.insert(
TextStyle::Heading,
FontId::new(FontSize::Heading.pixels(), FontWeight::SemiBold.family()),
);
text_styles.insert(
TextStyle::Monospace,
FontId::new(FontSize::Body.pixels(), FontFamily::Monospace),
);
style.text_styles = text_styles;
ctx.set_style(style);
}
pub fn init(ctx: &egui::Context) {
ctx.set_fonts(configure_fonts());
configure_text_styles(ctx);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_font_size_pixels() {
assert_eq!(FontSize::Caption.pixels(), 10.0);
assert_eq!(FontSize::Small.pixels(), 12.0);
assert_eq!(FontSize::Body.pixels(), 14.0);
assert_eq!(FontSize::Large.pixels(), 16.0);
assert_eq!(FontSize::Heading.pixels(), 18.0);
assert_eq!(FontSize::Title.pixels(), 24.0);
assert_eq!(FontSize::Display.pixels(), 32.0);
}
#[test]
fn test_font_weight_family() {
assert_eq!(
FontWeight::Regular.family(),
FontFamily::Name(FAMILY_GEIST_REGULAR.into())
);
assert_eq!(
FontWeight::Medium.family(),
FontFamily::Name(FAMILY_GEIST_MEDIUM.into())
);
assert_eq!(
FontWeight::SemiBold.family(),
FontFamily::Name(FAMILY_GEIST_SEMIBOLD.into())
);
}
#[test]
fn test_font_helper() {
let font_id = font(FontSize::Body, FontWeight::Regular);
assert_eq!(font_id.size, 14.0);
assert_eq!(
font_id.family,
FontFamily::Name(FAMILY_GEIST_REGULAR.into())
);
}
#[test]
fn test_mono_helper() {
let font_id = mono(FontSize::Body);
assert_eq!(font_id.size, 14.0);
assert_eq!(font_id.family, FontFamily::Name(FAMILY_GEIST_MONO.into()));
}
#[test]
fn test_configure_fonts_has_all_families() {
let fonts = configure_fonts();
assert!(fonts.font_data.contains_key(FAMILY_GEIST_REGULAR));
assert!(fonts.font_data.contains_key(FAMILY_GEIST_MEDIUM));
assert!(fonts.font_data.contains_key(FAMILY_GEIST_SEMIBOLD));
assert!(fonts.font_data.contains_key(FAMILY_GEIST_MONO));
assert!(fonts
.families
.contains_key(&FontFamily::Name(FAMILY_GEIST_REGULAR.into())));
assert!(fonts
.families
.contains_key(&FontFamily::Name(FAMILY_GEIST_MEDIUM.into())));
assert!(fonts
.families
.contains_key(&FontFamily::Name(FAMILY_GEIST_SEMIBOLD.into())));
assert!(fonts
.families
.contains_key(&FontFamily::Name(FAMILY_GEIST_MONO.into())));
let proportional = fonts.families.get(&FontFamily::Proportional).unwrap();
assert_eq!(proportional.first().unwrap(), FAMILY_GEIST_REGULAR);
let monospace = fonts.families.get(&FontFamily::Monospace).unwrap();
assert_eq!(monospace.first().unwrap(), FAMILY_GEIST_MONO);
}
}