mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-20 22:39:39 +00:00
refactor: remove 34 @ts-expect-error suppressions from widget-related files
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
import { t } from '@/i18n'
|
||||
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
|
||||
import type { INumericWidget } from '@/lib/litegraph/src/types/widgets'
|
||||
import { useToastStore } from '@/platform/updates/common/toastStore'
|
||||
|
||||
import { api } from '../../scripts/api'
|
||||
@@ -6,15 +8,19 @@ import { app } from '../../scripts/app'
|
||||
|
||||
const WEBCAM_READY = Symbol()
|
||||
|
||||
interface WebcamNode extends LGraphNode {
|
||||
[WEBCAM_READY]?: Promise<HTMLVideoElement>
|
||||
}
|
||||
|
||||
app.registerExtension({
|
||||
name: 'Comfy.WebcamCapture',
|
||||
getCustomWidgets() {
|
||||
return {
|
||||
WEBCAM(node, inputName) {
|
||||
// @ts-expect-error fixme ts strict error
|
||||
let res
|
||||
// @ts-expect-error fixme ts strict error
|
||||
node[WEBCAM_READY] = new Promise((resolve) => (res = resolve))
|
||||
WEBCAM(node: WebcamNode, inputName: string) {
|
||||
let resolveVideo: (video: HTMLVideoElement) => void
|
||||
node[WEBCAM_READY] = new Promise((resolve) => {
|
||||
resolveVideo = resolve
|
||||
})
|
||||
|
||||
const container = document.createElement('div')
|
||||
container.style.background = 'rgba(0,0,0,0.25)'
|
||||
@@ -31,10 +37,12 @@ app.registerExtension({
|
||||
})
|
||||
container.replaceChildren(video)
|
||||
|
||||
// @ts-expect-error fixme ts strict error
|
||||
setTimeout(() => res(video), 500) // Fallback as loadedmetadata doesnt fire sometimes?
|
||||
// @ts-expect-error fixme ts strict error
|
||||
video.addEventListener('loadedmetadata', () => res(video), false)
|
||||
setTimeout(() => resolveVideo(video), 500) // Fallback as loadedmetadata doesnt fire sometimes?
|
||||
video.addEventListener(
|
||||
'loadedmetadata',
|
||||
() => resolveVideo(video),
|
||||
false
|
||||
)
|
||||
video.srcObject = stream
|
||||
video.play()
|
||||
} catch (error) {
|
||||
@@ -44,16 +52,16 @@ app.registerExtension({
|
||||
label.style.maxHeight = '100%'
|
||||
label.style.whiteSpace = 'pre-wrap'
|
||||
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : String(error)
|
||||
if (window.isSecureContext) {
|
||||
label.textContent =
|
||||
'Unable to load webcam, please ensure access is granted:\n' +
|
||||
// @ts-expect-error fixme ts strict error
|
||||
error.message
|
||||
errorMessage
|
||||
} else {
|
||||
label.textContent =
|
||||
'Unable to load webcam. A secure context is required, if you are not accessing ComfyUI on localhost (127.0.0.1) you will have to enable TLS (https)\n\n' +
|
||||
// @ts-expect-error fixme ts strict error
|
||||
error.message
|
||||
errorMessage
|
||||
}
|
||||
|
||||
container.replaceChildren(label)
|
||||
@@ -66,32 +74,31 @@ app.registerExtension({
|
||||
}
|
||||
}
|
||||
},
|
||||
nodeCreated(node) {
|
||||
nodeCreated(node: WebcamNode) {
|
||||
if ((node.type, node.constructor.comfyClass !== 'WebcamCapture')) return
|
||||
|
||||
// @ts-expect-error fixme ts strict error
|
||||
let video
|
||||
// @ts-expect-error fixme ts strict error
|
||||
const camera = node.widgets.find((w) => w.name === 'image')
|
||||
// @ts-expect-error fixme ts strict error
|
||||
const w = node.widgets.find((w) => w.name === 'width')
|
||||
// @ts-expect-error fixme ts strict error
|
||||
const h = node.widgets.find((w) => w.name === 'height')
|
||||
// @ts-expect-error fixme ts strict error
|
||||
const captureOnQueue = node.widgets.find(
|
||||
let video: HTMLVideoElement | undefined
|
||||
const camera = node.widgets?.find((w) => w.name === 'image')
|
||||
const widthWidget = node.widgets?.find((w) => w.name === 'width') as
|
||||
| INumericWidget
|
||||
| undefined
|
||||
const heightWidget = node.widgets?.find((w) => w.name === 'height') as
|
||||
| INumericWidget
|
||||
| undefined
|
||||
const captureOnQueue = node.widgets?.find(
|
||||
(w) => w.name === 'capture_on_queue'
|
||||
)
|
||||
|
||||
const canvas = document.createElement('canvas')
|
||||
|
||||
const capture = () => {
|
||||
// @ts-expect-error widget value type narrow down
|
||||
canvas.width = w.value
|
||||
// @ts-expect-error widget value type narrow down
|
||||
canvas.height = h.value
|
||||
if (!widthWidget || !heightWidget || !video) return
|
||||
const width = widthWidget.value ?? 640
|
||||
const height = heightWidget.value ?? 480
|
||||
canvas.width = width
|
||||
canvas.height = height
|
||||
const ctx = canvas.getContext('2d')
|
||||
// @ts-expect-error widget value type narrow down
|
||||
ctx.drawImage(video, 0, 0, w.value, h.value)
|
||||
ctx?.drawImage(video, 0, 0, width, height)
|
||||
const data = canvas.toDataURL('image/png')
|
||||
|
||||
const img = new Image()
|
||||
@@ -112,48 +119,47 @@ app.registerExtension({
|
||||
btn.disabled = true
|
||||
btn.serializeValue = () => undefined
|
||||
|
||||
// @ts-expect-error fixme ts strict error
|
||||
camera.serializeValue = async () => {
|
||||
// @ts-expect-error fixme ts strict error
|
||||
if (captureOnQueue.value) {
|
||||
capture()
|
||||
} else if (!node.imgs?.length) {
|
||||
const err = `No webcam image captured`
|
||||
useToastStore().addAlert(err)
|
||||
throw new Error(err)
|
||||
}
|
||||
if (camera) {
|
||||
camera.serializeValue = async () => {
|
||||
if (captureOnQueue?.value) {
|
||||
capture()
|
||||
} else if (!node.imgs?.length) {
|
||||
const err = `No webcam image captured`
|
||||
useToastStore().addAlert(err)
|
||||
throw new Error(err)
|
||||
}
|
||||
|
||||
// Upload image to temp storage
|
||||
// @ts-expect-error fixme ts strict error
|
||||
const blob = await new Promise<Blob>((r) => canvas.toBlob(r))
|
||||
const name = `${+new Date()}.png`
|
||||
const file = new File([blob], name)
|
||||
const body = new FormData()
|
||||
body.append('image', file)
|
||||
body.append('subfolder', 'webcam')
|
||||
body.append('type', 'temp')
|
||||
const resp = await api.fetchApi('/upload/image', {
|
||||
method: 'POST',
|
||||
body
|
||||
})
|
||||
if (resp.status !== 200) {
|
||||
const err = `Error uploading camera image: ${resp.status} - ${resp.statusText}`
|
||||
useToastStore().addAlert(err)
|
||||
throw new Error(err)
|
||||
// Upload image to temp storage
|
||||
const blob = await new Promise<Blob>((resolve, reject) => {
|
||||
canvas.toBlob((b) => (b ? resolve(b) : reject(new Error('No blob'))))
|
||||
})
|
||||
const name = `${+new Date()}.png`
|
||||
const file = new File([blob], name)
|
||||
const body = new FormData()
|
||||
body.append('image', file)
|
||||
body.append('subfolder', 'webcam')
|
||||
body.append('type', 'temp')
|
||||
const resp = await api.fetchApi('/upload/image', {
|
||||
method: 'POST',
|
||||
body
|
||||
})
|
||||
if (resp.status !== 200) {
|
||||
const err = `Error uploading camera image: ${resp.status} - ${resp.statusText}`
|
||||
useToastStore().addAlert(err)
|
||||
throw new Error(err)
|
||||
}
|
||||
return `webcam/${name} [temp]`
|
||||
}
|
||||
return `webcam/${name} [temp]`
|
||||
}
|
||||
|
||||
// @ts-expect-error fixme ts strict error
|
||||
node[WEBCAM_READY].then((v) => {
|
||||
node[WEBCAM_READY]?.then((v) => {
|
||||
video = v
|
||||
// If width isn't specified then use video output resolution
|
||||
// @ts-expect-error fixme ts strict error
|
||||
if (!w.value) {
|
||||
// @ts-expect-error fixme ts strict error
|
||||
w.value = video.videoWidth || 640
|
||||
// @ts-expect-error fixme ts strict error
|
||||
h.value = video.videoHeight || 480
|
||||
if (widthWidget && !widthWidget.value) {
|
||||
widthWidget.value = video.videoWidth || 640
|
||||
}
|
||||
if (heightWidget && !heightWidget.value) {
|
||||
heightWidget.value = video.videoHeight || 480
|
||||
}
|
||||
btn.disabled = false
|
||||
btn.label = t('g.capture')
|
||||
|
||||
@@ -9,9 +9,15 @@ import type {
|
||||
ISlotType,
|
||||
LLink
|
||||
} from '@/lib/litegraph/src/litegraph'
|
||||
import type { IWidgetLocator } from '@/lib/litegraph/src/interfaces'
|
||||
import { NodeSlot } from '@/lib/litegraph/src/node/NodeSlot'
|
||||
import type { CanvasPointerEvent } from '@/lib/litegraph/src/types/events'
|
||||
import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets'
|
||||
import type {
|
||||
IBaseWidget,
|
||||
IComboWidget,
|
||||
INumericWidget
|
||||
} from '@/lib/litegraph/src/types/widgets'
|
||||
import { isPrimitiveNode } from '@/renderer/utils/nodeTypeGuards'
|
||||
import type { InputSpec } from '@/schemas/nodeDefSchema'
|
||||
import { app } from '@/scripts/app'
|
||||
import {
|
||||
@@ -22,7 +28,16 @@ import {
|
||||
import { CONFIG, GET_CONFIG } from '@/services/litegraphService'
|
||||
import { mergeInputSpec } from '@/utils/nodeDefUtil'
|
||||
import { applyTextReplacements } from '@/utils/searchAndReplace'
|
||||
import { isPrimitiveNode } from '@/renderer/utils/nodeTypeGuards'
|
||||
|
||||
/**
|
||||
* Widget locator with CONFIG symbol properties for accessing input spec.
|
||||
* Used on input/output slots to retrieve widget configuration.
|
||||
*/
|
||||
interface IWidgetLocatorWithConfig extends IWidgetLocator {
|
||||
name: string
|
||||
[GET_CONFIG]?: () => InputSpec
|
||||
[CONFIG]?: InputSpec
|
||||
}
|
||||
|
||||
const replacePropertyName = 'Run widget replace on values'
|
||||
export class PrimitiveNode extends LGraphNode {
|
||||
@@ -89,14 +104,17 @@ export class PrimitiveNode extends LGraphNode {
|
||||
override refreshComboInNode() {
|
||||
const widget = this.widgets?.[0]
|
||||
if (widget?.type === 'combo') {
|
||||
// @ts-expect-error fixme ts strict error
|
||||
widget.options.values = this.outputs[0].widget[GET_CONFIG]()[0]
|
||||
|
||||
// @ts-expect-error fixme ts strict error
|
||||
if (!widget.options.values.includes(widget.value as string)) {
|
||||
// @ts-expect-error fixme ts strict error
|
||||
widget.value = widget.options.values[0]
|
||||
;(widget.callback as Function)(widget.value)
|
||||
const comboWidget = widget as IComboWidget
|
||||
const widgetLocator = this.outputs[0].widget as IWidgetLocatorWithConfig
|
||||
const config = widgetLocator?.[GET_CONFIG]?.()
|
||||
const rawValues = config?.[0]
|
||||
if (Array.isArray(rawValues)) {
|
||||
const newValues = rawValues.map(String)
|
||||
comboWidget.options.values = newValues
|
||||
if (!newValues.includes(String(comboWidget.value))) {
|
||||
comboWidget.value = newValues[0]
|
||||
comboWidget.callback?.(comboWidget.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -186,15 +204,16 @@ export class PrimitiveNode extends LGraphNode {
|
||||
const input = theirNode.inputs[link.target_slot]
|
||||
if (!input) return
|
||||
|
||||
let widget
|
||||
let widget: IWidgetLocatorWithConfig
|
||||
if (!input.widget) {
|
||||
if (!(input.type in ComfyWidgets)) return
|
||||
widget = { name: input.name, [GET_CONFIG]: () => [input.type, {}] } //fake widget
|
||||
if (typeof input.type !== 'string' || !(input.type in ComfyWidgets))
|
||||
return
|
||||
const inputType = input.type
|
||||
widget = { name: input.name, [GET_CONFIG]: () => [inputType, {}] }
|
||||
} else {
|
||||
widget = input.widget
|
||||
widget = input.widget as IWidgetLocatorWithConfig
|
||||
}
|
||||
|
||||
// @ts-expect-error fixme ts strict error
|
||||
const config = widget[GET_CONFIG]?.()
|
||||
if (!config) return
|
||||
|
||||
@@ -208,8 +227,7 @@ export class PrimitiveNode extends LGraphNode {
|
||||
widget[CONFIG] ?? config,
|
||||
theirNode,
|
||||
widget.name,
|
||||
// @ts-expect-error fixme ts strict error
|
||||
recreating
|
||||
recreating ?? false
|
||||
)
|
||||
}
|
||||
|
||||
@@ -227,12 +245,12 @@ export class PrimitiveNode extends LGraphNode {
|
||||
|
||||
// Store current size as addWidget resizes the node
|
||||
const [oldWidth, oldHeight] = this.size
|
||||
let widget: IBaseWidget
|
||||
let widget: IBaseWidget | undefined
|
||||
if (isValidWidgetType(type)) {
|
||||
widget = (ComfyWidgets[type](this, 'value', inputData, app) || {}).widget
|
||||
} else {
|
||||
// @ts-expect-error InputSpec is not typed correctly
|
||||
widget = this.addWidget(type, 'value', null, () => {}, {})
|
||||
// Unknown widget type - use 'custom' as fallback
|
||||
widget = this.addWidget('custom', 'value', type, () => {}, {})
|
||||
}
|
||||
|
||||
if (node?.widgets && widget) {
|
||||
@@ -474,7 +492,7 @@ export function mergeIfValid(
|
||||
output: INodeOutputSlot | INodeInputSlot,
|
||||
config2: InputSpec,
|
||||
forceUpdate?: boolean,
|
||||
recreateWidget?: () => void,
|
||||
recreateWidget?: () => IBaseWidget | undefined,
|
||||
config1?: InputSpec
|
||||
): { customConfig: InputSpec[1] } {
|
||||
if (!config1) {
|
||||
@@ -484,25 +502,20 @@ export function mergeIfValid(
|
||||
const customSpec = mergeInputSpec(config1, config2)
|
||||
|
||||
if (customSpec || forceUpdate) {
|
||||
if (customSpec) {
|
||||
// @ts-expect-error fixme ts strict error
|
||||
output.widget[CONFIG] = customSpec
|
||||
if (customSpec && output.widget) {
|
||||
const widgetLocator = output.widget as IWidgetLocatorWithConfig
|
||||
widgetLocator[CONFIG] = customSpec
|
||||
}
|
||||
|
||||
// @ts-expect-error fixme ts strict error
|
||||
const widget = recreateWidget?.call(this)
|
||||
// When deleting a node this can be null
|
||||
if (widget) {
|
||||
// @ts-expect-error fixme ts strict error
|
||||
const min = widget.options.min
|
||||
// @ts-expect-error fixme ts strict error
|
||||
const max = widget.options.max
|
||||
// @ts-expect-error fixme ts strict error
|
||||
if (min != null && widget.value < min) widget.value = min
|
||||
// @ts-expect-error fixme ts strict error
|
||||
if (max != null && widget.value > max) widget.value = max
|
||||
// @ts-expect-error fixme ts strict error
|
||||
widget.callback(widget.value)
|
||||
const widget = recreateWidget?.()
|
||||
if (widget?.type === 'number') {
|
||||
const numericWidget = widget as INumericWidget
|
||||
const { min, max } = numericWidget.options
|
||||
let currentValue = numericWidget.value ?? 0
|
||||
if (min != null && currentValue < min) currentValue = min
|
||||
if (max != null && currentValue > max) currentValue = max
|
||||
numericWidget.value = currentValue
|
||||
numericWidget.callback?.(currentValue)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -512,7 +525,6 @@ export function mergeIfValid(
|
||||
app.registerExtension({
|
||||
name: 'Comfy.WidgetInputs',
|
||||
async beforeRegisterNodeDef(nodeType, _nodeData, app) {
|
||||
// @ts-expect-error adding extra property
|
||||
nodeType.prototype.convertWidgetToInput = function (this: LGraphNode) {
|
||||
console.warn(
|
||||
'Please remove call to convertWidgetToInput. Widget to socket conversion is no longer necessary, as they co-exist now.'
|
||||
|
||||
@@ -23,9 +23,7 @@ const isImageFile = (file: File) => file.type.startsWith('image/')
|
||||
const isVideoFile = (file: File) => file.type.startsWith('video/')
|
||||
|
||||
const findFileComboWidget = (node: LGraphNode, inputName: string) =>
|
||||
node.widgets!.find((w) => w.name === inputName) as IComboWidget & {
|
||||
value: ExposedValue
|
||||
}
|
||||
node.widgets!.find((w) => w.name === inputName) as IComboWidget
|
||||
|
||||
export const useImageUploadWidget = () => {
|
||||
const widgetConstructor: ComfyWidgetConstructor = (
|
||||
@@ -80,10 +78,13 @@ export const useImageUploadWidget = () => {
|
||||
output.forEach((path) => addToComboValues(fileComboWidget, path))
|
||||
|
||||
// Create a NEW array to ensure Vue reactivity detects the change
|
||||
const newValue = allow_batch ? [...output] : output[0]
|
||||
|
||||
// @ts-expect-error litegraph combo value type does not support arrays yet
|
||||
fileComboWidget.value = newValue
|
||||
// Value property is redefined via Object.defineProperty to support batch uploads
|
||||
const newValue: ExposedValue = allow_batch ? [...output] : output[0]
|
||||
;(
|
||||
fileComboWidget as unknown as Omit<IComboWidget, 'value'> & {
|
||||
value: ExposedValue
|
||||
}
|
||||
).value = newValue
|
||||
fileComboWidget.callback?.(newValue)
|
||||
}
|
||||
})
|
||||
@@ -103,9 +104,9 @@ export const useImageUploadWidget = () => {
|
||||
|
||||
// Add our own callback to the combo widget to render an image when it changes
|
||||
fileComboWidget.callback = function () {
|
||||
nodeOutputStore.setNodeOutputs(node, fileComboWidget.value, {
|
||||
isAnimated
|
||||
})
|
||||
// Image upload widget value is always a string path, never a number
|
||||
const value = fileComboWidget.value as string | string[]
|
||||
nodeOutputStore.setNodeOutputs(node, value, { isAnimated })
|
||||
node.graph?.setDirtyCanvas(true)
|
||||
}
|
||||
|
||||
@@ -113,9 +114,8 @@ export const useImageUploadWidget = () => {
|
||||
// The value isn't set immediately so we need to wait a moment
|
||||
// No change callbacks seem to be fired on initial setting of the value
|
||||
requestAnimationFrame(() => {
|
||||
nodeOutputStore.setNodeOutputs(node, fileComboWidget.value, {
|
||||
isAnimated
|
||||
})
|
||||
const value = fileComboWidget.value as string | string[]
|
||||
nodeOutputStore.setNodeOutputs(node, value, { isAnimated })
|
||||
showPreview({ block: false })
|
||||
})
|
||||
|
||||
|
||||
@@ -3,9 +3,28 @@ import { type LGraphNode, isComboWidget } from '@/lib/litegraph/src/litegraph'
|
||||
import type {
|
||||
IBaseWidget,
|
||||
IComboWidget,
|
||||
INumericWidget,
|
||||
IStringWidget
|
||||
} from '@/lib/litegraph/src/types/widgets'
|
||||
import { useSettingStore } from '@/platform/settings/settingStore'
|
||||
|
||||
type ComboValuesType = IComboWidget['options']['values']
|
||||
|
||||
/**
|
||||
* Normalizes combo widget values to an array.
|
||||
* Handles the case where values may be a dictionary (Record<string, string>)
|
||||
* or a legacy function type.
|
||||
*/
|
||||
function getComboValuesArray(
|
||||
values: ComboValuesType | undefined,
|
||||
widget?: IComboWidget,
|
||||
node?: LGraphNode
|
||||
): string[] {
|
||||
if (!values) return []
|
||||
if (typeof values === 'function') return values(widget, node)
|
||||
if (Array.isArray(values)) return values
|
||||
return Object.keys(values)
|
||||
}
|
||||
import { dynamicWidgets } from '@/core/graph/widgets/dynamicWidgets'
|
||||
import { useBooleanWidget } from '@/renderer/extensions/vueNodes/widgets/composables/useBooleanWidget'
|
||||
import { useChartWidget } from '@/renderer/extensions/vueNodes/widgets/composables/useChartWidget'
|
||||
@@ -143,9 +162,11 @@ export function addValueControlWidgets(
|
||||
|
||||
const isCombo = isComboWidget(targetWidget)
|
||||
let comboFilter: IStringWidget
|
||||
if (isCombo && valueControl.options.values) {
|
||||
// @ts-expect-error Combo widget values may be a dictionary or legacy function type
|
||||
valueControl.options.values.push('increment-wrap')
|
||||
if (isCombo) {
|
||||
const controlValues = valueControl.options.values
|
||||
if (Array.isArray(controlValues)) {
|
||||
controlValues.push('increment-wrap')
|
||||
}
|
||||
}
|
||||
if (isCombo && options.addFilterList !== false) {
|
||||
comboFilter = node.addWidget(
|
||||
@@ -165,13 +186,18 @@ export function addValueControlWidgets(
|
||||
}
|
||||
|
||||
const applyWidgetControl = () => {
|
||||
var v = valueControl.value
|
||||
const v = valueControl.value
|
||||
|
||||
if (isCombo && v !== 'fixed') {
|
||||
let values = targetWidget.options.values ?? []
|
||||
const comboWidget = targetWidget as IComboWidget
|
||||
let values = getComboValuesArray(
|
||||
comboWidget.options.values,
|
||||
comboWidget,
|
||||
node
|
||||
)
|
||||
const filter = comboFilter?.value
|
||||
if (filter) {
|
||||
let check
|
||||
let check: ((item: string) => boolean) | undefined
|
||||
if (filter.startsWith('/') && filter.endsWith('/')) {
|
||||
try {
|
||||
const regex = new RegExp(filter.substring(1, filter.length - 1))
|
||||
@@ -188,18 +214,23 @@ export function addValueControlWidgets(
|
||||
const lower = filter.toLocaleLowerCase()
|
||||
check = (item: string) => item.toLocaleLowerCase().includes(lower)
|
||||
}
|
||||
// @ts-expect-error Combo widget values may be a dictionary or legacy function type
|
||||
values = values.filter((item: string) => check(item))
|
||||
if (!values.length && targetWidget.options.values?.length) {
|
||||
console.warn(
|
||||
'Filter for node ' + node.id + ' has filtered out all items',
|
||||
filter
|
||||
values = values.filter(check)
|
||||
if (!values.length && comboWidget.options.values) {
|
||||
const originalValues = getComboValuesArray(
|
||||
comboWidget.options.values,
|
||||
comboWidget,
|
||||
node
|
||||
)
|
||||
if (originalValues.length) {
|
||||
console.warn(
|
||||
'Filter for node ' + node.id + ' has filtered out all items',
|
||||
filter
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
// @ts-expect-error targetWidget.value can be number or string
|
||||
let current_index = values.indexOf(targetWidget.value)
|
||||
let current_length = values.length
|
||||
let current_index = values.indexOf(String(comboWidget.value))
|
||||
const current_length = values.length
|
||||
|
||||
switch (v) {
|
||||
case 'increment':
|
||||
@@ -215,54 +246,45 @@ export function addValueControlWidgets(
|
||||
current_index -= 1
|
||||
break
|
||||
case 'randomize':
|
||||
// @ts-expect-error Combo widget values may be a dictionary or legacy function type
|
||||
current_index = Math.floor(Math.random() * current_length)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
current_index = Math.max(0, current_index)
|
||||
// @ts-expect-error Combo widget values may be a dictionary or legacy function type
|
||||
current_index = Math.min(current_length - 1, current_index)
|
||||
if (current_index >= 0) {
|
||||
// @ts-expect-error Combo widget values may be a dictionary or legacy function type
|
||||
let value = values[current_index]
|
||||
targetWidget.value = value
|
||||
targetWidget.callback?.(value)
|
||||
const value = values[current_index]
|
||||
comboWidget.value = value
|
||||
comboWidget.callback?.(value)
|
||||
}
|
||||
} else {
|
||||
//number
|
||||
let { min = 0, max = 1, step2 = 1 } = targetWidget.options
|
||||
// limit to something that javascript can handle
|
||||
} else if (!isCombo) {
|
||||
const numericWidget = targetWidget as INumericWidget
|
||||
let currentValue = numericWidget.value ?? 0
|
||||
let { min = 0, max = 1, step2 = 1 } = numericWidget.options
|
||||
max = Math.min(1125899906842624, max)
|
||||
min = Math.max(-1125899906842624, min)
|
||||
let range = (max - min) / step2
|
||||
const range = (max - min) / step2
|
||||
|
||||
//adjust values based on valueControl Behaviour
|
||||
switch (v) {
|
||||
case 'fixed':
|
||||
break
|
||||
case 'increment':
|
||||
// @ts-expect-error targetWidget.value can be number or string
|
||||
targetWidget.value += step2
|
||||
currentValue += step2
|
||||
break
|
||||
case 'decrement':
|
||||
// @ts-expect-error targetWidget.value can be number or string
|
||||
targetWidget.value -= step2
|
||||
currentValue -= step2
|
||||
break
|
||||
case 'randomize':
|
||||
targetWidget.value = Math.floor(Math.random() * range) * step2 + min
|
||||
currentValue = Math.floor(Math.random() * range) * step2 + min
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
/*check if values are over or under their respective
|
||||
* ranges and set them to min or max.*/
|
||||
// @ts-expect-error targetWidget.value can be number or string
|
||||
if (targetWidget.value < min) targetWidget.value = min
|
||||
// @ts-expect-error targetWidget.value can be number or string
|
||||
if (targetWidget.value > max) targetWidget.value = max
|
||||
targetWidget.callback?.(targetWidget.value)
|
||||
if (currentValue < min) currentValue = min
|
||||
if (currentValue > max) currentValue = max
|
||||
numericWidget.value = currentValue
|
||||
numericWidget.callback?.(currentValue)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
5
src/types/litegraph-augmentation.d.ts
vendored
5
src/types/litegraph-augmentation.d.ts
vendored
@@ -113,6 +113,11 @@ declare module '@/lib/litegraph/src/litegraph' {
|
||||
): ExecutableLGraphNode[]
|
||||
/** @deprecated groupNode */
|
||||
convertToNodes?(): LGraphNode[]
|
||||
/**
|
||||
* @deprecated Widget to socket conversion is no longer necessary as they co-exist now.
|
||||
* This method is a no-op stub for backward compatibility with extensions.
|
||||
*/
|
||||
convertWidgetToInput?(): boolean
|
||||
recreate?(): Promise<LGraphNode | null>
|
||||
refreshComboInNode?(defs: Record<string, ComfyNodeDef>)
|
||||
/** @deprecated groupNode */
|
||||
|
||||
@@ -44,10 +44,9 @@ export function isAudioNode(node: LGraphNode | undefined): boolean {
|
||||
export function addToComboValues(widget: IComboWidget, value: string) {
|
||||
if (!widget.options) widget.options = { values: [] }
|
||||
if (!widget.options.values) widget.options.values = []
|
||||
// @ts-expect-error Combo widget values may be a dictionary or legacy function type
|
||||
if (!widget.options.values.includes(value)) {
|
||||
// @ts-expect-error Combo widget values may be a dictionary or legacy function type
|
||||
widget.options.values.push(value)
|
||||
const { values } = widget.options
|
||||
if (Array.isArray(values) && !values.includes(value)) {
|
||||
values.push(value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user