Merge #2177: engine: deleting a layer clears the references to it (#2153) (@Anubhav-Rai)

This commit is contained in:
aiongg
2026-10-24 01:11:56 +00:00
2 changed files with 33 additions and 0 deletions
+16
View File
@@ -1,6 +1,7 @@
//! Edit menu.
use effectcraft_color::Label;
use effectcraft_keyframe::Value as KV;
use effectcraft_project::{Comp, Expression, ItemKind, Layer, LayerId, LayerSource, TrackMatte};
use effectcraft_time::Tick;
use serde_json::{Value, json};
@@ -201,6 +202,21 @@ fn delete(s: &mut Session, p: &Value) -> Result<Value> {
if l.track_matte.is_some_and(|m| ids.contains(&m.layer)) {
l.track_matte = None;
}
// A layer-reference property (an Environment light's Source, an effect's Clone Source,
// Back Layer…) must read as None once its layer is gone, in this same history step: a
// dead id renders as nothing while the UI shows "None", which means "fall back to the
// comp's Environment Layer" (#2153). Keys carry the same value kind as the property.
l.props.walk_mut(&mut |p| {
let dead = |v: &KV| matches!(v, KV::Layer(Some(id)) if ids.contains(&LayerId(*id)));
if dead(&p.value) {
p.value = KV::Layer(None);
}
for k in &mut p.keys {
if dead(&k.value) {
k.value = KV::Layer(None);
}
}
});
}
st.selected_layers.clear();
st.selected_props.clear();
+17
View File
@@ -131,6 +131,23 @@ fn environment_light_is_listed_and_takes_a_source_layer() {
assert_eq!(prop(&s, env, "lightOptions/source").as_layer(), None);
}
/// Deleting the layer a Source points at leaves no dangling id: "None" means the comp's
/// Environment Layer, and a dead id rendered as nothing at all (#2153).
#[test]
fn deleting_a_source_layer_clears_the_reference() {
let mut s = session();
let sky = s.execute("layer.newSolid", json!({"width": 256, "height": 128, "name": "Sky"})).unwrap()["layer"].as_u64().unwrap();
let env = s.execute("layer.newLight", json!({"kind": "Environment", "name": "Env"})).unwrap()["layer"].as_u64().unwrap();
s.execute("prop.set", json!({"layer": env, "path": "lightOptions/source", "value": sky})).unwrap();
assert_eq!(prop(&s, env, "lightOptions/source").as_layer(), Some(sky));
s.execute("edit.clear", json!({"layers": [sky]})).unwrap();
assert_eq!(prop(&s, env, "lightOptions/source").as_layer(), None, "the reference goes with the layer");
// One history step with the delete, so undo brings both back.
s.undo();
assert_eq!(prop(&s, env, "lightOptions/source").as_layer(), Some(sky));
assert!(s.active_comp().unwrap().layer(effectcraft_project::LayerId(sky)).is_some());
}
#[test]
fn three_d_switch_undo_redo() {
let mut s = session();