1use egui::Color32;
11use facett_core::Theme;
12
13#[derive(Clone, Copy, Debug)]
16pub struct Ramp {
17 stops: [Color32; 3],
19}
20
21impl Ramp {
22 pub fn sequential(th: &Theme) -> Self {
25 let low = lerp_color(th.bg, th.accent, 0.25);
28 Self { stops: [low, th.accent, th.glow] }
29 }
30
31 pub fn diverging(th: &Theme) -> Self {
34 Self { stops: [th.accent, th.text_dim, th.glow] }
35 }
36
37 pub fn at(&self, t: f32) -> Color32 {
39 let t = t.clamp(0.0, 1.0);
40 if t <= 0.5 {
41 lerp_color(self.stops[0], self.stops[1], t * 2.0)
42 } else {
43 lerp_color(self.stops[1], self.stops[2], (t - 0.5) * 2.0)
44 }
45 }
46
47 pub fn stops(&self) -> [Color32; 3] {
49 self.stops
50 }
51}
52
53pub fn lerp_color(a: Color32, b: Color32, t: f32) -> Color32 {
56 let t = t.clamp(0.0, 1.0);
57 let l = |x: u8, y: u8| (x as f32 + (y as f32 - x as f32) * t).round().clamp(0.0, 255.0) as u8;
58 Color32::from_rgba_unmultiplied(l(a.r(), b.r()), l(a.g(), b.g()), l(a.b(), b.b()), l(a.a(), b.a()))
59}
60
61pub fn normalize(v: f64, min: f64, max: f64) -> f32 {
64 if !(max > min) {
65 return 0.5;
66 }
67 (((v - min) / (max - min)) as f32).clamp(0.0, 1.0)
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 #[test]
75 fn lerp_endpoints_and_mid() {
76 let a = Color32::from_rgb(0, 0, 0);
77 let b = Color32::from_rgb(100, 200, 50);
78 assert_eq!(lerp_color(a, b, 0.0), a);
79 assert_eq!(lerp_color(a, b, 1.0), b);
80 let m = lerp_color(a, b, 0.5);
81 assert_eq!((m.r(), m.g(), m.b()), (50, 100, 25));
82 }
83
84 #[test]
85 fn ramp_hits_its_stops() {
86 let r = Ramp::sequential(&Theme::default());
87 let [lo, mid, hi] = r.stops();
88 assert_eq!(r.at(0.0), lo);
89 assert_eq!(r.at(0.5), mid);
90 assert_eq!(r.at(1.0), hi);
91 }
92
93 #[test]
94 fn ramp_clamps_out_of_range() {
95 let r = Ramp::diverging(&Theme::sci_fi());
96 assert_eq!(r.at(-3.0), r.at(0.0));
97 assert_eq!(r.at(9.0), r.at(1.0));
98 }
99
100 #[test]
101 fn normalize_handles_degenerate_range() {
102 assert_eq!(normalize(5.0, 5.0, 5.0), 0.5);
103 assert_eq!(normalize(0.0, 0.0, 10.0), 0.0);
104 assert_eq!(normalize(10.0, 0.0, 10.0), 1.0);
105 assert_eq!(normalize(2.5, 0.0, 10.0), 0.25);
106 assert_eq!(normalize(-1.0, 0.0, 10.0), 0.0);
108 assert_eq!(normalize(99.0, 0.0, 10.0), 1.0);
109 }
110}