| |
|
| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| | export class EzConnection {
|
| |
|
| | app;
|
| |
|
| | link;
|
| |
|
| | get originNode() {
|
| | return new EzNode(this.app, this.app.graph.getNodeById(this.link.origin_id));
|
| | }
|
| |
|
| | get originOutput() {
|
| | return this.originNode.outputs[this.link.origin_slot];
|
| | }
|
| |
|
| | get targetNode() {
|
| | return new EzNode(this.app, this.app.graph.getNodeById(this.link.target_id));
|
| | }
|
| |
|
| | get targetInput() {
|
| | return this.targetNode.inputs[this.link.target_slot];
|
| | }
|
| |
|
| | |
| | |
| | |
| |
|
| | constructor(app, link) {
|
| | this.app = app;
|
| | this.link = link;
|
| | }
|
| |
|
| | disconnect() {
|
| | this.targetInput.disconnect();
|
| | }
|
| | }
|
| |
|
| | export class EzSlot {
|
| |
|
| | node;
|
| |
|
| | index;
|
| |
|
| | |
| | |
| | |
| |
|
| | constructor(node, index) {
|
| | this.node = node;
|
| | this.index = index;
|
| | }
|
| | }
|
| |
|
| | export class EzInput extends EzSlot {
|
| |
|
| | input;
|
| |
|
| | |
| | |
| | |
| | |
| |
|
| | constructor(node, index, input) {
|
| | super(node, index);
|
| | this.input = input;
|
| | }
|
| |
|
| | get connection() {
|
| | const link = this.node.node.inputs?.[this.index]?.link;
|
| | if (link == null) {
|
| | return null;
|
| | }
|
| | return new EzConnection(this.node.app, this.node.app.graph.links[link]);
|
| | }
|
| |
|
| | disconnect() {
|
| | this.node.node.disconnectInput(this.index);
|
| | }
|
| | }
|
| |
|
| | export class EzOutput extends EzSlot {
|
| |
|
| | output;
|
| |
|
| | |
| | |
| | |
| | |
| |
|
| | constructor(node, index, output) {
|
| | super(node, index);
|
| | this.output = output;
|
| | }
|
| |
|
| | get connections() {
|
| | return (this.node.node.outputs?.[this.index]?.links ?? []).map(
|
| | (l) => new EzConnection(this.node.app, this.node.app.graph.links[l])
|
| | );
|
| | }
|
| |
|
| | |
| | |
| |
|
| | connectTo(input) {
|
| | if (!input) throw new Error("Invalid input");
|
| |
|
| | |
| | |
| |
|
| | const link = this.node.node.connect(this.index, input.node.node, input.index);
|
| | if (!link) {
|
| | const inp = input.input;
|
| | const inName = inp.name || inp.label || inp.type;
|
| | throw new Error(
|
| | `Connecting from ${input.node.node.type}#${input.node.id}[${inName}#${input.index}] -> ${this.node.node.type}#${this.node.id}[${
|
| | this.output.name ?? this.output.type
|
| | }#${this.index}] failed.`
|
| | );
|
| | }
|
| | return link;
|
| | }
|
| | }
|
| |
|
| | export class EzNodeMenuItem {
|
| |
|
| | node;
|
| |
|
| | index;
|
| |
|
| | item;
|
| |
|
| | |
| | |
| | |
| | |
| |
|
| | constructor(node, index, item) {
|
| | this.node = node;
|
| | this.index = index;
|
| | this.item = item;
|
| | }
|
| |
|
| | call(selectNode = true) {
|
| | if (!this.item?.callback) throw new Error(`Menu Item ${this.item?.content ?? "[null]"} has no callback.`);
|
| | if (selectNode) {
|
| | this.node.select();
|
| | }
|
| | return this.item.callback.call(this.node.node, undefined, undefined, undefined, undefined, this.node.node);
|
| | }
|
| | }
|
| |
|
| | export class EzWidget {
|
| |
|
| | node;
|
| |
|
| | index;
|
| |
|
| | widget;
|
| |
|
| | |
| | |
| | |
| | |
| |
|
| | constructor(node, index, widget) {
|
| | this.node = node;
|
| | this.index = index;
|
| | this.widget = widget;
|
| | }
|
| |
|
| | get value() {
|
| | return this.widget.value;
|
| | }
|
| |
|
| | set value(v) {
|
| | this.widget.value = v;
|
| | this.widget.callback?.call?.(this.widget, v)
|
| | }
|
| |
|
| | get isConvertedToInput() {
|
| |
|
| | return this.widget.type === "converted-widget";
|
| | }
|
| |
|
| | getConvertedInput() {
|
| | if (!this.isConvertedToInput) throw new Error(`Widget ${this.widget.name} is not converted to input.`);
|
| |
|
| | return this.node.inputs.find((inp) => inp.input["widget"]?.name === this.widget.name);
|
| | }
|
| |
|
| | convertToWidget() {
|
| | if (!this.isConvertedToInput)
|
| | throw new Error(`Widget ${this.widget.name} cannot be converted as it is already a widget.`);
|
| | var menu = this.node.menu["Convert Input to Widget"].item.submenu.options;
|
| | var index = menu.findIndex(a => a.content == `Convert ${this.widget.name} to widget`);
|
| | menu[index].callback.call();
|
| | }
|
| |
|
| | convertToInput() {
|
| | if (this.isConvertedToInput)
|
| | throw new Error(`Widget ${this.widget.name} cannot be converted as it is already an input.`);
|
| | var menu = this.node.menu["Convert Widget to Input"].item.submenu.options;
|
| | var index = menu.findIndex(a => a.content == `Convert ${this.widget.name} to input`);
|
| | menu[index].callback.call();
|
| | }
|
| | }
|
| |
|
| | export class EzNode {
|
| |
|
| | app;
|
| |
|
| | node;
|
| |
|
| | |
| | |
| | |
| |
|
| | constructor(app, node) {
|
| | this.app = app;
|
| | this.node = node;
|
| | }
|
| |
|
| | get id() {
|
| | return this.node.id;
|
| | }
|
| |
|
| | get inputs() {
|
| | return this.#makeLookupArray("inputs", "name", EzInput);
|
| | }
|
| |
|
| | get outputs() {
|
| | return this.#makeLookupArray("outputs", "name", EzOutput);
|
| | }
|
| |
|
| | get widgets() {
|
| | return this.#makeLookupArray("widgets", "name", EzWidget);
|
| | }
|
| |
|
| | get menu() {
|
| | return this.#makeLookupArray(() => this.app.canvas.getNodeMenuOptions(this.node), "content", EzNodeMenuItem);
|
| | }
|
| |
|
| | get isRemoved() {
|
| | return !this.app.graph.getNodeById(this.id);
|
| | }
|
| |
|
| | select(addToSelection = false) {
|
| | this.app.canvas.selectNode(this.node, addToSelection);
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #makeLookupArray(nodeProperty, nameProperty, ctor) {
|
| | const items = typeof nodeProperty === "function" ? nodeProperty() : this.node[nodeProperty];
|
| |
|
| | return (items ?? []).reduce((p, s, i) => {
|
| | if (!s) return p;
|
| |
|
| | const name = s[nameProperty];
|
| | const item = new ctor(this, i, s);
|
| |
|
| | p.push(item);
|
| | if (name) {
|
| |
|
| | if (name in p) {
|
| | throw new Error(`Unable to store ${nodeProperty} ${name} on array as name conflicts.`);
|
| | }
|
| | }
|
| |
|
| | p[name] = item;
|
| | return p;
|
| | }, Object.assign([], { $: this }));
|
| | }
|
| | }
|
| |
|
| | export class EzGraph {
|
| |
|
| | app;
|
| |
|
| | |
| | |
| |
|
| | constructor(app) {
|
| | this.app = app;
|
| | }
|
| |
|
| | get nodes() {
|
| | return this.app.graph._nodes.map((n) => new EzNode(this.app, n));
|
| | }
|
| |
|
| | clear() {
|
| | this.app.graph.clear();
|
| | }
|
| |
|
| | arrange() {
|
| | this.app.graph.arrange();
|
| | }
|
| |
|
| | stringify() {
|
| | return JSON.stringify(this.app.graph.serialize(), undefined);
|
| | }
|
| |
|
| | |
| | |
| | |
| |
|
| | find(obj) {
|
| | let match;
|
| | let id;
|
| | if (typeof obj === "number") {
|
| | id = obj;
|
| | } else {
|
| | id = obj.id;
|
| | }
|
| |
|
| | match = this.app.graph.getNodeById(id);
|
| |
|
| | if (!match) {
|
| | throw new Error(`Unable to find node with ID ${id}.`);
|
| | }
|
| |
|
| | return new EzNode(this.app, match);
|
| | }
|
| |
|
| | |
| | |
| |
|
| | reload() {
|
| | const graph = JSON.parse(JSON.stringify(this.app.graph.serialize()));
|
| | return new Promise((r) => {
|
| | this.app.graph.clear();
|
| | setTimeout(async () => {
|
| | await this.app.loadGraphData(graph);
|
| | r();
|
| | }, 10);
|
| | });
|
| | }
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | toPrompt() {
|
| |
|
| | return this.app.graphToPrompt();
|
| | }
|
| | }
|
| |
|
| | export const Ez = {
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | graph(app, LiteGraph = window["LiteGraph"], LGraphCanvas = window["LGraphCanvas"], clearGraph = true) {
|
| |
|
| | LGraphCanvas.active_canvas = app.canvas;
|
| |
|
| | if (clearGraph) {
|
| | app.graph.clear();
|
| | }
|
| |
|
| |
|
| | const factory = new Proxy(
|
| | {},
|
| | {
|
| | get(_, p) {
|
| | if (typeof p !== "string") throw new Error("Invalid node");
|
| | const node = LiteGraph.createNode(p);
|
| | if (!node) throw new Error(`Unknown node "${p}"`);
|
| | app.graph.add(node);
|
| |
|
| | |
| | |
| |
|
| | return function (...args) {
|
| | const ezNode = new EzNode(app, node);
|
| | const inputs = ezNode.inputs;
|
| |
|
| | let slot = 0;
|
| | for (const arg of args) {
|
| | if (arg instanceof EzOutput) {
|
| | arg.connectTo(inputs[slot++]);
|
| | } else {
|
| | for (const k in arg) {
|
| | ezNode.widgets[k].value = arg[k];
|
| | }
|
| | }
|
| | }
|
| |
|
| | return ezNode;
|
| | };
|
| | },
|
| | }
|
| | );
|
| |
|
| | return { graph: new EzGraph(app), ez: factory };
|
| | },
|
| | };
|
| |
|