Skip to main content

rscad_core/
color.rs

1use crate::prelude_::*;
2#[derive(Clone, Copy, Debug, Default)]
3#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
4#[cfg_attr(feature = "reflect", derive(bevy_reflect::Reflect))]
5pub struct Colored<T: Object> {
6    pub object: T,
7    pub color: Color,
8}
9
10impl<O: Object> Colored<O> {
11    pub fn new<X: ColorFormat>(object: O, color: X) -> Self {
12        Self {
13            object,
14            color: color.color(),
15        }
16    }
17}
18
19#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
20#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
21#[cfg_attr(feature = "reflect", derive(bevy_reflect::Reflect))]
22pub struct Color {
23    pub r: u8,
24    pub g: u8,
25    pub b: u8,
26    pub a: u8,
27}
28
29impl Color {
30    pub const WHITE: Self = Self::new(0xff, 0xff, 0xff, 0xff);
31    pub const BLACK: Self = Self::new(0, 0, 0, 0xff);
32    pub const RED: Self = Self::new(0xff, 0, 0, 0xff);
33    pub const GREEN: Self = Self::new(0, 0xff, 0, 0xff);
34    pub const BLUE: Self = Self::new(0, 0, 0xff, 0xff);
35    pub const YELLOW: Self = Self::new(0xff, 0xff, 0, 0xff);
36    pub const CYAN: Self = Self::new(0, 0xff, 0xff, 0xff);
37    pub const MAGENTA: Self = Self::new(0xff, 0, 0xff, 0xff);
38    pub const fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
39        Self { r, g, b, a }
40    }
41    pub fn parse(hex: &str) -> Result<Self> {
42        let hex = hex.trim_start_matches('#');
43        match hex.len() {
44            3 => {
45                let r = u8::from_str_radix(&hex[0..1], 16).cc()?;
46                let g = u8::from_str_radix(&hex[1..2], 16).cc()?;
47                let b = u8::from_str_radix(&hex[2..3], 16).cc()?;
48                Ok(Self::new(r * 0x11, g * 0x11, b * 0x11, 0xff))
49            }
50            4 => {
51                let r = u8::from_str_radix(&hex[0..1], 16).cc()?;
52                let g = u8::from_str_radix(&hex[1..2], 16).cc()?;
53                let b = u8::from_str_radix(&hex[2..3], 16).cc()?;
54                let a = u8::from_str_radix(&hex[3..4], 16).cc()?;
55                Ok(Self::new(r * 0x11, g * 0x11, b * 0x11, a * 0x11))
56            }
57            6 => {
58                let r = u8::from_str_radix(&hex[0..2], 16).cc()?;
59                let g = u8::from_str_radix(&hex[2..4], 16).cc()?;
60                let b = u8::from_str_radix(&hex[4..6], 16).cc()?;
61                Ok(Self::new(r, g, b, 0xff))
62            }
63            8 => {
64                let r = u8::from_str_radix(&hex[0..2], 16).cc()?;
65                let g = u8::from_str_radix(&hex[2..4], 16).cc()?;
66                let b = u8::from_str_radix(&hex[4..6], 16).cc()?;
67                let a = u8::from_str_radix(&hex[6..8], 16).cc()?;
68                Ok(Self::new(r, g, b, a))
69            }
70            _ => Err(Error).attach("Failed to parse hex color"),
71        }
72    }
73}
74
75pub trait ColorFormat {
76    fn color(self) -> Color;
77}
78
79impl ColorFormat for (u8, u8, u8) {
80    fn color(self) -> Color {
81        Color::new(self.0, self.1, self.2, 0xff)
82    }
83}
84impl ColorFormat for (u8, u8, u8, u8) {
85    fn color(self) -> Color {
86        Color::new(self.0, self.1, self.2, self.3)
87    }
88}
89impl ColorFormat for [u8; 3] {
90    fn color(self) -> Color {
91        Color::new(self[0], self[1], self[2], 0xff)
92    }
93}
94impl ColorFormat for [u8; 4] {
95    fn color(self) -> Color {
96        Color::new(self[0], self[1], self[2], self[3])
97    }
98}
99
100impl ColorFormat for u32 {
101    fn color(self) -> Color {
102        Color::new(
103            ((self >> 16) & 0xff) as u8,
104            ((self >> 8) & 0xff) as u8,
105            (self & 0xff) as u8,
106            0xff,
107        )
108    }
109}
110
111impl ColorFormat for Color {
112    fn color(self) -> Color {
113        self
114    }
115}
116
117pub trait ColorObject: Object + Sized {
118    fn colored(self, color: impl ColorFormat) -> Colored<Self>;
119}
120
121impl<T: Object + Sized> ColorObject for T {
122    fn colored(self, color: impl ColorFormat) -> Colored<Self> {
123        Colored::new(self, color)
124    }
125}
126
127impl<T: Object> Object for Colored<T> {}
128
129pub trait ColorExt: Object {
130    fn color(&self) -> Color;
131}
132
133impl<T: Object> ColorExt for Colored<T> {
134    fn color(&self) -> Color {
135        self.color
136    }
137}
138
139impl<A: Object, B: ColorExt> ColorExt for TwoContainer<A, B> {
140    fn color(&self) -> Color {
141        B::color(&self.b)
142    }
143}