|
1 | 1 | use gtk::{CssProvider, gdk::Display, STYLE_PROVIDER_PRIORITY_APPLICATION}; |
2 | | - |
3 | | -pub fn apply_styles() { |
4 | | - let provider = CssProvider::new(); |
5 | | - provider.load_from_data(r#" |
6 | | - /* Global window styling */ |
7 | | - window { |
8 | | - background-color: rgba(18, 18, 18, 0.95); /* Semi-transparent modern dark background */ |
9 | | - border-radius: 12px; /* Rounded corners for modern look */ |
10 | | - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5); /* Subtle shadow */ |
11 | | -} |
12 | | -
|
13 | | -/* Header bar styling */ |
14 | | -headerbar { |
15 | | -background-color: rgba(30, 30, 30, 0.9); |
16 | | - border-bottom: 1px solid rgba(255, 255, 255, 0.1); |
17 | | - box-shadow: none; |
18 | | - padding: 4px; |
19 | | -} |
20 | | -
|
21 | | -/* Notebook and tabs */ |
22 | | -notebook { |
23 | | -background-color: transparent; |
24 | | -border: none; |
25 | | -} |
26 | | -
|
27 | | -notebook tab { |
28 | | -background-color: rgba(40, 40, 40, 0.8); |
29 | | - border: 1px solid rgba(255, 255, 255, 0.05); |
30 | | - border-radius: 8px 8px 0 0; |
31 | | - padding: 6px 12px; |
32 | | - margin: 2px; |
33 | | - transition: background-color 0.2s ease; |
34 | | -} |
35 | | -
|
36 | | -notebook tab:hover { |
37 | | -background-color: rgba(60, 60, 60, 0.9); |
38 | | -} |
39 | | -
|
40 | | -notebook tab:checked { |
41 | | -background-color: rgba(80, 80, 80, 0.95); |
42 | | - border-bottom: none; |
| 2 | +use std::fs::{self, create_dir_all}; |
| 3 | +use serde::Deserialize; |
| 4 | +use toml; |
| 5 | +#[derive(Deserialize, Debug, Default)] |
| 6 | +pub struct Config { |
| 7 | + pub background_opacity: Option<f32>, |
| 8 | + pub background_color: Option<String>, |
| 9 | + pub font_family: Option<String>, |
| 10 | + pub font_size: Option<u32>, |
| 11 | + pub text_color: Option<String>, |
| 12 | + pub cursor_color: Option<String>, |
| 13 | + pub header_background_color: Option<String>, |
| 14 | + pub tab_background_color: Option<String>, |
| 15 | + pub button_background_color: Option<String>, |
| 16 | + pub particle_color: Option<String>, |
| 17 | + pub particle_count: Option<u32>, |
| 18 | + pub particle_life_min: Option<u32>, |
| 19 | + pub particle_life_max: Option<u32>, |
| 20 | + pub particle_size_min: Option<f32>, |
| 21 | + pub particle_size_max: Option<f32>, |
| 22 | + // Add more configurable fields as needed |
43 | 23 | } |
44 | | -
|
45 | | -/* Scrolled window */ |
46 | | -scrolledwindow { |
47 | | -background-color: transparent; |
48 | | -border: none; |
| 24 | +fn hex_to_rgba(hex: &str, alpha: f32) -> String { |
| 25 | + let hex = hex.trim_start_matches('#'); |
| 26 | + let (r, g, b) = if hex.len() == 6 { |
| 27 | + ( |
| 28 | + u8::from_str_radix(&hex[0..2], 16).unwrap_or(0), |
| 29 | + u8::from_str_radix(&hex[2..4], 16).unwrap_or(0), |
| 30 | + u8::from_str_radix(&hex[4..6], 16).unwrap_or(0), |
| 31 | + ) |
| 32 | + } else if hex.len() == 3 { |
| 33 | + ( |
| 34 | + u8::from_str_radix(&hex[0..1], 16).unwrap_or(0) * 17, |
| 35 | + u8::from_str_radix(&hex[1..2], 16).unwrap_or(0) * 17, |
| 36 | + u8::from_str_radix(&hex[2..3], 16).unwrap_or(0) * 17, |
| 37 | + ) |
| 38 | + } else { |
| 39 | + (0, 0, 0) |
| 40 | + }; |
| 41 | + format!("rgba({},{},{},{})", r, g, b, alpha) |
49 | 42 | } |
50 | | -
|
51 | | -/* VTE Terminal styling */ |
52 | | -vte-terminal { |
53 | | -background-color: transparent; |
54 | | -color: #e0e0e0; /* Light gray text for readability */ |
55 | | -font-family: 'JetBrains Mono', monospace; /* Modern monospace font */ |
56 | | -font-size: 13pt; |
57 | | -padding: 10px; |
58 | | -border-radius: 8px; |
| 43 | +pub fn load_config() -> Config { |
| 44 | + let mut config_path = dirs::home_dir().unwrap_or_default(); |
| 45 | + config_path.push(".hackeros"); |
| 46 | + config_path.push("hacker-term"); |
| 47 | + let _ = create_dir_all(&config_path); // Create directories if not exist |
| 48 | + config_path.push("config.toml"); |
| 49 | + if let Ok(config_str) = fs::read_to_string(config_path) { |
| 50 | + toml::from_str(&config_str).unwrap_or_default() |
| 51 | + } else { |
| 52 | + Config::default() |
| 53 | + } |
59 | 54 | } |
60 | | -
|
61 | | -/* Buttons */ |
62 | | -button { |
63 | | -background-color: rgba(50, 50, 50, 0.8); |
64 | | - border: 1px solid rgba(255, 255, 255, 0.1); |
65 | | - border-radius: 6px; |
66 | | - padding: 4px 8px; |
67 | | - transition: background-color 0.2s ease; |
68 | | -} |
69 | | -
|
70 | | -button:hover { |
71 | | -background-color: rgba(70, 70, 70, 0.9); |
72 | | -} |
73 | | -
|
74 | | -/* Close button in tabs */ |
75 | | -button.flat { |
76 | | -background: none; |
77 | | -border: none; |
78 | | -color: #ff5555; /* Red for close */ |
79 | | -} |
80 | | -
|
81 | | -button.flat:hover { |
82 | | -color: #ff7777; |
83 | | -} |
84 | | -
|
85 | | -/* Overlay for webview */ |
86 | | -overlay { |
87 | | -background-color: transparent; |
88 | | -} |
89 | | -"#); |
90 | | - |
| 55 | +pub fn apply_styles() { |
| 56 | + let config = load_config(); |
| 57 | + let background_opacity = config.background_opacity.unwrap_or(0.8); |
| 58 | + let background_color = config.background_color.unwrap_or_else(|| "#1e1e2e".to_string()); // Nicer default: dark purple-gray |
| 59 | + let font_family = config.font_family.unwrap_or_else(|| "'JetBrains Mono', monospace".to_string()); |
| 60 | + let font_size = config.font_size.unwrap_or(13); |
| 61 | + let text_color = config.text_color.unwrap_or_else(|| "#cdd6f4".to_string()); // Nicer light color |
| 62 | + let cursor_color = config.cursor_color.unwrap_or_else(|| "#f5e0dc".to_string()); // Soft pink |
| 63 | + let header_background_color = config.header_background_color.unwrap_or_else(|| "#313244".to_string()); |
| 64 | + let tab_background_color = config.tab_background_color.unwrap_or_else(|| "#45475a".to_string()); |
| 65 | + let button_background_color = config.button_background_color.unwrap_or_else(|| "#6c7086".to_string()); |
| 66 | + let window_bg = hex_to_rgba(&background_color, background_opacity); |
| 67 | + let header_bg = hex_to_rgba(&header_background_color, background_opacity); |
| 68 | + let tab_bg = hex_to_rgba(&tab_background_color, background_opacity); |
| 69 | + let terminal_bg = hex_to_rgba(&background_color, background_opacity); |
| 70 | + let button_bg = hex_to_rgba(&button_background_color, 0.8); |
| 71 | + let css = format!(r#" |
| 72 | + /* Global window styling */ |
| 73 | + window {{ |
| 74 | + background-color: {}; /* Configurable nicer background with opacity */ |
| 75 | + border-radius: 12px; /* Rounded corners for modern look */ |
| 76 | + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5); /* Subtle shadow */ |
| 77 | + }} |
| 78 | + /* Header bar styling */ |
| 79 | + headerbar {{ |
| 80 | + background-color: {}; |
| 81 | + border-bottom: 1px solid rgba(255, 255, 255, 0.1); |
| 82 | + box-shadow: none; |
| 83 | + padding: 4px; |
| 84 | + }} |
| 85 | + /* Notebook and tabs */ |
| 86 | + notebook {{ |
| 87 | + background-color: transparent; |
| 88 | + border: none; |
| 89 | + }} |
| 90 | + notebook tab {{ |
| 91 | + background-color: {}; |
| 92 | + border: 1px solid rgba(255, 255, 255, 0.05); |
| 93 | + border-radius: 8px 8px 0 0; |
| 94 | + padding: 6px 12px; |
| 95 | + margin: 2px; |
| 96 | + transition: background-color 0.2s ease; |
| 97 | + }} |
| 98 | + notebook tab:hover {{ |
| 99 | + background-color: rgba(60, 60, 60, 0.9); |
| 100 | + }} |
| 101 | + notebook tab:checked {{ |
| 102 | + background-color: rgba(80, 80, 80, 0.95); |
| 103 | + border-bottom: none; |
| 104 | + }} |
| 105 | + /* Scrolled window */ |
| 106 | + scrolledwindow {{ |
| 107 | + background-color: transparent; |
| 108 | + border: none; |
| 109 | + }} |
| 110 | + /* VTE Terminal styling */ |
| 111 | + vte-terminal {{ |
| 112 | + background-color: {}; /* Nicer configurable background for terminal */ |
| 113 | + color: {}; /* Configurable text color */ |
| 114 | + font-family: {}; /* Configurable font family */ |
| 115 | + font-size: {}pt; /* Configurable font size */ |
| 116 | + padding: 10px; |
| 117 | + border-radius: 8px; |
| 118 | + -vte-cursor-color: {}; /* Configurable cursor color */ |
| 119 | + }} |
| 120 | + /* Buttons */ |
| 121 | + button {{ |
| 122 | + background-color: {}; |
| 123 | + border: 1px solid rgba(255, 255, 255, 0.1); |
| 124 | + border-radius: 6px; |
| 125 | + padding: 4px 8px; |
| 126 | + transition: background-color 0.2s ease; |
| 127 | + }} |
| 128 | + button:hover {{ |
| 129 | + background-color: rgba(70, 70, 70, 0.9); |
| 130 | + }} |
| 131 | + /* Close button in tabs */ |
| 132 | + button.flat {{ |
| 133 | + background: none; |
| 134 | + border: none; |
| 135 | + color: #ff5555; /* Red for close */ |
| 136 | + }} |
| 137 | + button.flat:hover {{ |
| 138 | + color: #ff7777; |
| 139 | + }} |
| 140 | + /* Overlay for webview */ |
| 141 | + overlay {{ |
| 142 | + background-color: transparent; |
| 143 | + }} |
| 144 | + "#, window_bg, header_bg, tab_bg, terminal_bg, text_color, font_family, font_size, cursor_color, button_bg); |
| 145 | + let provider = CssProvider::new(); |
| 146 | + provider.load_from_data(&css); |
91 | 147 | gtk::style_context_add_provider_for_display( |
92 | 148 | &Display::default().expect("No GDK Display"), |
93 | | - &provider, |
94 | | - STYLE_PROVIDER_PRIORITY_APPLICATION, |
| 149 | + &provider, |
| 150 | + STYLE_PROVIDER_PRIORITY_APPLICATION, |
95 | 151 | ); |
96 | 152 | } |
0 commit comments