diff --git a/cosmic-settings/src/app.rs b/cosmic-settings/src/app.rs index 0d3a371..31db049 100644 --- a/cosmic-settings/src/app.rs +++ b/cosmic-settings/src/app.rs @@ -603,12 +603,6 @@ impl cosmic::Application for SettingsApp { return page.dnd_icon(); } - if let Some(page) = self.pages.page::() { - if id == page.color_dialog { - return page.show_color_dialog(); - } - } - panic!("unknown window ID: {id:?}"); } diff --git a/cosmic-settings/src/pages/desktop/appearance.rs b/cosmic-settings/src/pages/desktop/appearance.rs index 77e1f38..dfe31c4 100644 --- a/cosmic-settings/src/pages/desktop/appearance.rs +++ b/cosmic-settings/src/pages/desktop/appearance.rs @@ -33,6 +33,7 @@ use slotmap::SlotMap; use tokio::io::AsyncBufReadExt; use crate::app; +use crate::widget::color_picker_context_view; use super::wallpaper::widgets::color_image; @@ -423,40 +424,6 @@ impl Page { Ok(()) } - fn color_picker_context_view( - &self, - description: Option>, - reset: Cow<'static, str>, - on_update: fn(ColorPickerUpdate) -> Message, - model: impl Fn(&Self) -> &ColorPickerModel, - ) -> Element<'_, crate::pages::Message> { - cosmic::widget::column() - .push_maybe(description.map(|description| text::body(description).width(Length::Fill))) - .push( - model(self) - .builder(on_update) - .reset_label(reset) - .height(Length::Fixed(158.0)) - .build( - fl!("recent-colors"), - fl!("copy-to-clipboard"), - fl!("copied-to-clipboard"), - ) - .apply(container) - .width(Length::Fixed(248.0)) - .align_x(alignment::Horizontal::Center) - .apply(container) - .width(Length::Fill) - .align_x(alignment::Horizontal::Center), - ) - .padding(self.theme_builder.spacing.space_l) - .align_items(cosmic::iced_core::Alignment::Center) - .spacing(self.theme_builder.spacing.space_m) - .width(Length::Fill) - .apply(Element::from) - .map(crate::pages::Message::Appearance) - } - fn experimental_context_view(&self) -> Element<'_, crate::pages::Message> { let active = self.icon_theme_active; let theme = cosmic::theme::active(); @@ -1084,49 +1051,55 @@ impl page::Page for Page { fn context_drawer(&self) -> Option> { let view = match self.context_view? { - ContextView::AccentWindowHint => self.color_picker_context_view( + ContextView::AccentWindowHint => color_picker_context_view( None, RESET_TO_DEFAULT.as_str().into(), Message::AccentWindowHint, - |this| &this.accent_window_hint, - ), + &self.accent_window_hint, + ) + .map(crate::pages::Message::Appearance), - ContextView::ApplicationBackground => self.color_picker_context_view( + ContextView::ApplicationBackground => color_picker_context_view( None, RESET_TO_DEFAULT.as_str().into(), Message::ApplicationBackground, - |this| &this.application_background, - ), + &self.application_background, + ) + .map(crate::pages::Message::Appearance), - ContextView::ContainerBackground => self.color_picker_context_view( + ContextView::ContainerBackground => color_picker_context_view( Some(fl!("container-background", "desc-detail").into()), fl!("container-background", "reset").into(), Message::ContainerBackground, - |this| &this.container_background, - ), + &self.container_background, + ) + .map(crate::pages::Message::Appearance), - ContextView::ControlComponent => self.color_picker_context_view( + ContextView::ControlComponent => color_picker_context_view( None, RESET_TO_DEFAULT.as_str().into(), Message::ControlComponent, - |this| &this.control_component, - ), + &self.control_component, + ) + .map(crate::pages::Message::Appearance), - ContextView::CustomAccent => self.color_picker_context_view( + ContextView::CustomAccent => color_picker_context_view( None, RESET_TO_DEFAULT.as_str().into(), Message::CustomAccent, - |this| &this.custom_accent, - ), + &self.custom_accent, + ) + .map(crate::pages::Message::Appearance), ContextView::Experimental => self.experimental_context_view(), - ContextView::InterfaceText => self.color_picker_context_view( + ContextView::InterfaceText => color_picker_context_view( None, RESET_TO_DEFAULT.as_str().into(), Message::InterfaceText, - |this| &this.interface_text, - ), + &self.interface_text, + ) + .map(crate::pages::Message::Appearance), }; Some(view) diff --git a/cosmic-settings/src/pages/desktop/wallpaper/mod.rs b/cosmic-settings/src/pages/desktop/wallpaper/mod.rs index be25b26..0a91c12 100644 --- a/cosmic-settings/src/pages/desktop/wallpaper/mod.rs +++ b/cosmic-settings/src/pages/desktop/wallpaper/mod.rs @@ -87,16 +87,14 @@ pub enum Message { ChangeCategory(Category), /// Changes the displayed images in the wallpaper view. ChangeFolder(Context), - /// Creates a color dialog - ColorAddDialog, /// Handles messages from the color dialog. - ColorDialogUpdate(ColorPickerUpdate), + ColorAdd(ColorPickerUpdate), + /// Creates a color context drawer + ColorAddContext, /// Removes a custom color from the color view. ColorRemove(wallpaper::Color), /// Selects a color in the color view. ColorSelect(wallpaper::Color), - /// Handles the drag message in the color dialog. - DragColorDialog, /// Sets the wallpaper fit parameter. Fit(usize), /// Adds a new custom image to the wallpaper view. @@ -141,8 +139,16 @@ pub enum Category { Wallpapers, } +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum ContextView { + AddColor, +} + /// The page struct for the wallpaper view. pub struct Page { + /// Whether to show a context drawer. + context_view: Option, + /// Whether to show the tab_bar or not. show_tab_bar: bool, @@ -160,9 +166,6 @@ pub struct Page { /// Model for the category dropdown, which has categories and recent folders. categories: dropdown::multi::Model, - /// The window ID of the color dialog. - pub color_dialog: window::Id, - /// The color model updated by the color dialog. color_model: ColorPickerModel, @@ -252,6 +255,18 @@ impl page::Page for Page { }))) }) } + + fn context_drawer(&self) -> Option> { + self.context_view.map(|view| match view { + ContextView::AddColor => crate::widget::color_picker_context_view( + None, + fl!("reset-to-default").into(), + Message::ColorAdd, + &self.color_model, + ) + .map(crate::pages::Message::DesktopWallpaper), + }) + } } impl page::AutoBind for Page {} @@ -259,6 +274,7 @@ impl page::AutoBind for Page {} impl Default for Page { fn default() -> Self { let mut page = Page { + context_view: None, show_tab_bar: false, active_output: None, cached_display_handle: None, @@ -290,7 +306,6 @@ impl Default for Page { categories }, wallpaper_service_config: wallpaper::Config::default(), - color_dialog: window::Id::unique(), color_model: ColorPickerModel::new(fl!("hex"), fl!("rgb"), None, Some(Color::WHITE)), config: Config::new(), fit_options: vec![fl!("fill"), fl!("fit-to-screen")], @@ -669,46 +684,8 @@ impl Page { } } - Message::DragColorDialog => { - return cosmic::iced_sctk::commands::window::start_drag_window(self.color_dialog) - } - Message::CacheDisplayImage => self.cache_display_image(), - Message::ColorDialogUpdate(update) => { - let cmd = match update { - ColorPickerUpdate::AppliedColor - | ColorPickerUpdate::Cancel - | ColorPickerUpdate::Reset => { - if let Some(color) = self.color_model.get_applied_color() { - let color = wallpaper::Color::Single([color.r, color.g, color.b]); - - if let Err(why) = self.config.add_custom_color(color.clone()) { - tracing::error!(?why, "could not set custom color"); - } - - self.selection.add_custom_color(color); - } - - close_window(self.color_dialog) - } - - ColorPickerUpdate::ActionFinished => { - let _res = self - .color_model - .update::(ColorPickerUpdate::AppliedColor); - Command::none() - } - - _ => Command::none(), - }; - - return Command::batch(vec![ - cmd, - self.color_model.update::(update), - ]); - } - Message::ChangeFolder(mut context) => { // Reassign custom colors and images to the new context. std::mem::swap(&mut context, &mut self.selection); @@ -730,8 +707,38 @@ impl Page { self.select_first_wallpaper(); } - Message::ColorAddDialog => { - return get_window(color_picker_window_settings(self.color_dialog)); + Message::ColorAdd(message) => { + match message { + ColorPickerUpdate::ActionFinished => { + let _res = self + .color_model + .update::(ColorPickerUpdate::AppliedColor); + + if let Some(color) = self.color_model.get_applied_color() { + let color = wallpaper::Color::Single([color.r, color.g, color.b]); + + if let Err(why) = self.config.add_custom_color(color.clone()) { + tracing::error!(?why, "could not set custom color"); + } + + self.selection.add_custom_color(color.clone()); + self.selection.active = Choice::Color(color); + self.cached_display_handle = None; + self.context_view = None; + } + } + + _ => (), + }; + + return self.color_model.update::(message); + } + + Message::ColorAddContext => { + self.context_view = Some(ContextView::AddColor); + return cosmic::command::message(crate::app::Message::OpenContextDrawer( + fl!("color-picker").into(), + )); } Message::ColorRemove(color) => { @@ -1053,15 +1060,6 @@ impl Page { self.cache_display_image(); } - - pub fn show_color_dialog(&self) -> Element { - color_picker_view( - &self.color_model, - Message::DragColorDialog, - Message::ColorDialogUpdate, - ) - .map(|m| crate::app::Message::PageMessage(crate::pages::Message::DesktopWallpaper(m))) - } } #[derive(Clone, Debug, PartialEq)] @@ -1264,7 +1262,7 @@ pub fn settings() -> Section { let add_button = if let Some(Category::Colors | Category::Wallpapers) = page.categories.selected { let (text, message) = if Some(Category::Colors) == page.categories.selected { - (fl!("add-color"), Message::ColorAddDialog) + (fl!("add-color"), Message::ColorAddContext) } else { (fl!("add-image"), Message::ImageAddDialog) }; @@ -1329,62 +1327,42 @@ pub fn settings() -> Section { }) } -fn color_picker_window_settings(window_id: window::Id) -> SctkWindowSettings { - SctkWindowSettings { - window_id, - app_id: Some("com.system76.CosmicSettings".to_string()), - title: Some(fl!("color-picker")), - parent: Some(window::Id::MAIN), - autosize: false, - size_limits: layout::Limits::NONE - .min_width(300.0) - .max_width(800.0) - .min_height(520.0) - .max_height(520.0), - size: (300, 520), - resizable: Some(8.0), - client_decorations: true, - transparent: true, - ..Default::default() - } -} +// // TODO: Reuse with the appearance page +// pub fn color_picker_view( +// model: &ColorPickerModel, +// on_drag: Message, +// on_message: fn(ColorPickerUpdate) -> Message, +// ) -> Element { +// let header = cosmic::widget::header_bar() +// .title(fl!("color-picker")) +// .on_close(on_message(ColorPickerUpdate::AppliedColor)) +// .on_drag(on_drag); -// TODO: Reuse with the appearance page -pub fn color_picker_view( - model: &ColorPickerModel, - on_drag: Message, - on_message: fn(ColorPickerUpdate) -> Message, -) -> Element { - let header = cosmic::widget::header_bar() - .title(fl!("color-picker")) - .on_close(on_message(ColorPickerUpdate::AppliedColor)) - .on_drag(on_drag); +// let content = cosmic::widget::container( +// model +// .builder(on_message) +// .width(Length::Fixed(254.0)) +// .height(Length::Fixed(174.0)) +// .reset_label(fl!("reset-to-default")) +// .build( +// fl!("recent-colors"), +// fl!("copy-to-clipboard"), +// fl!("copied-to-clipboard"), +// ), +// ) +// .width(Length::Fill) +// .height(Length::Fill) +// .center_x() +// .style(cosmic::theme::style::Container::Background); - let content = cosmic::widget::container( - model - .builder(on_message) - .width(Length::Fixed(254.0)) - .height(Length::Fixed(174.0)) - .reset_label(fl!("reset-to-default")) - .build( - fl!("recent-colors"), - fl!("copy-to-clipboard"), - fl!("copied-to-clipboard"), - ), - ) - .width(Length::Fill) - .height(Length::Fill) - .center_x() - .style(cosmic::theme::style::Container::Background); - - cosmic::widget::column::with_capacity(2) - .push(header) - .push(content) - .width(Length::Fill) - .height(Length::Fill) - .align_items(cosmic::iced_core::Alignment::Center) - .apply(Element::from) -} +// cosmic::widget::column::with_capacity(2) +// .push(header) +// .push(content) +// .width(Length::Fill) +// .height(Length::Fill) +// .align_items(cosmic::iced_core::Alignment::Center) +// .apply(Element::from) +// } enum DialogResponse { Error(String), diff --git a/cosmic-settings/src/widget/mod.rs b/cosmic-settings/src/widget/mod.rs index 8f0a672..b41b893 100644 --- a/cosmic-settings/src/widget/mod.rs +++ b/cosmic-settings/src/widget/mod.rs @@ -1,15 +1,54 @@ // Copyright 2023 System76 // SPDX-License-Identifier: GPL-3.0-only -use cosmic::iced::Length; +use std::borrow::Cow; + +use cosmic::iced::{alignment, Length}; use cosmic::iced_core::text::Wrap; +use cosmic::prelude::CollectionWidget; +use cosmic::widget::color_picker::ColorPickerUpdate; use cosmic::widget::{ self, button, column, container, divider, horizontal_space, icon, row, settings, text, - vertical_space, + vertical_space, ColorPickerModel, }; use cosmic::{theme, Apply, Element}; use cosmic_settings_page as page; +pub fn color_picker_context_view<'a, Message: Clone + 'static>( + description: Option>, + reset: Cow<'static, str>, + on_update: fn(ColorPickerUpdate) -> Message, + model: &'a ColorPickerModel, +) -> Element<'a, Message> { + let theme = cosmic::theme::active(); + let spacing = &theme.cosmic().spacing; + + cosmic::widget::column() + .push_maybe(description.map(|description| text(description).width(Length::Fill))) + .push( + model + .builder(on_update) + .reset_label(reset) + .height(Length::Fixed(158.0)) + .build( + fl!("recent-colors"), + fl!("copy-to-clipboard"), + fl!("copied-to-clipboard"), + ) + .apply(container) + .width(Length::Fixed(248.0)) + .align_x(alignment::Horizontal::Center) + .apply(container) + .width(Length::Fill) + .align_x(alignment::Horizontal::Center), + ) + .padding(spacing.space_l) + .align_items(cosmic::iced_core::Alignment::Center) + .spacing(spacing.space_m) + .width(Length::Fill) + .apply(Element::from) +} + #[must_use] pub fn search_header( pages: &page::Binder,