gemini_engine/core/colchar/
mod.rs

1use std::fmt::{self, Debug, Display};
2
3mod colour;
4mod modifier;
5
6pub use colour::Colour;
7pub use modifier::Modifier;
8
9/// A coloured character. Made up of `text_char`, a single ascii character used as the "pixel" when drawn to a [`Canvas`](super::Canvas), and `modifier`, which gives that pixel a colour or makes it bold/italic
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub struct ColChar {
12    /// A single ascii character used as the "pixel" when drawn to a [`Canvas`](super::Canvas)
13    pub text_char: char,
14    /// Defines the appearance of the character - colour, bold/italic, etc.
15    pub modifier: Modifier,
16}
17
18impl ColChar {
19    /// A solid █ character with no [`Modifier`].
20    ///
21    /// ## Example
22    /// Using a sequence like this will create a red █ `ColChar`
23    /// ```rs
24    /// ColChar::SOLID.with_rgb(255, 0, 0)
25    /// ```
26    pub const SOLID: Self = Self {
27        text_char: '█',
28        modifier: Modifier::None,
29    };
30    /// A less solid ░ character with no [`Modifier`]
31    pub const BACKGROUND: Self = Self {
32        text_char: '░',
33        modifier: Modifier::None,
34    };
35    /// A whitespace character with no [`Modifier`]
36    pub const EMPTY: Self = Self {
37        text_char: ' ',
38        modifier: Modifier::None,
39    };
40    /// An opaque whitespace character (`\u{2008}`) with no [`Modifier`]
41    ///
42    /// ASCII Whitespaces are interpreted as transparent by [`ascii`](crate::ascii) elements. If you want opacity, use this void character
43    pub const VOID: Self = Self {
44        text_char: ' ', // \u{2008}
45        modifier: Modifier::None,
46    };
47
48    /// Create a new `ColChar` with a text character and a [`Modifier`]
49    #[must_use]
50    pub const fn new(text_char: char, modifier: Modifier) -> Self {
51        Self {
52            text_char,
53            modifier,
54        }
55    }
56
57    /// Return a `ColChar` with the same modifier and new `text_char`
58    #[must_use]
59    pub const fn with_char(mut self, text_char: char) -> Self {
60        self.text_char = text_char;
61        self
62    }
63
64    /// Return a `ColChar` with the same `text_char` and new modifier
65    #[must_use]
66    pub const fn with_mod(mut self, modifier: Modifier) -> Self {
67        self.modifier = modifier;
68        self
69    }
70
71    /// Return a `ColChar` with the same `text_char` and new `Modifier::Colour` modifier
72    #[must_use]
73    pub const fn with_colour(mut self, colour: Colour) -> Self {
74        self.modifier = Modifier::Colour(colour);
75        self
76    }
77
78    /// Return a `ColChar` with the same `text_char` and new `Modifier::Colour` modifier from an RGB value
79    #[must_use]
80    pub const fn with_rgb(mut self, r: u8, g: u8, b: u8) -> Self {
81        self.modifier = Modifier::from_rgb(r, g, b);
82        self
83    }
84
85    /// Return a `ColChar` with the same `text_char` and new `Modifier::Colour` modifier from an HSV value
86    #[must_use]
87    pub fn with_hsv(mut self, h: u8, s: u8, v: u8) -> Self {
88        self.modifier = Modifier::from_hsv(h, s, v);
89        self
90    }
91
92    /// Return the displayed `ColChar`, omitting the `Modifier`s where necessary
93    pub(crate) fn display_with_prev_and_next(
94        self,
95        f: &mut fmt::Formatter,
96        prev_mod: Option<Modifier>,
97        next_mod: Option<Modifier>,
98    ) -> fmt::Result {
99        let modifier = if prev_mod == Some(self.modifier) {
100            Modifier::None
101        } else {
102            self.modifier
103        };
104        let end = if next_mod == Some(self.modifier) {
105            Modifier::None
106        } else {
107            Modifier::END
108        };
109
110        write!(f, "{}{}{}", modifier, self.text_char, end)
111    }
112}
113
114impl Default for ColChar {
115    fn default() -> Self {
116        Self::SOLID
117    }
118}
119
120impl Display for ColChar {
121    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122        match self.modifier {
123            Modifier::None => write!(f, "{}", self.text_char),
124            _ => write!(f, "{}{}{}", self.modifier, self.text_char, Modifier::END),
125        }
126    }
127}