aboutsummaryrefslogtreecommitdiff
path: root/src/layout/scrolling.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/layout/scrolling.rs')
-rw-r--r--src/layout/scrolling.rs105
1 files changed, 102 insertions, 3 deletions
diff --git a/src/layout/scrolling.rs b/src/layout/scrolling.rs
index 81f01559..03eb1552 100644
--- a/src/layout/scrolling.rs
+++ b/src/layout/scrolling.rs
@@ -123,7 +123,7 @@ struct ColumnData {
}
#[derive(Debug)]
-enum ViewOffset {
+pub(super) enum ViewOffset {
/// The view offset is static.
Static(f64),
/// The view offset is animating.
@@ -133,7 +133,7 @@ enum ViewOffset {
}
#[derive(Debug)]
-struct ViewGesture {
+pub(super) struct ViewGesture {
current_view_offset: f64,
tracker: SwipeTracker,
delta_from_tracker: f64,
@@ -141,6 +141,10 @@ struct ViewGesture {
stationary_view_offset: f64,
/// Whether the gesture is controlled by the touchpad.
is_touchpad: bool,
+
+ // If this gesture is for drag-and-drop scrolling, this is the last event's unadjusted
+ // timestamp.
+ dnd_last_event_time: Option<Duration>,
}
#[derive(Debug)]
@@ -324,6 +328,17 @@ impl<W: LayoutElement> ScrollingSpace<W> {
}
}
+ if let ViewOffset::Gesture(gesture) = &mut self.view_offset {
+ // Make sure the last event time doesn't go too much out of date (for
+ // workspaces not under cursor), causing sudden jumps.
+ //
+ // This happens after any dnd_scroll_gesture_scroll() calls (in
+ // Layout::advance_animations()), so it doesn't mess up the time delta there.
+ if let Some(last_time) = &mut gesture.dnd_last_event_time {
+ *last_time = self.clock.now_unadjusted();
+ }
+ }
+
for col in &mut self.columns {
col.advance_animations();
}
@@ -2711,10 +2726,34 @@ impl<W: LayoutElement> ScrollingSpace<W> {
delta_from_tracker: self.view_offset.current(),
stationary_view_offset: self.view_offset.stationary(),
is_touchpad,
+ dnd_last_event_time: None,
};
self.view_offset = ViewOffset::Gesture(gesture);
}
+ pub fn dnd_scroll_gesture_begin(&mut self) {
+ if let ViewOffset::Gesture(ViewGesture {
+ dnd_last_event_time: Some(_),
+ ..
+ }) = &self.view_offset
+ {
+ // Already active.
+ return;
+ }
+
+ let gesture = ViewGesture {
+ current_view_offset: self.view_offset.current(),
+ tracker: SwipeTracker::new(),
+ delta_from_tracker: self.view_offset.current(),
+ stationary_view_offset: self.view_offset.stationary(),
+ is_touchpad: false,
+ dnd_last_event_time: Some(self.clock.now_unadjusted()),
+ };
+ self.view_offset = ViewOffset::Gesture(gesture);
+
+ self.interactive_resize = None;
+ }
+
pub fn view_offset_gesture_update(
&mut self,
delta_x: f64,
@@ -2725,7 +2764,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
return None;
};
- if gesture.is_touchpad != is_touchpad {
+ if gesture.is_touchpad != is_touchpad || gesture.dnd_last_event_time.is_some() {
return None;
}
@@ -2743,6 +2782,61 @@ impl<W: LayoutElement> ScrollingSpace<W> {
Some(true)
}
+ pub fn dnd_scroll_gesture_scroll(&mut self, delta: f64) {
+ let ViewOffset::Gesture(gesture) = &mut self.view_offset else {
+ return;
+ };
+
+ let Some(last_time) = gesture.dnd_last_event_time else {
+ // Not a DnD scroll.
+ return;
+ };
+
+ let now = self.clock.now_unadjusted();
+ gesture.dnd_last_event_time = Some(now);
+ let time_delta = now.saturating_sub(last_time).as_secs_f64();
+
+ let delta = delta * time_delta * 50.;
+
+ gesture.tracker.push(delta, now);
+
+ let view_offset = gesture.tracker.pos() + gesture.delta_from_tracker;
+
+ // Clamp it so that it doesn't go too much out of bounds.
+ let (leftmost, rightmost) = if self.columns.is_empty() {
+ (0., 0.)
+ } else {
+ let gaps = self.options.gaps;
+
+ let mut leftmost = -self.working_area.size.w;
+
+ let last_col_idx = self.columns.len() - 1;
+ let last_col_x = self
+ .columns
+ .iter()
+ .take(last_col_idx)
+ .fold(0., |col_x, col| col_x + col.width() + gaps);
+ let last_col_width = self.data[last_col_idx].width;
+ let mut rightmost = last_col_x + last_col_width - self.working_area.loc.x;
+
+ let active_col_x = self
+ .columns
+ .iter()
+ .take(self.active_column_idx)
+ .fold(0., |col_x, col| col_x + col.width() + gaps);
+ leftmost -= active_col_x;
+ rightmost -= active_col_x;
+
+ (leftmost, rightmost)
+ };
+ let min_offset = f64::min(leftmost, rightmost);
+ let max_offset = f64::max(leftmost, rightmost);
+ let clamped_offset = view_offset.clamp(min_offset, max_offset);
+
+ gesture.delta_from_tracker += clamped_offset - view_offset;
+ gesture.current_view_offset = clamped_offset;
+ }
+
pub fn view_offset_gesture_end(&mut self, _cancelled: bool, is_touchpad: Option<bool>) -> bool {
let ViewOffset::Gesture(gesture) = &mut self.view_offset else {
return false;
@@ -3229,6 +3323,11 @@ impl<W: LayoutElement> ScrollingSpace<W> {
}
#[cfg(test)]
+ pub(super) fn view_offset(&self) -> &ViewOffset {
+ &self.view_offset
+ }
+
+ #[cfg(test)]
pub fn verify_invariants(&self, working_area: Rectangle<f64, Logical>) {
assert!(self.view_size.w > 0.);
assert!(self.view_size.h > 0.);