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}