1use egui::Color32;
2use palette::{Hsl, IntoColor, Srgba};
3
4#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
5#[derive(Debug, Clone, Copy)]
6pub struct Hsla {
7 pub h: f32,
9 pub s: f32,
11 pub l: f32,
13 pub a: f32,
15}
16
17impl Hsla {
18 pub fn from_color32(c: Color32) -> Self {
19 let srgba = Srgba::new(
20 c.r() as f32 / 255.0,
21 c.g() as f32 / 255.0,
22 c.b() as f32 / 255.0,
23 c.a() as f32 / 255.0,
24 );
25 let hsl: Hsl = srgba.into_color();
26 let (h, s, l) = hsl.into_components();
27 let mut hue = h.into_degrees();
29 hue = (hue % 360.0 + 360.0) % 360.0;
30 Hsla {
31 h: hue,
32 s: s * 100.0,
33 l: l * 100.0,
34 a: srgba.alpha,
35 }
36 }
37
38 pub fn from_hex(hex: &str) -> Option<Self> {
39 match Color32::from_hex(hex) {
40 Ok(c) => Some(Self::from_color32(c)),
41 Err(_) => None,
42 }
43 }
44
45 pub fn to_color32(&self) -> Color32 {
46 let srgba = self.to_srgba();
47 let (r, g, b, a) = srgba.into_components();
48 Color32::from_rgba_unmultiplied(
49 (r * 255.0) as u8,
50 (g * 255.0) as u8,
51 (b * 255.0) as u8,
52 (a * 255.0) as u8,
53 )
54 }
55
56 pub fn to_srgba(&self) -> Srgba {
57 let hsl = Hsl::new(self.h, self.s / 100.0, self.l / 100.0);
58 hsl.into_color()
59 }
60
61 pub fn to_rgba_components(&self) -> (u8, u8, u8, u8) {
62 let srgba = self.to_srgba();
63 let (r, g, b, a) = srgba.into_components();
64 let r = (r * 255.0) as u8;
65 let g = (g * 255.0) as u8;
66 let b = (b * 255.0) as u8;
67 let a = (a * 255.0) as u8;
68 (r, g, b, a)
69 }
70
71 pub fn shades(&self, num_shades: usize, direction: ShadeDirection) -> Vec<Color32> {
72 let mut shades = Vec::new();
73 let step = if direction == ShadeDirection::Lighter {
74 5.0
75 } else {
76 -5.0
77 };
78 let mut current = *self;
79 for _ in 0..num_shades {
80 shades.push(current.to_color32());
81 current.l = (current.l as f32 + step).clamp(0.0, 100.0);
82 }
83 shades
84 }
85}
86
87#[derive(Debug, PartialEq, Eq, Clone, Copy)]
88pub enum ShadeDirection {
89 Lighter,
90 Darker,
91}