mirror of
https://github.com/storytold/filmcraft.git
synced 2026-10-24 10:10:05 -06:00
Merge pull request #207 from carlitosteso3/fix/ripple-trim-targets-164
Q/W ripple trim only the selected clips' tracks (#164)
This commit is contained in:
@@ -415,3 +415,23 @@ fn fps_validation_keeps_real_rates_and_refuses_degenerate_ones() {
|
||||
assert_eq!(s.sequence_rate(), before);
|
||||
assert_eq!(s.execute("project.inspect", json!({})).unwrap().to_string().len(), n, "no sequence was created");
|
||||
}
|
||||
|
||||
/// #164: with a clip selected, Q/W trim only its tracks (and its linked sound), not every
|
||||
/// targeted track under the playhead (the music on A2 used to be cut too).
|
||||
#[test]
|
||||
fn ripple_trim_to_playhead_follows_the_selection() {
|
||||
let mut s = demo_unlocked();
|
||||
let rate = s.sequence_rate();
|
||||
let a2 = |s: &Session| s.active_sequence().unwrap().audio_tracks[1].items.iter().map(|i| (i.start, i.duration)).collect::<Vec<_>>();
|
||||
let music = a2(&s);
|
||||
assert!(!music.is_empty(), "the demo has music on A2");
|
||||
let (id, start, _) = v1(&s)[1];
|
||||
s.execute("timeline.select", json!({"clips": [id]})).unwrap();
|
||||
let ph = start + rate.tick_of(10);
|
||||
s.execute("playhead.set", json!({"time": ph.0})).unwrap();
|
||||
s.execute("trim.rippleNext", json!({})).unwrap();
|
||||
assert_eq!(v1(&s).into_iter().find(|c| c.0 == id).unwrap().2, ph, "the selected clip ends at the playhead");
|
||||
assert_eq!(a2(&s), music, "the music on A2 is untouched");
|
||||
let linked = s.active_sequence().unwrap().audio_tracks[0].items.iter().find(|i| i.start == start).map(|i| i.end());
|
||||
assert_eq!(linked, Some(ph), "its linked sound on A1 is trimmed with it");
|
||||
}
|
||||
|
||||
@@ -239,14 +239,18 @@ pub fn to_playhead(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let ripple = p.get("ripple").and_then(Value::as_bool).unwrap_or(true);
|
||||
let ph = s.playhead();
|
||||
let seq = s.active_sequence().ok_or(EngineError::NoSequence)?;
|
||||
let targeted = s.targeting().targeted;
|
||||
let tracks: Vec<TrackId> = seq
|
||||
.video_tracks
|
||||
.iter()
|
||||
.chain(seq.audio_tracks.iter())
|
||||
.filter(|t| targeted.contains(&t.id) && !t.locked && t.items.iter().any(|i| i.start < ph && ph < i.end()))
|
||||
.map(|t| t.id)
|
||||
.collect();
|
||||
let under = |t: &filmcraft_project::Track, keep: &dyn Fn(ClipId) -> bool| t.items.iter().any(|i| i.start < ph && ph < i.end() && keep(i.id));
|
||||
// Like Add Edit: selected clips under the playhead (and their linked partners) are trimmed,
|
||||
// and only their tracks (#164); with none, the targeted tracks are.
|
||||
let sel = crate::commands::with_links(s, &s.state.selection);
|
||||
let selected: Vec<TrackId> =
|
||||
seq.video_tracks.iter().chain(seq.audio_tracks.iter()).filter(|t| !t.locked && under(t, &|c| sel.contains(&c))).map(|t| t.id).collect();
|
||||
let tracks = if selected.is_empty() {
|
||||
let targeted = s.targeting().targeted;
|
||||
seq.video_tracks.iter().chain(seq.audio_tracks.iter()).filter(|t| targeted.contains(&t.id) && !t.locked && under(t, &|_| true)).map(|t| t.id).collect()
|
||||
} else {
|
||||
selected
|
||||
};
|
||||
if tracks.is_empty() {
|
||||
return Err(EngineError::Other("no clip under the playhead on the targeted tracks".into()));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user