Skip to content

Commit 472f31e

Browse files
committed
feat(keyboard): add numlock configuration
1 parent 7cf3f68 commit 472f31e

File tree

5 files changed

+148
-14
lines changed

5 files changed

+148
-14
lines changed

cosmic-settings/src/pages/accessibility/magnifier.rs

+58-5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use cosmic::{
88
};
99
use cosmic_comp_config::{ZoomConfig, ZoomMovement};
1010
use cosmic_config::{ConfigGet, ConfigSet};
11+
use cosmic_settings_config::{shortcuts, Action, Binding};
1112
use cosmic_settings_page::{
1213
self as page,
1314
section::{self, Section},
@@ -26,6 +27,8 @@ pub struct Page {
2627
zoom_config: ZoomConfig,
2728
increment_values: Vec<String>,
2829
increment_idx: Option<usize>,
30+
zoom_in_shortcuts: Vec<Binding>,
31+
zoom_out_shortcuts: Vec<Binding>,
2932

3033
wayland_thread: Option<wayland::Sender>,
3134
magnifier_state: bool,
@@ -56,7 +59,7 @@ impl Default for Page {
5659
let mut values = HashSet::<u32>::from_iter([25, 50, 100, 150, 200, zoom_config.increment])
5760
.into_iter()
5861
.collect::<Vec<_>>();
59-
values.sort();
62+
values.sort_unstable();
6063
let increment_values = values
6164
.into_iter()
6265
.map(|val| {
@@ -72,16 +75,20 @@ impl Default for Page {
7275
})
7376
.collect::<Vec<_>>();
7477
let increment_idx = increment_values.iter().position(|s| {
75-
s.split("%").next().and_then(|val| str::parse(val).ok()) == Some(zoom_config.increment)
78+
s.split('%').next().and_then(|val| str::parse(val).ok()) == Some(zoom_config.increment)
7679
});
7780

81+
let (zoom_in_shortcuts, zoom_out_shortcuts) = zoom_shortcuts();
82+
7883
Page {
7984
entity: Entity::default(),
8085

8186
accessibility_config: comp_config,
8287
zoom_config,
8388
increment_values,
8489
increment_idx,
90+
zoom_in_shortcuts,
91+
zoom_out_shortcuts,
8592

8693
wayland_thread: None,
8794
magnifier_state: false,
@@ -107,7 +114,7 @@ impl page::Page<crate::pages::Message> for Page {
107114
sections: &mut SlotMap<section::Entity, page::Section<crate::pages::Message>>,
108115
) -> Option<page::Content> {
109116
Some(vec![
110-
sections.insert(magnifier()),
117+
sections.insert(magnifier(&self.zoom_in_shortcuts, &self.zoom_out_shortcuts)),
111118
sections.insert(tip()),
112119
sections.insert(view_movement()),
113120
])
@@ -161,10 +168,36 @@ impl page::Page<crate::pages::Message> for Page {
161168

162169
impl page::AutoBind<crate::pages::Message> for Page {}
163170

164-
pub fn magnifier() -> section::Section<crate::pages::Message> {
171+
pub fn magnifier(
172+
zoom_in: &[Binding],
173+
zoom_out: &[Binding],
174+
) -> section::Section<crate::pages::Message> {
175+
let zoom_in = if zoom_in.is_empty() {
176+
String::from("zero")
177+
} else {
178+
zoom_in.iter().fold(String::new(), |mut str, b| {
179+
if !str.is_empty() {
180+
str += ", ";
181+
}
182+
b.to_string_in_place(&mut str);
183+
str
184+
})
185+
};
186+
let zoom_out = if zoom_out.is_empty() {
187+
String::from("zero")
188+
} else {
189+
zoom_out.iter().fold(String::new(), |mut str, b| {
190+
if !str.is_empty() {
191+
str += ", ";
192+
}
193+
b.to_string_in_place(&mut str);
194+
str
195+
})
196+
};
197+
165198
crate::slab!(descriptions {
166199
magnifier = fl!("magnifier");
167-
controls = fl!("magnifier", "controls");
200+
controls = fl!("magnifier", "controls", zoom_in = zoom_in, zoom_out = zoom_out);
168201
increment = fl!("magnifier", "increment");
169202
signin = fl!("magnifier", "signin");
170203
});
@@ -337,3 +370,23 @@ impl Page {
337370
cosmic::iced::Task::none()
338371
}
339372
}
373+
374+
fn zoom_shortcuts() -> (Vec<Binding>, Vec<Binding>) {
375+
let Some(config) = shortcuts::context().ok() else {
376+
return (Vec::new(), Vec::new());
377+
};
378+
let shortcuts = dbg!(shortcuts::shortcuts(&config));
379+
380+
let zoom_in = shortcuts
381+
.iter()
382+
.filter(|&(_binding, action)| *action == Action::ZoomIn)
383+
.map(|(binding, _action)| binding.clone())
384+
.collect();
385+
let zoom_out = shortcuts
386+
.iter()
387+
.filter(|&(_binding, action)| *action == Action::ZoomOut)
388+
.map(|(binding, _action)| binding.clone())
389+
.collect();
390+
391+
(zoom_in, zoom_out)
392+
}

cosmic-settings/src/pages/input/keyboard/mod.rs

+74-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use cosmic::{
1313
widget::{self, button, container, icon, radio, row, settings, ListColumn},
1414
Apply, Element, Task,
1515
};
16-
use cosmic_comp_config::XkbConfig;
16+
use cosmic_comp_config::{KeyboardConfig, NumlockState, XkbConfig};
1717
use cosmic_settings_page::{self as page, section, Section};
1818
use itertools::Itertools;
1919
use slab::Slab;
@@ -58,13 +58,15 @@ pub enum Message {
5858
ExpandInputSourcePopover(Option<DefaultKey>),
5959
InputSourceSearch(String),
6060
OpenSpecialCharacterContext(SpecialKey),
61+
OpenNumlockContext,
6162
ShowInputSourcesContext,
6263
SourceAdd(DefaultKey),
6364
SourceContext(SourceContext),
6465
SpecialCharacterSelect(Option<&'static str>),
6566
SetRepeatKeysDelay(u32),
6667
SetRepeatKeysRate(u32),
6768
SetShowExtendedInputSources(bool),
69+
SetNumlockState(NumlockState),
6870
}
6971

7072
#[derive(Clone, Debug)]
@@ -102,6 +104,7 @@ pub struct Page {
102104
context: Option<Context>,
103105
input_source_search: String,
104106
xkb: XkbConfig,
107+
keyboard_config: KeyboardConfig,
105108
keyboard_layouts: SlotMap<DefaultKey, (Locale, Variant, Description, LayoutSource)>,
106109
active_layouts: Vec<DefaultKey>,
107110
expanded_source_popover: Option<DefaultKey>,
@@ -120,6 +123,7 @@ impl Default for Page {
120123
keyboard_layouts: SlotMap::new(),
121124
active_layouts: Vec::new(),
122125
xkb: XkbConfig::default(),
126+
keyboard_config: KeyboardConfig::default(),
123127
input_source_search: String::new(),
124128
show_extended_input_sources: false,
125129
config,
@@ -130,6 +134,7 @@ impl Default for Page {
130134
enum Context {
131135
ShowInputSourcesContext,
132136
SpecialCharacter(SpecialKey),
137+
NumlockState,
133138
}
134139

135140
#[derive(Copy, Clone, Debug)]
@@ -279,6 +284,7 @@ impl page::Page<crate::pages::Message> for Page {
279284
sections.insert(special_character_entry()),
280285
sections.insert(keyboard_shortcuts()),
281286
sections.insert(keyboard_typing_assist()),
287+
sections.insert(keyboard_num_lock()),
282288
])
283289
}
284290

@@ -295,13 +301,18 @@ impl page::Page<crate::pages::Message> for Page {
295301
.special_character_key_view(special_key)
296302
.map(crate::pages::Message::Keyboard)
297303
.apply(Some),
304+
Some(Context::NumlockState) => self
305+
.numlock_state_view()
306+
.map(crate::pages::Message::Keyboard)
307+
.apply(Some),
298308

299309
None => None,
300310
}
301311
}
302312

303313
fn on_enter(&mut self) -> Task<crate::pages::Message> {
304314
self.xkb = super::get_config(&self.config, "xkb_config");
315+
self.keyboard_config = super::get_config(&self.config, "keyboard_config");
305316
match (
306317
xkb_data::keyboard_layouts(),
307318
xkb_data::extra_keyboard_layouts(),
@@ -490,6 +501,14 @@ impl Page {
490501
));
491502
}
492503

504+
Message::OpenNumlockContext => {
505+
self.context = Some(Context::NumlockState);
506+
return cosmic::task::message(crate::app::Message::OpenContextDrawer(
507+
self.entity,
508+
fl!("keyboard-numlock-boot", "set").into(),
509+
));
510+
}
511+
493512
Message::SpecialCharacterSelect(id) => {
494513
if let Some(Context::SpecialCharacter(special_key)) = self.context {
495514
let options = self.xkb.options.as_deref().unwrap_or_default();
@@ -518,6 +537,12 @@ impl Page {
518537
Message::SetShowExtendedInputSources(value) => {
519538
self.show_extended_input_sources = value;
520539
}
540+
Message::SetNumlockState(numlock_state) => {
541+
self.keyboard_config.numlock_state = numlock_state;
542+
if let Err(err) = self.config.set("keyboard_config", &self.keyboard_config) {
543+
tracing::error!(?err, "Failed to set config 'keyboard_config'");
544+
}
545+
}
521546
}
522547

523548
Task::none()
@@ -613,6 +638,32 @@ impl Page {
613638
cosmic::widget::container(list).padding(24).into()
614639
}
615640

641+
fn numlock_state_view(&self) -> cosmic::Element<'_, Message> {
642+
let current = self.keyboard_config.numlock_state;
643+
let options = [
644+
(fl!("keyboard-numlock-boot", "off"), NumlockState::BootOff),
645+
(fl!("keyboard-numlock-boot", "on"), NumlockState::BootOn),
646+
(
647+
fl!("keyboard-numlock-boot", "last-boot"),
648+
NumlockState::LastBoot,
649+
),
650+
];
651+
652+
let mut list = cosmic::widget::list_column();
653+
for (desc, state) in options {
654+
list = list.add(settings::item_row(vec![radio(
655+
cosmic::widget::text(desc),
656+
Some(state),
657+
Some(Some(current)),
658+
|_| Message::SetNumlockState(state),
659+
)
660+
.width(Length::Fill)
661+
.into()]));
662+
}
663+
664+
cosmic::widget::container(list).padding(24).into()
665+
}
666+
616667
fn update_xkb_config(&mut self) {
617668
let result = update_xkb_config(
618669
&self.config,
@@ -792,6 +843,28 @@ fn keyboard_typing_assist() -> Section<crate::pages::Message> {
792843
})
793844
}
794845

846+
fn keyboard_num_lock() -> Section<crate::pages::Message> {
847+
let mut descriptions = Slab::new();
848+
849+
let boot_state = descriptions.insert(fl!("keyboard-numlock-boot", "boot-state"));
850+
851+
Section::default()
852+
.title(fl!("keyboard-numlock-boot"))
853+
.descriptions(descriptions)
854+
.view::<Page>(move |_binder, _page, section| {
855+
let descriptions = &section.descriptions;
856+
857+
settings::section()
858+
.title(&section.title)
859+
.add(crate::widget::go_next_item(
860+
&descriptions[boot_state],
861+
Message::OpenNumlockContext,
862+
))
863+
.apply(cosmic::Element::from)
864+
.map(crate::pages::Message::Keyboard)
865+
})
866+
}
867+
795868
fn update_xkb_config(
796869
config: &cosmic_config::Config,
797870
xkb: &mut XkbConfig,

cosmic-settings/src/pages/input/keyboard/shortcuts/move_window.rs

-2
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,6 @@ pub const fn actions() -> &'static [Action] {
9292
Action::MoveToWorkspace(7),
9393
Action::MoveToWorkspace(8),
9494
Action::MoveToWorkspace(9),
95-
Action::MoveToPreviousOutput,
96-
Action::MoveToNextOutput,
9795
Action::MoveToOutput(Direction::Down),
9896
Action::MoveToOutput(Direction::Left),
9997
Action::MoveToOutput(Direction::Right),

cosmic-settings/src/pages/input/keyboard/shortcuts/nav.rs

-2
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,6 @@ pub const fn actions() -> &'static [Action] {
8585
Action::PreviousWorkspace,
8686
Action::NextWorkspace,
8787
Action::LastWorkspace,
88-
Action::PreviousOutput,
89-
Action::NextOutput,
9088
Action::SwitchOutput(Direction::Left),
9189
Action::SwitchOutput(Direction::Right),
9290
Action::SwitchOutput(Direction::Up),

i18n/en/cosmic_settings.ftl

+16-4
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,15 @@ accessibility = Accessibility
135135
.off = Off
136136
.unavailable = Unavailable
137137
magnifier = Magnifier
138-
.controls =
139-
Or use keyboard shortcuts:
140-
Super + = to zoom in,
141-
Super + - to zoom out,
138+
.controls = Or use these shortcuts: { $zoom_in ->
139+
[zero] {""}
140+
*[other] {""}
141+
{$zoom_in} to zoom in,
142+
}{ $zoom_out ->
143+
[zero] {""}
144+
*[other] {""}
145+
{$zoom_out} to zoom out,
146+
}
142147
Super + scroll with your mouse
143148
.increment = Zoom increment
144149
.signin = Start magnifier on sign in
@@ -545,6 +550,13 @@ keyboard-typing-assist = Typing
545550
.repeat-rate = Repeat rate
546551
.repeat-delay = Repeat delay
547552
553+
keyboard-numlock-boot = Numlock
554+
.boot-state = State on boot
555+
.last-boot = Last boot
556+
.on = On
557+
.off = Off
558+
.set = Set numlock boot state
559+
548560
added = Added
549561
type-to-search = Type to search...
550562
show-extended-input-sources = Show extended input sources

0 commit comments

Comments
 (0)