Add touchpad settings

This commit is contained in:
Ian Douglas Scott 2023-09-06 14:44:50 -07:00
parent 69b5c3148f
commit cafe56d86c
4 changed files with 225 additions and 61 deletions

View file

@ -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<String>),
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<String>,
sources: Vec<keyboard::InputSource>,
@ -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<F: Fn(&mut InputConfig)>(&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<app::Message> {
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<crate::pages::Message> for Page {
impl page::AutoBind<crate::pages::Message> for Page {
fn sub_pages(page: page::Insert<crate::pages::Message>) -> page::Insert<crate::pages::Message> {
page.sub_page::<keyboard::Page>().sub_page::<mouse::Page>()
page.sub_page::<keyboard::Page>()
.sub_page::<mouse::Page>()
.sub_page::<touchpad::Page>()
}
}

View file

@ -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<crate::pages::Message> {
let input = binder.page::<super::Page>().expect("input page not found");
// TODO need something more custom
settings::view_section(&section.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<crate::pages::Message> {
.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<crate::pages::Message> {
.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<crate::pages::Message> {
.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<crate::pages::Message> {
.as_ref()
.and_then(|x| x.natural_scroll)
.unwrap_or(false),
Message::SetNaturalScroll,
|x| Message::SetNaturalScroll(x, false),
),
)
.apply(Element::from)

View file

@ -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<crate::pages::Message> for Page {
fn content(
&self,
sections: &mut SlotMap<section::Entity, Section<crate::pages::Message>>,
) -> Option<page::Content> {
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<crate::pages::Message> for Page {}
fn touchpad() -> Section<crate::pages::Message> {
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::<Page>(|binder, _page, section| {
let descriptions = &section.descriptions;
let input = binder.page::<super::Page>().expect("input page not found");
settings::view_section(&section.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<crate::pages::Message> {
Section::default()
.title(fl!("mouse-scrolling"))
.descriptions(vec![
fl!("mouse-scrolling", "speed"),
fl!("mouse-scrolling", "natural"),
fl!("mouse-scrolling", "natural-desc"),
])
.view::<Page>(|binder, _page, section| {
let descriptions = &section.descriptions;
let input = binder.page::<super::Page>().expect("input page not found");
settings::view_section(&section.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)
})
}

View file

@ -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.