Appearance: effect.apply reports the new effect's index in the object whose row it names

The reply's index came from the last object the effect was added to, while
its item came from the first selected object (or the first target for an
explicit item). When those objects held different numbers of effects on the
row, the reply named no effect of that object. The index is now read from
that object's effect list.
This commit is contained in:
dotCooCoo
2026-11-01 04:55:10 +07:00
committed by bflatastic
parent ef69c82fca
commit 18510b77af
2 changed files with 23 additions and 3 deletions
+2 -3
View File
@@ -213,16 +213,15 @@ pub(crate) fn apply(s: &mut Session, p: &Value) -> Result<Value> {
}
}
}
let mut index = 0;
let ids = edit_effects(s, p, item, C, &label, "Apply Effect: select objects", 0, |fx, _| {
fx.push(effect.clone());
index = fx.len() - 1;
true
})?;
// The item the effect landed on in the object whose row the item is (the first selected object
// for the active item, which applies where it fits).
// for the active item, which applies where it fits), and the effect's index in that object.
let first = ids.get(item.anchor(s, &ids)).and_then(|id| s.doc().ok()?.doc.node(*id));
let landed = first.and_then(|n| item.effects_item(&n.appearance, C).ok().flatten());
let index = first.and_then(|n| n.appearance.effects_at(landed)).map_or(0, |fx| fx.len().saturating_sub(1));
Ok(json!({ "ids": ids_json(&ids), "index": index, "item": landed }))
}
+21
View File
@@ -513,6 +513,27 @@ fn edits_change_the_active_row_of_the_first_selected_object() {
assert!(!e.contains("internal error"), "{e}");
}
/// `effect.apply`'s reply names the new effect by its index in the object whose row `item` is,
/// also when the objects painted after it already have effects there.
#[test]
fn apply_reports_the_index_in_the_object_whose_row_it_names() {
let mut s = session();
let (a, b) = reversed_pair(&mut s);
let c = rect(&mut s, 350.0);
run(&mut s, "effect.apply", json!({"effect": "distort.twist", "item": 0}));
// b's red fill row is not shared, so each object's row 0 takes the effect: c's second one.
run(&mut s, "select.set", json!({"ids": [b.0, a.0, c.0]}));
run(&mut s, "appearance.setActiveItem", json!({"index": 0}));
let r = run(&mut s, "effect.apply", json!({"effect": "distort.twist"}));
assert_eq!(node(&s, c).appearance.items[0].effects().len(), 2);
assert_eq!((r["item"].clone(), r["index"].clone()), (json!(0), json!(0)), "b's row 0 holds one effect");
// An explicit item is a row of the first target, a, which paints below c.
run(&mut s, "select.set", json!({"ids": [c.0, a.0]}));
let r = run(&mut s, "effect.apply", json!({"effect": "distort.twist", "item": 0}));
assert_eq!(node(&s, c).appearance.items[0].effects().len(), 3);
assert_eq!((r["item"].clone(), r["index"].clone()), (json!(0), json!(1)), "a's row 0 holds two effects");
}
/// How many steps there are to undo and to redo, and whether the document has unsaved changes.
fn history(s: &Session) -> (usize, usize, bool) {
let st = s.doc().unwrap();