diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/layout/scrolling.rs | 35 | ||||
| -rw-r--r-- | src/layout/tests/animations.rs | 56 | ||||
| -rw-r--r-- | src/layout/tile.rs | 11 |
3 files changed, 71 insertions, 31 deletions
diff --git a/src/layout/scrolling.rs b/src/layout/scrolling.rs index 94f2aa97..1d43ac56 100644 --- a/src/layout/scrolling.rs +++ b/src/layout/scrolling.rs @@ -4056,12 +4056,35 @@ impl<W: LayoutElement> Column<W> { // windows in the column, so they should all be animated. How should this interact with // animated vs. non-animated resizes? For example, an animated +20 resize followed by two // non-animated -10 resizes. - if !is_tabbed && tile.resize_animation().is_some() && offset != 0. { - for tile in &mut self.tiles[tile_idx + 1..] { - tile.animate_move_y_from_with_config( - offset, - self.options.animations.window_resize.anim, - ); + if !is_tabbed && offset != 0. { + if tile.resize_animation().is_some() { + // If there's a resize animation (that may have just started in + // tile.update_window()), then the apparent size change is smooth with no sudden + // jumps. This corresponds to adding an Y animation to tiles below. + for tile in &mut self.tiles[tile_idx + 1..] { + tile.animate_move_y_from_with_config( + offset, + self.options.animations.window_resize.anim, + ); + } + } else { + // There's no resize animation, but the offset is nonzero. This could happen for + // example: + // - if the window resized on its own, which we don't animate + // - if the window resized by less than 10 px (the resize threshold) + // + // The latter case could also cancel an ongoing resize animation. + // + // Now, stationary tiles below shouldn't react to this offset change in any way, + // i.e. their apparent Y position should jump together with the resize. However, + // tiles below that are already animating an Y movement should offset their + // animations to avoid the jump. + // + // Notably, this is necessary to fix the animation jump when resizing height back + // and forth in quick succession (in a way that cancels the resize animation). + for tile in &mut self.tiles[tile_idx + 1..] { + tile.offset_move_y_anim_current(offset); + } } } } diff --git a/src/layout/tests/animations.rs b/src/layout/tests/animations.rs index 817304df..3db2bfe8 100644 --- a/src/layout/tests/animations.rs +++ b/src/layout/tests/animations.rs @@ -269,14 +269,20 @@ fn height_resize_and_cancel() { ]; check_ops_on_layout(&mut layout, &ops); - // Since the resize animation is cancelled, the height goes to the new value immediately, and - // the Y position should also go to 100 immediately, cancelling the movement. - // - // FIXME: right now, the Y position jumps to 5 and will continue animating to 100 from there - // because cancelling the resize anim doesn't cancel the induced Y movement. + // Since the resize animation is cancelled, the height goes to the new value immediately. The Y + // position doesn't jump, instead the animation is offset to preserve the current position. assert_snapshot!(format_tiles(&layout), @r" 100 × 100 at x: 0 y: 0 - 200 × 200 at x: 0 y: 5 + 200 × 200 at x: 0 y:105 + "); + + // Advance to the end of the move animation. + Op::AdvanceAnimations { msec_delta: 950 }.apply(&mut layout); + + // Final state. + assert_snapshot!(format_tiles(&layout), @r" + 100 × 100 at x: 0 y: 0 + 200 × 200 at x: 0 y:100 "); } @@ -506,23 +512,30 @@ fn height_resize_and_cancel_during_another_y_anim() { ]; check_ops_on_layout(&mut layout, &ops); - // Since the resize anim was cancelled, second window's Y should jump a little to go back to - // its original trajectory. - // - // FIXME: right now, the Y position jumps and will continue to animate from there because - // cancelling the resize anim doesn't cancel the induced Y movement. + // Since the resize anim was cancelled, second window's Y anim is adjusted to preserve the + // current position while targeting the new final position. assert_snapshot!(format_tiles(&layout), @r" 100 × 100 at x: 0 y: 0 - 200 × 200 at x: 45 y:-43 + 200 × 200 at x: 45 y: 58 "); // Advance the time to complete the consume movement. Op::AdvanceAnimations { msec_delta: 450 }.apply(&mut layout); - // Final state. Y should be at 100 since the resize-induced Y anim was cancelled. + // Since we don't cancel the resize-induced part of the anim (in fact the move Y anim isn't + // split into parts, so there's no way to tell), it keeps going still. assert_snapshot!(format_tiles(&layout), @r" 100 × 100 at x: 0 y: 0 - 200 × 200 at x: 0 y: 25 + 200 × 200 at x: 0 y: 78 + "); + + // Advance the time to complete the resize-induced anim. + Op::AdvanceAnimations { msec_delta: 550 }.apply(&mut layout); + + // Final state. + assert_snapshot!(format_tiles(&layout), @r" + 100 × 100 at x: 0 y: 0 + 200 × 200 at x: 0 y:100 "); } @@ -723,14 +736,10 @@ fn height_resize_before_another_y_anim_then_cancel() { ]; check_ops_on_layout(&mut layout, &ops); - // This should cause the second window's trajectory to readjust to the new final position at - // 100px. Ideally without big jumps because even though the first window's actual size changed - // from 200 px to 100 px, the cancelled resize only shifted it from 104 px to 100 px. - // - // FIXME: currently causes a 100 px jump due to the change in the actual window size. + // The second window's trajectory readjusts to the new final position at 100 px, without jumps. assert_snapshot!(format_tiles(&layout), @r" 100 × 100 at x: 0 y: 0 - 200 × 200 at x: 98 y:-96 + 200 × 200 at x: 98 y: 4 "); // Advance the time to complete the consume movement. @@ -791,13 +800,10 @@ fn clientside_height_change_during_another_y_anim() { ]; check_ops_on_layout(&mut layout, &ops); - // This should cause the second window's trajectory to readjust to the new final position at - // 200px. Ideally without big jumps. - // - // FIXME: currently causes a 100 px jump due to the change in the window size. + // The second window's trajectory readjusts to the new final position at 200 px, without jumps. assert_snapshot!(format_tiles(&layout), @r" 100 × 200 at x: 0 y: 0 - 200 × 200 at x: 80 y:120 + 200 × 200 at x: 80 y: 20 "); // Advance the time to complete the consume movement. diff --git a/src/layout/tile.rs b/src/layout/tile.rs index dea2a773..a4fe8a57 100644 --- a/src/layout/tile.rs +++ b/src/layout/tile.rs @@ -485,6 +485,17 @@ impl<W: LayoutElement> Tile<W> { }); } + pub fn offset_move_y_anim_current(&mut self, offset: f64) { + if let Some(move_) = self.move_y_animation.as_mut() { + // If the anim is almost done, there's little point trying to offset it; we can let + // things jump. If it turns out like a bad idea, we could restart the anim intead. + let value = move_.anim.value(); + if value > 0.001 { + move_.from += offset / value; + } + } + } + pub fn stop_move_animations(&mut self) { self.move_x_animation = None; self.move_y_animation = None; |
