inquire/ui/api/style.rs
1//! Contains definitions to apply style to rendered contents.
2
3use std::fmt::Display;
4
5use bitflags::bitflags;
6
7use super::Color;
8
9bitflags! {
10 /// Attributes to apply to a text via the [StyleSheet] struct.
11 ///
12 /// These attributes are flags and can thus be combined.
13 ///
14 /// # Example
15 ///
16 /// ```
17 /// use inquire::ui::Attributes;
18 ///
19 /// let attributes = Attributes::ITALIC | Attributes::BOLD;
20 ///
21 /// assert!(attributes.contains(Attributes::BOLD));
22 /// assert!(attributes.contains(Attributes::ITALIC));
23 /// ```
24 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
25 pub struct Attributes: u8 {
26 /// Increases the text intensity
27 const BOLD = 0b01;
28
29 /// Emphasises the text.
30 const ITALIC = 0b10;
31 }
32}
33
34/// Style definitions that can be applied to the rendered content.
35///
36/// # Example
37///
38/// ```
39/// use inquire::ui::{Attributes, Color, StyleSheet};
40///
41/// let style_sheet = StyleSheet::default();
42///
43/// assert!(style_sheet.is_empty());
44///
45/// let style_sheet = style_sheet
46/// .with_bg(Color::DarkBlue)
47/// .with_attr(Attributes::ITALIC | Attributes::BOLD);
48///
49/// assert!(!style_sheet.is_empty());
50/// ```
51#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
52pub struct StyleSheet {
53 /// Foreground color of text.
54 pub fg: Option<Color>,
55 /// Background color of text.
56 pub bg: Option<Color>,
57 /// Attributes applied to text.
58 pub att: Attributes,
59}
60
61impl StyleSheet {
62 /// Creates a style sheet with no colors and no attributes
63 pub fn new() -> Self {
64 Self::empty()
65 }
66
67 /// A stylesheet with no colors and no attributes.
68 pub fn empty() -> Self {
69 Self {
70 fg: None,
71 bg: None,
72 att: Attributes::empty(),
73 }
74 }
75
76 /// Check if the stylesheet contains no colors and no attributes.
77 pub fn is_empty(&self) -> bool {
78 self.fg.is_none() && self.bg.is_none() && self.att.is_empty()
79 }
80
81 /// Copies the StyleSheet to a new one set with the defined foreground [Color].
82 pub fn with_fg(mut self, fg: Color) -> Self {
83 self.fg = Some(fg);
84 self
85 }
86
87 /// Copies the StyleSheet to a new one set with the defined background [Color].
88 pub fn with_bg(mut self, bg: Color) -> Self {
89 self.bg = Some(bg);
90 self
91 }
92
93 /// Copies the style sheet to a new one with the specified attributes.
94 ///
95 /// Warning: this does not keep the previously applied attributes. If you want
96 /// to just set a new attribute and keep the others, you need to apply the OR
97 /// operation yourself.
98 ///
99 /// # Example
100 ///
101 /// ```
102 /// use inquire::ui::{Attributes, Color, StyleSheet};
103 ///
104 /// let style_sheet = StyleSheet::default().with_attr(Attributes::BOLD);
105 /// assert_eq!(true, style_sheet.att.contains(Attributes::BOLD));
106 /// assert_eq!(false, style_sheet.att.contains(Attributes::ITALIC));
107 ///
108 /// let style_sheet = style_sheet.with_attr(Attributes::ITALIC);
109 /// assert_eq!(false, style_sheet.att.contains(Attributes::BOLD));
110 /// assert_eq!(true, style_sheet.att.contains(Attributes::ITALIC));
111 ///
112 /// let style_sheet = style_sheet.with_attr(style_sheet.att | Attributes::BOLD);
113 /// assert_eq!(true, style_sheet.att.contains(Attributes::BOLD));
114 /// assert_eq!(true, style_sheet.att.contains(Attributes::ITALIC));
115 /// ```
116 pub fn with_attr(mut self, attributes: Attributes) -> Self {
117 self.att = attributes;
118 self
119 }
120}
121
122impl Default for StyleSheet {
123 /// A stylesheet with no colors and no attributes.
124 fn default() -> Self {
125 Self::empty()
126 }
127}
128
129/// Represents a content that when rendered must have the associated style
130/// applied to it.
131#[derive(Clone, Debug)]
132pub struct Styled<T>
133where
134 T: Display,
135{
136 /// Content to be rendered.
137 pub content: T,
138
139 /// Style sheet to be applied to content when rendered.
140 pub style: StyleSheet,
141}
142
143impl<T> Styled<T>
144where
145 T: Display,
146{
147 /// Creates a new `Styled` object with the specified content
148 /// and a default (empty) style sheet.
149 pub fn new(content: T) -> Self {
150 Self {
151 content,
152 style: StyleSheet::default(),
153 }
154 }
155
156 /// Sets the style sheet to the styled struct.
157 #[allow(unused)]
158 pub fn with_style_sheet(mut self, style_sheet: StyleSheet) -> Self {
159 self.style = style_sheet;
160 self
161 }
162
163 /// Sets the styled content to have the defined foreground [Color].
164 pub fn with_fg(mut self, fg: Color) -> Self {
165 self.style.fg = Some(fg);
166 self
167 }
168
169 /// Sets the styled content to have the defined foreground [Color].
170 pub fn with_bg(mut self, bg: Color) -> Self {
171 self.style.bg = Some(bg);
172 self
173 }
174
175 /// Sets the styled content to have the defined attributes.
176 ///
177 /// Warning: this does not keep the previously applied attributes. If you want
178 /// to just set a new attribute and keep the others, you need to apply the OR
179 /// operation yourself.
180 pub fn with_attr(mut self, attributes: Attributes) -> Self {
181 self.style.att = attributes;
182 self
183 }
184
185 /// Updates the content while keeping the style sheet constant.
186 pub fn with_content<U>(self, content: U) -> Styled<U>
187 where
188 U: Display,
189 {
190 Styled {
191 content,
192 style: self.style,
193 }
194 }
195}
196
197impl<T> Copy for Styled<T> where T: Copy + Display {}
198
199impl<T> Default for Styled<T>
200where
201 T: Default + Display,
202{
203 fn default() -> Self {
204 Self {
205 content: Default::default(),
206 style: Default::default(),
207 }
208 }
209}
210
211impl<T> From<T> for Styled<T>
212where
213 T: Display,
214{
215 fn from(from: T) -> Self {
216 Self::new(from)
217 }
218}
219
220impl<T> PartialEq for Styled<T>
221where
222 T: PartialEq + Display,
223{
224 fn eq(&self, other: &Self) -> bool {
225 self.style == other.style && self.content == other.content
226 }
227}
228
229impl<T> Eq for Styled<T> where T: Eq + Display {}