From 78cbfd2a7aad87d7443644529ead7d2bb80ceb70 Mon Sep 17 00:00:00 2001 From: DrJKL Date: Tue, 30 Sep 2025 16:11:00 -0700 Subject: [PATCH] fix: DO NOT MERGE: Try to fix the types, behavior is not correct --- src/lib/litegraph/src/DragAndScale.ts | 2 +- src/lib/litegraph/src/LGraphCanvas.ts | 51 ++++++--- src/lib/litegraph/src/interfaces.ts | 2 +- .../canvas/links/slotLinkPreviewRenderer.ts | 106 ++++++++++-------- .../canvas/litegraph/litegraphLinkAdapter.ts | 4 +- src/renderer/core/canvas/pathRenderer.ts | 3 +- .../vueNodes/components/LGraphNodePreview.vue | 8 +- .../vueNodes/components/NodeSlots.test.ts | 11 +- .../vueNodes/components/NodeSlots.vue | 36 +++--- .../vueNodes/components/NodeWidgets.vue | 5 +- 10 files changed, 130 insertions(+), 98 deletions(-) diff --git a/src/lib/litegraph/src/DragAndScale.ts b/src/lib/litegraph/src/DragAndScale.ts index 4d921ba78..0c58d2a36 100644 --- a/src/lib/litegraph/src/DragAndScale.ts +++ b/src/lib/litegraph/src/DragAndScale.ts @@ -220,7 +220,7 @@ export class DragAndScale { * @param bounds The bounds to animate the view to, defined by a rectangle. */ animateToBounds( - bounds: Rect | Rectangle, + bounds: Readonly, setDirty: () => void, { duration = 350, diff --git a/src/lib/litegraph/src/LGraphCanvas.ts b/src/lib/litegraph/src/LGraphCanvas.ts index 1eb76f386..4167aed73 100644 --- a/src/lib/litegraph/src/LGraphCanvas.ts +++ b/src/lib/litegraph/src/LGraphCanvas.ts @@ -4733,32 +4733,47 @@ export class LGraphCanvas for (const renderLink of renderLinks) { const { fromSlot, - fromPos: pos, - fromDirection, - dragDirection + fromPos: pos + // fromDirection, + // dragDirection } = renderLink const connShape = fromSlot.shape const connType = fromSlot.type - const colour = resolveConnectingLinkColor(connType) + const color = resolveConnectingLinkColor(connType) // the connection being dragged by the mouse - if (this.linkRenderer) { - this.linkRenderer.renderDraggingLink( - ctx, - pos, - highlightPos, - colour, - fromDirection, - dragDirection, - { - ...this.buildLinkRenderContext(), - linkMarkerShape: LinkMarkerShape.None - } - ) + if ( + this.linkRenderer && + renderLink.fromSlotIndex !== undefined && + renderLink.node !== undefined + ) { + const { fromSlotIndex, node } = renderLink + if ( + node instanceof LGraphNode && + ('link' in fromSlot || 'links' in fromSlot) + ) { + this.linkRenderer.renderDraggingLink( + ctx, + node, + fromSlot, + fromSlotIndex, + highlightPos, + this.buildLinkRenderContext(), + { fromInput: 'link' in fromSlot, color } + // pos, + // colour, + // fromDirection, + // dragDirection, + // { + // ...this.buildLinkRenderContext(), + // linkMarkerShape: LinkMarkerShape.None + // } + ) + } } - ctx.fillStyle = colour + ctx.fillStyle = color ctx.beginPath() if (connType === LiteGraph.EVENT || connShape === RenderShape.BOX) { ctx.rect(pos[0] - 6 + 0.5, pos[1] - 5 + 0.5, 14, 10) diff --git a/src/lib/litegraph/src/interfaces.ts b/src/lib/litegraph/src/interfaces.ts index b5703f67e..8f45804f8 100644 --- a/src/lib/litegraph/src/interfaces.ts +++ b/src/lib/litegraph/src/interfaces.ts @@ -1,4 +1,4 @@ -import { Rectangle } from '@/lib/litegraph/src/infrastructure/Rectangle' +import type { Rectangle } from '@/lib/litegraph/src/infrastructure/Rectangle' import type { CanvasPointerEvent } from '@/lib/litegraph/src/types/events' import type { ContextMenu } from './ContextMenu' diff --git a/src/renderer/core/canvas/links/slotLinkPreviewRenderer.ts b/src/renderer/core/canvas/links/slotLinkPreviewRenderer.ts index 281c9b42b..bfe682dea 100644 --- a/src/renderer/core/canvas/links/slotLinkPreviewRenderer.ts +++ b/src/renderer/core/canvas/links/slotLinkPreviewRenderer.ts @@ -1,13 +1,15 @@ import type { LGraphCanvas } from '@/lib/litegraph/src/LGraphCanvas' -import type { RenderLink } from '@/lib/litegraph/src/canvas/RenderLink' -import type { ReadOnlyPoint } from '@/lib/litegraph/src/interfaces' -import { LinkDirection } from '@/lib/litegraph/src/types/globalEnums' +import { LGraphNode } from '@/lib/litegraph/src/LGraphNode' +// import type { RenderLink } from '@/lib/litegraph/src/canvas/RenderLink' +import type { Point } from '@/lib/litegraph/src/interfaces' +// import { LinkDirection } from '@/lib/litegraph/src/types/globalEnums' import { resolveConnectingLinkColor } from '@/lib/litegraph/src/utils/linkColors' import { createLinkConnectorAdapter } from '@/renderer/core/canvas/links/linkConnectorAdapter' import { useSlotLinkDragState } from '@/renderer/core/canvas/links/slotLinkDragState' import type { LinkRenderContext } from '@/renderer/core/canvas/litegraph/litegraphLinkAdapter' -import { getSlotKey } from '@/renderer/core/layout/slots/slotIdentifier' -import { layoutStore } from '@/renderer/core/layout/store/layoutStore' + +// import { getSlotKey } from '@/renderer/core/layout/slots/slotIdentifier' +// import { layoutStore } from '@/renderer/core/layout/store/layoutStore' function buildContext(canvas: LGraphCanvas): LinkRenderContext { return { @@ -49,24 +51,32 @@ export function attachSlotLinkPreviewRenderer(canvas: LGraphCanvas) { const renderLinks = createLinkConnectorAdapter()?.renderLinks if (!renderLinks || renderLinks.length === 0) return - const to: ReadOnlyPoint = [pointer.canvas.x, pointer.canvas.y] + const to: Point = [pointer.canvas.x, pointer.canvas.y] ctx.save() for (const link of renderLinks) { - const startDir = link.fromDirection ?? LinkDirection.RIGHT - const endDir = link.dragDirection ?? LinkDirection.CENTER - const colour = resolveConnectingLinkColor(link.fromSlot.type) + // const startDir = link.fromDirection ?? LinkDirection.RIGHT + // const endDir = link.dragDirection ?? LinkDirection.CENTER + const color = resolveConnectingLinkColor(link.fromSlot.type) - const fromPoint = resolveRenderLinkOrigin(link) - - linkRenderer.renderDraggingLink( - ctx, - fromPoint, - to, - colour, - startDir, - endDir, - context - ) + // const fromPoint = resolveRenderLinkOrigin(link) + const { node, fromSlot, fromSlotIndex } = link + if (node instanceof LGraphNode && 'link' in fromSlot) { + linkRenderer.renderDraggingLink( + ctx, + node, + fromSlot, + fromSlotIndex, + to, + context, + { + color + } + // colour, + // startDir, + // endDir, + // context + ) + } } ctx.restore() } @@ -74,35 +84,35 @@ export function attachSlotLinkPreviewRenderer(canvas: LGraphCanvas) { canvas.onDrawForeground = patched } -function resolveRenderLinkOrigin(link: RenderLink): ReadOnlyPoint { - if (link.fromReroute) { - const rerouteLayout = layoutStore.getRerouteLayout(link.fromReroute.id) - if (rerouteLayout) { - return [rerouteLayout.position.x, rerouteLayout.position.y] - } +// function resolveRenderLinkOrigin(link: RenderLink): Point { +// if (link.fromReroute) { +// const rerouteLayout = layoutStore.getRerouteLayout(link.fromReroute.id) +// if (rerouteLayout) { +// return [rerouteLayout.position.x, rerouteLayout.position.y] +// } - const [x, y] = link.fromReroute.pos - return [x, y] - } +// const [x, y] = link.fromReroute.pos +// return [x, y] +// } - const nodeId = getRenderLinkNodeId(link) - if (nodeId != null) { - const isInputFrom = link.toType === 'output' - const key = getSlotKey(String(nodeId), link.fromSlotIndex, isInputFrom) - const layout = layoutStore.getSlotLayout(key) - if (layout) { - return [layout.position.x, layout.position.y] - } - } +// const nodeId = getRenderLinkNodeId(link) +// if (nodeId != null) { +// const isInputFrom = link.toType === 'output' +// const key = getSlotKey(String(nodeId), link.fromSlotIndex, isInputFrom) +// const layout = layoutStore.getSlotLayout(key) +// if (layout) { +// return [layout.position.x, layout.position.y] +// } +// } - return link.fromPos -} +// return link.fromPos +// } -function getRenderLinkNodeId(link: RenderLink): number | null { - const node = link.node - if (typeof node === 'object' && node !== null && 'id' in node) { - const maybeId = node.id - if (typeof maybeId === 'number') return maybeId - } - return null -} +// function getRenderLinkNodeId(link: RenderLink): number | null { +// const node = link.node +// if (typeof node === 'object' && node !== null && 'id' in node) { +// const maybeId = node.id +// if (typeof maybeId === 'number') return maybeId +// } +// return null +// } diff --git a/src/renderer/core/canvas/litegraph/litegraphLinkAdapter.ts b/src/renderer/core/canvas/litegraph/litegraphLinkAdapter.ts index a6189eda9..7494be19c 100644 --- a/src/renderer/core/canvas/litegraph/litegraphLinkAdapter.ts +++ b/src/renderer/core/canvas/litegraph/litegraphLinkAdapter.ts @@ -7,7 +7,7 @@ * Maintains backward compatibility with existing litegraph integration. */ import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode' -import { LLink } from '@/lib/litegraph/src/LLink' +import type { LLink } from '@/lib/litegraph/src/LLink' import type { Reroute } from '@/lib/litegraph/src/Reroute' import type { CanvasColour, @@ -21,6 +21,7 @@ import { LinkMarkerShape, LinkRenderType } from '@/lib/litegraph/src/types/globalEnums' +import { getSlotPosition } from '@/renderer/core/canvas/litegraph/slotCalculations' import { type ArrowShape, CanvasPathRenderer, @@ -411,7 +412,6 @@ export class LitegraphLinkAdapter { const slotDir = fromSlot.dir || (options.fromInput ? LinkDirection.LEFT : LinkDirection.RIGHT) - // Create drag data const dragData: DragLinkData = { fixedPoint: { x: slotPos[0], y: slotPos[1] }, diff --git a/src/renderer/core/canvas/pathRenderer.ts b/src/renderer/core/canvas/pathRenderer.ts index 126b98e00..421ac5117 100644 --- a/src/renderer/core/canvas/pathRenderer.ts +++ b/src/renderer/core/canvas/pathRenderer.ts @@ -70,7 +70,7 @@ export interface RenderContext { highlightedIds?: Set } -interface DragLinkData { +export interface DragLinkData { /** Fixed end - the slot being dragged from */ fixedPoint: Point fixedDirection: Direction @@ -605,6 +605,7 @@ export class CanvasPathRenderer { type: dragData.type, disabled: dragData.disabled } + console.log({ linkData }) // Use standard link drawing return this.drawLink(ctx, linkData, context) diff --git a/src/renderer/extensions/vueNodes/components/LGraphNodePreview.vue b/src/renderer/extensions/vueNodes/components/LGraphNodePreview.vue index a6513f039..8bc3f23cc 100644 --- a/src/renderer/extensions/vueNodes/components/LGraphNodePreview.vue +++ b/src/renderer/extensions/vueNodes/components/LGraphNodePreview.vue @@ -42,7 +42,7 @@ import type { INodeInputSlot, INodeOutputSlot } from '@/lib/litegraph/src/interfaces' -import { RenderShape } from '@/lib/litegraph/src/litegraph' +import { Rectangle, RenderShape } from '@/lib/litegraph/src/litegraph' import NodeContent from '@/renderer/extensions/vueNodes/components/NodeContent.vue' import NodeHeader from '@/renderer/extensions/vueNodes/components/NodeHeader.vue' import NodeSlots from '@/renderer/extensions/vueNodes/components/NodeSlots.vue' @@ -85,7 +85,7 @@ const nodeData = computed(() => { name, type: input.type, shape: input.isOptional ? RenderShape.HollowCircle : undefined, - boundingRect: [0, 0, 0, 0], + boundingRect: new Rectangle(0, 0, 0, 0), link: null })) @@ -94,13 +94,13 @@ const nodeData = computed(() => { return { name: output, type: output, - boundingRect: [0, 0, 0, 0], + boundingRect: new Rectangle(0, 0, 0, 0), links: [] } } return { ...output, - boundingRect: [0, 0, 0, 0], + boundingRect: new Rectangle(0, 0, 0, 0), links: [] } }) diff --git a/src/renderer/extensions/vueNodes/components/NodeSlots.test.ts b/src/renderer/extensions/vueNodes/components/NodeSlots.test.ts index ed8bb8ed2..036298bd3 100644 --- a/src/renderer/extensions/vueNodes/components/NodeSlots.test.ts +++ b/src/renderer/extensions/vueNodes/components/NodeSlots.test.ts @@ -7,6 +7,7 @@ import { createI18n } from 'vue-i18n' import type { VueNodeData } from '@/composables/graph/useGraphNodeManager' import type { INodeOutputSlot } from '@/lib/litegraph/src/interfaces' import type { INodeInputSlot } from '@/lib/litegraph/src/interfaces' +import { Rectangle } from '@/lib/litegraph/src/litegraph' import enMessages from '@/locales/en/main.json' with { type: 'json' } import NodeSlots from './NodeSlots.vue' @@ -29,7 +30,7 @@ const makeNodeData = (overrides: Partial = {}): VueNodeData => ({ interface StubSlotData { name?: string type?: string - boundingRect?: [number, number, number, number] + boundingRect?: Rectangle } const InputSlotStub = defineComponent({ @@ -96,13 +97,13 @@ describe('NodeSlots.vue', () => { const inputObjNoWidget = { name: 'objNoWidget', type: 'number', - boundingRect: new Float32Array([0, 0, 0, 0]), + boundingRect: new Rectangle(0, 0, 0, 0), link: null } const inputObjWithWidget = { name: 'objWithWidget', type: 'number', - boundingRect: new Float32Array([0, 0, 0, 0]), + boundingRect: new Rectangle(0, 0, 0, 0), widget: { name: 'objWithWidget' }, link: null } @@ -150,13 +151,13 @@ describe('NodeSlots.vue', () => { const outputObj = { name: 'outA', type: 'any', - boundingRect: new Float32Array([0, 0, 0, 0]), + boundingRect: new Rectangle(0, 0, 0, 0), links: [] } const outputObjB = { name: 'outB', type: 'any', - boundingRect: new Float32Array([0, 0, 0, 0]), + boundingRect: new Rectangle(0, 0, 0, 0), links: [] } const outputs: INodeOutputSlot[] = [outputObj, outputObjB] diff --git a/src/renderer/extensions/vueNodes/components/NodeSlots.vue b/src/renderer/extensions/vueNodes/components/NodeSlots.vue index 26187899d..41bb83937 100644 --- a/src/renderer/extensions/vueNodes/components/NodeSlots.vue +++ b/src/renderer/extensions/vueNodes/components/NodeSlots.vue @@ -34,7 +34,7 @@ import { computed, onErrorCaptured, ref } from 'vue' import type { VueNodeData } from '@/composables/graph/useGraphNodeManager' import { useErrorHandling } from '@/composables/useErrorHandling' -import type { INodeSlot } from '@/lib/litegraph/src/litegraph' +import { type INodeSlot, Rectangle } from '@/lib/litegraph/src/litegraph' import { isSlotObject } from '@/utils/typeGuardUtil' import InputSlot from './InputSlot.vue' @@ -60,28 +60,30 @@ const filteredInputs = computed(() => { } return true }) - .map((input) => - isSlotObject(input) - ? input - : ({ - name: typeof input === 'string' ? input : '', - type: 'any', - boundingRect: [0, 0, 0, 0] as [number, number, number, number] - } as INodeSlot) + .map( + (input): INodeSlot => + isSlotObject(input) + ? input + : { + name: typeof input === 'string' ? input : '', + type: 'any', + boundingRect: new Rectangle(0, 0, 0, 0) + } ) }) // Outputs don't have widgets, so we don't need to filter them const filteredOutputs = computed(() => { const outputs = nodeData?.outputs || [] - return outputs.map((output) => - isSlotObject(output) - ? output - : ({ - name: typeof output === 'string' ? output : '', - type: 'any', - boundingRect: [0, 0, 0, 0] as [number, number, number, number] - } as INodeSlot) + return outputs.map( + (output): INodeSlot => + isSlotObject(output) + ? output + : { + name: typeof output === 'string' ? output : '', + type: 'any', + boundingRect: new Rectangle(0, 0, 0, 0) + } ) }) diff --git a/src/renderer/extensions/vueNodes/components/NodeWidgets.vue b/src/renderer/extensions/vueNodes/components/NodeWidgets.vue index 59f4fe3bf..7b4ead7b6 100644 --- a/src/renderer/extensions/vueNodes/components/NodeWidgets.vue +++ b/src/renderer/extensions/vueNodes/components/NodeWidgets.vue @@ -30,7 +30,7 @@ :slot-data="{ name: widget.name, type: widget.type, - boundingRect: [0, 0, 0, 0] + boundingRect }" :node-id="nodeData?.id != null ? String(nodeData.id) : ''" :index="getWidgetInputIndex(widget)" @@ -60,6 +60,7 @@ import type { VueNodeData } from '@/composables/graph/useGraphNodeManager' import { useErrorHandling } from '@/composables/useErrorHandling' +import { Rectangle } from '@/lib/litegraph/src/litegraph' import { useCanvasInteractions } from '@/renderer/core/canvas/useCanvasInteractions' import { useNodeTooltips } from '@/renderer/extensions/vueNodes/composables/useNodeTooltips' // Import widget components directly @@ -164,6 +165,8 @@ const processedWidgets = computed((): ProcessedWidget[] => { return result }) +const boundingRect = new Rectangle(0, 0, 0, 0) + // TODO: Refactor to avoid O(n) lookup - consider storing input index on widget creation // or restructuring data model to unify widgets and inputs // Map a widget to its corresponding input slot index