diff --git a/examples/cosmic/src/window.rs b/examples/cosmic/src/window.rs index 672f8e68..e1175bab 100644 --- a/examples/cosmic/src/window.rs +++ b/examples/cosmic/src/window.rs @@ -25,7 +25,7 @@ mod bluetooth; mod demo; -use self::{demo::ThemeMode, desktop::DesktopPage}; +use self::desktop::DesktopPage; mod desktop; mod editor; @@ -176,7 +176,7 @@ impl Window { } #[allow(dead_code)] -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] pub enum Message { Bluetooth(bluetooth::Message), Close, @@ -390,10 +390,9 @@ impl Application for Window { Message::Demo(message) => match self.demo.update(message) { Some(demo::Output::Debug(debug)) => self.debug = debug, Some(demo::Output::ScalingFactor(factor)) => self.set_scale_factor(factor), - Some(demo::Output::ThemeChanged(theme)) => match theme { - ThemeMode::Light => self.theme = Theme::light(), - ThemeMode::Dark => self.theme = Theme::dark(), - }, + Some(demo::Output::ThemeChanged(theme)) => { + self.theme = theme; + } Some(demo::Output::ToggleWarning) => self.toggle_warning(), None => (), }, @@ -568,6 +567,6 @@ impl Application for Window { } fn theme(&self) -> Theme { - self.theme.clone() + self.theme } } diff --git a/examples/cosmic/src/window/demo.rs b/examples/cosmic/src/window/demo.rs index 2f8f6f00..6af7eca8 100644 --- a/examples/cosmic/src/window/demo.rs +++ b/examples/cosmic/src/window/demo.rs @@ -29,13 +29,7 @@ pub enum MultiOption { OptionE, } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum ThemeMode { - Light, - Dark, -} - -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] pub enum Message { ButtonPressed, CheckboxToggled(bool), @@ -48,7 +42,7 @@ pub enum Message { Selection(segmented_button::Entity), SliderChanged(f32), SpinButton(spin_button::Message), - ThemeChanged(ThemeMode), + ThemeChanged(Theme), ToggleWarning, TogglerToggled(bool), ViewSwitcher(segmented_button::Entity), @@ -57,7 +51,7 @@ pub enum Message { pub enum Output { Debug(bool), ScalingFactor(f32), - ThemeChanged(ThemeMode), + ThemeChanged(Theme), ToggleWarning, } @@ -148,15 +142,20 @@ impl State { } pub(super) fn view<'a>(&'a self, window: &'a Window) -> Element<'a, Message> { - let choose_theme = [ThemeMode::Light, ThemeMode::Dark].iter().fold( + let choose_theme = [ + Theme::light(), + Theme::dark(), + Theme::light_hc(), + Theme::dark_hc(), + ] + .iter() + .fold( row![].spacing(10).align_items(Alignment::Center), |row, theme| { row.push(radio( - format!("{:?}", theme), + format!("{:?}", theme.theme_type), *theme, - if window.theme.cosmic().is_dark && matches!(theme, ThemeMode::Dark) - || !window.theme.cosmic().is_dark && matches!(theme, ThemeMode::Light) - { + if window.theme == *theme { Some(*theme) } else { None diff --git a/src/theme/mod.rs b/src/theme/mod.rs index be9294c2..0631499e 100644 --- a/src/theme/mod.rs +++ b/src/theme/mod.rs @@ -39,7 +39,9 @@ type CosmicThemeCss = cosmic_theme::Theme; lazy_static::lazy_static! { pub static ref COSMIC_DARK: CosmicTheme = CosmicThemeCss::dark_default().into_srgba(); + pub static ref COSMIC_HC_DARK: CosmicTheme = CosmicThemeCss::high_contrast_dark_default().into_srgba(); pub static ref COSMIC_LIGHT: CosmicTheme = CosmicThemeCss::light_default().into_srgba(); + pub static ref COSMIC_HC_LIGHT: CosmicTheme = CosmicThemeCss::high_contrast_light_default().into_srgba(); pub static ref TRANSPARENT_COMPONENT: Component = Component { base: CosmicColor::new(0.0, 0.0, 0.0, 0.0), hover: CosmicColor::new(0.0, 0.0, 0.0, 0.0), @@ -54,54 +56,79 @@ lazy_static::lazy_static! { }; } -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Theme { - pub cosmic: cosmic_theme::Theme, +#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)] +pub enum ThemeType { + #[default] + Dark, + Light, + HighContrastDark, + HighContrastLight, } -impl Default for Theme { - fn default() -> Self { - Self::dark() - } +#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)] +pub struct Theme { + pub theme_type: ThemeType, + pub layer: cosmic_theme::Layer, } impl Theme { - #[must_use] - pub fn new(cosmic: cosmic_theme::Theme) -> Self { - Self { cosmic } - } - #[must_use] pub fn cosmic(&self) -> &cosmic_theme::Theme { - &self.cosmic - } - - pub fn cosmic_mut(&mut self) -> &mut cosmic_theme::Theme { - &mut self.cosmic - } - - pub fn set_cosmic(&mut self, cosmic: cosmic_theme::Theme) { - self.cosmic = cosmic; + match self.theme_type { + ThemeType::Dark => &COSMIC_DARK, + ThemeType::Light => &COSMIC_LIGHT, + ThemeType::HighContrastDark => &COSMIC_HC_DARK, + ThemeType::HighContrastLight => &COSMIC_HC_LIGHT, + } } #[must_use] pub fn dark() -> Self { Self { - cosmic: COSMIC_DARK.clone(), + theme_type: ThemeType::Dark, + ..Default::default() } } #[must_use] pub fn light() -> Self { Self { - cosmic: COSMIC_LIGHT.clone(), + theme_type: ThemeType::Light, + ..Default::default() + } + } + + #[must_use] + pub fn dark_hc() -> Self { + Self { + theme_type: ThemeType::HighContrastDark, + ..Default::default() + } + } + + #[must_use] + pub fn light_hc() -> Self { + Self { + theme_type: ThemeType::HighContrastLight, + ..Default::default() + } + } + + /// get current container + /// can be used in a component that is intended to be a child of a `CosmicContainer` + #[must_use] + pub fn current_container(&self) -> &cosmic_theme::Container { + match self.layer { + cosmic_theme::Layer::Background => &self.cosmic().background, + cosmic_theme::Layer::Primary => &self.cosmic().primary, + cosmic_theme::Layer::Secondary => &self.cosmic().secondary, } } } impl LayeredTheme for Theme { fn set_layer(&mut self, layer: cosmic_theme::Layer) { - self.cosmic.layer = layer; + self.layer = layer; } } @@ -166,14 +193,14 @@ impl Button { let cosmic = theme.cosmic(); match self { Button::Primary => &cosmic.accent, - Button::Secondary => &cosmic.current_container().component, + Button::Secondary => &theme.current_container().component, Button::Positive => &cosmic.success, Button::Destructive => &cosmic.destructive, - Button::Text => &cosmic.current_container().component, + Button::Text => &theme.current_container().component, Button::Link => &cosmic.accent, Button::LinkActive => &cosmic.accent, Button::Transparent => &TRANSPARENT_COMPONENT, - Button::Deactivated => &cosmic.current_container().component, + Button::Deactivated => &theme.current_container().component, Button::Custom { .. } => &TRANSPARENT_COMPONENT, } } @@ -359,15 +386,15 @@ impl checkbox::StyleSheet for Theme { }, Checkbox::Secondary => checkbox::Appearance { background: Background::Color(if is_checked { - palette.current_container().base.into() + self.current_container().base.into() } else { neutral_10.into() }), - checkmark_color: palette.current_container().on.into(), + checkmark_color: self.current_container().on.into(), border_radius: 4.0, border_width: if is_checked { 0.0 } else { 1.0 }, border_color: if is_checked { - palette.current_container().base + self.current_container().base } else { neutral_7 } @@ -538,7 +565,7 @@ impl slider::StyleSheet for Theme { let mut style = self.active(style); style.handle.shape = slider::HandleShape::Circle { radius: 16.0 }; style.handle.border_width = 6.0; - let mut border_color = self.cosmic.palette.neutral_10; + let mut border_color = self.cosmic().palette.neutral_10; border_color.alpha = 0.1; style.handle.border_color = border_color.into(); style @@ -546,7 +573,7 @@ impl slider::StyleSheet for Theme { fn dragging(&self, style: &Self::Style) -> slider::Appearance { let mut style = self.hovered(style); - let mut border_color = self.cosmic.palette.neutral_10; + let mut border_color = self.cosmic().palette.neutral_10; border_color.alpha = 0.2; style.handle.border_color = border_color.into(); @@ -789,33 +816,25 @@ impl rule::StyleSheet for Theme { type Style = Rule; fn appearance(&self, style: &Self::Style) -> rule::Appearance { - let palette = self.cosmic(); - match style { Rule::Default => rule::Appearance { - color: palette.current_container().divider.into(), + color: self.current_container().divider.into(), width: 1, radius: 0.0, fill_mode: rule::FillMode::Full, }, - Rule::LightDivider => { - let cosmic = &self.cosmic(); - rule::Appearance { - color: cosmic.current_container().divider.into(), - width: 1, - radius: 0.0, - fill_mode: rule::FillMode::Padded(10), - } - } - Rule::HeavyDivider => { - let cosmic = &self.cosmic(); - rule::Appearance { - color: cosmic.current_container().divider.into(), - width: 4, - radius: 4.0, - fill_mode: rule::FillMode::Full, - } - } + Rule::LightDivider => rule::Appearance { + color: self.current_container().divider.into(), + width: 1, + radius: 0.0, + fill_mode: rule::FillMode::Padded(10), + }, + Rule::HeavyDivider => rule::Appearance { + color: self.current_container().divider.into(), + width: 4, + radius: 4.0, + fill_mode: rule::FillMode::Full, + }, Rule::Custom(f) => f(self), } } @@ -828,17 +847,15 @@ impl scrollable::StyleSheet for Theme { type Style = (); fn active(&self, _style: &Self::Style) -> scrollable::Scrollbar { - let theme = self.cosmic(); - scrollable::Scrollbar { background: Some(Background::Color( - theme.current_container().component.base.into(), + self.current_container().component.base.into(), )), border_radius: 4.0, border_width: 0.0, border_color: Color::TRANSPARENT, scroller: scrollable::Scroller { - color: theme.current_container().component.divider.into(), + color: self.current_container().component.divider.into(), border_radius: 4.0, border_width: 0.0, border_color: Color::TRANSPARENT, @@ -851,7 +868,7 @@ impl scrollable::StyleSheet for Theme { scrollable::Scrollbar { background: Some(Background::Color( - theme.current_container().component.hover.into(), + self.current_container().component.hover.into(), )), border_radius: 4.0, border_width: 0.0, @@ -907,7 +924,7 @@ impl svg::StyleSheet for Theme { Svg::Default => svg::Appearance::default(), Svg::Custom(appearance) => appearance(self), Svg::Symbolic => svg::Appearance { - color: Some(self.cosmic().current_container().on.into()), + color: Some(self.current_container().on.into()), }, Svg::SymbolicActive => svg::Appearance { color: Some(self.cosmic().accent.base.into()), @@ -977,7 +994,7 @@ impl text_input::StyleSheet for Theme { background: Color::from(bg).into(), border_radius: 2.0, border_width: 1.0, - border_color: palette.current_container().component.divider.into(), + border_color: self.current_container().component.divider.into(), }, TextInput::Search => text_input::Appearance { background: Color::from(bg).into(), diff --git a/src/widget/list/column.rs b/src/widget/list/column.rs index 308220c2..9a6e8144 100644 --- a/src/widget/list/column.rs +++ b/src/widget/list/column.rs @@ -59,8 +59,7 @@ impl<'a, Message: 'static> From> for Element<'a, Message #[must_use] #[allow(clippy::trivially_copy_pass_by_ref)] pub fn style(theme: &crate::Theme) -> iced::widget::container::Appearance { - let cosmic = &theme.cosmic(); - let container = &cosmic.current_container().component; + let container = &theme.current_container().component; iced::widget::container::Appearance { text_color: Some(container.on.into()), background: Some(Background::Color(container.base.into())),