feat: support disabled state and upstream value display for curve widget

This commit is contained in:
Terry Jia
2026-03-03 20:20:31 -05:00
parent fe8ab1d896
commit 6816fae86c
3 changed files with 108 additions and 17 deletions

View File

@@ -3,8 +3,13 @@
ref="svgRef"
viewBox="-0.04 -0.04 1.08 1.08"
preserveAspectRatio="xMidYMid meet"
class="aspect-square w-full cursor-crosshair rounded-[5px] bg-node-component-surface"
@pointerdown.stop="handleSvgPointerDown"
:class="
cn(
'aspect-square w-full rounded-[5px] bg-node-component-surface',
disabled ? 'cursor-default' : 'cursor-crosshair'
)
"
@pointerdown.stop="onSvgPointerDown"
@contextmenu.prevent.stop
>
<line
@@ -56,20 +61,23 @@
:stroke="curveColor"
stroke-width="0.008"
stroke-linecap="round"
:opacity="disabled ? 0.5 : 1"
/>
<circle
v-for="(point, i) in modelValue"
:key="i"
:cx="point[0]"
:cy="1 - point[1]"
r="0.02"
:fill="curveColor"
stroke="white"
stroke-width="0.004"
class="cursor-grab"
@pointerdown.stop="startDrag(i, $event)"
/>
<template v-if="!disabled">
<circle
v-for="(point, i) in modelValue"
:key="i"
:cx="point[0]"
:cy="1 - point[1]"
r="0.02"
:fill="curveColor"
stroke="white"
stroke-width="0.004"
class="cursor-grab"
@pointerdown.stop="startDrag(i, $event)"
/>
</template>
</svg>
</template>
@@ -77,14 +85,20 @@
import { computed, useTemplateRef } from 'vue'
import { useCurveEditor } from '@/composables/useCurveEditor'
import { cn } from '@/utils/tailwindUtil'
import type { CurvePoint } from './types'
import { histogramToPath } from './curveUtils'
const { curveColor = 'white', histogram } = defineProps<{
const {
curveColor = 'white',
histogram,
disabled = false
} = defineProps<{
curveColor?: string
histogram?: Uint32Array | null
disabled?: boolean
}>()
const modelValue = defineModel<CurvePoint[]>({
@@ -98,6 +112,10 @@ const { curvePath, handleSvgPointerDown, startDrag } = useCurveEditor({
modelValue
})
function onSvgPointerDown(e: PointerEvent) {
if (!disabled) handleSvgPointerDown(e)
}
const histogramPath = computed(() =>
histogram ? histogramToPath(histogram) : ''
)

View File

@@ -1,11 +1,24 @@
<template>
<CurveEditor v-model="modelValue" />
<CurveEditor
:model-value="effectivePoints"
:disabled="isDisabled"
@update:model-value="modelValue = $event"
/>
</template>
<script setup lang="ts">
import type { CurvePoint } from './types'
import { computed } from 'vue'
import { useLinkedWidgetValue } from '@/composables/useLinkedWidgetValue'
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
import CurveEditor from './CurveEditor.vue'
import type { CurvePoint } from './types'
const { widget, nodeId } = defineProps<{
widget: SimplifiedWidget
nodeId: string
}>()
const modelValue = defineModel<CurvePoint[]>({
default: () => [
@@ -13,4 +26,14 @@ const modelValue = defineModel<CurvePoint[]>({
[1, 1]
]
})
const isDisabled = computed(() => !!widget.options?.disabled)
const upstreamValue = useLinkedWidgetValue(nodeId, widget.name, 'curve')
const effectivePoints = computed(() =>
isDisabled.value && upstreamValue.value
? (upstreamValue.value as CurvePoint[])
: modelValue.value
)
</script>

View File

@@ -0,0 +1,50 @@
import type { ComputedRef } from 'vue'
import { computed } from 'vue'
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
import { useWidgetValueStore } from '@/stores/widgetValueStore'
/**
* Returns the upstream widget value for a connected input slot.
* Matches by output slot name first, then falls back to widget type.
*/
export function useLinkedWidgetValue(
nodeId: string,
widgetName: string,
widgetType: string
): ComputedRef<unknown | undefined> {
const canvasStore = useCanvasStore()
const widgetValueStore = useWidgetValueStore()
return computed(() => {
const graph = canvasStore.canvas?.graph
if (!graph) return undefined
const node = graph.getNodeById(nodeId)
if (!node?.inputs) return undefined
const slot = node.inputs.find((s) => s.name === widgetName)
if (!slot?.link) return undefined
const link = graph.getLink(slot.link)
if (!link) return undefined
const graphId = graph.rootGraph.id
const originNode = graph.getNodeById(link.origin_id)
const outputName = originNode?.outputs?.[link.origin_slot]?.name
const upstreamWidgets = widgetValueStore.getNodeWidgets(
graphId,
link.origin_id
)
const matched = outputName
? upstreamWidgets.find((w) => w.name === outputName)
: undefined
if (matched) return matched.value
const typeMatches = upstreamWidgets.filter((w) => w.type === widgetType)
return typeMatches.length === 1 ? typeMatches[0].value : undefined
})
}