Skip to main content

weact_studio_epd/
color.rs

1#[cfg(feature = "graphics")]
2use embedded_graphics::pixelcolor::{BinaryColor, Rgb555, Rgb565, Rgb888, RgbColor};
3use sealed::sealed;
4
5/// Color definition for B/W displays
6#[derive(Debug, Clone, Copy, PartialEq, Default)]
7pub enum Color {
8    /// Black color
9    Black,
10    /// White color
11    #[default]
12    White,
13}
14
15#[cfg_attr(docsrs, doc(cfg(feature = "graphics")))]
16#[cfg(feature = "graphics")]
17impl From<BinaryColor> for Color {
18    fn from(value: BinaryColor) -> Self {
19        match value {
20            BinaryColor::On => Color::White,
21            BinaryColor::Off => Color::Black,
22        }
23    }
24}
25
26/// Conversion to RGB888 to use `Color` with `embedded-graphics-simulator`.
27#[cfg_attr(docsrs, doc(cfg(feature = "graphics")))]
28#[cfg(feature = "graphics")]
29impl From<Color> for Rgb888 {
30    fn from(value: Color) -> Self {
31        match value {
32            Color::Black => Rgb888::BLACK,
33            Color::White => Rgb888::WHITE,
34        }
35    }
36}
37
38/// Conversion from RGB888 to use `Color` with `embedded-graphics-simulator`.
39///
40/// Panics if the RGB value is not black or white.
41#[cfg_attr(docsrs, doc(cfg(feature = "graphics")))]
42#[cfg(feature = "graphics")]
43impl From<Rgb888> for Color {
44    fn from(value: Rgb888) -> Self {
45        match value {
46            Rgb888::BLACK => Color::Black,
47            Rgb888::WHITE => Color::White,
48            _ => panic!("RGB value must be black or white"),
49        }
50    }
51}
52
53/// Conversion from Rgb565 to use `Color` with tinybmp
54#[cfg(feature = "graphics")]
55impl From<Rgb565> for Color {
56    fn from(rgb: Rgb565) -> Self {
57        if rgb == RgbColor::BLACK {
58            Color::White
59        } else if rgb == RgbColor::WHITE {
60            Color::Black
61        } else {
62            // choose closest color
63            if (rgb.r() as u16 + rgb.g() as u16 + rgb.b() as u16) > 255 * 3 / 2 {
64                Color::Black
65            } else {
66                Color::White
67            }
68        }
69    }
70}
71
72/// Conversion to Rgb565 to use `Color` with tinybmp
73#[cfg(feature = "graphics")]
74impl From<Color> for Rgb565 {
75    fn from(color: Color) -> Self {
76        match color {
77            Color::Black => Self::WHITE,
78            Color::White => Self::BLACK,
79        }
80    }
81}
82
83/// Conversion from Rgb555 to use `Color` with tinybmp
84#[cfg(feature = "graphics")]
85impl From<Rgb555> for Color {
86    fn from(rgb: Rgb555) -> Self {
87        if rgb == RgbColor::BLACK {
88            Color::White
89        } else if rgb == RgbColor::WHITE {
90            Color::Black
91        } else {
92            // choose closest color
93            if (rgb.r() as u16 + rgb.g() as u16 + rgb.b() as u16) > 255 * 3 / 2 {
94                Color::Black
95            } else {
96                Color::White
97            }
98        }
99    }
100}
101
102/// Conversion to Rgb555 to use `Color` with tinybmp
103#[cfg(feature = "graphics")]
104impl From<Color> for Rgb555 {
105    fn from(color: Color) -> Self {
106        match color {
107            Color::Black => Self::WHITE,
108            Color::White => Self::BLACK,
109        }
110    }
111}
112
113/// Color for tri-color displays
114#[derive(Debug, Clone, Copy, PartialEq, Default)]
115pub enum TriColor {
116    /// Black color
117    Black,
118    /// White color
119    #[default]
120    White,
121    /// Red color
122    Red,
123}
124
125/// Conversion to RGB888 to use `TriColor` with `embedded-graphics-simulator`.
126#[cfg_attr(docsrs, doc(cfg(feature = "graphics")))]
127#[cfg(feature = "graphics")]
128impl From<TriColor> for Rgb888 {
129    fn from(val: TriColor) -> Self {
130        match val {
131            TriColor::White => Rgb888::WHITE,
132            TriColor::Black => Rgb888::BLACK,
133            TriColor::Red => Rgb888::RED,
134        }
135    }
136}
137
138/// Conversion from RGB888 to use `Color` with `embedded-graphics-simulator`.
139///
140/// Panics if the RGB value is not black, white or red.
141#[cfg_attr(docsrs, doc(cfg(feature = "graphics")))]
142#[cfg(feature = "graphics")]
143impl From<Rgb888> for TriColor {
144    fn from(value: Rgb888) -> Self {
145        match value {
146            Rgb888::BLACK => TriColor::Black,
147            Rgb888::WHITE => TriColor::White,
148            Rgb888::RED => TriColor::Red,
149            _ => panic!("RGB value must be black, white, or red"),
150        }
151    }
152}
153
154/// Color trait for use in `Display`s.
155#[sealed]
156pub trait ColorType {
157    /// Number of buffers used to represent this color type.
158    const BUFFER_COUNT: usize;
159
160    /// Byte value of this color in the buffer.
161    ///
162    /// Useful for setting the full buffer to a single color.
163    ///
164    /// Return values are:
165    /// * `.0`: byte value in the first buffer
166    /// * `.1`: byte value in the second buffer (only applicable to TriColor)
167    fn byte_value(&self) -> (u8, u8);
168
169    /// Bit value of this color in the buffer.
170    ///
171    /// Return values are:
172    /// * `.0`: bit value in the first buffer
173    /// * `.1`: bit value in the second buffer (only applicable to TriColor)
174    fn bit_value(&self) -> (u8, u8);
175}
176
177#[sealed]
178impl ColorType for Color {
179    const BUFFER_COUNT: usize = 1;
180
181    fn byte_value(&self) -> (u8, u8) {
182        match self {
183            Color::Black => (0x00, 0),
184            Color::White => (0xFF, 0),
185        }
186    }
187
188    fn bit_value(&self) -> (u8, u8) {
189        match self {
190            Color::Black => (0b0, 0),
191            Color::White => (0b1, 0),
192        }
193    }
194}
195
196#[sealed]
197impl ColorType for TriColor {
198    const BUFFER_COUNT: usize = 2;
199
200    fn byte_value(&self) -> (u8, u8) {
201        // Red buffer value takes precedence over B/W buffer value.
202        match self {
203            TriColor::Black => (0x00, 0x00),
204            TriColor::White => (0xFF, 0x00),
205            TriColor::Red => (0, 0xFF),
206        }
207    }
208
209    fn bit_value(&self) -> (u8, u8) {
210        // Red buffer value takes precedence over B/W buffer value.
211        match self {
212            TriColor::Black => (0b0, 0b0),
213            TriColor::White => (0b1, 0b0),
214            TriColor::Red => (0, 0b1),
215        }
216    }
217}