1
0
Fork 0
forked from wry/wry

Fallback layout animations by motion group

This commit is contained in:
atagen 2026-05-21 18:46:10 +10:00
parent a516b2e721
commit 4ee2c324e1
3 changed files with 115 additions and 27 deletions

View file

@ -81,6 +81,33 @@ pub fn plan_no_overlap(request: &MultiphaseRequest) -> Result<MultiphasePlan, Mu
Err(MultiphaseError::NoPlan)
}
pub(crate) fn partition_motion_groups(windows: &[MultiphaseWindow]) -> Vec<Vec<usize>> {
let mut groups = vec![];
let mut seen = vec![false; windows.len()];
for start in 0..windows.len() {
if seen[start] {
continue;
}
seen[start] = true;
let mut group = vec![];
let mut pending = vec![start];
while let Some(idx) = pending.pop() {
group.push(idx);
let bounds = motion_bounds(windows[idx]);
for other in 0..windows.len() {
if seen[other] || !bounds.intersects(&motion_bounds(windows[other])) {
continue;
}
seen[other] = true;
pending.push(other);
}
}
group.sort_unstable();
groups.push(group);
}
groups
}
fn validate_request(request: &MultiphaseRequest) -> Result<(), MultiphaseError> {
if request.bounds.is_empty() {
return Err(MultiphaseError::EmptyBounds);
@ -380,6 +407,10 @@ fn overlaps(rects: impl IntoIterator<Item = Rect>) -> bool {
false
}
fn motion_bounds(window: MultiphaseWindow) -> Rect {
window.from.union(window.to)
}
fn push_step(steps: &mut Vec<MultiphaseStep>, node_id: NodeId, from: Rect, to: Rect) {
if from != to {
steps.push(MultiphaseStep { node_id, from, to });
@ -697,4 +728,48 @@ mod tests {
}]);
assert_eq!(plan_no_overlap(&req), Err(MultiphaseError::NoPlan));
}
#[test]
fn motion_groups_split_disjoint_layout_changes() {
let windows = vec![
MultiphaseWindow {
node_id: id(1),
from: rect(0, 0, 100, 100),
to: rect(100, 0, 200, 100),
},
MultiphaseWindow {
node_id: id(2),
from: rect(100, 0, 200, 100),
to: rect(0, 0, 100, 100),
},
MultiphaseWindow {
node_id: id(3),
from: rect(300, 0, 400, 100),
to: rect(400, 0, 500, 100),
},
];
assert_eq!(partition_motion_groups(&windows), vec![vec![0, 1], vec![2]]);
}
#[test]
fn motion_groups_are_transitive() {
let windows = vec![
MultiphaseWindow {
node_id: id(1),
from: rect(0, 0, 100, 100),
to: rect(80, 0, 180, 100),
},
MultiphaseWindow {
node_id: id(2),
from: rect(170, 0, 270, 100),
to: rect(250, 0, 350, 100),
},
MultiphaseWindow {
node_id: id(3),
from: rect(90, 0, 180, 100),
to: rect(180, 0, 260, 100),
},
];
assert_eq!(partition_motion_groups(&windows), vec![vec![0, 1, 2]]);
}
}