From feafbf9cbf287408066053cbb638fba0716452b6 Mon Sep 17 00:00:00 2001 From: filtered <176114999+webfiltered@users.noreply.github.com> Date: Wed, 13 Nov 2024 03:46:14 +1100 Subject: [PATCH] Litegraph Reroute Beta (#1421) * Add Reroute support - ConnectingLinkImpl Bonus: TS strict * Add Reroute support * Remove unused TS expect error * Add reroute beta opt-in option * Add settings option: Middle-click reroute node * Add settings: Link Markers * Move settings * Update litegraph --------- Co-authored-by: huchenlei --- package-lock.json | 8 ++-- package.json | 2 +- src/components/graph/GraphCanvas.vue | 24 +++++++++++ .../searchbox/NodeSearchBoxPopover.vue | 14 +++++-- src/stores/coreSettings.ts | 30 ++++++++++++++ src/types/litegraphTypes.ts | 40 +++++++------------ 6 files changed, 84 insertions(+), 34 deletions(-) diff --git a/package-lock.json b/package-lock.json index b38457d3e..d055d0e62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "dependencies": { "@atlaskit/pragmatic-drag-and-drop": "^1.3.1", "@comfyorg/comfyui-electron-types": "^0.2.10", - "@comfyorg/litegraph": "^0.8.25", + "@comfyorg/litegraph": "^0.8.26", "@primevue/themes": "^4.0.5", "@vueuse/core": "^11.0.0", "@xterm/addon-fit": "^0.10.0", @@ -1922,9 +1922,9 @@ "license": "GPL-3.0-only" }, "node_modules/@comfyorg/litegraph": { - "version": "0.8.25", - "resolved": "https://registry.npmjs.org/@comfyorg/litegraph/-/litegraph-0.8.25.tgz", - "integrity": "sha512-VYMpxNLAwLgmT1mFX77RNA3O5KavhWBmYJpb3+BLW6BwmnDCd0QHX9gy5IFsGSpQP28k2lWgANIcGZF2Ev2eqg==", + "version": "0.8.26", + "resolved": "https://registry.npmjs.org/@comfyorg/litegraph/-/litegraph-0.8.26.tgz", + "integrity": "sha512-q0Vcd5usphR5nghfyFksVx+VM+eSB1MyX8Ne304KFDnr214KQMA6DAjrEQJlGBUUCybLiOtPCvd3dxPecEQiSQ==", "license": "MIT" }, "node_modules/@cspotcode/source-map-support": { diff --git a/package.json b/package.json index 61dfcf448..8e53da800 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "dependencies": { "@atlaskit/pragmatic-drag-and-drop": "^1.3.1", "@comfyorg/comfyui-electron-types": "^0.2.10", - "@comfyorg/litegraph": "^0.8.25", + "@comfyorg/litegraph": "^0.8.26", "@primevue/themes": "^4.0.5", "@vueuse/core": "^11.0.0", "@xterm/addon-fit": "^0.10.0", diff --git a/src/components/graph/GraphCanvas.vue b/src/components/graph/GraphCanvas.vue index 8c68ba723..9443edd54 100644 --- a/src/components/graph/GraphCanvas.vue +++ b/src/components/graph/GraphCanvas.vue @@ -104,6 +104,12 @@ watchEffect(() => { ) }) +watchEffect(() => { + LiteGraph.middle_click_slot_add_default_node = settingStore.get( + 'Comfy.Node.MiddleClickRerouteNode' + ) +}) + watchEffect(() => { nodeDefStore.showDeprecated = settingStore.get('Comfy.Node.ShowDeprecated') }) @@ -134,6 +140,24 @@ watchEffect(() => { } }) +watchEffect(() => { + const linkMarkerShape = settingStore.get('Comfy.Graph.LinkMarkers') + const { canvas } = canvasStore + if (canvas) { + canvas.linkMarkerShape = linkMarkerShape + canvas.setDirty(false, true) + } +}) + +watchEffect(() => { + const reroutesEnabled = settingStore.get('Comfy.RerouteBeta') + const { canvas } = canvasStore + if (canvas) { + canvas.reroutesEnabled = reroutesEnabled + canvas.setDirty(false, true) + } +}) + watchEffect(() => { if (!canvasStore.canvas) return diff --git a/src/components/searchbox/NodeSearchBoxPopover.vue b/src/components/searchbox/NodeSearchBoxPopover.vue index f8ba60a86..dee8dad74 100644 --- a/src/components/searchbox/NodeSearchBoxPopover.vue +++ b/src/components/searchbox/NodeSearchBoxPopover.vue @@ -58,7 +58,6 @@ const getNewNodeLocation = (): [number, number] => { } const originalEvent = triggerEvent.value.detail.originalEvent - // @ts-expect-error LiteGraph types are not typed return [originalEvent.canvasX, originalEvent.canvasY] } const nodeFilters = ref([]) @@ -153,8 +152,16 @@ const showContextMenu = (e: LiteGraphCanvasEvent) => { showSearchBox: () => showSearchBox(e) } const connectionOptions = firstLink.output - ? { nodeFrom: firstLink.node, slotFrom: firstLink.output } - : { nodeTo: firstLink.node, slotTo: firstLink.input } + ? { + nodeFrom: firstLink.node, + slotFrom: firstLink.output, + afterRerouteId: firstLink.afterRerouteId + } + : { + nodeTo: firstLink.node, + slotTo: firstLink.input, + afterRerouteId: firstLink.afterRerouteId + } canvasStore.canvas.showConnectionMenu({ ...connectionOptions, ...commonOptions @@ -178,7 +185,6 @@ const canvasEventHandler = (e: LiteGraphCanvasEvent) => { } else if (e.detail.subType === 'group-double-click') { const group = e.detail.group const [x, y] = group.pos - // @ts-expect-error LiteGraphCanvasEvent is not typed const relativeY = e.detail.originalEvent.canvasY - y // Show search box if the click is NOT on the title bar if (relativeY > group.titleHeight) { diff --git a/src/stores/coreSettings.ts b/src/stores/coreSettings.ts index 43b7a538d..a1a25fdf2 100644 --- a/src/stores/coreSettings.ts +++ b/src/stores/coreSettings.ts @@ -5,6 +5,7 @@ import { LinkReleaseTriggerMode } from '@/types/searchBoxTypes' import type { SettingParams } from '@/types/settingTypes' +import { LinkMarkerShape } from '@comfyorg/litegraph' import { LiteGraph } from '@comfyorg/litegraph' export const CORE_SETTINGS: SettingParams[] = [ @@ -484,5 +485,34 @@ export const CORE_SETTINGS: SettingParams[] = [ type: 'boolean', defaultValue: true, versionAdded: '1.3.40' + }, + { + id: 'Comfy.Node.MiddleClickRerouteNode', + name: 'Middle-click creates a new Reroute node', + type: 'boolean', + defaultValue: true, + versionAdded: '1.3.42' + }, + { + id: 'Comfy.RerouteBeta', + name: 'Opt-in to the reroute beta test', + tooltip: + 'Enables the new native reroutes.\n\nReroutes can be added by holding alt and dragging from a link line, or on the link menu.\n\nDisabling this option is non-destructive - reroutes are hidden.', + experimental: true, + type: 'boolean', + defaultValue: false, + versionAdded: '1.3.42' + }, + { + id: 'Comfy.Graph.LinkMarkers', + name: 'Link midpoint markers', + defaultValue: LinkMarkerShape.Circle, + type: 'combo', + options: [ + { value: LinkMarkerShape.None, text: 'None' }, + { value: LinkMarkerShape.Circle, text: 'Circle' }, + { value: LinkMarkerShape.Arrow, text: 'Arrow' } + ], + versionAdded: '1.3.42' } ] diff --git a/src/types/litegraphTypes.ts b/src/types/litegraphTypes.ts index 892c0ab3b..f9e7ab987 100644 --- a/src/types/litegraphTypes.ts +++ b/src/types/litegraphTypes.ts @@ -1,35 +1,24 @@ -// @ts-strict-ignore import type { ConnectingLink, LGraphNode, Vector2, INodeInputSlot, INodeOutputSlot, - INodeSlot + INodeSlot, + ISlotType } from '@comfyorg/litegraph' -import type { ISlotType } from '@comfyorg/litegraph' import { LiteGraph } from '@comfyorg/litegraph' +import { RerouteId } from '@comfyorg/litegraph/dist/Reroute' export class ConnectingLinkImpl implements ConnectingLink { - node: LGraphNode - slot: number - input: INodeInputSlot | null - output: INodeOutputSlot | null - pos: Vector2 - constructor( - node: LGraphNode, - slot: number, - input: INodeInputSlot | null, - output: INodeOutputSlot | null, - pos: Vector2 - ) { - this.node = node - this.slot = slot - this.input = input - this.output = output - this.pos = pos - } + public node: LGraphNode, + public slot: number, + public input: INodeInputSlot | undefined, + public output: INodeOutputSlot | undefined, + public pos: Vector2, + public afterRerouteId?: RerouteId + ) {} static createFromPlainObject(obj: ConnectingLink) { return new ConnectingLinkImpl( @@ -37,12 +26,13 @@ export class ConnectingLinkImpl implements ConnectingLink { obj.slot, obj.input, obj.output, - obj.pos + obj.pos, + obj.afterRerouteId ) } get type(): ISlotType | null { - const result = this.input ? this.input.type : this.output.type + const result = this.input ? this.input.type : this.output?.type ?? null return result === -1 ? null : result } @@ -71,9 +61,9 @@ export class ConnectingLinkImpl implements ConnectingLink { } if (this.releaseSlotType === 'input') { - this.node.connect(this.slot, newNode, newNodeSlot) + this.node.connect(this.slot, newNode, newNodeSlot, this.afterRerouteId) } else { - newNode.connect(newNodeSlot, this.node, this.slot) + newNode.connect(newNodeSlot, this.node, this.slot, this.afterRerouteId) } } }