max / audiofiles
1 file changed,
+50 insertions,
-13 deletions
| @@ -134,6 +134,49 @@ pub use makeover::ThemeMeta; | |||
| 134 | 134 | ||
| 135 | 135 | static THEME: LazyLock<RwLock<ThemeColors>> = LazyLock::new(|| RwLock::new(ThemeColors::default())); | |
| 136 | 136 | ||
| 137 | + | /// Colors derived from the base palette via OKLab blends (row striping, | |
| 138 | + | /// selection highlight, piano keys, the trim wash). | |
| 139 | + | /// | |
| 140 | + | /// These were previously recomputed on every accessor call — an OKLab blend per | |
| 141 | + | /// call, hundreds of times per frame for row striping and selection alone. They | |
| 142 | + | /// depend only on the palette, so they are now blended once whenever the theme | |
| 143 | + | /// changes and read straight from here. Kept in lockstep with `THEME` by routing | |
| 144 | + | /// every theme install through [`install_theme`]. | |
| 145 | + | #[derive(Debug, Clone)] | |
| 146 | + | struct DerivedColors { | |
| 147 | + | row_even: Color32, | |
| 148 | + | selection: Color32, | |
| 149 | + | piano_white_key: Color32, | |
| 150 | + | piano_black_key: Color32, | |
| 151 | + | trim_mute_overlay: Color32, | |
| 152 | + | } | |
| 153 | + | ||
| 154 | + | impl DerivedColors { | |
| 155 | + | fn from_base(t: &ThemeColors) -> Self { | |
| 156 | + | let bg = t.surface_page; | |
| 157 | + | Self { | |
| 158 | + | row_even: lerp_color(t.surface_page, t.surface_overlay, 0.3), | |
| 159 | + | selection: lerp_color(t.surface_page, t.action, 0.3), | |
| 160 | + | piano_white_key: lerp_color(t.surface_raised, Color32::WHITE, 0.7), | |
| 161 | + | piano_black_key: lerp_color(t.surface_raised, Color32::BLACK, 0.7), | |
| 162 | + | // Dim toward the theme's own background rather than hardcoded black, | |
| 163 | + | // so the trimmed-region wash reads correctly on light themes too. | |
| 164 | + | trim_mute_overlay: Color32::from_rgba_unmultiplied(bg.r(), bg.g(), bg.b(), 160), | |
| 165 | + | } | |
| 166 | + | } | |
| 167 | + | } | |
| 168 | + | ||
| 169 | + | static DERIVED: LazyLock<RwLock<DerivedColors>> = | |
| 170 | + | LazyLock::new(|| RwLock::new(DerivedColors::from_base(&ThemeColors::default()))); | |
| 171 | + | ||
| 172 | + | /// Install a freshly parsed theme, recomputing the cached derived colors so the | |
| 173 | + | /// two never drift. Every write to `THEME` goes through here. | |
| 174 | + | fn install_theme(colors: ThemeColors) { | |
| 175 | + | let derived = DerivedColors::from_base(&colors); | |
| 176 | + | *THEME.write() = colors; | |
| 177 | + | *DERIVED.write() = derived; | |
| 178 | + | } | |
| 179 | + | ||
| 137 | 180 | // --- Derived color helpers --- | |
| 138 | 181 | // | |
| 139 | 182 | // The color math lives once in `makeover` (OKLab blends + WCAG contrast), | |
| @@ -180,8 +223,7 @@ pub fn surface_sunken() -> Color32 { | |||
| 180 | 223 | ||
| 181 | 224 | /// Even-row background, derived by blending primary and secondary. | |
| 182 | 225 | pub fn row_even() -> Color32 { | |
| 183 | - | let t = THEME.read(); | |
| 184 | - | lerp_color(t.surface_page, t.surface_overlay, 0.3) | |
| 226 | + | DERIVED.read().row_even | |
| 185 | 227 | } | |
| 186 | 228 | /// Odd-row background (same as primary). | |
| 187 | 229 | pub fn row_odd() -> Color32 { | |
| @@ -193,8 +235,7 @@ pub fn hover_surface() -> Color32 { | |||
| 193 | 235 | } | |
| 194 | 236 | /// Selected-row background, derived by blending primary with accent blue. | |
| 195 | 237 | pub fn selection() -> Color32 { | |
| 196 | - | let t = THEME.read(); | |
| 197 | - | lerp_color(t.surface_page, t.action, 0.3) | |
| 238 | + | DERIVED.read().selection | |
| 198 | 239 | } | |
| 199 | 240 | ||
| 200 | 241 | /// Primary text color. | |
| @@ -256,22 +297,18 @@ pub fn grid_row_spacing() -> f32 { | |||
| 256 | 297 | ||
| 257 | 298 | /// Piano white key — always a light shade regardless of theme variant. | |
| 258 | 299 | pub fn piano_white_key() -> Color32 { | |
| 259 | - | lerp_color(THEME.read().surface_raised, Color32::WHITE, 0.7) | |
| 300 | + | DERIVED.read().piano_white_key | |
| 260 | 301 | } | |
| 261 | 302 | /// Piano black key — always a dark shade regardless of theme variant. | |
| 262 | 303 | pub fn piano_black_key() -> Color32 { | |
| 263 | - | lerp_color(THEME.read().surface_raised, Color32::BLACK, 0.7) | |
| 304 | + | DERIVED.read().piano_black_key | |
| 264 | 305 | } | |
| 265 | 306 | ||
| 266 | 307 | /// Semi-opaque overlay used by the edit panel's trim preview (C-1) to mark | |
| 267 | 308 | /// regions that will be removed. Painted on top of the rendered waveform; the | |
| 268 | 309 | /// underlying peaks stay partly visible so the user retains spatial reference. | |
| 269 | 310 | pub fn trim_mute_overlay() -> Color32 { | |
| 270 | - | // Dim toward the theme's own background rather than hardcoded black, so the | |
| 271 | - | // trimmed-region wash reads correctly on light themes too (a black overlay | |
| 272 | - | // assumes a dark base). | |
| 273 | - | let bg = THEME.read().surface_page; | |
| 274 | - | Color32::from_rgba_unmultiplied(bg.r(), bg.g(), bg.b(), 160) | |
| 311 | + | DERIVED.read().trim_mute_overlay | |
| 275 | 312 | } | |
| 276 | 313 | ||
| 277 | 314 | // --- Theme discovery --- | |
| @@ -509,7 +546,7 @@ pub fn set_theme(id: &str) { | |||
| 509 | 546 | if *bundled_id == id { | |
| 510 | 547 | match parse_theme(content) { | |
| 511 | 548 | Ok(colors) => { | |
| 512 | - | *THEME.write() = colors; | |
| 549 | + | install_theme(colors); | |
| 513 | 550 | return; | |
| 514 | 551 | } | |
| 515 | 552 | Err(e) => { | |
| @@ -526,7 +563,7 @@ pub fn set_theme(id: &str) { | |||
| 526 | 563 | if path.exists() { | |
| 527 | 564 | match load_theme(&path) { | |
| 528 | 565 | Ok(colors) => { | |
| 529 | - | *THEME.write() = colors; | |
| 566 | + | install_theme(colors); | |
| 530 | 567 | return; | |
| 531 | 568 | } | |
| 532 | 569 | Err(e) => { |