use crate::color::Color;
use crate::units::Pt;
#[derive(Debug, Clone, PartialEq)]
pub struct TypographyStyle {
pub font_families: Vec<String>,
pub font_size: Pt,
pub font_weight: u16,
pub font_style: FontStyle,
pub line_height: LineHeight,
pub letter_spacing: Pt,
pub word_spacing: Pt,
pub text_align: TextAlign,
pub text_decoration: TextDecoration,
pub text_indent: Pt,
pub white_space: WhiteSpace,
pub text_overflow: TextOverflow,
pub vertical_align: VerticalAlign,
pub text_transform: TextTransform,
pub text_shadow: Vec<TextShadow>,
pub word_break: WordBreak,
pub overflow_wrap: OverflowWrap,
pub tab_size: u32,
pub color: Color,
pub direction: TextDirection,
pub font_features: OpenTypeFeatures,
pub microtypography: Microtypography,
}
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct Microtypography {
pub hanging_punctuation: f64,
pub optical_margin: f64,
pub max_tracking_adjust: f64,
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct OpenTypeFeatures {
pub ligatures: Option<bool>,
pub small_caps: bool,
pub old_style_nums: bool,
pub kerning: Option<bool>,
pub custom: Vec<(String, u32)>,
}
impl Default for TypographyStyle {
fn default() -> Self {
Self {
font_families: Vec::new(),
font_size: Pt::new(12.0),
font_weight: 400,
font_style: FontStyle::Normal,
line_height: LineHeight::Normal,
letter_spacing: Pt::ZERO,
word_spacing: Pt::ZERO,
text_align: TextAlign::Start,
text_decoration: TextDecoration::None,
text_indent: Pt::ZERO,
white_space: WhiteSpace::Normal,
text_overflow: TextOverflow::Clip,
vertical_align: VerticalAlign::Baseline,
text_transform: TextTransform::None,
text_shadow: Vec::new(),
word_break: WordBreak::Normal,
overflow_wrap: OverflowWrap::Normal,
tab_size: 8,
color: Color::BLACK,
direction: TextDirection::Ltr,
font_features: OpenTypeFeatures::default(),
microtypography: Microtypography::default(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[repr(u8)]
pub enum FontStyle {
#[default]
Normal = 0,
Italic = 1,
Oblique = 2,
}
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub enum LineHeight {
#[default]
Normal,
Length(Pt),
Number(f64),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum TextAlign {
#[default]
Start,
End,
Left,
Right,
Center,
Justify,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum TextDecoration {
#[default]
None,
Underline,
Overline,
LineThrough,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum WhiteSpace {
#[default]
Normal,
Pre,
NoWrap,
PreWrap,
PreLine,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum TextOverflow {
#[default]
Clip,
Ellipsis,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum VerticalAlign {
#[default]
Baseline,
Top,
Middle,
Bottom,
Sub,
Super,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum TextTransform {
#[default]
None,
Uppercase,
Lowercase,
Capitalize,
}
impl TextTransform {
#[must_use]
pub fn apply(&self, text: &str) -> String {
match self {
Self::None => text.to_string(),
Self::Uppercase => text.to_uppercase(),
Self::Lowercase => text.to_lowercase(),
Self::Capitalize => capitalize_words(text),
}
}
}
fn capitalize_words(text: &str) -> String {
let mut result = String::with_capacity(text.len());
let mut prev_is_space = true;
for ch in text.chars() {
if prev_is_space && ch.is_alphabetic() {
for c in ch.to_uppercase() {
result.push(c);
}
} else {
result.push(ch);
}
prev_is_space = ch.is_whitespace();
}
result
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct TextShadow {
pub offset_x: Pt,
pub offset_y: Pt,
pub blur_radius: Pt,
pub color: Color,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum WordBreak {
#[default]
Normal,
BreakAll,
KeepAll,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum OverflowWrap {
#[default]
Normal,
BreakWord,
Anywhere,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum TextDirection {
#[default]
Ltr,
Rtl,
}