1use super::fonts::{FontFamily, FontWeight};
2use incular_rendering::Shadow;
3use std::sync::Arc;
4
5#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
6pub enum FontStyle {
7 #[default]
8 Normal,
9 Italic,
10}
11
12#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
13pub enum TextAlign {
14 #[default]
15 Start,
16 Center,
17 End,
18 Justify,
19}
20
21#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
23pub enum TextBaseline {
24 #[default]
25 Alphabetic,
26 Ideographic,
27}
28
29#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
31pub enum TextLeadingDistribution {
32 #[default]
33 Proportional,
34 Even,
35}
36
37#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
39pub enum TextWidthBasis {
40 #[default]
41 Parent,
42 LongestLine,
43}
44
45#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
47pub struct TextHeightBehavior {
48 pub apply_height_to_first_ascent: bool,
49 pub apply_height_to_last_descent: bool,
50 pub leading_distribution: TextLeadingDistribution,
51}
52
53impl TextHeightBehavior {
54 #[must_use]
55 pub const fn new(
56 apply_height_to_first_ascent: bool,
57 apply_height_to_last_descent: bool,
58 leading_distribution: TextLeadingDistribution,
59 ) -> Self {
60 Self {
61 apply_height_to_first_ascent,
62 apply_height_to_last_descent,
63 leading_distribution,
64 }
65 }
66}
67
68#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
70pub struct TextDecoration(u8);
71
72impl TextDecoration {
73 pub const NONE: Self = Self(0);
74 pub const UNDERLINE: Self = Self(1);
75 pub const OVERLINE: Self = Self(2);
76 pub const LINE_THROUGH: Self = Self(4);
77
78 #[must_use]
79 pub const fn combine(decorations: &[Self]) -> Self {
80 let mut bits = 0;
81 let mut i = 0;
82 while i < decorations.len() {
83 bits |= decorations[i].0;
84 i += 1;
85 }
86 Self(bits)
87 }
88
89 #[must_use]
90 pub const fn contains(self, other: Self) -> bool {
91 (self.0 & other.0) == other.0
92 }
93}
94
95impl std::ops::BitOr for TextDecoration {
96 type Output = Self;
97
98 fn bitor(self, rhs: Self) -> Self {
99 Self(self.0 | rhs.0)
100 }
101}
102
103impl std::ops::BitAnd for TextDecoration {
104 type Output = Self;
105
106 fn bitand(self, rhs: Self) -> Self {
107 Self(self.0 & rhs.0)
108 }
109}
110
111#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
113pub enum TextDecorationStyle {
114 #[default]
115 Solid,
116 Double,
117 Dotted,
118 Dashed,
119 Wavy,
120}
121
122pub type TextShadow = Shadow;
125
126#[derive(Clone, Debug, Default, PartialEq)]
128pub struct StrutStyle {
129 pub font_family: Option<FontFamily>,
130 pub font_family_fallback: Arc<[FontFamily]>,
131 pub font_size: Option<f32>,
132 pub font_weight: Option<FontWeight>,
133 pub font_style: Option<FontStyle>,
134 pub height: Option<f32>,
135 pub leading_distribution: Option<TextLeadingDistribution>,
136 pub force_strut_height: Option<bool>,
137}
138
139impl StrutStyle {
140 #[must_use]
141 pub fn new() -> Self {
142 Self::default()
143 }
144
145 #[must_use]
146 pub fn font_family(mut self, family: impl Into<String>) -> Self {
147 self.font_family = Some(FontFamily::named(family));
148 self
149 }
150
151 #[must_use]
152 pub fn font_size(mut self, size: f32) -> Self {
153 self.font_size = Some(size.max(0.0));
154 self
155 }
156
157 #[must_use]
158 pub fn font_weight(mut self, weight: FontWeight) -> Self {
159 self.font_weight = Some(weight);
160 self
161 }
162
163 #[must_use]
164 pub fn font_style(mut self, style: FontStyle) -> Self {
165 self.font_style = Some(style);
166 self
167 }
168
169 #[must_use]
170 pub fn height(mut self, height: f32) -> Self {
171 self.height = Some(height.max(0.0));
172 self
173 }
174
175 #[must_use]
176 pub fn leading_distribution(mut self, distribution: TextLeadingDistribution) -> Self {
177 self.leading_distribution = Some(distribution);
178 self
179 }
180
181 #[must_use]
182 pub fn force_strut_height(mut self, force: bool) -> Self {
183 self.force_strut_height = Some(force);
184 self
185 }
186}
187
188#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
190pub enum TextOverflow {
191 #[default]
192 Clip,
193 Ellipsis,
194 Visible,
195 Fade,
196}
197
198#[derive(Clone, Copy, Debug, PartialEq)]
200pub struct TextScaler {
201 kind: TextScalerKind,
202 factor: f32,
203}
204
205#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
206pub enum TextScalerKind {
207 Linear,
208 NoScaling,
209}
210
211impl TextScaler {
212 pub const NO_SCALING: Self = Self {
213 kind: TextScalerKind::NoScaling,
214 factor: 1.0,
215 };
216
217 #[must_use]
218 pub const fn linear(factor: f32) -> Self {
219 Self {
220 kind: TextScalerKind::Linear,
221 factor,
222 }
223 }
224
225 #[must_use]
226 pub const fn no_scaling() -> Self {
227 Self::NO_SCALING
228 }
229
230 #[must_use]
231 pub const fn factor(self) -> f32 {
232 self.factor
233 }
234
235 #[must_use]
236 pub const fn kind(self) -> TextScalerKind {
237 self.kind
238 }
239
240 #[must_use]
241 pub fn scale(self, font_size: f32) -> f32 {
242 let factor = if self.factor.is_finite() && self.factor >= 0.0 {
243 self.factor
244 } else {
245 1.0
246 };
247 (font_size.max(0.0) * factor).max(0.0)
248 }
249
250 #[must_use]
251 pub fn is_no_scaling(self) -> bool {
252 self.kind == TextScalerKind::NoScaling
253 }
254}
255
256impl Default for TextScaler {
257 fn default() -> Self {
258 Self::NO_SCALING
259 }
260}
261
262#[derive(Clone, Copy, Debug, PartialEq)]
264pub enum LineHeight {
265 Normal,
267 Multiplier(f32),
269 Absolute(f32),
271}
272
273impl LineHeight {
274 #[must_use]
275 pub const fn multiplier(factor: f32) -> Self {
276 Self::Multiplier(factor)
277 }
278
279 #[must_use]
280 pub const fn absolute(pixels: f32) -> Self {
281 Self::Absolute(pixels)
282 }
283
284 #[must_use]
285 pub fn to_parley(self, font_size: f32) -> Option<parley::style::LineHeight> {
286 match self {
287 Self::Normal => None,
288 Self::Multiplier(factor) => Some(parley::style::LineHeight::Absolute(
289 (factor * font_size).max(0.0),
290 )),
291 Self::Absolute(pixels) => Some(parley::style::LineHeight::Absolute(pixels.max(0.0))),
292 }
293 }
294}