//! Hue rotation for palette-wide color transforms. use super::palette::{Palette, Rgb}; use super::build::build; use super::ThemeColors; fn rgb_to_hsv(r: u8, g: u8, b: u8) -> (f32, f32, f32) { let r = r as f32 / 255.0; let g = g as f32 / 255.0; let b = b as f32 / 255.0; let max = r.max(g).max(b); let min = r.min(g).min(b); let delta = max - min; let h = if delta == 0.0 { 0.0 } else if max == r { 60.0 * (((g - b) / delta) % 6.0) } else if max == g { 60.0 * (((b - r) / delta) + 2.0) } else { 60.0 * (((r - g) / delta) + 4.0) }; let h = if h < 0.0 { h + 360.0 } else { h }; let s = if max == 0.0 { 0.0 } else { delta / max }; (h, s, max) } fn hsv_to_rgb(h: f32, s: f32, v: f32) -> (u8, u8, u8) { let c = v * s; let x = c * (1.0 - ((h / 60.0) % 2.0 - 1.0).abs()); let m = v - c; let (r, g, b) = if h < 60.0 { (c, x, 0.0) } else if h < 120.0 { (x, c, 0.0) } else if h < 180.0 { (0.0, c, x) } else if h < 240.0 { (0.0, x, c) } else if h < 300.0 { (x, 0.0, c) } else { (c, 0.0, x) }; ( ((r + m) * 255.0) as u8, ((g + m) * 255.0) as u8, ((b + m) * 255.0) as u8, ) } fn rotate(c: Rgb, degrees: f32) -> Rgb { let (h, s, v) = rgb_to_hsv(c.0, c.1, c.2); let new_h = (h + degrees) % 360.0; let new_h = if new_h < 0.0 { new_h + 360.0 } else { new_h }; hsv_to_rgb(new_h, s, v) } fn rotate5(arr: [Rgb; 5], d: f32) -> [Rgb; 5] { [rotate(arr[0], d), rotate(arr[1], d), rotate(arr[2], d), rotate(arr[3], d), rotate(arr[4], d)] } fn rotate3(arr: [Rgb; 3], d: f32) -> [Rgb; 3] { [rotate(arr[0], d), rotate(arr[1], d), rotate(arr[2], d)] } /// Build a [`ThemeColors`] with all palette hues rotated by `degrees`. pub fn rotate_palette(palette: &Palette, degrees: f32) -> ThemeColors { if degrees == 0.0 { return build(palette); } let d = degrees; build(&Palette { bg: rotate(palette.bg, d), surface: rotate(palette.surface, d), surface2: rotate(palette.surface2, d), fg: rotate(palette.fg, d), fg_dim: rotate(palette.fg_dim, d), fg_muted: rotate(palette.fg_muted, d), accent: rotate(palette.accent, d), red: rotate(palette.red, d), green: rotate(palette.green, d), yellow: rotate(palette.yellow, d), blue: rotate(palette.blue, d), purple: rotate(palette.purple, d), cyan: rotate(palette.cyan, d), orange: rotate(palette.orange, d), tempo_color: rotate(palette.tempo_color, d), bank_color: rotate(palette.bank_color, d), pattern_color: rotate(palette.pattern_color, d), title_accent: rotate(palette.title_accent, d), title_author: rotate(palette.title_author, d), secondary: rotate(palette.secondary, d), link_bright: rotate5(palette.link_bright, d), link_dim: rotate5(palette.link_dim, d), sparkle: rotate5(palette.sparkle, d), meter: rotate3(palette.meter, d), }) }