Skip tiny swap redistribution phases
This commit is contained in:
parent
09305ab026
commit
158682757a
1 changed files with 85 additions and 10 deletions
|
|
@ -1,6 +1,9 @@
|
|||
use {crate::rect::Rect, crate::tree::NodeId};
|
||||
|
||||
const MIN_SHRINK_DENOMINATOR: i32 = 8;
|
||||
// Integer split remainders can make swapped siblings differ by one pixel. Do
|
||||
// not spend a full animation phase on that imperceptible bookkeeping step.
|
||||
const SWAP_AXIS_SNAP_PX: i32 = 1;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MultiphaseRequest {
|
||||
|
|
@ -876,7 +879,10 @@ fn plan_axis_crossing_lanes(
|
|||
main_start(window.to, axis),
|
||||
main_end(window.to, axis),
|
||||
);
|
||||
let lane_move = crossing_lane_move_rect(lane_from, window.to, axis);
|
||||
let mut lane_move = crossing_lane_move_rect(lane_from, window.to, axis);
|
||||
if same_axis_delta_within(lane_move, lane_to, axis, SWAP_AXIS_SNAP_PX) {
|
||||
lane_move = lane_to;
|
||||
}
|
||||
push_step(&mut phase1, window.node_id, window.from, lane_from);
|
||||
push_step(&mut phase2, window.node_id, lane_from, lane_move);
|
||||
push_step(&mut phase3, window.node_id, lane_move, lane_to);
|
||||
|
|
@ -897,12 +903,10 @@ fn plan_axis_crossing_lanes(
|
|||
lane_axis: axis.other(),
|
||||
},
|
||||
),
|
||||
phase_draft(
|
||||
PhaseKind::Move,
|
||||
axis,
|
||||
phase_draft_classified(
|
||||
phase2,
|
||||
PhaseReason::MoveThroughFreedSpace,
|
||||
),
|
||||
)?,
|
||||
phase_draft(
|
||||
PhaseKind::Scale,
|
||||
axis,
|
||||
|
|
@ -919,6 +923,17 @@ fn plan_axis_crossing_lanes(
|
|||
)
|
||||
}
|
||||
|
||||
fn phase_draft_classified(
|
||||
steps: Vec<MultiphaseStep>,
|
||||
reason: PhaseReason,
|
||||
) -> Result<MultiphasePhaseDraft, MultiphasePlanFailure> {
|
||||
let actions = steps
|
||||
.iter()
|
||||
.map(|step| classify_step(*step).ok_or(MultiphasePlanFailure::NoPattern))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
Ok(phase_draft_mixed(steps, actions, reason))
|
||||
}
|
||||
|
||||
fn crossing_lane_move_rect(from: Rect, target: Rect, axis: PhaseAxis) -> Rect {
|
||||
let size = main_size(from, axis);
|
||||
if main_start(target, axis) > main_start(from, axis) {
|
||||
|
|
@ -930,6 +945,12 @@ fn crossing_lane_move_rect(from: Rect, target: Rect, axis: PhaseAxis) -> Rect {
|
|||
}
|
||||
}
|
||||
|
||||
fn same_axis_delta_within(from: Rect, to: Rect, axis: PhaseAxis, max_delta: i32) -> bool {
|
||||
let start_delta = (main_start(from, axis) - main_start(to, axis)).abs();
|
||||
let end_delta = (main_end(from, axis) - main_end(to, axis)).abs();
|
||||
start_delta.max(end_delta) <= max_delta
|
||||
}
|
||||
|
||||
fn lane_sort_key(window: MultiphaseWindow, axis: PhaseAxis) -> (usize, i32, i32, u32) {
|
||||
let delta = main_start(window.to, axis) - main_start(window.from, axis);
|
||||
let direction = match delta.cmp(&0) {
|
||||
|
|
@ -2092,7 +2113,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn uneven_swap_lanes_split_move_and_same_axis_scale() {
|
||||
fn one_pixel_uneven_swap_lanes_fold_remainder_into_crossing_phase() {
|
||||
let req = request(vec![
|
||||
window(1, rect(0, 0, 101, 100), rect(101, 0, 201, 100)),
|
||||
window(2, rect(101, 0, 201, 100), rect(0, 0, 101, 100)),
|
||||
|
|
@ -2100,6 +2121,43 @@ mod tests {
|
|||
let planned = plan_no_overlap_explained(&req).unwrap();
|
||||
let plan = &planned.plan;
|
||||
|
||||
assert_eq!(
|
||||
planned.explanation.strategy,
|
||||
PlanStrategy::SwapLanes {
|
||||
axis: PhaseAxis::Horizontal,
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
actions(plan),
|
||||
vec![
|
||||
PhaseAction {
|
||||
kind: PhaseKind::Scale,
|
||||
axis: PhaseAxis::Vertical,
|
||||
},
|
||||
PhaseAction {
|
||||
kind: PhaseKind::Scale,
|
||||
axis: PhaseAxis::Horizontal,
|
||||
},
|
||||
PhaseAction {
|
||||
kind: PhaseKind::Scale,
|
||||
axis: PhaseAxis::Vertical,
|
||||
},
|
||||
]
|
||||
);
|
||||
assert_eq!(step_to(plan, 1, id(1)), rect(101, 0, 201, 50));
|
||||
assert_eq!(step_to(plan, 1, id(2)), rect(0, 50, 101, 100));
|
||||
assert!(validate_plan_continuous(&req, plan));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn large_uneven_swap_lanes_split_move_and_same_axis_scale() {
|
||||
let req = request(vec![
|
||||
window(1, rect(0, 0, 120, 100), rect(120, 0, 200, 100)),
|
||||
window(2, rect(120, 0, 200, 100), rect(0, 0, 120, 100)),
|
||||
]);
|
||||
let planned = plan_no_overlap_explained(&req).unwrap();
|
||||
let plan = &planned.plan;
|
||||
|
||||
assert_eq!(
|
||||
planned.explanation.strategy,
|
||||
PlanStrategy::SwapLanes {
|
||||
|
|
@ -2127,10 +2185,10 @@ mod tests {
|
|||
},
|
||||
]
|
||||
);
|
||||
assert_eq!(step_to(plan, 1, id(1)), rect(100, 0, 201, 50));
|
||||
assert_eq!(step_to(plan, 1, id(2)), rect(0, 50, 100, 100));
|
||||
assert_eq!(step_to(plan, 2, id(1)), rect(101, 0, 201, 50));
|
||||
assert_eq!(step_to(plan, 2, id(2)), rect(0, 50, 101, 100));
|
||||
assert_eq!(step_to(plan, 1, id(1)), rect(80, 0, 200, 50));
|
||||
assert_eq!(step_to(plan, 1, id(2)), rect(0, 50, 80, 100));
|
||||
assert_eq!(step_to(plan, 2, id(1)), rect(120, 0, 200, 50));
|
||||
assert_eq!(step_to(plan, 2, id(2)), rect(0, 50, 120, 100));
|
||||
assert!(validate_plan_continuous(&req, plan));
|
||||
}
|
||||
|
||||
|
|
@ -2149,6 +2207,23 @@ mod tests {
|
|||
axis: PhaseAxis::Horizontal,
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
actions(&planned.plan),
|
||||
vec![
|
||||
PhaseAction {
|
||||
kind: PhaseKind::Scale,
|
||||
axis: PhaseAxis::Vertical,
|
||||
},
|
||||
PhaseAction {
|
||||
kind: PhaseKind::Scale,
|
||||
axis: PhaseAxis::Horizontal,
|
||||
},
|
||||
PhaseAction {
|
||||
kind: PhaseKind::Scale,
|
||||
axis: PhaseAxis::Vertical,
|
||||
},
|
||||
]
|
||||
);
|
||||
assert!(validate_plan_continuous(&req, &planned.plan));
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue