diff --git a/src/theme.rs b/src/theme.rs new file mode 100644 index 0000000..552713a --- /dev/null +++ b/src/theme.rs @@ -0,0 +1,191 @@ +use eframe::egui; + +/// Modern dark purple color palette +pub struct ColorPalette { + // Background colors + pub bg_primary: egui::Color32, // Main background + pub bg_secondary: egui::Color32, // Secondary panels + pub bg_tertiary: egui::Color32, // Elevated elements + pub bg_hover: egui::Color32, // Hover states + + // Accent colors + pub accent_primary: egui::Color32, // Primary purple accent + pub accent_secondary: egui::Color32, // Secondary accent + pub accent_bright: egui::Color32, // Bright highlights + + // Text colors + pub text_primary: egui::Color32, + pub text_secondary: egui::Color32, + pub text_muted: egui::Color32, + + // UI element colors + pub selection: egui::Color32, + pub highlight: egui::Color32, + pub line_number: egui::Color32, + pub border: egui::Color32, + + // Status colors + pub success: egui::Color32, + pub warning: egui::Color32, + pub error: egui::Color32, +} + +impl ColorPalette { + pub fn dark_purple() -> Self { + Self { + // Deep purple-gray backgrounds + bg_primary: egui::Color32::from_rgb(24, 20, 32), // #18141F + bg_secondary: egui::Color32::from_rgb(32, 26, 42), // #201A2A + bg_tertiary: egui::Color32::from_rgb(42, 35, 54), // #2A2336 + bg_hover: egui::Color32::from_rgba_premultiplied(90, 75, 115, 40), + + // Purple accents - modern and vibrant + accent_primary: egui::Color32::from_rgb(138, 98, 208), // #8A62D0 + accent_secondary: egui::Color32::from_rgb(108, 68, 178), // #6C44B2 + accent_bright: egui::Color32::from_rgb(168, 128, 238), // #A880EE + + // Text colors with good contrast + text_primary: egui::Color32::from_rgb(230, 230, 240), // #E6E6F0 + text_secondary: egui::Color32::from_rgb(190, 190, 210), // #BEBED2 + text_muted: egui::Color32::from_rgb(140, 140, 165), // #8C8CA5 + + // UI elements + selection: egui::Color32::from_rgb(108, 68, 178), // #6C44B2 + highlight: egui::Color32::from_rgba_premultiplied(138, 98, 208, 60), + line_number: egui::Color32::from_rgb(110, 100, 130), // #6E6482 + border: egui::Color32::from_rgb(60, 50, 75), // #3C324B + + // Status colors + success: egui::Color32::from_rgb(100, 200, 130), // #64C882 + warning: egui::Color32::from_rgb(255, 180, 80), // #FFB450 + error: egui::Color32::from_rgb(240, 100, 120), // #F06478 + } + } +} + +/// Apply the dark purple theme to the egui context +pub fn apply_theme(ctx: &egui::Context) { + let palette = ColorPalette::dark_purple(); + + let mut style = (*ctx.style()).clone(); + + // === Spacing and sizing for better UX === + style.spacing.item_spacing = egui::vec2(8.0, 6.0); + style.spacing.button_padding = egui::vec2(12.0, 6.0); + style.spacing.menu_margin = egui::Margin::same(8.0); + style.spacing.indent = 20.0; + style.spacing.scroll = egui::style::ScrollStyle { + bar_width: 10.0, + handle_min_length: 20.0, + bar_inner_margin: 2.0, + bar_outer_margin: 0.0, + ..Default::default() + }; + + // === Color scheme === + let visuals = &mut style.visuals; + + // Dark mode + visuals.dark_mode = true; + + // Window and panel backgrounds + visuals.window_fill = palette.bg_primary; + visuals.panel_fill = palette.bg_primary; + visuals.faint_bg_color = palette.bg_secondary; + visuals.extreme_bg_color = palette.bg_tertiary; + + // Text colors (using override_text_color to set custom text color) + visuals.override_text_color = Some(palette.text_primary); + + // Widget colors + visuals.widgets.noninteractive.bg_fill = palette.bg_secondary; + visuals.widgets.noninteractive.weak_bg_fill = palette.bg_secondary; + visuals.widgets.noninteractive.bg_stroke = egui::Stroke::new(1.0, palette.border); + visuals.widgets.noninteractive.fg_stroke = egui::Stroke::new(1.0, palette.text_secondary); + + // Inactive/hovered widgets + visuals.widgets.inactive.bg_fill = palette.bg_secondary; + visuals.widgets.inactive.weak_bg_fill = palette.bg_secondary; + visuals.widgets.inactive.bg_stroke = egui::Stroke::new(1.0, palette.border); + visuals.widgets.inactive.fg_stroke = egui::Stroke::new(1.0, palette.text_primary); + + visuals.widgets.hovered.bg_fill = palette.bg_tertiary; + visuals.widgets.hovered.weak_bg_fill = palette.bg_tertiary; + visuals.widgets.hovered.bg_stroke = egui::Stroke::new(1.5, palette.accent_primary); + visuals.widgets.hovered.fg_stroke = egui::Stroke::new(1.5, palette.text_primary); + + // Active/clicked widgets + visuals.widgets.active.bg_fill = palette.accent_secondary; + visuals.widgets.active.weak_bg_fill = palette.accent_secondary; + visuals.widgets.active.bg_stroke = egui::Stroke::new(2.0, palette.accent_bright); + visuals.widgets.active.fg_stroke = egui::Stroke::new(2.0, palette.text_primary); + + visuals.widgets.open.bg_fill = palette.accent_secondary; + visuals.widgets.open.weak_bg_fill = palette.accent_secondary; + visuals.widgets.open.bg_stroke = egui::Stroke::new(1.5, palette.accent_primary); + visuals.widgets.open.fg_stroke = egui::Stroke::new(1.5, palette.text_primary); + + // Selection + visuals.selection.bg_fill = palette.selection; + visuals.selection.stroke = egui::Stroke::new(1.0, palette.accent_bright); + + // Hyperlinks + visuals.hyperlink_color = palette.accent_bright; + + // Window styling + visuals.window_rounding = egui::Rounding::same(8.0); + visuals.window_shadow = egui::epaint::Shadow { + offset: egui::vec2(0.0, 8.0), + blur: 20.0, + spread: 0.0, + color: egui::Color32::from_black_alpha(80), + }; + visuals.window_stroke = egui::Stroke::new(1.0, palette.border); + + // Popup styling + visuals.popup_shadow = egui::epaint::Shadow { + offset: egui::vec2(0.0, 4.0), + blur: 16.0, + spread: 0.0, + color: egui::Color32::from_black_alpha(100), + }; + + // Resize handle + visuals.resize_corner_size = 12.0; + + // Menu rounding + visuals.menu_rounding = egui::Rounding::same(6.0); + + // Indent guide + visuals.indent_has_left_vline = true; + visuals.striped = true; + + // Borders and separators + visuals.window_stroke = egui::Stroke::new(1.0, palette.border); + + // === Text styles with better readability === + style.text_styles.insert( + egui::TextStyle::Body, + egui::FontId::proportional(14.0), + ); + style.text_styles.insert( + egui::TextStyle::Button, + egui::FontId::proportional(14.0), + ); + style.text_styles.insert( + egui::TextStyle::Heading, + egui::FontId::proportional(18.0), + ); + style.text_styles.insert( + egui::TextStyle::Monospace, + egui::FontId::monospace(13.0), + ); + + // Apply the style + ctx.set_style(style); +} + +/// Get the color palette for use in custom rendering +pub fn get_palette() -> ColorPalette { + ColorPalette::dark_purple() +}