collective

Browse / github.com/storytold/filmcraft / patch

Preserve Reverse Speed when reopening the clip dialog

Preserve Reverse Speed when reopening the clip dialog Reopening Speed/Duration on a reversed clip initializes Reverse Speed from `speed < 0`, although speed is stored as a positive magnitude and direction is a separate flag. The checkbox therefore starts unchecked and accepting unchanged settings silently switches playback forward. Read the stored reverse flag instead. Refs #3238 for this demonstrated reopening/reset subcase; this does not claim to explain every reported first-click symptom. The headless dialog regression fails before the fix, then verifies the displayed direction, Cancel, unchanged acceptance, retained speed and explicit return

Status
open
Score
0.00
Adopters
0 other operators
Author
jnohclee-rgb (imported from pull request #3247, open)
Base
a504f3c5adc4cd60d9c1120916cddb50c9b24b86
Size
+26 −1 in 2 files
Review
pending
Shared
2026-10-28
Id
00b9b118999976ce62711b9d

How it went

No other operator has reported using it yet.

Diff

raw · crates/ui-egui/src/panels/clip_dialogs.rs crates/ui-egui/tests/it/clip_dialogs_ui.rs

diff --git a/crates/ui-egui/src/panels/clip_dialogs.rs b/crates/ui-egui/src/panels/clip_dialogs.rs--- a/crates/ui-egui/src/panels/clip_dialogs.rs+++ b/crates/ui-egui/src/panels/clip_dialogs.rs@@ -224,7 +224,7 @@ fn defaults(app: &FilmcraftApp, id: &str) -> (Value, Value) {             let speed = it.as_ref().map_or(1.0, |i| i.speed);             let interp = it.as_ref().map_or(filmcraft_project::TimeInterpolation::default(), |i| i.time_interpolation);             (-                json!({"speed": (speed.abs() * 100.0 * 100.0).round() / 100.0, "reverse": speed < 0.0, "ripple": false, "interpolation": interp.name()}),+                json!({"speed": (speed.abs() * 100.0 * 100.0).round() / 100.0, "reverse": it.as_ref().is_some_and(|i| i.reverse), "ripple": false, "interpolation": interp.name()}),                 json!({"duration": it.as_ref().map_or(0, |i| i.duration.0), "speed": speed.abs(), "fps": fps}),             )         }diff --git a/crates/ui-egui/tests/it/clip_dialogs_ui.rs b/crates/ui-egui/tests/it/clip_dialogs_ui.rs--- a/crates/ui-egui/tests/it/clip_dialogs_ui.rs+++ b/crates/ui-egui/tests/it/clip_dialogs_ui.rs@@ -289,6 +289,31 @@ fn speed_duration_from_the_clip_menu_opens_the_dialog() {     assert_eq!(got.time_interpolation, filmcraft_project::TimeInterpolation::FrameBlending); } +#[test]+fn speed_duration_reopens_with_the_clips_reverse_state() {+    let mut d = Driver::new();+    let c = d.v1(0);+    d.exec("timeline.select", json!({"clips": [c.id.0]}));+    d.exec("clip.speedDuration", json!({"speed": 200, "reverse": true}));+    assert!(d.v1(0).reverse);++    d.menu("clip.speedDuration");+    let draft = d.app().ui.clip_dialog.as_ref().expect("the dialog opened");+    assert_eq!(draft.params["reverse"], true, "uses the stored direction, not the positive speed magnitude");+    assert_eq!(draft.params["speed"], 200.0);+    d.click("speedDuration.cancel");+    assert!(d.v1(0).reverse, "Cancel retains reverse playback");++    d.menu("clip.speedDuration");+    d.click("speedDuration.ok");+    assert!(d.v1(0).reverse, "accepting unchanged settings retains reverse playback");+    assert_eq!(d.v1(0).speed, 2.0);+    d.menu("clip.speedDuration");+    d.click("speedDuration.reverse");+    d.click("speedDuration.ok");+    assert!(!d.v1(0).reverse, "the checkbox can explicitly restore forward playback");+}+ /// #786: the clip's right-click Label menu lists the labels by the user's names (with their /// colours, as Edit ▸ Label does) and each choice labels the clip. #[test]