|
| 1 | +/// Terminal color scheme utilities for VTE4 with libadwaita theme support |
| 2 | +/// Provides ANSI color palettes that respect the system light/dark theme preference |
| 3 | +use gtk::gdk; |
| 4 | +use adw; |
| 5 | +use vte4::prelude::*; |
| 6 | + |
| 7 | +/// ANSI color palette entry |
| 8 | +#[derive(Clone, Copy)] |
| 9 | +pub struct ColorPalette { |
| 10 | + /// Foreground text color |
| 11 | + pub foreground: gdk::RGBA, |
| 12 | + /// Background color |
| 13 | + pub background: gdk::RGBA, |
| 14 | + /// Standard ANSI colors (0-15) |
| 15 | + pub palette: [gdk::RGBA; 16], |
| 16 | +} |
| 17 | + |
| 18 | +impl ColorPalette { |
| 19 | + /// Create a color palette from RGB components |
| 20 | + fn color(r: f32, g: f32, b: f32) -> gdk::RGBA { |
| 21 | + gdk::RGBA::new(r, g, b, 1.0) |
| 22 | + } |
| 23 | + |
| 24 | + /// Get the dark theme color palette (similar to GNOME Terminal/Ptyxis dark) |
| 25 | + /// This palette respects libadwaita's dark theme colors |
| 26 | + pub fn dark() -> Self { |
| 27 | + Self { |
| 28 | + // Adwaita dark: text on dark background |
| 29 | + foreground: Self::color(0.92, 0.92, 0.92), // #ebebeb |
| 30 | + background: Self::color(0.1, 0.1, 0.1), // #1a1a1a |
| 31 | + palette: [ |
| 32 | + // Standard colors (0-7) |
| 33 | + Self::color(0.2, 0.2, 0.2), // 0: black (darker than bg for contrast) |
| 34 | + Self::color(0.89, 0.35, 0.36), // 1: red |
| 35 | + Self::color(0.37, 0.76, 0.36), // 2: green |
| 36 | + Self::color(0.87, 0.75, 0.29), // 3: yellow |
| 37 | + Self::color(0.36, 0.62, 0.89), // 4: blue |
| 38 | + Self::color(0.76, 0.51, 0.85), // 5: magenta |
| 39 | + Self::color(0.36, 0.78, 0.85), // 6: cyan |
| 40 | + Self::color(0.82, 0.82, 0.82), // 7: white (lighter) |
| 41 | + // Bright colors (8-15) |
| 42 | + Self::color(0.5, 0.5, 0.5), // 8: bright black (gray) |
| 43 | + Self::color(1.0, 0.55, 0.56), // 9: bright red |
| 44 | + Self::color(0.56, 0.93, 0.56), // 10: bright green |
| 45 | + Self::color(1.0, 0.93, 0.56), // 11: bright yellow |
| 46 | + Self::color(0.56, 0.8, 1.0), // 12: bright blue |
| 47 | + Self::color(0.94, 0.71, 1.0), // 13: bright magenta |
| 48 | + Self::color(0.56, 0.96, 1.0), // 14: bright cyan |
| 49 | + Self::color(1.0, 1.0, 1.0), // 15: bright white |
| 50 | + ], |
| 51 | + } |
| 52 | + } |
| 53 | + |
| 54 | + /// Get the light theme color palette (similar to GNOME Terminal/Ptyxis light) |
| 55 | + /// This palette respects libadwaita's light theme colors |
| 56 | + pub fn light() -> Self { |
| 57 | + Self { |
| 58 | + // Adwaita light: dark text on light background |
| 59 | + foreground: Self::color(0.2, 0.2, 0.2), // #333333 |
| 60 | + background: Self::color(0.98, 0.98, 0.98), // #fafafa (nearly white) |
| 61 | + palette: [ |
| 62 | + // Standard colors (0-7) |
| 63 | + Self::color(0.2, 0.2, 0.2), // 0: black |
| 64 | + Self::color(0.8, 0.0, 0.0), // 1: red |
| 65 | + Self::color(0.0, 0.6, 0.0), // 2: green |
| 66 | + Self::color(0.8, 0.62, 0.0), // 3: yellow |
| 67 | + Self::color(0.13, 0.34, 0.76), // 4: blue |
| 68 | + Self::color(0.76, 0.27, 0.76), // 5: magenta |
| 69 | + Self::color(0.0, 0.6, 0.76), // 6: cyan |
| 70 | + Self::color(0.7, 0.7, 0.7), // 7: white (gray) |
| 71 | + // Bright colors (8-15) |
| 72 | + Self::color(0.5, 0.5, 0.5), // 8: bright black (gray) |
| 73 | + Self::color(1.0, 0.0, 0.0), // 9: bright red |
| 74 | + Self::color(0.0, 1.0, 0.0), // 10: bright green |
| 75 | + Self::color(1.0, 1.0, 0.0), // 11: bright yellow |
| 76 | + Self::color(0.0, 0.0, 1.0), // 12: bright blue |
| 77 | + Self::color(1.0, 0.0, 1.0), // 13: bright magenta |
| 78 | + Self::color(0.0, 1.0, 1.0), // 14: bright cyan |
| 79 | + Self::color(0.99, 0.99, 0.99), // 15: bright white |
| 80 | + ], |
| 81 | + } |
| 82 | + } |
| 83 | + |
| 84 | + /// Get the appropriate palette based on the current adwaita theme |
| 85 | + /// Checks the system style manager to determine if dark or light theme is active |
| 86 | + pub fn current() -> Self { |
| 87 | + let style_manager = adw::StyleManager::default(); |
| 88 | + if style_manager.is_dark() { |
| 89 | + Self::dark() |
| 90 | + } else { |
| 91 | + Self::light() |
| 92 | + } |
| 93 | + } |
| 94 | + |
| 95 | + /// Apply this color palette to a VTE terminal |
| 96 | + pub fn apply_to_terminal(&self, terminal: &vte4::Terminal) { |
| 97 | + let palette_refs: Vec<&gdk::RGBA> = self.palette.iter().collect(); |
| 98 | + terminal.set_colors( |
| 99 | + Some(&self.foreground), |
| 100 | + Some(&self.background), |
| 101 | + &palette_refs, |
| 102 | + ); |
| 103 | + } |
| 104 | +} |
| 105 | + |
| 106 | +#[cfg(test)] |
| 107 | +mod tests { |
| 108 | + use super::*; |
| 109 | + |
| 110 | + #[test] |
| 111 | + fn test_dark_palette() { |
| 112 | + let palette = ColorPalette::dark(); |
| 113 | + assert_ne!(palette.foreground, palette.background); |
| 114 | + assert_eq!(palette.palette.len(), 16); |
| 115 | + } |
| 116 | + |
| 117 | + #[test] |
| 118 | + fn test_light_palette() { |
| 119 | + let palette = ColorPalette::light(); |
| 120 | + assert_ne!(palette.foreground, palette.background); |
| 121 | + assert_eq!(palette.palette.len(), 16); |
| 122 | + } |
| 123 | +} |
0 commit comments