//! `style` contains the primitives used to control how your user interface will look. use bitflags::bitflags; #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum Color { Reset, Black, Red, Green, Yellow, Blue, Magenta, Cyan, Gray, DarkGray, LightRed, LightGreen, LightYellow, LightBlue, LightMagenta, LightCyan, White, Rgb(u8, u8, u8), Indexed(u8), } bitflags! { /// Modifier changes the way a piece of text is displayed. /// /// They are bitflags so they can easily be composed. /// /// ## Examples /// /// ```rust /// # use tui::style::Modifier; /// /// let m = Modifier::BOLD | Modifier::ITALIC; /// ``` #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Modifier: u16 { const BOLD = 0b0000_0000_0001; const DIM = 0b0000_0000_0010; const ITALIC = 0b0000_0000_0100; const UNDERLINED = 0b0000_0000_1000; const SLOW_BLINK = 0b0000_0001_0000; const RAPID_BLINK = 0b0000_0010_0000; const REVERSED = 0b0000_0100_0000; const HIDDEN = 0b0000_1000_0000; const CROSSED_OUT = 0b0001_0000_0000; } } /// Style let you control the main characteristics of the displayed elements. /// /// ```rust /// # use tui::style::{Color, Modifier, Style}; /// Style::default() /// .fg(Color::Black) /// .bg(Color::Green) /// .add_modifier(Modifier::ITALIC | Modifier::BOLD); /// ``` /// /// It represents an incremental change. If you apply the styles S1, S2, S3 to a cell of the /// terminal buffer, the style of this cell will be the result of the merge of S1, S2 and S3, not /// just S3. /// /// ```rust /// # use tui::style::{Color, Modifier, Style}; /// # use tui::buffer::Buffer; /// # use tui::layout::Rect; /// let styles = [ /// Style::default().fg(Color::Blue).add_modifier(Modifier::BOLD | Modifier::ITALIC), /// Style::default().bg(Color::Red), /// Style::default().fg(Color::Yellow).remove_modifier(Modifier::ITALIC), /// ]; /// let mut buffer = Buffer::empty(Rect::new(0, 0, 1, 1)); /// for style in &styles { /// buffer.get_mut(0, 0).set_style(*style); /// } /// assert_eq!( /// Style { /// fg: Some(Color::Yellow), /// bg: Some(Color::Red), /// add_modifier: Modifier::BOLD, /// sub_modifier: Modifier::empty(), /// }, /// buffer.get(0, 0).style(), /// ); /// ``` /// /// The default implementation returns a `Style` that does not modify anything. If you wish to /// reset all properties until that point use [`Style::reset`]. /// /// ``` /// # use tui::style::{Color, Modifier, Style}; /// # use tui::buffer::Buffer; /// # use tui::layout::Rect; /// let styles = [ /// Style::default().fg(Color::Blue).add_modifier(Modifier::BOLD | Modifier::ITALIC), /// Style::reset().fg(Color::Yellow), /// ]; /// let mut buffer = Buffer::empty(Rect::new(0, 0, 1, 1)); /// for style in &styles { /// buffer.get_mut(0, 0).set_style(*style); /// } /// assert_eq!( /// Style { /// fg: Some(Color::Yellow), /// bg: Some(Color::Reset), /// add_modifier: Modifier::empty(), /// sub_modifier: Modifier::empty(), /// }, /// buffer.get(0, 0).style(), /// ); /// ``` #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Style { pub fg: Option, pub bg: Option, pub add_modifier: Modifier, pub sub_modifier: Modifier, } impl Default for Style { fn default() -> Style { Style { fg: None, bg: None, add_modifier: Modifier::empty(), sub_modifier: Modifier::empty(), } } } impl Style { /// Returns a `Style` resetting all properties. pub fn reset() -> Style { Style { fg: Some(Color::Reset), bg: Some(Color::Reset), add_modifier: Modifier::empty(), sub_modifier: Modifier::all(), } } /// Changes the foreground color. /// /// ## Examples /// /// ```rust /// # use tui::style::{Color, Style}; /// let style = Style::default().fg(Color::Blue); /// let diff = Style::default().fg(Color::Red); /// assert_eq!(style.patch(diff), Style::default().fg(Color::Red)); /// ``` pub fn fg(mut self, color: Color) -> Style { self.fg = Some(color); self } /// Changes the background color. /// /// ## Examples /// /// ```rust /// # use tui::style::{Color, Style}; /// let style = Style::default().bg(Color::Blue); /// let diff = Style::default().bg(Color::Red); /// assert_eq!(style.patch(diff), Style::default().bg(Color::Red)); /// ``` pub fn bg(mut self, color: Color) -> Style { self.bg = Some(color); self } /// Changes the text emphasis. /// /// When applied, it adds the given modifier to the `Style` modifiers. /// /// ## Examples /// /// ```rust /// # use tui::style::{Color, Modifier, Style}; /// let style = Style::default().add_modifier(Modifier::BOLD); /// let diff = Style::default().add_modifier(Modifier::ITALIC); /// let patched = style.patch(diff); /// assert_eq!(patched.add_modifier, Modifier::BOLD | Modifier::ITALIC); /// assert_eq!(patched.sub_modifier, Modifier::empty()); /// ``` pub fn add_modifier(mut self, modifier: Modifier) -> Style { self.sub_modifier.remove(modifier); self.add_modifier.insert(modifier); self } /// Changes the text emphasis. /// /// When applied, it removes the given modifier from the `Style` modifiers. /// /// ## Examples /// /// ```rust /// # use tui::style::{Color, Modifier, Style}; /// let style = Style::default().add_modifier(Modifier::BOLD | Modifier::ITALIC); /// let diff = Style::default().remove_modifier(Modifier::ITALIC); /// let patched = style.patch(diff); /// assert_eq!(patched.add_modifier, Modifier::BOLD); /// assert_eq!(patched.sub_modifier, Modifier::ITALIC); /// ``` pub fn remove_modifier(mut self, modifier: Modifier) -> Style { self.add_modifier.remove(modifier); self.sub_modifier.insert(modifier); self } /// Results in a combined style that is equivalent to applying the two individual styles to /// a style one after the other. /// /// ## Examples /// ``` /// # use tui::style::{Color, Modifier, Style}; /// let style_1 = Style::default().fg(Color::Yellow); /// let style_2 = Style::default().bg(Color::Red); /// let combined = style_1.patch(style_2); /// assert_eq!( /// Style::default().patch(style_1).patch(style_2), /// Style::default().patch(combined)); /// ``` pub fn patch(mut self, other: Style) -> Style { self.fg = other.fg.or(self.fg); self.bg = other.bg.or(self.bg); self.add_modifier.remove(other.sub_modifier); self.add_modifier.insert(other.add_modifier); self.sub_modifier.remove(other.add_modifier); self.sub_modifier.insert(other.sub_modifier); self } } #[cfg(test)] mod tests { use super::*; fn styles() -> Vec