ltk/theme/fonts.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>
//! Font family definitions as declared by the theme document.
//!
//! This module only models the **declaration**: a family name, a set of
//! source files indexed by weight/style, and a fallback chain. Loading the
//! `.ttf` bytes into `fontdue` and resolving text styles against a live
//! registry is the runtime registry's job (see [`super::FontRegistry`]).
use std::path::PathBuf;
use super::text_style::FontStyle;
// ─── FontFamilyDef ───────────────────────────────────────────────────────────
/// A font family as declared by the theme document.
///
/// `sources` is a flat list indexed by weight + style, not a nested map, so
/// the JSON round-trips without ambiguity on ordering.
#[ derive( Debug, Clone, PartialEq ) ]
pub struct FontFamilyDef
{
/// Human-readable family name (e.g. `"Sora"`). Shown in telemetry and
/// in any eventual font-picker UI.
pub name: String,
/// Fallback chain if the family or a given weight/style is missing.
/// Resolved in order: the first entry that the font registry can
/// satisfy is used.
pub fallbacks: Vec<String>,
/// One source per weight/style the family ships. The runtime font
/// registry registers each source in `fontdue` at load time.
pub sources: Vec<FontSource>,
}
// ─── FontSource ──────────────────────────────────────────────────────────────
/// A single font file, specified by its numeric weight and style.
#[ derive( Debug, Clone, PartialEq, Eq ) ]
pub struct FontSource
{
/// CSS numeric weight (100..=900).
pub weight: u16,
/// Italic vs upright.
pub style: FontStyle,
/// Path to the `.ttf` / `.otf` file. Resolved to absolute at load time
/// (relative paths are taken to be relative to the theme directory root).
pub path: PathBuf,
}
// ─── Tests ───────────────────────────────────────────────────────────────────
#[ cfg( test ) ]
mod tests
{
use super::*;
#[ test ]
fn family_def_holds_multiple_weights_of_same_family()
{
let sora = FontFamilyDef
{
name: "Sora".to_string(),
fallbacks: vec![ "system-ui".to_string(), "sans-serif".to_string() ],
sources: vec!
[
FontSource { weight: 300, style: FontStyle::Normal, path: "fonts/Sora-Light.ttf".into() },
FontSource { weight: 400, style: FontStyle::Normal, path: "fonts/Sora-Regular.ttf".into() },
FontSource { weight: 600, style: FontStyle::Normal, path: "fonts/Sora-SemiBold.ttf".into() },
FontSource { weight: 700, style: FontStyle::Normal, path: "fonts/Sora-Bold.ttf".into() },
],
};
assert_eq!( sora.sources.len(), 4 );
assert_eq!( sora.sources[2].weight, 600 );
assert_eq!( sora.fallbacks[0], "system-ui" );
}
}