mirror of
https://github.com/storytold/effectcraft.git
synced 2026-11-15 06:42:31 +00:00
Number fields: Mask Feather stays non-negative on the other selected layers (#3195)
A typed *-1 (the edited layer clamped at 0 by the panel) or a change by the same amount could take another selected layer's Mask Feather below 0. Clamp it at 0 there, as the panels do for the edited layer.
This commit is contained in:
1 parent
0cb5bfefb5
commit
b2d6690fd2
2 files changed
+47
No files matched your search
@@ -436,6 +436,9 @@ fn set_selected(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let mut q = twin_params(p, olid, ouid);
|
||||
shifted(s, &mut q, olid, ouid, k);
|
||||
typed(s, &mut q, olid, ouid);
|
||||
if is_mask_feather(s, cid, olid, ouid) {
|
||||
non_negative(&mut q["value"]);
|
||||
}
|
||||
// (a layer that can't take it, e.g. a clamped or static property, keeps its value)
|
||||
let _ = set(s, &q);
|
||||
}
|
||||
@@ -444,6 +447,26 @@ fn set_selected(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
if merge_p(p).is_some() { run(s) } else { super::app_more::grouped(s, "Change Property", run) }
|
||||
}
|
||||
|
||||
/// Whether property `uid` of `lid` is a mask's Mask Feather, which is never negative (After
|
||||
/// Effects; the panels clamp a typed or scrubbed value at 0).
|
||||
fn is_mask_feather(s: &Session, cid: ItemId, lid: LayerId, uid: Uid) -> bool {
|
||||
let Some(l) = s.project.comp(cid).and_then(|c| c.layer(lid)) else { return false };
|
||||
l.props.find(uid).is_some_and(|q| q.match_id == "feather") && l.props.parent_of(uid).is_some_and(|g| matches!(g.kind, GroupKind::Mask { .. }))
|
||||
}
|
||||
|
||||
/// A JSON number, or each number of an array, raised to at least 0.
|
||||
fn non_negative(v: &mut Value) {
|
||||
match v {
|
||||
Value::Number(n) => {
|
||||
if let Some(x) = n.as_f64().filter(|x| *x < 0.0) {
|
||||
*v = json!(x.max(0.0));
|
||||
}
|
||||
}
|
||||
Value::Array(a) => a.iter_mut().for_each(non_negative),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// `prop.toggleAnimation`; with `selected`, the other selected layers' same property follows.
|
||||
fn toggle_anim_selected(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let twins = selected_twins(s, p, "prop.toggleAnimation")?;
|
||||
|
||||
@@ -1554,6 +1554,30 @@ fn a_typed_factor_scales_each_selected_layers_own_value() {
|
||||
assert_eq!(prop(&s, b, "transform/position").value.components()[..2], [50.0, 50.0], "B halves its own X, keeps its Y");
|
||||
}
|
||||
|
||||
/// #3195: Mask Feather is never negative on the other selected layers either, when a typed `*-1`
|
||||
/// (the edited layer clamped at 0 by the panel) or a change by the same amount takes theirs
|
||||
/// below 0.
|
||||
#[test]
|
||||
fn a_selected_mask_feather_stays_non_negative() {
|
||||
let (mut s, a) = setup();
|
||||
let b = s.execute("layer.newSolid", json!({"color": "#ff0000", "width": 50, "height": 50})).unwrap()["layer"].as_u64().unwrap();
|
||||
for (l, feather) in [(a, [10.0, 20.0]), (b, [4.0, 30.0])] {
|
||||
s.execute("mask.new", json!({"layer": l, "vertices": [[0, 0], [20, 0], [20, 20]]})).unwrap();
|
||||
s.execute("prop.set", json!({"layer": l, "path": "masks/#1/feather", "value": feather})).unwrap();
|
||||
}
|
||||
s.execute("layer.select", json!({"layers": [a, b]})).unwrap();
|
||||
let feather = |s: &Session, l: u64| prop(s, l, "masks/#1/feather").value.components();
|
||||
let uid = prop(&s, a, "masks/#1/feather").uid;
|
||||
// `*-1` into the linked pair: the panel clamps the edited layer at [0, 0].
|
||||
s.execute_checked("prop.set", json!({"layer": a, "prop": uid, "value": [0.0, 0.0], "selected": true, "dims": [0, 1], "factor": -1.0})).unwrap();
|
||||
assert_eq!(feather(&s, a), [0.0, 0.0]);
|
||||
assert_eq!(feather(&s, b), [0.0, 0.0], "B is clamped at 0, not [-4, -30]");
|
||||
// A change by the same amount (a scrub, or a typed `+`): A by [-10, -15] from [10, 20].
|
||||
s.execute("edit.undo", json!({})).unwrap();
|
||||
s.execute_checked("prop.set", json!({"layer": a, "prop": uid, "value": [0.0, 5.0], "selected": true, "offset": true})).unwrap();
|
||||
assert_eq!(feather(&s, b), [0.0, 15.0], "B's X is clamped at 0, its Y moves by -15");
|
||||
}
|
||||
|
||||
/// #2485: linked Audio Levels typed with several layers selected: each takes the typed Left, and
|
||||
/// its Right moves by its own change, so every layer keeps its own stereo balance.
|
||||
#[test]
|
||||
|
||||
Reference in new issue
Block a user