Animate command-driven floating changes
This commit is contained in:
parent
aeaea3419f
commit
d0cc5dc3c7
4 changed files with 60 additions and 18 deletions
|
|
@ -82,8 +82,8 @@ Implementation shape:
|
|||
Initial scope:
|
||||
|
||||
- Tiled reflow animation.
|
||||
- Floating command-driven moves are deferred until after tiled reflow, spawn-in,
|
||||
and float/tile transitions are validated.
|
||||
- Floating command-driven moves and resizes are animated. Pointer and tablet
|
||||
drag/resize paths still snap directly to the live cursor position.
|
||||
- Cross-output and cross-scale movements snap for now.
|
||||
- Linear mode may overlap windows during swaps. That is expected for the classic
|
||||
interpolation mode; no-overlap is Phase 3.
|
||||
|
|
@ -101,6 +101,8 @@ Tests:
|
|||
- drag-driven floating movement bypasses animation
|
||||
- damage includes old, current, and final rects
|
||||
- command-driven tile-to-float and float-to-tile transitions use linear motion
|
||||
- command-driven floating moves and resizes animate without affecting pointer
|
||||
drag/resize behavior
|
||||
- pointer/header double-click unfloat bypasses the command-animation gate
|
||||
|
||||
## Phase 2: Retained Texture Freezing
|
||||
|
|
|
|||
|
|
@ -668,7 +668,9 @@ impl ConfigProxyHandler {
|
|||
fn handle_window_move(&self, window: Window, direction: Direction) -> Result<(), CphError> {
|
||||
self.state.with_layout_animations(|| {
|
||||
let window = self.get_window(window)?;
|
||||
if let Some(c) = toplevel_parent_container(&*window) {
|
||||
if let Some(float) = window.tl_data().float.get() {
|
||||
float.move_by_direction(direction.into());
|
||||
} else if let Some(c) = toplevel_parent_container(&*window) {
|
||||
c.move_child(window, direction.into());
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -936,6 +936,9 @@ impl WlSeatGlobal {
|
|||
{
|
||||
c.move_child(tl, direction);
|
||||
self.maybe_schedule_warp_mouse_to_focus();
|
||||
} else if let Some(float) = data.float.get() {
|
||||
float.move_by_direction(direction);
|
||||
self.maybe_schedule_warp_mouse_to_focus();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@ use {
|
|||
};
|
||||
|
||||
tree_id!(FloatNodeId);
|
||||
|
||||
const COMMAND_MOVE_DELTA: i32 = 100;
|
||||
|
||||
pub struct FloatNode {
|
||||
pub id: FloatNodeId,
|
||||
pub state: Rc<State>,
|
||||
|
|
@ -371,6 +374,51 @@ impl FloatNode {
|
|||
y2 += y1 - pos.y1();
|
||||
}
|
||||
let new_pos = Rect::new_saturating(x1, y1, x2, y2);
|
||||
self.set_position(new_pos);
|
||||
}
|
||||
|
||||
pub fn move_by_direction(self: &Rc<Self>, direction: Direction) {
|
||||
let (dx, dy) = match direction {
|
||||
Direction::Left => (-COMMAND_MOVE_DELTA, 0),
|
||||
Direction::Down => (0, COMMAND_MOVE_DELTA),
|
||||
Direction::Up => (0, -COMMAND_MOVE_DELTA),
|
||||
Direction::Right => (COMMAND_MOVE_DELTA, 0),
|
||||
Direction::Unspecified => return,
|
||||
};
|
||||
self.set_position(self.position.get().move_(dx, dy));
|
||||
}
|
||||
|
||||
fn body_for_outer(&self, outer: Rect) -> Rect {
|
||||
let bw = self.state.theme.sizes.border_width.get();
|
||||
Rect::new_sized_saturating(
|
||||
outer.x1() + bw,
|
||||
outer.y1() + bw,
|
||||
outer.width() - 2 * bw,
|
||||
outer.height() - 2 * bw,
|
||||
)
|
||||
}
|
||||
|
||||
fn queue_position_animation(&self, old_pos: Rect, new_pos: Rect) {
|
||||
self.state
|
||||
.clone()
|
||||
.queue_tiled_animation(self.id.into(), old_pos, new_pos, None);
|
||||
let Some(child) = self.child.get() else {
|
||||
return;
|
||||
};
|
||||
self.state.clone().queue_tiled_animation(
|
||||
child.node_id(),
|
||||
self.body_for_outer(old_pos),
|
||||
self.body_for_outer(new_pos),
|
||||
child.tl_animation_snapshot(),
|
||||
);
|
||||
}
|
||||
|
||||
fn set_position(self: &Rc<Self>, new_pos: Rect) {
|
||||
let pos = self.position.get();
|
||||
if new_pos == pos {
|
||||
return;
|
||||
}
|
||||
self.queue_position_animation(pos, new_pos);
|
||||
self.position.set(new_pos);
|
||||
if self.visible.get() {
|
||||
self.state.damage(pos);
|
||||
|
|
@ -799,13 +847,7 @@ impl ContainingNode for FloatNode {
|
|||
let bw = theme.sizes.border_width.get();
|
||||
let (x, y) = (x - bw, y - bw);
|
||||
let pos = self.position.get();
|
||||
if pos.position() != (x, y) {
|
||||
let new_pos = pos.at_point(x, y);
|
||||
self.position.set(new_pos);
|
||||
self.state.damage(pos);
|
||||
self.state.damage(new_pos);
|
||||
self.schedule_layout();
|
||||
}
|
||||
self.set_position(pos.at_point(x, y));
|
||||
}
|
||||
|
||||
fn cnode_resize_child(
|
||||
|
|
@ -836,14 +878,7 @@ impl ContainingNode for FloatNode {
|
|||
y2 = (v + bw).max(y1 + bw + bw);
|
||||
}
|
||||
let new_pos = Rect::new_saturating(x1, y1, x2, y2);
|
||||
if new_pos != pos {
|
||||
self.position.set(new_pos);
|
||||
if self.visible.get() {
|
||||
self.state.damage(pos);
|
||||
self.state.damage(new_pos);
|
||||
}
|
||||
self.schedule_layout();
|
||||
}
|
||||
self.set_position(new_pos);
|
||||
}
|
||||
|
||||
fn cnode_pinned(&self) -> bool {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue