Keep the playhead on the frame shown in the current-time field.

Timecode and Frames entries were parsed as absolute counts without the composition Start Timecode or Start Numbering Frames At offset, so committing the displayed text jumped to another frame.
This commit is contained in:
Vikram Bhaskaran committed 2026-10-11 03:32:01 +11:00
1 parent 813c7c4650
commit 9ae7788f8d
2 files changed
+36 -1

No files matched your search

+13 -1
View File
@@ -38,7 +38,19 @@ pub fn parse_display_time(s: &Session, comp: &Comp, text: &str, current: i64) ->
let start = fr.frame_at(comp.display_start) + st.frame_start;
effectcraft_time::parse_feet_frames(text, pf, current + start).map(|f| f - start).map_err(|e| e.0)
}
None => effectcraft_time::parse_timecode(text, fr, fr.supports_drop_frame(), current).map_err(|e| e.0),
None => {
let parsed = effectcraft_time::parse_timecode(text, fr, fr.supports_drop_frame(), current).map_err(|e| e.0)?;
let relative = text.trim().starts_with('+') || text.trim().starts_with('-');
if relative {
Ok(parsed)
} else if st.time_display == TimeDisplayStyle::Frames {
// Displayed digits are composition frame plus Start Numbering Frames At.
Ok(parsed - st.frame_start)
} else {
// Displayed timecode includes the composition Start Timecode offset.
Ok(parsed - fr.frame_at(comp.display_start))
}
}
}
}
+23
View File
@@ -375,6 +375,29 @@ fn time_set_snaps_to_the_nearest_frame_and_ae_timecode() {
assert_eq!(effectcraft_time::format_timecode_ae(75, fr, true), "0;00;02;15");
}
#[test]
fn time_set_keeps_the_frame_shown_in_the_current_time_field() {
let mut s = Session::default();
s.execute(
"comp.new",
json!({"name": "Example", "width": 64, "height": 64, "frameRate": 30, "duration": 0.6, "startTimecode": "0:00:00:05"}),
)
.unwrap();
let r = s.execute("time.set", json!({"frame": 0})).unwrap();
assert_eq!(r["display"], "0:00:00:05");
let r = s.execute("time.set", json!({"timecode": "0:00:00:05"})).unwrap();
assert_eq!((r["frame"].as_i64(), r["time"].as_f64()), (Some(0), Some(0.0)));
s.execute("file.projectSettings", json!({"timeDisplay": "frames"})).unwrap();
std::sync::Arc::make_mut(&mut s.project).settings.frame_start = 1;
let r = s.execute("time.set", json!({"frame": 12})).unwrap();
assert_eq!(r["display"], "00013");
let r = s.execute("time.set", json!({"timecode": "00013"})).unwrap();
assert_eq!((r["frame"].as_i64(), r["time"].as_f64()), (Some(12), Some(0.4)));
let r = s.execute("time.set", json!({"timecode": "+1"})).unwrap();
assert_eq!(r["frame"], 13);
}
#[test]
fn separate_dimensions_split_and_rejoin() {
let (mut s, l) = setup();