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