mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-31 15:48:33 +00:00
#1685: preserve composition selection and resolve all expression targets
This commit is contained in:
1 parent
86b357162c
commit
088bedff45
2 files changed
+68
-3
No files matched your search
@@ -82,8 +82,13 @@ pub(super) fn sync_polystar_property(
|
||||
let layer = layer_mut(proj, cid, lid)?;
|
||||
let removed = sync_polystar_type(layer, uid, layer.layer_time(time), &mut next)?;
|
||||
if !removed.is_empty() {
|
||||
state.selected_props.retain(|(layer, prop)| *layer != lid || !removed.contains(prop));
|
||||
state.selected_keys.retain(|key| key.layer != lid || !removed.contains(&key.prop));
|
||||
if state.active_comp == Some(cid) {
|
||||
state.selected_props.retain(|(layer, prop)| *layer != lid || !removed.contains(prop));
|
||||
state.selected_keys.retain(|key| key.layer != lid || !removed.contains(&key.prop));
|
||||
} else if let Some(selection) = state.comp_selections.get_mut(&cid) {
|
||||
selection.props.retain(|(layer, prop)| *layer != lid || !removed.contains(prop));
|
||||
selection.keys.retain(|key| key.layer != lid || !removed.contains(&key.prop));
|
||||
}
|
||||
}
|
||||
proj.next_id = next;
|
||||
Ok(())
|
||||
@@ -678,14 +683,19 @@ fn set_expr(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let times: Vec<_> = targets.iter().map(|(cid, _, _)| s.time_of(*cid)).collect();
|
||||
let results = s.edit("Expression", merge_p(p), |proj, state| {
|
||||
let mut out = vec![];
|
||||
let mut changed_types = vec![];
|
||||
for (((cid, lid, uid), def), time) in targets.iter().zip(&defs).zip(×) {
|
||||
let pr = layer_mut(proj, *cid, *lid)?.props.find_mut(*uid).ok_or_else(|| bad(C, "property vanished"))?;
|
||||
apply_expr(pr, &text, enabled, def);
|
||||
out.push(json!(pr.expr.as_ref().map(|e| e.text.clone())));
|
||||
if pr.match_id == "type" {
|
||||
sync_polystar_property(proj, state, *cid, *lid, *uid, *time)?;
|
||||
changed_types.push((*cid, *lid, *uid, *time));
|
||||
}
|
||||
}
|
||||
// All selected targets must be edited before a Type change can remove inner controls.
|
||||
for (cid, lid, uid, time) in changed_types {
|
||||
sync_polystar_property(proj, state, cid, lid, uid, time)?;
|
||||
}
|
||||
Ok(out)
|
||||
})?;
|
||||
let r = if explicit { results.into_iter().next().unwrap_or(Value::Null) } else { Value::Array(results) };
|
||||
|
||||
@@ -766,3 +766,58 @@ fn deleting_the_last_polystar_type_key_removes_stale_controls_and_selection() {
|
||||
assert_eq!(group(&s), polygon);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn polystar_sync_cleans_the_edited_compositions_parked_selection() {
|
||||
let mut s = comp();
|
||||
let first = s.active_comp_id().unwrap();
|
||||
let lid = s.execute("layer.newShape", json!({"kind": "polygon"})).unwrap()["layer"].as_u64().unwrap();
|
||||
let path = "contents/group/contents/star";
|
||||
let type_uid = layer(&s, lid).props.group(path).unwrap().get("type").unwrap().uid;
|
||||
s.execute("prop.addKey", json!({"layer": lid, "prop": type_uid, "time": 0, "value": 1})).unwrap();
|
||||
let before = layer(&s, lid).props.group(path).unwrap().clone();
|
||||
let inner = before.get("innerRadius").unwrap().uid;
|
||||
s.state.selected_props = vec![(LayerId(lid), inner)];
|
||||
s.state.selected_keys = vec![crate::KeyRef { layer: LayerId(lid), prop: inner, time: Tick::ZERO }];
|
||||
s.execute("comp.new", json!({"width": 100, "height": 100, "duration": 2})).unwrap();
|
||||
let second = s.active_comp_id().unwrap();
|
||||
let other = s.execute("layer.newSolid", json!({})).unwrap()["layer"].as_u64().unwrap();
|
||||
let other_prop = layer(&s, other).props.prop("transform/rotation").unwrap().uid;
|
||||
s.execute("prop.addKey", json!({"layer": other, "prop": other_prop, "time": 0, "value": 15})).unwrap();
|
||||
s.state.selected_props = vec![(LayerId(other), other_prop)];
|
||||
s.state.selected_keys = vec![crate::KeyRef { layer: LayerId(other), prop: other_prop, time: Tick::ZERO }];
|
||||
let live = (s.state.selected_props.clone(), s.state.selected_keys.clone());
|
||||
s.execute("prop.toggleAnimation", json!({"comp": first.0, "layer": lid, "prop": type_uid, "value": false})).unwrap();
|
||||
assert_eq!(s.active_comp_id(), Some(second));
|
||||
assert_eq!((s.state.selected_props.clone(), s.state.selected_keys.clone()), live);
|
||||
let parked = s.state.comp_selections.get(&first).unwrap();
|
||||
assert!(parked.props.is_empty() && parked.keys.is_empty(), "the inactive composition must not keep removed control references");
|
||||
let after = s.project.comp(first).unwrap().layer(LayerId(lid)).unwrap().props.group(path).unwrap().clone();
|
||||
assert!(after.get("innerRadius").is_none());
|
||||
assert!(s.undo());
|
||||
assert_eq!(s.project.comp(first).unwrap().layer(LayerId(lid)).unwrap().props.group(path).unwrap(), &before);
|
||||
assert!(s.redo());
|
||||
assert_eq!(s.project.comp(first).unwrap().layer(LayerId(lid)).unwrap().props.group(path).unwrap(), &after);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn polystar_multi_property_expression_clear_resolves_targets_before_removing_controls() {
|
||||
let mut s = comp();
|
||||
let lid = s.execute("layer.newShape", json!({"kind": "polygon"})).unwrap()["layer"].as_u64().unwrap();
|
||||
let group = |s: &Session| layer(s, lid).props.group("contents/group/contents/star").unwrap().clone();
|
||||
let type_uid = group(&s).get("type").unwrap().uid;
|
||||
s.execute("prop.setExpression", json!({"layer": lid, "prop": type_uid, "expression": "1"})).unwrap();
|
||||
let inner = group(&s).get("innerRadius").unwrap().uid;
|
||||
s.execute("prop.setExpression", json!({"layer": lid, "prop": inner, "expression": "37"})).unwrap();
|
||||
let before = group(&s);
|
||||
s.state.selected_props = vec![(LayerId(lid), type_uid), (LayerId(lid), inner)];
|
||||
assert_eq!(s.execute("prop.setExpression", json!({"expression": ""})).unwrap(), json!([null, null]));
|
||||
let after = group(&s);
|
||||
assert!(after.get("type").unwrap().expr.is_none());
|
||||
assert!(after.get("innerRadius").is_none());
|
||||
assert_eq!(s.state.selected_props, vec![(LayerId(lid), type_uid)]);
|
||||
assert!(s.undo());
|
||||
assert_eq!(group(&s), before);
|
||||
assert!(s.redo());
|
||||
assert_eq!(group(&s), after);
|
||||
}
|
||||
Reference in new issue
Block a user