//! Derive [`ThemeColors`] from a [`Palette`]. use super::*; use super::palette::{Palette, Rgb, darken, mid, rgb, tint}; /// Build a complete [`ThemeColors`] from a [`Palette`]. pub fn build(p: &Palette) -> ThemeColors { let darker_bg = darken(p.bg, 0.15); ThemeColors { ui: UiColors { bg: rgb(p.bg), bg_rgb: p.bg, text_primary: rgb(p.fg), text_muted: rgb(p.fg_dim), text_dim: rgb(p.fg_muted), border: rgb(p.surface2), header: rgb(p.cyan), unfocused: rgb(p.fg_muted), accent: rgb(p.accent), surface: rgb(p.surface), }, status: StatusColors { playing_bg: rgb(tint(p.bg, p.green, 0.25)), playing_fg: rgb(p.green), stopped_bg: rgb(tint(p.bg, p.red, 0.25)), stopped_fg: rgb(p.red), fill_on: rgb(p.green), fill_off: rgb(p.fg_muted), fill_bg: rgb(p.surface), }, selection: SelectionColors { cursor_bg: rgb(p.accent), cursor_fg: rgb(p.bg), selected_bg: rgb(tint(p.bg, p.accent, 0.30)), selected_fg: rgb(p.accent), in_range_bg: rgb(tint(p.bg, p.accent, 0.20)), in_range_fg: rgb(p.fg), cursor: rgb(p.accent), selected: rgb(tint(p.bg, p.accent, 0.30)), in_range: rgb(tint(p.bg, p.accent, 0.20)), }, tile: TileColors { playing_active_bg: rgb(tint(p.bg, p.orange, 0.35)), playing_active_fg: rgb(p.orange), playing_inactive_bg: rgb(tint(p.bg, p.yellow, 0.30)), playing_inactive_fg: rgb(p.yellow), active_bg: rgb(tint(p.bg, p.cyan, 0.25)), active_fg: rgb(p.cyan), content_bg: rgb(tint(p.bg, p.cyan, 0.30)), inactive_bg: rgb(p.surface), inactive_fg: rgb(p.fg_dim), active_selected_bg: rgb(tint(p.bg, p.accent, 0.35)), active_in_range_bg: rgb(tint(p.bg, p.accent, 0.22)), link_bright: p.link_bright, link_dim: p.link_dim, }, header: HeaderColors { tempo_bg: rgb(tint(p.bg, p.tempo_color, 0.30)), tempo_fg: rgb(p.tempo_color), beat_bg: rgb(tint(p.bg, p.tempo_color, 0.45)), bank_bg: rgb(tint(p.bg, p.bank_color, 0.25)), bank_fg: rgb(p.bank_color), pattern_bg: rgb(tint(p.bg, p.pattern_color, 0.25)), pattern_fg: rgb(p.pattern_color), stats_bg: rgb(p.surface), stats_fg: rgb(p.fg_dim), }, modal: ModalColors { border: rgb(p.cyan), border_accent: rgb(p.accent), border_warn: rgb(p.orange), border_dim: rgb(p.fg_muted), confirm: rgb(p.orange), rename: rgb(p.purple), input: rgb(p.cyan), editor: rgb(p.cyan), preview: rgb(p.fg_muted), }, flash: FlashColors { error_bg: rgb(tint(p.bg, p.red, 0.30)), error_fg: rgb(p.red), success_bg: rgb(tint(p.bg, p.green, 0.25)), success_fg: rgb(p.green), info_bg: rgb(p.surface), info_fg: rgb(p.fg), }, list: ListColors { playing_bg: rgb(tint(p.bg, p.green, 0.25)), playing_fg: rgb(p.green), staged_play_bg: rgb(tint(p.bg, p.purple, 0.30)), staged_play_fg: rgb(p.purple), staged_stop_bg: rgb(tint(p.bg, p.red, 0.30)), staged_stop_fg: rgb(p.red), edit_bg: rgb(tint(p.bg, p.cyan, 0.25)), edit_fg: rgb(p.cyan), hover_bg: rgb(p.surface2), hover_fg: rgb(p.fg), muted_bg: rgb(tint(p.bg, p.surface, 0.30)), muted_fg: rgb(p.fg_muted), soloed_bg: rgb(tint(p.bg, p.yellow, 0.30)), soloed_fg: rgb(p.yellow), }, link_status: LinkStatusColors { disabled: rgb(p.red), connected: rgb(p.green), listening: rgb(p.yellow), }, syntax: syntax_colors(p, darker_bg), table: TableColors { row_even: rgb(darker_bg), row_odd: rgb(p.bg), }, values: ValuesColors { tempo: rgb(p.orange), value: rgb(p.fg_dim), }, hint: HintColors { key: rgb(p.orange), text: rgb(p.fg_muted), }, view_badge: ViewBadgeColors { bg: rgb(p.fg), fg: rgb(p.bg), }, nav: NavColors { selected_bg: rgb(tint(p.bg, p.accent, 0.35)), selected_fg: rgb(p.fg), unselected_bg: rgb(p.surface), unselected_fg: rgb(p.fg_muted), }, editor_widget: EditorWidgetColors { cursor_bg: rgb(p.fg), cursor_fg: rgb(p.bg), selection_bg: rgb(tint(p.bg, p.accent, 0.30)), completion_bg: rgb(p.surface), completion_fg: rgb(p.fg), completion_selected: rgb(p.orange), completion_example: rgb(p.cyan), }, browser: BrowserColors { directory: rgb(p.blue), project_file: rgb(p.purple), selected: rgb(p.orange), file: rgb(p.fg), focused_border: rgb(p.orange), unfocused_border: rgb(p.fg_muted), root: rgb(p.fg), file_icon: rgb(p.fg_muted), folder_icon: rgb(p.blue), empty_text: rgb(p.fg_muted), }, input: InputColors { text: rgb(p.cyan), cursor: rgb(p.fg), hint: rgb(p.fg_muted), }, search: SearchColors { active: rgb(p.orange), inactive: rgb(p.fg_muted), match_bg: rgb(p.yellow), match_fg: rgb(p.bg), }, markdown: MarkdownColors { h1: rgb(p.cyan), h2: rgb(p.orange), h3: rgb(p.purple), code: rgb(p.green), code_border: rgb(mid(p.surface2, p.fg_muted, 0.3)), link: rgb(p.accent), link_url: rgb(mid(p.fg_muted, p.fg_dim, 0.3)), quote: rgb(p.fg_muted), text: rgb(p.fg), list: rgb(p.fg), }, engine: engine_colors(p), dict: dict_colors(p), title: TitleColors { big_title: rgb(p.title_accent), author: rgb(p.title_author), link: rgb(p.green), license: rgb(p.orange), prompt: rgb(mid(p.fg_dim, p.fg, 0.3)), subtitle: rgb(p.fg), }, meter: MeterColors { low: rgb(p.green), mid: rgb(p.yellow), high: rgb(p.red), low_rgb: p.meter[0], mid_rgb: p.meter[1], high_rgb: p.meter[2], }, sparkle: SparkleColors { colors: p.sparkle, }, confirm: ConfirmColors { border: rgb(p.orange), button_selected_bg: rgb(p.orange), button_selected_fg: rgb(p.bg), }, } } fn syntax_colors(p: &Palette, darker_bg: Rgb) -> SyntaxColors { let syn_bg = |accent: Rgb| -> Color { rgb(tint(p.bg, accent, 0.20)) }; let interval_fg = mid(p.green, p.fg, 0.3); SyntaxColors { gap_bg: rgb(darker_bg), executed_bg: rgb(tint(p.bg, p.purple, 0.15)), selected_bg: rgb(tint(p.bg, p.orange, 0.30)), emit: (rgb(p.fg), syn_bg(p.accent)), number: (rgb(p.purple), syn_bg(p.purple)), string: (rgb(p.green), syn_bg(p.green)), comment: (rgb(p.fg_muted), rgb(darker_bg)), keyword: (rgb(p.accent), syn_bg(p.accent)), stack_op: (rgb(p.blue), syn_bg(p.blue)), operator: (rgb(p.red), syn_bg(p.red)), sound: (rgb(p.cyan), syn_bg(p.cyan)), param: (rgb(p.orange), syn_bg(p.orange)), context: (rgb(p.orange), syn_bg(p.orange)), note: (rgb(p.green), syn_bg(p.green)), interval: (rgb(interval_fg), syn_bg(p.green)), variable: (rgb(p.purple), syn_bg(p.purple)), vary: (rgb(p.yellow), syn_bg(p.yellow)), generator: (rgb(p.cyan), syn_bg(p.cyan)), user_defined: (rgb(p.secondary), syn_bg(p.secondary)), default: (rgb(p.fg_dim), rgb(darker_bg)), } } fn engine_colors(p: &Palette) -> EngineColors { let divider = mid(p.surface2, p.fg_muted, 0.2); let label = mid(p.fg_muted, p.fg, 0.4); EngineColors { header: rgb(p.cyan), header_focused: rgb(p.yellow), divider: rgb(divider), scroll_indicator: rgb(mid(divider, p.fg_muted, 0.3)), label: rgb(label), label_focused: rgb(mid(label, p.fg, 0.3)), label_dim: rgb(mid(p.fg_muted, label, 0.3)), value: rgb(mid(p.fg_dim, p.fg, 0.5)), focused: rgb(p.yellow), normal: rgb(p.fg), dim: rgb(mid(divider, p.fg_muted, 0.3)), path: rgb(label), border_magenta: rgb(p.purple), border_green: rgb(p.green), border_cyan: rgb(p.cyan), separator: rgb(divider), hint_active: rgb(mid(p.orange, p.yellow, 0.5)), hint_inactive: rgb(divider), } } fn dict_colors(p: &Palette) -> DictColors { let divider = mid(p.surface2, p.fg_muted, 0.2); let label = mid(p.fg_muted, p.fg, 0.4); DictColors { word_name: rgb(p.green), word_bg: rgb(tint(p.bg, p.cyan, 0.20)), alias: rgb(p.fg_muted), stack_sig: rgb(p.purple), description: rgb(p.fg), example: rgb(label), category_focused: rgb(p.yellow), category_selected: rgb(p.cyan), category_normal: rgb(p.fg), category_dimmed: rgb(mid(divider, p.fg_muted, 0.3)), border_focused: rgb(p.yellow), border_normal: rgb(divider), header_desc: rgb(mid(label, p.fg, 0.3)), } }