349 lines
17 KiB
Rust
349 lines
17 KiB
Rust
use ratatui::style::Color;
|
|
use super::*;
|
|
|
|
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 };
|
|
let v = max;
|
|
|
|
(h, s, v)
|
|
}
|
|
|
|
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_hue_rgb(r: u8, g: u8, b: u8, degrees: f32) -> (u8, u8, u8) {
|
|
let (h, s, v) = rgb_to_hsv(r, g, b);
|
|
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 rotate_color(color: Color, degrees: f32) -> Color {
|
|
match color {
|
|
Color::Rgb(r, g, b) => {
|
|
let (nr, ng, nb) = rotate_hue_rgb(r, g, b, degrees);
|
|
Color::Rgb(nr, ng, nb)
|
|
}
|
|
_ => color,
|
|
}
|
|
}
|
|
|
|
fn rotate_tuple(tuple: (u8, u8, u8), degrees: f32) -> (u8, u8, u8) {
|
|
rotate_hue_rgb(tuple.0, tuple.1, tuple.2, degrees)
|
|
}
|
|
|
|
fn rotate_color_pair(pair: (Color, Color), degrees: f32) -> (Color, Color) {
|
|
(rotate_color(pair.0, degrees), rotate_color(pair.1, degrees))
|
|
}
|
|
|
|
pub fn rotate_theme(theme: ThemeColors, degrees: f32) -> ThemeColors {
|
|
if degrees == 0.0 {
|
|
return theme;
|
|
}
|
|
|
|
ThemeColors {
|
|
ui: UiColors {
|
|
bg: rotate_color(theme.ui.bg, degrees),
|
|
bg_rgb: rotate_tuple(theme.ui.bg_rgb, degrees),
|
|
text_primary: rotate_color(theme.ui.text_primary, degrees),
|
|
text_muted: rotate_color(theme.ui.text_muted, degrees),
|
|
text_dim: rotate_color(theme.ui.text_dim, degrees),
|
|
border: rotate_color(theme.ui.border, degrees),
|
|
header: rotate_color(theme.ui.header, degrees),
|
|
unfocused: rotate_color(theme.ui.unfocused, degrees),
|
|
accent: rotate_color(theme.ui.accent, degrees),
|
|
surface: rotate_color(theme.ui.surface, degrees),
|
|
},
|
|
status: StatusColors {
|
|
playing_bg: rotate_color(theme.status.playing_bg, degrees),
|
|
playing_fg: rotate_color(theme.status.playing_fg, degrees),
|
|
stopped_bg: rotate_color(theme.status.stopped_bg, degrees),
|
|
stopped_fg: rotate_color(theme.status.stopped_fg, degrees),
|
|
fill_on: rotate_color(theme.status.fill_on, degrees),
|
|
fill_off: rotate_color(theme.status.fill_off, degrees),
|
|
fill_bg: rotate_color(theme.status.fill_bg, degrees),
|
|
},
|
|
selection: SelectionColors {
|
|
cursor_bg: rotate_color(theme.selection.cursor_bg, degrees),
|
|
cursor_fg: rotate_color(theme.selection.cursor_fg, degrees),
|
|
selected_bg: rotate_color(theme.selection.selected_bg, degrees),
|
|
selected_fg: rotate_color(theme.selection.selected_fg, degrees),
|
|
in_range_bg: rotate_color(theme.selection.in_range_bg, degrees),
|
|
in_range_fg: rotate_color(theme.selection.in_range_fg, degrees),
|
|
cursor: rotate_color(theme.selection.cursor, degrees),
|
|
selected: rotate_color(theme.selection.selected, degrees),
|
|
in_range: rotate_color(theme.selection.in_range, degrees),
|
|
},
|
|
tile: TileColors {
|
|
playing_active_bg: rotate_color(theme.tile.playing_active_bg, degrees),
|
|
playing_active_fg: rotate_color(theme.tile.playing_active_fg, degrees),
|
|
playing_inactive_bg: rotate_color(theme.tile.playing_inactive_bg, degrees),
|
|
playing_inactive_fg: rotate_color(theme.tile.playing_inactive_fg, degrees),
|
|
active_bg: rotate_color(theme.tile.active_bg, degrees),
|
|
active_fg: rotate_color(theme.tile.active_fg, degrees),
|
|
inactive_bg: rotate_color(theme.tile.inactive_bg, degrees),
|
|
inactive_fg: rotate_color(theme.tile.inactive_fg, degrees),
|
|
active_selected_bg: rotate_color(theme.tile.active_selected_bg, degrees),
|
|
active_in_range_bg: rotate_color(theme.tile.active_in_range_bg, degrees),
|
|
link_bright: [
|
|
rotate_tuple(theme.tile.link_bright[0], degrees),
|
|
rotate_tuple(theme.tile.link_bright[1], degrees),
|
|
rotate_tuple(theme.tile.link_bright[2], degrees),
|
|
rotate_tuple(theme.tile.link_bright[3], degrees),
|
|
rotate_tuple(theme.tile.link_bright[4], degrees),
|
|
],
|
|
link_dim: [
|
|
rotate_tuple(theme.tile.link_dim[0], degrees),
|
|
rotate_tuple(theme.tile.link_dim[1], degrees),
|
|
rotate_tuple(theme.tile.link_dim[2], degrees),
|
|
rotate_tuple(theme.tile.link_dim[3], degrees),
|
|
rotate_tuple(theme.tile.link_dim[4], degrees),
|
|
],
|
|
},
|
|
header: HeaderColors {
|
|
tempo_bg: rotate_color(theme.header.tempo_bg, degrees),
|
|
tempo_fg: rotate_color(theme.header.tempo_fg, degrees),
|
|
bank_bg: rotate_color(theme.header.bank_bg, degrees),
|
|
bank_fg: rotate_color(theme.header.bank_fg, degrees),
|
|
pattern_bg: rotate_color(theme.header.pattern_bg, degrees),
|
|
pattern_fg: rotate_color(theme.header.pattern_fg, degrees),
|
|
stats_bg: rotate_color(theme.header.stats_bg, degrees),
|
|
stats_fg: rotate_color(theme.header.stats_fg, degrees),
|
|
},
|
|
modal: ModalColors {
|
|
border: rotate_color(theme.modal.border, degrees),
|
|
border_accent: rotate_color(theme.modal.border_accent, degrees),
|
|
border_warn: rotate_color(theme.modal.border_warn, degrees),
|
|
border_dim: rotate_color(theme.modal.border_dim, degrees),
|
|
confirm: rotate_color(theme.modal.confirm, degrees),
|
|
rename: rotate_color(theme.modal.rename, degrees),
|
|
input: rotate_color(theme.modal.input, degrees),
|
|
editor: rotate_color(theme.modal.editor, degrees),
|
|
preview: rotate_color(theme.modal.preview, degrees),
|
|
},
|
|
flash: FlashColors {
|
|
error_bg: rotate_color(theme.flash.error_bg, degrees),
|
|
error_fg: rotate_color(theme.flash.error_fg, degrees),
|
|
success_bg: rotate_color(theme.flash.success_bg, degrees),
|
|
success_fg: rotate_color(theme.flash.success_fg, degrees),
|
|
info_bg: rotate_color(theme.flash.info_bg, degrees),
|
|
info_fg: rotate_color(theme.flash.info_fg, degrees),
|
|
},
|
|
list: ListColors {
|
|
playing_bg: rotate_color(theme.list.playing_bg, degrees),
|
|
playing_fg: rotate_color(theme.list.playing_fg, degrees),
|
|
staged_play_bg: rotate_color(theme.list.staged_play_bg, degrees),
|
|
staged_play_fg: rotate_color(theme.list.staged_play_fg, degrees),
|
|
staged_stop_bg: rotate_color(theme.list.staged_stop_bg, degrees),
|
|
staged_stop_fg: rotate_color(theme.list.staged_stop_fg, degrees),
|
|
edit_bg: rotate_color(theme.list.edit_bg, degrees),
|
|
edit_fg: rotate_color(theme.list.edit_fg, degrees),
|
|
hover_bg: rotate_color(theme.list.hover_bg, degrees),
|
|
hover_fg: rotate_color(theme.list.hover_fg, degrees),
|
|
muted_bg: rotate_color(theme.list.muted_bg, degrees),
|
|
muted_fg: rotate_color(theme.list.muted_fg, degrees),
|
|
soloed_bg: rotate_color(theme.list.soloed_bg, degrees),
|
|
soloed_fg: rotate_color(theme.list.soloed_fg, degrees),
|
|
},
|
|
link_status: LinkStatusColors {
|
|
disabled: rotate_color(theme.link_status.disabled, degrees),
|
|
connected: rotate_color(theme.link_status.connected, degrees),
|
|
listening: rotate_color(theme.link_status.listening, degrees),
|
|
},
|
|
syntax: SyntaxColors {
|
|
gap_bg: rotate_color(theme.syntax.gap_bg, degrees),
|
|
executed_bg: rotate_color(theme.syntax.executed_bg, degrees),
|
|
selected_bg: rotate_color(theme.syntax.selected_bg, degrees),
|
|
emit: rotate_color_pair(theme.syntax.emit, degrees),
|
|
number: rotate_color_pair(theme.syntax.number, degrees),
|
|
string: rotate_color_pair(theme.syntax.string, degrees),
|
|
comment: rotate_color_pair(theme.syntax.comment, degrees),
|
|
keyword: rotate_color_pair(theme.syntax.keyword, degrees),
|
|
stack_op: rotate_color_pair(theme.syntax.stack_op, degrees),
|
|
operator: rotate_color_pair(theme.syntax.operator, degrees),
|
|
sound: rotate_color_pair(theme.syntax.sound, degrees),
|
|
param: rotate_color_pair(theme.syntax.param, degrees),
|
|
context: rotate_color_pair(theme.syntax.context, degrees),
|
|
note: rotate_color_pair(theme.syntax.note, degrees),
|
|
interval: rotate_color_pair(theme.syntax.interval, degrees),
|
|
variable: rotate_color_pair(theme.syntax.variable, degrees),
|
|
vary: rotate_color_pair(theme.syntax.vary, degrees),
|
|
generator: rotate_color_pair(theme.syntax.generator, degrees),
|
|
default: rotate_color_pair(theme.syntax.default, degrees),
|
|
},
|
|
table: TableColors {
|
|
row_even: rotate_color(theme.table.row_even, degrees),
|
|
row_odd: rotate_color(theme.table.row_odd, degrees),
|
|
},
|
|
values: ValuesColors {
|
|
tempo: rotate_color(theme.values.tempo, degrees),
|
|
value: rotate_color(theme.values.value, degrees),
|
|
},
|
|
hint: HintColors {
|
|
key: rotate_color(theme.hint.key, degrees),
|
|
text: rotate_color(theme.hint.text, degrees),
|
|
},
|
|
view_badge: ViewBadgeColors {
|
|
bg: rotate_color(theme.view_badge.bg, degrees),
|
|
fg: rotate_color(theme.view_badge.fg, degrees),
|
|
},
|
|
nav: NavColors {
|
|
selected_bg: rotate_color(theme.nav.selected_bg, degrees),
|
|
selected_fg: rotate_color(theme.nav.selected_fg, degrees),
|
|
unselected_bg: rotate_color(theme.nav.unselected_bg, degrees),
|
|
unselected_fg: rotate_color(theme.nav.unselected_fg, degrees),
|
|
},
|
|
editor_widget: EditorWidgetColors {
|
|
cursor_bg: rotate_color(theme.editor_widget.cursor_bg, degrees),
|
|
cursor_fg: rotate_color(theme.editor_widget.cursor_fg, degrees),
|
|
selection_bg: rotate_color(theme.editor_widget.selection_bg, degrees),
|
|
completion_bg: rotate_color(theme.editor_widget.completion_bg, degrees),
|
|
completion_fg: rotate_color(theme.editor_widget.completion_fg, degrees),
|
|
completion_selected: rotate_color(theme.editor_widget.completion_selected, degrees),
|
|
completion_example: rotate_color(theme.editor_widget.completion_example, degrees),
|
|
},
|
|
browser: BrowserColors {
|
|
directory: rotate_color(theme.browser.directory, degrees),
|
|
project_file: rotate_color(theme.browser.project_file, degrees),
|
|
selected: rotate_color(theme.browser.selected, degrees),
|
|
file: rotate_color(theme.browser.file, degrees),
|
|
focused_border: rotate_color(theme.browser.focused_border, degrees),
|
|
unfocused_border: rotate_color(theme.browser.unfocused_border, degrees),
|
|
root: rotate_color(theme.browser.root, degrees),
|
|
file_icon: rotate_color(theme.browser.file_icon, degrees),
|
|
folder_icon: rotate_color(theme.browser.folder_icon, degrees),
|
|
empty_text: rotate_color(theme.browser.empty_text, degrees),
|
|
},
|
|
input: InputColors {
|
|
text: rotate_color(theme.input.text, degrees),
|
|
cursor: rotate_color(theme.input.cursor, degrees),
|
|
hint: rotate_color(theme.input.hint, degrees),
|
|
},
|
|
search: SearchColors {
|
|
active: rotate_color(theme.search.active, degrees),
|
|
inactive: rotate_color(theme.search.inactive, degrees),
|
|
match_bg: rotate_color(theme.search.match_bg, degrees),
|
|
match_fg: rotate_color(theme.search.match_fg, degrees),
|
|
},
|
|
markdown: MarkdownColors {
|
|
h1: rotate_color(theme.markdown.h1, degrees),
|
|
h2: rotate_color(theme.markdown.h2, degrees),
|
|
h3: rotate_color(theme.markdown.h3, degrees),
|
|
code: rotate_color(theme.markdown.code, degrees),
|
|
code_border: rotate_color(theme.markdown.code_border, degrees),
|
|
link: rotate_color(theme.markdown.link, degrees),
|
|
link_url: rotate_color(theme.markdown.link_url, degrees),
|
|
quote: rotate_color(theme.markdown.quote, degrees),
|
|
text: rotate_color(theme.markdown.text, degrees),
|
|
list: rotate_color(theme.markdown.list, degrees),
|
|
},
|
|
engine: EngineColors {
|
|
header: rotate_color(theme.engine.header, degrees),
|
|
header_focused: rotate_color(theme.engine.header_focused, degrees),
|
|
divider: rotate_color(theme.engine.divider, degrees),
|
|
scroll_indicator: rotate_color(theme.engine.scroll_indicator, degrees),
|
|
label: rotate_color(theme.engine.label, degrees),
|
|
label_focused: rotate_color(theme.engine.label_focused, degrees),
|
|
label_dim: rotate_color(theme.engine.label_dim, degrees),
|
|
value: rotate_color(theme.engine.value, degrees),
|
|
focused: rotate_color(theme.engine.focused, degrees),
|
|
normal: rotate_color(theme.engine.normal, degrees),
|
|
dim: rotate_color(theme.engine.dim, degrees),
|
|
path: rotate_color(theme.engine.path, degrees),
|
|
border_magenta: rotate_color(theme.engine.border_magenta, degrees),
|
|
border_green: rotate_color(theme.engine.border_green, degrees),
|
|
border_cyan: rotate_color(theme.engine.border_cyan, degrees),
|
|
separator: rotate_color(theme.engine.separator, degrees),
|
|
hint_active: rotate_color(theme.engine.hint_active, degrees),
|
|
hint_inactive: rotate_color(theme.engine.hint_inactive, degrees),
|
|
},
|
|
dict: DictColors {
|
|
word_name: rotate_color(theme.dict.word_name, degrees),
|
|
word_bg: rotate_color(theme.dict.word_bg, degrees),
|
|
alias: rotate_color(theme.dict.alias, degrees),
|
|
stack_sig: rotate_color(theme.dict.stack_sig, degrees),
|
|
description: rotate_color(theme.dict.description, degrees),
|
|
example: rotate_color(theme.dict.example, degrees),
|
|
category_focused: rotate_color(theme.dict.category_focused, degrees),
|
|
category_selected: rotate_color(theme.dict.category_selected, degrees),
|
|
category_normal: rotate_color(theme.dict.category_normal, degrees),
|
|
category_dimmed: rotate_color(theme.dict.category_dimmed, degrees),
|
|
border_focused: rotate_color(theme.dict.border_focused, degrees),
|
|
border_normal: rotate_color(theme.dict.border_normal, degrees),
|
|
header_desc: rotate_color(theme.dict.header_desc, degrees),
|
|
},
|
|
title: TitleColors {
|
|
big_title: rotate_color(theme.title.big_title, degrees),
|
|
author: rotate_color(theme.title.author, degrees),
|
|
link: rotate_color(theme.title.link, degrees),
|
|
license: rotate_color(theme.title.license, degrees),
|
|
prompt: rotate_color(theme.title.prompt, degrees),
|
|
subtitle: rotate_color(theme.title.subtitle, degrees),
|
|
},
|
|
meter: MeterColors {
|
|
low: rotate_color(theme.meter.low, degrees),
|
|
mid: rotate_color(theme.meter.mid, degrees),
|
|
high: rotate_color(theme.meter.high, degrees),
|
|
low_rgb: rotate_tuple(theme.meter.low_rgb, degrees),
|
|
mid_rgb: rotate_tuple(theme.meter.mid_rgb, degrees),
|
|
high_rgb: rotate_tuple(theme.meter.high_rgb, degrees),
|
|
},
|
|
sparkle: SparkleColors {
|
|
colors: [
|
|
rotate_tuple(theme.sparkle.colors[0], degrees),
|
|
rotate_tuple(theme.sparkle.colors[1], degrees),
|
|
rotate_tuple(theme.sparkle.colors[2], degrees),
|
|
rotate_tuple(theme.sparkle.colors[3], degrees),
|
|
rotate_tuple(theme.sparkle.colors[4], degrees),
|
|
],
|
|
},
|
|
confirm: ConfirmColors {
|
|
border: rotate_color(theme.confirm.border, degrees),
|
|
button_selected_bg: rotate_color(theme.confirm.button_selected_bg, degrees),
|
|
button_selected_fg: rotate_color(theme.confirm.button_selected_fg, degrees),
|
|
},
|
|
}
|
|
}
|