Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 191 additions & 2 deletions cosmic-settings/src/pages/desktop/workspaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
// TODO make settings work

use cosmic::cosmic_config::{self, ConfigGet, ConfigSet};
use cosmic::widget::{self, settings};
use cosmic::iced::{Alignment, Length};
use cosmic::widget::{self, icon, settings, text};
use cosmic::{Apply, Element, surface};
use cosmic_comp_config::workspace::{Action, WorkspaceConfig, WorkspaceLayout, WorkspaceMode};
use cosmic_comp_config::WorkspaceAssignment;
use cosmic_settings_page::{self as page, Section, section};
use slotmap::SlotMap;
use tracing::error;
Expand All @@ -17,9 +19,16 @@ pub enum Message {
SetWorkspaceMode(WorkspaceMode),
SetWorkspaceLayout(WorkspaceLayout),
SetWorkspaceWraparound(bool),
SetGridColumns(u32),
SetGridRows(u32),
SetShowName(bool),
SetShowNumber(bool),
Surface(surface::Action),
SetAssignmentWorkspace(usize, u32),
RemoveAssignment(usize),
NewAssignmentAppId(String),
NewAssignmentWorkspace(u32),
AddAssignment,
}

pub struct Page {
Expand All @@ -30,6 +39,9 @@ pub struct Page {
action_on_typing_active: Option<usize>,
show_workspace_name: bool,
show_workspace_number: bool,
workspace_assignments: Vec<WorkspaceAssignment>,
new_assignment_app_id: String,
new_assignment_workspace: u32,
}

impl Default for Page {
Expand Down Expand Up @@ -59,6 +71,15 @@ impl Default for Page {

false
});
let workspace_assignments: Vec<WorkspaceAssignment> = comp_config
.get("workspace_assignments")
.unwrap_or_else(|err| {
if err.is_err() {
error!(?err, "Failed to read config 'workspace_assignments'");
}

Vec::new()
});
Self {
config,
comp_config,
Expand All @@ -71,6 +92,9 @@ impl Default for Page {
action_on_typing_active,
show_workspace_name,
show_workspace_number,
workspace_assignments,
new_assignment_app_id: String::new(),
new_assignment_workspace: 1,
}
}
}
Expand All @@ -85,6 +109,7 @@ impl page::Page<crate::pages::Message> for Page {
sections.insert(multi_behavior()),
sections.insert(workspace_orientation()),
sections.insert(workspace_navigation()),
sections.insert(workspace_assignments()),
])
}

Expand All @@ -107,6 +132,15 @@ impl Page {
}
}

fn save_assignments(&self) {
if let Err(err) = self
.comp_config
.set("workspace_assignments", &self.workspace_assignments)
{
error!(?err, "Failed to set config 'workspace_assignments'");
}
}

