100 lines
3.0 KiB
Rust
100 lines
3.0 KiB
Rust
//! 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),
|
|
})
|
|
}
|