use eframe::egui::{self, Color32, Stroke};
use crate::theme::ThemeSpec;
#[derive(Clone, Copy)]
pub struct GuiTheme {
pub bg: Color32,
pub panel: Color32,
pub text: Color32,
pub dim: Color32,
pub accent: Color32,
pub ok: Color32,
pub err: Color32,
pub subst: Color32,
pub pending: Color32,
pub select_bg: Color32,
pub select_fg: Color32,
}
fn c([r, g, b]: [u8; 3]) -> Color32 {
Color32::from_rgb(r, g, b)
}
pub fn from_ratatui(color: ratatui::style::Color, fallback: Color32) -> Color32 {
match color {
ratatui::style::Color::Rgb(r, g, b) => Color32::from_rgb(r, g, b),
_ => fallback,
}
}
fn mix(a: Color32, b: Color32, t: f32) -> Color32 {
let l = |x: u8, y: u8| (x as f32 * (1.0 - t) + y as f32 * t).round() as u8;
Color32::from_rgb(l(a.r(), b.r()), l(a.g(), b.g()), l(a.b(), b.b()))
}
impl GuiTheme {
pub fn from_spec(s: &ThemeSpec) -> Self {
Self {
bg: c(s.bg),
panel: c(s.panel),
text: c(s.text),
dim: c(s.dim),
accent: c(s.accent),
ok: c(s.ok),
err: c(s.err),
subst: c(s.subst),
pending: c(s.pending),
select_bg: c(s.select_bg),
select_fg: c(s.select_fg),
}
}
pub fn raised(&self) -> Color32 {
mix(self.panel, self.text, 0.06)
}
pub fn sunken(&self) -> Color32 {
mix(self.bg, Color32::BLACK, 0.10)
}
pub fn apply(&self, ctx: &egui::Context) {
let mut visuals = egui::Visuals::dark();
visuals.override_text_color = Some(self.text);
visuals.window_fill = self.bg;
visuals.panel_fill = self.panel;
visuals.faint_bg_color = self.raised();
visuals.extreme_bg_color = self.sunken();
visuals.hyperlink_color = self.accent;
visuals.selection.bg_fill = self.select_bg;
visuals.selection.stroke = Stroke::new(1.0, self.select_fg);
visuals.window_stroke = Stroke::new(1.0, mix(self.panel, self.text, 0.18));
let w = &mut visuals.widgets;
w.noninteractive.bg_fill = self.panel;
w.noninteractive.weak_bg_fill = self.panel;
w.noninteractive.fg_stroke = Stroke::new(1.0, self.dim);
w.noninteractive.bg_stroke = Stroke::new(1.0, mix(self.panel, self.text, 0.10));
w.inactive.bg_fill = self.raised();
w.inactive.weak_bg_fill = self.raised();
w.inactive.fg_stroke = Stroke::new(1.0, self.text);
w.inactive.bg_stroke = Stroke::new(1.0, mix(self.panel, self.text, 0.12));
w.hovered.bg_fill = mix(self.panel, self.accent, 0.30);
w.hovered.weak_bg_fill = mix(self.panel, self.accent, 0.22);
w.hovered.fg_stroke = Stroke::new(1.0, self.text);
w.hovered.bg_stroke = Stroke::new(1.0, self.accent);
w.active.bg_fill = mix(self.panel, self.accent, 0.45);
w.active.weak_bg_fill = mix(self.panel, self.accent, 0.35);
w.active.fg_stroke = Stroke::new(1.0, self.text);
w.active.bg_stroke = Stroke::new(1.0, self.accent);
w.open.bg_fill = self.raised();
w.open.fg_stroke = Stroke::new(1.0, self.text);
ctx.all_styles_mut(|style| {
style.visuals = visuals.clone();
style.spacing.item_spacing = egui::vec2(6.0, 6.0);
style.spacing.button_padding = egui::vec2(8.0, 4.0);
});
}
}
pub fn method_color(method: &str) -> Color32 {
match crate::hurl::method_rgb(method) {
Some((r, g, b)) => Color32::from_rgb(r, g, b),
None => Color32::GRAY,
}
}