mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-30 13:08:07 -06:00
Expressions: a layer is a callable property group
In After Effects a layer is a property group: thisLayer("transform"),
thisComp.layer("Other")("effects")("Blur"), thisLayer(1). In
EffectCraft's expression runtime a Layer was a plain object, so those
failed with "TypeError: not a callable function", including the
references the pick whip writes with Compact English off
(thisComp.layer("Other")("effects")("ec.noise.fractal")(...)).
A Layer is now callable like a property group (built as __mkGroup
builds groups), looking up its own properties by match name, name or
index, and keeps its methods, name and index. The places that took a
layer for a plain object (the result reading as the layer's index,
thisComp.layer(layer, offset), a Layer Control's value handed through
the property proxy) accept it.
Test: layers_are_callable_property_groups (fails before).
This commit is contained in:
@@ -44,7 +44,7 @@ function __finish(r) {
|
||||
|
||||
function __result(r) {
|
||||
r = __v(r);
|
||||
if (r !== null && typeof r === 'object' && r.__isLayer) return r.index;
|
||||
if (r !== null && r !== undefined && r.__isLayer) return r.index;
|
||||
if (r !== null && typeof r === 'object' && r.__isTextStyle) return r.__out();
|
||||
// `[temp, temp]` where temp is a property (pick-whip 1D → 2D): read the values here, while
|
||||
// host requests can still be answered and the script re-run.
|
||||
@@ -464,7 +464,7 @@ Comp.prototype = {
|
||||
return __err('Composition "' + this.name + '" has no active camera');
|
||||
},
|
||||
layer: function (a, rel) {
|
||||
if (a !== null && typeof a === 'object' && a.__isLayer) return this.layer(a.index + (rel || 0));
|
||||
if (a !== null && a !== undefined && a.__isLayer) return this.layer(a.index + (rel || 0));
|
||||
var id = __h(__LAYER, this.__c, a);
|
||||
if (id === null) __err(typeof a === 'string' ? 'Layer named "' + a + '" does not exist' : 'Layer index ' + a + ' out of range');
|
||||
return new Layer(this.__c, id);
|
||||
@@ -542,7 +542,17 @@ var thisProject = {
|
||||
|
||||
// Layer -----------------------------------------------------------------------------------------
|
||||
|
||||
function Layer(c, l) { this.__c = c; this.__l = l; this.__i = null; }
|
||||
// A layer is a property group too, as in After Effects: `thisLayer("transform")`, another layer's
|
||||
// `("effects")("Slider Control")`, `thisLayer(1)` (what the pick whip writes with Compact English
|
||||
// off). Callable like a group (`__mkGroup`), with the Layer methods.
|
||||
function Layer(c, l) {
|
||||
var f = function (k) { return f.__group(k); };
|
||||
delete f.name;
|
||||
delete f.length;
|
||||
Object.setPrototypeOf(f, Layer.prototype);
|
||||
f.__c = c; f.__l = l; f.__i = null;
|
||||
return f;
|
||||
}
|
||||
|
||||
function __m3(m, p) {
|
||||
var x = p[0] || 0, y = p[1] || 0;
|
||||
@@ -846,8 +856,9 @@ var __propHandler = {
|
||||
var v = t.value;
|
||||
if (v === null || v === undefined) return undefined;
|
||||
var x = v[k];
|
||||
// Property groups are callable proxies: hand them over as they are, not bound like methods (#809).
|
||||
if (x?.__isGroup) return x;
|
||||
// Property groups and layers are callable: hand them over as they are, not bound like methods
|
||||
// (#809).
|
||||
if (x?.__isGroup || x?.__isLayer) return x;
|
||||
return typeof x === 'function' ? x.bind(v) : x;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1370,4 +1370,21 @@ fn time_to_frames_preserves_coercion_and_small_durations() {
|
||||
}
|
||||
}
|
||||
|
||||
/// A layer is a property group too, as in After Effects: `thisLayer("transform")`, another
|
||||
/// layer's `("effects")("Slider Control")` or `(1)`, as the pick whip writes them with Compact
|
||||
/// English off (they failed: "not a callable function"). It is still a layer.
|
||||
#[test]
|
||||
fn layers_are_callable_property_groups() {
|
||||
let f = fx();
|
||||
assert_close!(f.num("thisLayer(\"transform\")(\"opacity\")", 0.0), 100.0);
|
||||
assert_close!(f.num("thisComp.layer(\"A\")(\"effects\")(\"ec.control.slider\")(\"slider\")", 0.0), 42.0);
|
||||
assert_close!(f.num("thisComp.layer(\"A\")(\"effects\")(\"Slider Control\")(1)", 0.0), 42.0);
|
||||
assert_close!(f.num("thisComp.layer(1)(\"effects\")(1)(1)", 0.0), 42.0);
|
||||
// Its own name, index and methods, and a layer as the result still reads as its index.
|
||||
assert_close!(f.num("thisLayer.name == \"A\" ? thisComp.layer(\"B\").index : 0", 0.0), 2.0);
|
||||
assert_close!(f.num("thisComp.layer(\"B\")", 0.0), 2.0);
|
||||
assert_close!(f.num("thisComp.layer(thisComp.layer(\"B\"), -1).index", 0.0), 1.0);
|
||||
assert!(f.err("thisLayer(\"nope\")").contains("no property"), "{}", f.err("thisLayer(\"nope\")"));
|
||||
}
|
||||
|
||||
mod property_group;
|
||||
|
||||
Reference in New Issue
Block a user