refactor(theme): make Theme Copy
This commit is contained in:
parent
3245ff1b0e
commit
844aeba379
4 changed files with 97 additions and 83 deletions
|
|
@ -25,7 +25,7 @@ mod bluetooth;
|
||||||
|
|
||||||
mod demo;
|
mod demo;
|
||||||
|
|
||||||
use self::{demo::ThemeMode, desktop::DesktopPage};
|
use self::desktop::DesktopPage;
|
||||||
mod desktop;
|
mod desktop;
|
||||||
|
|
||||||
mod editor;
|
mod editor;
|
||||||
|
|
@ -176,7 +176,7 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum Message {
|
pub enum Message {
|
||||||
Bluetooth(bluetooth::Message),
|
Bluetooth(bluetooth::Message),
|
||||||
Close,
|
Close,
|
||||||
|
|
@ -390,10 +390,9 @@ impl Application for Window {
|
||||||
Message::Demo(message) => match self.demo.update(message) {
|
Message::Demo(message) => match self.demo.update(message) {
|
||||||
Some(demo::Output::Debug(debug)) => self.debug = debug,
|
Some(demo::Output::Debug(debug)) => self.debug = debug,
|
||||||
Some(demo::Output::ScalingFactor(factor)) => self.set_scale_factor(factor),
|
Some(demo::Output::ScalingFactor(factor)) => self.set_scale_factor(factor),
|
||||||
Some(demo::Output::ThemeChanged(theme)) => match theme {
|
Some(demo::Output::ThemeChanged(theme)) => {
|
||||||
ThemeMode::Light => self.theme = Theme::light(),
|
self.theme = theme;
|
||||||
ThemeMode::Dark => self.theme = Theme::dark(),
|
}
|
||||||
},
|
|
||||||
Some(demo::Output::ToggleWarning) => self.toggle_warning(),
|
Some(demo::Output::ToggleWarning) => self.toggle_warning(),
|
||||||
None => (),
|
None => (),
|
||||||
},
|
},
|
||||||
|
|
@ -568,6 +567,6 @@ impl Application for Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn theme(&self) -> Theme {
|
fn theme(&self) -> Theme {
|
||||||
self.theme.clone()
|
self.theme
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,13 +29,7 @@ pub enum MultiOption {
|
||||||
OptionE,
|
OptionE,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum ThemeMode {
|
|
||||||
Light,
|
|
||||||
Dark,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum Message {
|
pub enum Message {
|
||||||
ButtonPressed,
|
ButtonPressed,
|
||||||
CheckboxToggled(bool),
|
CheckboxToggled(bool),
|
||||||
|
|
@ -48,7 +42,7 @@ pub enum Message {
|
||||||
Selection(segmented_button::Entity),
|
Selection(segmented_button::Entity),
|
||||||
SliderChanged(f32),
|
SliderChanged(f32),
|
||||||
SpinButton(spin_button::Message),
|
SpinButton(spin_button::Message),
|
||||||
ThemeChanged(ThemeMode),
|
ThemeChanged(Theme),
|
||||||
ToggleWarning,
|
ToggleWarning,
|
||||||
TogglerToggled(bool),
|
TogglerToggled(bool),
|
||||||
ViewSwitcher(segmented_button::Entity),
|
ViewSwitcher(segmented_button::Entity),
|
||||||
|
|
@ -57,7 +51,7 @@ pub enum Message {
|
||||||
pub enum Output {
|
pub enum Output {
|
||||||
Debug(bool),
|
Debug(bool),
|
||||||
ScalingFactor(f32),
|
ScalingFactor(f32),
|
||||||
ThemeChanged(ThemeMode),
|
ThemeChanged(Theme),
|
||||||
ToggleWarning,
|
ToggleWarning,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -148,15 +142,20 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn view<'a>(&'a self, window: &'a Window) -> Element<'a, Message> {
|
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![].spacing(10).align_items(Alignment::Center),
|
||||||
|row, theme| {
|
|row, theme| {
|
||||||
row.push(radio(
|
row.push(radio(
|
||||||
format!("{:?}", theme),
|
format!("{:?}", theme.theme_type),
|
||||||
*theme,
|
*theme,
|
||||||
if window.theme.cosmic().is_dark && matches!(theme, ThemeMode::Dark)
|
if window.theme == *theme {
|
||||||
|| !window.theme.cosmic().is_dark && matches!(theme, ThemeMode::Light)
|
|
||||||
{
|
|
||||||
Some(*theme)
|
Some(*theme)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
|
||||||
137
src/theme/mod.rs
137
src/theme/mod.rs
|
|
@ -39,7 +39,9 @@ type CosmicThemeCss = cosmic_theme::Theme<cosmic_theme::util::CssColor>;
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
pub static ref COSMIC_DARK: CosmicTheme = CosmicThemeCss::dark_default().into_srgba();
|
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_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 {
|
pub static ref TRANSPARENT_COMPONENT: Component<CosmicColor> = Component {
|
||||||
base: CosmicColor::new(0.0, 0.0, 0.0, 0.0),
|
base: CosmicColor::new(0.0, 0.0, 0.0, 0.0),
|
||||||
hover: 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)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
|
||||||
pub struct Theme {
|
pub enum ThemeType {
|
||||||
pub cosmic: cosmic_theme::Theme<Srgba>,
|
#[default]
|
||||||
|
Dark,
|
||||||
|
Light,
|
||||||
|
HighContrastDark,
|
||||||
|
HighContrastLight,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Theme {
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
|
||||||
fn default() -> Self {
|
pub struct Theme {
|
||||||
Self::dark()
|
pub theme_type: ThemeType,
|
||||||
}
|
pub layer: cosmic_theme::Layer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Theme {
|
impl Theme {
|
||||||
#[must_use]
|
|
||||||
pub fn new(cosmic: cosmic_theme::Theme<Srgba>) -> Self {
|
|
||||||
Self { cosmic }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn cosmic(&self) -> &cosmic_theme::Theme<Srgba> {
|
pub fn cosmic(&self) -> &cosmic_theme::Theme<Srgba> {
|
||||||
&self.cosmic
|
match self.theme_type {
|
||||||
}
|
ThemeType::Dark => &COSMIC_DARK,
|
||||||
|
ThemeType::Light => &COSMIC_LIGHT,
|
||||||
pub fn cosmic_mut(&mut self) -> &mut cosmic_theme::Theme<Srgba> {
|
ThemeType::HighContrastDark => &COSMIC_HC_DARK,
|
||||||
&mut self.cosmic
|
ThemeType::HighContrastLight => &COSMIC_HC_LIGHT,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_cosmic(&mut self, cosmic: cosmic_theme::Theme<Srgba>) {
|
|
||||||
self.cosmic = cosmic;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn dark() -> Self {
|
pub fn dark() -> Self {
|
||||||
Self {
|
Self {
|
||||||
cosmic: COSMIC_DARK.clone(),
|
theme_type: ThemeType::Dark,
|
||||||
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn light() -> Self {
|
pub fn light() -> Self {
|
||||||
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 {
|
impl LayeredTheme for Theme {
|
||||||
fn set_layer(&mut self, layer: cosmic_theme::Layer) {
|
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();
|
let cosmic = theme.cosmic();
|
||||||
match self {
|
match self {
|
||||||
Button::Primary => &cosmic.accent,
|
Button::Primary => &cosmic.accent,
|
||||||
Button::Secondary => &cosmic.current_container().component,
|
Button::Secondary => &theme.current_container().component,
|
||||||
Button::Positive => &cosmic.success,
|
Button::Positive => &cosmic.success,
|
||||||
Button::Destructive => &cosmic.destructive,
|
Button::Destructive => &cosmic.destructive,
|
||||||
Button::Text => &cosmic.current_container().component,
|
Button::Text => &theme.current_container().component,
|
||||||
Button::Link => &cosmic.accent,
|
Button::Link => &cosmic.accent,
|
||||||
Button::LinkActive => &cosmic.accent,
|
Button::LinkActive => &cosmic.accent,
|
||||||
Button::Transparent => &TRANSPARENT_COMPONENT,
|
Button::Transparent => &TRANSPARENT_COMPONENT,
|
||||||
Button::Deactivated => &cosmic.current_container().component,
|
Button::Deactivated => &theme.current_container().component,
|
||||||
Button::Custom { .. } => &TRANSPARENT_COMPONENT,
|
Button::Custom { .. } => &TRANSPARENT_COMPONENT,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -359,15 +386,15 @@ impl checkbox::StyleSheet for Theme {
|
||||||
},
|
},
|
||||||
Checkbox::Secondary => checkbox::Appearance {
|
Checkbox::Secondary => checkbox::Appearance {
|
||||||
background: Background::Color(if is_checked {
|
background: Background::Color(if is_checked {
|
||||||
palette.current_container().base.into()
|
self.current_container().base.into()
|
||||||
} else {
|
} else {
|
||||||
neutral_10.into()
|
neutral_10.into()
|
||||||
}),
|
}),
|
||||||
checkmark_color: palette.current_container().on.into(),
|
checkmark_color: self.current_container().on.into(),
|
||||||
border_radius: 4.0,
|
border_radius: 4.0,
|
||||||
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.current_container().base
|
self.current_container().base
|
||||||
} else {
|
} else {
|
||||||
neutral_7
|
neutral_7
|
||||||
}
|
}
|
||||||
|
|
@ -538,7 +565,7 @@ impl slider::StyleSheet for Theme {
|
||||||
let mut style = self.active(style);
|
let mut style = self.active(style);
|
||||||
style.handle.shape = slider::HandleShape::Circle { radius: 16.0 };
|
style.handle.shape = slider::HandleShape::Circle { radius: 16.0 };
|
||||||
style.handle.border_width = 6.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;
|
border_color.alpha = 0.1;
|
||||||
style.handle.border_color = border_color.into();
|
style.handle.border_color = border_color.into();
|
||||||
style
|
style
|
||||||
|
|
@ -546,7 +573,7 @@ impl slider::StyleSheet for Theme {
|
||||||
|
|
||||||
fn dragging(&self, style: &Self::Style) -> slider::Appearance {
|
fn dragging(&self, style: &Self::Style) -> slider::Appearance {
|
||||||
let mut style = self.hovered(style);
|
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;
|
border_color.alpha = 0.2;
|
||||||
style.handle.border_color = border_color.into();
|
style.handle.border_color = border_color.into();
|
||||||
|
|
||||||
|
|
@ -789,33 +816,25 @@ impl rule::StyleSheet for Theme {
|
||||||
type Style = Rule;
|
type Style = Rule;
|
||||||
|
|
||||||
fn appearance(&self, style: &Self::Style) -> rule::Appearance {
|
fn appearance(&self, style: &Self::Style) -> rule::Appearance {
|
||||||
let palette = self.cosmic();
|
|
||||||
|
|
||||||
match style {
|
match style {
|
||||||
Rule::Default => rule::Appearance {
|
Rule::Default => rule::Appearance {
|
||||||
color: palette.current_container().divider.into(),
|
color: self.current_container().divider.into(),
|
||||||
width: 1,
|
width: 1,
|
||||||
radius: 0.0,
|
radius: 0.0,
|
||||||
fill_mode: rule::FillMode::Full,
|
fill_mode: rule::FillMode::Full,
|
||||||
},
|
},
|
||||||
Rule::LightDivider => {
|
Rule::LightDivider => rule::Appearance {
|
||||||
let cosmic = &self.cosmic();
|
color: self.current_container().divider.into(),
|
||||||
rule::Appearance {
|
width: 1,
|
||||||
color: cosmic.current_container().divider.into(),
|
radius: 0.0,
|
||||||
width: 1,
|
fill_mode: rule::FillMode::Padded(10),
|
||||||
radius: 0.0,
|
},
|
||||||
fill_mode: rule::FillMode::Padded(10),
|
Rule::HeavyDivider => rule::Appearance {
|
||||||
}
|
color: self.current_container().divider.into(),
|
||||||
}
|
width: 4,
|
||||||
Rule::HeavyDivider => {
|
radius: 4.0,
|
||||||
let cosmic = &self.cosmic();
|
fill_mode: rule::FillMode::Full,
|
||||||
rule::Appearance {
|
},
|
||||||
color: cosmic.current_container().divider.into(),
|
|
||||||
width: 4,
|
|
||||||
radius: 4.0,
|
|
||||||
fill_mode: rule::FillMode::Full,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Rule::Custom(f) => f(self),
|
Rule::Custom(f) => f(self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -828,17 +847,15 @@ impl scrollable::StyleSheet for Theme {
|
||||||
type Style = ();
|
type Style = ();
|
||||||
|
|
||||||
fn active(&self, _style: &Self::Style) -> scrollable::Scrollbar {
|
fn active(&self, _style: &Self::Style) -> scrollable::Scrollbar {
|
||||||
let theme = self.cosmic();
|
|
||||||
|
|
||||||
scrollable::Scrollbar {
|
scrollable::Scrollbar {
|
||||||
background: Some(Background::Color(
|
background: Some(Background::Color(
|
||||||
theme.current_container().component.base.into(),
|
self.current_container().component.base.into(),
|
||||||
)),
|
)),
|
||||||
border_radius: 4.0,
|
border_radius: 4.0,
|
||||||
border_width: 0.0,
|
border_width: 0.0,
|
||||||
border_color: Color::TRANSPARENT,
|
border_color: Color::TRANSPARENT,
|
||||||
scroller: scrollable::Scroller {
|
scroller: scrollable::Scroller {
|
||||||
color: theme.current_container().component.divider.into(),
|
color: self.current_container().component.divider.into(),
|
||||||
border_radius: 4.0,
|
border_radius: 4.0,
|
||||||
border_width: 0.0,
|
border_width: 0.0,
|
||||||
border_color: Color::TRANSPARENT,
|
border_color: Color::TRANSPARENT,
|
||||||
|
|
@ -851,7 +868,7 @@ impl scrollable::StyleSheet for Theme {
|
||||||
|
|
||||||
scrollable::Scrollbar {
|
scrollable::Scrollbar {
|
||||||
background: Some(Background::Color(
|
background: Some(Background::Color(
|
||||||
theme.current_container().component.hover.into(),
|
self.current_container().component.hover.into(),
|
||||||
)),
|
)),
|
||||||
border_radius: 4.0,
|
border_radius: 4.0,
|
||||||
border_width: 0.0,
|
border_width: 0.0,
|
||||||
|
|
@ -907,7 +924,7 @@ impl svg::StyleSheet for Theme {
|
||||||
Svg::Default => svg::Appearance::default(),
|
Svg::Default => svg::Appearance::default(),
|
||||||
Svg::Custom(appearance) => appearance(self),
|
Svg::Custom(appearance) => appearance(self),
|
||||||
Svg::Symbolic => svg::Appearance {
|
Svg::Symbolic => svg::Appearance {
|
||||||
color: Some(self.cosmic().current_container().on.into()),
|
color: Some(self.current_container().on.into()),
|
||||||
},
|
},
|
||||||
Svg::SymbolicActive => svg::Appearance {
|
Svg::SymbolicActive => svg::Appearance {
|
||||||
color: Some(self.cosmic().accent.base.into()),
|
color: Some(self.cosmic().accent.base.into()),
|
||||||
|
|
@ -977,7 +994,7 @@ impl text_input::StyleSheet for Theme {
|
||||||
background: Color::from(bg).into(),
|
background: Color::from(bg).into(),
|
||||||
border_radius: 2.0,
|
border_radius: 2.0,
|
||||||
border_width: 1.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 {
|
TextInput::Search => text_input::Appearance {
|
||||||
background: Color::from(bg).into(),
|
background: Color::from(bg).into(),
|
||||||
|
|
|
||||||
|
|
@ -59,8 +59,7 @@ impl<'a, Message: 'static> From<ListColumn<'a, Message>> for Element<'a, Message
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
#[allow(clippy::trivially_copy_pass_by_ref)]
|
||||||
pub fn style(theme: &crate::Theme) -> iced::widget::container::Appearance {
|
pub fn style(theme: &crate::Theme) -> iced::widget::container::Appearance {
|
||||||
let cosmic = &theme.cosmic();
|
let container = &theme.current_container().component;
|
||||||
let container = &cosmic.current_container().component;
|
|
||||||
iced::widget::container::Appearance {
|
iced::widget::container::Appearance {
|
||||||
text_color: Some(container.on.into()),
|
text_color: Some(container.on.into()),
|
||||||
background: Some(Background::Color(container.base.into())),
|
background: Some(Background::Color(container.base.into())),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue