Skip to main content

zeus_theme/
hsla.rs

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   /// Hue 0.0..=360.0
8   pub h: f32,
9   /// Saturation 0.0..=100.0
10   pub s: f32,
11   /// Lightness 0.0..=100.0
12   pub l: f32,
13   /// Alpha 0.0..=1.0
14   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      // Normalize hue to [0, 360)
28      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}