diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2025-02-08 15:24:02 +0300 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2025-02-10 07:29:33 -0800 |
| commit | 02eccf7762bf01cca0bf066d769e2533e2d5a3d2 (patch) | |
| tree | 25afba081f03c1f4d45a84f415dcf3651196d914 /src/layout/scrolling.rs | |
| parent | 89cf276779d75c52c261d9ef78e1e808021164e4 (diff) | |
| download | niri-02eccf7762bf01cca0bf066d769e2533e2d5a3d2.tar.gz niri-02eccf7762bf01cca0bf066d769e2533e2d5a3d2.tar.bz2 niri-02eccf7762bf01cca0bf066d769e2533e2d5a3d2.zip | |
layout: Fix/add animations around tabbed columns
Diffstat (limited to 'src/layout/scrolling.rs')
| -rw-r--r-- | src/layout/scrolling.rs | 77 |
1 files changed, 76 insertions, 1 deletions
diff --git a/src/layout/scrolling.rs b/src/layout/scrolling.rs index 55ddfc1b..59681cdf 100644 --- a/src/layout/scrolling.rs +++ b/src/layout/scrolling.rs @@ -865,6 +865,19 @@ impl<W: LayoutElement> ScrollingSpace<W> { } } + let target_column = &mut self.columns[col_idx]; + if target_column.display_mode == ColumnDisplay::Tabbed { + if target_column.active_tile_idx == tile_idx { + // Fade out the previously active tile. + let tile = &mut target_column.tiles[prev_active_tile_idx]; + tile.animate_alpha(1., 0., self.options.animations.window_movement.0); + } else { + // Fade out when adding into a tabbed column into the background. + let tile = &mut target_column.tiles[tile_idx]; + tile.animate_alpha(1., 0., self.options.animations.window_movement.0); + } + } + // Adding a wider window into a column increases its width now (even if the window will // shrink later). Move the columns to account for this. let offset = self.column_x(col_idx + 1) - prev_next_x; @@ -1004,6 +1017,8 @@ impl<W: LayoutElement> ScrollingSpace<W> { let column = &mut self.columns[column_idx]; let prev_width = self.data[column_idx].width; + let movement_config = anim_config.unwrap_or(self.options.animations.window_movement.0); + // Animate movement of other tiles. // FIXME: tiles can move by X too, in a centered or resizing layout with one window smaller // than the others. @@ -1012,6 +1027,12 @@ impl<W: LayoutElement> ScrollingSpace<W> { tile.animate_move_y_from(offset_y); } + if column.display_mode == ColumnDisplay::Tabbed && tile_idx != column.active_tile_idx { + // Fade in when removing background tab from a tabbed column. + let tile = &mut column.tiles[tile_idx]; + tile.animate_alpha(0., 1., movement_config); + } + let tile = column.tiles.remove(tile_idx); column.data.remove(tile_idx); @@ -1036,6 +1057,7 @@ impl<W: LayoutElement> ScrollingSpace<W> { is_floating: false, }; + #[allow(clippy::comparison_chain)] // What do you even want here? if tile_idx < column.active_tile_idx { // A tile above was removed; preserve the current position. column.active_tile_idx -= 1; @@ -1044,6 +1066,9 @@ impl<W: LayoutElement> ScrollingSpace<W> { if tile_idx == column.tiles.len() { // The bottom tile was removed and it was active, update active idx to remain valid. column.activate_idx(tile_idx - 1); + } else { + // Ensure the newly active tile animates to opaque. + column.tiles[tile_idx].ensure_alpha_animates_to_1(); } } @@ -1052,7 +1077,6 @@ impl<W: LayoutElement> ScrollingSpace<W> { let offset = prev_width - column.width(); // Animate movement of the other columns. - let movement_config = anim_config.unwrap_or(self.options.animations.window_movement.0); if self.active_column_idx <= column_idx { for col in &mut self.columns[column_idx + 1..] { col.animate_move_from_with_config(offset, movement_config); @@ -1980,6 +2004,7 @@ impl<W: LayoutElement> ScrollingSpace<W> { // Animations self.columns[target_column_idx].tiles[target_tile_idx] .animate_move_from(source_pt - target_pt); + self.columns[target_column_idx].tiles[target_tile_idx].ensure_alpha_animates_to_1(); // FIXME: this stop_move_animations() causes the target tile animation to "reset" when // swapping. It's here as a workaround to stop the unwanted animation of moving the source @@ -1989,6 +2014,7 @@ impl<W: LayoutElement> ScrollingSpace<W> { self.columns[source_column_idx].tiles[source_tile_idx].stop_move_animations(); self.columns[source_column_idx].tiles[source_tile_idx] .animate_move_from(target_pt - source_pt); + self.columns[source_column_idx].tiles[source_tile_idx].ensure_alpha_animates_to_1(); self.activate_column(target_column_idx); } @@ -2602,6 +2628,12 @@ impl<W: LayoutElement> ScrollingSpace<W> { let focus_ring = focus_ring && first; first = false; + // In the scrolling layout, we currently use visible only for hidden tabs in the + // tabbed mode. We want to animate their opacity when going in and out of tabbed + // mode, so we don't want to apply "visible" immediately. However, "visible" is + // also used for input handling, and there we *do* want to apply it immediately. + // So, let's just selectively ignore "visible" here when animating alpha. + let visible = visible || tile.alpha_animation.is_some(); if !visible { continue; } @@ -3521,6 +3553,8 @@ impl<W: LayoutElement> Column<W> { self.active_tile_idx = idx; + self.tiles[idx].ensure_alpha_animates_to_1(); + true } @@ -4258,6 +4292,47 @@ impl<W: LayoutElement> Column<W> { return; } + // Animate the movement. + // + // We're doing some shortcuts here because we know that currently normal vs. tabbed can + // only cause a vertical shift + a shift to the origin. + // + // Doing it this way to avoid storing all tile positions in a vector. If more display modes + // are added it might be simpler to just collect everything into a smallvec. + let prev_origin = self.tiles_origin(); + self.display_mode = display; + let new_origin = self.tiles_origin(); + let origin_delta = prev_origin - new_origin; + + // When need to walk the tiles in the normal display mode to get the right offsets. + self.display_mode = ColumnDisplay::Normal; + for (tile, pos) in self.tiles_mut() { + let mut y_delta = pos.y - prev_origin.y; + + // Invert the Y motion when transitioning *to* normal display mode. + if display == ColumnDisplay::Normal { + y_delta *= -1.; + } + + let mut delta = origin_delta; + delta.y += y_delta; + tile.animate_move_from(delta); + } + + // Animate the opacity. + for (idx, tile) in self.tiles.iter_mut().enumerate() { + let is_active = idx == self.active_tile_idx; + if !is_active { + let (from, to) = if display == ColumnDisplay::Tabbed { + (1., 0.) + } else { + (0., 1.) + }; + tile.animate_alpha(from, to, self.options.animations.window_movement.0); + } + } + + // Now switch the display mode for real. self.display_mode = display; self.update_tile_sizes(true); } |
