#890: the Timeline time field reads its displayed timecode back as the same frame at 29.97/59.94 fps
Problem: the Timeline shows non-drop timecode, but time.set (the current-time field) parsed typed text as drop-frame at 29.97/59.94 fps, so committing the displayed time, or typing a time, landed on another frame from minute 1 on (frame 1800 "0:01:00:00" -> 1798). Fix: typed text is read as drop-frame only when it uses ';' fields; ':' and '.' follow the displayed non-drop style. Regression test round-trips the display at both rates. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
67434e9038
commit
51501bbd21
|
|
@ -39,7 +39,10 @@ pub fn parse_display_time(s: &Session, comp: &Comp, text: &str, current: i64) ->
|
|||
effectcraft_time::parse_feet_frames(text, pf, current + start).map(|f| f - start).map_err(|e| e.0)
|
||||
}
|
||||
None => {
|
||||
let parsed = effectcraft_time::parse_timecode(text, fr, fr.supports_drop_frame(), current).map_err(|e| e.0)?;
|
||||
// The Timeline shows non-drop timecode (`:`), so typed `:`/`.` text is read as non-drop
|
||||
// too; only explicit `;` fields mean drop-frame (#890).
|
||||
let drop_frame = fr.supports_drop_frame() && text.contains(';');
|
||||
let parsed = effectcraft_time::parse_timecode(text, fr, drop_frame, current).map_err(|e| e.0)?;
|
||||
let relative = text.trim().starts_with('+') || text.trim().starts_with('-');
|
||||
if relative {
|
||||
Ok(parsed)
|
||||
|
|
|
|||
|
|
@ -414,6 +414,25 @@ 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");
|
||||
}
|
||||
|
||||
/// #890: at 29.97 / 59.94 fps the displayed (non-drop) timecode was read back as drop-frame, so
|
||||
/// committing the current-time field moved the playhead to another frame from minute 1 on.
|
||||
#[test]
|
||||
fn time_set_round_trips_the_displayed_timecode_at_drop_frame_rates() {
|
||||
for fps in [29.97, 59.94] {
|
||||
let mut s = Session::default();
|
||||
s.execute("comp.new", json!({"name": "T", "width": 64, "height": 64, "frameRate": fps, "duration": 4000})).unwrap();
|
||||
for frame in [0_i64, 1799, 1800, 1801, 3600, 17982, 17983, 100_000] {
|
||||
let r = s.execute("time.set", json!({"frame": frame})).unwrap();
|
||||
let display = r["display"].as_str().unwrap().to_string();
|
||||
let r = s.execute("time.set", json!({"timecode": display})).unwrap();
|
||||
assert_eq!(r["frame"], frame, "{fps} fps: displayed {display}");
|
||||
}
|
||||
// Explicit drop-frame fields still mean drop-frame.
|
||||
let r = s.execute("time.set", json!({"timecode": "0;01;00;02"})).unwrap();
|
||||
assert_eq!(r["frame"], if fps > 30.0 { 3598 } else { 1800 });
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn time_set_keeps_the_frame_shown_in_the_current_time_field() {
|
||||
let mut s = Session::default();
|
||||
|
|
|
|||
Loading…
Reference in New Issue