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}