From d22c715fb9bdce5a9de1c71d7d2c7ec49e70d070 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Wed, 28 Jun 2023 14:24:39 -0700 Subject: [PATCH] Update workspace settings to be closer to mockup; use cosmic-config Not quite like mockup. May need a custom widget to have radio buttons that work the same way. Also needs images used in mockup. --- app/src/app.rs | 4 + app/src/pages/desktop/workspaces.rs | 213 +++++++++++++++++++++++++--- app/src/pages/mod.rs | 1 + i18n/en/cosmic_settings.ftl | 10 ++ 4 files changed, 207 insertions(+), 21 deletions(-) diff --git a/app/src/app.rs b/app/src/app.rs index 4263e9d..819290a 100644 --- a/app/src/app.rs +++ b/app/src/app.rs @@ -298,6 +298,10 @@ impl cosmic::Application for SettingsApp { } } + crate::pages::Message::DesktopWorkspaces(message) => { + page::update!(self.pages, message, desktop::workspaces::Page); + } + crate::pages::Message::Input(message) => { if let Some(page) = self.pages.page_mut::() { return page.update(message).map(cosmic::app::Message::App); diff --git a/app/src/pages/desktop/workspaces.rs b/app/src/pages/desktop/workspaces.rs index 27b788a..9d19f95 100644 --- a/app/src/pages/desktop/workspaces.rs +++ b/app/src/pages/desktop/workspaces.rs @@ -1,14 +1,72 @@ // Copyright 2023 System76 // SPDX-License-Identifier: GPL-3.0-only -use cosmic::iced::{widget::horizontal_space, Length}; +// TODO make settings work + +use apply::Apply; use cosmic::widget::settings; +use cosmic::{ + cosmic_config::{self, ConfigGet, ConfigSet}, + iced::widget::{column, radio, text}, + Element, +}; +use cosmic_comp_config::workspace::{ + WorkspaceAmount, WorkspaceConfig, WorkspaceLayout, WorkspaceMode, +}; use cosmic_settings_page::Section; use cosmic_settings_page::{self as page, section}; use slotmap::SlotMap; +use tracing::error; -#[derive(Default)] -pub struct Page; +#[derive(Clone, Debug)] +pub enum Message { + SetWorkspaceAmount(WorkspaceAmount), + SetWorkspaceMode(WorkspaceMode), + OrientationButtonSelected(cosmic::widget::segmented_button::Entity), + SetShowName(bool), + SetShowNumber(bool), +} + +pub struct Page { + config: cosmic_config::Config, + comp_config: cosmic_config::Config, + comp_workspace_config: WorkspaceConfig, + show_workspace_name: bool, + show_workspace_number: bool, + orientation_model: cosmic::widget::segmented_button::SingleSelectModel, +} + +impl Default for Page { + fn default() -> Self { + let comp_config = cosmic_config::Config::new("com.system76.CosmicComp", 1).unwrap(); + let comp_workspace_config = comp_config.get("workspaces").unwrap_or_else(|err| { + error!(?err, "Failed to read config 'workspaces'"); + WorkspaceConfig::default() + }); + let mut orientation_model = cosmic::widget::segmented_button::SingleSelectModel::builder() + .insert(|b| b.text(fl!("workspaces-orientation", "vertical"))) + .insert(|b| b.text(fl!("workspaces-orientation", "horizontal"))) + .build(); + orientation_model.activate_position(0); + let config = cosmic_config::Config::new("com.system76.CosmicWorkspaces", 1).unwrap(); + let show_workspace_name = config.get("show_workspace_name").unwrap_or_else(|err| { + error!(?err, "Failed to read config 'show_workspace_name'"); + false + }); + let show_workspace_number = config.get("show_workspace_number").unwrap_or_else(|err| { + error!(?err, "Failed to read config 'show_workspace_number'"); + false + }); + Self { + config, + comp_config, + comp_workspace_config, + show_workspace_name, + show_workspace_number, + orientation_model, + } + } +} impl page::Page for Page { fn content( @@ -18,6 +76,8 @@ impl page::Page for Page { Some(vec![ sections.insert(behavior()), sections.insert(multi_behavior()), + sections.insert(overview_thumbnails()), + sections.insert(workspace_orientation()), ]) } @@ -30,26 +90,92 @@ impl page::Page for Page { impl page::AutoBind for Page {} +impl Page { + fn save_comp_config(&self) { + if let Err(err) = self + .comp_config + .set("workspaces", &self.comp_workspace_config) + { + error!(?err, "Failed to set config 'workspaces'"); + } + } + + pub fn update(&mut self, message: Message) { + match message { + Message::SetWorkspaceAmount(value) => { + self.comp_workspace_config.workspace_amount = value; + self.save_comp_config(); + } + Message::SetWorkspaceMode(value) => { + self.comp_workspace_config.workspace_mode = value; + self.save_comp_config(); + } + Message::OrientationButtonSelected(entity) => { + self.orientation_model.activate(entity); + let horizontal_entity = self.orientation_model.entity_at(1).unwrap(); + let layout = if self.orientation_model.active() == horizontal_entity { + WorkspaceLayout::Horizontal + } else { + WorkspaceLayout::Vertical + }; + self.comp_workspace_config.workspace_layout = layout; + self.save_comp_config(); + } + Message::SetShowName(value) => { + self.show_workspace_name = value; + if let Err(err) = self.config.set("show_workspace_name", value) { + error!(?err, "Failed to set config 'show_workspace_name'"); + } + } + Message::SetShowNumber(value) => { + self.show_workspace_number = value; + if let Err(err) = self.config.set("show_workspace_number", value) { + error!(?err, "Failed to set config 'show_workspace_number'"); + } + } + } + } +} + fn behavior() -> Section { Section::default() .title(fl!("workspaces-behavior")) .descriptions(vec![ fl!("workspaces-behavior", "dynamic"), + fl!("workspaces-behavior", "dynamic-desc"), fl!("workspaces-behavior", "fixed"), + fl!("workspaces-behavior", "fixed-desc"), ]) - .view::(|_binder, _page, section| { + .view::(|_binder, page, section| { let descriptions = §ion.descriptions; + let fixed_workspaces = + page.comp_workspace_config.workspace_amount != WorkspaceAmount::Dynamic; settings::view_section(§ion.title) - .add(settings::item( - &descriptions[0], - horizontal_space(Length::Fill), - )) - .add(settings::item( - &descriptions[1], - horizontal_space(Length::Fill), - )) - .into() + // TODO subtitle postiion as part of radio? + .add(column![ + settings::item_row(vec![radio( + &descriptions[0], + false, + Some(fixed_workspaces), + |_| Message::SetWorkspaceAmount(WorkspaceAmount::Dynamic) + ) + .into()]), + text(&descriptions[1]).size(10) + ]) + .add(column![ + settings::item_row(vec![radio( + &descriptions[2], + true, + Some(fixed_workspaces), + // TODO Selector for number + |_| Message::SetWorkspaceAmount(WorkspaceAmount::Static(10)), + ) + .into()]), + text(&descriptions[3]).size(10) + ]) + .apply(Element::from) + .map(crate::pages::Message::DesktopWorkspaces) }) } @@ -60,17 +186,62 @@ fn multi_behavior() -> Section { fl!("workspaces-multi-behavior", "span"), fl!("workspaces-multi-behavior", "separate"), ]) - .view::(|_binder, _page, section| { + .view::(|_binder, page, section| { let descriptions = §ion.descriptions; settings::view_section(§ion.title) - .add(settings::item( + .add(settings::item_row(vec![radio( &descriptions[0], - horizontal_space(Length::Fill), - )) - .add(settings::item( + WorkspaceMode::Global, + Some(page.comp_workspace_config.workspace_mode), + |x| Message::SetWorkspaceMode(x), + ) + .into()])) + .add(settings::item_row(vec![radio( &descriptions[1], - horizontal_space(Length::Fill), - )) - .into() + WorkspaceMode::OutputBound, + Some(page.comp_workspace_config.workspace_mode), + |x| Message::SetWorkspaceMode(x), + ) + .into()])) + .apply(Element::from) + .map(crate::pages::Message::DesktopWorkspaces) + }) +} + +fn overview_thumbnails() -> Section { + Section::default() + .title(fl!("workspaces-overview-thumbnails")) + .descriptions(vec![ + fl!("workspaces-overview-thumbnails", "show-number"), + fl!("workspaces-overview-thumbnails", "show-name"), + ]) + .view::(|_binder, page, section| { + let descriptions = §ion.descriptions; + settings::view_section(§ion.title) + .add( + settings::item::builder(&descriptions[0]) + .toggler(page.show_workspace_number, Message::SetShowNumber), + ) + .add( + settings::item::builder(&descriptions[1]) + .toggler(page.show_workspace_name, Message::SetShowName), + ) + .apply(Element::from) + .map(crate::pages::Message::DesktopWorkspaces) + }) +} + +fn workspace_orientation() -> Section { + Section::default() + .title(fl!("workspaces-orientation")) + .descriptions(vec![]) + .view::(|_binder, page, section| { + settings::view_section(§ion.title) + .add( + cosmic::widget::segmented_selection::horizontal(&page.orientation_model) + .on_activate(|x| Message::OrientationButtonSelected(x)), + ) + .apply(Element::from) + .map(crate::pages::Message::DesktopWorkspaces) }) } diff --git a/app/src/pages/mod.rs b/app/src/pages/mod.rs index 238d69e..fe3b9aa 100644 --- a/app/src/pages/mod.rs +++ b/app/src/pages/mod.rs @@ -21,6 +21,7 @@ pub enum Message { PanelApplet(desktop::panel::applets_inner::Message), DockApplet(desktop::dock::applets::Message), Appearance(desktop::appearance::Message), + DesktopWorkspaces(desktop::workspaces::Message), Input(input::Message), External { id: String, message: Vec }, Page(Entity), diff --git a/i18n/en/cosmic_settings.ftl b/i18n/en/cosmic_settings.ftl index 3e8c24c..609ce93 100644 --- a/i18n/en/cosmic_settings.ftl +++ b/i18n/en/cosmic_settings.ftl @@ -177,12 +177,22 @@ workspaces = Workspaces workspaces-behavior = Workspace Behavior .dynamic = Dynamic workspaces + .dynamic-desc = Automatically removes empty workspaces. .fixed = Fixed Number of Workspaces + .fixed-desc = Add or remove workspaces in the overview. workspaces-multi-behavior = Multi-monitor Behavior .span = Workspaces Span Displays .separate = Displays Have Separate Workspaces +workspaces-overview-thumbnails = Workspace Overview Thumbnails + .show-number = Show Workspace Number + .show-name = Show Workspace Name + +workspaces-orientation = Workspaces Orientation + .vertical = Vertical + .horizontal = Horizontal + ## Networking: Wired wired = Wired