Implement rubber banding for the vertical gesture

This commit is contained in:
Ivan Molodetskikh 2024-03-05 13:32:57 +04:00
parent ae89b2e514
commit f9127616b0
3 changed files with 59 additions and 3 deletions

View File

@ -15,12 +15,18 @@ use super::workspace::{
use super::{LayoutElement, Options}; use super::{LayoutElement, Options};
use crate::animation::Animation; use crate::animation::Animation;
use crate::render_helpers::renderer::NiriRenderer; use crate::render_helpers::renderer::NiriRenderer;
use crate::rubber_band::RubberBand;
use crate::swipe_tracker::SwipeTracker; use crate::swipe_tracker::SwipeTracker;
use crate::utils::output_size; use crate::utils::output_size;
/// Amount of touchpad movement to scroll the height of one workspace. /// Amount of touchpad movement to scroll the height of one workspace.
const WORKSPACE_GESTURE_MOVEMENT: f64 = 300.; const WORKSPACE_GESTURE_MOVEMENT: f64 = 300.;
const WORKSPACE_GESTURE_RUBBER_BAND: RubberBand = RubberBand {
stiffness: 0.5,
limit: 0.05,
};
#[derive(Debug)] #[derive(Debug)]
pub struct Monitor<W: LayoutElement> { pub struct Monitor<W: LayoutElement> {
/// Output for this monitor. /// Output for this monitor.
@ -762,7 +768,8 @@ impl<W: LayoutElement> Monitor<W> {
let min = gesture.center_idx.saturating_sub(1) as f64; let min = gesture.center_idx.saturating_sub(1) as f64;
let max = (gesture.center_idx + 1).min(self.workspaces.len() - 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 { if gesture.current_idx == new_idx {
return Some(false); return Some(false);
@ -783,14 +790,23 @@ impl<W: LayoutElement> Monitor<W> {
return true; 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 pos = gesture.tracker.projected_end_pos() / WORKSPACE_GESTURE_MOVEMENT;
let min = gesture.center_idx.saturating_sub(1) as f64; let min = gesture.center_idx.saturating_sub(1) as f64;
let max = (gesture.center_idx + 1).min(self.workspaces.len() - 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; 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.active_workspace_idx = new_idx;
self.workspace_switch = Some(WorkspaceSwitch::Animation(Animation::new( self.workspace_switch = Some(WorkspaceSwitch::Animation(Animation::new(
gesture.current_idx, gesture.current_idx,

View File

@ -15,6 +15,7 @@ pub mod layout;
pub mod niri; pub mod niri;
pub mod protocols; pub mod protocols;
pub mod render_helpers; pub mod render_helpers;
pub mod rubber_band;
pub mod swipe_tracker; pub mod swipe_tracker;
pub mod ui; pub mod ui;
pub mod utils; pub mod utils;

39
src/rubber_band.rs Normal file
View File

@ -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)
}
}