Inplace widget to input conversion (#2588)
Co-authored-by: github-actions <github-actions@github.com>
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 101 KiB |
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 98 KiB |
8
package-lock.json
generated
@@ -11,7 +11,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@atlaskit/pragmatic-drag-and-drop": "^1.3.1",
|
"@atlaskit/pragmatic-drag-and-drop": "^1.3.1",
|
||||||
"@comfyorg/comfyui-electron-types": "^0.4.16",
|
"@comfyorg/comfyui-electron-types": "^0.4.16",
|
||||||
"@comfyorg/litegraph": "^0.8.81",
|
"@comfyorg/litegraph": "^0.8.82",
|
||||||
"@primevue/forms": "^4.2.5",
|
"@primevue/forms": "^4.2.5",
|
||||||
"@primevue/themes": "^4.2.5",
|
"@primevue/themes": "^4.2.5",
|
||||||
"@sentry/vue": "^8.48.0",
|
"@sentry/vue": "^8.48.0",
|
||||||
@@ -1944,9 +1944,9 @@
|
|||||||
"license": "GPL-3.0-only"
|
"license": "GPL-3.0-only"
|
||||||
},
|
},
|
||||||
"node_modules/@comfyorg/litegraph": {
|
"node_modules/@comfyorg/litegraph": {
|
||||||
"version": "0.8.81",
|
"version": "0.8.82",
|
||||||
"resolved": "https://registry.npmjs.org/@comfyorg/litegraph/-/litegraph-0.8.81.tgz",
|
"resolved": "https://registry.npmjs.org/@comfyorg/litegraph/-/litegraph-0.8.82.tgz",
|
||||||
"integrity": "sha512-YJDbOXGTDUKdLooNgNlfY3Zrl9GM4t1QPYNZS/qd5xvU5pPsqZ743Hz8gqH5tr4g4xcuC94q+pCek2yAfsIwpA==",
|
"integrity": "sha512-grwCXpjSKdyH/nVt+PYnv8BLavNNdyIhCAqiAMx9V5cK4bKsFFdHweuyYD8D2ySPR1iPPhOwsvfpi42ud+mbJQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@cspotcode/source-map-support": {
|
"node_modules/@cspotcode/source-map-support": {
|
||||||
|
|||||||
@@ -84,7 +84,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@atlaskit/pragmatic-drag-and-drop": "^1.3.1",
|
"@atlaskit/pragmatic-drag-and-drop": "^1.3.1",
|
||||||
"@comfyorg/comfyui-electron-types": "^0.4.16",
|
"@comfyorg/comfyui-electron-types": "^0.4.16",
|
||||||
"@comfyorg/litegraph": "^0.8.81",
|
"@comfyorg/litegraph": "^0.8.82",
|
||||||
"@primevue/forms": "^4.2.5",
|
"@primevue/forms": "^4.2.5",
|
||||||
"@primevue/themes": "^4.2.5",
|
"@primevue/themes": "^4.2.5",
|
||||||
"@sentry/vue": "^8.48.0",
|
"@sentry/vue": "^8.48.0",
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ useExtensionService().registerExtension({
|
|||||||
const widgets = node.widgets.filter((w) => w.dynamicPrompts)
|
const widgets = node.widgets.filter((w) => w.dynamicPrompts)
|
||||||
for (const widget of widgets) {
|
for (const widget of widgets) {
|
||||||
// Override the serialization of the value to resolve dynamic prompts for all widgets supporting it in this node
|
// Override the serialization of the value to resolve dynamic prompts for all widgets supporting it in this node
|
||||||
// @ts-expect-error hacky override
|
|
||||||
widget.serializeValue = (workflowNode, widgetIndex) => {
|
widget.serializeValue = (workflowNode, widgetIndex) => {
|
||||||
if (typeof widget.value !== 'string') return widget.value
|
if (typeof widget.value !== 'string') return widget.value
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import type {
|
|||||||
LiteGraphCanvasEvent
|
LiteGraphCanvasEvent
|
||||||
} from '@comfyorg/litegraph'
|
} from '@comfyorg/litegraph'
|
||||||
import type { IFoundSlot } from '@comfyorg/litegraph'
|
import type { IFoundSlot } from '@comfyorg/litegraph'
|
||||||
|
import { INodeSlot } from '@comfyorg/litegraph'
|
||||||
|
|
||||||
import { useNodeDefStore } from '@/stores/nodeDefStore'
|
import { useNodeDefStore } from '@/stores/nodeDefStore'
|
||||||
import { useSettingStore } from '@/stores/settingStore'
|
import { useSettingStore } from '@/stores/settingStore'
|
||||||
@@ -422,11 +423,11 @@ class PrimitiveNode extends LGraphNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getWidgetConfig(slot) {
|
export function getWidgetConfig(slot: INodeSlot) {
|
||||||
return slot.widget[CONFIG] ?? slot.widget[GET_CONFIG]?.() ?? ['*', {}]
|
return slot.widget[CONFIG] ?? slot.widget[GET_CONFIG]?.() ?? ['*', {}]
|
||||||
}
|
}
|
||||||
|
|
||||||
function getConfig(widgetName) {
|
function getConfig(widgetName: string) {
|
||||||
const { nodeData } = this.constructor
|
const { nodeData } = this.constructor
|
||||||
return (
|
return (
|
||||||
nodeData?.input?.required?.[widgetName] ??
|
nodeData?.input?.required?.[widgetName] ??
|
||||||
@@ -434,21 +435,33 @@ function getConfig(widgetName) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function isConvertibleWidget(widget, config) {
|
function isConvertibleWidget(widget: IWidget, config: InputSpec): boolean {
|
||||||
return (
|
return (
|
||||||
(VALID_TYPES.includes(widget.type) || VALID_TYPES.includes(config[0])) &&
|
(VALID_TYPES.includes(widget.type) || VALID_TYPES.includes(config[0])) &&
|
||||||
!widget.options?.forceInput
|
!widget.options?.forceInput
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideWidget(node, widget, suffix = '') {
|
function hideWidget(
|
||||||
|
node: LGraphNode,
|
||||||
|
widget: IWidget,
|
||||||
|
options: { suffix?: string; holdSpace?: boolean } = {}
|
||||||
|
) {
|
||||||
|
const { suffix = '', holdSpace = true } = options
|
||||||
|
|
||||||
if (widget.type?.startsWith(CONVERTED_TYPE)) return
|
if (widget.type?.startsWith(CONVERTED_TYPE)) return
|
||||||
widget.origType = widget.type
|
widget.origType = widget.type
|
||||||
widget.origComputeSize = widget.computeSize
|
widget.origComputeSize = widget.computeSize
|
||||||
widget.origSerializeValue = widget.serializeValue
|
widget.origSerializeValue = widget.serializeValue
|
||||||
widget.computeSize = () => [0, -4] // -4 is due to the gap litegraph adds between widgets automatically
|
// @ts-expect-error custom widget type
|
||||||
widget.type = CONVERTED_TYPE + suffix
|
widget.type = CONVERTED_TYPE + suffix
|
||||||
widget.serializeValue = () => {
|
if (holdSpace) {
|
||||||
|
widget.computeSize = () => [0, LiteGraph.NODE_WIDGET_HEIGHT]
|
||||||
|
} else {
|
||||||
|
// -4 is due to the gap litegraph adds between widgets automatically
|
||||||
|
widget.computeSize = () => [0, -4]
|
||||||
|
}
|
||||||
|
widget.serializeValue = (node: LGraphNode, index: number) => {
|
||||||
// Prevent serializing the widget if we have no input linked
|
// Prevent serializing the widget if we have no input linked
|
||||||
if (!node.inputs) {
|
if (!node.inputs) {
|
||||||
return undefined
|
return undefined
|
||||||
@@ -459,19 +472,20 @@ function hideWidget(node, widget, suffix = '') {
|
|||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
return widget.origSerializeValue
|
return widget.origSerializeValue
|
||||||
? widget.origSerializeValue()
|
? widget.origSerializeValue(node, index)
|
||||||
: widget.value
|
: widget.value
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hide any linked widgets, e.g. seed+seedControl
|
// Hide any linked widgets, e.g. seed+seedControl
|
||||||
if (widget.linkedWidgets) {
|
if (widget.linkedWidgets) {
|
||||||
for (const w of widget.linkedWidgets) {
|
for (const w of widget.linkedWidgets) {
|
||||||
hideWidget(node, w, ':' + widget.name)
|
hideWidget(node, w, { suffix: ':' + widget.name, holdSpace: false })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showWidget(widget) {
|
function showWidget(widget: IWidget) {
|
||||||
|
// @ts-expect-error custom widget type
|
||||||
widget.type = widget.origType
|
widget.type = widget.origType
|
||||||
widget.computeSize = widget.origComputeSize
|
widget.computeSize = widget.origComputeSize
|
||||||
widget.serializeValue = widget.origSerializeValue
|
widget.serializeValue = widget.origSerializeValue
|
||||||
@@ -517,7 +531,7 @@ export function convertToInput(
|
|||||||
return input
|
return input
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertToWidget(node, widget) {
|
function convertToWidget(node: LGraphNode, widget: IWidget) {
|
||||||
showWidget(widget)
|
showWidget(widget)
|
||||||
const [oldWidth, oldHeight] = node.size
|
const [oldWidth, oldHeight] = node.size
|
||||||
node.removeInput(node.inputs.findIndex((i) => i.widget?.name === widget.name))
|
node.removeInput(node.inputs.findIndex((i) => i.widget?.name === widget.name))
|
||||||
@@ -542,7 +556,7 @@ function getWidgetType(config: InputSpec) {
|
|||||||
return { type }
|
return { type }
|
||||||
}
|
}
|
||||||
|
|
||||||
function isValidCombo(combo, obj) {
|
function isValidCombo(combo: string[], obj: unknown) {
|
||||||
// New input isnt a combo
|
// New input isnt a combo
|
||||||
if (!(obj instanceof Array)) {
|
if (!(obj instanceof Array)) {
|
||||||
console.log(`connection rejected: tried to connect combo to ${obj}`)
|
console.log(`connection rejected: tried to connect combo to ${obj}`)
|
||||||
|
|||||||
17
src/types/litegraph-augmentation.d.ts
vendored
@@ -1,5 +1,5 @@
|
|||||||
import '@comfyorg/litegraph'
|
import '@comfyorg/litegraph'
|
||||||
import type { LLink } from '@comfyorg/litegraph'
|
import type { LLink, Size } from '@comfyorg/litegraph'
|
||||||
|
|
||||||
import type { DOMWidget } from '@/scripts/domWidget'
|
import type { DOMWidget } from '@/scripts/domWidget'
|
||||||
import type { ComfyNodeDef } from '@/types/apiTypes'
|
import type { ComfyNodeDef } from '@/types/apiTypes'
|
||||||
@@ -17,13 +17,26 @@ declare module '@comfyorg/litegraph/dist/types/widgets' {
|
|||||||
onRemove?: () => void
|
onRemove?: () => void
|
||||||
beforeQueued?: () => unknown
|
beforeQueued?: () => unknown
|
||||||
afterQueued?: () => unknown
|
afterQueued?: () => unknown
|
||||||
serializeValue?: (node: LGraphNode, index: number) => Promise<unknown>
|
serializeValue?: (
|
||||||
|
node: LGraphNode,
|
||||||
|
index: number
|
||||||
|
) => Promise<unknown> | unknown
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the widget supports dynamic prompts, this will be set to true.
|
* If the widget supports dynamic prompts, this will be set to true.
|
||||||
* See extensions/core/dynamicPrompts.ts
|
* See extensions/core/dynamicPrompts.ts
|
||||||
*/
|
*/
|
||||||
dynamicPrompts?: boolean
|
dynamicPrompts?: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Widget conversion fields
|
||||||
|
*/
|
||||||
|
origType?: string
|
||||||
|
origComputeSize?: (width: number) => Size
|
||||||
|
origSerializeValue?: (
|
||||||
|
node: LGraphNode,
|
||||||
|
index: number
|
||||||
|
) => Promise<unknown> | unknown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||