diff --git a/crates/rnote-ui/data/icons/scalable/actions/touch-disabled-symbolic.svg b/crates/rnote-ui/data/icons/scalable/actions/touch-disabled-symbolic.svg new file mode 100644 index 0000000000..542d81314e --- /dev/null +++ b/crates/rnote-ui/data/icons/scalable/actions/touch-disabled-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/crates/rnote-ui/data/resources.gresource.xml b/crates/rnote-ui/data/resources.gresource.xml index 5532364b4b..1e3c8bf61a 100644 --- a/crates/rnote-ui/data/resources.gresource.xml +++ b/crates/rnote-ui/data/resources.gresource.xml @@ -78,6 +78,7 @@ icons/scalable/actions/emojichooser-symbolic.svg icons/scalable/actions/fill-color-symbolic.svg icons/scalable/actions/focus-mode-symbolic.svg + icons/scalable/actions/touch-disabled-symbolic.svg icons/scalable/actions/keyboard-ctrl-space-shortcut-symbolic.svg icons/scalable/actions/minus-symbolic.svg icons/scalable/actions/misc-menu-symbolic.svg diff --git a/crates/rnote-ui/data/ui/mainheader.ui b/crates/rnote-ui/data/ui/mainheader.ui index be5de3e529..f63f40654d 100644 --- a/crates/rnote-ui/data/ui/mainheader.ui +++ b/crates/rnote-ui/data/ui/mainheader.ui @@ -61,6 +61,13 @@ Focus Mode + + + touch-disabled-symbolic + win.block-touch + Block Touch + + diff --git a/crates/rnote-ui/src/appwindow/actions.rs b/crates/rnote-ui/src/appwindow/actions.rs index 740ca2245e..2edf7f28cc 100644 --- a/crates/rnote-ui/src/appwindow/actions.rs +++ b/crates/rnote-ui/src/appwindow/actions.rs @@ -150,6 +150,8 @@ impl RnAppWindow { let action_block_pinch_zoom = gio::PropertyAction::new("block-pinch-zoom", self, "block-pinch-zoom"); self.add_action(&action_block_pinch_zoom); + let action_block_touch = gio::PropertyAction::new("block-touch", self, "block-touch"); + self.add_action(&action_block_touch); let action_respect_borders = gio::PropertyAction::new("respect-borders", self, "respect-borders"); self.add_action(&action_respect_borders); diff --git a/crates/rnote-ui/src/appwindow/imp.rs b/crates/rnote-ui/src/appwindow/imp.rs index 438b7f2c67..90131ea6a5 100644 --- a/crates/rnote-ui/src/appwindow/imp.rs +++ b/crates/rnote-ui/src/appwindow/imp.rs @@ -26,6 +26,7 @@ pub(crate) struct RnAppWindow { pub(crate) autosave_interval_secs: Cell, pub(crate) righthanded: Cell, pub(crate) block_pinch_zoom: Cell, + pub(crate) block_touch: Cell, pub(crate) respect_borders: Cell, pub(crate) touch_drawing: Cell, pub(crate) focus_mode: Cell, @@ -65,6 +66,7 @@ impl Default for RnAppWindow { autosave_interval_secs: Cell::new(super::RnAppWindow::AUTOSAVE_INTERVAL_DEFAULT), righthanded: Cell::new(true), block_pinch_zoom: Cell::new(false), + block_touch: Cell::new(false), respect_borders: Cell::new(false), touch_drawing: Cell::new(false), focus_mode: Cell::new(false), @@ -163,6 +165,9 @@ impl ObjectImpl for RnAppWindow { glib::ParamSpecBoolean::builder("block-pinch-zoom") .default_value(false) .build(), + glib::ParamSpecBoolean::builder("block-touch") + .default_value(false) + .build(), glib::ParamSpecBoolean::builder("respect-borders") .default_value(false) .build(), @@ -195,6 +200,7 @@ impl ObjectImpl for RnAppWindow { "autosave-interval-secs" => self.autosave_interval_secs.get().to_value(), "righthanded" => self.righthanded.get().to_value(), "block-pinch-zoom" => self.block_pinch_zoom.get().to_value(), + "block-touch" => self.block_touch.get().to_value(), "respect-borders" => self.respect_borders.get().to_value(), "touch-drawing" => self.touch_drawing.get().to_value(), "focus-mode" => self.focus_mode.get().to_value(), @@ -280,6 +286,10 @@ impl ObjectImpl for RnAppWindow { value.get().expect("The value needs to be of type `bool`"); self.block_pinch_zoom.replace(block_pinch_zoom); } + "block-touch" => { + let block_touch: bool = value.get().expect("The value needs to be of type `bool`"); + self.block_touch.replace(block_touch); + } "respect-borders" => { let respect_borders: bool = value.get().expect("The value needs to be of type `bool`"); diff --git a/crates/rnote-ui/src/appwindow/mod.rs b/crates/rnote-ui/src/appwindow/mod.rs index d8b7e23bb3..12e5a162c3 100644 --- a/crates/rnote-ui/src/appwindow/mod.rs +++ b/crates/rnote-ui/src/appwindow/mod.rs @@ -150,6 +150,16 @@ impl RnAppWindow { self.set_property("focus-mode", focus_mode.to_value()); } + #[allow(unused)] + pub(crate) fn block_touch(&self) -> bool { + self.property::("block-touch") + } + + #[allow(unused)] + pub(crate) fn set_block_touch(&self, focus_mode: bool) { + self.set_property("block-touch", focus_mode.to_value()); + } + #[allow(unused)] pub(crate) fn devel_mode(&self) -> bool { self.property::("devel-mode") diff --git a/crates/rnote-ui/src/canvaswrapper.rs b/crates/rnote-ui/src/canvaswrapper.rs index 7b6cec5104..c7b01d8cc9 100644 --- a/crates/rnote-ui/src/canvaswrapper.rs +++ b/crates/rnote-ui/src/canvaswrapper.rs @@ -17,6 +17,7 @@ use std::time::Instant; #[derive(Debug, Default)] struct Connections { appwindow_block_pinch_zoom_bind: Option, + appwindow_block_touch_bind: Option, appwindow_show_scrollbars_bind: Option, appwindow_inertial_scrolling_bind: Option, appwindow_righthanded_bind: Option, @@ -32,6 +33,7 @@ mod imp { pub(crate) canvas_touch_drawing_handler: RefCell>, pub(crate) show_scrollbars: Cell, pub(crate) block_pinch_zoom: Cell, + pub(crate) block_touch: Cell, pub(crate) inertial_scrolling: Cell, pub(crate) pointer_pos: Cell>>, pub(crate) last_contextmenu_pos: Cell>>, @@ -131,6 +133,7 @@ mod imp { canvas_touch_drawing_handler: RefCell::new(None), show_scrollbars: Cell::new(false), block_pinch_zoom: Cell::new(false), + block_touch: Cell::new(false), inertial_scrolling: Cell::new(true), pointer_pos: Cell::new(None), last_contextmenu_pos: Cell::new(None), @@ -244,6 +247,9 @@ mod imp { glib::ParamSpecBoolean::builder("block-pinch-zoom") .default_value(false) .build(), + glib::ParamSpecBoolean::builder("block-touch") + .default_value(false) + .build(), glib::ParamSpecBoolean::builder("inertial-scrolling") .default_value(true) .build(), @@ -256,6 +262,7 @@ mod imp { match pspec.name() { "show-scrollbars" => self.show_scrollbars.get().to_value(), "block-pinch-zoom" => self.block_pinch_zoom.get().to_value(), + "block-touch" => self.block_pinch_zoom.get().to_value(), "inertial-scrolling" => self.inertial_scrolling.get().to_value(), _ => unimplemented!(), } @@ -279,6 +286,15 @@ mod imp { self.block_pinch_zoom.replace(block_pinch_zoom); self.canvas_zoom_gesture_update(); } + "block-touch" => { + let block_touch = value + .get::() + .expect("The value needs to be of type `bool`"); + self.block_touch.replace(block_touch); + self.canvas_touch_pan_update(); + self.canvas_zoom_gesture_update(); + self.canvas_kinetic_scrolling_update(); + } "inertial-scrolling" => { let inertial_scrolling = value .get::() @@ -296,7 +312,10 @@ mod imp { impl RnCanvasWrapper { fn canvas_zoom_gesture_update(&self) { - if !self.block_pinch_zoom.get() && !self.canvas.touch_drawing() { + if !self.block_pinch_zoom.get() + && !self.block_touch.get() + && !self.canvas.touch_drawing() + { self.canvas_zoom_gesture .set_propagation_phase(PropagationPhase::Capture); } else { @@ -305,9 +324,30 @@ mod imp { } } + fn canvas_touch_pan_update(&self) { + if !self.block_touch.get() && !self.canvas.touch_drawing() { + self.canvas_drag_gesture + .set_propagation_phase(PropagationPhase::Bubble); + self.touch_two_finger_long_press_gesture + .set_propagation_phase(PropagationPhase::Capture); + self.touch_long_press_gesture + .set_propagation_phase(PropagationPhase::Capture); + } else { + // set everythinbg to `None` + self.canvas_drag_gesture + .set_propagation_phase(PropagationPhase::None); + self.touch_two_finger_long_press_gesture + .set_propagation_phase(PropagationPhase::None); + self.touch_long_press_gesture + .set_propagation_phase(PropagationPhase::None); + } + } + fn canvas_kinetic_scrolling_update(&self) { self.scroller.set_kinetic_scrolling( - !self.canvas.touch_drawing() && self.inertial_scrolling.get(), + !self.block_touch.get() + && !self.canvas.touch_drawing() + && self.inertial_scrolling.get(), ); } @@ -405,6 +445,9 @@ mod imp { #[weak(rename_to=canvaswrapper)] obj, move |_, _, _| { + if canvaswrapper.block_touch() { + return (); + } // We don't claim the sequence, because we we want to allow touch zooming. // When the zoom gesture is recognized, it claims it and denies this touch drag gesture. @@ -420,6 +463,9 @@ mod imp { #[weak(rename_to=canvaswrapper)] obj, move |_, x, y| { + if canvaswrapper.block_touch() { + return (); + } let canvas = canvaswrapper.canvas(); let new_offset = touch_drag_start.get() - na::vector![x, y]; let widget_flags = canvas.engine_mut().camera_set_offset_expand(new_offset); @@ -430,6 +476,9 @@ mod imp { #[weak(rename_to=canvaswrapper)] obj, move |_, _, _| { + if canvaswrapper.block_touch() { + return (); + } let widget_flags = canvaswrapper .canvas() .engine_mut() @@ -832,6 +881,7 @@ impl RnCanvasWrapper { pub(crate) fn set_show_scrollbars(&self, show_scrollbars: bool) { self.set_property("show-scrollbars", show_scrollbars.to_value()); } + #[allow(unused)] pub(crate) fn block_pinch_zoom(&self) -> bool { self.property::("block-pinch-zoom") @@ -842,6 +892,16 @@ impl RnCanvasWrapper { self.set_property("block-pinch-zoom", block_pinch_zoom); } + #[allow(unused)] + pub(crate) fn block_touch(&self) -> bool { + self.property::("block-touch") + } + + #[allow(unused)] + pub(crate) fn set_block_touch(&self, block_touch: bool) { + self.set_property("block-touch", block_touch); + } + #[allow(unused)] pub(crate) fn inertial_scrolling(&self) -> bool { self.property::("inertial-scrolling") @@ -885,6 +945,11 @@ impl RnCanvasWrapper { .sync_create() .build(); + let appwindow_block_touch_bind = appwindow + .bind_property("block-touch", self, "block_touch") + .sync_create() + .build(); + let appwindow_show_scrollbars_bind = appwindow .sidebar() .settings_panel() @@ -920,6 +985,12 @@ impl RnCanvasWrapper { { old.unbind() } + if let Some(old) = connections + .appwindow_block_touch_bind + .replace(appwindow_block_touch_bind) + { + old.unbind() + } if let Some(old) = connections .appwindow_show_scrollbars_bind .replace(appwindow_show_scrollbars_bind) @@ -951,6 +1022,9 @@ impl RnCanvasWrapper { if let Some(old) = connections.appwindow_block_pinch_zoom_bind.take() { old.unbind(); } + if let Some(old) = connections.appwindow_block_touch_bind.take() { + old.unbind(); + } if let Some(old) = connections.appwindow_show_scrollbars_bind.take() { old.unbind(); }