diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2023-09-13 16:57:12 +0400 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2023-09-13 16:57:12 +0400 |
| commit | 219ca08836adcd91f42ca24ec20f643af17dd270 (patch) | |
| tree | 3395f5dda3bcd3a2be755bdbc401a43a8a45d2b9 /src | |
| parent | c8b85b83c7d1db9ae4834fa95223cfb8b13e276a (diff) | |
| download | niri-219ca08836adcd91f42ca24ec20f643af17dd270.tar.gz niri-219ca08836adcd91f42ca24ec20f643af17dd270.tar.bz2 niri-219ca08836adcd91f42ca24ec20f643af17dd270.zip | |
Implement minimizing view movement on changes
Before this commit, windows were always left-aligned.
Now, when changing focus, if the window is fully visible, the view
doesn't move. If the window is not fully visible, the view is moved the
minimum amount.
Diffstat (limited to 'src')
| -rw-r--r-- | src/animation.rs | 4 | ||||
| -rw-r--r-- | src/layout.rs | 71 |
2 files changed, 68 insertions, 7 deletions
diff --git a/src/animation.rs b/src/animation.rs index 430e3516..e2b9dc39 100644 --- a/src/animation.rs +++ b/src/animation.rs @@ -46,4 +46,8 @@ impl Animation { let x = (passed / total).clamp(0., 1.); EaseOutCubic.y(x) * (self.to - self.from) + self.from } + + pub fn to(&self) -> f64 { + self.to + } } diff --git a/src/layout.rs b/src/layout.rs index 753529ab..3d85ecbe 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -1340,14 +1340,21 @@ impl<W: LayoutElement> Workspace<W> { self.active_column_idx = idx; - self.view_offset = 0; - let new_x = self.view_pos(); - + let new_x = self.column_x(idx) - PADDING; + let new_view_offset = compute_new_view_offset( + current_x, + self.view_size.w, + new_x, + self.columns[idx].size().w, + ); + + let from_view_offset = current_x - new_x; self.view_offset_anim = Some(Animation::new( - (current_x - new_x) as f64, - 0., + from_view_offset as f64, + new_view_offset as f64, Duration::from_millis(250), )); + self.view_offset = from_view_offset; } fn has_windows(&self) -> bool { @@ -1419,12 +1426,41 @@ impl<W: LayoutElement> Workspace<W> { } fn update_window(&mut self, window: &W) { - let column = self + let (idx, column) = self .columns .iter_mut() - .find(|col| col.contains(window)) + .enumerate() + .find(|(_, col)| col.contains(window)) .unwrap(); column.update_window_sizes(self.view_size); + + if idx == self.active_column_idx { + // We might need to move the view to ensure the resized window is still visible. + let current_x = self.view_pos(); + let new_x = self.column_x(idx) - PADDING; + + let new_view_offset = compute_new_view_offset( + current_x, + self.view_size.w, + new_x, + self.columns[idx].size().w, + ); + + let cur_view_offset = self + .view_offset_anim + .as_ref() + .map(|a| a.to().round() as i32) + .unwrap_or(self.view_offset); + if cur_view_offset != new_view_offset { + let from_view_offset = current_x - new_x; + self.view_offset_anim = Some(Animation::new( + from_view_offset as f64, + new_view_offset as f64, + Duration::from_millis(250), + )); + self.view_offset = from_view_offset; + } + } } fn activate_window(&mut self, window: &W) { @@ -1974,6 +2010,27 @@ pub fn configure_new_window(view_size: Size<i32, Logical>, window: &Window) { }); } +fn compute_new_view_offset(cur_x: i32, view_width: i32, new_x: i32, new_col_width: i32) -> i32 { + // If the column is wider than the view, always left-align it. + if new_col_width + PADDING * 2 >= view_width { + return 0; + } + + // If the column is already fully visible, leave the view as is. + if new_x >= cur_x && new_x + new_col_width + PADDING * 2 <= cur_x + view_width { + return -(new_x - cur_x); + } + + // Otherwise, prefer the aligment that results in less motion from the current position. + let dist_to_left = cur_x.abs_diff(new_x); + let dist_to_right = (cur_x + view_width).abs_diff(new_x + new_col_width + PADDING * 2); + if dist_to_left <= dist_to_right { + 0 + } else { + -(view_width - new_col_width - PADDING * 2) + } +} + #[cfg(test)] mod tests { use std::cell::Cell; |
