Merge pull request #2426 from jerome25000/fix/2201-mask-free-transform-undo

Fix #2201: one undo reverts a whole mask free-transform drag
This commit is contained in:
BFlat
2026-10-30 04:09:12 +07:00
committed by GitHub
2 changed files with 22 additions and 3 deletions
+3 -3
View File
@@ -8,7 +8,7 @@ use effectcraft_project::{FeatherFalloff, GroupKind, ItemId, LayerId, LayerSourc
use serde_json::{Value, json};
use super::layer_menu::target_masks;
use super::{CommandSpec, b_p, bad, f_p, has_comp, has_layers, layer_mut, layer_p, str_p};
use super::{CommandSpec, b_p, bad, f_p, has_comp, has_layers, layer_mut, layer_p, merge_p, str_p};
use crate::{EngineError, Result, Session, VertexRef, cmd};
// ---------------------------------------------------------------- RotoBezier
@@ -308,7 +308,7 @@ fn free_transform(s: &mut Session, p: &Value) -> Result<Value> {
let y = v[1] * scale[1];
[x * c - y * sn, x * sn + y * c]
};
let n = s.edit("Free Transform Points", None, |proj, _| {
let n = s.edit("Free Transform Points", merge_p(p), |proj, _| {
let mut n = 0;
for (lid, uid) in &targets {
let l = layer_mut(proj, cid, *lid)?;
@@ -542,7 +542,7 @@ pub fn specs() -> Vec<CommandSpec> {
"Free Transform Points",
["Layer", "Mask and Shape Path"],
None,
"{layer?, mask?, scale?: % | [x%, y%], rotation?: deg, offset?: [dx, dy], anchor?: [x, y]}",
"{layer?, mask?, scale?: % | [x%, y%], rotation?: deg, offset?: [dx, dy], anchor?: [x, y], merge?: string}",
has_layers,
free_transform
),
+19
View File
@@ -584,3 +584,22 @@ fn convert_to_bezier_reads_the_shape_as_it_is_set() {
let mid = |v: &[f64]| (v.iter().copied().fold(f64::MAX, f64::min) + v.iter().copied().fold(f64::MIN, f64::max)) / 2.0;
assert!((mid(&xs) - 10.0).abs() < 1e-6 && (mid(&ys) - 5.0).abs() < 1e-6, "centred on the position: {:?} {:?}", mid(&xs), mid(&ys));
}
/// #2201: a viewer drag on the free-transform box sends one `path.freeTransform` per frame with a
/// shared merge key; one undo must revert the whole drag, not the last frame.
#[test]
fn free_transform_drag_undoes_in_one_step() {
let mut s = comp();
let (l, m) = masked(&mut s);
s.state.selected_vertices.clear();
let before = mask_path(&s, l, m);
for k in [90, 90, 90, 90] {
s.execute("path.freeTransform", json!({"layer": l, "scale": k, "merge": "viewer-drag-1"})).unwrap();
}
let after = mask_path(&s, l, m);
assert_ne!(after, before);
s.execute("edit.undo", json!({})).unwrap();
assert_eq!(mask_path(&s, l, m), before, "one undo reverts the whole drag");
s.execute("edit.redo", json!({})).unwrap();
assert_eq!(mask_path(&s, l, m), after, "redo restores the whole drag");
}