Merge pull request #1378 from vangel76/fix-1368-nudge-track

#1368: nudge clip selection up/down works for linked video+audio
This commit is contained in:
Brandon Thomas committed 2026-10-13 00:03:29 -04:00
commit 20487653ce
2 files changed
+17 -2

No files matched your search

+9 -2
View File
@@ -225,6 +225,7 @@ fn nudge_time(s: &mut Session, frames: i64) -> Result<Value> {
fn nudge_track(s: &mut Session, up: bool) -> Result<Value> {
let seq = s.active_sequence().ok_or(EngineError::NoSequence)?;
let mut moves = Vec::new();
let mut blocked = 0usize;
for c in &s.state.selection {
let Some((tid, it)) = seq.find_item(*c) else { continue };
let Some(tr) = seq.track(tid) else { continue };
@@ -234,11 +235,17 @@ fn nudge_track(s: &mut Session, up: bool) -> Result<Value> {
(TrackKind::Video, true) | (TrackKind::Audio, false) => 1,
_ => -1,
};
let dest = usize::try_from(idx + step).ok().and_then(|i| list.get(i)).ok_or_else(|| EngineError::Other("no track to move to".into()))?;
// a clip already on the outermost track stays put (a linked video+audio selection must not
// fail because its audio has nowhere to go)
let Some(dest) = usize::try_from(idx + step).ok().and_then(|i| list.get(i)) else {
blocked += 1;
continue;
};
moves.push((*c, dest.id, it.start));
}
if moves.is_empty() {
return Err(EngineError::Other("no clips selected".into()));
let why = if blocked > 0 { "no track to move to" } else { "no clips selected" };
return Err(EngineError::Other(why.into()));
}
s.edit_sequence("Nudge", |q, ctx, _| Ok(edit::move_items(q, &moves, false, ctx)?))?;
Ok(json!({"moved": moves.len()}))
+8
View File
@@ -190,6 +190,14 @@ fn nudge_slip_and_slide_the_selection_with_undo() {
s.execute("timeline.nudgeDown", json!({})).unwrap();
assert_eq!(track_of(&s, last.0), v1_id);
assert!(s.execute("timeline.nudgeDown", json!({})).is_err(), "there is no track below V1");
// a linked video+audio selection: the video goes up, the audio (already on the outermost
// track in that direction) stays, instead of the whole nudge failing (#1368)
s.execute("timeline.select", json!({"clips": [last.0]})).unwrap();
assert!(s.state.selection.len() > 1, "the linked audio is selected too");
s.execute("timeline.nudgeUp", json!({})).unwrap();
assert_eq!(track_of(&s, last.0), s.active_sequence().unwrap().video_tracks[1].id);
s.execute("timeline.nudgeDown", json!({})).unwrap();
assert_eq!(track_of(&s, last.0), v1_id);
// slip: the source In moves, the clip stays
let mid = v1[1];
s.execute("timeline.select", json!({"clips": [mid.0]})).unwrap();