| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | 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 }; |
| | }, |
| | }; |
| |
|