1use std::ops::Mul;
2
3use freya_engine::prelude::{
4 SkColor,
5 SkColor4f,
6 SkRGB,
7};
8
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, Hash)]
11pub struct Color(u32);
12
13impl Mul<f32> for Color {
14 type Output = Color;
15 fn mul(self, rhs: f32) -> Self::Output {
16 (
17 (self.r() as f32 * rhs) as u8,
18 (self.g() as f32 * rhs) as u8,
19 (self.b() as f32 * rhs) as u8,
20 self.a(),
21 )
22 .into()
23 }
24}
25
26impl Color {
27 pub fn mul_if(self, check: bool, var: f32) -> Self {
28 if check { self * var } else { self }
29 }
30}
31
32impl From<(u8, u8, u8)> for Color {
33 fn from((r, g, b): (u8, u8, u8)) -> Self {
34 Color::from_rgb(r, g, b)
35 }
36}
37
38impl From<(u8, u8, u8, f32)> for Color {
39 fn from((r, g, b, a): (u8, u8, u8, f32)) -> Self {
40 Color::from_af32rgb(a, r, g, b)
41 }
42}
43
44impl From<(u8, u8, u8, u8)> for Color {
45 fn from((r, g, b, a): (u8, u8, u8, u8)) -> Self {
46 Color::from_argb(a, r, g, b)
47 }
48}
49
50impl From<u32> for Color {
51 fn from(value: u32) -> Self {
52 Color(value)
53 }
54}
55
56impl From<Color> for u32 {
57 fn from(value: Color) -> Self {
58 value.0
59 }
60}
61
62impl From<Color> for SkColor {
63 fn from(value: Color) -> Self {
64 Self::new(value.0)
65 }
66}
67
68impl From<Color> for SkColor4f {
69 fn from(value: Color) -> Self {
70 SkColor4f::new(
71 value.r() as f32,
72 value.g() as f32,
73 value.b() as f32,
74 value.a() as f32,
75 )
76 }
77}
78
79impl From<SkColor> for Color {
80 fn from(value: SkColor) -> Self {
81 let a = value.a();
82 let r = value.r();
83 let g = value.g();
84 let b = value.b();
85 Color::from_argb(a, r, g, b)
86 }
87}
88
89impl Color {
90 pub const TRANSPARENT: Self = Color::new(0);
91 pub const BLACK: Self = Color::new(4278190080);
92 pub const DARK_GRAY: Self = Color::new(4282664004);
93 pub const GRAY: Self = Color::new(4287137928);
94 pub const LIGHT_GRAY: Self = Color::new(4291611852);
95 pub const DARK_GREY: Self = Color::new(4282664004);
96 pub const GREY: Self = Color::new(4287137928);
97 pub const LIGHT_GREY: Self = Color::new(4291611852);
98 pub const WHITE: Self = Color::new(4294967295);
99 pub const RED: Self = Color::new(4294901760);
100 pub const GREEN: Self = Color::new(4278255360);
101 pub const BLUE: Self = Color::new(4278190335);
102 pub const YELLOW: Self = Color::new(4294967040);
103 pub const CYAN: Self = Color::new(4278255615);
104 pub const MAGENTA: Self = Color::new(4294902015);
105
106 pub const fn new(value: u32) -> Self {
107 Self(value)
108 }
109
110 pub const fn from_af32rgb(a: f32, r: u8, g: u8, b: u8) -> Self {
111 Self::from_argb((255. * a) as u8, r, g, b)
112 }
113
114 pub const fn from_argb(a: u8, r: u8, g: u8, b: u8) -> Self {
115 Self(((a as u32) << 24) | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32))
116 }
117
118 pub const fn from_rgb(r: u8, g: u8, b: u8) -> Self {
119 Self::from_argb(255, r, g, b)
120 }
121
122 pub fn from_hex(hex: &str) -> Option<Self> {
123 let s = if let Some(stripped) = hex.strip_prefix('#') {
124 stripped
125 } else if let Some(stripped) = hex.strip_prefix("0x") {
126 stripped
127 } else {
128 hex
129 };
130
131 match s.len() {
132 6 => {
133 u32::from_str_radix(s, 16).ok().map(|rgb| {
135 let r = ((rgb >> 16) & 0xFF) as u8;
136 let g = ((rgb >> 8) & 0xFF) as u8;
137 let b = (rgb & 0xFF) as u8;
138 Color::from_rgb(r, g, b)
139 })
140 }
141 8 => {
142 u32::from_str_radix(s, 16).ok().map(|rgba| {
144 let r = ((rgba >> 24) & 0xFF) as u8;
145 let g = ((rgba >> 16) & 0xFF) as u8;
146 let b = ((rgba >> 8) & 0xFF) as u8;
147 let a = (rgba & 0xFF) as u8;
148 Color::from_argb(a, r, g, b)
149 })
150 }
151 _ => None,
152 }
153 }
154
155 pub fn with_a(self, a: u8) -> Self {
156 let color: SkColor = self.into();
157 color.with_a(a).into()
158 }
159
160 pub fn a(self) -> u8 {
161 (self.0 >> 24) as _
162 }
163
164 pub fn r(self) -> u8 {
165 (self.0 >> 16) as _
166 }
167
168 pub fn g(self) -> u8 {
169 (self.0 >> 8) as _
170 }
171
172 pub fn b(self) -> u8 {
173 self.0 as _
174 }
175
176 pub fn to_rgb(self) -> SkRGB {
177 let color: SkColor = self.into();
178 color.to_rgb()
179 }
180
181 pub fn pretty(&self) -> String {
182 format!(
183 "({:?}, {:?}, {:?}, {:?})",
184 self.r(),
185 self.g(),
186 self.b(),
187 self.a() as f32 / 100.
188 )
189 }
190}