Compare commits

...

1 Commits

Author SHA1 Message Date
Terry Jia
e154bba37e feat: add proxyWidgetSelector support to SubgraphNode 2026-04-03 18:51:54 -04:00
3 changed files with 84 additions and 3 deletions

View File

@@ -16,7 +16,10 @@ import type {
INodeInputSlot,
INodeOutputSlot
} from '@/lib/litegraph/src/interfaces'
import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets'
import type {
IBaseWidget,
IWidgetOptions
} from '@/lib/litegraph/src/types/widgets'
import { useLayoutMutations } from '@/renderer/core/layout/operations/layoutMutations'
import { layoutStore } from '@/renderer/core/layout/store/layoutStore'
import { LayoutSource } from '@/renderer/core/layout/types'
@@ -74,6 +77,7 @@ export interface SafeWidgetData {
advanced?: boolean
hidden?: boolean
read_only?: boolean
values?: IWidgetOptions['values']
}
/** Input specification from node definition */
spec?: InputSpec
@@ -222,7 +226,8 @@ function safeWidgetMapper(
canvasOnly: widget.options.canvasOnly,
advanced: widget.options?.advanced ?? widget.advanced,
hidden: widget.options.hidden,
read_only: widget.options.read_only
read_only: widget.options.read_only,
values: widget.options.values
}
}

View File

@@ -10,6 +10,15 @@ const proxyWidgetTupleSchema = z.union([
const proxyWidgetsPropertySchema = z.array(proxyWidgetTupleSchema)
type ProxyWidgetsProperty = z.infer<typeof proxyWidgetsPropertySchema>
export interface ProxyWidgetSelector {
name?: string
selected: string
options: {
label: string
widgets?: string[][]
}[]
}
export function parseProxyWidgets(
property: NodeProperty | undefined
): ProxyWidgetsProperty {

View File

@@ -45,6 +45,7 @@ import {
supportsVirtualCanvasImagePreview
} from '@/composables/node/canvasImagePreviewTypes'
import { parseProxyWidgets } from '@/core/schemas/promotionSchema'
import type { ProxyWidgetSelector } from '@/core/schemas/promotionSchema'
import { useDomWidgetStore } from '@/stores/domWidgetStore'
import {
makePromotionEntryKey,
@@ -116,6 +117,7 @@ export class SubgraphNode extends LGraphNode implements BaseLGraph {
hasMissingBoundSourceWidget: boolean
views: PromotedWidgetView[]
}
private _selectorWidget: IBaseWidget | null = null
// Declared as accessor via Object.defineProperty in constructor.
// TypeScript doesn't allow overriding a property with get/set syntax,
@@ -297,6 +299,69 @@ export class SubgraphNode extends LGraphNode implements BaseLGraph {
return views
}
private _getWidgetsWithSelector(): IBaseWidget[] {
const views = this._getPromotedViews()
const selector = this.properties.proxyWidgetSelector as
| ProxyWidgetSelector
| undefined
if (!selector?.options?.length || !this._selectorWidget) return views
const selectedOption =
selector.options.find((opt) => opt.label === selector.selected) ??
selector.options[0]
if (!selectedOption?.widgets) return [this._selectorWidget, ...views]
const allGroupedKeys = new Set(
selector.options.flatMap((opt) =>
(opt.widgets ?? []).map(([nid, wn]) => `${nid}:${wn}`)
)
)
const selectedKeys = new Set(
selectedOption.widgets.map(([nid, wn]) => `${nid}:${wn}`)
)
const filteredViews = views.filter((v) => {
const key = `${v.sourceNodeId}:${v.sourceWidgetName}`
return !allGroupedKeys.has(key) || selectedKeys.has(key)
})
return [this._selectorWidget, ...filteredViews]
}
private _initSelectorWidget(): void {
const selector = this.properties.proxyWidgetSelector as
| ProxyWidgetSelector
| undefined
if (!selector?.options?.length) {
this._selectorWidget = null
return
}
const validLabels = selector.options.map((o) => o.label)
if (!validLabels.includes(selector.selected)) {
selector.selected = validLabels[0]
}
this._selectorWidget = {
name: selector.name ?? 'selector',
type: 'combo',
value: selector.selected,
y: 0,
serialize: false,
options: {
values: validLabels
},
callback: (value: unknown) => {
selector.selected = String(value)
this._selectorWidget!.value = String(value)
this._invalidatePromotedViewsCache()
const minSize = this.computeSize()
this.setSize([this.size[0], minSize[1]])
this.graph?.setDirtyCanvas(true, true)
}
}
}
private _invalidatePromotedViewsCache(): void {
this._cacheVersion++
}
@@ -695,7 +760,7 @@ export class SubgraphNode extends LGraphNode implements BaseLGraph {
// Synthetic widgets getter — SubgraphNodes have no native widgets.
Object.defineProperty(this, 'widgets', {
get: () => this._getPromotedViews(),
get: () => this._getWidgetsWithSelector(),
set: () => {
if (import.meta.env.DEV)
console.warn(
@@ -1097,6 +1162,8 @@ export class SubgraphNode extends LGraphNode implements BaseLGraph {
this.properties.proxyWidgets = serialized
}
this._initSelectorWidget()
// Check all inputs for connected widgets
for (const input of this.inputs) {
const subgraphInput = input._subgraphSlot