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