use std::cell::RefCell;
use std::sync::atomic::{AtomicU64, Ordering};
use crate::color::Color;
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub enum ThemePreference {
#[default]
Dark,
Light,
System,
}
#[derive(Clone, Debug)]
pub struct Visuals {
pub bg_color: Color,
pub panel_fill: Color,
pub top_bar_bg: Color,
pub window_fill: Color,
pub window_title_fill: Color,
pub window_title_fill_drag: Color,
pub window_shadow: Color,
pub window_stroke: Color,
pub window_title_text: Color,
pub window_close_bg: Color,
pub window_close_bg_hovered: Color,
pub window_close_fg: Color,
pub window_resize_hover: Color,
pub window_resize_active: Color,
pub text_color: Color,
pub text_dim: Color,
pub text_link: Color,
pub text_link_hovered: Color,
pub accent: Color,
pub accent_hovered: Color,
pub accent_pressed: Color,
pub accent_focus: Color,
pub widget_bg: Color,
pub widget_bg_hovered: Color,
pub widget_stroke: Color,
pub widget_stroke_active: Color,
pub track_bg: Color,
pub scroll_track: Color,
pub scroll_thumb: Color,
pub scroll_thumb_hovered: Color,
pub scroll_thumb_dragging: Color,
pub separator: Color,
pub selection_bg: Color,
pub selection_bg_unfocused: Color,
}
impl Visuals {
pub fn dark() -> Self {
let accent = Color::rgb(0.22, 0.45, 0.88);
let accent_hovered = Color::rgb(0.30, 0.52, 0.92);
let accent_pressed = Color::rgb(0.16, 0.36, 0.72);
Self {
bg_color: Color::rgb(0.10, 0.10, 0.12),
panel_fill: Color::rgb(0.13, 0.13, 0.15),
top_bar_bg: Color::rgb(0.15, 0.15, 0.17),
window_fill: Color::rgb(0.15, 0.15, 0.18),
window_title_fill: Color::rgb(0.20, 0.20, 0.24),
window_title_fill_drag: Color::rgb(0.16, 0.16, 0.20),
window_shadow: Color::rgba(0.0, 0.0, 0.0, 0.35),
window_stroke: Color::rgba(1.0, 1.0, 1.0, 0.08),
window_title_text: Color::rgba(1.0, 1.0, 1.0, 0.90),
window_close_bg: Color::rgba(1.0, 1.0, 1.0, 0.12),
window_close_bg_hovered:Color::rgba(1.0, 1.0, 1.0, 0.25),
window_close_fg: Color::rgba(1.0, 1.0, 1.0, 0.80),
window_resize_hover: Color::rgba(1.0, 1.0, 1.0, 0.40),
window_resize_active: Color::rgba(1.0, 1.0, 1.0, 0.80),
text_color: Color::rgb(0.90, 0.90, 0.92),
text_dim: Color::rgba(0.90, 0.90, 0.92, 0.50),
text_link: Color::rgb(0.45, 0.65, 1.00),
text_link_hovered: Color::rgb(0.35, 0.55, 0.90),
accent,
accent_hovered,
accent_pressed,
accent_focus: Color::rgba(0.22, 0.45, 0.88, 0.45),
widget_bg: Color::rgb(0.22, 0.22, 0.26),
widget_bg_hovered: Color::rgb(0.28, 0.28, 0.33),
widget_stroke: Color::rgba(0.60, 0.60, 0.65, 0.60),
widget_stroke_active: accent_pressed,
track_bg: Color::rgb(0.25, 0.25, 0.28),
scroll_track: Color::rgba(1.0, 1.0, 1.0, 0.04),
scroll_thumb: Color::rgba(1.0, 1.0, 1.0, 0.18),
scroll_thumb_hovered: Color::rgba(1.0, 1.0, 1.0, 0.32),
scroll_thumb_dragging: Color::rgba(1.0, 1.0, 1.0, 0.45),
separator: Color::rgba(1.0, 1.0, 1.0, 0.10),
selection_bg: Color::rgba(0.22, 0.45, 0.88, 0.45),
selection_bg_unfocused: Color::rgba(0.60, 0.60, 0.65, 0.35),
}
}
pub fn light() -> Self {
let accent = Color::rgb(0.22, 0.45, 0.88);
let accent_hovered = Color::rgb(0.30, 0.52, 0.92);
let accent_pressed = Color::rgb(0.16, 0.36, 0.72);
Self {
bg_color: Color::rgb(0.90, 0.90, 0.92),
panel_fill: Color::rgb(0.92, 0.92, 0.95),
top_bar_bg: Color::rgb(0.88, 0.88, 0.91),
window_fill: Color::rgb(0.97, 0.97, 0.98),
window_title_fill: Color::rgb(0.87, 0.87, 0.91),
window_title_fill_drag: Color::rgb(0.80, 0.80, 0.85),
window_shadow: Color::rgba(0.0, 0.0, 0.0, 0.18),
window_stroke: Color::rgba(0.0, 0.0, 0.0, 0.15),
window_title_text: Color::rgba(0.05, 0.05, 0.10, 0.90),
window_close_bg: Color::rgba(0.0, 0.0, 0.0, 0.08),
window_close_bg_hovered:Color::rgba(0.0, 0.0, 0.0, 0.18),
window_close_fg: Color::rgba(0.0, 0.0, 0.0, 0.65),
window_resize_hover: Color::rgba(0.0, 0.0, 0.0, 0.30),
window_resize_active: Color::rgba(0.0, 0.0, 0.0, 0.65),
text_color: Color::rgb(0.08, 0.08, 0.10),
text_dim: Color::rgba(0.08, 0.08, 0.10, 0.50),
text_link: Color::rgb(0.15, 0.35, 0.75),
text_link_hovered: Color::rgb(0.10, 0.28, 0.62),
accent,
accent_hovered,
accent_pressed,
accent_focus: Color::rgba(0.22, 0.45, 0.88, 0.45),
widget_bg: Color::rgb(1.00, 1.00, 1.00),
widget_bg_hovered: Color::rgb(0.92, 0.93, 0.95),
widget_stroke: Color::rgb(0.75, 0.76, 0.78),
widget_stroke_active: accent_pressed,
track_bg: Color::rgb(0.85, 0.86, 0.88),
scroll_track: Color::rgba(0.0, 0.0, 0.0, 0.04),
scroll_thumb: Color::rgba(0.0, 0.0, 0.0, 0.18),
scroll_thumb_hovered: Color::rgba(0.0, 0.0, 0.0, 0.32),
scroll_thumb_dragging: Color::rgba(0.0, 0.0, 0.0, 0.45),
separator: Color::rgba(0.0, 0.0, 0.0, 0.12),
selection_bg: Color::rgba(0.22, 0.45, 0.88, 0.45),
selection_bg_unfocused: Color::rgba(0.45, 0.45, 0.50, 0.35),
}
}
pub fn for_preference(pref: ThemePreference) -> Self {
match pref {
ThemePreference::Light => Self::light(),
_ => Self::dark(),
}
}
}
thread_local! {
static VISUALS: RefCell<Visuals> = RefCell::new(Visuals::dark());
}
static VISUALS_EPOCH: AtomicU64 = AtomicU64::new(1);
pub fn current_visuals_epoch() -> u64 {
VISUALS_EPOCH.load(Ordering::Relaxed)
}
pub fn set_visuals(v: Visuals) {
VISUALS.with(|cell| *cell.borrow_mut() = v);
VISUALS_EPOCH.fetch_add(1, Ordering::Relaxed);
}
pub fn current_visuals() -> Visuals {
VISUALS.with(|cell| cell.borrow().clone())
}