Compare commits

..

6 commits

Author SHA1 Message Date
Ashley Wulber
1b74c6f999 wip: blurred transparency 2026-04-13 11:04:55 -04:00
Ashley Wulber
ded784a4e3 chore: update qt light default kcolorscheme
this was likely off by one because of a rounding change from v1
2026-04-08 16:20:29 -04:00
Ashley Wulber
99e196cc79 chore: update ron files 2026-04-08 16:20:29 -04:00
Ashley Wulber
141bbd23ec feat: hex_color serialization for the theme
can also can deserialize the previous version of the theme, so existing themes should not be affected
2026-04-08 16:20:29 -04:00
Ashley Wulber
6653157def feat(config): support for intermediate serialization/deserialization type via field attribute 2026-04-08 16:20:29 -04:00
Ashley Wulber
bec679efc9 feat(config): support for fallback to previous config version 2026-04-08 16:20:29 -04:00
26 changed files with 615 additions and 158 deletions

View file

@ -170,12 +170,12 @@ cosmic-config = { path = "cosmic-config", features = ["dbus"] }
cosmic-settings-daemon = { git = "https://github.com/pop-os/dbus-settings-bindings" } cosmic-settings-daemon = { git = "https://github.com/pop-os/dbus-settings-bindings" }
zbus = { version = "5.14.0", default-features = false } zbus = { version = "5.14.0", default-features = false }
[target.'cfg(all(unix, not(target_os = "macos")))'.dependencies] [target.'cfg(unix)'.dependencies]
freedesktop-icons = { package = "cosmic-freedesktop-icons", git = "https://github.com/pop-os/freedesktop-icons" } freedesktop-icons = { package = "cosmic-freedesktop-icons", git = "https://github.com/pop-os/freedesktop-icons" }
freedesktop-desktop-entry = { version = "0.8.1", optional = true } freedesktop-desktop-entry = { version = "0.8.1", optional = true }
shlex = { version = "1.3.0", optional = true } shlex = { version = "1.3.0", optional = true }
[target.'cfg(any(not(unix), target_os = "macos"))'.dependencies] [target.'cfg(not(unix))'.dependencies]
# Used to embed bundled icons for non-unix platforms. # Used to embed bundled icons for non-unix platforms.
phf = { version = "0.13.1", features = ["macros"] } phf = { version = "0.13.1", features = ["macros"] }

View file

@ -3,9 +3,7 @@ use std::env;
fn main() { fn main() {
println!("cargo::rerun-if-changed=build.rs"); println!("cargo::rerun-if-changed=build.rs");
if env::var_os("CARGO_CFG_UNIX").is_none() if env::var_os("CARGO_CFG_UNIX").is_none() {
|| env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("macos")
{
generate_bundled_icons(); generate_bundled_icons();
} }
} }

View file

