mirror of
https://github.com/storytold/effectcraft.git
synced 2026-11-10 20:41:25 +00:00
Timeline: a Shift-drag on an unselected bar moves the whole selection (#1828)
A Shift-press on an unselected bar adds it to the selection, so the drag now moves that selection and its layers are no snap targets. Tests cover the selection drag and that a moved layer's own marker is no target. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3f3031d941
commit
3c6abe3606
3 files changed
+36
-9
No files matched your search
@@ -3526,11 +3526,15 @@ fn layer_bar_drag(g: &mut Rw, rc: &RowCtx<'_>, bars: &BarResps, quick: bool) {
|
||||
}
|
||||
let id = egui::Id::unique(("bar-drag", layer.id.0, kind));
|
||||
if resp.dragged() {
|
||||
// Moving or trimming a selected layer acts on the whole selection as it was when the
|
||||
// drag started (a Shift-drag adds the layer to it); each layer trims from its own
|
||||
// in/out point.
|
||||
let shift = ctx.input(|i| i.modifiers.shift);
|
||||
// Moving or trimming a selected layer acts on the whole selection as it is when the
|
||||
// drag starts; each layer trims from its own in/out point. A Shift-drag on an
|
||||
// unselected bar adds it to the selection (`layer_bar_hits`) and moves them all.
|
||||
let start = || {
|
||||
let edited = edited_layers(layer.id, &g.selected);
|
||||
let mut edited = edited_layers(layer.id, &g.selected);
|
||||
if kind == "move" && shift && !g.selected.contains(&layer.id) {
|
||||
edited.extend(g.selected.iter().map(|l| l.0));
|
||||
}
|
||||
let (i, o) = (layer.in_point.seconds(), layer.out_point.seconds());
|
||||
let ends = match kind {
|
||||
"move" => vec![i, o],
|
||||
@@ -3543,7 +3547,6 @@ fn layer_bar_drag(g: &mut Rw, rc: &RowCtx<'_>, bars: &BarResps, quick: bool) {
|
||||
};
|
||||
let mut drag = ctx.data(|d| d.get_temp::<BarDrag>(id)).filter(|_| !resp.drag_started()).unwrap_or_else(start);
|
||||
drag.px += f64::from(resp.drag_delta().x);
|
||||
let shift = ctx.input(|i| i.modifiers.shift);
|
||||
let frames = bar_drag_frames(drag.px, g.tl.pps, g.tl.fd, &drag.ends, &drag.targets, shift);
|
||||
if frames != drag.sent {
|
||||
let d = frames.saturating_sub(drag.sent) as f64 * g.tl.fd;
|
||||
|
||||
@@ -432,11 +432,22 @@ fn cti_snaps_to_the_nearest_candidate() {
|
||||
let comp = app.session.active_comp().unwrap().clone();
|
||||
let c = snap_candidates(&comp, &build_rows(&app, &comp));
|
||||
assert!(c.contains(&comp.duration.seconds()) && c.contains(&0.0));
|
||||
// A dragged layer's own ends are no targets; moved, neither are its markers and keys (#1828).
|
||||
}
|
||||
|
||||
/// A dragged layer's own In / Out points are no snap targets; moved, neither are its markers
|
||||
/// (#1828).
|
||||
#[test]
|
||||
fn bar_drags_dont_snap_to_their_own_layer() {
|
||||
let mut app = app();
|
||||
let bx = app.session.active_comp().unwrap().layers.iter().find(|l| l.name == "Box").unwrap().id.0;
|
||||
app.session.execute("layer.addMarker", json!({"layers": [bx], "time": 1.0})).unwrap();
|
||||
let comp = app.session.active_comp().unwrap().clone();
|
||||
let rows = build_rows(&app, &comp);
|
||||
let l = comp.layers.first().unwrap().id.0;
|
||||
assert_eq!(snap_targets(&comp, &rows, &[l], false).len(), c.len() - 2);
|
||||
assert!(snap_targets(&comp, &rows, &[l], true).len() <= c.len() - 2);
|
||||
let all = snap_targets(&comp, &rows, &[], false);
|
||||
let trimmed = snap_targets(&comp, &rows, &[bx], false);
|
||||
let moved = snap_targets(&comp, &rows, &[bx], true);
|
||||
assert_eq!(trimmed.len(), all.len() - 2, "trimming drops only the layer's In and Out");
|
||||
assert!(trimmed.contains(&1.0) && !moved.contains(&1.0), "moving drops the layer's marker: {moved:?}");
|
||||
}
|
||||
|
||||
/// Shift snaps a bar drag's nearest end to a target within 8 px of the pointer; farther away, or
|
||||
|
||||
@@ -148,6 +148,19 @@ fn dragging_bar_ends_trims_in_and_out() {
|
||||
assert!((i - 3.0).abs() < 1e-6 && (o - 8.0).abs() < 1.5 / 30.0 && s.abs() < 1e-6, "out extended to ~8 s, not slipped: in {i} out {o} start {s}");
|
||||
}
|
||||
|
||||
/// A Shift-drag on an unselected bar adds it to the selection and moves the whole selection
|
||||
/// together, so the other selected layers keep their offset (#1828).
|
||||
#[test]
|
||||
fn shift_dragging_an_unselected_bar_moves_the_selection() {
|
||||
let (mut h, solid, pre) = harness();
|
||||
h.state_mut().session.execute("layer.select", json!({"layers": [pre]})).unwrap();
|
||||
h.run_steps(2);
|
||||
let b = bar(&h, solid);
|
||||
drag_with(&mut h, b.center(), b.center() + vec2(b.width() / 4.0 * 2.5, 0.0), Modifiers::SHIFT);
|
||||
let ((si, ..), (pi, ..)) = (timing(&h, solid), timing(&h, pre));
|
||||
assert!(si > 4.0 && (pi - si - 1.0).abs() < 1e-6, "both moved by the same amount: solid in {si}, precomp in {pi}");
|
||||
}
|
||||
|
||||
/// With Frames and Frame Count Start at 1, In moves to 00061 but the Duration column still counts
|
||||
/// the layer's 120 frames (#1807).
|
||||
#[test]
|
||||
|
||||
Reference in new issue
Block a user