diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2025-02-15 11:15:35 +0300 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2025-02-15 13:28:57 +0300 |
| commit | d7f3ca00c70b264032025c262b3c0b10e67c04be (patch) | |
| tree | 6482ce869331d5befa38dfed24efb34c285d4a17 /src/layout/scrolling.rs | |
| parent | fd8140e091df24e02de279b287d42b087eab19e2 (diff) | |
| download | niri-d7f3ca00c70b264032025c262b3c0b10e67c04be.tar.gz niri-d7f3ca00c70b264032025c262b3c0b10e67c04be.tar.bz2 niri-d7f3ca00c70b264032025c262b3c0b10e67c04be.zip | |
Implement scrolling the view during interactive move
Diffstat (limited to 'src/layout/scrolling.rs')
| -rw-r--r-- | src/layout/scrolling.rs | 105 |
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.); |
