aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2023-09-13 16:57:12 +0400
committerIvan Molodetskikh <yalterz@gmail.com>2023-09-13 16:57:12 +0400
commit219ca08836adcd91f42ca24ec20f643af17dd270 (patch)
tree3395f5dda3bcd3a2be755bdbc401a43a8a45d2b9 /src
parentc8b85b83c7d1db9ae4834fa95223cfb8b13e276a (diff)
downloadniri-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.rs4
-rw-r--r--src/layout.rs71
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;