refactor(theme): make Theme Copy

This commit is contained in:
Ashley Wulber 2023-02-27 19:56:53 -05:00 committed by Jeremy Soller
parent 3245ff1b0e
commit 844aeba379
4 changed files with 97 additions and 83 deletions

View file

@ -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
}
}

View file

@ -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

View file

@ -39,7 +39,9 @@ type CosmicThemeCss = cosmic_theme::Theme<cosmic_theme::util::CssColor>;
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<CosmicColor> = 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<Srgba>,
#[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<Srgba>) -> Self {
Self { cosmic }
}
#[must_use]
pub fn cosmic(&self) -> &cosmic_theme::Theme<Srgba> {
&self.cosmic
}
pub fn cosmic_mut(&mut self) -> &mut cosmic_theme::Theme<Srgba> {
&mut self.cosmic
}
pub fn set_cosmic(&mut self, cosmic: cosmic_theme::Theme<Srgba>) {
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<Srgba> {
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(),

View file

@ -59,8 +59,7 @@ impl<'a, Message: 'static> From<ListColumn<'a, Message>> 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())),