Merge pull request #1182 from marcoarnulfo/fix/speed-graph-handle-upward

This commit is contained in:
Brandon Thomas committed 2026-10-13 04:28:47 -04:00
commit bb0273dd91
2 files changed
+32 -1

No files matched your search

+4 -1
View File
@@ -376,7 +376,10 @@ pub(crate) fn show(app: &mut EffectcraftApp, ui: &mut egui::Ui, p: &egui::Painte
let (lid, uid, d) = (c.layer.id, c.prop.uid, c.dim);
for k in &c.keys {
let kp = pos2(tm.x(k.t), ymap(k.v));
if !plot.expand(6.0).contains(kp) {
// In the speed graph an end key rises with the handle being dragged; skipping it once it
// leaves the plot would drop the handle's widget and end the drag at the top edge.
let handle_dragged = || ["in", "out"].iter().any(|side| ctx.is_being_dragged(egui::Id::new(("ghandle", uid, d, k.idx, *side))));
if !plot.expand(6.0).contains(kp) && !handle_dragged() {
continue;
}
let kjson = json!({"layer": lid.0, "prop": uid, "time": k.time.seconds()});
+28
View File
@@ -435,3 +435,31 @@ fn ctrl_alt_scrub_in_the_timeline_is_proportional() {
assert!(moved[0].abs() < 1e-9, "the first selected layer stays: {moved:?}");
assert!((moved[1] - moved[2] / 2.0).abs() < 1e-6, "the middle one moves by half: {moved:?}");
}
/// #1171: in the speed graph an end key sits at its one side's speed, so it rises with the handle
/// being dragged; once it left the plot its handles were skipped and the drag stopped at the top
/// edge. A drag that ends above the graph keeps raising the speed as far as the pointer goes.
#[test]
fn speed_graph_handle_drags_upward_past_the_top() {
let (mut h, id, uid) = harness();
let s = &mut h.state_mut().session;
s.execute("prop.select", json!({"layer": id.0, "prop": uid})).unwrap();
s.execute("keys.selectAll", json!({})).unwrap();
s.execute("keys.easyEase", json!({})).unwrap();
h.state_mut().ui.timeline.graph_editor = true;
h.state_mut().ui.timeline.graph_mode = "speed".into();
h.run_steps(4);
let out_speed = |h: &Harness<'_, EffectcraftApp>| {
h.state().session.active_comp().unwrap().layer(id).unwrap().props.prop("transform/opacity").unwrap().keys[0].out_ease[0].speed
};
let e = h.state().auto.find(&format!("timeline.graph.handle.{uid}.0.0.out")).cloned().expect("the first key's out handle shows");
let at = pos2(e.rect[0] + e.rect[2] / 2.0, e.rect[1] + e.rect[3] / 2.0);
drag(&mut h, at, at + egui::vec2(0.0, -40.0), Default::default());
let short = out_speed(&h);
h.state_mut().session.execute("edit.undo", json!({})).unwrap();
h.run_steps(4);
assert_eq!(out_speed(&h), 0.0);
drag(&mut h, at, at + egui::vec2(0.0, -400.0), Default::default());
let long = out_speed(&h);
assert!(short > 1.0 && long > 9.0 * short, "40 px up gave {short}, 400 px up gave {long}");
}