diff --git a/app/src/pages/input/mod.rs b/app/src/pages/input/mod.rs index a73b5f0..f526178 100644 --- a/app/src/pages/input/mod.rs +++ b/app/src/pages/input/mod.rs @@ -15,15 +15,16 @@ use tracing::error; pub mod keyboard; mod mouse; +mod touchpad; #[derive(Clone, Debug)] pub enum Message { - SetAcceleration(bool), - SetNaturalScroll(bool), - SetScrollFactor(f64), - SetDoubleClickSpeed(u32), - SetMouseSpeed(f64), - PrimaryButtonSelected(cosmic::widget::segmented_button::Entity), + SetAcceleration(bool, bool), + SetNaturalScroll(bool, bool), + SetScrollFactor(f64, bool), + SetDoubleClickSpeed(u32, bool), + SetMouseSpeed(f64, bool), + PrimaryButtonSelected(cosmic::widget::segmented_button::Entity, bool), // seperate close message, to make sure another isn't closed? ExpandInputSourcePopover(Option), OpenSpecialCharacterDialog(keyboard::SpecialKey), @@ -40,6 +41,9 @@ pub struct Page { // Mouse primary_button: cosmic::widget::segmented_button::SingleSelectModel, + // Touchpad + touchpad_primary_button: cosmic::widget::segmented_button::SingleSelectModel, + // Keyboard expanded_source_popover: Option, sources: Vec, @@ -61,17 +65,25 @@ impl Default for Page { fn default() -> Self { let config = cosmic_config::Config::new("com.system76.CosmicComp", 1).unwrap(); let input_default: InputConfig = get_config(&config, "input-default"); - let input_touchpad = get_config(&config, "input-touchpad"); + let input_touchpad: InputConfig = get_config(&config, "input-touchpad"); let xkb = get_config(&config, "xkb-config"); let mut primary_button = mouse::default_primary_button(); let idx = if input_default.left_handed.unwrap_or(false) { - 0 - } else { 1 + } else { + 0 }; primary_button.activate_position(idx); + let mut touchpad_primary_button = mouse::default_primary_button(); + let idx = if input_touchpad.left_handed.unwrap_or(false) { + 1 + } else { + 0 + }; + touchpad_primary_button.activate_position(idx); + Self { config, input_default, @@ -80,6 +92,9 @@ impl Default for Page { // Mouse primary_button, + // Touchpad + touchpad_primary_button, + // Keyboard expanded_source_popover: None, sources: keyboard::default_input_sources(), @@ -90,61 +105,56 @@ impl Default for Page { } impl Page { - // TODO + fn update_input(&mut self, touchpad: bool, f: F) { + let (name, input_config) = if touchpad { + ("input-touchpad", &mut self.input_touchpad) + } else { + ("input-default", &mut self.input_default) + }; + f(input_config); + if let Err(err) = self.config.set(name, input_config) { + error!(?err, "Failed to set config '{}'", name); + } + } + pub fn update(&mut self, message: Message) -> iced::Command { match message { - Message::SetAcceleration(value) => { + Message::SetAcceleration(value, touchpad) => { let profile = if value { AccelProfile::Adaptive } else { AccelProfile::Flat }; - self.input_default - .acceleration - .get_or_insert(Default::default()) - .profile = Some(profile); - if let Err(err) = self.config.set("input-default", &self.input_default) { - error!(?err, "Failed to set config 'input-default'"); - } + self.update_input(touchpad, |x| { + x.acceleration.get_or_insert(Default::default()).profile = Some(profile); + }); } - Message::SetNaturalScroll(value) => { - self.input_default - .scroll_config + Message::SetNaturalScroll(value, touchpad) => self.update_input(touchpad, |x| { + x.scroll_config .get_or_insert(Default::default()) .natural_scroll = Some(value); - if let Err(err) = self.config.set("input-default", &self.input_default) { - error!(?err, "Failed to set config 'input-default'"); - } - } - Message::SetScrollFactor(value) => { - self.input_default - .scroll_config + }), + Message::SetScrollFactor(value, touchpad) => self.update_input(touchpad, |x| { + x.scroll_config .get_or_insert(Default::default()) - .scroll_factor = Some(value); - if let Err(err) = self.config.set("input-default", &self.input_default) { - error!(?err, "Failed to set config 'input-default'"); - } - } - Message::SetDoubleClickSpeed(_value) => { + .scroll_factor = Some(value) + }), + Message::SetDoubleClickSpeed(_value, _touchpad) => { // TODO } - Message::SetMouseSpeed(value) => { - self.input_default - .acceleration - .get_or_insert(Default::default()) - .speed = value; - if let Err(err) = self.config.set("input-default", &self.input_default) { - error!(?err, "Failed to set config 'input-default'"); - } - } - Message::PrimaryButtonSelected(entity) => { - self.primary_button.activate(entity); - let left_entity = self.primary_button.entity_at(1).unwrap(); - let left_handed = self.primary_button.active() == left_entity; - self.input_default.left_handed = Some(left_handed); - if let Err(err) = self.config.set("input-default", &self.input_default) { - error!(?err, "Failed to set config 'input-default'"); - } + Message::SetMouseSpeed(value, touchpad) => self.update_input(touchpad, |x| { + x.acceleration.get_or_insert(Default::default()).speed = value + }), + Message::PrimaryButtonSelected(entity, touchpad) => { + let select_model = if touchpad { + &mut self.touchpad_primary_button + } else { + &mut self.primary_button + }; + select_model.activate(entity); + let left_entity = select_model.entity_at(1).unwrap(); + let left_handed = select_model.active() == left_entity; + self.update_input(touchpad, |x| x.left_handed = Some(left_handed)); } Message::ExpandInputSourcePopover(value) => { self.expanded_source_popover = value; @@ -204,6 +214,8 @@ impl page::Page for Page { impl page::AutoBind for Page { fn sub_pages(page: page::Insert) -> page::Insert { - page.sub_page::().sub_page::() + page.sub_page::() + .sub_page::() + .sub_page::() } } diff --git a/app/src/pages/input/mouse.rs b/app/src/pages/input/mouse.rs index dea7766..2c88456 100644 --- a/app/src/pages/input/mouse.rs +++ b/app/src/pages/input/mouse.rs @@ -9,7 +9,6 @@ use slotmap::SlotMap; use super::Message; -// XXX pub fn default_primary_button() -> cosmic::widget::segmented_button::SingleSelectModel { let mut model = cosmic::widget::segmented_button::SingleSelectModel::builder() .insert(|b| b.text(fl!("mouse", "primary-button-left"))) @@ -54,13 +53,11 @@ fn mouse() -> Section { let input = binder.page::().expect("input page not found"); - // TODO need something more custom settings::view_section(§ion.title) - // TODO .add(settings::item( &descriptions[0], cosmic::widget::segmented_selection::horizontal(&input.primary_button) - .on_activate(Message::PrimaryButtonSelected), + .on_activate(|x| Message::PrimaryButtonSelected(x, false)), )) .add( settings::item::builder(&descriptions[1]).control(widget::slider( @@ -72,7 +69,7 @@ fn mouse() -> Section { .map_or(0.0, |x| x.speed) + 1.0) * 50.0, - |value| Message::SetMouseSpeed((value / 50.0) - 1.0), + |value| Message::SetMouseSpeed((value / 50.0) - 1.0, false), )), ) .add( @@ -84,13 +81,15 @@ fn mouse() -> Section { .acceleration .as_ref() .map_or(true, |x| x.profile == Some(AccelProfile::Adaptive)), - Message::SetAcceleration, + |x| Message::SetAcceleration(x, false), ), ) .add( settings::item::builder(&descriptions[4]) .description(&descriptions[5]) - .control(widget::slider(0..=100, 0, Message::SetDoubleClickSpeed)), + .control(widget::slider(0..=100, 0, |x| { + Message::SetDoubleClickSpeed(x, false) + })), ) .apply(Element::from) .map(crate::pages::Message::Input) @@ -126,7 +125,7 @@ fn scrolling() -> Section { .log(2.) * 10.0 + 50.0, - |value| Message::SetScrollFactor(2f64.powf((value - 50.0) / 10.0)), + |value| Message::SetScrollFactor(2f64.powf((value - 50.0) / 10.0), false), ), )) .add( @@ -139,7 +138,7 @@ fn scrolling() -> Section { .as_ref() .and_then(|x| x.natural_scroll) .unwrap_or(false), - Message::SetNaturalScroll, + |x| Message::SetNaturalScroll(x, false), ), ) .apply(Element::from) diff --git a/app/src/pages/input/touchpad.rs b/app/src/pages/input/touchpad.rs new file mode 100644 index 0000000..6e2305e --- /dev/null +++ b/app/src/pages/input/touchpad.rs @@ -0,0 +1,142 @@ +use apply::Apply; +use cosmic::iced::widget; +use cosmic::widget::settings; +use cosmic::Element; +use cosmic_comp_config::input::AccelProfile; +use cosmic_settings_page::Section; +use cosmic_settings_page::{self as page, section}; +use slotmap::SlotMap; + +use super::Message; + +#[derive(Default)] +pub struct Page; + +impl page::Page for Page { + fn content( + &self, + sections: &mut SlotMap>, + ) -> Option { + Some(vec![ + sections.insert(touchpad()), + sections.insert(scrolling()), + ]) + } + + fn info(&self) -> page::Info { + page::Info::new("touchpad", "input-touchpad-symbolic") + .title(fl!("touchpad")) + .description(fl!("touchpad", "desc")) + } +} + +impl page::AutoBind for Page {} + +fn touchpad() -> Section { + Section::default() + .descriptions(vec![ + fl!("touchpad", "primary-button"), + fl!("touchpad", "speed"), + fl!("touchpad", "acceleration"), + fl!("touchpad", "acceleration-desc"), + fl!("touchpad", "double-click-speed"), + fl!("touchpad", "double-click-speed-desc"), + ]) + .view::(|binder, _page, section| { + let descriptions = §ion.descriptions; + + let input = binder.page::().expect("input page not found"); + + settings::view_section(§ion.title) + .add(settings::item( + &descriptions[0], + cosmic::widget::segmented_selection::horizontal(&input.touchpad_primary_button) + .on_activate(|x| Message::PrimaryButtonSelected(x, true)), + )) + .add( + settings::item::builder(&descriptions[1]).control(widget::slider( + 0.0..=100.0, + (input + .input_touchpad + .acceleration + .as_ref() + .map_or(0.0, |x| x.speed) + + 1.0) + * 50.0, + |value| Message::SetMouseSpeed((value / 50.0) - 1.0, true), + )), + ) + .add( + settings::item::builder(&descriptions[2]) + .description(&descriptions[3]) + .toggler( + input + .input_touchpad + .acceleration + .as_ref() + .map_or(true, |x| x.profile == Some(AccelProfile::Adaptive)), + |x| Message::SetAcceleration(x, true), + ), + ) + // TODO disable while typing + .add( + settings::item::builder(&descriptions[4]) + .description(&descriptions[5]) + .control(widget::slider(0..=100, 0, |x| { + Message::SetDoubleClickSpeed(x, true) + })), + ) + .apply(Element::from) + .map(crate::pages::Message::Input) + }) +} + +fn scrolling() -> Section { + Section::default() + .title(fl!("mouse-scrolling")) + .descriptions(vec![ + fl!("mouse-scrolling", "speed"), + fl!("mouse-scrolling", "natural"), + fl!("mouse-scrolling", "natural-desc"), + ]) + .view::(|binder, _page, section| { + let descriptions = §ion.descriptions; + + let input = binder.page::().expect("input page not found"); + + settings::view_section(§ion.title) + .add(settings::item( + &descriptions[0], + // TODO show numeric value + // TODO desired range? + widget::slider( + 1.0..=100.0, + input + .input_touchpad + .scroll_config + .as_ref() + .and_then(|x| x.scroll_factor) + .unwrap_or(1.) + .log(2.) + * 10.0 + + 50.0, + |value| Message::SetScrollFactor(2f64.powf((value - 50.0) / 10.0), true), + ), + )) + .add( + settings::item::builder(&descriptions[1]) + .description(&descriptions[2]) + .toggler( + input + .input_touchpad + .scroll_config + .as_ref() + .and_then(|x| x.natural_scroll) + .unwrap_or(false), + |x| Message::SetNaturalScroll(x, true), + ), + ) + .apply(Element::from) + .map(crate::pages::Message::Input) + }) +} diff --git a/i18n/en/cosmic_settings.ftl b/i18n/en/cosmic_settings.ftl index b7e7aa4..f1f0822 100644 --- a/i18n/en/cosmic_settings.ftl +++ b/i18n/en/cosmic_settings.ftl @@ -267,3 +267,14 @@ mouse-scrolling = Scrolling .natural-desc = Scroll the content, instead of the view ## Input: Touchpad + +touchpad = Touchpad + .desc = Touchpad speed, click options, gestures. + .primary-button = Primary button + .primary-button-left = Left + .primary-button-right = Right + .speed = Touchpad speed + .acceleration = Enable touchpad acceleration + .acceleration-desc = Automatically adjusts tracking sensitivty based on speed. + .double-click-speed = Double-click speed + .double-click-speed-desc = Changes how fast double-clicks have to be to register.