runmat_plot/styling/
theme.rs

1//! Modern dark theme system with professional styling
2//!
3//! Provides a sleek, modern dark theme with excellent contrast,
4//! readability, and visual hierarchy.
5
6use glam::Vec4;
7
8/// Professional color palette for the modern dark theme
9#[derive(Debug, Clone)]
10pub struct ModernDarkTheme {
11    // Background colors
12    pub background_primary: Vec4,
13    pub background_secondary: Vec4,
14    pub background_tertiary: Vec4,
15
16    // Text colors
17    pub text_primary: Vec4,
18    pub text_secondary: Vec4,
19    pub text_accent: Vec4,
20
21    // Accent colors (inspired by the green theme in the image)
22    pub accent_primary: Vec4,
23    pub accent_secondary: Vec4,
24    pub accent_success: Vec4,
25    pub accent_warning: Vec4,
26    pub accent_error: Vec4,
27
28    // Plot colors
29    pub plot_background: Vec4,
30    pub grid_major: Vec4,
31    pub grid_minor: Vec4,
32    pub axis_color: Vec4,
33
34    // Data colors (beautiful palette for multiple series)
35    pub data_colors: Vec<Vec4>,
36}
37
38impl Default for ModernDarkTheme {
39    fn default() -> Self {
40        Self {
41            // Rich dark backgrounds with subtle gradients
42            background_primary: Vec4::new(0.08, 0.09, 0.11, 1.0), // Deep charcoal
43            background_secondary: Vec4::new(0.12, 0.14, 0.16, 1.0), // Lighter charcoal
44            background_tertiary: Vec4::new(0.16, 0.18, 0.21, 1.0), // Card backgrounds
45
46            // High contrast text for excellent readability
47            text_primary: Vec4::new(0.95, 0.96, 0.97, 1.0), // Almost white
48            text_secondary: Vec4::new(0.75, 0.78, 0.82, 1.0), // Light grey
49            text_accent: Vec4::new(0.40, 0.85, 0.55, 1.0),  // Beautiful green accent
50
51            // Modern accent colors inspired by the provided image
52            accent_primary: Vec4::new(0.35, 0.78, 0.48, 1.0), // Primary green
53            accent_secondary: Vec4::new(0.28, 0.65, 0.40, 1.0), // Darker green
54            accent_success: Vec4::new(0.42, 0.85, 0.55, 1.0), // Success green
55            accent_warning: Vec4::new(0.95, 0.75, 0.25, 1.0), // Warm amber
56            accent_error: Vec4::new(0.92, 0.35, 0.35, 1.0),   // Soft red
57
58            // Professional plot styling
59            plot_background: Vec4::new(0.10, 0.11, 0.13, 1.0), // Slightly lighter than main bg
60            grid_major: Vec4::new(0.25, 0.27, 0.30, 0.6),      // Subtle grid lines
61            grid_minor: Vec4::new(0.20, 0.22, 0.25, 0.3),      // Very subtle minor grid
62            axis_color: Vec4::new(0.65, 0.68, 0.72, 1.0),      // Clear axis lines
63
64            // Beautiful data color palette (carefully chosen for contrast and aesthetics)
65            data_colors: vec![
66                Vec4::new(0.35, 0.78, 0.48, 1.0), // Primary green
67                Vec4::new(0.25, 0.65, 0.85, 1.0), // Beautiful blue
68                Vec4::new(0.95, 0.55, 0.25, 1.0), // Warm orange
69                Vec4::new(0.75, 0.35, 0.85, 1.0), // Royal purple
70                Vec4::new(0.95, 0.75, 0.25, 1.0), // Golden yellow
71                Vec4::new(0.85, 0.35, 0.55, 1.0), // Rose pink
72                Vec4::new(0.25, 0.85, 0.75, 1.0), // Turquoise
73                Vec4::new(0.65, 0.75, 0.35, 1.0), // Lime green
74            ],
75        }
76    }
77}
78
79impl ModernDarkTheme {
80    /// Get data color by index (cycles through palette)
81    pub fn get_data_color(&self, index: usize) -> Vec4 {
82        self.data_colors[index % self.data_colors.len()]
83    }
84
85    /// Create a lighter variant of a color (for highlights)
86    pub fn lighten_color(color: Vec4, factor: f32) -> Vec4 {
87        Vec4::new(
88            (color.x + factor).min(1.0),
89            (color.y + factor).min(1.0),
90            (color.z + factor).min(1.0),
91            color.w,
92        )
93    }
94
95    /// Create a darker variant of a color (for shadows)
96    pub fn darken_color(color: Vec4, factor: f32) -> Vec4 {
97        Vec4::new(
98            (color.x - factor).max(0.0),
99            (color.y - factor).max(0.0),
100            (color.z - factor).max(0.0),
101            color.w,
102        )
103    }
104
105    /// Apply this theme to egui context
106    pub fn apply_to_egui(&self, ctx: &egui::Context) {
107        let mut visuals = egui::Visuals::dark();
108
109        // Main UI colors
110        visuals.window_fill = egui::Color32::from_rgba_unmultiplied(
111            (self.background_secondary.x * 255.0) as u8,
112            (self.background_secondary.y * 255.0) as u8,
113            (self.background_secondary.z * 255.0) as u8,
114            (self.background_secondary.w * 255.0) as u8,
115        );
116
117        visuals.panel_fill = egui::Color32::from_rgba_unmultiplied(
118            (self.background_tertiary.x * 255.0) as u8,
119            (self.background_tertiary.y * 255.0) as u8,
120            (self.background_tertiary.z * 255.0) as u8,
121            (self.background_tertiary.w * 255.0) as u8,
122        );
123
124        // Text colors
125        visuals.widgets.noninteractive.fg_stroke.color = egui::Color32::from_rgba_unmultiplied(
126            (self.text_primary.x * 255.0) as u8,
127            (self.text_primary.y * 255.0) as u8,
128            (self.text_primary.z * 255.0) as u8,
129            (self.text_primary.w * 255.0) as u8,
130        );
131
132        // Accent colors
133        visuals.selection.bg_fill = egui::Color32::from_rgba_unmultiplied(
134            (self.accent_primary.x * 255.0) as u8,
135            (self.accent_primary.y * 255.0) as u8,
136            (self.accent_primary.z * 255.0) as u8,
137            64, // Semi-transparent
138        );
139
140        // Apply the theme
141        ctx.set_visuals(visuals);
142    }
143}
144
145/// Typography system for professional text rendering
146#[derive(Debug, Clone)]
147pub struct Typography {
148    pub title_font_size: f32,
149    pub subtitle_font_size: f32,
150    pub axis_label_font_size: f32,
151    pub tick_label_font_size: f32,
152    pub legend_font_size: f32,
153
154    pub title_font_family: String,
155    pub body_font_family: String,
156    pub monospace_font_family: String,
157}
158
159impl Default for Typography {
160    fn default() -> Self {
161        Self {
162            title_font_size: 18.0,
163            subtitle_font_size: 14.0,
164            axis_label_font_size: 12.0,
165            tick_label_font_size: 10.0,
166            legend_font_size: 11.0,
167
168            title_font_family: "SF Pro Display".to_string(), // Modern, clean
169            body_font_family: "SF Pro Text".to_string(),     // Readable
170            monospace_font_family: "SF Mono".to_string(),    // For numbers
171        }
172    }
173}
174
175/// Professional spacing and layout constants
176#[derive(Debug, Clone)]
177pub struct Layout {
178    pub plot_padding: f32,
179    pub title_margin: f32,
180    pub axis_margin: f32,
181    pub legend_margin: f32,
182    pub grid_line_width: f32,
183    pub axis_line_width: f32,
184    pub data_line_width: f32,
185    pub point_size: f32,
186}
187
188impl Default for Layout {
189    fn default() -> Self {
190        Self {
191            plot_padding: 20.0,
192            title_margin: 15.0,
193            axis_margin: 10.0,
194            legend_margin: 8.0,
195            grid_line_width: 0.5,
196            axis_line_width: 1.0,
197            data_line_width: 2.0,
198            point_size: 4.0,
199        }
200    }
201}