Add some branching nodes
This commit is contained in:
Submodule litegraph updated: 0e4bbd2169...fd56d0c4e6
@@ -44,6 +44,7 @@
|
||||
"@litegraph-ts/core": "workspace:*",
|
||||
"@litegraph-ts/nodes-basic": "workspace:*",
|
||||
"@litegraph-ts/nodes-events": "workspace:*",
|
||||
"@litegraph-ts/nodes-math": "workspace:*",
|
||||
"@litegraph-ts/tsconfig": "workspace:*",
|
||||
"@sveltejs/vite-plugin-svelte": "^2.1.1",
|
||||
"@tsconfig/svelte": "^4.0.1",
|
||||
|
||||
19
pnpm-lock.yaml
generated
19
pnpm-lock.yaml
generated
@@ -40,6 +40,9 @@ importers:
|
||||
'@litegraph-ts/nodes-events':
|
||||
specifier: workspace:*
|
||||
version: link:litegraph/packages/nodes-events
|
||||
'@litegraph-ts/nodes-math':
|
||||
specifier: workspace:*
|
||||
version: link:litegraph/packages/nodes-math
|
||||
'@litegraph-ts/tsconfig':
|
||||
specifier: workspace:*
|
||||
version: link:litegraph/packages/tsconfig
|
||||
@@ -786,6 +789,22 @@ importers:
|
||||
specifier: ^4.2.1
|
||||
version: 4.3.1
|
||||
|
||||
litegraph/packages/nodes-math:
|
||||
dependencies:
|
||||
'@litegraph-ts/core':
|
||||
specifier: workspace:*
|
||||
version: link:../core
|
||||
devDependencies:
|
||||
'@litegraph-ts/tsconfig':
|
||||
specifier: workspace:*
|
||||
version: link:../tsconfig
|
||||
typescript:
|
||||
specifier: ^5.0.3
|
||||
version: 5.0.3
|
||||
vite:
|
||||
specifier: ^4.2.1
|
||||
version: 4.3.1
|
||||
|
||||
litegraph/packages/tsconfig: {}
|
||||
|
||||
packages:
|
||||
|
||||
@@ -8,6 +8,7 @@ import { get } from "svelte/store";
|
||||
import type ComfyGraphNode from "./nodes/ComfyGraphNode";
|
||||
import type IComfyInputSlot from "./IComfyInputSlot";
|
||||
import type { ComfyBackendNode } from "./nodes/ComfyBackendNode";
|
||||
import type { ComfyWidgetNode } from "./nodes";
|
||||
|
||||
type ComfyGraphEvents = {
|
||||
configured: (graph: LGraph) => void
|
||||
@@ -52,31 +53,56 @@ export default class ComfyGraph extends LGraph {
|
||||
layoutState.nodeAdded(node)
|
||||
this.graphSync.onNodeAdded(node);
|
||||
|
||||
if ("comfyClass" in node // Is this a comfy node
|
||||
&& !("svelteComponentType" in node) // ...and not also a ComfyWidgetNode
|
||||
&& !options.addedByDeserialize // ...and we're not trying to deserialize an existing workflow
|
||||
&& get(uiState).autoAddUI) {
|
||||
console.debug("[ComfyGraph] AutoAdd UI")
|
||||
const comfyNode = node as ComfyBackendNode;
|
||||
const widgetNodesAdded = []
|
||||
for (let index = 0; index < comfyNode.inputs.length; index++) {
|
||||
const input = comfyNode.inputs[index];
|
||||
if ("config" in input) {
|
||||
const comfyInput = input as IComfyInputSlot;
|
||||
if (comfyInput.defaultWidgetNode) {
|
||||
const widgetNode = LiteGraph.createNode(comfyInput.defaultWidgetNode)
|
||||
const inputPos = comfyNode.getConnectionPos(true, index);
|
||||
this.add(widgetNode)
|
||||
widgetNode.connect(0, comfyNode, index);
|
||||
widgetNode.collapse();
|
||||
widgetNode.pos = [inputPos[0] - 140, inputPos[1] + LiteGraph.NODE_SLOT_HEIGHT / 2];
|
||||
widgetNodesAdded.push(widgetNode)
|
||||
if ("outputProperties" in node) {
|
||||
const widgetNode = node as ComfyWidgetNode;
|
||||
for (const propName of widgetNode.outputProperties) {
|
||||
widgetNode.addPropertyAsOutput(propName.name, propName.type)
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the class declared a default widget layout
|
||||
if ("defaultWidgets" in node && !("svelteComponentType" in node)) {
|
||||
const comfyNode = node as ComfyGraphNode;
|
||||
const widgets = comfyNode.defaultWidgets;
|
||||
|
||||
if (widgets) {
|
||||
if (widgets.inputs) {
|
||||
for (const pair of Object.entries(comfyNode.defaultWidgets.inputs)) {
|
||||
const [index, spec] = pair
|
||||
const input = comfyNode.inputs[index] as IComfyInputSlot;
|
||||
input.defaultWidgetNode = spec.defaultWidgetNode;
|
||||
if (spec.config)
|
||||
input.config = spec.config
|
||||
}
|
||||
}
|
||||
}
|
||||
const dragItems = widgetNodesAdded.map(wn => get(layoutState).allItemsByNode[wn.id]?.dragItem).filter(di => di)
|
||||
console.debug("[ComfyGraph] Group new widgets", dragItems)
|
||||
layoutState.groupItems(dragItems, { title: comfyNode.comfyClass })
|
||||
}
|
||||
|
||||
if (get(uiState).autoAddUI) {
|
||||
if (!("svelteComponentType" in node) && !options.addedByDeserialize) {
|
||||
console.debug("[ComfyGraph] AutoAdd UI")
|
||||
const comfyNode = node as ComfyGraphNode;
|
||||
const widgetNodesAdded = []
|
||||
for (let index = 0; index < comfyNode.inputs.length; index++) {
|
||||
const input = comfyNode.inputs[index];
|
||||
if ("config" in input) {
|
||||
const comfyInput = input as IComfyInputSlot;
|
||||
if (comfyInput.defaultWidgetNode) {
|
||||
const widgetNode = LiteGraph.createNode(comfyInput.defaultWidgetNode)
|
||||
const inputPos = comfyNode.getConnectionPos(true, index);
|
||||
this.add(widgetNode)
|
||||
widgetNode.connect(0, comfyNode, index);
|
||||
widgetNode.collapse();
|
||||
widgetNode.pos = [inputPos[0] - 140, inputPos[1] + LiteGraph.NODE_SLOT_HEIGHT / 2];
|
||||
widgetNodesAdded.push(widgetNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
const dragItems = widgetNodesAdded.map(wn => get(layoutState).allItemsByNode[wn.id]?.dragItem).filter(di => di)
|
||||
console.debug("[ComfyGraph] Group new widgets", dragItems)
|
||||
|
||||
layoutState.groupItems(dragItems, { title: node.title })
|
||||
}
|
||||
}
|
||||
|
||||
console.debug("Added", node);
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
let resizeTimeout: NodeJS.Timeout | null;
|
||||
let hasShownUIHelpToast: boolean = false;
|
||||
|
||||
let debugLayout: boolean = true;
|
||||
let debugLayout: boolean = false;
|
||||
|
||||
const toastOptions = {
|
||||
intro: { duration: 200 },
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { LiteGraph, LGraph, LGraphCanvas, LGraphNode, type LGraphNodeConstructor, type LGraphNodeExecutable, type SerializedLGraph, type SerializedLGraphGroup, type SerializedLGraphNode, type SerializedLLink, NodeMode, type Vector2, BuiltInSlotType } from "@litegraph-ts/core";
|
||||
import type { LConnectionKind, INodeSlot } from "@litegraph-ts/core";
|
||||
import ComfyAPI from "$lib/api"
|
||||
import { ComfyWidgets } from "$lib/widgets"
|
||||
import defaultGraph from "$lib/defaultGraph"
|
||||
import { getPngMetadata, importA1111 } from "$lib/pnginfo";
|
||||
import EventEmitter from "events";
|
||||
@@ -10,6 +9,7 @@ import type TypedEmitter from "typed-emitter";
|
||||
// Import nodes
|
||||
import "@litegraph-ts/nodes-basic"
|
||||
import "@litegraph-ts/nodes-events"
|
||||
import "@litegraph-ts/nodes-math"
|
||||
import * as nodes from "$lib/nodes/index"
|
||||
|
||||
import ComfyGraphCanvas, { type SerializedGraphCanvasState } from "$lib/ComfyGraphCanvas";
|
||||
@@ -482,17 +482,19 @@ export default class ComfyApp {
|
||||
for (let i = 0; i < node.inputs.length; i++) {
|
||||
let parent: ComfyGraphNode = node.getInputNode(i) as ComfyGraphNode;
|
||||
if (parent) {
|
||||
const seen = {}
|
||||
let link = node.getInputLink(i);
|
||||
while (parent && !parent.isBackendNode) {
|
||||
link = parent.getInputLink(link.origin_slot);
|
||||
if (link) {
|
||||
if (link && !seen[link.id]) {
|
||||
seen[link.id] = true
|
||||
parent = parent.getInputNode(link.origin_slot) as ComfyGraphNode;
|
||||
} else {
|
||||
parent = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (link) {
|
||||
if (link && parent && parent.isBackendNode) {
|
||||
const input = node.inputs[i]
|
||||
// TODO can null be a legitimate value in some cases?
|
||||
// Nodes like CLIPLoader will never have a value in the frontend, hence "null".
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,10 +1,24 @@
|
||||
import type { ComfyInputConfig } from "$lib/IComfyInputSlot";
|
||||
import type { SerializedPrompt } from "$lib/components/ComfyApp";
|
||||
import type ComfyWidget from "$lib/components/widgets/ComfyWidget";
|
||||
import { LGraph, LGraphNode } from "@litegraph-ts/core";
|
||||
import type { SvelteComponentDev } from "svelte/internal";
|
||||
import type { ComfyWidgetNode } from "./ComfyWidgetNodes";
|
||||
|
||||
export type DefaultWidgetSpec = {
|
||||
defaultWidgetNode: new (name?: string) => ComfyWidgetNode,
|
||||
config?: ComfyInputConfig
|
||||
}
|
||||
|
||||
export type DefaultWidgetLayout = {
|
||||
inputs?: Record<number, DefaultWidgetSpec>,
|
||||
}
|
||||
|
||||
export default class ComfyGraphNode extends LGraphNode {
|
||||
isBackendNode?: boolean;
|
||||
|
||||
afterQueued?(prompt: SerializedPrompt): void;
|
||||
onExecuted?(output: any): void;
|
||||
|
||||
defaultWidgets?: DefaultWidgetLayout
|
||||
}
|
||||
|
||||
120
src/lib/nodes/ComfySelector.ts
Normal file
120
src/lib/nodes/ComfySelector.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import { BuiltInSlotType, LiteGraph, type SlotLayout } from "@litegraph-ts/core";
|
||||
import ComfyGraphNode from "./ComfyGraphNode";
|
||||
|
||||
export interface ComfySelectorProperties extends Record<any, any> {
|
||||
value: any
|
||||
}
|
||||
|
||||
export default class ComfySelector extends ComfyGraphNode {
|
||||
override properties: ComfySelectorProperties = {
|
||||
value: null
|
||||
}
|
||||
|
||||
static slotLayout: SlotLayout = {
|
||||
inputs: [
|
||||
{ name: "select", type: "number" },
|
||||
{ name: "A", type: "*" },
|
||||
{ name: "B", type: "*" },
|
||||
{ name: "C", type: "*" },
|
||||
{ name: "D", type: "*" },
|
||||
],
|
||||
outputs: [
|
||||
{ name: "out", type: "*" }
|
||||
],
|
||||
}
|
||||
|
||||
private selected: number = 0;
|
||||
|
||||
constructor(title?: string) {
|
||||
super(title);
|
||||
}
|
||||
|
||||
override onDrawBackground(ctx: CanvasRenderingContext2D) {
|
||||
if (this.flags.collapsed) {
|
||||
return;
|
||||
}
|
||||
ctx.fillStyle = "#AFB";
|
||||
var y = (this.selected + 1) * LiteGraph.NODE_SLOT_HEIGHT + 6;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(50, y);
|
||||
ctx.lineTo(50, y + LiteGraph.NODE_SLOT_HEIGHT);
|
||||
ctx.lineTo(34, y + LiteGraph.NODE_SLOT_HEIGHT * 0.5);
|
||||
ctx.fill();
|
||||
};
|
||||
|
||||
override onExecute() {
|
||||
var sel = this.getInputData(0);
|
||||
if (sel == null || sel.constructor !== Number)
|
||||
sel = 0;
|
||||
this.selected = sel = Math.round(sel) % (this.inputs.length - 1);
|
||||
var v = this.getInputData(sel + 1);
|
||||
if (v !== undefined) {
|
||||
this.setOutputData(0, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LiteGraph.registerNodeType({
|
||||
class: ComfySelector,
|
||||
title: "Comfy.Selector",
|
||||
desc: "Selects an output from two or more inputs",
|
||||
type: "utils/selector"
|
||||
})
|
||||
|
||||
export interface ComfySelectorTwoProperties extends Record<any, any> {
|
||||
value: any
|
||||
}
|
||||
|
||||
export class ComfySelectorTwo extends ComfyGraphNode {
|
||||
override properties: ComfySelectorTwoProperties = {
|
||||
value: null
|
||||
}
|
||||
|
||||
static slotLayout: SlotLayout = {
|
||||
inputs: [
|
||||
{ name: "select", type: "boolean" },
|
||||
{ name: "true", type: "*" },
|
||||
{ name: "false", type: "*" },
|
||||
],
|
||||
outputs: [
|
||||
{ name: "out", type: "*" }
|
||||
],
|
||||
}
|
||||
|
||||
private selected: number = 0;
|
||||
|
||||
constructor(title?: string) {
|
||||
super(title);
|
||||
}
|
||||
|
||||
override onDrawBackground(ctx: CanvasRenderingContext2D) {
|
||||
if (this.flags.collapsed) {
|
||||
return;
|
||||
}
|
||||
ctx.fillStyle = "#AFB";
|
||||
var y = (this.selected + 1) * LiteGraph.NODE_SLOT_HEIGHT + 6;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(50, y);
|
||||
ctx.lineTo(50, y + LiteGraph.NODE_SLOT_HEIGHT);
|
||||
ctx.lineTo(34, y + LiteGraph.NODE_SLOT_HEIGHT * 0.5);
|
||||
ctx.fill();
|
||||
};
|
||||
|
||||
override onExecute() {
|
||||
var sel = this.getInputData(0);
|
||||
if (sel == null || sel.constructor !== Boolean)
|
||||
sel = 0;
|
||||
this.selected = sel ? 0 : 1;
|
||||
var v = this.getInputData(this.selected + 1);
|
||||
if (v !== undefined) {
|
||||
this.setOutputData(0, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LiteGraph.registerNodeType({
|
||||
class: ComfySelectorTwo,
|
||||
title: "Comfy.Selector2",
|
||||
desc: "Selects an output from two inputs with a boolean",
|
||||
type: "utils/selector2"
|
||||
})
|
||||
107
src/lib/nodes/ComfyValueControl.ts
Normal file
107
src/lib/nodes/ComfyValueControl.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import { BuiltInSlotType, LiteGraph, type SlotLayout } from "@litegraph-ts/core";
|
||||
import ComfyGraphNode, { type DefaultWidgetLayout } from "./ComfyGraphNode";
|
||||
import { clamp } from "$lib/utils";
|
||||
import ComboWidget from "$lib/widgets/ComboWidget.svelte";
|
||||
import { ComfyComboNode } from "./ComfyWidgetNodes";
|
||||
|
||||
export interface ComfyValueControlProperties extends Record<any, any> {
|
||||
value: any,
|
||||
action: "fixed" | "increment" | "decrement" | "randomize",
|
||||
min: number,
|
||||
max: number,
|
||||
step: number
|
||||
}
|
||||
|
||||
const INT_MAX = 1125899906842624;
|
||||
|
||||
export default class ComfyValueControl extends ComfyGraphNode {
|
||||
override properties: ComfyValueControlProperties = {
|
||||
value: null,
|
||||
action: "fixed",
|
||||
min: -INT_MAX,
|
||||
max: INT_MAX,
|
||||
step: 1
|
||||
}
|
||||
|
||||
static slotLayout: SlotLayout = {
|
||||
inputs: [
|
||||
{ name: "value", type: "number" },
|
||||
{ name: "trigger", type: BuiltInSlotType.ACTION },
|
||||
{ name: "action", type: "string" },
|
||||
{ name: "min", type: "number" },
|
||||
{ name: "max", type: "number" },
|
||||
{ name: "step", type: "number" }
|
||||
],
|
||||
outputs: [
|
||||
{ name: "value", type: "*" }
|
||||
],
|
||||
}
|
||||
|
||||
override defaultWidgets: DefaultWidgetLayout = {
|
||||
inputs: {
|
||||
2: {
|
||||
defaultWidgetNode: ComfyComboNode,
|
||||
config: {
|
||||
defaultValue: "randomize",
|
||||
values: ["fixed", "increment", "decrement", "randomize"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor(title?: string) {
|
||||
super(title);
|
||||
}
|
||||
|
||||
override onExecute() {
|
||||
this.setProperty("action", this.getInputData(2) || "fixed")
|
||||
this.setProperty("min", this.getInputData(3))
|
||||
this.setProperty("max", this.getInputData(4))
|
||||
this.setProperty("step", this.getInputData(5) || 1)
|
||||
}
|
||||
|
||||
override onAction(action: any, param: any) {
|
||||
var v = this.getInputData(0)
|
||||
if (typeof v !== "number")
|
||||
return
|
||||
|
||||
let min = this.properties.min
|
||||
let max = this.properties.max
|
||||
if (min == null) min = -INT_MAX
|
||||
if (max == null) max = INT_MAX
|
||||
|
||||
// limit to something that javascript can handle
|
||||
min = Math.max(-INT_MAX, this.properties.min);
|
||||
max = Math.min(INT_MAX, this.properties.max);
|
||||
let range = (max - min) / (this.properties.step);
|
||||
|
||||
//adjust values based on valueControl Behaviour
|
||||
switch (this.properties.action) {
|
||||
case "fixed":
|
||||
break;
|
||||
case "increment":
|
||||
v += this.properties.step;
|
||||
break;
|
||||
case "decrement":
|
||||
v -= this.properties.step;
|
||||
break;
|
||||
case "randomize":
|
||||
v = Math.floor(Math.random() * range) * (this.properties.step) + min;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
v = clamp(v, min, max)
|
||||
this.setProperty("value", v)
|
||||
this.setOutputData(0, v)
|
||||
|
||||
console.debug("ValueControl", v, this.properties)
|
||||
};
|
||||
}
|
||||
|
||||
LiteGraph.registerNodeType({
|
||||
class: ComfyValueControl,
|
||||
title: "Comfy.ValueControl",
|
||||
desc: "Adjusts an incoming value based on behavior",
|
||||
type: "utils/value_control"
|
||||
})
|
||||
@@ -36,6 +36,15 @@ export abstract class ComfyWidgetNode<T = any> extends ComfyGraphNode {
|
||||
/** If false, user manually set min/max/step, and should not be autoinherited from connected input */
|
||||
autoConfig: boolean = true;
|
||||
|
||||
copyFromInputLink: boolean = true;
|
||||
|
||||
/** Names of properties to add as inputs */
|
||||
// shownInputProperties: string[] = []
|
||||
|
||||
/** Names of properties to add as outputs */
|
||||
private shownOutputProperties: Record<string, { type: string, index: number }> = {}
|
||||
outputProperties: { name: string, type: string }[] = []
|
||||
|
||||
override isBackendNode = false;
|
||||
override serialize_widgets = true;
|
||||
|
||||
@@ -62,6 +71,18 @@ export abstract class ComfyWidgetNode<T = any> extends ComfyGraphNode {
|
||||
this.unsubscribe = this.value.subscribe(this.onValueUpdated.bind(this))
|
||||
}
|
||||
|
||||
addPropertyAsOutput(propertyName: string, type: string) {
|
||||
if (this.shownOutputProperties[propertyName])
|
||||
return;
|
||||
|
||||
if (!(propertyName in this.properties)) {
|
||||
throw `No property named ${propertyName} found!`
|
||||
}
|
||||
|
||||
this.shownOutputProperties[propertyName] = { type, index: this.outputs.length }
|
||||
this.addOutput(propertyName, type)
|
||||
}
|
||||
|
||||
formatValue(value: any): string {
|
||||
return Watch.toString(value)
|
||||
}
|
||||
@@ -84,21 +105,33 @@ export abstract class ComfyWidgetNode<T = any> extends ComfyGraphNode {
|
||||
this.value.set(value)
|
||||
}
|
||||
|
||||
abstract validateValue(value: any): boolean;
|
||||
override onPropertyChanged(property: string, value: any, prevValue?: any) {
|
||||
const data = this.shownOutputProperties[property]
|
||||
if (data)
|
||||
this.setOutputData(data.index, value)
|
||||
}
|
||||
|
||||
/*
|
||||
* Logic to run if this widget can be treated as output (slider, combo, text)
|
||||
*/
|
||||
override onExecute() {
|
||||
if (this.inputs.length >= this.inputIndex) {
|
||||
const data = this.getInputData(this.inputIndex)
|
||||
if (data && this.validateValue(data)) { // TODO can "null" be a legitimate value here?
|
||||
this.setValue(data)
|
||||
if (this.copyFromInputLink) {
|
||||
if (this.inputs.length >= this.inputIndex) {
|
||||
const data = this.getInputData(this.inputIndex)
|
||||
if (data) { // TODO can "null" be a legitimate value here?
|
||||
this.setValue(data)
|
||||
const input = this.getInputLink(this.inputIndex)
|
||||
input.data = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.outputs.length >= this.outputIndex) {
|
||||
this.setOutputData(this.outputIndex, get(this.value))
|
||||
}
|
||||
for (const propName in this.shownOutputProperties) {
|
||||
const data = this.shownOutputProperties[propName]
|
||||
this.setOutputData(data.index, this.properties[propName])
|
||||
}
|
||||
}
|
||||
|
||||
/** Called when a backend node sends a ComfyUI output over a link */
|
||||
@@ -118,18 +151,19 @@ export abstract class ComfyWidgetNode<T = any> extends ComfyGraphNode {
|
||||
const comfyInput = input as IComfyInputSlot;
|
||||
for (const key in comfyInput.config)
|
||||
this.setProperty(key, comfyInput.config[key])
|
||||
|
||||
if ("defaultValue" in this.properties)
|
||||
this.setValue(this.properties.defaultValue)
|
||||
|
||||
const widget = layoutState.findLayoutForNode(this.id)
|
||||
if (widget && input.name !== "") {
|
||||
widget.attrs.title = input.name;
|
||||
}
|
||||
|
||||
console.debug("Property copy", input, this.properties)
|
||||
|
||||
this.setValue(get(this.value))
|
||||
}
|
||||
if ("defaultValue" in this.properties)
|
||||
this.setValue(this.properties.defaultValue)
|
||||
|
||||
const widget = layoutState.findLayoutForNode(this.id)
|
||||
if (widget && input.name !== "") {
|
||||
widget.attrs.title = input.name;
|
||||
}
|
||||
|
||||
console.debug("Property copy", input, this.properties)
|
||||
|
||||
this.setValue(get(this.value))
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -167,11 +201,13 @@ export abstract class ComfyWidgetNode<T = any> extends ComfyGraphNode {
|
||||
clampOneConfig(input: IComfyInputSlot) { }
|
||||
|
||||
override onSerialize(o: SerializedLGraphNode) {
|
||||
(o as any).comfyValue = get(this.value)
|
||||
(o as any).comfyValue = get(this.value);
|
||||
(o as any).shownOutputProperties = this.shownOutputProperties
|
||||
}
|
||||
|
||||
override onConfigure(o: SerializedLGraphNode) {
|
||||
this.value.set((o as any).comfyValue)
|
||||
this.value.set((o as any).comfyValue);
|
||||
this.shownOutputProperties = (o as any).shownOutputProperties;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,25 +235,32 @@ export class ComfySliderNode extends ComfyWidgetNode<number> {
|
||||
],
|
||||
outputs: [
|
||||
{ name: "value", type: "number" },
|
||||
{ name: "changed", type: BuiltInSlotType.EVENT }
|
||||
{ name: "changed", type: BuiltInSlotType.EVENT },
|
||||
]
|
||||
}
|
||||
|
||||
override outputProperties = [
|
||||
{ name: "min", type: "number" },
|
||||
{ name: "max", type: "number" },
|
||||
{ name: "step", type: "number" },
|
||||
{ name: "precision", type: "number" },
|
||||
]
|
||||
|
||||
constructor(name?: string) {
|
||||
super(name, 0)
|
||||
}
|
||||
|
||||
override validateValue(value: any): boolean {
|
||||
return typeof value === "number"
|
||||
&& value >= this.properties.min
|
||||
&& value <= this.properties.max
|
||||
override setValue(value: any) {
|
||||
if (typeof value !== "number")
|
||||
return;
|
||||
super.setValue(clamp(value, this.properties.min, this.properties.max))
|
||||
}
|
||||
|
||||
override clampOneConfig(input: IComfyInputSlot) {
|
||||
// this.setProperty("min", clamp(this.properties.min, input.config.min, input.config.max))
|
||||
// this.setProperty("max", clamp(this.properties.max, input.config.max, input.config.min))
|
||||
// this.setProperty("step", Math.min(this.properties.step, input.config.step))
|
||||
this.setValue(clamp(this.properties.defaultValue, this.properties.min, this.properties.max))
|
||||
this.setValue(this.properties.defaultValue)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,10 +323,10 @@ export class ComfyComboNode extends ComfyWidgetNode<string> {
|
||||
return true;
|
||||
}
|
||||
|
||||
override validateValue(value: any): boolean {
|
||||
if (typeof value !== "string")
|
||||
return false;
|
||||
return this.properties.values.indexOf(value) !== -1;
|
||||
override setValue(value: any) {
|
||||
if (typeof value !== "string" || this.properties.values.indexOf(value) === -1)
|
||||
return;
|
||||
super.setValue(value)
|
||||
}
|
||||
|
||||
override clampOneConfig(input: IComfyInputSlot) {
|
||||
@@ -291,7 +334,7 @@ export class ComfyComboNode extends ComfyWidgetNode<string> {
|
||||
if (input.config.values.length === 0)
|
||||
this.setValue("")
|
||||
else
|
||||
this.setValue(input.config.values[0])
|
||||
this.setValue(input.config.defaultValue || input.config.values[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -329,8 +372,8 @@ export class ComfyTextNode extends ComfyWidgetNode<string> {
|
||||
super(name, "")
|
||||
}
|
||||
|
||||
override validateValue(value: any): boolean {
|
||||
return typeof value === "string"
|
||||
override setValue(value: any) {
|
||||
super.setValue(`${value}`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,6 +411,7 @@ export class ComfyGalleryNode extends ComfyWidgetNode<GradioFileData[]> {
|
||||
}
|
||||
|
||||
override svelteComponentType = GalleryWidget
|
||||
override copyFromInputLink = false;
|
||||
|
||||
constructor(name?: string) {
|
||||
super(name, [])
|
||||
@@ -380,12 +424,29 @@ export class ComfyGalleryNode extends ComfyWidgetNode<GradioFileData[]> {
|
||||
}
|
||||
}
|
||||
|
||||
override formatValue(value: GradioFileData[]): string {
|
||||
return `Images: ${value.length}`
|
||||
override formatValue(value: GradioFileData[] | null): string {
|
||||
return `Images: ${value?.length || 0}`
|
||||
}
|
||||
|
||||
override validateValue(value: any): boolean {
|
||||
return Array.isArray(value) && value.every(e => "images" in e)
|
||||
private convertItems(output: GalleryOutput): GradioFileData[] {
|
||||
return output.images.map(r => {
|
||||
// TODO configure backend URL
|
||||
const url = "http://localhost:8188/view?"
|
||||
const params = new URLSearchParams(r)
|
||||
return {
|
||||
name: null,
|
||||
data: url + params
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
override setValue(value: any) {
|
||||
if (Array.isArray(value)) {
|
||||
super.setValue(value)
|
||||
}
|
||||
else {
|
||||
super.setValue([])
|
||||
}
|
||||
}
|
||||
|
||||
receiveOutput() {
|
||||
@@ -394,15 +455,7 @@ export class ComfyGalleryNode extends ComfyWidgetNode<GradioFileData[]> {
|
||||
const data = link.data as GalleryOutput
|
||||
console.debug("[ComfyGalleryNode] Received output!", data)
|
||||
|
||||
const galleryItems: GradioFileData[] = data.images.map(r => {
|
||||
// TODO configure backend URL
|
||||
const url = "http://localhost:8188/view?"
|
||||
const params = new URLSearchParams(r)
|
||||
return {
|
||||
name: null,
|
||||
data: url + params
|
||||
}
|
||||
});
|
||||
const galleryItems: GradioFileData[] = this.convertItems(link.data)
|
||||
|
||||
const currentValue = get(this.value)
|
||||
this.setValue(currentValue.concat(galleryItems))
|
||||
@@ -429,7 +482,7 @@ export class ComfyButtonNode extends ComfyWidgetNode<boolean> {
|
||||
|
||||
static slotLayout: SlotLayout = {
|
||||
outputs: [
|
||||
{ name: "event", type: BuiltInSlotType.EVENT },
|
||||
{ name: "clicked", type: BuiltInSlotType.EVENT },
|
||||
{ name: "isClicked", type: "boolean" },
|
||||
]
|
||||
}
|
||||
@@ -437,8 +490,8 @@ export class ComfyButtonNode extends ComfyWidgetNode<boolean> {
|
||||
override outputIndex = 1;
|
||||
override svelteComponentType = ButtonWidget;
|
||||
|
||||
override validateValue(value: any): boolean {
|
||||
return typeof value === "boolean"
|
||||
override setValue(value: any) {
|
||||
super.setValue(Boolean(value))
|
||||
}
|
||||
|
||||
onClick() {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
export { default as ComfyReroute } from "./ComfyReroute"
|
||||
export { ComfyWidgetNode, ComfySliderNode, ComfyComboNode, ComfyTextNode } from "./ComfyWidgetNodes"
|
||||
export { ComfyCopyAction } from "./ComfyActionNodes"
|
||||
export { default as ComfyValueControl } from "./ComfyValueControl"
|
||||
export { default as ComfySelector } from "./ComfySelector"
|
||||
|
||||
Reference in New Issue
Block a user