freya_core/style/
color.rs

1use std::ops::Mul;
2
3use freya_engine::prelude::{
4    SkColor,
5    SkColor4f,
6    SkHSV,
7    SkRGB,
8};
9
10/// Represents one color.
11/// You may create [Color]s using
12/// - [Color::from_rgb],
13/// - [Color::from_argb],
14/// - [Color::from_af32rgb],
15/// - [Color::new],
16/// - Or using tuples like `(255, 0, 150)`, `(133, 133, 133, 0.5)` (alpha as `f32` in 0.0..=1.0), or `(200, 100, 50, 180)` (alpha as `u8` in 0..=255)
17#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
18#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, Hash)]
19pub struct Color(u32);
20
21impl Mul<f32> for Color {
22    type Output = Color;
23    fn mul(self, rhs: f32) -> Self::Output {
24        (
25            (self.r() as f32 * rhs) as u8,
26            (self.g() as f32 * rhs) as u8,
27            (self.b() as f32 * rhs) as u8,
28            self.a(),
29        )
30            .into()
31    }
32}
33
34impl Color {
35    pub fn mul_if(self, check: bool, var: f32) -> Self {
36        if check { self * var } else { self }
37    }
38}
39
40impl From<(u8, u8, u8)> for Color {
41    fn from((r, g, b): (u8, u8, u8)) -> Self {
42        Color::from_rgb(r, g, b)
43    }
44}
45
46impl From<(u8, u8, u8, f32)> for Color {
47    fn from((r, g, b, a): (u8, u8, u8, f32)) -> Self {
48        Color::from_af32rgb(a, r, g, b)
49    }
50}
51
52impl From<(u8, u8, u8, u8)> for Color {
53    fn from((r, g, b, a): (u8, u8, u8, u8)) -> Self {
54        Color::from_argb(a, r, g, b)
55    }
56}
57
58impl From<u32> for Color {
59    fn from(value: u32) -> Self {
60        Color(value)
61    }
62}
63
64impl From<Color> for u32 {
65    fn from(value: Color) -> Self {
66        value.0
67    }
68}
69
70impl From<Color> for SkColor {
71    fn from(value: Color) -> Self {
72        Self::new(value.0)
73    }
74}
75
76impl From<Color> for SkColor4f {
77    fn from(value: Color) -> Self {
78        SkColor4f::new(
79            value.r() as f32,
80            value.g() as f32,
81            value.b() as f32,
82            value.a() as f32,
83        )
84    }
85}
86
87impl From<SkColor> for Color {
88    fn from(value: SkColor) -> Self {
89        let a = value.a();
90        let r = value.r();
91        let g = value.g();
92        let b = value.b();
93        Color::from_argb(a, r, g, b)
94    }
95}
96
97impl Color {
98    pub const TRANSPARENT: Self = Color::new(0);
99    pub const BLACK: Self = Color::new(4278190080);
100    pub const DARK_GRAY: Self = Color::new(4282664004);
101    pub const GRAY: Self = Color::new(4287137928);
102    pub const LIGHT_GRAY: Self = Color::new(4291611852);
103    pub const DARK_GREY: Self = Color::new(4282664004);
104    pub const GREY: Self = Color::new(4287137928);
105    pub const LIGHT_GREY: Self = Color::new(4291611852);
106    pub const WHITE: Self = Color::new(4294967295);
107    pub const RED: Self = Color::new(4294901760);
108    pub const GREEN: Self = Color::new(4278255360);
109    pub const BLUE: Self = Color::new(4278190335);
110    pub const YELLOW: Self = Color::new(4294967040);
111    pub const CYAN: Self = Color::new(4278255615);
112    pub const MAGENTA: Self = Color::new(4294902015);
113
114    pub const fn new(value: u32) -> Self {
115        Self(value)
116    }
117
118    pub const fn from_af32rgb(a: f32, r: u8, g: u8, b: u8) -> Self {
119        Self::from_argb((255. * a) as u8, r, g, b)
120    }
121
122    pub const fn from_argb(a: u8, r: u8, g: u8, b: u8) -> Self {
123        Self(((a as u32) << 24) | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32))
124    }
125
126    pub const fn from_rgb(r: u8, g: u8, b: u8) -> Self {
127        Self::from_argb(255, r, g, b)
128    }
129
130    pub fn from_hsv(h: f32, s: f32, v: f32) -> Self {
131        SkHSV { h, s, v }.to_color(255).into()
132    }
133
134    pub fn from_hex(hex: &str) -> Option<Self> {
135        let s = if let Some(stripped) = hex.strip_prefix('#') {
136            stripped
137        } else if let Some(stripped) = hex.strip_prefix("0x") {
138            stripped
139        } else {
140            hex
141        };
142
143        match s.len() {
144            6 => {
145                // RRGGBB
146                u32::from_str_radix(s, 16).ok().map(|rgb| {
147                    let r = ((rgb >> 16) & 0xFF) as u8;
148                    let g = ((rgb >> 8) & 0xFF) as u8;
149                    let b = (rgb & 0xFF) as u8;
150                    Color::from_rgb(r, g, b)
151                })
152            }
153            8 => {
154                // RRGGBBAA
155                u32::from_str_radix(s, 16).ok().map(|rgba| {
156                    let r = ((rgba >> 24) & 0xFF) as u8;
157                    let g = ((rgba >> 16) & 0xFF) as u8;
158                    let b = ((rgba >> 8) & 0xFF) as u8;
159                    let a = (rgba & 0xFF) as u8;
160                    Color::from_argb(a, r, g, b)
161                })
162            }
163            _ => None,
164        }
165    }
166
167    pub fn with_a(self, a: u8) -> Self {
168        let color: SkColor = self.into();
169        color.with_a(a).into()
170    }
171
172    pub fn a(self) -> u8 {
173        (self.0 >> 24) as _
174    }
175
176    pub fn r(self) -> u8 {
177        (self.0 >> 16) as _
178    }
179
180    pub fn g(self) -> u8 {
181        (self.0 >> 8) as _
182    }
183
184    pub fn b(self) -> u8 {
185        self.0 as _
186    }
187
188    pub fn to_rgb(self) -> SkRGB {
189        let color: SkColor = self.into();
190        color.to_rgb()
191    }
192
193    pub fn to_hsv(self) -> SkHSV {
194        let color: SkColor = self.into();
195        color.to_hsv()
196    }
197
198    pub fn with_h(self, h: f32) -> Color {
199        let color: SkColor = self.into();
200        let hsv = color.to_hsv();
201        Self::from_hsv(h, hsv.s, hsv.v)
202    }
203
204    pub fn with_s(self, s: f32) -> Color {
205        let color: SkColor = self.into();
206        let hsv = color.to_hsv();
207        Self::from_hsv(hsv.h, s, hsv.v)
208    }
209
210    pub fn with_v(self, v: f32) -> Color {
211        let color: SkColor = self.into();
212        let hsv = color.to_hsv();
213        Self::from_hsv(hsv.h, hsv.s, v)
214    }
215
216    pub fn to_hex_string(&self) -> String {
217        format!(
218            "#{:02X}{:02X}{:02X}{:02X}",
219            self.a(),
220            self.r(),
221            self.g(),
222            self.b(),
223        )
224    }
225
226    pub fn to_rgb_string(&self) -> String {
227        format!(
228            "rgb({:?}, {:?}, {:?}, {:?})",
229            self.r(),
230            self.g(),
231            self.b(),
232            self.a() as f32 / 100.
233        )
234    }
235
236    pub fn pretty(&self) -> String {
237        self.to_rgb_string()
238    }
239}