use egui::{CornerRadius, Stroke, Style};
use super::density::Density;
use super::elevation::Elevation;
use super::palette::Palette;
use super::state;
use super::tokens::{RADIUS, SPACING};
pub fn apply_theme(ctx: &egui::Context, palette: &Palette) {
apply_theme_with(ctx, palette, Density::Comfortable);
}
pub fn apply_theme_with(ctx: &egui::Context, palette: &Palette, density: Density) {
ctx.all_styles_mut(|style| {
apply_visuals(style, palette);
apply_spacing(style, density);
});
state::store(ctx, palette, density);
}
fn apply_visuals(style: &mut Style, p: &Palette) {
let v = &mut style.visuals;
let r_md = corner(RADIUS.md);
v.window_fill = p.bg_surface;
v.panel_fill = p.bg_app;
v.extreme_bg_color = p.bg_surface;
v.faint_bg_color = p.bg_hover;
v.window_stroke = Stroke::new(1.0, p.border_default);
v.window_corner_radius = corner(RADIUS.lg);
v.window_shadow = Elevation::Modal.shadow(p.dark_mode);
v.popup_shadow = Elevation::Popover.shadow(p.dark_mode);
v.override_text_color = Some(p.text_primary);
v.widgets.noninteractive.bg_fill = p.bg_surface;
v.widgets.noninteractive.weak_bg_fill = p.bg_surface;
v.widgets.noninteractive.bg_stroke = Stroke::new(1.0, p.border_subtle);
v.widgets.noninteractive.fg_stroke = Stroke::new(1.0, p.text_secondary);
v.widgets.noninteractive.corner_radius = r_md;
v.widgets.inactive.bg_fill = p.bg_surface;
v.widgets.inactive.weak_bg_fill = p.bg_surface;
v.widgets.inactive.bg_stroke = Stroke::new(1.0, p.border_default);
v.widgets.inactive.fg_stroke = Stroke::new(1.0, p.text_primary);
v.widgets.inactive.corner_radius = r_md;
v.widgets.hovered.bg_fill = p.bg_hover;
v.widgets.hovered.weak_bg_fill = p.bg_hover;
v.widgets.hovered.bg_stroke = Stroke::new(1.0, p.brand_default);
v.widgets.hovered.fg_stroke = Stroke::new(1.0, p.text_primary);
v.widgets.hovered.corner_radius = r_md;
v.widgets.active.bg_fill = p.bg_pressed;
v.widgets.active.weak_bg_fill = p.bg_pressed;
v.widgets.active.bg_stroke = Stroke::new(1.5, p.brand_hover);
v.widgets.active.fg_stroke = Stroke::new(1.0, p.text_primary);
v.widgets.active.corner_radius = r_md;
v.widgets.open.bg_fill = p.bg_surface_alt;
v.widgets.open.weak_bg_fill = p.bg_surface_alt;
v.widgets.open.bg_stroke = Stroke::new(1.0, p.brand_default);
v.widgets.open.fg_stroke = Stroke::new(1.0, p.text_primary);
v.widgets.open.corner_radius = r_md;
v.selection.bg_fill = multiply_alpha(p.brand_default, 0.25);
v.selection.stroke = Stroke::new(2.0, p.focus_ring);
v.hyperlink_color = p.brand_hover;
v.error_fg_color = p.error;
v.warn_fg_color = p.warning;
}
fn apply_spacing(style: &mut Style, density: Density) {
let k = density.scale();
let s = &mut style.spacing;
s.item_spacing = egui::vec2(SPACING.s2 * k, 6.0 * k);
s.button_padding = egui::vec2(SPACING.s3 * k, SPACING.s2 * k);
s.window_margin = egui::Margin::same((SPACING.s4 * k) as i8);
s.indent = SPACING.s4 * k;
s.interact_size.y = density.interact_size();
s.icon_width = 16.0 * k;
s.icon_spacing = SPACING.s2 * k;
}
fn corner(px: f32) -> CornerRadius {
CornerRadius::same(px.round().clamp(0.0, 255.0) as u8)
}
fn multiply_alpha(c: egui::Color32, factor: f32) -> egui::Color32 {
let [r, g, b, a] = c.to_array();
let a = (a as f32 * factor).round().clamp(0.0, 255.0) as u8;
egui::Color32::from_rgba_unmultiplied(r, g, b, a)
}