Make interactively moved window semitransparent

This commit is contained in:
Ivan Molodetskikh
2025-03-01 09:45:57 +03:00
parent 4f5c8e745b
commit 88614c08fe
3 changed files with 87 additions and 3 deletions
+64 -1
View File
@@ -93,6 +93,9 @@ pub const RESIZE_ANIMATION_THRESHOLD: f64 = 10.;
/// Pointer needs to move this far to pull a window from the layout. /// Pointer needs to move this far to pull a window from the layout.
const INTERACTIVE_MOVE_START_THRESHOLD: f64 = 256. * 256.; const INTERACTIVE_MOVE_START_THRESHOLD: f64 = 256. * 256.;
/// Opacity of interactively moved tiles targeting the scrolling layout.
const INTERACTIVE_MOVE_ALPHA: f64 = 0.75;
/// Size-relative units. /// Size-relative units.
pub struct SizeFrac; pub struct SizeFrac;
@@ -2334,6 +2337,34 @@ impl<W: LayoutElement> Layout<W> {
// Tile position must be rounded to physical pixels. // Tile position must be rounded to physical pixels.
assert_abs_diff_eq!(tile_pos.x, rounded_pos.x, epsilon = 1e-5); assert_abs_diff_eq!(tile_pos.x, rounded_pos.x, epsilon = 1e-5);
assert_abs_diff_eq!(tile_pos.y, rounded_pos.y, epsilon = 1e-5); assert_abs_diff_eq!(tile_pos.y, rounded_pos.y, epsilon = 1e-5);
if let Some(alpha) = &move_.tile.alpha_animation {
if move_.is_floating {
assert_eq!(
alpha.anim.to(),
1.,
"interactively moved floating tile can animate alpha only to 1"
);
assert!(
!alpha.hold_after_done,
"interactively moved floating tile \
cannot have held alpha animation"
);
} else {
assert_ne!(
alpha.anim.to(),
1.,
"interactively moved scrolling tile must animate alpha to not 1"
);
assert!(
alpha.hold_after_done,
"interactively moved scrolling tile \
must have held alpha animation"
);
}
}
} }
} }
} }
@@ -3005,6 +3036,21 @@ impl<W: LayoutElement> Layout<W> {
size.h = ensure_min_max_size_maybe_zero(size.h, min_size.h, max_size.h); size.h = ensure_min_max_size_maybe_zero(size.h, min_size.h, max_size.h);
win.request_size_once(size, true); win.request_size_once(size, true);
// Animate the tile back to opaque.
move_.tile.animate_alpha(
INTERACTIVE_MOVE_ALPHA,
1.,
self.options.animations.window_movement.0,
);
} else {
// Animate the tile back to semitransparent.
move_.tile.animate_alpha(
1.,
INTERACTIVE_MOVE_ALPHA,
self.options.animations.window_movement.0,
);
move_.tile.hold_alpha_animation_after_done();
} }
return; return;
@@ -3773,6 +3819,16 @@ impl<W: LayoutElement> Layout<W> {
is_floating = unfullscreen_to_floating; is_floating = unfullscreen_to_floating;
} }
// Animate to semitransparent.
if !is_floating {
tile.animate_alpha(
1.,
INTERACTIVE_MOVE_ALPHA,
self.options.animations.window_movement.0,
);
tile.hold_alpha_animation_after_done();
}
let mut data = InteractiveMoveData { let mut data = InteractiveMoveData {
tile, tile,
output, output,
@@ -3869,7 +3925,7 @@ impl<W: LayoutElement> Layout<W> {
return; return;
} }
let Some(InteractiveMoveState::Moving(move_)) = self.interactive_move.take() else { let Some(InteractiveMoveState::Moving(mut move_)) = self.interactive_move.take() else {
unreachable!() unreachable!()
}; };
@@ -3878,6 +3934,13 @@ impl<W: LayoutElement> Layout<W> {
for ws in self.workspaces_mut() { for ws in self.workspaces_mut() {
ws.dnd_scroll_gesture_end(); ws.dnd_scroll_gesture_end();
} }
// Also animate the tile back to opaque.
move_.tile.animate_alpha(
INTERACTIVE_MOVE_ALPHA,
1.,
self.options.animations.window_movement.0,
);
} }
match &mut self.monitor_set { match &mut self.monitor_set {
+18 -2
View File
@@ -148,6 +148,12 @@ struct MoveAnimation {
#[derive(Debug)] #[derive(Debug)]
pub(super) struct AlphaAnimation { pub(super) struct AlphaAnimation {
pub(super) anim: Animation, pub(super) anim: Animation,
/// Whether the animation should persist after it's done.
///
/// This is used by things like interactive move which need to animate alpha to
/// semitransparent, then hold it at semitransparent for a while, until the operation
/// completes.
pub(super) hold_after_done: bool,
offscreen: OffscreenBuffer, offscreen: OffscreenBuffer,
} }
@@ -319,7 +325,7 @@ impl<W: LayoutElement> Tile<W> {
} }
if let Some(alpha) = &mut self.alpha_animation { if let Some(alpha) = &mut self.alpha_animation {
if alpha.anim.is_done() { if !alpha.hold_after_done && alpha.anim.is_done() {
self.alpha_animation = None; self.alpha_animation = None;
} }
} }
@@ -334,7 +340,10 @@ impl<W: LayoutElement> Tile<W> {
|| self.resize_animation.is_some() || self.resize_animation.is_some()
|| self.move_x_animation.is_some() || self.move_x_animation.is_some()
|| self.move_y_animation.is_some() || self.move_y_animation.is_some()
|| self.alpha_animation.is_some() || self
.alpha_animation
.as_ref()
.is_some_and(|alpha| !alpha.anim.is_done())
} }
pub fn update_render_elements(&mut self, is_active: bool, view_rect: Rectangle<f64, Logical>) { pub fn update_render_elements(&mut self, is_active: bool, view_rect: Rectangle<f64, Logical>) {
@@ -491,6 +500,7 @@ impl<W: LayoutElement> Tile<W> {
self.alpha_animation = Some(AlphaAnimation { self.alpha_animation = Some(AlphaAnimation {
anim: Animation::new(self.clock.clone(), current, to, 0., config), anim: Animation::new(self.clock.clone(), current, to, 0., config),
hold_after_done: false,
offscreen, offscreen,
}); });
} }
@@ -505,6 +515,12 @@ impl<W: LayoutElement> Tile<W> {
} }
} }
pub fn hold_alpha_animation_after_done(&mut self) {
if let Some(alpha) = &mut self.alpha_animation {
alpha.hold_after_done = true;
}
}
pub fn window(&self) -> &W { pub fn window(&self) -> &W {
&self.window &self.window
} }
+5
View File
@@ -1757,6 +1757,11 @@ impl<W: LayoutElement> Workspace<W> {
if visible { if visible {
assert_eq!(anim.to(), 1., "visible tiles can animate alpha only to 1"); assert_eq!(anim.to(), 1., "visible tiles can animate alpha only to 1");
} }
assert!(
!alpha.hold_after_done,
"tiles in the layout cannot have held alpha animation"
);
} }
} }
} }