wip: calculate theme using new method
This commit is contained in:
parent
607883e4ad
commit
a618c1b94a
6 changed files with 257 additions and 423 deletions
|
|
@ -98,5 +98,6 @@ exclude = [
|
||||||
[patch."https://github.com/pop-os/libcosmic"]
|
[patch."https://github.com/pop-os/libcosmic"]
|
||||||
libcosmic = { path = "./", features = ["wayland", "tokio", "a11y"]}
|
libcosmic = { path = "./", features = ["wayland", "tokio", "a11y"]}
|
||||||
|
|
||||||
|
# TODO Remove me when the palette crate gets an update & before merging
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
palette = {git = "https://github.com/Ogeon/palette", features = ["serializing"] }
|
palette = {git = "https://github.com/Ogeon/palette", features = ["serializing"] }
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use palette::Srgba;
|
||||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||||
use std::fmt;
|
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
|
/// 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)]
|
#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
|
||||||
|
|
@ -31,134 +31,20 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(component: Component<C>, bg: C, on_bg: C) -> Self {
|
||||||
palette: CosmicPalette<C>,
|
|
||||||
container_type: ComponentType,
|
|
||||||
bg: C,
|
|
||||||
on_bg: C,
|
|
||||||
) -> Self {
|
|
||||||
let mut divider_c: Srgba = on_bg.clone().into();
|
let mut divider_c: Srgba = on_bg.clone().into();
|
||||||
divider_c.alpha = 0.2;
|
divider_c.alpha = 0.2;
|
||||||
|
|
||||||
let divider = over(divider_c.clone(), bg.clone());
|
let divider = over(divider_c.clone(), bg.clone());
|
||||||
Self {
|
Self {
|
||||||
base: bg,
|
base: bg,
|
||||||
component: (palette, container_type).into(),
|
component,
|
||||||
divider: divider.into(),
|
divider: divider.into(),
|
||||||
on: on_bg,
|
on: on_bg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C> From<(CosmicPalette<C>, ContainerType)> for Container<C>
|
|
||||||
where
|
|
||||||
C: Clone + fmt::Debug + Default + Into<Srgba> + From<Srgba> + Serialize + DeserializeOwned,
|
|
||||||
{
|
|
||||||
fn from((p, t): (CosmicPalette<C>, 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
|
/// The colors for a widget of the Cosmic theme
|
||||||
#[derive(Clone, PartialEq, Debug, Default, Deserialize, Serialize, Eq)]
|
#[derive(Clone, PartialEq, Debug, Default, Deserialize, Serialize, Eq)]
|
||||||
pub struct Component<C> {
|
pub struct Component<C> {
|
||||||
|
|
@ -263,8 +149,6 @@ where
|
||||||
pub fn component(
|
pub fn component(
|
||||||
base: C,
|
base: C,
|
||||||
component_state_overlay: C,
|
component_state_overlay: C,
|
||||||
base_overlay: C,
|
|
||||||
base_overlay_alpha: f32,
|
|
||||||
accent: C,
|
accent: C,
|
||||||
on_component: C,
|
on_component: C,
|
||||||
is_high_contrast: bool,
|
is_high_contrast: bool,
|
||||||
|
|
@ -276,9 +160,6 @@ where
|
||||||
component_state_overlay_20.alpha = 0.2;
|
component_state_overlay_20.alpha = 0.2;
|
||||||
|
|
||||||
let base = base.into();
|
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();
|
let mut base_50 = base.clone();
|
||||||
base_50.alpha = 0.5;
|
base_50.alpha = 0.5;
|
||||||
|
|
||||||
|
|
@ -306,175 +187,3 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Derived theme element from a palette and constraints
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Derivation<E> {
|
|
||||||
/// Derived theme element
|
|
||||||
pub derived: E,
|
|
||||||
/// Derivation errors (Failed constraints)
|
|
||||||
pub errors: Vec<anyhow::Error>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) enum ComponentType {
|
|
||||||
Background,
|
|
||||||
Primary,
|
|
||||||
Secondary,
|
|
||||||
Destructive,
|
|
||||||
Warning,
|
|
||||||
Success,
|
|
||||||
Accent,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<C> From<(CosmicPalette<C>, ComponentType)> for Component<C>
|
|
||||||
where
|
|
||||||
C: Clone + fmt::Debug + Default + Into<Srgba> + From<Srgba> + Serialize + DeserializeOwned,
|
|
||||||
{
|
|
||||||
fn from((p, t): (CosmicPalette<C>, 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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
5
cosmic-theme/src/model/layout.rs
Normal file
5
cosmic-theme/src/model/layout.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Layout {
|
||||||
|
corner_radii: [u32;4],
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
util::CssColor, Component, ComponentType, Container, ContainerType, CornerRadii, CosmicPalette,
|
steps::steps, Component, Container, CornerRadii, CosmicPalette, CosmicPaletteInner, Spacing,
|
||||||
CosmicPaletteInner, Spacing, DARK_PALETTE, LIGHT_PALETTE, NAME, THEME_DIR,
|
DARK_PALETTE, LIGHT_PALETTE, NAME, THEME_DIR,
|
||||||
};
|
};
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use cosmic_config::{Config, ConfigGet, ConfigSet, CosmicConfigEntry};
|
use cosmic_config::{Config, ConfigGet, ConfigSet, CosmicConfigEntry};
|
||||||
use directories::{BaseDirsExt, ProjectDirsExt};
|
use directories::{BaseDirsExt, ProjectDirsExt};
|
||||||
use palette::{Srgb, Srgba};
|
use palette::{FromColor, Oklcha, Srgb, Srgba};
|
||||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
fmt,
|
fmt,
|
||||||
|
|
@ -57,7 +57,7 @@ pub struct Theme<C> {
|
||||||
pub is_high_contrast: bool,
|
pub is_high_contrast: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CosmicConfigEntry for Theme<CssColor> {
|
impl CosmicConfigEntry for Theme<Srgba> {
|
||||||
fn write_entry(&self, config: &Config) -> Result<(), cosmic_config::Error> {
|
fn write_entry(&self, config: &Config) -> Result<(), cosmic_config::Error> {
|
||||||
let self_ = self.clone();
|
let self_ = self.clone();
|
||||||
// TODO do as transaction
|
// TODO do as transaction
|
||||||
|
|
@ -86,35 +86,35 @@ impl CosmicConfigEntry for Theme<CssColor> {
|
||||||
Ok(name) => default.name = name,
|
Ok(name) => default.name = name,
|
||||||
Err(e) => errors.push(e),
|
Err(e) => errors.push(e),
|
||||||
}
|
}
|
||||||
match config.get::<Container<CssColor>>("background") {
|
match config.get::<Container<Srgba>>("background") {
|
||||||
Ok(background) => default.background = background,
|
Ok(background) => default.background = background,
|
||||||
Err(e) => errors.push(e),
|
Err(e) => errors.push(e),
|
||||||
}
|
}
|
||||||
match config.get::<Container<CssColor>>("primary") {
|
match config.get::<Container<Srgba>>("primary") {
|
||||||
Ok(primary) => default.primary = primary,
|
Ok(primary) => default.primary = primary,
|
||||||
Err(e) => errors.push(e),
|
Err(e) => errors.push(e),
|
||||||
}
|
}
|
||||||
match config.get::<Container<CssColor>>("secondary") {
|
match config.get::<Container<Srgba>>("secondary") {
|
||||||
Ok(secondary) => default.secondary = secondary,
|
Ok(secondary) => default.secondary = secondary,
|
||||||
Err(e) => errors.push(e),
|
Err(e) => errors.push(e),
|
||||||
}
|
}
|
||||||
match config.get::<Component<CssColor>>("accent") {
|
match config.get::<Component<Srgba>>("accent") {
|
||||||
Ok(accent) => default.accent = accent,
|
Ok(accent) => default.accent = accent,
|
||||||
Err(e) => errors.push(e),
|
Err(e) => errors.push(e),
|
||||||
}
|
}
|
||||||
match config.get::<Component<CssColor>>("success") {
|
match config.get::<Component<Srgba>>("success") {
|
||||||
Ok(success) => default.success = success,
|
Ok(success) => default.success = success,
|
||||||
Err(e) => errors.push(e),
|
Err(e) => errors.push(e),
|
||||||
}
|
}
|
||||||
match config.get::<Component<CssColor>>("destructive") {
|
match config.get::<Component<Srgba>>("destructive") {
|
||||||
Ok(destructive) => default.destructive = destructive,
|
Ok(destructive) => default.destructive = destructive,
|
||||||
Err(e) => errors.push(e),
|
Err(e) => errors.push(e),
|
||||||
}
|
}
|
||||||
match config.get::<Component<CssColor>>("warning") {
|
match config.get::<Component<Srgba>>("warning") {
|
||||||
Ok(warning) => default.warning = warning,
|
Ok(warning) => default.warning = warning,
|
||||||
Err(e) => errors.push(e),
|
Err(e) => errors.push(e),
|
||||||
}
|
}
|
||||||
match config.get::<CosmicPaletteInner<CssColor>>("palette") {
|
match config.get::<CosmicPaletteInner<Srgba>>("palette") {
|
||||||
Ok(palette) => default.palette = palette,
|
Ok(palette) => default.palette = palette,
|
||||||
Err(e) => errors.push(e),
|
Err(e) => errors.push(e),
|
||||||
}
|
}
|
||||||
|
|
@ -144,12 +144,6 @@ impl CosmicConfigEntry for Theme<CssColor> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Theme<Srgba> {
|
impl Default for Theme<Srgba> {
|
||||||
fn default() -> Self {
|
|
||||||
Theme::<CssColor>::dark_default().into_srgba()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Theme<CssColor> {
|
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::dark_default()
|
Self::dark_default()
|
||||||
}
|
}
|
||||||
|
|
@ -426,7 +420,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Theme<CssColor> {
|
impl Theme<Srgba> {
|
||||||
/// get the built in light theme
|
/// get the built in light theme
|
||||||
pub fn light_default() -> Self {
|
pub fn light_default() -> Self {
|
||||||
LIGHT_PALETTE.clone().into()
|
LIGHT_PALETTE.clone().into()
|
||||||
|
|
@ -446,54 +440,14 @@ impl Theme<CssColor> {
|
||||||
pub fn high_contrast_light_default() -> Self {
|
pub fn high_contrast_light_default() -> Self {
|
||||||
CosmicPalette::HighContrastLight(LIGHT_PALETTE.as_ref().clone()).into()
|
CosmicPalette::HighContrastLight(LIGHT_PALETTE.as_ref().clone()).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// convert to srgba
|
|
||||||
pub fn into_srgba(self) -> Theme<Srgba> {
|
|
||||||
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<C> From<CosmicPalette<C>> for Theme<C>
|
impl<C> From<CosmicPalette<C>> for Theme<Srgba>
|
||||||
where
|
where
|
||||||
C: Clone + fmt::Debug + Default + Into<Srgba> + From<Srgba> + Serialize + DeserializeOwned,
|
CosmicPalette<C>: Into<CosmicPalette<Srgba>>,
|
||||||
{
|
{
|
||||||
fn from(p: CosmicPalette<C>) -> Self {
|
fn from(p: CosmicPalette<C>) -> Self {
|
||||||
let is_dark = p.is_dark();
|
ThemeBuilder::palette(p.into()).build()
|
||||||
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(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -506,6 +460,7 @@ pub struct ThemeBuilder {
|
||||||
neutral_tint: Option<Srgb>,
|
neutral_tint: Option<Srgb>,
|
||||||
bg_color: Option<Srgba>,
|
bg_color: Option<Srgba>,
|
||||||
primary_container_bg: Option<Srgba>,
|
primary_container_bg: Option<Srgba>,
|
||||||
|
secondary_container_bg: Option<Srgba>,
|
||||||
text_tint: Option<Srgb>,
|
text_tint: Option<Srgb>,
|
||||||
accent: Option<Srgb>,
|
accent: Option<Srgb>,
|
||||||
}
|
}
|
||||||
|
|
@ -520,6 +475,7 @@ impl Default for ThemeBuilder {
|
||||||
text_tint: Default::default(),
|
text_tint: Default::default(),
|
||||||
bg_color: Default::default(),
|
bg_color: Default::default(),
|
||||||
primary_container_bg: Default::default(),
|
primary_container_bg: Default::default(),
|
||||||
|
secondary_container_bg: Default::default(),
|
||||||
accent: 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<Srgba>) -> Self {
|
||||||
|
Self {
|
||||||
|
palette,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// set the spacing of the builder
|
/// set the spacing of the builder
|
||||||
pub fn spacing(mut self, spacing: Spacing) -> Self {
|
pub fn spacing(mut self, spacing: Spacing) -> Self {
|
||||||
self.spacing = spacing;
|
self.spacing = spacing;
|
||||||
|
|
@ -612,6 +576,7 @@ impl ThemeBuilder {
|
||||||
text_tint,
|
text_tint,
|
||||||
bg_color,
|
bg_color,
|
||||||
primary_container_bg,
|
primary_container_bg,
|
||||||
|
secondary_container_bg,
|
||||||
accent,
|
accent,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
|
|
@ -619,15 +584,175 @@ impl ThemeBuilder {
|
||||||
palette.as_mut().accent = accent.into();
|
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 {
|
if let Some(accent) = accent {
|
||||||
palette.as_mut().accent = accent.into();
|
palette.as_mut().accent = accent.into();
|
||||||
}
|
}
|
||||||
|
let p_ref = palette.as_ref();
|
||||||
|
|
||||||
let mut theme: Theme<Srgba> = 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<Srgba> = 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.spacing = spacing;
|
||||||
theme.corner_radii = corner_radii;
|
theme.corner_radii = corner_radii;
|
||||||
theme
|
theme
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_index(base_index: usize, steps: usize, step_len: usize, is_dark: bool) -> Option<usize> {
|
||||||
|
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: C, array_len: usize) -> usize
|
||||||
|
where
|
||||||
|
Oklcha: FromColor<C>,
|
||||||
|
{
|
||||||
|
let c = Oklcha::from_color(c);
|
||||||
|
((c.l * array_len as f32).round() as usize).clamp(0, array_len - 1)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
use almost::equal;
|
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
|
/// Get an array of 100 colors with a specific hue and chroma
|
||||||
/// over the full range of lightness.
|
/// over the full range of lightness.
|
||||||
/// Colors which are not valid Srgb will fallback to a color with the nearest valid chroma.
|
/// Colors which are not valid Srgba will fallback to a color with the nearest valid chroma.
|
||||||
pub fn steps(mut c: Oklch) -> [Srgb; 100] {
|
pub fn steps(mut c: Oklcha) -> [Srgba; 100] {
|
||||||
let mut steps = [Srgb::new(0.0, 0.0, 0.0); 100];
|
let mut steps = [Srgba::new(0.0, 0.0, 0.0, 1.0); 100];
|
||||||
|
|
||||||
for i in 0..steps.len() {
|
for i in 0..steps.len() {
|
||||||
let lightness = i as f32 / 100.0;
|
let lightness = i as f32 / 100.0;
|
||||||
|
|
@ -16,12 +16,12 @@ pub fn steps(mut c: Oklch) -> [Srgb; 100] {
|
||||||
steps
|
steps
|
||||||
}
|
}
|
||||||
|
|
||||||
/// find the nearest chroma which makes our color a valid color in Srgb
|
/// find the nearest chroma which makes our color a valid color in Srgba
|
||||||
pub fn oklch_to_srgba_nearest_chroma(mut c: Oklch) -> Srgb {
|
pub fn oklch_to_srgba_nearest_chroma(mut c: Oklcha) -> Srgba {
|
||||||
let mut r_chroma = c.chroma;
|
let mut r_chroma = c.chroma;
|
||||||
let mut l_chroma = 0.0;
|
let mut l_chroma = 0.0;
|
||||||
// exit early if we found it right away
|
// 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) {
|
if is_valid_srgb(new_c) {
|
||||||
new_c.clamp_assign();
|
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?
|
// is this an excessive depth to search?
|
||||||
for _ in 0..64 {
|
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) {
|
if is_valid_srgb(new_c) {
|
||||||
l_chroma = c.chroma;
|
l_chroma = c.chroma;
|
||||||
c.chroma = (c.chroma + r_chroma) / 2.0;
|
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;
|
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
|
/// 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.red, Srgb::max_red()) || (c.red >= Srgb::min_red() && c.red <= Srgb::max_red()))
|
||||||
&& (equal(c.blue, Srgb::max_blue())
|
&& (equal(c.blue, Srgb::max_blue())
|
||||||
|| (c.blue >= Srgb::min_blue() && 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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use almost::equal;
|
use almost::equal;
|
||||||
use palette::{OklabHue, Srgb};
|
use palette::{OklabHue, Srgba};
|
||||||
|
|
||||||
use super::{is_valid_srgb, oklch_to_srgba_nearest_chroma};
|
use super::{is_valid_srgb, oklch_to_srgba_nearest_chroma};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_valid_check() {
|
fn test_valid_check() {
|
||||||
assert!(is_valid_srgb(Srgb::new(1.0, 1.0, 1.0)));
|
assert!(is_valid_srgb(Srgba::new(1.0, 1.0, 1.0, 1.0)));
|
||||||
assert!(is_valid_srgb(Srgb::new(0.0, 0.0, 0.0)));
|
assert!(is_valid_srgb(Srgba::new(0.0, 0.0, 0.0, 1.0)));
|
||||||
assert!(is_valid_srgb(Srgb::new(0.5, 0.5, 0.5)));
|
assert!(is_valid_srgb(Srgba::new(0.5, 0.5, 0.5, 1.0)));
|
||||||
assert!(!is_valid_srgb(Srgb::new(-0.1, 0.0, 0.0)));
|
assert!(!is_valid_srgb(Srgba::new(-0.1, 0.0, 0.0, 1.0)));
|
||||||
assert!(!is_valid_srgb(Srgb::new(0.0, -0.1, 0.0)));
|
assert!(!is_valid_srgb(Srgba::new(0.0, -0.1, 0.0, 1.0)));
|
||||||
assert!(!is_valid_srgb(Srgb::new(-0.0, 0.0, -0.1)));
|
assert!(!is_valid_srgb(Srgba::new(-0.0, 0.0, -0.1, 1.0)));
|
||||||
assert!(!is_valid_srgb(Srgb::new(-100.1, 0.0, 0.0)));
|
assert!(!is_valid_srgb(Srgba::new(-100.1, 0.0, 0.0, 1.0)));
|
||||||
assert!(!is_valid_srgb(Srgb::new(0.0, -100.1, 0.0)));
|
assert!(!is_valid_srgb(Srgba::new(0.0, -100.1, 0.0, 1.0)));
|
||||||
assert!(!is_valid_srgb(Srgb::new(-0.0, 0.0, -100.1)));
|
assert!(!is_valid_srgb(Srgba::new(-0.0, 0.0, -100.1, 1.0)));
|
||||||
assert!(!is_valid_srgb(Srgb::new(1.1, 0.0, 0.0)));
|
assert!(!is_valid_srgb(Srgba::new(1.1, 0.0, 0.0, 1.0)));
|
||||||
assert!(!is_valid_srgb(Srgb::new(0.0, 1.1, 0.0)));
|
assert!(!is_valid_srgb(Srgba::new(0.0, 1.1, 0.0, 1.0)));
|
||||||
assert!(!is_valid_srgb(Srgb::new(-0.0, 0.0, 1.1)));
|
assert!(!is_valid_srgb(Srgba::new(-0.0, 0.0, 1.1, 1.0)));
|
||||||
assert!(!is_valid_srgb(Srgb::new(100.1, 0.0, 0.0)));
|
assert!(!is_valid_srgb(Srgba::new(100.1, 0.0, 0.0, 1.0)));
|
||||||
assert!(!is_valid_srgb(Srgb::new(0.0, 100.1, 0.0)));
|
assert!(!is_valid_srgb(Srgba::new(0.0, 100.1, 0.0, 1.0)));
|
||||||
assert!(!is_valid_srgb(Srgb::new(-0.0, 0.0, 100.1)));
|
assert!(!is_valid_srgb(Srgba::new(-0.0, 0.0, 100.1, 1.0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_conversion_boundaries() {
|
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);
|
let srgb = oklch_to_srgba_nearest_chroma(c1);
|
||||||
equal(srgb.red, 0.0);
|
equal(srgb.red, 0.0);
|
||||||
equal(srgb.blue, 0.0);
|
equal(srgb.blue, 0.0);
|
||||||
equal(srgb.green, 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);
|
let srgb = oklch_to_srgba_nearest_chroma(c1);
|
||||||
|
|
||||||
equal(srgb.red, 1.0);
|
equal(srgb.red, 1.0);
|
||||||
|
|
@ -95,20 +95,20 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_conversion_colors() {
|
fn test_conversion_colors() {
|
||||||
let c1 = palette::Oklch::new(0.4608, 0.11111, OklabHue::new(57.31));
|
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::<u8>();
|
let srgb = oklch_to_srgba_nearest_chroma(c1).into_format::<u8, u8>();
|
||||||
assert!(srgb.red == 133);
|
assert!(srgb.red == 133);
|
||||||
assert!(srgb.green == 69);
|
assert!(srgb.green == 69);
|
||||||
assert!(srgb.blue == 0);
|
assert!(srgb.blue == 0);
|
||||||
|
|
||||||
let c1 = palette::Oklch::new(0.30, 0.08, OklabHue::new(35.0));
|
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::<u8>();
|
let srgb = oklch_to_srgba_nearest_chroma(c1).into_format::<u8, u8>();
|
||||||
assert!(srgb.red == 78);
|
assert!(srgb.red == 78);
|
||||||
assert!(srgb.green == 27);
|
assert!(srgb.green == 27);
|
||||||
assert!(srgb.blue == 15);
|
assert!(srgb.blue == 15);
|
||||||
|
|
||||||
let c1 = palette::Oklch::new(0.757, 0.146, OklabHue::new(301.2));
|
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::<u8>();
|
let srgb = oklch_to_srgba_nearest_chroma(c1).into_format::<u8, u8>();
|
||||||
assert!(srgb.red == 192);
|
assert!(srgb.red == 192);
|
||||||
assert!(srgb.green == 153);
|
assert!(srgb.green == 153);
|
||||||
assert!(srgb.blue == 253);
|
assert!(srgb.blue == 253);
|
||||||
|
|
@ -116,20 +116,20 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_conversion_fallback_colors() {
|
fn test_conversion_fallback_colors() {
|
||||||
let c1 = palette::Oklch::new(0.70, 0.284, OklabHue::new(35.0));
|
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::<u8>();
|
let srgb = oklch_to_srgba_nearest_chroma(c1).into_format::<u8, u8>();
|
||||||
assert!(srgb.red == 255);
|
assert!(srgb.red == 255);
|
||||||
assert!(srgb.green == 103);
|
assert!(srgb.green == 103);
|
||||||
assert!(srgb.blue == 65);
|
assert!(srgb.blue == 65);
|
||||||
|
|
||||||
let c1 = palette::Oklch::new(0.757, 0.239, OklabHue::new(301.2));
|
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::<u8>();
|
let srgb = oklch_to_srgba_nearest_chroma(c1).into_format::<u8, u8>();
|
||||||
assert!(srgb.red == 193);
|
assert!(srgb.red == 193);
|
||||||
assert!(srgb.green == 152);
|
assert!(srgb.green == 152);
|
||||||
assert!(srgb.blue == 255);
|
assert!(srgb.blue == 255);
|
||||||
|
|
||||||
let c1 = palette::Oklch::new(0.163, 0.333, OklabHue::new(141.0));
|
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::<u8>();
|
let srgb = oklch_to_srgba_nearest_chroma(c1).into_format::<u8, u8>();
|
||||||
assert!(srgb.red == 1);
|
assert!(srgb.red == 1);
|
||||||
assert!(srgb.green == 19);
|
assert!(srgb.green == 19);
|
||||||
assert!(srgb.blue == 0);
|
assert!(srgb.blue == 0);
|
||||||
|
|
|
||||||
|
|
@ -44,13 +44,12 @@ use palette::Srgba;
|
||||||
pub type CosmicColor = ::palette::rgb::Srgba;
|
pub type CosmicColor = ::palette::rgb::Srgba;
|
||||||
pub type CosmicComponent = cosmic_theme::Component<CosmicColor>;
|
pub type CosmicComponent = cosmic_theme::Component<CosmicColor>;
|
||||||
pub type CosmicTheme = cosmic_theme::Theme<CosmicColor>;
|
pub type CosmicTheme = cosmic_theme::Theme<CosmicColor>;
|
||||||
pub 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 = CosmicTheme::dark_default();
|
||||||
pub static ref COSMIC_HC_DARK: CosmicTheme = CosmicThemeCss::high_contrast_dark_default().into_srgba();
|
pub static ref COSMIC_HC_DARK: CosmicTheme = CosmicTheme::high_contrast_dark_default();
|
||||||
pub static ref COSMIC_LIGHT: CosmicTheme = CosmicThemeCss::light_default().into_srgba();
|
pub static ref COSMIC_LIGHT: CosmicTheme = CosmicTheme::light_default();
|
||||||
pub static ref COSMIC_HC_LIGHT: CosmicTheme = CosmicThemeCss::high_contrast_light_default().into_srgba();
|
pub static ref COSMIC_HC_LIGHT: CosmicTheme = CosmicTheme::high_contrast_light_default();
|
||||||
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),
|
||||||
|
|
@ -1202,6 +1201,7 @@ impl text_input::StyleSheet for Theme {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn theme() -> Theme {
|
pub fn theme() -> Theme {
|
||||||
let Ok(helper) = crate::cosmic_config::Config::new(
|
let Ok(helper) = crate::cosmic_config::Config::new(
|
||||||
crate::cosmic_theme::NAME,
|
crate::cosmic_theme::NAME,
|
||||||
|
|
@ -1209,34 +1209,28 @@ pub fn theme() -> Theme {
|
||||||
) else {
|
) else {
|
||||||
return crate::theme::Theme::dark();
|
return crate::theme::Theme::dark();
|
||||||
};
|
};
|
||||||
let t = crate::cosmic_theme::Theme::get_entry(&helper).map_or_else(
|
let t = crate::cosmic_theme::Theme::get_entry(&helper).unwrap_or_else(|(errors, theme)| {
|
||||||
|(errors, theme)| {
|
for err in errors {
|
||||||
for err in errors {
|
tracing::error!("{:?}", err);
|
||||||
tracing::error!("{:?}", err);
|
}
|
||||||
}
|
theme
|
||||||
theme.into_srgba()
|
});
|
||||||
},
|
|
||||||
crate::cosmic_theme::Theme::into_srgba,
|
|
||||||
);
|
|
||||||
crate::theme::Theme::custom(Arc::new(t))
|
crate::theme::Theme::custom(Arc::new(t))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subscription(id: u64) -> Subscription<crate::theme::Theme> {
|
pub fn subscription(id: u64) -> Subscription<crate::theme::Theme> {
|
||||||
config_subscription::<u64, crate::cosmic_theme::Theme<CssColor>>(
|
config_subscription::<u64, crate::cosmic_theme::Theme<Srgba>>(
|
||||||
id,
|
id,
|
||||||
crate::cosmic_theme::NAME.into(),
|
crate::cosmic_theme::NAME.into(),
|
||||||
crate::cosmic_theme::Theme::<CssColor>::version(),
|
crate::cosmic_theme::Theme::<Srgba>::version(),
|
||||||
)
|
)
|
||||||
.map(|(_, res)| {
|
.map(|(_, res)| {
|
||||||
let theme = res.map_or_else(
|
let theme = res.unwrap_or_else(|(errors, theme)| {
|
||||||
|(errors, theme)| {
|
for err in errors {
|
||||||
for err in errors {
|
tracing::error!("{:?}", err);
|
||||||
tracing::error!("{:?}", err);
|
}
|
||||||
}
|
theme
|
||||||
theme.into_srgba()
|
});
|
||||||
},
|
|
||||||
crate::cosmic_theme::Theme::into_srgba,
|
|
||||||
);
|
|
||||||
crate::theme::Theme::custom(Arc::new(theme))
|
crate::theme::Theme::custom(Arc::new(theme))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue