Merge pull request #755 from vangel76/fix-227-transitions-follow-move
#227: transitions travel with the clips they sit on when moved
This commit is contained in:
commit
a6b323056f
|
|
@ -487,17 +487,45 @@ pub fn move_items(seq: &mut Sequence, moves: &[(ClipId, TrackId, Tick)], insert_
|
|||
it.start = (*start).max(Tick::ZERO);
|
||||
placed.push((*dest, it));
|
||||
}
|
||||
// carry transitions with moved clips? Premiere drops transitions whose partner is not moved.
|
||||
let carried = carried_transitions(&work, &placed);
|
||||
// a transition whose partner stays behind is dropped, as in Premiere
|
||||
delete_items(&mut work, &moves.iter().map(|m| m.0).collect::<Vec<_>>());
|
||||
if insert_mode {
|
||||
insert(&mut work, placed, ctx)?;
|
||||
} else {
|
||||
overwrite(&mut work, placed, ctx)?;
|
||||
}
|
||||
for (dest, tr) in carried {
|
||||
let t = track_mut(&mut work, dest)?;
|
||||
if [tr.from, tr.to].into_iter().flatten().all(|c| t.item(c).is_some()) {
|
||||
t.transitions.push(tr);
|
||||
t.sort();
|
||||
}
|
||||
}
|
||||
*seq = work;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// The transitions that travel with a move (#227, #374): those whose clips all move, onto one
|
||||
/// track and by one offset (a fade at a moved clip's edge, or the cut between two clips that move
|
||||
/// together), shifted to where those clips land.
|
||||
fn carried_transitions(seq: &Sequence, placed: &[(TrackId, TrackItem)]) -> Vec<(TrackId, Transition)> {
|
||||
let landing = |c: ClipId| {
|
||||
let (dest, it) = placed.iter().find(|(_, it)| it.id == c)?;
|
||||
let (_, old) = seq.find_item(c)?;
|
||||
Some((*dest, it.start - old.start))
|
||||
};
|
||||
let mut carried = Vec::new();
|
||||
for tr in seq.all_tracks().filter(|t| !t.locked).flat_map(|t| t.transitions.iter()) {
|
||||
let lands: Option<Vec<(TrackId, Tick)>> = [tr.from, tr.to].into_iter().flatten().map(landing).collect();
|
||||
let Some((&(dest, delta), rest)) = lands.as_deref().and_then(<[_]>::split_first) else { continue };
|
||||
if rest.iter().all(|l| *l == (dest, delta)) {
|
||||
carried.push((dest, Transition { start: tr.start + delta, ..tr.clone() }));
|
||||
}
|
||||
}
|
||||
carried
|
||||
}
|
||||
|
||||
fn media_len(ctx: &EditCtx, item: &TrackItem) -> Option<Tick> {
|
||||
if item.frame_hold.is_some() {
|
||||
return None;
|
||||
|
|
|
|||
|
|
@ -464,6 +464,39 @@ fn transitions_stay_on_their_cuts() {
|
|||
fx.seq.check().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transitions_travel_with_moved_clips() {
|
||||
// V1: a [0,10) fading in, b [10,20), c [20,30); b→c crossfade, c fading out
|
||||
let mut fx = Fx::new();
|
||||
let (v1, v2) = (fx.v(0), fx.v(1));
|
||||
let a = fx.put(v1, 0, 10, 10);
|
||||
let b = fx.put(v1, 10, 10, 10);
|
||||
let c = fx.put(v1, 20, 10, 10);
|
||||
let tr = |id, start, from, to| Transition {
|
||||
id: TransitionId(id),
|
||||
effect: filmcraft_project::find_effect("cross_dissolve").unwrap().instance(),
|
||||
start: f(start),
|
||||
duration: f(4),
|
||||
from,
|
||||
to,
|
||||
align: Default::default(),
|
||||
reverse: false,
|
||||
};
|
||||
fx.seq.track_mut(v1).unwrap().transitions = vec![tr(1, 0, None, Some(a)), tr(2, 18, Some(b), Some(c)), tr(3, 26, Some(c), None)];
|
||||
let at = |fx: &Fx, track: TrackId| -> Vec<(u64, i64)> { fx.seq.track(track).unwrap().transitions.iter().map(|t| (t.id.0, R.frame_at(t.start))).collect() };
|
||||
let mut n = fx.next;
|
||||
// a fade at a clip's edge goes with it, to another track too
|
||||
move_items(&mut fx.seq, &[(a, v2, f(40))], false, &mut Fx::ctx(&mut n)).unwrap();
|
||||
assert_eq!((at(&fx, v1), at(&fx, v2)), (vec![(2, 18), (3, 26)], vec![(1, 40)]));
|
||||
// a cut whose two clips move together keeps its transition, in an insert move as well
|
||||
move_items(&mut fx.seq, &[(b, v1, f(60)), (c, v1, f(70))], true, &mut Fx::ctx(&mut n)).unwrap();
|
||||
assert_eq!(at(&fx, v1), vec![(2, 68), (3, 76)]);
|
||||
// a crossfade whose partner stays behind is dropped; the other clip's fade stays with it
|
||||
move_items(&mut fx.seq, &[(c, v1, f(90))], false, &mut Fx::ctx(&mut n)).unwrap();
|
||||
assert_eq!(at(&fx, v1), vec![(3, 96)]);
|
||||
fx.seq.check().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rate_stretch_and_speed() {
|
||||
let mut fx = Fx::new();
|
||||
|
|
|
|||
Loading…
Reference in New Issue