mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-28 12:07:48 -06:00
M13.11: essential graphics mirrored and linked properties
Adding a property already in the Essential Graphics panel adds a mirror (EgKind::Mirror: own name and place, one value in the comp and in every instance; editing, reverting or pushing either acts on both). A property control can also drive further properties of the comp (links follow the main property both ways and take instance values). essential.addMirror, essential.linkProperty, essential.unlinkProperty; panel badges and menu; ExtendScript addToMotionGraphicsTemplate(As), canAddToMotionGraphicsTemplate, motionGraphicsTemplateName, controller count/name and exportAsMotionGraphicsTemplate. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
bb24b931a6
commit
d774d11231
@@ -805,8 +805,22 @@ Property.prototype.property = function () { return null; };
|
||||
};
|
||||
P.keyLabel = function () { return 0; };
|
||||
P.setLabelAtKey = function () {};
|
||||
P.addToMotionGraphicsTemplate = function () { return false; };
|
||||
P.canAddToMotionGraphicsTemplate = function () { return false; };
|
||||
// Essential Graphics: `comp` must be the comp holding the property. A property already in
|
||||
// the panel is added again as a mirror (both controls edit one value).
|
||||
P.canAddToMotionGraphicsTemplate = function (comp) {
|
||||
var c = comp && comp.__id !== undefined ? comp.__id : this.__layer.__comp;
|
||||
if (c !== this.__layer.__comp) return false;
|
||||
var sup = __call("essential.list", { comp: c, supported: true }).supported || [], uid = this.__uid;
|
||||
for (var i = 0; i < sup.length; i++) if (sup[i].uid === uid) return true;
|
||||
return false;
|
||||
};
|
||||
P.addToMotionGraphicsTemplateAs = function (comp, name) {
|
||||
if (!this.canAddToMotionGraphicsTemplate(comp)) return false;
|
||||
var p = this.__ref();
|
||||
if (name !== undefined) p.name = String(name);
|
||||
return __call("essential.addProperty", p).controls.length > 0;
|
||||
};
|
||||
P.addToMotionGraphicsTemplate = function (comp) { return this.addToMotionGraphicsTemplateAs(comp); };
|
||||
})();
|
||||
|
||||
// Layer / composition markers (`layer.marker`, `comp.markerProperty`): keyframes are markers.
|
||||
@@ -1352,7 +1366,39 @@ CompItem.prototype.constructor = CompItem;
|
||||
};
|
||||
P.openInViewer = function () { __call("comp.open", { comp: this.__id }); return null; };
|
||||
P.duplicate = function () { return __item(__call("project.duplicate", { items: [this.__id] }).items[0]); };
|
||||
P.exportAsMotionGraphicsTemplate = function () { return false; };
|
||||
// Essential Graphics template: name, controllers (property, mirror and media controls in
|
||||
// panel order, 1-based) and export.
|
||||
P.__egControllers = function () {
|
||||
var out = [];
|
||||
(function go(v) {
|
||||
for (var i = 0; i < v.length; i++) {
|
||||
if (v[i].kind === "group") go(v[i].children || []);
|
||||
else if (v[i].kind !== "comment") out.push(v[i]);
|
||||
}
|
||||
})(__call("essential.list", { comp: this.__id }).controls || []);
|
||||
return out;
|
||||
};
|
||||
def("motionGraphicsTemplateName", function () { return __call("essential.list", { comp: this.__id }).name; }, function (v) {
|
||||
__call("essential.setName", { comp: this.__id, name: String(v) });
|
||||
});
|
||||
def("motionGraphicsTemplateControllerCount", function () { return this.__egControllers().length; });
|
||||
P.getMotionGraphicsTemplateControllerName = function (i) {
|
||||
var c = this.__egControllers()[__num(i, "index") - 1];
|
||||
if (!c) throw __err("controller index out of range");
|
||||
return c.name;
|
||||
};
|
||||
P.setMotionGraphicsControllerName = function (i, name) {
|
||||
var c = this.__egControllers()[__num(i, "index") - 1];
|
||||
if (!c) throw __err("controller index out of range");
|
||||
__call("essential.rename", { comp: this.__id, control: c.id, name: String(name) });
|
||||
return String(name);
|
||||
};
|
||||
P.exportAsMotionGraphicsTemplate = function (overwrite, path) {
|
||||
if (path === undefined) return false;
|
||||
var p = path && path.fsName !== undefined ? path.fsName : String(path);
|
||||
if (!overwrite && new File(p).exists) return false;
|
||||
try { __call("essential.exportTemplate", { comp: this.__id, path: p }); return true; } catch (e) { return false; }
|
||||
};
|
||||
})();
|
||||
|
||||
function FootageItem(id) {
|
||||
|
||||
@@ -446,3 +446,41 @@ fn layer_switches_timing_and_comp_settings() {
|
||||
let o = ok(&mut s, "var n = app.project.numItems; app.project.item(1).remove(); n - app.project.numItems");
|
||||
assert_eq!(o.result, json!(1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn motion_graphics_template_hooks_add_mirrors_and_controllers() {
|
||||
let mut s = session();
|
||||
let dir = std::env::temp_dir().join(format!("effectcraft-eg-script-{}", std::process::id()));
|
||||
let _ = std::fs::create_dir_all(&dir);
|
||||
let path = dir.join("card.ectemplate");
|
||||
let o = ok(
|
||||
&mut s,
|
||||
&format!(
|
||||
r#"
|
||||
var comp = app.project.items.addComp("Card", 64, 64, 1, 2, 30);
|
||||
var bg = comp.layers.addSolid([1, 1, 1], "BG", 64, 64, 1);
|
||||
var op = bg.transform.opacity;
|
||||
var r = [op.canAddToMotionGraphicsTemplate(comp), op.addToMotionGraphicsTemplateAs(comp, "Fade")];
|
||||
// Again: a mirror of the same property.
|
||||
r.push(op.addToMotionGraphicsTemplate(comp));
|
||||
r.push(comp.motionGraphicsTemplateControllerCount);
|
||||
r.push(comp.getMotionGraphicsTemplateControllerName(1), comp.getMotionGraphicsTemplateControllerName(2));
|
||||
comp.setMotionGraphicsControllerName(2, "Fade Again");
|
||||
comp.motionGraphicsTemplateName = "Lower Card";
|
||||
r.push(comp.getMotionGraphicsTemplateControllerName(2), comp.motionGraphicsTemplateName);
|
||||
// A property of another comp can't be added.
|
||||
var other = app.project.items.addComp("Other", 64, 64, 1, 2, 30);
|
||||
r.push(op.canAddToMotionGraphicsTemplate(other));
|
||||
r.push(comp.exportAsMotionGraphicsTemplate(true, new File("{}")));
|
||||
r
|
||||
"#,
|
||||
path.to_string_lossy()
|
||||
),
|
||||
);
|
||||
assert_eq!(o.result, json!([true, true, true, 2, "Fade", "Fade", "Fade Again", "Lower Card", false, true]));
|
||||
let (_, c) = comp_named(&s, "Card");
|
||||
let eg = c.essential.as_ref().unwrap();
|
||||
assert!(matches!(eg.controls[1].kind, effectcraft_engine::project::essential::EgKind::Mirror { of } if of == eg.controls[0].id));
|
||||
assert!(path.exists());
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user