inquire/ui/
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    pub struct Attributes: u8 {
25        /// Increases the text intensity
26        const BOLD   = 0b01;
27
28        /// Emphasises the text.
29        const ITALIC = 0b10;
30    }
31}
32
33/// Style definitions that can be applied to the rendered content.
34///
35/// # Example
36///
37/// ```
38/// use inquire::ui::{Attributes, Color, StyleSheet};
39///
40/// let style_sheet = StyleSheet::default();
41///
42/// assert!(style_sheet.is_empty());
43///
44/// let style_sheet = style_sheet
45///     .with_bg(Color::DarkBlue)
46///     .with_attr(Attributes::ITALIC | Attributes::BOLD);
47///
48/// assert!(!style_sheet.is_empty());
49/// ```
50#[derive(Copy, Clone, Debug, PartialEq, Eq)]
51pub struct StyleSheet {
52    /// Foreground color of text.
53    pub fg: Option<Color>,
54    /// Background color of text.
55    pub bg: Option<Color>,
56    /// Attributes applied to text.
57    pub att: Attributes,
58}
59
60impl StyleSheet {
61    /// Creates a style sheet with no colors and no attributes
62    pub fn new() -> Self {
63        Self::empty()
64    }
65
66    /// A stylesheet with no colors and no attributes.
67    pub fn empty() -> Self {
68        Self {
69            fg: None,
70            bg: None,
71            att: Attributes::empty(),
72        }
73    }
74
75    /// Check if the stylesheet contains no colors and no attributes.
76    pub fn is_empty(&self) -> bool {
77        self.fg.is_none() && self.bg.is_none() && self.att.is_empty()
78    }
79
80    /// Copies the StyleSheet to a new one set with the defined foreground [Color].
81    pub fn with_fg(mut self, fg: Color) -> Self {
82        self.fg = Some(fg);
83        self
84    }
85
86    /// Copies the StyleSheet to a new one set with the defined background [Color].
87    pub fn with_bg(mut self, bg: Color) -> Self {
88        self.bg = Some(bg);
89        self
90    }
91
92    /// Copies the style sheet to a new one with the specified attributes.
93    ///
94    /// Warning: this does not keep the previously applied attributes. If you want
95    /// to just set a new attribute and keep the others, you need to apply the OR
96    /// operation yourself.
97    ///
98    /// # Example
99    ///
100    /// ```
101    /// use inquire::ui::{Attributes, Color, StyleSheet};
102    ///
103    /// let style_sheet = StyleSheet::default().with_attr(Attributes::BOLD);
104    /// assert_eq!(true,  style_sheet.att.contains(Attributes::BOLD));
105    /// assert_eq!(false, style_sheet.att.contains(Attributes::ITALIC));
106    ///
107    /// let style_sheet = style_sheet.with_attr(Attributes::ITALIC);
108    /// assert_eq!(false, style_sheet.att.contains(Attributes::BOLD));
109    /// assert_eq!(true,  style_sheet.att.contains(Attributes::ITALIC));
110    ///
111    /// let style_sheet = style_sheet.with_attr(style_sheet.att | Attributes::BOLD);
112    /// assert_eq!(true, style_sheet.att.contains(Attributes::BOLD));
113    /// assert_eq!(true, style_sheet.att.contains(Attributes::ITALIC));
114    /// ```
115    pub fn with_attr(mut self, attributes: Attributes) -> Self {
116        self.att = attributes;
117        self
118    }
119}
120
121impl Default for StyleSheet {
122    /// A stylesheet with no colors and no attributes.
123    fn default() -> Self {
124        Self::empty()
125    }
126}
127
128/// Represents a content that when rendered must have the associated style
129/// applied to it.
130#[derive(Clone, Debug)]
131pub struct Styled<T>
132where
133    T: Display,
134{
135    /// Content to be rendered.
136    pub content: T,
137
138    /// Style sheet to be applied to content when rendered.
139    pub style: StyleSheet,
140}
141
142impl<T> Styled<T>
143where
144    T: Display,
145{
146    /// Creates a new `Styled` object with the specified content
147    /// and a default (empty) style sheet.
148    pub fn new(content: T) -> Self {
149        Self {
150            content,
151            style: StyleSheet::default(),
152        }
153    }
154
155    /// Sets the style sheet to the styled struct.
156    #[allow(unused)]
157    pub fn with_style_sheet(mut self, style_sheet: StyleSheet) -> Self {
158        self.style = style_sheet;
159        self
160    }
161
162    /// Sets the styled content to have the defined foreground [Color].
163    pub fn with_fg(mut self, fg: Color) -> Self {
164        self.style.fg = Some(fg);
165        self
166    }
167
168    /// Sets the styled content to have the defined foreground [Color].
169    pub fn with_bg(mut self, bg: Color) -> Self {
170        self.style.bg = Some(bg);
171        self
172    }
173
174    /// Sets the styled content to have the defined attributes.
175    ///
176    /// Warning: this does not keep the previously applied attributes. If you want
177    /// to just set a new attribute and keep the others, you need to apply the OR
178    /// operation yourself.
179    pub fn with_attr(mut self, attributes: Attributes) -> Self {
180        self.style.att = attributes;
181        self
182    }
183}
184
185impl<T> Copy for Styled<T> where T: Copy + Display {}