@ -1,8 +1,8 @@
use proc_macro::TokenStream; use proc_macro::TokenStream;
use quote::quote; use quote::quote;
use syn::{self}; use syn;
#[proc_macro_derive(CosmicConfigEntry, attributes(version, id))] #[proc_macro_derive(CosmicConfigEntry, attributes(version, id, cosmic_config_entry))]
pub fn cosmic_config_entry_derive(input: TokenStream) -> TokenStream { pub fn cosmic_config_entry_derive(input: TokenStream) -> TokenStream {
// Construct a representation of Rust code as a syntax tree // Construct a representation of Rust code as a syntax tree
// that we can manipulate // that we can manipulate
@ -12,6 +12,25 @@ pub fn cosmic_config_entry_derive(input: TokenStream) -> TokenStream {
impl_cosmic_config_entry_macro(&ast) impl_cosmic_config_entry_macro(&ast)
} }
fn get_cosmic_config_attrs(field: &syn::Field) -> Result<Option<syn::Type>, syn::Error> {
let mut with = None;
for attr in &field.attrs {
if !attr.path().is_ident("cosmic_config_entry") {
continue;
}
attr.parse_nested_meta(|meta| {
if meta.path.is_ident("with") {
let value = meta.value()?;
with = Some(value.parse()?);
}
Ok(())
})?;
}
Ok(with)
}
fn impl_cosmic_config_entry_macro(ast: &syn::DeriveInput) -> TokenStream { fn impl_cosmic_config_entry_macro(ast: &syn::DeriveInput) -> TokenStream {
let attributes = &ast.attrs; let attributes = &ast.attrs;
let version = attributes let version = attributes
@ -48,19 +67,54 @@ fn impl_cosmic_config_entry_macro(ast: &syn::DeriveInput) -> TokenStream {
let write_each_config_field = fields.iter().map(|field| { let write_each_config_field = fields.iter().map(|field| {
let field_name = &field.ident; let field_name = &field.ident;
quote! { let with = match get_cosmic_config_attrs(field) {
cosmic_config::ConfigSet::set(&tx, stringify!(#field_name), &self.#field_name)?; Ok(attrs) => attrs,
Err(e) => {
return e.to_compile_error();
}
};
if let Some(with) = with {
quote! {
{
let conv = self.#field_name.clone().into();
cosmic_config::ConfigSet::set::<#with>(&tx, stringify!(#field_name), conv)?;
}
}
} else {
quote! {
cosmic_config::ConfigSet::set(&tx, stringify!(#field_name), &self.#field_name)?;
}
} }
}); });
let get_each_config_field = fields.iter().map(|field| { let get_each_config_field = fields.iter().map(|field| {
let field_name = &field.ident; let field_name = &field.ident;
let field_type = &field.ty; let field_type = &field.ty;
quote! { let with = match get_cosmic_config_attrs(field) {
match cosmic_config::ConfigGet::get::<#field_type>(config, stringify!(#field_name)) { Ok(attrs) => attrs,
Ok(#field_name) => default.#field_name = #field_name, Err(e) => {
Err(why) if matches!(why, cosmic_config::Error::NoConfigDirectory) => (), return e.to_compile_error();
Err(e) => errors.push(e), }
};
if let Some(with) = with {
quote! {
match cosmic_config::ConfigGet::get::<#with>(config, stringify!(#field_name)) {
Ok(value) => {
default.#field_name = value.into();
}
Err(why) if matches!(why, cosmic_config::Error::NoConfigDirectory) => (),
Err(e) => errors.push(e),
}
}
} else {
quote! {
match cosmic_config::ConfigGet::get::<#field_type>(config, stringify!(#field_name)) {
Ok(#field_name) => default.#field_name = #field_name,
Err(why) if matches!(why, cosmic_config::Error::NoConfigDirectory) => (),
Err(e) => errors.push(e),
}
} }
} }
}); });
@ -68,17 +122,39 @@ fn impl_cosmic_config_entry_macro(ast: &syn::DeriveInput) -> TokenStream {
let update_each_config_field = fields.iter().map(|field| { let update_each_config_field = fields.iter().map(|field| {
let field_name = &field.ident; let field_name = &field.ident;
let field_type = &field.ty; let field_type = &field.ty;
quote! { let with = match get_cosmic_config_attrs(field) {
stringify!(#field_name) => { Ok(attrs) => attrs,
match cosmic_config::ConfigGet::get::<#field_type>(config, stringify!(#field_name)) { Err(e) => {
Ok(value) => { return e.to_compile_error();
if self.#field_name != value { }
keys.push(stringify!(#field_name)); };
}
self.#field_name = value; if let Some(with) = with {
}, quote! {
Err(e) => { stringify!(#field_name) => {
errors.push(e); match cosmic_config::ConfigGet::get::<#with>(config, stringify!(#field_name)) {
Ok(value) => {
let value = value.into();
if self.#field_name != value {
keys.push(stringify!(#field_name));
}
self.#field_name = value;
},
Err(e) => errors.push(e),
}
}
}
} else {
quote! {
stringify!(#field_name) => {
match cosmic_config::ConfigGet::get::<#field_type>(config, stringify!(#field_name)) {
Ok(value) => {
if self.#field_name != value {
keys.push(stringify!(#field_name));
}
self.#field_name = value;
},
Err(e) => errors.push(e),
} }
} }
} }

View file

@ -162,6 +162,7 @@ pub trait ConfigSet {
pub struct Config { pub struct Config {
system_path: Option<PathBuf>, system_path: Option<PathBuf>,
user_path: Option<PathBuf>, user_path: Option<PathBuf>,
previous: Option<Box<Config>>,
} }
/// Check that the name is relative and doesn't contain . or .. /// Check that the name is relative and doesn't contain . or ..
@ -180,9 +181,13 @@ fn sanitize_name(name: &str) -> Result<&Path, Error> {
impl Config { impl Config {
/// Get a system config for the given name and config version /// Get a system config for the given name and config version
pub fn system(name: &str, version: u64) -> Result<Self, Error> { pub fn system(name: &str, version: u64) -> Result<Self, Error> {
Self::system_inner(name, version, true)
}
fn system_inner(name: &str, version: u64, look_for_previous: bool) -> Result<Self, Error> {
let path = sanitize_name(name)?.join(format!("v{version}")); let path = sanitize_name(name)?.join(format!("v{version}"));
#[cfg(unix)] #[cfg(unix)]
let system_path = xdg::BaseDirectories::with_prefix("cosmic").find_data_file(path); let system_path = xdg::BaseDirectories::with_prefix("cosmic").find_data_file(&path);
#[cfg(windows)] #[cfg(windows)]
let system_path = let system_path =
@ -192,6 +197,13 @@ impl Config {
Ok(Self { Ok(Self {
system_path, system_path,
user_path: None, user_path: None,
previous: if version > 1 && look_for_previous {
Self::system_inner(name, version - 1, false)
.ok()
.map(Box::new)
} else {
None
},
}) })
} }
@ -199,6 +211,10 @@ impl Config {
// Use folder at XDG config/name for config storage, return Config if successful // Use folder at XDG config/name for config storage, return Config if successful
//TODO: fallbacks for flatpak (HOST_XDG_CONFIG_HOME, xdg-desktop settings proxy) //TODO: fallbacks for flatpak (HOST_XDG_CONFIG_HOME, xdg-desktop settings proxy)
pub fn new(name: &str, version: u64) -> Result<Self, Error> { pub fn new(name: &str, version: u64) -> Result<Self, Error> {
Self::new_inner(name, version, true)
}
fn new_inner(name: &str, version: u64, look_for_previous: bool) -> Result<Self, Error> {
// Look for [name]/v[version] // Look for [name]/v[version]
let path = sanitize_name(name)?.join(format!("v{}", version)); let path = sanitize_name(name)?.join(format!("v{}", version));
@ -223,15 +239,29 @@ impl Config {
Ok(Self { Ok(Self {
system_path, system_path,
user_path: Some(user_path), user_path: Some(user_path),
previous: if version > 1 && look_for_previous {
Self::new_inner(name, version - 1, false).ok().map(Box::new)
} else {
None
},
}) })
} }
/// Get config for the given application name and config version and custom path. /// Get config for the given application name and config version and custom path.
pub fn with_custom_path(name: &str, version: u64, custom_path: PathBuf) -> Result<Self, Error> { pub fn with_custom_path(name: &str, version: u64, custom_path: PathBuf) -> Result<Self, Error> {
Self::with_custom_path_inner(name, version, custom_path, true)
}
fn with_custom_path_inner(
name: &str,
version: u64,
custom_path: PathBuf,
look_for_previous: bool,
) -> Result<Self, Error> {
// Look for [name]/v[version] // Look for [name]/v[version]
let path = sanitize_name(name)?.join(format!("v{version}")); let path = sanitize_name(name)?.join(format!("v{version}"));
let mut user_path = custom_path; let mut user_path = custom_path.clone();
user_path.push("cosmic"); user_path.push("cosmic");
user_path.push(path); user_path.push(path);
// Create new configuration directory if not found. // Create new configuration directory if not found.
@ -241,6 +271,13 @@ impl Config {
Ok(Self { Ok(Self {
system_path: None, system_path: None,
user_path: Some(user_path), user_path: Some(user_path),
previous: if version > 1 && look_for_previous {
Self::with_custom_path_inner(name, version - 1, custom_path.clone(), false)
.ok()
.map(Box::new)
} else {
None
},
}) })
} }
@ -250,6 +287,10 @@ impl Config {
// Use folder at XDG config/name for config storage, return Config if successful // Use folder at XDG config/name for config storage, return Config if successful
//TODO: fallbacks for flatpak (HOST_XDG_CONFIG_HOME, xdg-desktop settings proxy) //TODO: fallbacks for flatpak (HOST_XDG_CONFIG_HOME, xdg-desktop settings proxy)
pub fn new_state(name: &str, version: u64) -> Result<Self, Error> { pub fn new_state(name: &str, version: u64) -> Result<Self, Error> {
Self::new_state_inner(name, version, true)
}
fn new_state_inner(name: &str, version: u64, look_for_previous: bool) -> Result<Self, Error> {
// Look for [name]/v[version] // Look for [name]/v[version]
let path = sanitize_name(name)?.join(format!("v{}", version)); let path = sanitize_name(name)?.join(format!("v{}", version));
@ -263,6 +304,13 @@ impl Config {
Ok(Self { Ok(Self {
system_path: None, system_path: None,
user_path: Some(user_path), user_path: Some(user_path),
previous: if version > 1 && look_for_previous {
Self::new_state_inner(name, version - 1, false)
.ok()
.map(Box::new)
} else {
None
},
}) })
} }
@ -373,7 +421,13 @@ impl ConfigGet for Config {
Ok(ron::from_str(&data)?) Ok(ron::from_str(&data)?)
} }
_ => Err(Error::NotFound), _ => {
if let Some(previous) = self.previous.as_ref() {
previous.get_local(key)
} else {
Err(Error::NotFound)
}
}
} }
} }

View file

@ -15,6 +15,7 @@ export = ["serde_json"]
no-default = [] no-default = []
[dependencies] [dependencies]
hex_color = { version = "3", features = ["serde"] }
palette = { version = "0.7.6", features = ["serializing"] } palette = { version = "0.7.6", features = ["serializing"] }
almost = "0.2" almost = "0.2"
serde = { version = "1.0.228", features = ["derive"] } serde = { version = "1.0.228", features = ["derive"] }

View file

@ -0,0 +1,173 @@
//! Color representation and serde helpers for the Cosmic theme
use hex_color::HexColor;
use palette::{Srgb, Srgba};
use serde::{Deserialize, Serialize};
/// A color in the Cosmic theme for serialization and deserialization
#[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize)]
#[serde(untagged)]
pub enum ColorRepr {
/// A color represented as a hex string
#[serde(with = "hex_color::rgba")]
Hex(HexColor),
/// A color represented as an RGBA value
Rgba(Srgba),
/// A color represented as an RGB value
Rgb(Srgb),
}
/// An optional color in the Cosmic theme for serialization and deserialization
#[repr(transparent)]
#[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize)]
#[serde(transparent)]
pub struct ColorReprOption(Option<ColorRepr>);
impl From<Srgb> for ColorRepr {
fn from(color: Srgb) -> Self {
let rgb_u8: Srgb<u8> = color.into_format();
ColorRepr::Hex(HexColor {
r: rgb_u8.red,
g: rgb_u8.green,
b: rgb_u8.blue,
a: 255,
})
}
}
impl From<Srgba> for ColorRepr {
fn from(color: Srgba) -> Self {
let rgba_u8: Srgba<u8> = color.into_format();
ColorRepr::Hex(HexColor {
r: rgba_u8.red,
g: rgba_u8.green,
b: rgba_u8.blue,
a: rgba_u8.alpha,
})
}
}
impl From<ColorRepr> for Srgb {
fn from(value: ColorRepr) -> Self {
match value {
ColorRepr::Hex(hex) => Srgb::<u8>::new(hex.r, hex.g, hex.b).into_format(),
ColorRepr::Rgb(rgb) => rgb,
ColorRepr::Rgba(rgba) => Srgb::new(rgba.red, rgba.green, rgba.blue),
}
}
}
impl From<ColorRepr> for Srgba {
fn from(value: ColorRepr) -> Self {
match value {
ColorRepr::Hex(hex) => Srgba::<u8>::new(hex.r, hex.g, hex.b, hex.a).into_format(),
ColorRepr::Rgb(rgb) => Srgba::new(rgb.red, rgb.green, rgb.blue, 1.0),
ColorRepr::Rgba(rgba) => rgba,
}
}
}
impl From<ColorReprOption> for Option<Srgb> {
fn from(value: ColorReprOption) -> Self {
value.0.map(std::convert::Into::into)
}
}
impl From<ColorReprOption> for Option<Srgba> {
fn from(value: ColorReprOption) -> Self {
value.0.map(std::convert::Into::into)
}
}
impl From<Option<Srgb>> for ColorReprOption {
fn from(value: Option<Srgb>) -> Self {
ColorReprOption(value.map(std::convert::Into::into))
}
}
impl From<Option<Srgba>> for ColorReprOption {
fn from(value: Option<Srgba>) -> Self {
ColorReprOption(value.map(std::convert::Into::into))
}
}
/// A trait for converting between a color type and its representation for serialization and deserialization
pub trait ConvColorRepr: Sized {
/// Convert from a color representation to the color type
fn from_repr(repr: ColorRepr) -> Self;
/// Convert from the color type to its representation for serialization
fn to_repr(&self) -> ColorRepr;
}
impl ConvColorRepr for Srgba {
fn from_repr(repr: ColorRepr) -> Self {
repr.into()
}
fn to_repr(&self) -> ColorRepr {
(*self).into()
}
}
impl ConvColorRepr for Srgb {
fn from_repr(repr: ColorRepr) -> Self {
repr.into()
}
fn to_repr(&self) -> ColorRepr {
(*self).into()
}
}
/// Serde helpers for serializing and deserializing colors in the Cosmic theme
pub mod color_serde {
use super::*;
use serde::{Deserialize, Deserializer, Serializer};
/// Serialize a color to a hex string
pub fn serialize<T, S>(color: &T, serializer: S) -> Result<S::Ok, S::Error>
where
T: ConvColorRepr,
S: Serializer,
{
let repr = color.to_repr();
repr.serialize(serializer)
}
/// Deserialize a color from a hex string or RGB/RGBA
pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
where
T: ConvColorRepr,
D: Deserializer<'de>,
{
let repr = ColorRepr::deserialize(deserializer)?;
Ok(T::from_repr(repr))
}
/// Serde helpers for serializing and deserializing optional colors in the Cosmic theme
pub mod option {
use super::*;
/// Serialize an optional color
pub fn serialize<T, S>(value: &Option<T>, serializer: S) -> Result<S::Ok, S::Error>
where
T: ConvColorRepr,
S: Serializer,
{
match value {
Some(v) => super::serialize(v, serializer),
None => serializer.serialize_none(),
}
}
/// Deserialize an optional color
pub fn deserialize<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
where
T: ConvColorRepr,
D: Deserializer<'de>,
{
let opt = Option::<ColorRepr>::deserialize(deserializer)?;
Ok(opt.map(T::from_repr))
}
}
}

View file

@ -1,3 +1,4 @@
use crate::color::color_serde;
use palette::Srgba; use palette::Srgba;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::sync::LazyLock; use std::sync::LazyLock;
@ -95,75 +96,107 @@ pub struct CosmicPaletteInner {
/// Utility Colors /// Utility Colors
/// Colors used for various points of emphasis in the UI. /// Colors used for various points of emphasis in the UI.
#[serde(with = "color_serde")]
pub bright_red: Srgba, pub bright_red: Srgba,
/// Colors used for various points of emphasis in the UI. /// Colors used for various points of emphasis in the UI.
#[serde(with = "color_serde")]
pub bright_green: Srgba, pub bright_green: Srgba,
/// Colors used for various points of emphasis in the UI. /// Colors used for various points of emphasis in the UI.
#[serde(with = "color_serde")]
pub bright_orange: Srgba, pub bright_orange: Srgba,
/// Surface Grays /// Surface Grays
/// Colors used for three levels of surfaces in the UI. /// Colors used for three levels of surfaces in the UI.
#[serde(with = "color_serde")]
pub gray_1: Srgba, pub gray_1: Srgba,
/// Colors used for three levels of surfaces in the UI. /// Colors used for three levels of surfaces in the UI.
#[serde(with = "color_serde")]
pub gray_2: Srgba, pub gray_2: Srgba,
/// System Neutrals /// System Neutrals
/// A wider spread of dark colors for more general use. /// A wider spread of dark colors for more general use.
#[serde(with = "color_serde")]
pub neutral_0: Srgba, pub neutral_0: Srgba,
/// A wider spread of dark colors for more general use. /// A wider spread of dark colors for more general use.
#[serde(with = "color_serde")]
pub neutral_1: Srgba, pub neutral_1: Srgba,
/// A wider spread of dark colors for more general use. /// A wider spread of dark colors for more general use.
#[serde(with = "color_serde")]
pub neutral_2: Srgba, pub neutral_2: Srgba,
/// A wider spread of dark colors for more general use. /// A wider spread of dark colors for more general use.
#[serde(with = "color_serde")]
pub neutral_3: Srgba, pub neutral_3: Srgba,
/// A wider spread of dark colors for more general use. /// A wider spread of dark colors for more general use.
#[serde(with = "color_serde")]
pub neutral_4: Srgba, pub neutral_4: Srgba,
/// A wider spread of dark colors for more general use. /// A wider spread of dark colors for more general use.
#[serde(with = "color_serde")]
pub neutral_5: Srgba, pub neutral_5: Srgba,
/// A wider spread of dark colors for more general use. /// A wider spread of dark colors for more general use.
#[serde(with = "color_serde")]
pub neutral_6: Srgba, pub neutral_6: Srgba,
/// A wider spread of dark colors for more general use. /// A wider spread of dark colors for more general use.
#[serde(with = "color_serde")]
pub neutral_7: Srgba, pub neutral_7: Srgba,
/// A wider spread of dark colors for more general use. /// A wider spread of dark colors for more general use.
#[serde(with = "color_serde")]
pub neutral_8: Srgba, pub neutral_8: Srgba,
/// A wider spread of dark colors for more general use. /// A wider spread of dark colors for more general use.
#[serde(with = "color_serde")]
pub neutral_9: Srgba, pub neutral_9: Srgba,
/// A wider spread of dark colors for more general use. /// A wider spread of dark colors for more general use.
#[serde(with = "color_serde")]
pub neutral_10: Srgba, pub neutral_10: Srgba,
/// Potential Accent Color Combos /// Potential Accent Color Combos
#[serde(with = "color_serde")]
pub accent_blue: Srgba, pub accent_blue: Srgba,
/// Potential Accent Color Combos /// Potential Accent Color Combos
#[serde(with = "color_serde")]
pub accent_indigo: Srgba, pub accent_indigo: Srgba,
/// Potential Accent Color Combos /// Potential Accent Color Combos
#[serde(with = "color_serde")]
pub accent_purple: Srgba, pub accent_purple: Srgba,
/// Potential Accent Color Combos /// Potential Accent Color Combos
#[serde(with = "color_serde")]
pub accent_pink: Srgba, pub accent_pink: Srgba,
/// Potential Accent Color Combos /// Potential Accent Color Combos
#[serde(with = "color_serde")]
pub accent_red: Srgba, pub accent_red: Srgba,
/// Potential Accent Color Combos /// Potential Accent Color Combos
#[serde(with = "color_serde")]
pub accent_orange: Srgba, pub accent_orange: Srgba,
/// Potential Accent Color Combos /// Potential Accent Color Combos
#[serde(with = "color_serde")]
pub accent_yellow: Srgba, pub accent_yellow: Srgba,
/// Potential Accent Color Combos /// Potential Accent Color Combos
#[serde(with = "color_serde")]
pub accent_green: Srgba, pub accent_green: Srgba,
/// Potential Accent Color Combos /// Potential Accent Color Combos
#[serde(with = "color_serde")]
pub accent_warm_grey: Srgba, pub accent_warm_grey: Srgba,
/// Extended Color Palette /// Extended Color Palette
/// Colors used for themes, app icons, illustrations, and other brand purposes. /// Colors used for themes, app icons, illustrations, and other brand purposes.
#[serde(with = "color_serde")]
pub ext_warm_grey: Srgba, pub ext_warm_grey: Srgba,
/// Colors used for themes, app icons, illustrations, and other brand purposes. /// Colors used for themes, app icons, illustrations, and other brand purposes.
#[serde(with = "color_serde")]
pub ext_orange: Srgba, pub ext_orange: Srgba,
/// Colors used for themes, app icons, illustrations, and other brand purposes. /// Colors used for themes, app icons, illustrations, and other brand purposes.
#[serde(with = "color_serde")]
pub ext_yellow: Srgba, pub ext_yellow: Srgba,
/// Colors used for themes, app icons, illustrations, and other brand purposes. /// Colors used for themes, app icons, illustrations, and other brand purposes.
#[serde(with = "color_serde")]
pub ext_blue: Srgba, pub ext_blue: Srgba,
/// Colors used for themes, app icons, illustrations, and other brand purposes. /// Colors used for themes, app icons, illustrations, and other brand purposes.
#[serde(with = "color_serde")]
pub ext_purple: Srgba, pub ext_purple: Srgba,
/// Colors used for themes, app icons, illustrations, and other brand purposes. /// Colors used for themes, app icons, illustrations, and other brand purposes.
#[serde(with = "color_serde")]
pub ext_pink: Srgba, pub ext_pink: Srgba,
/// Colors used for themes, app icons, illustrations, and other brand purposes. /// Colors used for themes, app icons, illustrations, and other brand purposes.
#[serde(with = "color_serde")]
pub ext_indigo: Srgba, pub ext_indigo: Srgba,
} }

View file

@ -1 +1 @@
Dark((name:"cosmic-dark",bright_red:(red:1.0,green:0.62745098,blue:0.60392157,alpha:1.0),bright_green:(red:0.36862745,green:0.85882352,blue:0.54901960,alpha:1.0),bright_orange:(red:1.0,green:0.63921569,blue:0.49019608,alpha:1.0),gray_1:(red:0.10588235,green:0.10588235,blue:0.10588235,alpha:1.0),gray_2:(red:0.14901961,green:0.14901961,blue:0.14901961,alpha:1.0),neutral_0:(red:0.0,green:0.0,blue:0.0,alpha:1.0),neutral_1:(red:0.01176471,green:0.01176471,blue:0.01176471,alpha:1.0),neutral_2:(red:0.08627451,green:0.08627451,blue:0.08627451,alpha:1.0),neutral_3:(red:0.18039216,green:0.18039216,blue:0.18039216,alpha:1.0),neutral_4:(red:0.28235294,green:0.28235294,blue:0.28235294,alpha:1.0),neutral_5:(red:0.38823529,green:0.38823529,blue:0.38823529,alpha:1.0),neutral_6:(red:0.50196078,green:0.50196078,blue:0.50196078,alpha:1.0),neutral_7:(red:0.61960784,green:0.61960784,blue:0.61960784,alpha:1.0),neutral_8:(red:0.74509804,green:0.74509804,blue:0.74509804,alpha:1.0),neutral_9:(red:0.87058824,green:0.87058824,blue:0.87058824,alpha:1.0),neutral_10:(red:1.0,green:1.0,blue:1.0,alpha:1.0),accent_blue:(red:0.3882353,green:0.81568627,blue:0.87450981,alpha:1.0),accent_indigo:(red:0.63137255,green:0.75294118,blue:0.92156863,alpha:1.0),accent_purple:(red:0.90588235,green:0.61176471,blue:0.99607843,alpha:1.0),accent_pink:(red:1.0,green:0.61176471,blue:0.69411765,alpha:1.0),accent_red:(red:0.99215686,green:0.63137255,blue:0.62745098,alpha:1.0),accent_orange:(red:1.0,green:0.67843137,blue:0.0,alpha:1.0),accent_yellow:(red:0.96862745,green:0.87843137,blue:0.38431373,alpha:1.0),accent_green:(red:0.57254902,green:0.81176471,blue:0.61176471,alpha:1.0),accent_warm_grey:(red:0.79215686,green:0.72941176,blue:0.70588235,alpha:1.0),ext_warm_grey:(red:0.60784314,green:0.55686275,blue:0.54117647,alpha:1.0),ext_orange:(red:1.0,green:0.67843137,blue:0.0,alpha:1.0),ext_yellow:(red:0.99607843,green:0.85882353,blue:0.25098039,alpha:1.0),ext_blue:(red:0.28235294,green:0.72549020,blue:0.78039216,alpha:1.0),ext_purple:(red:0.81176471,green:0.49019608,blue:1.0,alpha:1.0),ext_pink:(red:0.97647059,green:0.22745098,blue:0.51372549,alpha:1.0),ext_indigo:(red:0.24313725,green:0.53333333,blue:1.0,alpha:1.0))) Dark((name: "cosmic-dark",bright_red: "#FFA09AFF",bright_green: "#5EDB8CFF",bright_orange: "#FFA37DFF",gray_1: "#1B1B1BFF",gray_2: "#262626FF",neutral_0: "#000000FF",neutral_1: "#030303FF",neutral_2: "#161616FF",neutral_3: "#2E2E2EFF",neutral_4: "#484848FF",neutral_5: "#636363FF",neutral_6: "#808080FF",neutral_7: "#9E9E9EFF",neutral_8: "#BEBEBEFF",neutral_9: "#DEDEDEFF",neutral_10: "#FFFFFFFF",accent_blue: "#63D0DFFF",accent_indigo: "#A1C0EBFF",accent_purple: "#E79CFEFF",accent_pink: "#FF9CB1FF",accent_red: "#FDA1A0FF",accent_orange: "#FFAD00FF",accent_yellow: "#F7E062FF",accent_green: "#92CF9CFF",accent_warm_grey: "#CABAB4FF",ext_warm_grey: "#9B8E8AFF",ext_orange: "#FFAD00FF",ext_yellow: "#FEDB40FF",ext_blue: "#48B9C7FF",ext_purple: "#CF7DFFFF",ext_pink: "#F93A83FF",ext_indigo: "#3E88FFFF",))

View file

@ -1,3 +1,4 @@
use crate::color::color_serde;
use palette::{Srgba, WithAlpha}; use palette::{Srgba, WithAlpha};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -8,14 +9,18 @@ use crate::composite::over;
#[must_use] #[must_use]
pub struct Container { pub struct Container {
/// the color of the container /// the color of the container
#[serde(with = "color_serde")]
pub base: Srgba, pub base: Srgba,
/// the color of components in the container /// the color of components in the container
pub component: Component, pub component: Component,
/// the color of dividers in the container /// the color of dividers in the container
#[serde(with = "color_serde")]
pub divider: Srgba, pub divider: Srgba,
/// the color of text in the container /// the color of text in the container
#[serde(with = "color_serde")]
pub on: Srgba, pub on: Srgba,
/// the color of @small_widget_container /// the color of @small_widget_container
#[serde(with = "color_serde")]
pub small_widget: Srgba, pub small_widget: Srgba,
} }
@ -45,30 +50,42 @@ impl Container {
#[must_use] #[must_use]
pub struct Component { pub struct Component {
/// The base color of the widget /// The base color of the widget
#[serde(with = "color_serde")]
pub base: Srgba, pub base: Srgba,
/// The color of the widget when it is hovered /// The color of the widget when it is hovered
#[serde(with = "color_serde")]
pub hover: Srgba, pub hover: Srgba,
/// the color of the widget when it is pressed /// the color of the widget when it is pressed
#[serde(with = "color_serde")]
pub pressed: Srgba, pub pressed: Srgba,
/// the color of the widget when it is selected /// the color of the widget when it is selected
#[serde(with = "color_serde")]
pub selected: Srgba, pub selected: Srgba,
/// the color of the widget when it is selected /// the color of the widget when it is selected
#[serde(with = "color_serde")]
pub selected_text: Srgba, pub selected_text: Srgba,
/// the color of the widget when it is focused /// the color of the widget when it is focused
#[serde(with = "color_serde")]
pub focus: Srgba, pub focus: Srgba,
/// the color of dividers for this widget /// the color of dividers for this widget
#[serde(with = "color_serde")]
pub divider: Srgba, pub divider: Srgba,
/// the color of text for this widget /// the color of text for this widget
#[serde(with = "color_serde")]
pub on: Srgba, pub on: Srgba,
// the color of text with opacity 80 for this widget // the color of text with opacity 80 for this widget
// pub text_opacity_80: Srgba, // pub text_opacity_80: Srgba,
/// the color of the widget when it is disabled /// the color of the widget when it is disabled
#[serde(with = "color_serde")]
pub disabled: Srgba, pub disabled: Srgba,
/// the color of text in the widget when it is disabled /// the color of text in the widget when it is disabled
#[serde(with = "color_serde")]
pub on_disabled: Srgba, pub on_disabled: Srgba,
/// the color of the border for the widget /// the color of the border for the widget
#[serde(with = "color_serde")]
pub border: Srgba, pub border: Srgba,
/// the color of the border for the widget when it is disabled /// the color of the border for the widget when it is disabled
#[serde(with = "color_serde")]
pub disabled_border: Srgba, pub disabled_border: Srgba,
} }

View file

@ -1 +1 @@
Light((name:"cosmic-light",bright_red:(red:0.53725490,green:0.01568627,blue:0.09411765,alpha:1.0),bright_green:(red:0.0,green:0.34117647,blue:0.17254901,alpha:1.0),bright_orange:(red:0.47450980,green:0.17254902,blue:0.0,alpha:1.0),gray_1:(red:0.84313725,green:0.84313725,blue:0.84313725,alpha:1.0),gray_2:(red:0.89411765,green:0.89411765,blue:0.89411765,alpha:1.0),neutral_0:(red:1.0,green:1.0,blue:1.0,alpha:1.0),neutral_1:(red:0.87058824,green:0.87058824,blue:0.87058824,alpha:1.0),neutral_2:(red:0.74509804,green:0.74509804,blue:0.74509804,alpha:1.0),neutral_3:(red:0.61960784,green:0.61960784,blue:0.61960784,alpha:1.0),neutral_4:(red:0.50196078,green:0.50196078,blue:0.50196078,alpha:1.0),neutral_5:(red:0.38823529,green:0.38823529,blue:0.38823529,alpha:1.0),neutral_6:(red:0.28235294,green:0.28235294,blue:0.28235294,alpha:1.0),neutral_7:(red:0.18039216,green:0.18039216,blue:0.18039216,alpha:1.0),neutral_8:(red:0.08627451,green:0.08627451,blue:0.08627451,alpha:1.0),neutral_9:(red:0.01176471,green:0.01176471,blue:0.01176471,alpha:1.0),neutral_10:(red:0.0,green:0.0,blue:0.0,alpha:1.0),accent_blue:(red:0.0,green:0.32156863,blue:0.35294118,alpha:1.0),accent_indigo:(red:0.18039216,green:0.28627451,blue:0.42745098,alpha:1.0),accent_purple:(red:0.40784314,green:0.12941176,blue:0.48627451,alpha:1.0),accent_pink:(red:0.52549020,green:0.01568627,blue:0.22745098,alpha:1.0),accent_red:(red:0.47058824,green:0.16078431,blue:0.18039216,alpha:1.0),accent_orange:(red:0.38431373,green:0.25098039,blue:0.0,alpha:1.0),accent_yellow:(red:0.32549020,green:0.28235294,blue:0.0,alpha:1.0),accent_green:(red:0.09411765,green:0.33333333,blue:0.16078431,alpha:1.0),accent_warm_grey:(red:0.33333333,green:0.27843137,blue:0.25882353,alpha:1.0),ext_warm_grey:(red:0.60784314,green:0.55686275,blue:0.54117647,alpha:1.0),ext_orange:(red:0.98431373,green:0.72156863,blue:0.42352941,alpha:1.0),ext_yellow:(red:0.96862745,green:0.87843137,blue:0.38431373,alpha:1.0),ext_blue:(red:0.41568627,green:0.79215686,blue:0.84705882,alpha:1.0),ext_purple:(red:0.83529412,green:0.54901961,blue:1.0,alpha:1.0),ext_pink:(red:1.0,green:0.61176471,blue:0.86666667,alpha:1.0),ext_indigo:(red:0.58431373,green:0.76862745,blue:0.98823529,alpha:1.0))) Light((name: "cosmic-light",bright_red: "#890418FF",bright_green: "#00572CFF",bright_orange: "#792C00FF",gray_1: "#D7D7D7FF",gray_2: "#E4E4E4FF",neutral_0: "#FFFFFFFF",neutral_1: "#DEDEDEFF",neutral_2: "#BEBEBEFF",neutral_3: "#9E9E9EFF",neutral_4: "#808080FF",neutral_5: "#636363FF",neutral_6: "#484848FF",neutral_7: "#2E2E2EFF",neutral_8: "#161616FF",neutral_9: "#030303FF",neutral_10: "#000000FF",accent_blue: "#00525AFF",accent_indigo: "#2E496DFF",accent_purple: "#68217CFF",accent_pink: "#86043AFF",accent_red: "#78292EFF",accent_orange: "#624000FF",accent_yellow: "#534800FF",accent_green: "#185529FF",accent_warm_grey: "#554742FF",ext_warm_grey: "#9B8E8AFF",ext_orange: "#FBB86CFF",ext_yellow: "#F7E062FF",ext_blue: "#6ACAD8FF",ext_purple: "#D58CFFFF",ext_pink: "#FF9CDDFF",ext_indigo: "#95C4FCFF",))

View file

@ -6,6 +6,7 @@ pub use mode::*;
pub use spacing::*; pub use spacing::*;
pub use theme::*; pub use theme::*;
pub mod color;
mod corner; mod corner;
mod cosmic_palette; mod cosmic_palette;
mod density; mod density;

View file

@ -1,10 +1,11 @@
use crate::{ use crate::{
Component, Container, CornerRadii, CosmicPalette, CosmicPaletteInner, DARK_PALETTE, Component, Container, CornerRadii, CosmicPalette, CosmicPaletteInner, DARK_PALETTE,
LIGHT_PALETTE, NAME, Spacing, ThemeMode, LIGHT_PALETTE, NAME, Spacing, ThemeMode,
color::{ColorRepr, ColorReprOption, color_serde, color_serde::option as color_serde_option},
composite::over, composite::over,
steps::{color_index, get_small_widget_color, get_surface_color, get_text, steps}, steps::{color_index, get_small_widget_color, get_surface_color, get_text, steps},
}; };
use cosmic_config::{Config, CosmicConfigEntry}; use cosmic_config::{Config, CosmicConfigEntry, cosmic_config_derive::CosmicConfigEntry};
use palette::{ use palette::{
IntoColor, Oklcha, Srgb, Srgba, WithAlpha, color_difference::Wcag21RelativeContrast, rgb::Rgb, IntoColor, Oklcha, Srgb, Srgba, WithAlpha, color_difference::Wcag21RelativeContrast, rgb::Rgb,
}; };
@ -37,15 +38,8 @@ pub enum Layer {
#[must_use] #[must_use]
/// Cosmic Theme data structure with all colors and its name /// Cosmic Theme data structure with all colors and its name
#[derive( #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, CosmicConfigEntry)]
Clone, #[version = 2]
Debug,
Serialize,
Deserialize,
PartialEq,
cosmic_config::cosmic_config_derive::CosmicConfigEntry,
)]
#[version = 1]
pub struct Theme { pub struct Theme {
/// name of the theme /// name of the theme
pub name: String, pub name: String,
@ -96,15 +90,24 @@ pub struct Theme {
/// cosmic-comp custom window hint color /// cosmic-comp custom window hint color
pub window_hint: Option<Srgb>, pub window_hint: Option<Srgb>,
/// enables blurred transparency /// enables blurred transparency
pub is_frosted: bool, /// If None, frosted effect is disabled.
pub frosted: Option<BlurStrength>,
/// shade color for dialogs /// shade color for dialogs
#[serde(with = "color_serde")]
#[cosmic_config_entry(with = ColorRepr)]
pub shade: Srgba, pub shade: Srgba,
/// accent text colors /// accent text colors
/// If None, accent base color is the accent text color. /// If None, accent base color is the accent text color.
#[serde(with = "color_serde_option")]
#[cosmic_config_entry(with = ColorReprOption)]
pub accent_text: Option<Srgba>, pub accent_text: Option<Srgba>,
/// control tint color /// control tint color
#[serde(with = "color_serde_option")]
#[cosmic_config_entry(with = ColorReprOption)]
pub control_tint: Option<Srgb>, pub control_tint: Option<Srgb>,
/// text tint color /// text tint color
#[serde(with = "color_serde_option")]
#[cosmic_config_entry(with = ColorReprOption)]
pub text_tint: Option<Srgb>, pub text_tint: Option<Srgb>,
} }
@ -739,7 +742,7 @@ impl Theme {
if color_scheme.trim().contains("default") || color_scheme.trim().contains("light") { if color_scheme.trim().contains("default") || color_scheme.trim().contains("light") {
return Self::light_default(); return Self::light_default();
} }
}; }
Self::dark_default() Self::dark_default()
} }
@ -748,10 +751,10 @@ impl Theme {
pub fn preferred_theme() -> Self { pub fn preferred_theme() -> Self {
let current_desktop = std::env::var("XDG_CURRENT_DESKTOP"); let current_desktop = std::env::var("XDG_CURRENT_DESKTOP");
if let Ok(desktop) = current_desktop { if let Ok(desktop) = current_desktop
if desktop.trim().to_lowercase().contains("gnome") { && desktop.trim().to_lowercase().contains("gnome")
return Self::gtk_prefer_colorscheme(); {
} return Self::gtk_prefer_colorscheme();
} }
Self::dark_default() Self::dark_default()
@ -766,15 +769,8 @@ impl From<CosmicPalette> for Theme {
#[must_use] #[must_use]
/// Helper for building customized themes /// Helper for building customized themes
#[derive( #[derive(Clone, Debug, Serialize, Deserialize, CosmicConfigEntry, PartialEq)]
Clone, #[version = 2]
Debug,
Serialize,
Deserialize,
cosmic_config::cosmic_config_derive::CosmicConfigEntry,
PartialEq,
)]
#[version = 1]
pub struct ThemeBuilder { pub struct ThemeBuilder {
/// override the palette for the builder /// override the palette for the builder
pub palette: CosmicPalette, pub palette: CosmicPalette,
@ -783,30 +779,50 @@ pub struct ThemeBuilder {
/// override corner radii for the builder /// override corner radii for the builder
pub corner_radii: CornerRadii, pub corner_radii: CornerRadii,
/// override neutral_tint for the builder /// override neutral_tint for the builder
#[serde(with = "color_serde_option")]
#[cosmic_config_entry(with = ColorReprOption)]
pub neutral_tint: Option<Srgb>, pub neutral_tint: Option<Srgb>,
/// override bg_color for the builder /// override bg_color for the builder
#[serde(with = "color_serde_option")]
#[cosmic_config_entry(with = ColorReprOption)]
pub bg_color: Option<Srgba>, pub bg_color: Option<Srgba>,
/// override the primary container bg color for the builder /// override the primary container bg color for the builder
#[serde(with = "color_serde_option")]
#[cosmic_config_entry(with = ColorReprOption)]
pub primary_container_bg: Option<Srgba>, pub primary_container_bg: Option<Srgba>,
/// override the secontary container bg color for the builder /// override the secontary container bg color for the builder
#[serde(with = "color_serde_option")]
#[cosmic_config_entry(with = ColorReprOption)]
pub secondary_container_bg: Option<Srgba>, pub secondary_container_bg: Option<Srgba>,
/// override the text tint for the builder /// override the text tint for the builder
#[serde(with = "color_serde_option")]
#[cosmic_config_entry(with = ColorReprOption)]
pub text_tint: Option<Srgb>, pub text_tint: Option<Srgb>,
/// override the accent color for the builder /// override the accent color for the builder
#[serde(with = "color_serde_option")]
#[cosmic_config_entry(with = ColorReprOption)]
pub accent: Option<Srgb>, pub accent: Option<Srgb>,
/// override the success color for the builder /// override the success color for the builder
#[serde(with = "color_serde_option")]
#[cosmic_config_entry(with = ColorReprOption)]
pub success: Option<Srgb>, pub success: Option<Srgb>,
/// override the warning color for the builder /// override the warning color for the builder
#[serde(with = "color_serde_option")]
#[cosmic_config_entry(with = ColorReprOption)]
pub warning: Option<Srgb>, pub warning: Option<Srgb>,
/// override the destructive color for the builder /// override the destructive color for the builder
#[serde(with = "color_serde_option")]
#[cosmic_config_entry(with = ColorReprOption)]
pub destructive: Option<Srgb>, pub destructive: Option<Srgb>,
/// enabled blurred transparency /// enabled blurred transparency
pub is_frosted: bool, // TODO handle pub frosted: Option<BlurStrength>,
/// cosmic-comp window gaps size (outer, inner) /// cosmic-comp window gaps size (outer, inner)
pub gaps: (u32, u32), pub gaps: (u32, u32),
/// cosmic-comp active hint window outline width /// cosmic-comp active hint window outline width
pub active_hint: u32, pub active_hint: u32,
/// cosmic-comp custom window hint color /// cosmic-comp custom window hint color
#[serde(with = "color_serde_option")]
#[cosmic_config_entry(with = ColorReprOption)]
pub window_hint: Option<Srgb>, pub window_hint: Option<Srgb>,
} }
@ -825,7 +841,7 @@ impl Default for ThemeBuilder {
success: Default::default(), success: Default::default(),
warning: Default::default(), warning: Default::default(),
destructive: Default::default(), destructive: Default::default(),
is_frosted: false, frosted: None,
// cosmic-comp theme settings // cosmic-comp theme settings
gaps: (0, 8), gaps: (0, 8),
active_hint: 3, active_hint: 3,
@ -971,9 +987,11 @@ impl ThemeBuilder {
gaps, gaps,
active_hint, active_hint,
window_hint, window_hint,
is_frosted, frosted,
} = self; } = self;
let container_alpha = frosted.map_or(1.0, |f| f.alpha());
let is_dark = palette.is_dark(); let is_dark = palette.is_dark();
let is_high_contrast = palette.is_high_contrast(); let is_high_contrast = palette.is_high_contrast();
@ -1019,12 +1037,14 @@ impl ThemeBuilder {
NonZeroUsize::new(100).unwrap(), NonZeroUsize::new(100).unwrap(),
); );
let bg = if let Some(bg_color) = bg_color { let mut bg = if let Some(bg_color) = bg_color {
bg_color bg_color
} else { } else {
p_ref.gray_1 p_ref.gray_1
}; };
bg.alpha = container_alpha;
let step_array = steps(bg, NonZeroUsize::new(100).unwrap()); let step_array = steps(bg, NonZeroUsize::new(100).unwrap());
let bg_index = color_index(bg, step_array.len()); let bg_index = color_index(bg, step_array.len());
@ -1055,11 +1075,12 @@ impl ThemeBuilder {
); );
let primary = { let primary = {
let container_bg = if let Some(primary_container_bg_color) = primary_container_bg { let mut container_bg = if let Some(primary_container_bg_color) = primary_container_bg {
primary_container_bg_color primary_container_bg_color
} else { } else {
get_surface_color(bg_index, 5, &step_array, is_dark, &control_steps_array[1]) get_surface_color(bg_index, 5, &step_array, is_dark, &control_steps_array[1])
}; };
container_bg.alpha = container_alpha;
let step_array = steps(container_bg, NonZeroUsize::new(100).unwrap()); let step_array = steps(container_bg, NonZeroUsize::new(100).unwrap());
let base_index: usize = color_index(container_bg, step_array.len()); let base_index: usize = color_index(container_bg, step_array.len());
@ -1176,11 +1197,13 @@ impl ThemeBuilder {
), ),
primary, primary,
secondary: { secondary: {
let container_bg = if let Some(secondary_container_bg) = secondary_container_bg { let mut container_bg = if let Some(secondary_container_bg) = secondary_container_bg
{
secondary_container_bg secondary_container_bg
} else { } else {
get_surface_color(bg_index, 10, &step_array, is_dark, &control_steps_array[2]) get_surface_color(bg_index, 10, &step_array, is_dark, &control_steps_array[2])
}; };
container_bg.alpha = container_alpha;
let step_array = steps(container_bg, NonZeroUsize::new(100).unwrap()); let step_array = steps(container_bg, NonZeroUsize::new(100).unwrap());
let base_index = color_index(container_bg, step_array.len()); let base_index = color_index(container_bg, step_array.len());
@ -1332,7 +1355,7 @@ impl ThemeBuilder {
gaps, gaps,
active_hint, active_hint,
window_hint, window_hint,
is_frosted, frosted,
accent_text, accent_text,
control_tint: neutral_tint, control_tint: neutral_tint,
text_tint, text_tint,
@ -1354,3 +1377,69 @@ impl ThemeBuilder {
Config::new(LIGHT_THEME_BUILDER_ID, Self::VERSION) Config::new(LIGHT_THEME_BUILDER_ID, Self::VERSION)
} }
} }
#[repr(u8)]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq)]
pub enum BlurStrength {
ExtremelyLow = 1,
ExtremelyLow2,
VeryLow,
VeryLow2,
Low,
Low2,
Medium,
Medium2,
High,
High2,
VeryHigh,
VeryHigh2,
ExtremelyHigh,
ExtremelyHigh2,
}
impl BlurStrength {
/// Get the alpha value corresponding to the blur strength
/// Lower alpha values correspond to stronger blur effects, and higher alpha values correspond to weaker blur effects. The mapping is as follows:
pub fn alpha(&self) -> f32 {
match self {
Self::ExtremelyLow => 0.95,
Self::ExtremelyLow2 => 0.85,
Self::VeryLow => 0.8,
Self::VeryLow2 => 0.75,
Self::Low => 0.7,
Self::Low2 => 0.65,
Self::Medium => 0.6,
Self::Medium2 => 0.55,
Self::High => 0.5,
Self::High2 => 0.45,
Self::VeryHigh => 0.4,
Self::VeryHigh2 => 0.35,
Self::ExtremelyHigh => 0.2,
Self::ExtremelyHigh2 => 0.05,
}
}
}
impl TryFrom<u8> for BlurStrength {
type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
1 => Ok(BlurStrength::ExtremelyLow),
2 => Ok(BlurStrength::ExtremelyLow2),
3 => Ok(BlurStrength::VeryLow),
4 => Ok(BlurStrength::VeryLow2),
5 => Ok(BlurStrength::Low),
6 => Ok(BlurStrength::Low2),
7 => Ok(BlurStrength::Medium),
8 => Ok(BlurStrength::Medium2),
9 => Ok(BlurStrength::High),
10 => Ok(BlurStrength::High2),
11 => Ok(BlurStrength::VeryHigh),
12 => Ok(BlurStrength::VeryHigh2),
13 => Ok(BlurStrength::ExtremelyHigh),
14 => Ok(BlurStrength::ExtremelyHigh2),
_ => Err(()),
}
}
}

View file

@ -81,7 +81,7 @@ ForegroundPositive=0,87,44
ForegroundVisited=0,82,90 ForegroundVisited=0,82,90
[Colors:Selection] [Colors:Selection]
BackgroundAlternate=108,149,152 BackgroundAlternate=108,149,153
BackgroundNormal=0,82,90 BackgroundNormal=0,82,90
DecorationFocus=0,82,90 DecorationFocus=0,82,90
DecorationHover=0,82,90 DecorationHover=0,82,90

View file

@ -6,7 +6,7 @@ links = Links
developers = Entwickler(innen) developers = Entwickler(innen)
designers = Designer(innen) designers = Designer(innen)
artists = Künstler(innen) artists = Künstler(innen)
translators = Übersetzer(innen) translators = Übersetzer*innen
documenters = Dokumentierer(innen) documenters = Dokumentierer(innen)
# Calendar # Calendar
january = Januar { $year } january = Januar { $year }

View file

View file

@ -1,33 +0,0 @@
close = Mdel
license = Turagt
links = Iseɣwan
developers = Ineflayen
artists = Inaẓuren
translators = Imsuqlen
january = Yennayer { $year }
february = Fuṛar { $year }
march = Meɣres { $year }
april = Yebrir { $year }
may = Mayyu { $year }
june = Yunyu { $year }
july = Yulyu { $year }
august = Ɣuct { $year }
september = Ctembeṛ { $year }
october = Tubeṛ { $year }
november = Wambeṛ { $year }
december = Dujembeṛ { $year }
documenters = Imeskaren
monday = Arim
mon = Ari
tuesday = Aram
tue = Ara
wednesday = Ahad
wed = Aha
thursday = Amhad
thu = Amh
friday = Sem
fri = Sm
saturday = Sed
sat = Sd
sunday = Acer
sun = Ace

View file

@ -2,33 +2,26 @@ february = { $year }년 2월
close = 닫기 close = 닫기
documenters = 문서 작성자 documenters = 문서 작성자
november = { $year }년 11월 november = { $year }년 11월
friday = 금요일 friday = 금
tuesday = 화요일 tuesday = 화
may = { $year }년 5월 may = { $year }년 5월
wednesday = 수요일 wednesday = 수
april = { $year }년 4월 april = { $year }년 4월
monday = 월요일 monday = 월
translators = 번역가 translators = 번역가
artists = 아티스트 artists = 아티스트
license = 라이선스 license = 라이선스
december = { $year }년 12월 december = { $year }년 12월
sunday = 일요일 sunday = 일
links = 링크 links = 링크
march = { $year }년 3월 march = { $year }년 3월
june = { $year }년 6월 june = { $year }년 6월
saturday = 토요일 saturday = 토
august = { $year }년 8월 august = { $year }년 8월
developers = 개발자 developers = 개발자
july = { $year }년 7월 july = { $year }년 7월
thursday = 목요일 thursday = 목
september = { $year }년 9월 september = { $year }년 9월
designers = 디자이너 designers = 디자이너
october = { $year }년 10월 october = { $year }년 10월
january = { $year }년 1월 january = { $year }년 1월
mon = 월
tue = 화
wed = 수
thu = 목
fri = 금
sat = 토
sun = 일

View file

@ -1,34 +0,0 @@
close = 關閉
developers = 開發人員
designers = 設計人員
artists = 美編設計
translators = 翻譯人員
documenters = 文件編輯人員
january = { $year } 年 1 月
monday = 星期一
tuesday = 星期二
wednesday = 星期三
thursday = 星期四
friday = 星期五
saturday = 星期六
sunday = 星期日
mon = 週一
tue = 週二
wed = 週三
thu = 週四
fri = 週五
sat = 週六
sun = 週日
license = 授權
links = 連結
february = { $year } 年 2 月
march = { $year } 年 3 月
april = { $year } 年 4 月
may = { $year } 年 5 月
june = { $year } 年 6 月
july = { $year } 年 7 月
august = { $year } 年 8 月
september = { $year } 年 9 月
october = { $year } 年 10 月
november = { $year } 年 11 月
december = { $year } 年 12 月

2
iced

@ -1 +1 @@
Subproject commit 78caabba7ef91cd1030da6f70b41d266704ffece Subproject commit 46b65a3c3e2fb6f1627d117ca061743417806aaf

View file

@ -773,10 +773,31 @@ impl<T: Application> Cosmic<T> {
if a.distance_squared(*t_inner.accent_color()) > 0.00001 { if a.distance_squared(*t_inner.accent_color()) > 0.00001 {
theme = Theme::system(Arc::new(t_inner.with_accent(a))); theme = Theme::system(Arc::new(t_inner.with_accent(a)));
} }
}; }
} }
let new_blur = theme.cosmic().frosted.is_some();
THEME.lock().unwrap().set_theme(theme.theme_type); THEME.lock().unwrap().set_theme(theme.theme_type);
let core = self.app.core();
if core.auto_blur {
let mut cmds = Vec::with_capacity(1 + self.tracked_windows.len());
let blur = if new_blur {
iced::window::enable_blur
} else {
iced::window::disable_blur
};
cmds.push(blur(
self.app
.core()
.main_window_id()
.unwrap_or(window::Id::RESERVED),
));
for id in &self.tracked_windows {
cmds.push(blur(*id));
}
return Task::batch(cmds);
}
} }
Action::SystemThemeChange(keys, theme) => { Action::SystemThemeChange(keys, theme) => {
@ -809,6 +830,8 @@ impl<T: Application> Cosmic<T> {
theme theme
}; };
new_theme.theme_type.prefer_dark(prefer_dark); new_theme.theme_type.prefer_dark(prefer_dark);
// TODO adjust theme container alphas to remove transparency?
// if auto-blur is disabled & theme is frosted, should we make container colors in theme opaque?
cosmic_theme.set_theme(new_theme.theme_type); cosmic_theme.set_theme(new_theme.theme_type);
#[cfg(all(feature = "wayland", target_os = "linux"))] #[cfg(all(feature = "wayland", target_os = "linux"))]
@ -873,7 +896,7 @@ impl<T: Application> Cosmic<T> {
} }
} }
// Update radius for all tracked windows // Update radius for all tracked windows
for id in self.tracked_windows.iter() { for id in &self.tracked_windows {
cmds.push( cmds.push(
corner_radius( corner_radius(
*id, *id,
@ -956,6 +979,9 @@ impl<T: Application> Cosmic<T> {
// Only apply update if the theme is set to load a system theme // Only apply update if the theme is set to load a system theme
if let ThemeType::System { .. } = cosmic_theme.theme_type { if let ThemeType::System { .. } = cosmic_theme.theme_type {
// TODO adjust theme container alphas to remove transparency?
// if auto-blur is disabled & theme is frosted, should we make container colors in theme opaque?
let new_blur = new_theme.cosmic().frosted.is_some();
cosmic_theme.set_theme(new_theme.theme_type); cosmic_theme.set_theme(new_theme.theme_type);
#[cfg(all(feature = "wayland", target_os = "linux"))] #[cfg(all(feature = "wayland", target_os = "linux"))]
if self.app.core().sync_window_border_radii_to_theme() { if self.app.core().sync_window_border_radii_to_theme() {
@ -1019,7 +1045,7 @@ impl<T: Application> Cosmic<T> {
} }
} }
// Update radius for all tracked windows // Update radius for all tracked windows
for id in self.tracked_windows.iter() { for id in &self.tracked_windows {
cmds.push( cmds.push(
corner_radius( corner_radius(
*id, *id,
@ -1039,6 +1065,25 @@ impl<T: Application> Cosmic<T> {
); );
} }
let core = self.app.core();
if core.auto_blur {
let blur = if new_blur {
iced::window::enable_blur
} else {
iced::window::disable_blur
};
cmds.push(blur(
self.app
.core()
.main_window_id()
.unwrap_or(window::Id::RESERVED),
));
for id in &self.tracked_windows {
cmds.push(blur(*id));
}
}
return Task::batch(cmds); return Task::batch(cmds);
} }
} }
@ -1147,7 +1192,26 @@ impl<T: Application> Cosmic<T> {
// Only apply update if the theme is set to load a system theme // Only apply update if the theme is set to load a system theme
if let ThemeType::System { theme: _, .. } = cosmic_theme.theme_type { if let ThemeType::System { theme: _, .. } = cosmic_theme.theme_type {
let mut cmds = Vec::with_capacity(1 + self.tracked_windows.len());
if core.auto_blur {
let blur = if new_theme.cosmic().frosted.is_some() {
iced::window::enable_blur
} else {
iced::window::disable_blur
};
cmds.push(blur(
self.app
.core()
.main_window_id()
.unwrap_or(window::Id::RESERVED),
));
for id in &self.tracked_windows {
cmds.push(blur(*id));
}
}
cosmic_theme.set_theme(new_theme.theme_type); cosmic_theme.set_theme(new_theme.theme_type);
return Task::batch(cmds);
} }
} }
} }
@ -1263,8 +1327,24 @@ impl<T: Application> Cosmic<T> {
}; };
// TODO do we need per window sharp corners? // TODO do we need per window sharp corners?
let rounded = !self.app.core().window.sharp_corners; let rounded = !self.app.core().window.sharp_corners;
let core = self.app.core();
let blur_cmd = if core.auto_blur {
let blur = if t.frosted.is_some() {
iced::window::enable_blur
} else {
iced::window::disable_blur
};
let mut cmds = Vec::with_capacity(1 + self.tracked_windows.len());
cmds.push(blur(id));
for id in &self.tracked_windows {
cmds.push(blur(*id));
}
Task::batch(cmds)
} else {
Task::none()
};
return Task::batch([ return Task::batch([
blur_cmd,
corner_radius( corner_radius(
id, id,
if rounded { if rounded {

View file

@ -65,7 +65,6 @@ pub fn file_transfer_send(
/// Returns a list of file paths. /// Returns a list of file paths.
#[cfg(feature = "xdg-portal")] #[cfg(feature = "xdg-portal")]
pub fn file_transfer_receive(key: String) -> iced::Task<ashpd::Result<Vec<String>>> { pub fn file_transfer_receive(key: String) -> iced::Task<ashpd::Result<Vec<String>>> {
dbg!(&key);
iced::Task::future(async move { iced::Task::future(async move {
let file_transfer = ashpd::documents::FileTransfer::new().await?; let file_transfer = ashpd::documents::FileTransfer::new().await?;
file_transfer.retrieve_files(&key).await file_transfer.retrieve_files(&key).await

View file

@ -101,6 +101,8 @@ pub struct Core {
#[cfg(all(feature = "wayland", target_os = "linux"))] #[cfg(all(feature = "wayland", target_os = "linux"))]
pub(crate) sync_window_border_radii_to_theme: bool, pub(crate) sync_window_border_radii_to_theme: bool,
pub(crate) auto_blur: bool,
} }
impl Default for Core { impl Default for Core {
@ -161,6 +163,7 @@ impl Default for Core {
menu_bars: HashMap::new(), menu_bars: HashMap::new(),
#[cfg(all(feature = "wayland", target_os = "linux"))] #[cfg(all(feature = "wayland", target_os = "linux"))]
sync_window_border_radii_to_theme: true, sync_window_border_radii_to_theme: true,
auto_blur: true,
} }
} }
} }
@ -502,4 +505,8 @@ impl Core {
pub fn sync_window_border_radii_to_theme(&self) -> bool { pub fn sync_window_border_radii_to_theme(&self) -> bool {
self.sync_window_border_radii_to_theme self.sync_window_border_radii_to_theme
} }
pub fn set_auto_blur(&mut self, auto_blur: bool) {
self.auto_blur = auto_blur;
}
} }

View file

@ -307,7 +307,7 @@ impl DefaultStyle for Theme {
fn default_style(&self) -> Appearance { fn default_style(&self) -> Appearance {
let cosmic = self.cosmic(); let cosmic = self.cosmic();
Appearance { Appearance {
icon_color: cosmic.on_bg_color().into(), icon_color: cosmic.bg_color().into(),
background_color: cosmic.bg_color().into(), background_color: cosmic.bg_color().into(),
text_color: cosmic.on_bg_color().into(), text_color: cosmic.on_bg_color().into(),
} }

View file

@ -43,7 +43,7 @@ pub mod application {
iced::theme::Style { iced::theme::Style {
background_color: cosmic.bg_color().into(), background_color: cosmic.bg_color().into(),
text_color: cosmic.on_bg_color().into(), text_color: cosmic.on_bg_color().into(),
icon_color: cosmic.on_bg_color().into(), icon_color: cosmic.bg_color().into(),
} }
} }
} }
@ -565,6 +565,9 @@ impl iced_container::Catalog for Theme {
Container::ContextDrawer => { Container::ContextDrawer => {
let mut a = Container::primary(cosmic); let mut a = Container::primary(cosmic);
if let Some(Background::Color(ref mut color)) = a.background {
color.a = 1.;
}
if cosmic.is_high_contrast { if cosmic.is_high_contrast {
a.border.width = 1.; a.border.width = 1.;

View file

@ -4,12 +4,12 @@
//! Embedded icons for platforms which do not support icon themes yet. //! Embedded icons for platforms which do not support icon themes yet.
/// Icon bundling is not enabled on unix platforms. /// Icon bundling is not enabled on unix platforms.
#[cfg(all(unix, not(target_os = "macos")))] #[cfg(unix)]
pub fn get(icon_name: &str) -> Option<super::Data> { pub fn get(icon_name: &str) -> Option<super::Data> {
None None
} }
#[cfg(any(not(unix), target_os = "macos"))] #[cfg(not(unix))]
/// Get a bundled icon on non-unix platforms. /// Get a bundled icon on non-unix platforms.
pub fn get(icon_name: &str) -> Option<super::Data> { pub fn get(icon_name: &str) -> Option<super::Data> {
ICONS ICONS
@ -17,5 +17,5 @@ pub fn get(icon_name: &str) -> Option<super::Data> {
.map(|bytes| super::Data::Svg(crate::iced::widget::svg::Handle::from_memory(*bytes))) .map(|bytes| super::Data::Svg(crate::iced::widget::svg::Handle::from_memory(*bytes)))
} }
#[cfg(any(not(unix), target_os = "macos"))] #[cfg(not(unix))]
include!(concat!(env!("OUT_DIR"), "/bundled_icons.rs")); include!(concat!(env!("OUT_DIR"), "/bundled_icons.rs"));

View file

@ -52,7 +52,7 @@ impl Named {
} }
} }
#[cfg(all(unix, not(target_os = "macos")))] #[cfg(not(windows))]
#[must_use] #[must_use]
pub fn path(self) -> Option<PathBuf> { pub fn path(self) -> Option<PathBuf> {
let name = &*self.name; let name = &*self.name;
@ -107,7 +107,7 @@ impl Named {
result result
} }
#[cfg(any(not(unix), target_os = "macos"))] #[cfg(windows)]
#[must_use] #[must_use]
pub fn path(self) -> Option<PathBuf> { pub fn path(self) -> Option<PathBuf> {
//TODO: implement icon lookup for Windows //TODO: implement icon lookup for Windows