Skip to content
Draft
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
8 changes: 8 additions & 0 deletions src/lib/litegraph/src/LGraphCanvas.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { toString } from 'es-toolkit/compat'

import { PREFIX, SEPARATOR } from '@/constants/groupNodeConstants'
import { MovingInputLink } from '@/lib/litegraph/src/canvas/MovingInputLink'
import { LitegraphLinkAdapter } from '@/renderer/core/canvas/litegraph/litegraphLinkAdapter'
import type { LinkRenderContext } from '@/renderer/core/canvas/litegraph/litegraphLinkAdapter'
import { getSlotPosition } from '@/renderer/core/canvas/litegraph/slotCalculations'
Expand Down Expand Up @@ -4769,6 +4770,7 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
}
)
}
if (renderLink instanceof MovingInputLink) this.setDirty(false, true)

ctx.fillStyle = colour
ctx.beginPath()
Expand Down Expand Up @@ -5699,6 +5701,12 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
// Never draw slots when the pointer is down
if (!this.pointer.isDown) reroute.drawSlots(ctx)
}

const highlightPos = this.#getHighlightPosition()
this.linkConnector.renderLinks
.filter((rl) => rl instanceof MovingInputLink)
.forEach((rl) => rl.drawConnectionCircle(ctx, highlightPos))

ctx.globalAlpha = 1
}

Expand Down
24 changes: 21 additions & 3 deletions src/lib/litegraph/src/canvas/LinkConnector.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { remove } from 'es-toolkit'

import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'
import { LLink } from '@/lib/litegraph/src/LLink'
import type { Reroute } from '@/lib/litegraph/src/Reroute'
Expand All @@ -13,7 +15,8 @@ import type {
INodeOutputSlot,
ItemLocator,
LinkNetwork,
LinkSegment
LinkSegment,
Point
} from '@/lib/litegraph/src/interfaces'
import { EmptySubgraphInput } from '@/lib/litegraph/src/subgraph/EmptySubgraphInput'
import { EmptySubgraphOutput } from '@/lib/litegraph/src/subgraph/EmptySubgraphOutput'
Expand Down Expand Up @@ -130,7 +133,11 @@ export class LinkConnector {
}

/** Drag an existing link to a different input. */
moveInputLink(network: LinkNetwork, input: INodeInputSlot): void {
moveInputLink(
network: LinkNetwork,
input: INodeInputSlot,
opts?: { startPoint?: Point }
): void {
if (this.isConnecting) throw new Error('Already dragging links.')

const { state, inputLinks, renderLinks } = this
Expand Down Expand Up @@ -221,7 +228,13 @@ export class LinkConnector {
// Regular node links
try {
const reroute = network.getReroute(link.parentId)
const renderLink = new MovingInputLink(network, link, reroute)
const renderLink = new MovingInputLink(
network,
link,
reroute,
undefined,
opts?.startPoint
)

const mayContinue = this.events.dispatch(
'before-move-input',
Expand Down Expand Up @@ -860,6 +873,11 @@ export class LinkConnector {
}

dropOnNothing(event: CanvasPointerEvent): void {
remove(
this.renderLinks,
(link) => link instanceof MovingInputLink && link.disconnectOnDrop
).forEach((link) => (link as MovingLinkBase).disconnect())
if (this.renderLinks.length === 0) return
// For external event only.
const mayContinue = this.events.dispatch('dropped-on-canvas', event)
if (mayContinue === false) return
Expand Down
27 changes: 26 additions & 1 deletion src/lib/litegraph/src/canvas/MovingInputLink.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'
import { LiteGraph } from '@/lib/litegraph/src/litegraph'
import type { LLink } from '@/lib/litegraph/src/LLink'
import type { Reroute } from '@/lib/litegraph/src/Reroute'
import type { CustomEventTarget } from '@/lib/litegraph/src/infrastructure/CustomEventTarget'
Expand All @@ -24,12 +25,15 @@ export class MovingInputLink extends MovingLinkBase {
readonly fromPos: Point
readonly fromDirection: LinkDirection
readonly fromSlotIndex: number
disconnectOnDrop: boolean
readonly disconnectOrigin: Point

constructor(
network: LinkNetwork,
link: LLink,
fromReroute?: Reroute,
dragDirection: LinkDirection = LinkDirection.CENTER
dragDirection: LinkDirection = LinkDirection.CENTER,
startPoint?: Point
) {
super(network, link, 'input', fromReroute, dragDirection)

Expand All @@ -38,6 +42,8 @@ export class MovingInputLink extends MovingLinkBase {
this.fromPos = fromReroute?.pos ?? this.outputPos
this.fromDirection = LinkDirection.NONE
this.fromSlotIndex = this.outputIndex
this.disconnectOnDrop = true
this.disconnectOrigin = startPoint ?? this.inputPos
}

canConnectToInput(
Expand Down Expand Up @@ -130,4 +136,23 @@ export class MovingInputLink extends MovingLinkBase {
disconnect(): boolean {
return this.inputNode.disconnectInput(this.inputIndex, true)
}

drawConnectionCircle(ctx: CanvasRenderingContext2D, to: Readonly<Point>) {
if (!this.disconnectOnDrop) return

const [originX, originY] = this.disconnectOrigin
const radius = 35
const distSquared = (originX - to[0]) ** 2 + (originY - to[1]) ** 2

ctx.save()
ctx.strokeStyle = LiteGraph.WIDGET_OUTLINE_COLOR
ctx.lineWidth = 2
ctx.beginPath()
ctx.moveTo(originX + radius, originY)
ctx.arc(originX, originY, radius, 0, Math.PI * 2)
ctx.stroke()
ctx.restore()

this.disconnectOnDrop = distSquared < radius ** 2
}
}
13 changes: 11 additions & 2 deletions src/renderer/core/canvas/links/linkConnectorAdapter.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { SlotLayout } from '@/renderer/core/layout/types'
import type { Point } from '@/lib/litegraph/src/interfaces'
import type { LGraph } from '@/lib/litegraph/src/LGraph'
import type { NodeId } from '@/lib/litegraph/src/LGraphNode'
import type { RerouteId } from '@/lib/litegraph/src/Reroute'
Expand Down Expand Up @@ -72,7 +74,11 @@ export class LinkConnectorAdapter {
beginFromInput(
nodeId: NodeId,
inputIndex: number,
opts?: { moveExisting?: boolean; fromRerouteId?: RerouteId }
opts?: {
fromRerouteId?: RerouteId
layout?: SlotLayout
moveExisting?: boolean
}
): void {
const node = this.network.getNodeById(nodeId)
const input = node?.inputs?.[inputIndex]
Expand All @@ -81,7 +87,10 @@ export class LinkConnectorAdapter {
const fromReroute = this.network.getReroute(opts?.fromRerouteId)

if (opts?.moveExisting) {
this.linkConnector.moveInputLink(this.network, input)
const startPoint: Point | undefined = opts.layout
? [opts.layout.position.x, opts.layout.position.y]
: undefined
this.linkConnector.moveInputLink(this.network, input, { startPoint })
} else {
this.linkConnector.dragNewFromInput(
this.network,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -671,7 +671,8 @@ export function useSlotLinkInteraction({
})
} else {
activeAdapter.beginFromInput(localNodeId, index, {
moveExisting: shouldMoveExistingInput
moveExisting: shouldMoveExistingInput,
layout
})
}

Expand Down
Loading