diff options
author | 2022-05-21 17:33:31 -0400 | |
---|---|---|
committer | 2022-05-21 17:33:31 -0400 | |
commit | 2cfb307f8c3927a0876c6b754a5d7d673b9edfee (patch) | |
tree | 577559723dcadfd2e8719780f711741c82086e56 /style/src/theme | |
parent | 664251f3f5c7b76f69a97683af1468094bba887f (diff) | |
download | iced-2cfb307f8c3927a0876c6b754a5d7d673b9edfee.tar.gz iced-2cfb307f8c3927a0876c6b754a5d7d673b9edfee.tar.bz2 iced-2cfb307f8c3927a0876c6b754a5d7d673b9edfee.zip |
Implement basic theming `Palette`
Diffstat (limited to 'style/src/theme')
-rw-r--r-- | style/src/theme/palette.rs | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/style/src/theme/palette.rs b/style/src/theme/palette.rs new file mode 100644 index 00000000..74139e6b --- /dev/null +++ b/style/src/theme/palette.rs @@ -0,0 +1,202 @@ +use iced_core::Color; + +use lazy_static::lazy_static; +use palette::{FromColor, Hsl, Mix, RelativeContrast, Srgb}; + +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct Palette { + background: Color, + text: Color, + primary: Color, + success: Color, + danger: Color, +} + +impl Palette { + pub const LIGHT: Self = Self { + background: Color::WHITE, + text: Color::BLACK, + primary: Color::from_rgb( + 0x5E as f32 / 255.0, + 0x7C as f32 / 255.0, + 0xE2 as f32 / 255.0, + ), + success: Color::from_rgb( + 0x12 as f32 / 255.0, + 0x66 as f32 / 255.0, + 0x4F as f32 / 255.0, + ), + danger: Color::from_rgb( + 0xC3 as f32 / 255.0, + 0x42 as f32 / 255.0, + 0x3F as f32 / 255.0, + ), + }; + + pub const DARK: Self = Self { + background: Color::WHITE, + text: Color::BLACK, + primary: Color::from_rgb( + 0x5E as f32 / 255.0, + 0x7C as f32 / 255.0, + 0xE2 as f32 / 255.0, + ), + success: Color::from_rgb( + 0x12 as f32 / 255.0, + 0x66 as f32 / 255.0, + 0x4F as f32 / 255.0, + ), + danger: Color::from_rgb( + 0xC3 as f32 / 255.0, + 0x42 as f32 / 255.0, + 0x3F as f32 / 255.0, + ), + }; +} + +pub struct Extended { + pub background: Background, + pub primary: Group, + pub success: Group, + pub danger: Group, +} + +lazy_static! { + pub static ref EXTENDED_LIGHT: Extended = + Extended::generate(Palette::LIGHT); + pub static ref EXTENDED_DARK: Extended = Extended::generate(Palette::DARK); +} + +impl Extended { + pub fn generate(palette: Palette) -> Self { + Self { + background: Background::new(palette.background, palette.text), + primary: Group::new( + palette.primary, + palette.background, + palette.text, + ), + success: Group::new( + palette.success, + palette.background, + palette.text, + ), + danger: Group::new( + palette.danger, + palette.background, + palette.text, + ), + } + } +} + +pub struct Background { + pub base: Color, + pub weak: Color, + pub strong: Color, + pub text: Color, +} + +impl Background { + pub fn new(base: Color, text: Color) -> Self { + Self { + base, + weak: muted(base, 0.1), + strong: muted(base, 0.2), + text, + } + } +} + +pub struct Group { + pub base: Color, + pub weak: Color, + pub strong: Color, + pub text: Color, +} + +impl Group { + pub fn new(base: Color, background: Color, text: Color) -> Self { + Self { + base, + weak: mix(base, background, 0.4), + strong: if is_dark(background) { + lighten(base, 0.1) + } else { + darken(base, 0.1) + }, + text: if is_readable(base, text) { + text + } else if is_dark(text) { + Color::WHITE + } else { + Color::BLACK + }, + } + } +} + +fn muted(color: Color, amount: f32) -> Color { + let mut hsl = to_hsl(color); + + hsl.lightness = if is_dark(color) { + let delta = amount * (1.0 - hsl.lightness).powi(7); + hsl.lightness + delta + } else { + let delta = amount * hsl.lightness.powi(5); + hsl.lightness - delta + }; + + from_hsl(hsl) +} + +fn darken(color: Color, amount: f32) -> Color { + let mut hsl = to_hsl(color); + + hsl.lightness = if hsl.lightness - amount < 0.0 { + 0.0 + } else { + hsl.lightness - amount + }; + + from_hsl(hsl) +} + +fn mix(a: Color, b: Color, factor: f32) -> Color { + let a_lin = Srgb::from(a).into_linear(); + let b_lin = Srgb::from(b).into_linear(); + + let mixed = a_lin.mix(&b_lin, factor); + Srgb::from_linear(mixed).into() +} + +fn lighten(color: Color, amount: f32) -> Color { + let mut hsl = to_hsl(color); + + hsl.lightness = if hsl.lightness + amount > 1.0 { + 1.0 + } else { + hsl.lightness + amount + }; + + from_hsl(hsl) +} + +fn is_dark(color: Color) -> bool { + to_hsl(color).lightness < 0.5 +} + +fn is_readable(a: Color, b: Color) -> bool { + let a_srgb = Srgb::from(a); + let b_srgb = Srgb::from(b); + + a_srgb.has_enhanced_contrast_text(&b_srgb) +} + +fn to_hsl(color: Color) -> Hsl { + Hsl::from_color(Srgb::from(color)) +} + +fn from_hsl(hsl: Hsl) -> Color { + Srgb::from_color(hsl).into() +} |