mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-30 19:21:54 +00:00
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:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
38
src/lib/litegraph/src/widgets/DisconnectedWidget.ts
Normal file
38
src/lib/litegraph/src/widgets/DisconnectedWidget.ts
Normal 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)
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user