diff --git a/src/lib/litegraph/src/LGraphCanvas.ts b/src/lib/litegraph/src/LGraphCanvas.ts index dd2a78bb9..85187cdb3 100644 --- a/src/lib/litegraph/src/LGraphCanvas.ts +++ b/src/lib/litegraph/src/LGraphCanvas.ts @@ -2801,7 +2801,7 @@ export class LGraphCanvas // Widget const widget = node.getWidgetOnPos(x, y) if (widget) { - this.#processWidgetClick(e, node, widget) + this.processWidgetClick(e, node, widget) this.node_widget = [node, widget] } else { // Node background @@ -2981,13 +2981,12 @@ export class LGraphCanvas this.dirty_canvas = true } - #processWidgetClick( + processWidgetClick( e: CanvasPointerEvent, node: LGraphNode, - widget: IBaseWidget + widget: IBaseWidget, + pointer = this.pointer ) { - const { pointer } = this - // Custom widget - CanvasPointer if (typeof widget.onPointerDown === 'function') { const handled = widget.onPointerDown(pointer, node, this) diff --git a/src/lib/litegraph/src/types/widgets.ts b/src/lib/litegraph/src/types/widgets.ts index 02111acef..2d2ceb103 100644 --- a/src/lib/litegraph/src/types/widgets.ts +++ b/src/lib/litegraph/src/types/widgets.ts @@ -363,6 +363,14 @@ export interface IBaseWidget< lowQuality?: boolean ): void + /** + * Compatibility method for widgets implementing the draw + * method when displayed in non-canvas renderers. + * Set by the current renderer implementation. + * When called, performs a draw operation. + */ + triggerDraw?: () => void + /** * Compute the size of the widget. Overrides {@link IBaseWidget.computeSize}. * @param width The width of the widget. diff --git a/src/renderer/extensions/vueNodes/components/NodeWidgets.vue b/src/renderer/extensions/vueNodes/components/NodeWidgets.vue index 312c9300b..c36a232c7 100644 --- a/src/renderer/extensions/vueNodes/components/NodeWidgets.vue +++ b/src/renderer/extensions/vueNodes/components/NodeWidgets.vue @@ -24,7 +24,7 @@
+import { useResizeObserver } from '@vueuse/core' +import { onBeforeUnmount, onMounted, ref, watch } from 'vue' + +import { useChainCallback } from '@/composables/functional/useChainCallback' +import { CanvasPointer } from '@/lib/litegraph/src/CanvasPointer' +import type { LGraphCanvas } from '@/lib/litegraph/src/LGraphCanvas' +import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode' +import type { CanvasPointerEvent } from '@/lib/litegraph/src/types/events' +import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets' +import { useCanvasStore } from '@/renderer/core/canvas/canvasStore' +import { useColorPaletteStore } from '@/stores/workspace/colorPaletteStore' +import type { SimplifiedWidget } from '@/types/simplifiedWidget' + +const props = defineProps<{ + widget: SimplifiedWidget + readonly?: boolean +}>() + +const canvasEl = ref() + +const canvas: LGraphCanvas = useCanvasStore().canvas as LGraphCanvas +let node: LGraphNode | undefined +let widgetInstance: IBaseWidget | undefined +let pointer: CanvasPointer | undefined +const scaleFactor = 2 + +onMounted(() => { + node = + canvas?.graph?.getNodeById( + canvasEl.value.parentElement.attributes['node-id'].value + ) ?? undefined + if (!node) return + widgetInstance = node.widgets?.find((w) => w.name === props.widget.name) + if (!widgetInstance) return + canvasEl.value.width *= scaleFactor + if (!widgetInstance.triggerDraw) + widgetInstance.callback = useChainCallback( + widgetInstance.callback, + function (this: IBaseWidget) { + this?.triggerDraw?.() + } + ) + widgetInstance.triggerDraw = draw + useResizeObserver(canvasEl.value.parentElement, draw) + watch(() => useColorPaletteStore().activePaletteId, draw) + pointer = new CanvasPointer(canvasEl.value) +}) +onBeforeUnmount(() => { + if (widgetInstance) widgetInstance.triggerDraw = () => {} +}) + +function draw() { + if (!widgetInstance || !node) return + const width = canvasEl.value.parentElement.clientWidth + const height = widgetInstance.computeSize + ? widgetInstance.computeSize(width)[1] + : 20 + widgetInstance.y = 0 + canvasEl.value.height = (height + 2) * scaleFactor + canvasEl.value.width = width * scaleFactor + const ctx = canvasEl.value?.getContext('2d') + if (!ctx) return + ctx.scale(scaleFactor, scaleFactor) + widgetInstance.draw?.(ctx, node, width, 1, height) +} +function translateEvent(e: PointerEvent): asserts e is CanvasPointerEvent { + if (!node) return + canvas.adjustMouseEvent(e) + canvas.graph_mouse[0] = e.offsetX + node.pos[0] + canvas.graph_mouse[1] = e.offsetY + node.pos[1] +} +//See LGraphCanvas.processWidgetClick +function handleDown(e: PointerEvent) { + if (!node || !widgetInstance || !pointer) return + translateEvent(e) + pointer.down(e) + if (widgetInstance.mouse) + pointer.onDrag = (e) => + widgetInstance!.mouse?.(e, [e.offsetX, e.offsetY], node!) + //NOTE: a mouseUp event is already registed under pointer.finally + canvas.processWidgetClick(e, node, widgetInstance, pointer) +} +function handleUp(e: PointerEvent) { + if (!pointer) return + translateEvent(e) + e.click_time = e.timeStamp - (pointer?.eDown?.timeStamp ?? 0) + pointer.up(e) +} +function handleMove(e: PointerEvent) { + if (!pointer) return + translateEvent(e) + pointer.move(e) +} + + diff --git a/src/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.ts b/src/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.ts index 6cab2dbdd..7c48b1f1e 100644 --- a/src/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.ts +++ b/src/renderer/extensions/vueNodes/widgets/registry/widgetRegistry.ts @@ -14,6 +14,7 @@ import WidgetGalleria from '../components/WidgetGalleria.vue' import WidgetImageCompare from '../components/WidgetImageCompare.vue' import WidgetInputNumber from '../components/WidgetInputNumber.vue' import WidgetInputText from '../components/WidgetInputText.vue' +import WidgetLegacy from '../components/WidgetLegacy.vue' import WidgetMarkdown from '../components/WidgetMarkdown.vue' import WidgetMultiSelect from '../components/WidgetMultiSelect.vue' import WidgetRecordAudio from '../components/WidgetRecordAudio.vue' @@ -114,6 +115,7 @@ const coreWidgetDefinitions: Array<[string, WidgetDefinition]> = [ 'markdown', { component: WidgetMarkdown, aliases: ['MARKDOWN'], essential: false } ], + ['legacy', { component: WidgetLegacy, aliases: [], essential: true }], [ 'audiorecord', { @@ -161,19 +163,11 @@ export const getComponent = (type: string, name: string): Component | null => { return widgets.get(canonicalType)?.component || null } -const isSupported = (type: string): boolean => { - const canonicalType = getCanonicalType(type) - return widgets.has(canonicalType) -} - export const isEssential = (type: string): boolean => { const canonicalType = getCanonicalType(type) return widgets.get(canonicalType)?.essential || false } export const shouldRenderAsVue = (widget: Partial): boolean => { - if (widget.options?.canvasOnly) return false - if (widget.isDOMWidget) return true - if (!widget.type) return false - return isSupported(widget.type) + return !widget.options?.canvasOnly && !!widget.type } diff --git a/tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useWidgetRenderer.test.ts b/tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useWidgetRenderer.test.ts index 773ed8364..7c1d2dd5d 100644 --- a/tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useWidgetRenderer.test.ts +++ b/tests-ui/tests/renderer/extensions/vueNodes/widgets/composables/useWidgetRenderer.test.ts @@ -123,10 +123,6 @@ describe('widgetRegistry', () => { expect(shouldRenderAsVue({ type: 'combo' })).toBe(true) }) - it('should return false for unknown types', () => { - expect(shouldRenderAsVue({ type: 'unknown_type' })).toBe(false) - }) - it('should respect options while checking type', () => { const widget = { type: 'text', options: { someOption: 'value' } } expect(shouldRenderAsVue(widget)).toBe(true)