From a618c1b94add2fa16a74c927ce56712732831106 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Thu, 3 Aug 2023 19:30:08 -0400 Subject: [PATCH] wip: calculate theme using new method --- Cargo.toml | 1 + cosmic-theme/src/model/derivation.rs | 297 +-------------------------- cosmic-theme/src/model/layout.rs | 5 + cosmic-theme/src/model/theme.rs | 253 +++++++++++++++++------ cosmic-theme/src/steps.rs | 80 ++++---- src/theme/mod.rs | 44 ++-- 6 files changed, 257 insertions(+), 423 deletions(-) create mode 100644 cosmic-theme/src/model/layout.rs diff --git a/Cargo.toml b/Cargo.toml index b0ad0d80..c8db8479 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -98,5 +98,6 @@ exclude = [ [patch."https://github.com/pop-os/libcosmic"] libcosmic = { path = "./", features = ["wayland", "tokio", "a11y"]} +# TODO Remove me when the palette crate gets an update & before merging [patch.crates-io] palette = {git = "https://github.com/Ogeon/palette", features = ["serializing"] } diff --git a/cosmic-theme/src/model/derivation.rs b/cosmic-theme/src/model/derivation.rs index 1868cdba..26b82ca9 100644 --- a/cosmic-theme/src/model/derivation.rs +++ b/cosmic-theme/src/model/derivation.rs @@ -2,7 +2,7 @@ use palette::Srgba; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use std::fmt; -use crate::{composite::over, CosmicPalette}; +use crate::composite::over; /// Theme Container colors of a theme, can be a theme background container, primary container, or secondary container #[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)] @@ -31,134 +31,20 @@ where } } - pub(crate) fn new( - palette: CosmicPalette, - container_type: ComponentType, - bg: C, - on_bg: C, - ) -> Self { + pub(crate) fn new(component: Component, bg: C, on_bg: C) -> Self { let mut divider_c: Srgba = on_bg.clone().into(); divider_c.alpha = 0.2; let divider = over(divider_c.clone(), bg.clone()); Self { base: bg, - component: (palette, container_type).into(), + component, divider: divider.into(), on: on_bg, } } } -impl From<(CosmicPalette, ContainerType)> for Container -where - C: Clone + fmt::Debug + Default + Into + From + Serialize + DeserializeOwned, -{ - fn from((p, t): (CosmicPalette, ContainerType)) -> Self { - match (p, t) { - (CosmicPalette::Dark(p), ContainerType::Background) => Self::new( - CosmicPalette::Dark(p.clone()), - ComponentType::Background, - p.gray_1.clone(), - p.neutral_7.clone(), - ), - (CosmicPalette::Dark(p), ContainerType::Primary) => Self::new( - CosmicPalette::Dark(p.clone()), - ComponentType::Primary, - p.gray_2.clone(), - p.neutral_8.clone(), - ), - (CosmicPalette::Dark(p), ContainerType::Secondary) => Self::new( - CosmicPalette::Dark(p.clone()), - ComponentType::Secondary, - p.gray_3.clone(), - p.neutral_8.clone(), - ), - (CosmicPalette::HighContrastDark(p), ContainerType::Background) => Self::new( - CosmicPalette::HighContrastDark(p.clone()), - ComponentType::Background, - p.gray_1.clone(), - p.neutral_8.clone(), - ), - (CosmicPalette::HighContrastDark(p), ContainerType::Primary) => Self::new( - CosmicPalette::HighContrastDark(p.clone()), - ComponentType::Primary, - p.gray_2.clone(), - p.neutral_9.clone(), - ), - (CosmicPalette::HighContrastDark(p), ContainerType::Secondary) => Self::new( - CosmicPalette::HighContrastDark(p.clone()), - ComponentType::Secondary, - p.gray_3.clone(), - p.neutral_9.clone(), - ), - (CosmicPalette::Light(p), ContainerType::Background) => Self::new( - CosmicPalette::Light(p.clone()), - ComponentType::Background, - p.gray_1.clone(), - p.neutral_9.clone(), - ), - (CosmicPalette::Light(p), ContainerType::Primary) => Self::new( - CosmicPalette::Light(p.clone()), - ComponentType::Primary, - p.gray_2.clone(), - p.neutral_8.clone(), - ), - (CosmicPalette::Light(p), ContainerType::Secondary) => Self::new( - CosmicPalette::Light(p.clone()), - ComponentType::Secondary, - p.gray_3.clone(), - p.neutral_8.clone(), - ), - (CosmicPalette::HighContrastLight(p), ContainerType::Background) => Self::new( - CosmicPalette::HighContrastLight(p.clone()), - ComponentType::Background, - p.gray_1.clone(), - p.neutral_10.clone(), - ), - (CosmicPalette::HighContrastLight(p), ContainerType::Primary) => Self::new( - CosmicPalette::HighContrastLight(p.clone()), - ComponentType::Primary, - p.gray_2.clone(), - p.neutral_9.clone(), - ), - (CosmicPalette::HighContrastLight(p), ContainerType::Secondary) => Self::new( - CosmicPalette::HighContrastLight(p.clone()), - ComponentType::Secondary, - p.gray_3.clone(), - p.neutral_9.clone(), - ), - } - } -} - -/// The type of the container -#[derive(Copy, Clone, PartialEq, Debug, Deserialize, Serialize)] -pub enum ContainerType { - /// Background type - Background, - /// Primary type - Primary, - /// Secondary type - Secondary, -} - -impl Default for ContainerType { - fn default() -> Self { - Self::Background - } -} - -impl fmt::Display for ContainerType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - ContainerType::Background => write!(f, "Background"), - ContainerType::Primary => write!(f, "Primary Container"), - ContainerType::Secondary => write!(f, "Secondary Container"), - } - } -} - /// The colors for a widget of the Cosmic theme #[derive(Clone, PartialEq, Debug, Default, Deserialize, Serialize, Eq)] pub struct Component { @@ -263,8 +149,6 @@ where pub fn component( base: C, component_state_overlay: C, - base_overlay: C, - base_overlay_alpha: f32, accent: C, on_component: C, is_high_contrast: bool, @@ -276,9 +160,6 @@ where component_state_overlay_20.alpha = 0.2; let base = base.into(); - let mut base_overlay = base_overlay.into(); - base_overlay.alpha = base_overlay_alpha; - let base = over(base_overlay, base); let mut base_50 = base.clone(); base_50.alpha = 0.5; @@ -306,175 +187,3 @@ where } } } - -/// Derived theme element from a palette and constraints -#[derive(Debug)] -pub struct Derivation { - /// Derived theme element - pub derived: E, - /// Derivation errors (Failed constraints) - pub errors: Vec, -} - -pub(crate) enum ComponentType { - Background, - Primary, - Secondary, - Destructive, - Warning, - Success, - Accent, -} - -impl From<(CosmicPalette, ComponentType)> for Component -where - C: Clone + fmt::Debug + Default + Into + From + Serialize + DeserializeOwned, -{ - fn from((p, t): (CosmicPalette, ComponentType)) -> Self { - match (p, t) { - (CosmicPalette::Dark(p), ComponentType::Background) => Self::component( - p.gray_1, - p.neutral_0, - p.neutral_10, - 0.08, - p.accent, - p.neutral_8, - false, - ), - - (CosmicPalette::Dark(p), ComponentType::Primary) => Self::component( - p.gray_2, - p.neutral_0, - p.neutral_10, - 0.08, - p.accent, - p.neutral_8, - false, - ), - - (CosmicPalette::Dark(p), ComponentType::Secondary) => Self::component( - p.gray_3, - p.neutral_0, - p.neutral_10, - 0.08, - p.accent, - p.neutral_9, - false, - ), - (CosmicPalette::HighContrastDark(p), ComponentType::Background) => Self::component( - p.gray_1, - p.neutral_0, - p.neutral_10, - 0.08, - p.accent, - p.neutral_9, - true, - ), - (CosmicPalette::HighContrastDark(p), ComponentType::Primary) => Self::component( - p.gray_2, - p.neutral_0, - p.neutral_10, - 0.08, - p.accent, - p.neutral_9, - true, - ), - (CosmicPalette::HighContrastDark(p), ComponentType::Secondary) => Self::component( - p.gray_3, - p.neutral_0, - p.neutral_10.clone(), - 0.08, - p.accent, - p.neutral_10, - true, - ), - - (CosmicPalette::Light(p), ComponentType::Background) => Component::component( - p.gray_1.clone(), - p.neutral_0.clone(), - p.neutral_0, - 0.75, - p.accent.clone(), - p.neutral_8, - false, - ), - (CosmicPalette::Light(p), ComponentType::Primary) => Component::component( - p.gray_2.clone(), - p.neutral_0.clone(), - p.neutral_0, - 0.9, - p.accent.clone(), - p.neutral_8, - false, - ), - (CosmicPalette::Light(p), ComponentType::Secondary) => Component::component( - p.gray_3.clone(), - p.neutral_0.clone(), - p.neutral_0, - 1.0, - p.accent.clone(), - p.neutral_8, - false, - ), - (CosmicPalette::HighContrastLight(p), ComponentType::Background) => { - Component::component( - p.gray_1.clone(), - p.neutral_0.clone(), - p.neutral_0, - 0.75, - p.accent.clone(), - p.neutral_9, - true, - ) - } - (CosmicPalette::HighContrastLight(p), ComponentType::Primary) => Component::component( - p.gray_2.clone(), - p.neutral_0.clone(), - p.neutral_0, - 0.9, - p.accent.clone(), - p.neutral_9, - true, - ), - (CosmicPalette::HighContrastLight(p), ComponentType::Secondary) => { - Component::component( - p.gray_3.clone(), - p.neutral_0.clone(), - p.neutral_0, - 1.0, - p.accent.clone(), - p.neutral_9, - true, - ) - } - - (CosmicPalette::Dark(p), ComponentType::Destructive) - | (CosmicPalette::Light(p), ComponentType::Destructive) - | (CosmicPalette::HighContrastLight(p), ComponentType::Destructive) - | (CosmicPalette::HighContrastDark(p), ComponentType::Destructive) => { - Component::colored_component(p.red.clone(), p.neutral_1.clone(), p.blue.clone()) - } - - (CosmicPalette::Dark(p), ComponentType::Warning) - | (CosmicPalette::Light(p), ComponentType::Warning) - | (CosmicPalette::HighContrastLight(p), ComponentType::Warning) - | (CosmicPalette::HighContrastDark(p), ComponentType::Warning) => { - Component::colored_component(p.yellow.clone(), p.neutral_0, p.blue.clone()) - } - - (CosmicPalette::Dark(p), ComponentType::Success) - | (CosmicPalette::Light(p), ComponentType::Success) - | (CosmicPalette::HighContrastLight(p), ComponentType::Success) - | (CosmicPalette::HighContrastDark(p), ComponentType::Success) => { - Component::colored_component(p.green.clone(), p.neutral_0, p.blue.clone()) - } - - (CosmicPalette::Dark(p), ComponentType::Accent) - | (CosmicPalette::Light(p), ComponentType::Accent) - | (CosmicPalette::HighContrastDark(p), ComponentType::Accent) - | (CosmicPalette::HighContrastLight(p), ComponentType::Accent) => { - Component::colored_component(p.blue.clone(), p.neutral_0, p.blue.clone()) - } - } - } -} diff --git a/cosmic-theme/src/model/layout.rs b/cosmic-theme/src/model/layout.rs new file mode 100644 index 00000000..79456dc6 --- /dev/null +++ b/cosmic-theme/src/model/layout.rs @@ -0,0 +1,5 @@ +#[derive(Default)] +pub struct Layout { + corner_radii: [u32;4], + +} \ No newline at end of file diff --git a/cosmic-theme/src/model/theme.rs b/cosmic-theme/src/model/theme.rs index 503b12d5..6c2bbcf8 100644 --- a/cosmic-theme/src/model/theme.rs +++ b/cosmic-theme/src/model/theme.rs @@ -1,11 +1,11 @@ use crate::{ - util::CssColor, Component, ComponentType, Container, ContainerType, CornerRadii, CosmicPalette, - CosmicPaletteInner, Spacing, DARK_PALETTE, LIGHT_PALETTE, NAME, THEME_DIR, + steps::steps, Component, Container, CornerRadii, CosmicPalette, CosmicPaletteInner, Spacing, + DARK_PALETTE, LIGHT_PALETTE, NAME, THEME_DIR, }; use anyhow::Context; use cosmic_config::{Config, ConfigGet, ConfigSet, CosmicConfigEntry}; use directories::{BaseDirsExt, ProjectDirsExt}; -use palette::{Srgb, Srgba}; +use palette::{FromColor, Oklcha, Srgb, Srgba}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use std::{ fmt, @@ -57,7 +57,7 @@ pub struct Theme { pub is_high_contrast: bool, } -impl CosmicConfigEntry for Theme { +impl CosmicConfigEntry for Theme { fn write_entry(&self, config: &Config) -> Result<(), cosmic_config::Error> { let self_ = self.clone(); // TODO do as transaction @@ -86,35 +86,35 @@ impl CosmicConfigEntry for Theme { Ok(name) => default.name = name, Err(e) => errors.push(e), } - match config.get::>("background") { + match config.get::>("background") { Ok(background) => default.background = background, Err(e) => errors.push(e), } - match config.get::>("primary") { + match config.get::>("primary") { Ok(primary) => default.primary = primary, Err(e) => errors.push(e), } - match config.get::>("secondary") { + match config.get::>("secondary") { Ok(secondary) => default.secondary = secondary, Err(e) => errors.push(e), } - match config.get::>("accent") { + match config.get::>("accent") { Ok(accent) => default.accent = accent, Err(e) => errors.push(e), } - match config.get::>("success") { + match config.get::>("success") { Ok(success) => default.success = success, Err(e) => errors.push(e), } - match config.get::>("destructive") { + match config.get::>("destructive") { Ok(destructive) => default.destructive = destructive, Err(e) => errors.push(e), } - match config.get::>("warning") { + match config.get::>("warning") { Ok(warning) => default.warning = warning, Err(e) => errors.push(e), } - match config.get::>("palette") { + match config.get::>("palette") { Ok(palette) => default.palette = palette, Err(e) => errors.push(e), } @@ -144,12 +144,6 @@ impl CosmicConfigEntry for Theme { } impl Default for Theme { - fn default() -> Self { - Theme::::dark_default().into_srgba() - } -} - -impl Default for Theme { fn default() -> Self { Self::dark_default() } @@ -426,7 +420,7 @@ where } } -impl Theme { +impl Theme { /// get the built in light theme pub fn light_default() -> Self { LIGHT_PALETTE.clone().into() @@ -446,54 +440,14 @@ impl Theme { pub fn high_contrast_light_default() -> Self { CosmicPalette::HighContrastLight(LIGHT_PALETTE.as_ref().clone()).into() } - - /// convert to srgba - pub fn into_srgba(self) -> Theme { - Theme { - name: self.name, - background: self.background.into_srgba(), - primary: self.primary.into_srgba(), - secondary: self.secondary.into_srgba(), - accent: self.accent.into_srgba(), - success: self.success.into_srgba(), - destructive: self.destructive.into_srgba(), - warning: self.warning.into_srgba(), - palette: self.palette.into(), - is_dark: self.is_dark, - is_high_contrast: self.is_high_contrast, - corner_radii: self.corner_radii, - spacing: self.spacing, - } - } } -impl From> for Theme +impl From> for Theme where - C: Clone + fmt::Debug + Default + Into + From + Serialize + DeserializeOwned, + CosmicPalette: Into>, { fn from(p: CosmicPalette) -> Self { - let is_dark = p.is_dark(); - let is_high_contrast = p.is_high_contrast(); - Self { - name: p.name().to_string(), - background: (p.clone(), ContainerType::Background).into(), - primary: (p.clone(), ContainerType::Primary).into(), - secondary: (p.clone(), ContainerType::Secondary).into(), - accent: (p.clone(), ComponentType::Accent).into(), - success: (p.clone(), ComponentType::Success).into(), - destructive: (p.clone(), ComponentType::Destructive).into(), - warning: (p.clone(), ComponentType::Warning).into(), - palette: match p { - CosmicPalette::Dark(p) => p.into(), - CosmicPalette::Light(p) => p.into(), - CosmicPalette::HighContrastLight(p) => p.into(), - CosmicPalette::HighContrastDark(p) => p.into(), - }, - is_dark, - is_high_contrast, - spacing: Spacing::default(), - corner_radii: CornerRadii::default(), - } + ThemeBuilder::palette(p.into()).build() } } @@ -506,6 +460,7 @@ pub struct ThemeBuilder { neutral_tint: Option, bg_color: Option, primary_container_bg: Option, + secondary_container_bg: Option, text_tint: Option, accent: Option, } @@ -520,6 +475,7 @@ impl Default for ThemeBuilder { text_tint: Default::default(), bg_color: Default::default(), primary_container_bg: Default::default(), + secondary_container_bg: Default::default(), accent: Default::default(), } } @@ -560,6 +516,14 @@ impl ThemeBuilder { } } + /// Get a builder that is initialized with the provided palette + pub fn palette(palette: CosmicPalette) -> Self { + Self { + palette, + ..Default::default() + } + } + /// set the spacing of the builder pub fn spacing(mut self, spacing: Spacing) -> Self { self.spacing = spacing; @@ -612,6 +576,7 @@ impl ThemeBuilder { text_tint, bg_color, primary_container_bg, + secondary_container_bg, accent, } = self; @@ -619,15 +584,175 @@ impl ThemeBuilder { palette.as_mut().accent = accent.into(); } - // TODO apply the customizations + // TODO apply the tint customizations + + let is_dark = palette.is_dark(); + let is_high_contrast = palette.is_high_contrast(); if let Some(accent) = accent { palette.as_mut().accent = accent.into(); } + let p_ref = palette.as_ref(); - let mut theme: Theme = palette.into(); + let bg = if let Some(bg_color) = bg_color { + bg_color + } else { + p_ref.neutral_0.clone() + }; + let ok_bg = Oklcha::from_color(bg); + let step_array = steps(ok_bg); + + let bg_index = color_index(bg, step_array.len()); + let primary_container_bg = if let Some(primary_container_bg_color) = primary_container_bg { + primary_container_bg_color + } else { + get_color(bg_index, 5, &step_array, is_dark, &p_ref.neutral_1) + }; + + let secondary_container_bg = if let Some(secondary_container_bg) = secondary_container_bg { + secondary_container_bg + } else { + get_color(bg_index, 10, &step_array, is_dark, &p_ref.neutral_2) + }; + + let bg_component = get_color(bg_index, 8, &step_array, is_dark, &p_ref.neutral_2); + let on_bg_component = get_text( + color_index(bg_component, step_array.len()), + &step_array, + is_dark, + &p_ref.neutral_8, + ); + let bg_component = Component::component( + bg_component, + p_ref.neutral_0.to_owned(), + p_ref.accent.to_owned(), + on_bg_component, + is_high_contrast, + ); + + let primary_index = color_index(primary_container_bg, step_array.len()); + let primary_component = get_color(primary_index, 6, &step_array, is_dark, &p_ref.neutral_3); + let on_primary_component = get_text( + color_index(primary_component, step_array.len()), + &step_array, + is_dark, + &p_ref.neutral_8, + ); + let primary_component = Component::component( + primary_component, + p_ref.neutral_0.to_owned(), + p_ref.accent.to_owned(), + on_primary_component, + is_high_contrast, + ); + + let secondary_index = color_index(secondary_container_bg, step_array.len()); + let secondary_component = + get_color(secondary_index, 3, &step_array, is_dark, &p_ref.neutral_4); + let on_secondary_component = get_text( + color_index(secondary_component, step_array.len()), + &step_array, + is_dark, + &p_ref.neutral_10, + ); + let secondary_component = Component::component( + secondary_component, + p_ref.neutral_0.to_owned(), + p_ref.accent.to_owned(), + on_secondary_component, + is_high_contrast, + ); + + let mut theme: Theme = Theme { + name: palette.name().to_string(), + background: Container::new( + bg_component, + bg, + get_text(bg_index, &step_array, is_dark, &p_ref.neutral_8), + ), + primary: Container::new( + primary_component, + primary_container_bg, + get_text(primary_index, &step_array, is_dark, &p_ref.neutral_8), + ), + secondary: Container::new( + secondary_component, + secondary_container_bg, + get_text(secondary_index, &step_array, is_dark, &p_ref.neutral_8), + ), + accent: Component::colored_component( + p_ref.accent.to_owned(), + p_ref.neutral_0.to_owned(), + p_ref.accent.to_owned(), + ), + success: Component::colored_component( + p_ref.green.to_owned(), + p_ref.neutral_0.to_owned(), + p_ref.accent.to_owned(), + ), + destructive: Component::colored_component( + p_ref.red.to_owned(), + p_ref.neutral_0.to_owned(), + p_ref.accent.to_owned(), + ), + warning: Component::colored_component( + p_ref.yellow.to_owned(), + p_ref.neutral_0.to_owned(), + p_ref.accent.to_owned(), + ), + palette: palette.inner(), + spacing, + corner_radii, + is_dark, + is_high_contrast, + }; theme.spacing = spacing; theme.corner_radii = corner_radii; theme } } + +fn get_index(base_index: usize, steps: usize, step_len: usize, is_dark: bool) -> Option { + if is_dark { + base_index.checked_add(steps) + } else { + base_index.checked_sub(steps) + } + .filter(|i| *i < step_len) +} + +fn get_color( + base_index: usize, + steps: usize, + step_array: &[Srgba; 100], + is_dark: bool, + fallback: &Srgba, +) -> Srgba { + get_index(base_index, steps, step_array.len(), is_dark) + .and_then(|i| step_array.get(i).cloned()) + .unwrap_or_else(|| fallback.to_owned()) +} + +fn get_text( + base_index: usize, + step_array: &[Srgba; 100], + is_dark: bool, + fallback: &Srgba, +) -> Srgba { + let Some(index) = get_index(base_index, 70, step_array.len(), is_dark).or_else(|| get_index(base_index, 50, step_array.len(), is_dark)) else { + return fallback.to_owned(); + }; + + step_array + .get(index) + .cloned() + .unwrap_or_else(|| fallback.to_owned()) +} + +fn color_index(c: C, array_len: usize) -> usize +where + Oklcha: FromColor, +{ + let c = Oklcha::from_color(c); + ((c.l * array_len as f32).round() as usize).clamp(0, array_len - 1) +} diff --git a/cosmic-theme/src/steps.rs b/cosmic-theme/src/steps.rs index 5e2f635c..5407a584 100644 --- a/cosmic-theme/src/steps.rs +++ b/cosmic-theme/src/steps.rs @@ -1,11 +1,11 @@ use almost::equal; -use palette::{convert::FromColorUnclamped, ClampAssign, Oklch, Srgb}; +use palette::{convert::FromColorUnclamped, ClampAssign, Oklcha, Srgb, Srgba}; /// Get an array of 100 colors with a specific hue and chroma /// over the full range of lightness. -/// Colors which are not valid Srgb will fallback to a color with the nearest valid chroma. -pub fn steps(mut c: Oklch) -> [Srgb; 100] { - let mut steps = [Srgb::new(0.0, 0.0, 0.0); 100]; +/// Colors which are not valid Srgba will fallback to a color with the nearest valid chroma. +pub fn steps(mut c: Oklcha) -> [Srgba; 100] { + let mut steps = [Srgba::new(0.0, 0.0, 0.0, 1.0); 100]; for i in 0..steps.len() { let lightness = i as f32 / 100.0; @@ -16,12 +16,12 @@ pub fn steps(mut c: Oklch) -> [Srgb; 100] { steps } -/// find the nearest chroma which makes our color a valid color in Srgb -pub fn oklch_to_srgba_nearest_chroma(mut c: Oklch) -> Srgb { +/// find the nearest chroma which makes our color a valid color in Srgba +pub fn oklch_to_srgba_nearest_chroma(mut c: Oklcha) -> Srgba { let mut r_chroma = c.chroma; let mut l_chroma = 0.0; // exit early if we found it right away - let mut new_c = Srgb::from_color_unclamped(c); + let mut new_c = Srgba::from_color_unclamped(c); if is_valid_srgb(new_c) { new_c.clamp_assign(); @@ -30,7 +30,7 @@ pub fn oklch_to_srgba_nearest_chroma(mut c: Oklch) -> Srgb { // is this an excessive depth to search? for _ in 0..64 { - let new_c = Srgb::from_color_unclamped(c); + let new_c = Srgba::from_color_unclamped(c); if is_valid_srgb(new_c) { l_chroma = c.chroma; c.chroma = (c.chroma + r_chroma) / 2.0; @@ -39,11 +39,11 @@ pub fn oklch_to_srgba_nearest_chroma(mut c: Oklch) -> Srgb { c.chroma = (c.chroma + l_chroma) / 2.0; } } - Srgb::from_color_unclamped(c) + Srgba::from_color_unclamped(c) } /// checks that the color is valid srgb -pub fn is_valid_srgb(c: Srgb) -> bool { +pub fn is_valid_srgb(c: Srgba) -> bool { (equal(c.red, Srgb::max_red()) || (c.red >= Srgb::min_red() && c.red <= Srgb::max_red())) && (equal(c.blue, Srgb::max_blue()) || (c.blue >= Srgb::min_blue() && c.blue <= Srgb::max_blue())) @@ -54,38 +54,38 @@ pub fn is_valid_srgb(c: Srgb) -> bool { #[cfg(test)] mod tests { use almost::equal; - use palette::{OklabHue, Srgb}; + use palette::{OklabHue, Srgba}; use super::{is_valid_srgb, oklch_to_srgba_nearest_chroma}; #[test] fn test_valid_check() { - assert!(is_valid_srgb(Srgb::new(1.0, 1.0, 1.0))); - assert!(is_valid_srgb(Srgb::new(0.0, 0.0, 0.0))); - assert!(is_valid_srgb(Srgb::new(0.5, 0.5, 0.5))); - assert!(!is_valid_srgb(Srgb::new(-0.1, 0.0, 0.0))); - assert!(!is_valid_srgb(Srgb::new(0.0, -0.1, 0.0))); - assert!(!is_valid_srgb(Srgb::new(-0.0, 0.0, -0.1))); - assert!(!is_valid_srgb(Srgb::new(-100.1, 0.0, 0.0))); - assert!(!is_valid_srgb(Srgb::new(0.0, -100.1, 0.0))); - assert!(!is_valid_srgb(Srgb::new(-0.0, 0.0, -100.1))); - assert!(!is_valid_srgb(Srgb::new(1.1, 0.0, 0.0))); - assert!(!is_valid_srgb(Srgb::new(0.0, 1.1, 0.0))); - assert!(!is_valid_srgb(Srgb::new(-0.0, 0.0, 1.1))); - assert!(!is_valid_srgb(Srgb::new(100.1, 0.0, 0.0))); - assert!(!is_valid_srgb(Srgb::new(0.0, 100.1, 0.0))); - assert!(!is_valid_srgb(Srgb::new(-0.0, 0.0, 100.1))); + assert!(is_valid_srgb(Srgba::new(1.0, 1.0, 1.0, 1.0))); + assert!(is_valid_srgb(Srgba::new(0.0, 0.0, 0.0, 1.0))); + assert!(is_valid_srgb(Srgba::new(0.5, 0.5, 0.5, 1.0))); + assert!(!is_valid_srgb(Srgba::new(-0.1, 0.0, 0.0, 1.0))); + assert!(!is_valid_srgb(Srgba::new(0.0, -0.1, 0.0, 1.0))); + assert!(!is_valid_srgb(Srgba::new(-0.0, 0.0, -0.1, 1.0))); + assert!(!is_valid_srgb(Srgba::new(-100.1, 0.0, 0.0, 1.0))); + assert!(!is_valid_srgb(Srgba::new(0.0, -100.1, 0.0, 1.0))); + assert!(!is_valid_srgb(Srgba::new(-0.0, 0.0, -100.1, 1.0))); + assert!(!is_valid_srgb(Srgba::new(1.1, 0.0, 0.0, 1.0))); + assert!(!is_valid_srgb(Srgba::new(0.0, 1.1, 0.0, 1.0))); + assert!(!is_valid_srgb(Srgba::new(-0.0, 0.0, 1.1, 1.0))); + assert!(!is_valid_srgb(Srgba::new(100.1, 0.0, 0.0, 1.0))); + assert!(!is_valid_srgb(Srgba::new(0.0, 100.1, 0.0, 1.0))); + assert!(!is_valid_srgb(Srgba::new(-0.0, 0.0, 100.1, 1.0))); } #[test] fn test_conversion_boundaries() { - let c1 = palette::Oklch::new(0.0, 0.288, OklabHue::from_degrees(0.0)); + let c1 = palette::Oklcha::new(0.0, 0.288, OklabHue::from_degrees(0.0), 1.0); let srgb = oklch_to_srgba_nearest_chroma(c1); equal(srgb.red, 0.0); equal(srgb.blue, 0.0); equal(srgb.green, 0.0); - let c1 = palette::Oklch::new(1.0, 0.288, OklabHue::from_degrees(0.0)); + let c1 = palette::Oklcha::new(1.0, 0.288, OklabHue::from_degrees(0.0), 1.0); let srgb = oklch_to_srgba_nearest_chroma(c1); equal(srgb.red, 1.0); @@ -95,20 +95,20 @@ mod tests { #[test] fn test_conversion_colors() { - let c1 = palette::Oklch::new(0.4608, 0.11111, OklabHue::new(57.31)); - let srgb = oklch_to_srgba_nearest_chroma(c1).into_format::(); + let c1 = palette::Oklcha::new(0.4608, 0.11111, OklabHue::new(57.31), 1.0); + let srgb = oklch_to_srgba_nearest_chroma(c1).into_format::(); assert!(srgb.red == 133); assert!(srgb.green == 69); assert!(srgb.blue == 0); - let c1 = palette::Oklch::new(0.30, 0.08, OklabHue::new(35.0)); - let srgb = oklch_to_srgba_nearest_chroma(c1).into_format::(); + let c1 = palette::Oklcha::new(0.30, 0.08, OklabHue::new(35.0), 1.0); + let srgb = oklch_to_srgba_nearest_chroma(c1).into_format::(); assert!(srgb.red == 78); assert!(srgb.green == 27); assert!(srgb.blue == 15); - let c1 = palette::Oklch::new(0.757, 0.146, OklabHue::new(301.2)); - let srgb = oklch_to_srgba_nearest_chroma(c1).into_format::(); + let c1 = palette::Oklcha::new(0.757, 0.146, OklabHue::new(301.2), 1.0); + let srgb = oklch_to_srgba_nearest_chroma(c1).into_format::(); assert!(srgb.red == 192); assert!(srgb.green == 153); assert!(srgb.blue == 253); @@ -116,20 +116,20 @@ mod tests { #[test] fn test_conversion_fallback_colors() { - let c1 = palette::Oklch::new(0.70, 0.284, OklabHue::new(35.0)); - let srgb = oklch_to_srgba_nearest_chroma(c1).into_format::(); + let c1 = palette::Oklcha::new(0.70, 0.284, OklabHue::new(35.0), 1.0); + let srgb = oklch_to_srgba_nearest_chroma(c1).into_format::(); assert!(srgb.red == 255); assert!(srgb.green == 103); assert!(srgb.blue == 65); - let c1 = palette::Oklch::new(0.757, 0.239, OklabHue::new(301.2)); - let srgb = oklch_to_srgba_nearest_chroma(c1).into_format::(); + let c1 = palette::Oklcha::new(0.757, 0.239, OklabHue::new(301.2), 1.0); + let srgb = oklch_to_srgba_nearest_chroma(c1).into_format::(); assert!(srgb.red == 193); assert!(srgb.green == 152); assert!(srgb.blue == 255); - let c1 = palette::Oklch::new(0.163, 0.333, OklabHue::new(141.0)); - let srgb = oklch_to_srgba_nearest_chroma(c1).into_format::(); + let c1 = palette::Oklcha::new(0.163, 0.333, OklabHue::new(141.0), 1.0); + let srgb = oklch_to_srgba_nearest_chroma(c1).into_format::(); assert!(srgb.red == 1); assert!(srgb.green == 19); assert!(srgb.blue == 0); diff --git a/src/theme/mod.rs b/src/theme/mod.rs index 8a23a039..2fb5e8c1 100644 --- a/src/theme/mod.rs +++ b/src/theme/mod.rs @@ -44,13 +44,12 @@ use palette::Srgba; pub type CosmicColor = ::palette::rgb::Srgba; pub type CosmicComponent = cosmic_theme::Component; pub type CosmicTheme = cosmic_theme::Theme; -pub 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 COSMIC_DARK: CosmicTheme = CosmicTheme::dark_default(); + pub static ref COSMIC_HC_DARK: CosmicTheme = CosmicTheme::high_contrast_dark_default(); + pub static ref COSMIC_LIGHT: CosmicTheme = CosmicTheme::light_default(); + pub static ref COSMIC_HC_LIGHT: CosmicTheme = CosmicTheme::high_contrast_light_default(); 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), @@ -1202,6 +1201,7 @@ impl text_input::StyleSheet for Theme { } } +#[must_use] pub fn theme() -> Theme { let Ok(helper) = crate::cosmic_config::Config::new( crate::cosmic_theme::NAME, @@ -1209,34 +1209,28 @@ pub fn theme() -> Theme { ) else { return crate::theme::Theme::dark(); }; - let t = crate::cosmic_theme::Theme::get_entry(&helper).map_or_else( - |(errors, theme)| { - for err in errors { - tracing::error!("{:?}", err); - } - theme.into_srgba() - }, - crate::cosmic_theme::Theme::into_srgba, - ); + let t = crate::cosmic_theme::Theme::get_entry(&helper).unwrap_or_else(|(errors, theme)| { + for err in errors { + tracing::error!("{:?}", err); + } + theme + }); crate::theme::Theme::custom(Arc::new(t)) } pub fn subscription(id: u64) -> Subscription { - config_subscription::>( + config_subscription::>( id, crate::cosmic_theme::NAME.into(), - crate::cosmic_theme::Theme::::version(), + crate::cosmic_theme::Theme::::version(), ) .map(|(_, res)| { - let theme = res.map_or_else( - |(errors, theme)| { - for err in errors { - tracing::error!("{:?}", err); - } - theme.into_srgba() - }, - crate::cosmic_theme::Theme::into_srgba, - ); + let theme = res.unwrap_or_else(|(errors, theme)| { + for err in errors { + tracing::error!("{:?}", err); + } + theme + }); crate::theme::Theme::custom(Arc::new(theme)) }) }