refactor: updates for buttons and checkboxes

This commit is contained in:
Ashley Wulber 2023-08-07 13:48:01 -04:00 committed by Ashley Wulber
parent dae262f466
commit ff83f893ef
4 changed files with 159 additions and 114 deletions

View file

@ -70,6 +70,10 @@ pub struct Component<C> {
pub disabled: C, pub disabled: C,
/// the color of text in the widget when it is disabled /// the color of text in the widget when it is disabled
pub on_disabled: C, pub on_disabled: C,
/// the color of the border for the widget
pub border: C,
/// the color of the border for the widget when it is disabled
pub disabled_border: C,
} }
impl<C> Component<C> impl<C> Component<C>
@ -109,6 +113,8 @@ where
on: self.on.into(), on: self.on.into(),
disabled: self.disabled.into(), disabled: self.disabled.into(),
on_disabled: self.on_disabled.into(), on_disabled: self.on_disabled.into(),
border: self.border.into(),
disabled_border: self.disabled_border.into(),
} }
} }
@ -124,7 +130,7 @@ where
let base: Srgba = base.into(); let base: Srgba = base.into();
let mut base_50 = base.clone(); let mut base_50 = base.clone();
base_50.alpha = 0.5; base_50.alpha *= 0.5;
let on_20 = neutral.clone(); let on_20 = neutral.clone();
let mut on_50 = on_20.clone(); let mut on_50 = on_20.clone();
@ -142,6 +148,8 @@ where
disabled: base_50.into(), disabled: base_50.into(),
on_disabled: on_50.into(), on_disabled: on_50.into(),
focus: accent, focus: accent,
border: base.into(),
disabled_border: base_50.into(),
} }
} }
@ -152,6 +160,7 @@ where
accent: C, accent: C,
on_component: C, on_component: C,
is_high_contrast: bool, is_high_contrast: bool,
border: C,
) -> Self { ) -> Self {
let component_state_overlay = component_state_overlay.clone().into(); let component_state_overlay = component_state_overlay.clone().into();
let mut component_state_overlay_10 = component_state_overlay.clone(); let mut component_state_overlay_10 = component_state_overlay.clone();
@ -161,7 +170,7 @@ where
let base = base.into(); let base = base.into();
let mut base_50 = base.clone(); let mut base_50 = base.clone();
base_50.alpha = 0.5; base_50.alpha *= 0.5;
let mut on_20 = on_component.clone().into(); let mut on_20 = on_component.clone().into();
let mut on_50 = on_20.clone(); let mut on_50 = on_20.clone();
@ -169,6 +178,10 @@ where
on_20.alpha = 0.2; on_20.alpha = 0.2;
on_50.alpha = 0.5; on_50.alpha = 0.5;
let border = border.into();
let mut disabled_border = border;
disabled_border.alpha *= 0.5;
Component { Component {
base: base.clone().into(), base: base.clone().into(),
hover: over(component_state_overlay_10, base).into(), hover: over(component_state_overlay_10, base).into(),
@ -184,6 +197,8 @@ where
on: on_component.clone(), on: on_component.clone(),
disabled: base_50.into(), disabled: base_50.into(),
on_disabled: on_50.into(), on_disabled: on_50.into(),
border: border.into(),
disabled_border: disabled_border.into(),
} }
} }
} }

View file

