ailloli_ui_core/style/text_style.rs
1//! Text font, logical size, color, and paint-only decoration.
2
3use crate::FontId;
4
5use super::Color;
6
7/// Paint-only line decoration applied after text shaping and layout.
8///
9/// Possible values are no decoration and underline.
10///
11/// # Examples
12///
13/// ```
14/// use ailloli_ui_core::TextDecoration;
15/// assert_eq!(TextDecoration::default(), TextDecoration::None);
16/// ```
17#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
18pub enum TextDecoration {
19 /// No additional line; this is the default.
20 #[default]
21 None,
22 /// Paint an underline without changing text shaping or layout metrics.
23 Underline,
24}
25
26/// Font and color for text layout and draw commands.
27///
28/// # Examples
29///
30/// ```
31/// use ailloli_ui_core::{Color, FontId, TextStyle};
32/// let style = TextStyle::new(FontId::Ui, 14, Color::WHITE);
33/// assert_eq!(style.px_size, 14);
34/// ```
35#[derive(Debug, Clone, Copy, PartialEq)]
36pub struct TextStyle {
37 /// Built-in font-family slot.
38 pub font: FontId,
39 /// Font size in logical pixels.
40 pub px_size: u16,
41 /// Linear-RGBA glyph and decoration color.
42 pub color: Color,
43 /// Paint-only line decoration.
44 pub decoration: TextDecoration,
45}
46
47impl TextStyle {
48 /// Creates undecorated text with the supplied font, size, and color.
49 ///
50 /// A zero pixel size is representable and left for the text engine to
51 /// interpret.
52 ///
53 /// # Examples
54 ///
55 /// ```
56 /// use ailloli_ui_core::{Color, FontId, TextDecoration, TextStyle};
57 /// let style = TextStyle::new(FontId::Mono, 13, Color::BLACK);
58 /// assert_eq!(style.decoration, TextDecoration::None);
59 /// ```
60 pub const fn new(font: FontId, px_size: u16, color: Color) -> Self {
61 Self {
62 font,
63 px_size,
64 color,
65 decoration: TextDecoration::None,
66 }
67 }
68
69 /// Returns this style with [`TextDecoration::Underline`].
70 ///
71 /// # Examples
72 ///
73 /// ```
74 /// use ailloli_ui_core::{Color, FontId, TextDecoration, TextStyle};
75 /// assert_eq!(TextStyle::new(FontId::Ui, 14, Color::WHITE).underline().decoration, TextDecoration::Underline);
76 /// ```
77 pub const fn underline(mut self) -> Self {
78 self.decoration = TextDecoration::Underline;
79 self
80 }
81
82 /// Returns this style with [`TextDecoration::None`].
83 ///
84 /// # Examples
85 ///
86 /// ```
87 /// use ailloli_ui_core::{Color, FontId, TextDecoration, TextStyle};
88 /// let style = TextStyle::new(FontId::Ui, 14, Color::WHITE).underline().without_decoration();
89 /// assert_eq!(style.decoration, TextDecoration::None);
90 /// ```
91 pub const fn without_decoration(mut self) -> Self {
92 self.decoration = TextDecoration::None;
93 self
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 //! Covers the decoration default and both decoration builders.
100
101 use super::*;
102 use crate::Color;
103
104 #[test]
105 fn decoration_defaults_to_none_and_builders_toggle_it() {
106 let style = TextStyle::new(FontId::Ui, 14, Color::WHITE);
107 assert_eq!(style.decoration, TextDecoration::None);
108 assert_eq!(style.underline().decoration, TextDecoration::Underline);
109 assert_eq!(
110 style.underline().without_decoration().decoration,
111 TextDecoration::None
112 );
113 }
114}