Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion src/composables/graph/useGraphNodeManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import type {
} from '@/lib/litegraph/src/litegraph'
import type { TitleMode } from '@/lib/litegraph/src/types/globalEnums'
import { NodeSlotType } from '@/lib/litegraph/src/types/globalEnums'
import { app } from '@/scripts/app'

export interface WidgetSlotMetadata {
index: number
Expand All @@ -47,6 +48,7 @@ export interface SafeWidgetData {
borderStyle?: string
callback?: ((value: unknown) => void) | undefined
controlWidget?: SafeControlWidget
hasLayoutSize?: boolean
isDOMWidget?: boolean
label?: string
nodeType?: string
Expand Down Expand Up @@ -171,7 +173,12 @@ export function safeWidgetMapper(
const callback = (v: unknown) => {
const value = normalizeWidgetValue(v)
widget.value = value ?? undefined
widget.callback?.(value)
// Match litegraph callback signature: (value, canvas, node, pos, event)
// Some extensions (e.g., Impact Pack) expect node as the 3rd parameter
widget.callback?.(value, app.canvas, node)
// Trigger redraw for all legacy widgets on this node (e.g., mask preview)
// This ensures widgets that depend on other widget values get updated
node.widgets?.forEach((w) => w.triggerDraw?.())
Comment on lines +179 to +181
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this line ever actually make a difference?

This callback is exclusively used on the vue side when @update:modelValue is emitted, but WidgetLegacy never emits (or defines a model) because all the values are tracked on the litegraph side.

}

return {
Expand All @@ -181,6 +188,7 @@ export function safeWidgetMapper(
borderStyle,
callback,
controlWidget: getControlWidget(widget),
hasLayoutSize: typeof widget.computeLayoutSize === 'function',
isDOMWidget: isDOMWidget(widget),
label: widget.label,
nodeType: getNodeType(node, widget),
Expand Down
11 changes: 7 additions & 4 deletions src/renderer/extensions/vueNodes/components/NodeWidgets.vue
Original file line number Diff line number Diff line change
Expand Up @@ -203,10 +203,13 @@ const processedWidgets = computed((): ProcessedWidget[] => {
})

const gridTemplateRows = computed((): string => {
const widgets = toValue(processedWidgets)
return widgets
.filter((w) => !w.simplified.options?.hidden)
.map((w) => (shouldExpand(w.type) ? 'auto' : 'min-content'))
if (!nodeData?.widgets) return ''
const processedNames = new Set(toValue(processedWidgets).map((w) => w.name))
return nodeData.widgets
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic should be order dependent. You should be able to test it with a subgraph that contains multiple of the same type of node with the same widget promoted.

.filter((w) => processedNames.has(w.name) && !w.options?.hidden)
.map((w) =>
shouldExpand(w.type) || w.hasLayoutSize ? 'auto' : 'min-content'
)
.join(' ')
})
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,17 @@ const precision = computed(() => {

// Calculate the step value based on precision or widget options
const stepValue = computed(() => {
// Use step2 (correct input spec value) instead of step (legacy 10x value)
// Use step2 (correct input spec value) if available
if (props.widget.options?.step2 !== undefined) {
return Number(props.widget.options.step2)
}
// Use step / 10 for custom large step values (> 10) to match litegraph behavior
// This is important for extensions like Impact Pack that use custom step values (e.g., 640)
// We skip default step values (1, 10) to avoid affecting normal widgets
const step = props.widget.options?.step
if (step !== undefined && step > 10) {
return Number(step) / 10
}
// Otherwise, derive from precision
if (precision.value !== undefined) {
if (precision.value === 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const props = defineProps<{
}>()

const canvasEl = ref()
const containerHeight = ref(20)

const canvas: LGraphCanvas = useCanvasStore().canvas as LGraphCanvas
let node: LGraphNode | undefined
Expand Down Expand Up @@ -52,9 +53,19 @@ onBeforeUnmount(() => {
function draw() {
if (!widgetInstance || !node) return
const width = canvasEl.value.parentElement.clientWidth
const height = widgetInstance.computeSize
? widgetInstance.computeSize(width)[1]
: 20
// Priority: computedHeight (from litegraph) > computeLayoutSize > computeSize
let height = 20
if (widgetInstance.computedHeight) {
height = widgetInstance.computedHeight
} else if (widgetInstance.computeLayoutSize) {
height = widgetInstance.computeLayoutSize(node).minHeight
} else if (widgetInstance.computeSize) {
height = widgetInstance.computeSize(width)[1]
}
containerHeight.value = height
// Set node.canvasHeight for legacy widgets that use it (e.g., Impact Pack)
// @ts-expect-error canvasHeight is a custom property used by some extensions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you augment the type instead of adding a suppression?

node.canvasHeight = height
widgetInstance.y = 0
canvasEl.value.height = (height + 2) * scaleFactor
canvasEl.value.width = width * scaleFactor
Expand Down Expand Up @@ -87,7 +98,10 @@ function handleMove(e: PointerEvent) {
}
</script>
<template>
<div class="relative mx-[-12px] min-w-0 basis-0">
<div
class="relative mx-[-12px] min-w-0 basis-0"
:style="{ minHeight: `${containerHeight}px` }"
>
<canvas
ref="canvasEl"
class="absolute mt-[-13px] w-full cursor-crosshair"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { computed, toValue } from 'vue'
import type { MaybeRefOrGetter } from 'vue'

interface NumberWidgetOptions {
step?: number
step2?: number
precision?: number
}
Expand All @@ -17,10 +18,17 @@ export function useNumberStepCalculation(
) {
return computed(() => {
const precision = toValue(precisionArg)
// Use step2 (correct input spec value) instead of step (legacy 10x value)
// Use step2 (correct input spec value) if available
if (options?.step2 !== undefined) {
return Number(options.step2)
}
// Use step / 10 for custom large step values (> 10) to match litegraph behavior
// This is important for extensions like Impact Pack that use custom step values (e.g., 640)
// We skip default step values (1, 10) to avoid affecting normal widgets
const step = options?.step
if (step !== undefined && step > 10) {
return Number(step) / 10
}

if (precision === undefined) {
return returnUndefinedForDefault ? undefined : 0
Expand All @@ -29,7 +37,9 @@ export function useNumberStepCalculation(
if (precision === 0) return 1

// For precision > 0, step = 1 / (10^precision)
const step = 1 / Math.pow(10, precision)
return returnUndefinedForDefault ? step : Number(step.toFixed(precision))
const calculatedStep = 1 / Math.pow(10, precision)
return returnUndefinedForDefault
? calculatedStep
: Number(calculatedStep.toFixed(precision))
})
}
Loading