pub fn update(&mut self, message: Message) -> cosmic::iced::Task<crate::app::Message> {
match message {
Message::SetWorkspaceMode(value) => {
Expand All @@ -127,6 +161,14 @@ impl Page {
self.comp_workspace_config.workspace_wraparound = value;
self.save_comp_config();
}
Message::SetGridColumns(value) => {
self.comp_workspace_config.workspace_grid_columns = value.max(1);
self.save_comp_config();
}
Message::SetGridRows(value) => {
self.comp_workspace_config.workspace_grid_rows = value.max(1);
self.save_comp_config();
}
Message::SetShowName(value) => {
self.show_workspace_name = value;
if let Err(err) = self.config.set("show_workspace_name", value) {
Expand All @@ -142,6 +184,36 @@ impl Page {
Message::Surface(a) => {
return cosmic::task::message(crate::app::Message::Surface(a));
}
Message::SetAssignmentWorkspace(index, value) => {
if let Some(rule) = self.workspace_assignments.get_mut(index) {
rule.workspace = value.max(1);
self.save_assignments();
}
}
Message::RemoveAssignment(index) => {
if index < self.workspace_assignments.len() {
self.workspace_assignments.remove(index);
self.save_assignments();
}
}
Message::NewAssignmentAppId(value) => {
self.new_assignment_app_id = value;
}
Message::NewAssignmentWorkspace(value) => {
self.new_assignment_workspace = value.max(1);
}
Message::AddAssignment => {
let app_id = self.new_assignment_app_id.trim().to_string();
if !app_id.is_empty() {
self.workspace_assignments.push(WorkspaceAssignment {
app_id,
workspace: self.new_assignment_workspace,
});
self.new_assignment_app_id.clear();
self.new_assignment_workspace = 1;
self.save_assignments();
}
}
}
cosmic::iced::Task::none()
}
Expand Down Expand Up @@ -229,14 +301,19 @@ fn workspace_orientation() -> Section<crate::pages::Message> {
crate::slab!(descriptions {
vertical = fl!("workspaces-orientation", "vertical");
horizontal = fl!("workspaces-orientation", "horizontal");
grid = fl!("workspaces-orientation", "grid");
grid_columns = fl!("workspaces-orientation", "grid-columns");
grid_rows = fl!("workspaces-orientation", "grid-rows");
});

Section::default()
.title(fl!("workspaces-orientation"))
.descriptions(descriptions)
.view::<Page>(move |_binder, page, section| {
let descriptions = &section.descriptions;
settings::section()
let is_grid =
page.comp_workspace_config.workspace_layout == WorkspaceLayout::Grid;
let mut section = settings::section()
.title(&section.title)
.add(settings::item::builder(&descriptions[vertical]).radio(
WorkspaceLayout::Vertical,
Expand All @@ -248,6 +325,41 @@ fn workspace_orientation() -> Section<crate::pages::Message> {
Some(page.comp_workspace_config.workspace_layout),
Message::SetWorkspaceLayout,
))
.add(settings::item::builder(&descriptions[grid]).radio(
WorkspaceLayout::Grid,
Some(page.comp_workspace_config.workspace_layout),
Message::SetWorkspaceLayout,
));
if is_grid {
section = section
.add(
settings::item::builder(&descriptions[grid_columns]).control(
widget::spin_button(
page.comp_workspace_config.workspace_grid_columns.to_string(),
"grid columns",
page.comp_workspace_config.workspace_grid_columns,
1,
1,
10,
Message::SetGridColumns,
),
),
)
.add(
settings::item::builder(&descriptions[grid_rows]).control(
widget::spin_button(
page.comp_workspace_config.workspace_grid_rows.to_string(),
"grid rows",
page.comp_workspace_config.workspace_grid_rows,
1,
1,
10,
Message::SetGridRows,
),
),
);
}
section
.apply(Element::from)
.map(crate::pages::Message::DesktopWorkspaces)
})
Expand All @@ -273,3 +385,80 @@ fn workspace_navigation() -> Section<crate::pages::Message> {
.map(crate::pages::Message::DesktopWorkspaces)
})
}

fn workspace_assignments() -> Section<crate::pages::Message> {
crate::slab!(descriptions {
description = fl!("workspaces-assignments", "description");
});

Section::default()
.title(fl!("workspaces-assignments"))
.descriptions(descriptions)
.view::<Page>(move |_binder, page, section| {
let cosmic::cosmic_theme::Spacing { space_xs, .. } = cosmic::theme::spacing();
let descriptions = &section.descriptions;

let mut section = settings::section()
.title(&section.title)
.add(text::body(&descriptions[description]));

if page.workspace_assignments.is_empty() {
section = section.add(text::body(fl!("workspaces-assignments", "none")));
} else {
for (index, rule) in page.workspace_assignments.iter().enumerate() {
let row = widget::row::with_capacity(4)
.spacing(space_xs)
.align_y(Alignment::Center)
.push(icon::from_name("application-x-executable-symbolic").size(24))
.push(text::body(rule.app_id.clone()).width(Length::Fill))
.push(widget::spin_button(
rule.workspace.to_string(),
"workspace",
rule.workspace,
1,
1,
99,
move |value| Message::SetAssignmentWorkspace(index, value),
))
.push(
widget::button::icon(icon::from_name("edit-delete-symbolic"))
.extra_small()
.on_press(Message::RemoveAssignment(index)),
);
section = section.add(row);
}
}

let add_row = widget::row::with_capacity(3)
.spacing(space_xs)
.align_y(Alignment::Center)
.push(
widget::text_input(
fl!("workspaces-assignments", "app-id-placeholder"),
&page.new_assignment_app_id,
)
.on_input(Message::NewAssignmentAppId)
.width(Length::Fill),
)
.push(widget::spin_button(
page.new_assignment_workspace.to_string(),
"new-assignment-workspace",
page.new_assignment_workspace,
1,
1,
99,
Message::NewAssignmentWorkspace,
))
.push(
widget::button::standard(fl!("workspaces-assignments", "add")).on_press_maybe(
(!page.new_assignment_app_id.trim().is_empty())
.then_some(Message::AddAssignment),
),
);

section
.add(add_row)
.apply(Element::from)
.map(crate::pages::Message::DesktopWorkspaces)
})
}
5 changes: 4 additions & 1 deletion cosmic-settings/src/pages/input/touchpad.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,10 @@ fn gestures() -> Section<crate::pages::Message> {
settings::item::builder(
&descriptions[match page.comp_workspace_config.workspace_layout {
WorkspaceLayout::Horizontal => switch_workspaces_horizontal,
WorkspaceLayout::Vertical => switch_workspaces_vertical,
// Grid behaves like Vertical for 4-finger swipes.
WorkspaceLayout::Vertical | WorkspaceLayout::Grid => {
switch_workspaces_vertical
}
}],
)
.flex_control(text::body(&descriptions[switch_workspaces])),
Expand Down
11 changes: 11 additions & 0 deletions i18n/en/cosmic_settings.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -538,13 +538,24 @@ workspaces-overview-thumbnails = Workspace overview thumbnails
workspaces-orientation = Workspaces orientation
.vertical = Vertical
.horizontal = Horizontal
.grid = Grid
.grid-columns = Grid columns
.grid-rows = Grid rows

hot-corner = Hot Corner
.top-left-corner = Enable top-left hot corner for Workspaces

workspaces-navigation = Navigation
.wraparound = Move between first and last workspace using keyboard shortcuts and gestures

workspaces-assignments = App workspace assignments
.description = Apps below always open on their assigned workspace, no matter where they're launched from.
.app-id = Application ID
.workspace = Workspace
.add = Add
.none = No apps assigned yet.
.app-id-placeholder = e.g. code, org.mozilla.firefox

## Displays

-requires-restart = Requires restart
Expand Down