@ -4,8 +4,8 @@ use crate::{
}; };
use cosmic_config::{Config, ConfigGet, ConfigSet, CosmicConfigEntry}; use cosmic_config::{Config, ConfigGet, ConfigSet, CosmicConfigEntry};
use palette::{IntoColor, Srgb, Srgba}; use palette::{IntoColor, Srgb, Srgba};
use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{fmt, num::NonZeroUsize}; use std::num::NonZeroUsize;
#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq, Eq)] #[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
/// Theme layer type /// Theme layer type
@ -38,6 +38,8 @@ pub struct Theme<C> {
pub destructive: Component<C>, pub destructive: Component<C>,
/// warning element colors /// warning element colors
pub warning: Component<C>, pub warning: Component<C>,
/// button component styling
pub button: Component<C>,
/// palette /// palette
pub palette: CosmicPaletteInner<C>, pub palette: CosmicPaletteInner<C>,
/// spacing /// spacing
@ -162,10 +164,27 @@ impl<C> Theme<C> {
} }
} }
impl<C> Theme<C> impl Theme<Srgba> {
where /// get the built in light theme
C: Clone + fmt::Debug + Default + Into<Srgba> + From<Srgba> + Serialize + DeserializeOwned, pub fn light_default() -> Self {
{ LIGHT_PALETTE.clone().into()
}
/// get the built in dark theme
pub fn dark_default() -> Self {
DARK_PALETTE.clone().into()
}
/// get the built in high contrast dark theme
pub fn high_contrast_dark_default() -> Self {
CosmicPalette::HighContrastDark(DARK_PALETTE.as_ref().clone()).into()
}
/// get the built in high contrast light theme
pub fn high_contrast_light_default() -> Self {
CosmicPalette::HighContrastLight(LIGHT_PALETTE.as_ref().clone()).into()
}
/// Convert the theme to a high-contrast variant /// Convert the theme to a high-contrast variant
pub fn to_high_contrast(&self) -> Self { pub fn to_high_contrast(&self) -> Self {
todo!(); todo!();
@ -174,134 +193,142 @@ where
// TODO convenient getter functions for each named color variable // TODO convenient getter functions for each named color variable
/// get @accent_color /// get @accent_color
pub fn accent_color(&self) -> Srgba { pub fn accent_color(&self) -> Srgba {
self.accent.base.clone().into() self.accent.base.clone()
} }
/// get @success_color /// get @success_color
pub fn success_color(&self) -> Srgba { pub fn success_color(&self) -> Srgba {
self.success.base.clone().into() self.success.base.clone()
} }
/// get @destructive_color /// get @destructive_color
pub fn destructive_color(&self) -> Srgba { pub fn destructive_color(&self) -> Srgba {
self.destructive.base.clone().into() self.destructive.base.clone()
} }
/// get @warning_color /// get @warning_color
pub fn warning_color(&self) -> Srgba { pub fn warning_color(&self) -> Srgba {
self.warning.base.clone().into() self.warning.base.clone()
} }
// Containers // Containers
/// get @bg_color /// get @bg_color
pub fn bg_color(&self) -> Srgba { pub fn bg_color(&self) -> Srgba {
self.background.base.clone().into() self.background.base.clone()
} }
/// get @bg_component_color /// get @bg_component_color
pub fn bg_component_color(&self) -> Srgba { pub fn bg_component_color(&self) -> Srgba {
self.background.component.base.clone().into() self.background.component.base.clone()
} }
/// get @primary_container_color /// get @primary_container_color
pub fn primary_container_color(&self) -> Srgba { pub fn primary_container_color(&self) -> Srgba {
self.primary.base.clone().into() self.primary.base.clone()
} }
/// get @primary_component_color /// get @primary_component_color
pub fn primary_component_color(&self) -> Srgba { pub fn primary_component_color(&self) -> Srgba {
self.primary.component.base.clone().into() self.primary.component.base.clone()
} }
/// get @secondary_container_color /// get @secondary_container_color
pub fn secondary_container_color(&self) -> Srgba { pub fn secondary_container_color(&self) -> Srgba {
self.secondary.base.clone().into() self.secondary.base.clone()
} }
/// get @secondary_component_color /// get @secondary_component_color
pub fn secondary_component_color(&self) -> Srgba { pub fn secondary_component_color(&self) -> Srgba {
self.secondary.component.base.clone().into() self.secondary.component.base.clone()
}
/// get @button_bg_color
pub fn button_bg_color(&self) -> Srgba {
self.button.base.clone()
} }
// Text // Text
/// get @on_bg_color /// get @on_bg_color
pub fn on_bg_color(&self) -> Srgba { pub fn on_bg_color(&self) -> Srgba {
self.background.on.clone().into() self.background.on.clone()
} }
/// get @on_bg_component_color /// get @on_bg_component_color
pub fn on_bg_component_color(&self) -> Srgba { pub fn on_bg_component_color(&self) -> Srgba {
self.background.component.on.clone().into() self.background.component.on.clone()
} }
/// get @on_primary_color /// get @on_primary_color
pub fn on_primary_container_color(&self) -> Srgba { pub fn on_primary_container_color(&self) -> Srgba {
self.primary.on.clone().into() self.primary.on.clone()
} }
/// get @on_primary_component_color /// get @on_primary_component_color
pub fn on_primary_component_color(&self) -> Srgba { pub fn on_primary_component_color(&self) -> Srgba {
self.primary.component.on.clone().into() self.primary.component.on.clone()
} }
/// get @on_secondary_color /// get @on_secondary_color
pub fn on_secondary_container_color(&self) -> Srgba { pub fn on_secondary_container_color(&self) -> Srgba {
self.secondary.on.clone().into() self.secondary.on.clone()
} }
/// get @on_secondary_component_color /// get @on_secondary_component_color
pub fn on_secondary_component_color(&self) -> Srgba { pub fn on_secondary_component_color(&self) -> Srgba {
self.secondary.component.on.clone().into() self.secondary.component.on.clone()
} }
/// get @accent_text_color /// get @accent_text_color
pub fn accent_text_color(&self) -> Srgba { pub fn accent_text_color(&self) -> Srgba {
self.accent.base.clone().into() self.accent.base.clone()
} }
/// get @success_text_color /// get @success_text_color
pub fn success_text_color(&self) -> Srgba { pub fn success_text_color(&self) -> Srgba {
self.success.base.clone().into() self.success.base.clone()
} }
/// get @warning_text_color /// get @warning_text_color
pub fn warning_text_color(&self) -> Srgba { pub fn warning_text_color(&self) -> Srgba {
self.warning.base.clone().into() self.warning.base.clone()
} }
/// get @destructive_text_color /// get @destructive_text_color
pub fn destructive_text_color(&self) -> Srgba { pub fn destructive_text_color(&self) -> Srgba {
self.destructive.base.clone().into() self.destructive.base.clone()
} }
/// get @on_accent_color /// get @on_accent_color
pub fn on_accent_color(&self) -> Srgba { pub fn on_accent_color(&self) -> Srgba {
self.accent.on.clone().into() self.accent.on.clone()
} }
/// get @on_success_color /// get @on_success_color
pub fn on_success_color(&self) -> Srgba { pub fn on_success_color(&self) -> Srgba {
self.success.on.clone().into() self.success.on.clone()
} }
/// get @oon_warning_color /// get @oon_warning_color
pub fn on_warning_color(&self) -> Srgba { pub fn on_warning_color(&self) -> Srgba {
self.warning.on.clone().into() self.warning.on.clone()
} }
/// get @on_destructive_color /// get @on_destructive_color
pub fn on_destructive_color(&self) -> Srgba { pub fn on_destructive_color(&self) -> Srgba {
self.destructive.on.clone().into() self.destructive.on.clone()
}
/// get @button_color
pub fn button_color(&self) -> Srgba {
self.button.on.clone()
} }
// Borders and Dividers // Borders and Dividers
/// get @bg_divider /// get @bg_divider
pub fn bg_divider(&self) -> Srgba { pub fn bg_divider(&self) -> Srgba {
self.background.divider.clone().into() self.background.divider.clone()
} }
/// get @bg_component_divider /// get @bg_component_divider
pub fn bg_component_divider(&self) -> Srgba { pub fn bg_component_divider(&self) -> Srgba {
self.background.component.divider.clone().into() self.background.component.divider.clone()
} }
/// get @primary_container_divider /// get @primary_container_divider
pub fn primary_container_divider(&self) -> Srgba { pub fn primary_container_divider(&self) -> Srgba {
self.primary.divider.clone().into() self.primary.divider.clone()
} }
/// get @primary_component_divider /// get @primary_component_divider
pub fn primary_component_divider(&self) -> Srgba { pub fn primary_component_divider(&self) -> Srgba {
self.primary.component.divider.clone().into() self.primary.component.divider.clone()
} }
/// get @secondary_container_divider /// get @secondary_container_divider
pub fn secondary_container_divider(&self) -> Srgba { pub fn secondary_container_divider(&self) -> Srgba {
self.secondary.divider.clone().into() self.secondary.divider.clone()
} }
/// get @secondary_component_divider /// get @button_divider
pub fn secondary_component_divider(&self) -> Srgba { pub fn button_divider(&self) -> Srgba {
self.secondary.component.divider.clone().into() self.button.divider.clone()
} }
/// get @window_header_bg /// get @window_header_bg
pub fn window_header_bg(&self) -> Srgba { pub fn window_header_bg(&self) -> Srgba {
self.background.base.clone().into() self.background.base.clone()
} }
/// get @space_none /// get @space_none
@ -371,28 +398,6 @@ where
} }
} }
impl Theme<Srgba> {
/// get the built in light theme
pub fn light_default() -> Self {
LIGHT_PALETTE.clone().into()
}
/// get the built in dark theme
pub fn dark_default() -> Self {
DARK_PALETTE.clone().into()
}
/// get the built in high contrast dark theme
pub fn high_contrast_dark_default() -> Self {
CosmicPalette::HighContrastDark(DARK_PALETTE.as_ref().clone()).into()
}
/// get the built in high contrast light theme
pub fn high_contrast_light_default() -> Self {
CosmicPalette::HighContrastLight(LIGHT_PALETTE.as_ref().clone()).into()
}
}
impl<C> From<CosmicPalette<C>> for Theme<Srgba> impl<C> From<CosmicPalette<C>> for Theme<Srgba>
where where
CosmicPalette<C>: Into<CosmicPalette<Srgba>>, CosmicPalette<C>: Into<CosmicPalette<Srgba>>,
@ -643,6 +648,7 @@ impl ThemeBuilder {
accent.clone(), accent.clone(),
on_bg_component, on_bg_component,
is_high_contrast, is_high_contrast,
p_ref.neutral_8,
); );
let primary_index = color_index(primary_container_bg, step_array.len()); let primary_index = color_index(primary_container_bg, step_array.len());
@ -661,6 +667,7 @@ impl ThemeBuilder {
accent.clone(), accent.clone(),
on_primary_component, on_primary_component,
is_high_contrast, is_high_contrast,
p_ref.neutral_8,
); );
let secondary_index = color_index(secondary_container_bg, step_array.len()); let secondary_index = color_index(secondary_container_bg, step_array.len());
@ -679,7 +686,22 @@ impl ThemeBuilder {
accent.clone(), accent.clone(),
on_secondary_component, on_secondary_component,
is_high_contrast, is_high_contrast,
p_ref.neutral_8,
); );
let neutral_7 = p_ref.neutral_7;
let mut button_bg = neutral_7;
button_bg.alpha = 0.25;
let neutral_10 = p_ref.neutral_10;
let mut button_hover_overlay = neutral_10;
button_hover_overlay.alpha = 0.10;
let mut button_press_overlay = neutral_10;
button_press_overlay.alpha = 0.20;
let mut button_disabled_bg = button_bg;
button_disabled_bg.alpha *= 0.5;
let button_border = p_ref.neutral_8.clone();
let mut button_disabled_border = button_border;
button_disabled_border.alpha *= 0.5;
let mut theme: Theme<Srgba> = Theme { let mut theme: Theme<Srgba> = Theme {
name: palette.name().to_string(), name: palette.name().to_string(),
@ -736,6 +758,14 @@ impl ThemeBuilder {
p_ref.neutral_0.to_owned(), p_ref.neutral_0.to_owned(),
accent.clone(), accent.clone(),
), ),
button: Component::component(
button_bg,
p_ref.neutral_10,
accent,
p_ref.neutral_9,
is_high_contrast,
p_ref.neutral_8,
),
palette: palette.inner(), palette: palette.inner(),
spacing, spacing,
corner_radii, corner_radii,

View file

@ -492,7 +492,7 @@ impl State {
)) ))
.layer(cosmic::cosmic_theme::Layer::Secondary) .layer(cosmic::cosmic_theme::Layer::Secondary)
.padding(16) .padding(16)
.style(cosmic::theme::Container::Secondary) .style(cosmic::theme::Container::Background)
.into(), .into(),
text_input( text_input(
"Type to search apps or type “?” for more options...", "Type to search apps or type “?” for more options...",

View file

@ -62,6 +62,8 @@ lazy_static::lazy_static! {
on: CosmicColor::new(0.0, 0.0, 0.0, 0.0), on: CosmicColor::new(0.0, 0.0, 0.0, 0.0),
on_disabled: CosmicColor::new(0.0, 0.0, 0.0, 0.0), on_disabled: CosmicColor::new(0.0, 0.0, 0.0, 0.0),
divider: CosmicColor::new(0.0, 0.0, 0.0, 0.0), divider: CosmicColor::new(0.0, 0.0, 0.0, 0.0),
border: CosmicColor::new(0.0, 0.0, 0.0, 0.0),
disabled_border: CosmicColor::new(0.0, 0.0, 0.0, 0.0),
}; };
} }
@ -355,69 +357,69 @@ impl checkbox::StyleSheet for Theme {
type Style = Checkbox; type Style = Checkbox;
fn active(&self, style: &Self::Style, is_checked: bool) -> checkbox::Appearance { fn active(&self, style: &Self::Style, is_checked: bool) -> checkbox::Appearance {
let palette = self.cosmic(); let cosmic = self.cosmic();
let neutral_7 = palette.palette.neutral_10;
let corners = &cosmic.corner_radii;
match style { match style {
Checkbox::Primary => checkbox::Appearance { Checkbox::Primary => checkbox::Appearance {
background: Background::Color(if is_checked { background: Background::Color(if is_checked {
palette.accent.base.into() cosmic.accent.base.into()
} else { } else {
palette.background.base.into() cosmic.button.base.into()
}), }),
icon_color: palette.accent.on.into(), icon_color: cosmic.accent.on.into(),
border_radius: 4.0.into(), border_radius: corners.radius_xs.into(),
border_width: if is_checked { 0.0 } else { 1.0 }, border_width: if is_checked { 0.0 } else { 1.0 },
border_color: if is_checked { border_color: if is_checked {
palette.accent.base cosmic.accent.base
} else { } else {
neutral_7 cosmic.button.border
} }
.into(), .into(),
text_color: None, text_color: None,
}, },
Checkbox::Secondary => checkbox::Appearance { Checkbox::Secondary => checkbox::Appearance {
background: Background::Color(if is_checked { background: Background::Color(if is_checked {
palette.background.component.base.into() cosmic.background.component.base.into()
} else { } else {
palette.background.base.into() cosmic.background.base.into()
}), }),
icon_color: palette.background.on.into(), icon_color: cosmic.background.on.into(),
border_radius: 4.0.into(), border_radius: corners.radius_xs.into(),
border_width: if is_checked { 0.0 } else { 1.0 }, border_width: if is_checked { 0.0 } else { 1.0 },
border_color: neutral_7.into(), border_color: cosmic.button.border.into(),
text_color: None, text_color: None,
}, },
Checkbox::Success => checkbox::Appearance { Checkbox::Success => checkbox::Appearance {
background: Background::Color(if is_checked { background: Background::Color(if is_checked {
palette.success.base.into() cosmic.success.base.into()
} else { } else {
palette.background.base.into() cosmic.button.base.into()
}), }),
icon_color: palette.success.on.into(), icon_color: cosmic.success.on.into(),
border_radius: 4.0.into(), border_radius: corners.radius_xs.into(),
border_width: if is_checked { 0.0 } else { 1.0 }, border_width: if is_checked { 0.0 } else { 1.0 },
border_color: if is_checked { border_color: if is_checked {
palette.success.base cosmic.success.base
} else { } else {
neutral_7 cosmic.button.border
} }
.into(), .into(),
text_color: None, text_color: None,
}, },
Checkbox::Danger => checkbox::Appearance { Checkbox::Danger => checkbox::Appearance {
background: Background::Color(if is_checked { background: Background::Color(if is_checked {
palette.destructive.base.into() cosmic.destructive.base.into()
} else { } else {
palette.background.base.into() cosmic.button.base.into()
}), }),
icon_color: palette.destructive.on.into(), icon_color: cosmic.destructive.on.into(),
border_radius: 4.0.into(), border_radius: corners.radius_xs.into(),
border_width: if is_checked { 0.0 } else { 1.0 }, border_width: if is_checked { 0.0 } else { 1.0 },
border_color: if is_checked { border_color: if is_checked {
palette.destructive.base cosmic.destructive.base
} else { } else {
neutral_7 cosmic.button.border
} }
.into(), .into(),
text_color: None, text_color: None,
@ -426,25 +428,23 @@ impl checkbox::StyleSheet for Theme {
} }
fn hovered(&self, style: &Self::Style, is_checked: bool) -> checkbox::Appearance { fn hovered(&self, style: &Self::Style, is_checked: bool) -> checkbox::Appearance {
let palette = self.cosmic(); let cosmic = self.cosmic();
let mut neutral_10 = palette.palette.neutral_10; let corners = &cosmic.corner_radii;
let neutral_7 = palette.palette.neutral_10;
neutral_10.alpha = 0.1;
match style { match style {
Checkbox::Primary => checkbox::Appearance { Checkbox::Primary => checkbox::Appearance {
background: Background::Color(if is_checked { background: Background::Color(if is_checked {
palette.accent.base.into() cosmic.accent.base.into()
} else { } else {
neutral_10.into() cosmic.button.base.into()
}), }),
icon_color: palette.accent.on.into(), icon_color: cosmic.accent.on.into(),
border_radius: 4.0.into(), border_radius: corners.radius_xs.into(),
border_width: if is_checked { 0.0 } else { 1.0 }, border_width: if is_checked { 0.0 } else { 1.0 },
border_color: if is_checked { border_color: if is_checked {
palette.accent.base cosmic.accent.base
} else { } else {
neutral_7 cosmic.button.border
} }
.into(), .into(),
text_color: None, text_color: None,
@ -453,49 +453,49 @@ impl checkbox::StyleSheet for Theme {
background: Background::Color(if is_checked { background: Background::Color(if is_checked {
self.current_container().base.into() self.current_container().base.into()
} else { } else {
neutral_10.into() cosmic.button.base.into()
}), }),
icon_color: self.current_container().on.into(), icon_color: self.current_container().on.into(),
border_radius: 4.0.into(), border_radius: corners.radius_xs.into(),
border_width: if is_checked { 0.0 } else { 1.0 }, border_width: if is_checked { 0.0 } else { 1.0 },
border_color: if is_checked { border_color: if is_checked {
self.current_container().base self.current_container().base
} else { } else {
neutral_7 cosmic.button.border
} }
.into(), .into(),
text_color: None, text_color: None,
}, },
Checkbox::Success => checkbox::Appearance { Checkbox::Success => checkbox::Appearance {
background: Background::Color(if is_checked { background: Background::Color(if is_checked {
palette.success.base.into() cosmic.success.base.into()
} else { } else {
neutral_10.into() cosmic.button.base.into()
}), }),
icon_color: palette.success.on.into(), icon_color: cosmic.success.on.into(),
border_radius: 4.0.into(), border_radius: corners.radius_xs.into(),
border_width: if is_checked { 0.0 } else { 1.0 }, border_width: if is_checked { 0.0 } else { 1.0 },
border_color: if is_checked { border_color: if is_checked {
palette.success.base cosmic.success.base
} else { } else {
neutral_7 cosmic.button.border
} }
.into(), .into(),
text_color: None, text_color: None,
}, },
Checkbox::Danger => checkbox::Appearance { Checkbox::Danger => checkbox::Appearance {
background: Background::Color(if is_checked { background: Background::Color(if is_checked {
palette.destructive.base.into() cosmic.destructive.base.into()
} else { } else {
neutral_10.into() cosmic.button.base.into()
}), }),
icon_color: palette.destructive.on.into(), icon_color: cosmic.destructive.on.into(),
border_radius: 4.0.into(), border_radius: corners.radius_xs.into(),
border_width: if is_checked { 0.0 } else { 1.0 }, border_width: if is_checked { 0.0 } else { 1.0 },
border_color: if is_checked { border_color: if is_checked {
palette.destructive.base cosmic.destructive.base
} else { } else {
neutral_7 cosmic.button.border
} }
.into(), .into(),
text_color: None, text_color: None,