freya_core/style/
color.rs

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                // RRGGBB
134                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                // RRGGBBAA
143                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}