1use egui::Color32;
4
5#[derive(Debug, Clone)]
7#[cfg_attr(feature = "persistence", derive(serde::Serialize, serde::Deserialize))]
8pub struct Theme {
9 pub background: Color32,
11 pub grid: Color32,
13 pub primary_curve: Color32,
15 pub secondary_curve: Color32,
17 pub text: Color32,
19 pub axis: Color32,
21 pub is_dark: bool,
23}
24
25impl Default for Theme {
26 fn default() -> Self {
27 Self::light()
28 }
29}
30
31impl Theme {
32 pub fn light() -> Self {
34 Self {
35 background: Color32::WHITE,
36 grid: Color32::from_gray(220),
37 primary_curve: Color32::from_rgb(220, 60, 60), secondary_curve: Color32::from_rgb(60, 60, 220), text: Color32::from_gray(40),
40 axis: Color32::from_gray(100),
41 is_dark: false,
42 }
43 }
44
45 pub fn dark() -> Self {
47 Self {
48 background: Color32::from_gray(30),
49 grid: Color32::from_gray(60),
50 primary_curve: Color32::from_rgb(255, 100, 100), secondary_curve: Color32::from_rgb(100, 150, 255), text: Color32::from_gray(220),
53 axis: Color32::from_gray(150),
54 is_dark: true,
55 }
56 }
57
58 pub fn from_egui(ctx: &egui::Context) -> Self {
60 if ctx.style().visuals.dark_mode {
61 Self::dark()
62 } else {
63 Self::light()
64 }
65 }
66
67 pub fn c_plane_color(&self, c_angle: f64, _total_planes: usize) -> Color32 {
69 let hue = (c_angle / 360.0) as f32;
70 let (r, g, b) = hsl_to_rgb(hue, 0.7, if self.is_dark { 0.6 } else { 0.45 });
71 Color32::from_rgb(r, g, b)
72 }
73
74 pub fn heatmap_color(&self, normalized: f64) -> Color32 {
76 let n = normalized.clamp(0.0, 1.0) as f32;
77
78 let (r, g, b) = if n < 0.25 {
80 let t = n / 0.25;
81 (0.0, t, 1.0) } else if n < 0.5 {
83 let t = (n - 0.25) / 0.25;
84 (0.0, 1.0, 1.0 - t) } else if n < 0.75 {
86 let t = (n - 0.5) / 0.25;
87 (t, 1.0, 0.0) } else {
89 let t = (n - 0.75) / 0.25;
90 (1.0, 1.0 - t, 0.0) };
92
93 Color32::from_rgb((r * 255.0) as u8, (g * 255.0) as u8, (b * 255.0) as u8)
94 }
95}
96
97fn hsl_to_rgb(h: f32, s: f32, l: f32) -> (u8, u8, u8) {
99 let c = (1.0 - (2.0 * l - 1.0).abs()) * s;
100 let x = c * (1.0 - ((h * 6.0) % 2.0 - 1.0).abs());
101 let m = l - c / 2.0;
102
103 let (r, g, b) = match (h * 6.0) as u32 {
104 0 => (c, x, 0.0),
105 1 => (x, c, 0.0),
106 2 => (0.0, c, x),
107 3 => (0.0, x, c),
108 4 => (x, 0.0, c),
109 _ => (c, 0.0, x),
110 };
111
112 (
113 ((r + m) * 255.0) as u8,
114 ((g + m) * 255.0) as u8,
115 ((b + m) * 255.0) as u8,
116 )
117}