Subgraph widget promotion - Part 1 (#5537)

* Prerequisite tweaks for subgraph widget promotion

* Clean up DOMWidget tracking on graph change

* Mark migrated CombOWidget functions private

* Cleanup placeholder node cast
This commit is contained in:
AustinMroz
2025-09-16 19:17:35 -07:00
committed by GitHub
parent ede43c5e5c
commit 6a01b08ebf
5 changed files with 70 additions and 22 deletions

View File

@@ -25,7 +25,9 @@ const config: KnipConfig = {
'src/types/generatedManagerTypes.ts', 'src/types/generatedManagerTypes.ts',
'src/types/comfyRegistryTypes.ts', 'src/types/comfyRegistryTypes.ts',
// Used by a custom node (that should move off of this) // Used by a custom node (that should move off of this)
'src/scripts/ui/components/splitButton.ts' 'src/scripts/ui/components/splitButton.ts',
// Staged for for use with subgraph widget promotion
'src/lib/litegraph/src/widgets/DisconnectedWidget.ts'
], ],
compilers: { compilers: {
// https://github.com/webpro-nl/knip/issues/1008#issuecomment-3207756199 // https://github.com/webpro-nl/knip/issues/1008#issuecomment-3207756199

View File

@@ -34,7 +34,7 @@ const updateWidgets = () => {
const widget = widgetState.widget const widget = widgetState.widget
// Early exit for non-visible widgets // Early exit for non-visible widgets
if (!widget.isVisible()) { if (!widget.isVisible() || !widgetState.active) {
widgetState.visible = false widgetState.visible = false
continue continue
} }

View File

@@ -45,7 +45,7 @@ export class ComboWidget
return typeof this.value === 'number' ? String(this.value) : this.value return typeof this.value === 'number' ? String(this.value) : this.value
} }
#getValues(node: LGraphNode): Values { private getValues(node: LGraphNode): Values {
const { values } = this.options const { values } = this.options
if (values == null) throw new Error('[ComboWidget]: values is required') if (values == null) throw new Error('[ComboWidget]: values is required')
@@ -57,7 +57,7 @@ export class ComboWidget
* @param increment `true` if checking the use of the increment button, `false` for decrement * @param increment `true` if checking the use of the increment button, `false` for decrement
* @returns `true` if the value is at the given index, otherwise `false`. * @returns `true` if the value is at the given index, otherwise `false`.
*/ */
#canUseButton(increment: boolean): boolean { private canUseButton(increment: boolean): boolean {
const { values } = this.options const { values } = this.options
// If using legacy duck-typed method, false is the most permissive return value // If using legacy duck-typed method, false is the most permissive return value
if (typeof values === 'function') return false if (typeof values === 'function') return false
@@ -78,23 +78,23 @@ export class ComboWidget
* Handles edge case where the value is both the first and last item in the list. * Handles edge case where the value is both the first and last item in the list.
*/ */
override canIncrement(): boolean { override canIncrement(): boolean {
return this.#canUseButton(true) return this.canUseButton(true)
} }
override canDecrement(): boolean { override canDecrement(): boolean {
return this.#canUseButton(false) return this.canUseButton(false)
} }
override incrementValue(options: WidgetEventOptions): void { override incrementValue(options: WidgetEventOptions): void {
this.#tryChangeValue(1, options) this.tryChangeValue(1, options)
} }
override decrementValue(options: WidgetEventOptions): void { override decrementValue(options: WidgetEventOptions): void {
this.#tryChangeValue(-1, options) this.tryChangeValue(-1, options)
} }
#tryChangeValue(delta: number, options: WidgetEventOptions): void { private tryChangeValue(delta: number, options: WidgetEventOptions): void {
const values = this.#getValues(options.node) const values = this.getValues(options.node)
const indexedValues = toArray(values) const indexedValues = toArray(values)
// avoids double click event // avoids double click event
@@ -128,7 +128,7 @@ export class ComboWidget
if (x > width - 40) return this.incrementValue({ e, node, canvas }) if (x > width - 40) return this.incrementValue({ e, node, canvas })
// Otherwise, show dropdown menu // Otherwise, show dropdown menu
const values = this.#getValues(node) const values = this.getValues(node)
const values_list = toArray(values) const values_list = toArray(values)
// Handle center click - show dropdown menu // Handle center click - show dropdown menu

View File

@@ -0,0 +1,38 @@
import { LGraphNode } from '@/lib/litegraph/src/LGraphNode'
import type { IButtonWidget } from '@/lib/litegraph/src/types/widgets'
import { BaseWidget, type DrawWidgetOptions } from './BaseWidget'
class DisconnectedWidget extends BaseWidget<IButtonWidget> {
constructor(widget: IButtonWidget) {
super(widget, new LGraphNode('DisconnectedPlaceholder'))
this.disabled = true
}
override drawWidget(
ctx: CanvasRenderingContext2D,
{ width, showText = true }: DrawWidgetOptions
) {
ctx.save()
this.drawWidgetShape(ctx, { width, showText })
if (showText) {
this.drawTruncatingText({ ctx, width, leftPadding: 0, rightPadding: 0 })
}
ctx.restore()
}
override onClick() {}
override get _displayValue() {
return 'Disconnected'
}
}
const conf: IButtonWidget = {
type: 'button',
value: undefined,
name: 'Disconnected',
options: {},
y: 0,
clicked: false
}
export const disconnectedWidget = new DisconnectedWidget(conf)

View File

@@ -35,6 +35,7 @@ import {
isComboInputSpecV1, isComboInputSpecV1,
isComboInputSpecV2 isComboInputSpecV2
} from '@/schemas/nodeDefSchema' } from '@/schemas/nodeDefSchema'
import { type BaseDOMWidget, DOMWidgetImpl } from '@/scripts/domWidget'
import { getFromWebmFile } from '@/scripts/metadata/ebml' import { getFromWebmFile } from '@/scripts/metadata/ebml'
import { getGltfBinaryMetadata } from '@/scripts/metadata/gltf' import { getGltfBinaryMetadata } from '@/scripts/metadata/gltf'
import { getFromIsobmffFile } from '@/scripts/metadata/isobmff' import { getFromIsobmffFile } from '@/scripts/metadata/isobmff'
@@ -837,22 +838,29 @@ export class ComfyApp {
this.canvas.canvas.addEventListener<'litegraph:set-graph'>( this.canvas.canvas.addEventListener<'litegraph:set-graph'>(
'litegraph:set-graph', 'litegraph:set-graph',
(e) => { (e) => {
// Assertion: Not yet defined in litegraph.
const { newGraph } = e.detail const { newGraph } = e.detail
const nodeSet = new Set(newGraph.nodes)
const widgetStore = useDomWidgetStore() const widgetStore = useDomWidgetStore()
// Assertions: UnwrapRef const activeWidgets: Record<
for (const { widget } of widgetStore.activeWidgetStates) { string,
if (!nodeSet.has(widget.node)) { BaseDOMWidget<object | string>
widgetStore.deactivateWidget(widget.id) > = Object.fromEntries(
} newGraph.nodes
} .flatMap((node) => node.widgets ?? [])
.filter((w) => w instanceof DOMWidgetImpl)
.map((w) => [w.id, w])
)
for (const { widget } of widgetStore.inactiveWidgetStates) { for (const [
if (nodeSet.has(widget.node)) { widgetId,
widgetStore.activateWidget(widget.id) widgetState
] of widgetStore.widgetStates.entries()) {
if (widgetId in activeWidgets) {
widgetState.active = true
widgetState.widget = activeWidgets[widgetId]
} else {
widgetState.active = false
} }
} }
} }