mod palette;
use std::fmt::Debug;
#[doc(inline)]
pub use palette::ThemePalette;
#[derive(Debug, Default, PartialEq, Clone, Copy)]
pub enum ThemeScheme {
#[default]
Light,
Dark,
}
#[derive(Debug, Default, PartialEq, Clone, Copy)]
pub enum ThemeContrast {
#[default]
Normal,
High,
}
#[derive(PartialEq, Clone, Copy)]
pub struct ThemeColor {
pub red: f32,
pub green: f32,
pub blue: f32,
}
impl Debug for ThemeColor {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"#{:02X}{:02X}{:02X}",
(self.red * 255.0) as u8,
(self.green * 255.0) as u8,
(self.blue * 255.0) as u8
)
}
}
impl ThemeColor {
pub const WHITE: Self = Self {
red: 1.0,
green: 1.0,
blue: 1.0,
};
pub const BLACK: Self = Self {
red: 0.0,
green: 0.0,
blue: 0.0,
};
pub const fn from_rgb8(red: u8, green: u8, blue: u8) -> Self {
Self {
red: red as f32 / 255.0,
green: green as f32 / 255.0,
blue: blue as f32 / 255.0,
}
}
}
#[derive(Debug, Default, PartialEq, Clone, Copy)]
pub enum ThemeKind {
#[cfg_attr(target_os = "windows", default)]
Windows,
#[cfg_attr(target_os = "macos", default)]
MacOS,
#[cfg_attr(not(any(target_os = "windows", target_os = "macos")), default)]
Gtk,
Qt,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Theme {
pub name: String,
pub palette: ThemePalette,
}
impl Default for Theme {
fn default() -> Self {
Theme::new(
ThemeKind::default(),
ThemeScheme::default(),
ThemeContrast::default(),
None,
)
}
}
impl Theme {
pub fn new(
kind: ThemeKind,
scheme: ThemeScheme,
contrast: ThemeContrast,
accent: Option<ThemeColor>,
) -> Self {
let (mut name, mut palette) = match kind {
ThemeKind::Windows => match scheme {
ThemeScheme::Light => ("FluentLight".to_string(), palette::FLUENT_LIGHT),
ThemeScheme::Dark => ("FluentDark".to_string(), palette::FLUENT_DARK),
},
ThemeKind::MacOS => match scheme {
ThemeScheme::Light => ("AquaLight".to_string(), palette::AQUA_LIGHT),
ThemeScheme::Dark => ("AquaDark".to_string(), palette::AQUA_DARK),
},
ThemeKind::Gtk => match scheme {
ThemeScheme::Light => ("AdwaitaLight".to_string(), palette::ADWAITA_LIGHT),
ThemeScheme::Dark => ("AdwaitaDark".to_string(), palette::ADWAITA_DARK),
},
ThemeKind::Qt => match scheme {
ThemeScheme::Light => ("BreezeLight".to_string(), palette::BREEZE_LIGHT),
ThemeScheme::Dark => ("BreezeDark".to_string(), palette::BREEZE_DARK),
},
};
if contrast == ThemeContrast::High {
name.push_str("HC");
match scheme {
ThemeScheme::Light => {
palette.background = ThemeColor::WHITE;
palette.foreground = ThemeColor::BLACK;
}
ThemeScheme::Dark => {
palette.background = ThemeColor::BLACK;
palette.foreground = ThemeColor::WHITE;
}
}
}
if let Some(accent) = accent {
palette.accent = accent;
}
Theme { name, palette }
}
}