Skip to main content

oxiui_core/
text_style.rs

1//! Text rendering style for labels and headings.
2//!
3//! [`TextStyle`] is an opinionated, builder-pattern helper that captures
4//! typography intent — size, weight, italic, colour, decorations — without
5//! depending on any shaping library. Adapters consume it however they see fit.
6
7/// Text rendering style for labels and headings.
8///
9/// All fields have sensible defaults (400-weight, upright, theme colour). Use
10/// the builder methods to produce variant styles without repeating boilerplate.
11///
12/// # Example
13/// ```
14/// use oxiui_core::TextStyle;
15///
16/// let style = TextStyle::default()
17///     .with_size(18.0)
18///     .with_weight(600)
19///     .with_color([0, 0, 0, 255]);
20/// ```
21#[derive(Debug, Clone, PartialEq)]
22pub struct TextStyle {
23    /// Font size in points (`None` = use the theme default).
24    pub font_size: Option<f32>,
25    /// Font weight: 100 = thin, 400 = regular, 700 = bold, 900 = black.
26    pub font_weight: u16,
27    /// Whether the text is rendered with an italic face.
28    pub italic: bool,
29    /// Text colour in RGBA bytes (`None` = use the theme default).
30    pub color: Option<[u8; 4]>,
31    /// Line height multiplier (`None` = platform/theme default of ~1.2).
32    pub line_height: Option<f32>,
33    /// Additional horizontal space between glyphs, in pixels (0.0 = default).
34    pub letter_spacing: f32,
35    /// Draw a line beneath the text.
36    pub underline: bool,
37    /// Draw a line through the middle of the text.
38    pub strikethrough: bool,
39}
40
41impl Default for TextStyle {
42    /// Returns a regular-weight, upright style with all overrides unset.
43    fn default() -> Self {
44        Self {
45            font_size: None,
46            font_weight: 400,
47            italic: false,
48            color: None,
49            line_height: None,
50            letter_spacing: 0.0,
51            underline: false,
52            strikethrough: false,
53        }
54    }
55}
56
57impl TextStyle {
58    /// A bold preset: weight 700, all other fields at their defaults.
59    pub fn bold() -> Self {
60        Self {
61            font_weight: 700,
62            ..Self::default()
63        }
64    }
65
66    /// An italic preset: italic enabled, all other fields at their defaults.
67    pub fn italic() -> Self {
68        Self {
69            italic: true,
70            ..Self::default()
71        }
72    }
73
74    /// A heading preset: 24 pt, bold (weight 700).
75    pub fn heading() -> Self {
76        Self {
77            font_size: Some(24.0),
78            font_weight: 700,
79            ..Self::default()
80        }
81    }
82
83    /// A body text preset: equivalent to `default()`.
84    pub fn body() -> Self {
85        Self::default()
86    }
87
88    /// A caption preset: 11 pt, regular weight.
89    pub fn caption() -> Self {
90        Self {
91            font_size: Some(11.0),
92            ..Self::default()
93        }
94    }
95
96    /// Builder: override the font size in points.
97    pub fn with_size(mut self, size: f32) -> Self {
98        self.font_size = Some(size);
99        self
100    }
101
102    /// Builder: override the font weight (100–900).
103    pub fn with_weight(mut self, weight: u16) -> Self {
104        self.font_weight = weight;
105        self
106    }
107
108    /// Builder: set an explicit RGBA colour override.
109    pub fn with_color(mut self, rgba: [u8; 4]) -> Self {
110        self.color = Some(rgba);
111        self
112    }
113
114    /// Builder: set the line height multiplier.
115    pub fn with_line_height(mut self, multiplier: f32) -> Self {
116        self.line_height = Some(multiplier);
117        self
118    }
119
120    /// Builder: set the additional letter spacing in pixels.
121    pub fn with_letter_spacing(mut self, spacing: f32) -> Self {
122        self.letter_spacing = spacing;
123        self
124    }
125
126    /// Builder: enable or disable the underline decoration.
127    pub fn with_underline(mut self, underline: bool) -> Self {
128        self.underline = underline;
129        self
130    }
131
132    /// Builder: enable or disable the strikethrough decoration.
133    pub fn with_strikethrough(mut self, strikethrough: bool) -> Self {
134        self.strikethrough = strikethrough;
135        self
136    }
137}