From 324b8c162279685c4e5fbabd9af1438ab40adf5a Mon Sep 17 00:00:00 2001 From: Michael Aaron Murphy Date: Thu, 27 Feb 2025 17:17:03 +0100 Subject: [PATCH] feat: add configurables for accent_palette_dark and accent_palette_light Closes #749 --- cosmic-settings/src/config.rs | 23 +- .../src/pages/desktop/appearance/mod.rs | 239 ++++++++++-------- 2 files changed, 159 insertions(+), 103 deletions(-) diff --git a/cosmic-settings/src/config.rs b/cosmic-settings/src/config.rs index 4f0e297..db9af4d 100644 --- a/cosmic-settings/src/config.rs +++ b/cosmic-settings/src/config.rs @@ -1,14 +1,19 @@ // Copyright 2023 System76 // SPDX-License-Identifier: GPL-3.0-only -use cosmic::cosmic_config::{self, ConfigGet, ConfigSet}; +use cosmic::{ + cosmic_config::{self, ConfigGet, ConfigSet}, + cosmic_theme::palette::Srgba, +}; const NAME: &str = "com.system76.CosmicSettings"; const ACTIVE_PAGE: &str = "active-page"; +const ACCENT_PALETTE_DARK: &str = "accent_palette_dark"; +const ACCENT_PALETTE_LIGHT: &str = "accent_palette_light"; #[must_use] -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Config { pub cosmic_config: Option, pub active_page: Box, @@ -35,6 +40,20 @@ impl Config { config } + pub fn accent_palette_dark(&self) -> Result, cosmic_config::Error> { + self.cosmic_config + .as_ref() + .unwrap() + .get::>(ACCENT_PALETTE_DARK) + } + + pub fn accent_palette_light(&self) -> Result, cosmic_config::Error> { + self.cosmic_config + .as_ref() + .unwrap() + .get::>(ACCENT_PALETTE_LIGHT) + } + pub fn set_active_page(&mut self, page: Box) { if let Some(context) = self.cosmic_config.as_ref() { if let Err(why) = context.set::>(ACTIVE_PAGE, page.clone()) { diff --git a/cosmic-settings/src/pages/desktop/appearance/mod.rs b/cosmic-settings/src/pages/desktop/appearance/mod.rs index f72762d..5837257 100644 --- a/cosmic-settings/src/pages/desktop/appearance/mod.rs +++ b/cosmic-settings/src/pages/desktop/appearance/mod.rs @@ -60,10 +60,12 @@ enum ContextView { MonospaceFont, SystemFont, } + #[allow(clippy::struct_excessive_bools)] pub struct Page { entity: page::Entity, on_enter_handle: Option, + accent_palette: AccentPalette, can_reset: bool, no_custom_window_hint: bool, context_view: Option, @@ -96,12 +98,21 @@ pub struct Page { auto_switch_descs: [Cow<'static, str>; 4], tk_config: Option, - + settings_config: crate::config::Config, day_time: bool, } +#[derive(Default)] +pub struct AccentPalette { + dark: Option>, + light: Option>, + theme: Vec, +} + impl Default for Page { fn default() -> Self { + let settings_config = crate::config::Config::new(); + let theme_mode_config = ThemeMode::config().ok(); let theme_mode = theme_mode_config .as_ref() @@ -116,26 +127,52 @@ impl Default for Page { }) .unwrap_or_default(); - (theme_mode_config, theme_mode).into() + let accent_palette = AccentPalette { + dark: settings_config.accent_palette_dark().ok(), + light: settings_config.accent_palette_light().ok(), + theme: Vec::new(), + }; + + let mut page: Page = ( + settings_config, + theme_mode_config, + theme_mode, + accent_palette, + ) + .into(); + page.update_accent_palette(); + page } } impl From<( + crate::config::Config, Option, ThemeMode, Option, ThemeBuilder, Option, + AccentPalette, )> for Page { fn from( - (theme_mode_config, theme_mode, theme_builder_config, theme_builder, tk_config): ( + ( + settings_config, + theme_mode_config, + theme_mode, + theme_builder_config, + theme_builder, + tk_config, + accent_palette, + ): ( + crate::config::Config, Option, ThemeMode, Option, ThemeBuilder, Option, + AccentPalette, ), ) -> Self { let theme = if theme_mode.is_dark { @@ -212,12 +249,14 @@ impl icon_theme_active: None, icon_themes: Vec::new(), icon_handles: Vec::new(), + accent_palette, theme, theme_mode_config, theme_builder_config, theme_mode, theme_builder, tk_config, + settings_config, day_time: true, auto_switch_descs: [ fl!("auto-switch", "sunrise").into(), @@ -229,8 +268,22 @@ impl } } -impl From<(Option, ThemeMode)> for Page { - fn from((theme_mode_config, theme_mode): (Option, ThemeMode)) -> Self { +impl + From<( + crate::config::Config, + Option, + ThemeMode, + AccentPalette, + )> for Page +{ + fn from( + (settings_config, theme_mode_config, theme_mode, accent_palette): ( + crate::config::Config, + Option, + ThemeMode, + AccentPalette, + ), + ) -> Self { let theme_builder_config = if theme_mode.is_dark { ThemeBuilder::dark_config() } else { @@ -259,11 +312,13 @@ impl From<(Option, ThemeMode)> for Page { let tk_config = CosmicTk::config().ok(); Self::from(( + settings_config, theme_mode_config, theme_mode, theme_builder_config, theme_builder, tk_config, + accent_palette, )) } } @@ -1110,6 +1165,7 @@ impl Page { // If the theme builder changed, write a new theme to disk on a background thread. if needs_build { + self.update_accent_palette(); let theme_builder = self.theme_builder.clone(); let is_dark = self.theme_mode.is_dark; let current_theme = self.theme.clone(); @@ -1186,6 +1242,21 @@ impl Page { cosmic::Task::batch(tasks) } + fn update_accent_palette(&mut self) { + let palette = self.theme_builder.palette.as_ref(); + self.accent_palette.theme = vec![ + palette.accent_blue, + palette.accent_indigo, + palette.accent_purple, + palette.accent_pink, + palette.accent_red, + palette.accent_orange, + palette.accent_yellow, + palette.accent_green, + palette.accent_warm_grey, + ]; + } + fn reload_theme_mode(&mut self) { let entity = self.entity; let font_config = std::mem::take(&mut self.font_config); @@ -1194,7 +1265,15 @@ impl Page { let icon_theme_active = self.icon_theme_active.take(); let day_time = self.day_time; - *self = Self::from((self.theme_mode_config.clone(), self.theme_mode)); + *self = Self::from(( + self.settings_config.clone(), + self.theme_mode_config.take(), + self.theme_mode, + std::mem::take(&mut self.accent_palette), + )); + + self.update_accent_palette(); + self.entity = entity; self.day_time = day_time; self.icon_themes = icon_themes; @@ -1624,6 +1703,58 @@ pub fn mode_and_colors() -> Section { .theme_builder .accent .map_or(palette.accent_blue, Srgba::from); + + let accent_palette_values = match ( + page.theme_mode.is_dark, + page.accent_palette.dark.as_ref(), + page.accent_palette.light.as_ref(), + ) { + (true, Some(dark_palette), _) => &dark_palette, + (false, _, Some(light_palette)) => &light_palette, + _ => &page.accent_palette.theme, + }; + + let mut accent_palette_row = + cosmic::widget::row::with_capacity(accent_palette_values.len()); + + for &color in accent_palette_values { + accent_palette_row = accent_palette_row.push(color_button( + Some(Message::PaletteAccent(color.into())), + color.into(), + cur_accent == color, + 48, + 48, + )); + } + + let accent_color_palette = cosmic::iced::widget::column![ + text::body(&descriptions[accent_color]), + scrollable( + accent_palette_row + .push(if let Some(c) = page.custom_accent.get_applied_color() { + container(color_button( + Some(Message::CustomAccent(ColorPickerUpdate::ToggleColorPicker)), + c, + cosmic::iced::Color::from(cur_accent) == c, + 48, + 48, + )) + } else { + container( + page.custom_accent + .picker_button(Message::CustomAccent, None) + .width(Length::Fixed(48.0)) + .height(Length::Fixed(48.0)), + ) + }) + .padding([0, 0, 16, 0]) + .spacing(16) + ) + .direction(Direction::Horizontal(Scrollbar::new())) + ] + .padding([16, 0, 0, 0]) + .spacing(space_xxs); + let mut section = settings::section() .title(§ion.title) .add( @@ -1682,101 +1813,7 @@ pub fn mode_and_colors() -> Section { ) .toggler(page.theme_mode.auto_switch, Message::Autoswitch), ) - .add( - cosmic::iced::widget::column![ - text::body(&descriptions[accent_color]), - scrollable( - cosmic::iced::widget::row![ - color_button( - Some(Message::PaletteAccent(palette.accent_blue.into())), - palette.accent_blue.into(), - cur_accent == palette.accent_blue, - 48, - 48 - ), - color_button( - Some(Message::PaletteAccent(palette.accent_indigo.into())), - palette.accent_indigo.into(), - cur_accent == palette.accent_indigo, - 48, - 48 - ), - color_button( - Some(Message::PaletteAccent(palette.accent_purple.into())), - palette.accent_purple.into(), - cur_accent == palette.accent_purple, - 48, - 48 - ), - color_button( - Some(Message::PaletteAccent(palette.accent_pink.into())), - palette.accent_pink.into(), - cur_accent == palette.accent_pink, - 48, - 48 - ), - color_button( - Some(Message::PaletteAccent(palette.accent_red.into())), - palette.accent_red.into(), - cur_accent == palette.accent_red, - 48, - 48 - ), - color_button( - Some(Message::PaletteAccent(palette.accent_orange.into())), - palette.accent_orange.into(), - cur_accent == palette.accent_orange, - 48, - 48 - ), - color_button( - Some(Message::PaletteAccent(palette.accent_yellow.into())), - palette.accent_yellow.into(), - cur_accent == palette.accent_yellow, - 48, - 48 - ), - color_button( - Some(Message::PaletteAccent(palette.accent_green.into())), - palette.accent_green.into(), - cur_accent == palette.accent_green, - 48, - 48 - ), - color_button( - Some(Message::PaletteAccent(palette.accent_warm_grey.into())), - palette.accent_warm_grey.into(), - cur_accent == palette.accent_warm_grey, - 48, - 48 - ), - if let Some(c) = page.custom_accent.get_applied_color() { - container(color_button( - Some(Message::CustomAccent( - ColorPickerUpdate::ToggleColorPicker, - )), - c, - cosmic::iced::Color::from(cur_accent) == c, - 48, - 48, - )) - } else { - container( - page.custom_accent - .picker_button(Message::CustomAccent, None) - .width(Length::Fixed(48.0)) - .height(Length::Fixed(48.0)), - ) - }, - ] - .padding([0, 0, 16, 0]) - .spacing(16) - ) - .direction(Direction::Horizontal(Scrollbar::new())) - ] - .padding([16, 0, 0, 0]) - .spacing(space_xxs), - ) + .add(accent_color_palette) .add( settings::item::builder(&descriptions[app_bg]).control( page.application_background