aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2024-03-05 13:32:57 +0400
committerIvan Molodetskikh <yalterz@gmail.com>2024-03-05 13:32:57 +0400
commitf9127616b02eb12b462aca3e48fa27bf0479a4b0 (patch)
treef7552abcb80253f29b01ce37583d960e9561ad85 /src
parentae89b2e514fd4c22a38c2dce258707c369ca944a (diff)
downloadniri-f9127616b02eb12b462aca3e48fa27bf0479a4b0.tar.gz
niri-f9127616b02eb12b462aca3e48fa27bf0479a4b0.tar.bz2
niri-f9127616b02eb12b462aca3e48fa27bf0479a4b0.zip
Implement rubber banding for the vertical gesture
Diffstat (limited to 'src')
-rw-r--r--src/layout/monitor.rs22
-rw-r--r--src/lib.rs1
-rw-r--r--src/rubber_band.rs39
3 files changed, 59 insertions, 3 deletions
diff --git a/src/layout/monitor.rs b/src/layout/monitor.rs
index f2e4c30e..f817ef1a 100644
--- a/src/layout/monitor.rs
+++ b/src/layout/monitor.rs
@@ -15,12 +15,18 @@ use super::workspace::{
use super::{LayoutElement, Options};
use crate::animation::Animation;
use crate::render_helpers::renderer::NiriRenderer;
+use crate::rubber_band::RubberBand;
use crate::swipe_tracker::SwipeTracker;
use crate::utils::output_size;
/// Amount of touchpad movement to scroll the height of one workspace.
const WORKSPACE_GESTURE_MOVEMENT: f64 = 300.;
+const WORKSPACE_GESTURE_RUBBER_BAND: RubberBand = RubberBand {
+ stiffness: 0.5,
+ limit: 0.05,
+};
+
#[derive(Debug)]
pub struct Monitor<W: LayoutElement> {
/// Output for this monitor.
@@ -762,7 +768,8 @@ impl<W: LayoutElement> Monitor<W> {
let min = gesture.center_idx.saturating_sub(1) as f64;
let max = (gesture.center_idx + 1).min(self.workspaces.len() - 1) as f64;
- let new_idx = (gesture.center_idx as f64 + pos).clamp(min, max);
+ let new_idx = gesture.center_idx as f64 + pos;
+ let new_idx = WORKSPACE_GESTURE_RUBBER_BAND.clamp(min, max, new_idx);
if gesture.current_idx == new_idx {
return Some(false);
@@ -783,14 +790,23 @@ impl<W: LayoutElement> Monitor<W> {
return true;
}
- let velocity = gesture.tracker.velocity() / WORKSPACE_GESTURE_MOVEMENT;
+ let mut velocity = gesture.tracker.velocity() / WORKSPACE_GESTURE_MOVEMENT;
+ let current_pos = gesture.tracker.pos() / WORKSPACE_GESTURE_MOVEMENT;
let pos = gesture.tracker.projected_end_pos() / WORKSPACE_GESTURE_MOVEMENT;
let min = gesture.center_idx.saturating_sub(1) as f64;
let max = (gesture.center_idx + 1).min(self.workspaces.len() - 1) as f64;
- let new_idx = (gesture.center_idx as f64 + pos).clamp(min, max);
+ let new_idx = gesture.center_idx as f64 + pos;
+
+ let new_idx = WORKSPACE_GESTURE_RUBBER_BAND.clamp(min, max, new_idx);
let new_idx = new_idx.round() as usize;
+ velocity *= WORKSPACE_GESTURE_RUBBER_BAND.clamp_derivative(
+ min,
+ max,
+ gesture.center_idx as f64 + current_pos,
+ );
+
self.active_workspace_idx = new_idx;
self.workspace_switch = Some(WorkspaceSwitch::Animation(Animation::new(
gesture.current_idx,
diff --git a/src/lib.rs b/src/lib.rs
index 9ccb0c2e..08be5398 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -15,6 +15,7 @@ pub mod layout;
pub mod niri;
pub mod protocols;
pub mod render_helpers;
+pub mod rubber_band;
pub mod swipe_tracker;
pub mod ui;
pub mod utils;
diff --git a/src/rubber_band.rs b/src/rubber_band.rs
new file mode 100644
index 00000000..1543d71e
--- /dev/null
+++ b/src/rubber_band.rs
@@ -0,0 +1,39 @@
+#[derive(Debug, Clone, Copy)]
+pub struct RubberBand {
+ pub stiffness: f64,
+ pub limit: f64,
+}
+
+impl RubberBand {
+ pub fn band(&self, x: f64) -> f64 {
+ let c = self.stiffness;
+ let d = self.limit;
+
+ (1. - (1. / (x * c / d + 1.))) * d
+ }
+
+ pub fn derivative(&self, x: f64) -> f64 {
+ let c = self.stiffness;
+ let d = self.limit;
+
+ c * d * d / (c * x + d).powi(2)
+ }
+
+ pub fn clamp(&self, min: f64, max: f64, x: f64) -> f64 {
+ let clamped = x.clamp(min, max);
+ let sign = if x < clamped { -1. } else { 1. };
+ let diff = (x - clamped).abs();
+
+ clamped + sign * self.band(diff)
+ }
+
+ pub fn clamp_derivative(&self, min: f64, max: f64, x: f64) -> f64 {
+ if min <= x && x <= max {
+ return 1.;
+ }
+
+ let clamped = x.clamp(min, max);
+ let diff = (x - clamped).abs();
+ self.derivative(diff)
+ }
+}