From d981eb4c4e4b888d227f7a1a3828500bfa2a8230 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Wed, 22 Feb 2023 14:06:09 -0500 Subject: [PATCH] wip(theme): remove palette --- examples/cosmic/src/window/desktop.rs | 2 +- src/theme/mod.rs | 232 +++++++++++---------- src/theme/palette.rs | 289 -------------------------- 3 files changed, 125 insertions(+), 398 deletions(-) delete mode 100644 src/theme/palette.rs diff --git a/examples/cosmic/src/window/desktop.rs b/examples/cosmic/src/window/desktop.rs index 685176e..7f3ddad 100644 --- a/examples/cosmic/src/window/desktop.rs +++ b/examples/cosmic/src/window/desktop.rs @@ -237,7 +237,7 @@ impl State { .width(Length::Units(300)) ) .padding(4) - .style(theme::Container::Box), + .style(theme::Container::Background), horizontal_space(Length::Fill), ) .into(), diff --git a/src/theme/mod.rs b/src/theme/mod.rs index 629283f..0536641 100644 --- a/src/theme/mod.rs +++ b/src/theme/mod.rs @@ -2,16 +2,15 @@ // SPDX-License-Identifier: MPL-2.0 pub mod expander; -pub mod palette; mod segmented_button; use std::hash::Hash; use std::hash::Hasher; -pub use self::palette::Palette; pub use self::segmented_button::SegmentedButton; use cosmic_theme::Component; +use cosmic_theme::CosmicPalette; use iced_core::BorderRadius; use iced_lazy::component; use iced_style::application; @@ -37,6 +36,7 @@ type CosmicColor = ::palette::rgb::Srgba; type CosmicComponent = cosmic_theme::Component; type CosmicTheme = cosmic_theme::Theme; type CosmicThemeCss = cosmic_theme::Theme; +type CosmicPaletteCss = cosmic_theme::Theme; lazy_static::lazy_static! { pub static ref COSMIC_DARK: CosmicTheme = CosmicThemeCss::dark_default().into_srgba(); @@ -68,22 +68,6 @@ impl Theme { Self::Light => &COSMIC_LIGHT, } } - - #[must_use] - pub fn palette(self) -> Palette { - match self { - Self::Dark => Palette::DARK, - Self::Light => Palette::LIGHT, - } - } - - #[must_use] - pub fn extended_palette(&self) -> &self::palette::Extended { - match self { - Self::Dark => &self::palette::EXTENDED_DARK, - Self::Light => &self::palette::EXTENDED_LIGHT, - } - } } impl Default for Theme { @@ -254,80 +238,84 @@ impl checkbox::StyleSheet for Theme { type Style = Checkbox; fn active(&self, style: &Self::Style, is_checked: bool) -> checkbox::Appearance { - let palette = self.extended_palette(); + let palette = self.cosmic(); match style { Checkbox::Primary => checkbox_appearance( - palette.primary.strong.text, - palette.background.base, - palette.primary.strong, + palette.accent.on, + palette.basic.base, + palette.accent.base, is_checked, ), Checkbox::Secondary => checkbox_appearance( - palette.background.base.text, - palette.background.base, - palette.background.base, + palette.basic.on, + palette.basic.base, + palette.basic.base, is_checked, ), Checkbox::Success => checkbox_appearance( - palette.success.base.text, - palette.background.base, + palette.success.on, + palette.basic.base, palette.success.base, is_checked, ), Checkbox::Danger => checkbox_appearance( - palette.danger.base.text, - palette.background.base, - palette.danger.base, + palette.destructive.on, + palette.basic.base, + palette.destructive.base, is_checked, ), } } fn hovered(&self, style: &Self::Style, is_checked: bool) -> checkbox::Appearance { - let palette = self.extended_palette(); + let palette = self.cosmic(); match style { Checkbox::Primary => checkbox_appearance( - palette.primary.strong.text, - palette.background.weak, - palette.primary.base, + palette.accent.on, + palette.basic.hover, + palette.accent.hover, is_checked, ), Checkbox::Secondary => checkbox_appearance( - palette.background.base.text, - palette.background.weak, - palette.background.base, + palette.basic.on, + palette.basic.hover, + palette.basic.hover, is_checked, ), Checkbox::Success => checkbox_appearance( - palette.success.base.text, - palette.background.weak, - palette.success.base, + palette.success.on, + palette.basic.hover, + palette.success.hover, is_checked, ), Checkbox::Danger => checkbox_appearance( - palette.danger.base.text, - palette.background.weak, - palette.danger.base, + palette.destructive.on, + palette.basic.hover, + palette.destructive.hover, is_checked, ), } } } -fn checkbox_appearance( - checkmark_color: Color, - base: palette::Pair, - accent: palette::Pair, +fn checkbox_appearance + Clone>( + checkmark_color: T, + base: T, + accent: T, is_checked: bool, ) -> checkbox::Appearance { checkbox::Appearance { - background: Background::Color(if is_checked { accent.color } else { base.color }), - checkmark_color, + background: Background::Color(if is_checked { + accent.clone().into() + } else { + base.into() + }), + checkmark_color: checkmark_color.into(), border_radius: 4.0, border_width: if is_checked { 0.0 } else { 1.0 }, - border_color: accent.color, + border_color: accent.into(), text_color: None, } } @@ -366,8 +354,10 @@ impl expander::StyleSheet for Theme { */ #[derive(Clone, Copy)] pub enum Container { + Background, + Primary, + Secondary, Transparent, - Box, Custom(fn(&Theme) -> container::Appearance), } @@ -389,18 +379,40 @@ impl container::StyleSheet for Theme { fn appearance(&self, style: &Self::Style) -> container::Appearance { match style { Container::Transparent => container::Appearance::default(), - Container::Box => { - let palette = self.extended_palette(); + Container::Custom(f) => f(self), + Container::Background => { + let palette = self.cosmic(); container::Appearance { text_color: None, - background: palette.background.weak.color.into(), + background: Some(iced::Background::Color(palette.background.base.into())), + border_radius: 2.0, + border_width: 0.0, + border_color: Color::TRANSPARENT, + } + } + Container::Primary => { + let palette = self.cosmic(); + + container::Appearance { + text_color: None, + background: Some(iced::Background::Color(palette.primary.base.into())), + border_radius: 2.0, + border_width: 0.0, + border_color: Color::TRANSPARENT, + } + } + Container::Secondary => { + let palette = self.cosmic(); + + container::Appearance { + text_color: None, + background: Some(iced::Background::Color(palette.secondary.base.into())), border_radius: 2.0, border_width: 0.0, border_color: Color::TRANSPARENT, } } - Container::Custom(f) => f(self), } } } @@ -508,25 +520,35 @@ impl pick_list::StyleSheet for Theme { impl radio::StyleSheet for Theme { type Style = (); - fn active(&self, _style: &Self::Style, _is_selected: bool) -> radio::Appearance { - let palette = self.extended_palette(); + fn active(&self, _style: &Self::Style, is_selected: bool) -> radio::Appearance { + let theme = self.cosmic(); radio::Appearance { - background: Color::TRANSPARENT.into(), - dot_color: palette.primary.strong.color, + background: if is_selected { + Color::from(theme.accent.base).into() + } else { + // TODO: this seems to be defined weirdly in FIGMA + Color::from(theme.basic.base).into() + }, + dot_color: theme.accent.on.into(), border_width: 1.0, - border_color: palette.primary.strong.color, + border_color: theme.on.into(), text_color: None, } } fn hovered(&self, style: &Self::Style, is_selected: bool) -> radio::Appearance { let active = self.active(style, is_selected); - let palette = self.extended_palette(); + let theme = self.cosmic(); radio::Appearance { - dot_color: palette.primary.strong.color, - background: palette.primary.weak.color.into(), + dot_color: theme.accent.on.into(), + background: if is_selected { + Color::from(theme.accent.hover).into() + } else { + // TODO: this seems to be defined weirdly in FIGMA + Color::from(theme.basic.hover).into() + }, ..active } } @@ -539,24 +561,18 @@ impl toggler::StyleSheet for Theme { type Style = (); fn active(&self, _style: &Self::Style, is_active: bool) -> toggler::Appearance { - let palette = self.palette(); + let theme = self.cosmic(); toggler::Appearance { background: if is_active { - palette.primary + theme.accent.base.into() } else { //TODO: Grab neutral from palette - match self { - Theme::Dark => Color::from_rgb8(0x78, 0x78, 0x78), - Theme::Light => Color::from_rgb8(0x93, 0x93, 0x93), - } + theme.palette.neutral_5.into() }, background_border: None, //TODO: Grab neutral from palette - foreground: match self { - Theme::Dark => Color::from_rgb8(0x27, 0x27, 0x27), - Theme::Light => Color::from_rgb8(0xe4, 0xe4, 0xe4), - }, + foreground: theme.palette.neutral_2.into(), foreground_border: None, } } @@ -591,19 +607,19 @@ impl pane_grid::StyleSheet for Theme { type Style = (); fn picked_split(&self, _style: &Self::Style) -> Option { - let palette = self.extended_palette(); + let theme = self.cosmic(); Some(pane_grid::Line { - color: palette.primary.strong.color, + color: theme.accent.base.into(), width: 2.0, }) } fn hovered_split(&self, _style: &Self::Style) -> Option { - let palette = self.extended_palette(); + let theme = self.cosmic(); Some(pane_grid::Line { - color: palette.primary.base.color, + color: theme.accent.hover.into(), width: 2.0, }) } @@ -630,18 +646,18 @@ impl progress_bar::StyleSheet for Theme { type Style = ProgressBar; fn appearance(&self, style: &Self::Style) -> progress_bar::Appearance { - let palette = self.extended_palette(); + let theme = self.cosmic(); - let from_palette = |bar: Color| progress_bar::Appearance { - background: palette.background.strong.color.into(), - bar: bar.into(), + let from_palette = |bar: cosmic_theme::Component<_>| progress_bar::Appearance { + background: Color::from(bar.base).into(), + bar: Color::from(bar.on).into(), border_radius: 2.0, }; match style { - ProgressBar::Primary => from_palette(palette.primary.base.color), - ProgressBar::Success => from_palette(palette.success.base.color), - ProgressBar::Danger => from_palette(palette.danger.base.color), + ProgressBar::Primary => from_palette(theme.basic.clone()), + ProgressBar::Success => from_palette(theme.success.clone()), + ProgressBar::Danger => from_palette(theme.destructive.clone()), ProgressBar::Custom(f) => f(self), } } @@ -668,11 +684,11 @@ impl rule::StyleSheet for Theme { type Style = Rule; fn appearance(&self, style: &Self::Style) -> rule::Appearance { - let palette = self.extended_palette(); + let palette = self.cosmic(); match style { Rule::Default => rule::Appearance { - color: palette.background.strong.color, + color: palette.on.into(), width: 1, radius: 0.0, fill_mode: rule::FillMode::Full, @@ -707,15 +723,15 @@ impl scrollable::StyleSheet for Theme { type Style = (); fn active(&self, _style: &Self::Style) -> scrollable::Scrollbar { - let palette = self.extended_palette(); + let theme = self.cosmic(); scrollable::Scrollbar { - background: palette.background.weak.color.into(), + background: Some(Background::Color(theme.basic.base.into())), border_radius: 4.0, border_width: 0.0, border_color: Color::TRANSPARENT, scroller: scrollable::Scroller { - color: palette.background.strong.color, + color: theme.divider.into(), border_radius: 4.0, border_width: 0.0, border_color: Color::TRANSPARENT, @@ -724,15 +740,15 @@ impl scrollable::StyleSheet for Theme { } fn hovered(&self, _style: &Self::Style) -> scrollable::Scrollbar { - let palette = self.extended_palette(); + let theme = self.cosmic(); scrollable::Scrollbar { - background: palette.background.weak.color.into(), + background: Some(Background::Color(theme.basic.base.into())), border_radius: 4.0, border_width: 0.0, border_color: Color::TRANSPARENT, scroller: scrollable::Scroller { - color: palette.primary.strong.color, + color: theme.accent.base.into(), border_radius: 4.0, border_width: 0.0, border_color: Color::TRANSPARENT, @@ -782,7 +798,7 @@ impl svg::StyleSheet for Theme { Svg::Default => svg::Appearance::default(), Svg::Custom(appearance) => appearance(self), Svg::Symbolic => svg::Appearance { - color: Some(self.extended_palette().background.base.text), + color: Some(self.cosmic().on.into()), }, Svg::SymbolicActive => svg::Appearance { color: Some(self.cosmic().accent.base.into()), @@ -844,14 +860,14 @@ impl text_input::StyleSheet for Theme { type Style = TextInput; fn active(&self, style: &Self::Style) -> text_input::Appearance { - let palette = self.extended_palette(); + let palette = self.cosmic(); match style { TextInput::Default => text_input::Appearance { - background: palette.background.base.color.into(), + background: Background::Color(palette.basic.base.into()), border_radius: 2.0, border_width: 1.0, - border_color: palette.background.strong.color, + border_color: palette.divider.into(), }, TextInput::Search => text_input::Appearance { background: Background::Color(Color::TRANSPARENT), @@ -863,14 +879,14 @@ impl text_input::StyleSheet for Theme { } fn hovered(&self, style: &Self::Style) -> text_input::Appearance { - let palette = self.extended_palette(); + let palette = self.cosmic(); match style { TextInput::Default => text_input::Appearance { - background: palette.background.base.color.into(), + background: Background::Color(palette.basic.base.into()), border_radius: 2.0, border_width: 1.0, - border_color: palette.background.base.text, + border_color: palette.on.into(), }, TextInput::Search => text_input::Appearance { background: Background::Color(Color::TRANSPARENT), @@ -882,14 +898,14 @@ impl text_input::StyleSheet for Theme { } fn focused(&self, style: &Self::Style) -> text_input::Appearance { - let palette = self.extended_palette(); + let palette = self.cosmic(); match style { TextInput::Default => text_input::Appearance { - background: palette.background.base.color.into(), + background: Background::Color(palette.basic.base.into()), border_radius: 2.0, border_width: 1.0, - border_color: palette.primary.strong.color, + border_color: palette.accent.base.into(), }, TextInput::Search => text_input::Appearance { background: Background::Color(Color::TRANSPARENT), @@ -901,20 +917,20 @@ impl text_input::StyleSheet for Theme { } fn placeholder_color(&self, _style: &Self::Style) -> Color { - let palette = self.extended_palette(); + let palette = self.cosmic(); - palette.background.strong.color + palette.divider.into() } fn value_color(&self, _style: &Self::Style) -> Color { - let palette = self.extended_palette(); + let palette = self.cosmic(); - palette.background.base.text + palette.on.into() } fn selection_color(&self, _style: &Self::Style) -> Color { - let palette = self.extended_palette(); + let palette = self.cosmic(); - palette.primary.weak.color + palette.basic.selected_text.into() } } diff --git a/src/theme/palette.rs b/src/theme/palette.rs deleted file mode 100644 index 6aca226..0000000 --- a/src/theme/palette.rs +++ /dev/null @@ -1,289 +0,0 @@ -// Copyright 2022 System76 -// SPDX-License-Identifier: MPL-2.0 - -//TODO: GET CORRECT PALETTE FROM COSMIC-THEME -use iced_core::Color; - -use lazy_static::lazy_static; -use palette::{FromColor, Hsl, Mix, RelativeContrast, Srgb}; - -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct Palette { - pub background: Color, - pub text: Color, - pub primary: Color, - pub success: Color, - pub danger: Color, -} - -impl Palette { - #[allow(clippy::cast_precision_loss)] - pub const LIGHT: Self = Self { - background: Color::from_rgb( - 0xee as f32 / 255.0, - 0xee as f32 / 255.0, - 0xee as f32 / 255.0, - ), - text: Color::from_rgb( - 0x00 as f32 / 255.0, - 0x00 as f32 / 255.0, - 0x00 as f32 / 255.0, - ), - primary: Color::from_rgb( - 0x00 as f32 / 255.0, - 0x49 as f32 / 255.0, - 0x6d as f32 / 255.0, - ), - success: Color::from_rgb( - 0x3b as f32 / 255.0, - 0x6e as f32 / 255.0, - 0x43 as f32 / 255.0, - ), - danger: Color::from_rgb( - 0xa0 as f32 / 255.0, - 0x25 as f32 / 255.0, - 0x2b as f32 / 255.0, - ), - }; - - #[allow(clippy::cast_precision_loss)] - pub const DARK: Self = Self { - background: Color::from_rgb( - 0x1e as f32 / 255.0, - 0x1e as f32 / 255.0, - 0x1e as f32 / 255.0, - ), - text: Color::from_rgb( - 0xe4 as f32 / 255.0, - 0xe4 as f32 / 255.0, - 0xe4 as f32 / 255.0, - ), - primary: Color::from_rgb( - 0x94 as f32 / 255.0, - 0xeb as f32 / 255.0, - 0xeb as f32 / 255.0, - ), - success: Color::from_rgb( - 0xac as f32 / 255.0, - 0xf7 as f32 / 255.0, - 0xd2 as f32 / 255.0, - ), - danger: Color::from_rgb( - 0xff as f32 / 255.0, - 0xb5 as f32 / 255.0, - 0xb5 as f32 / 255.0, - ), - }; -} - -pub struct Extended { - pub background: Background, - pub primary: Primary, - pub secondary: Secondary, - pub success: Success, - pub danger: Danger, -} - -lazy_static! { - pub static ref EXTENDED_LIGHT: Extended = Extended::generate(Palette::LIGHT); - pub static ref EXTENDED_DARK: Extended = Extended::generate(Palette::DARK); -} - -impl Extended { - #[must_use] - pub fn generate(palette: Palette) -> Self { - Self { - background: Background::new(palette.background, palette.text), - primary: Primary::generate(palette.primary, palette.background, palette.text), - secondary: Secondary::generate(palette.background, palette.text), - success: Success::generate(palette.success, palette.background, palette.text), - danger: Danger::generate(palette.danger, palette.background, palette.text), - } - } -} - -#[derive(Debug, Clone, Copy)] -pub struct Pair { - pub color: Color, - pub text: Color, -} - -impl Pair { - #[must_use] - pub fn new(color: Color, text: Color) -> Self { - Self { - color, - text: readable(color, text), - } - } -} - -pub struct Background { - pub base: Pair, - pub weak: Pair, - pub strong: Pair, -} - -impl Background { - #[must_use] - pub fn new(base: Color, text: Color) -> Self { - let weak = mix(base, text, 0.15); - let strong = mix(base, text, 0.40); - - Self { - base: Pair::new(base, text), - weak: Pair::new(weak, text), - strong: Pair::new(strong, text), - } - } -} - -pub struct Primary { - pub base: Pair, - pub weak: Pair, - pub strong: Pair, -} - -impl Primary { - #[must_use] - pub fn generate(base: Color, background: Color, text: Color) -> Self { - let weak = mix(base, background, 0.4); - let strong = deviate(base, 0.1); - - Self { - base: Pair::new(base, text), - weak: Pair::new(weak, text), - strong: Pair::new(strong, text), - } - } -} - -pub struct Secondary { - pub base: Pair, - pub weak: Pair, - pub strong: Pair, -} - -impl Secondary { - #[must_use] - pub fn generate(base: Color, text: Color) -> Self { - let base = mix(base, text, 0.2); - let weak = mix(base, text, 0.1); - let strong = mix(base, text, 0.3); - - Self { - base: Pair::new(base, text), - weak: Pair::new(weak, text), - strong: Pair::new(strong, text), - } - } -} - -pub struct Success { - pub base: Pair, - pub weak: Pair, - pub strong: Pair, -} - -impl Success { - #[must_use] - pub fn generate(base: Color, background: Color, text: Color) -> Self { - let weak = mix(base, background, 0.4); - let strong = deviate(base, 0.1); - - Self { - base: Pair::new(base, text), - weak: Pair::new(weak, text), - strong: Pair::new(strong, text), - } - } -} - -pub struct Danger { - pub base: Pair, - pub weak: Pair, - pub strong: Pair, -} - -impl Danger { - #[must_use] - pub fn generate(base: Color, background: Color, text: Color) -> Self { - let weak = mix(base, background, 0.4); - let strong = deviate(base, 0.1); - - Self { - base: Pair::new(base, text), - weak: Pair::new(weak, text), - strong: Pair::new(strong, text), - } - } -} - -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 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 deviate(color: Color, amount: f32) -> Color { - if is_dark(color) { - lighten(color, amount) - } else { - darken(color, amount) - } -} - -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 readable(background: Color, text: Color) -> Color { - if is_readable(background, text) { - text - } else if is_dark(background) { - Color::WHITE - } else { - Color::BLACK - } -} - -fn is_dark(color: Color) -> bool { - to_hsl(color).lightness < 0.6 -} - -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() -}