-
Notifications
You must be signed in to change notification settings - Fork 394
Slot functionality for vue nodes #5628
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
58 commits
Select commit
Hold shift + click to select a range
3112dba
add dom element resize observer registry for vue node components
christian-byrne b6269c0
Update src/renderer/extensions/vueNodes/composables/useVueNodeResizeT…
christian-byrne 4287526
refactor(vue-nodes): typed TransformState InjectionKey, safer ResizeO…
benceruleanlu 110ecf3
chore: make TransformState interface non-exported to satisfy knip pre…
benceruleanlu 9786ecf
Revert "chore: make TransformState interface non-exported to satisfy …
benceruleanlu dbacbc5
Revert "refactor(vue-nodes): typed TransformState InjectionKey, safer…
benceruleanlu d4c2e83
[refactor] Improve resize tracking composable documentation and test …
christian-byrne db5a68b
remove typo comment
christian-byrne c39cdaf
convert to functional bounds collection
christian-byrne d39bf36
remove inline import
christian-byrne ea93135
add interfaces for bounds mutations
christian-byrne ea9c121
remove change log
christian-byrne ed94827
fix bounds collection when vue nodes turned off
christian-byrne ffede77
fix title offset on y
christian-byrne 5022f14
move from resize observer to selection toolbox bounds
christian-byrne f63118b
refactor(vue-nodes): typed TransformState InjectionKey, safer ResizeO…
benceruleanlu cb2069c
Fix conversion
benceruleanlu a0ed9d9
Readd padding
benceruleanlu 3a7cc3f
revert churn reducings from layoutStore.ts
benceruleanlu 0ba660f
Rely on RO for resize, and batch
benceruleanlu ed7a4e9
Improve churn
benceruleanlu 121221d
Cache canvas offset
benceruleanlu 4de2c2f
Merge remote-tracking branch 'origin/main' into bl-update-slots
benceruleanlu 57a1359
rename from measure
benceruleanlu cb211eb
Merge remote-tracking branch 'origin/main' into bl-update-slots
benceruleanlu 1dfa72c
remove unused
benceruleanlu 69f5391
address review comments
benceruleanlu 9203ed5
Merge remote-tracking branch 'origin/main' into bl-update-slots
benceruleanlu 16ddd4d
allow dragging out links and creating connections
benceruleanlu 777e419
Merge remote-tracking branch 'origin/main' into bl-make-slots-work
benceruleanlu f91dc82
knip
benceruleanlu 6586ef4
nit
benceruleanlu ef709d1
nit
benceruleanlu f26d1e7
nit
benceruleanlu 1e0bb75
nit
benceruleanlu 9d55954
nit
benceruleanlu 196c0c4
excessively unhelpful commit message
benceruleanlu 402f734
tentatively fix numerical enum bug
benceruleanlu bcce2c8
Revert "tentatively fix numerical enum bug"
benceruleanlu 6eb1f5e
Decisively fix numerical enum bug
benceruleanlu 75d3788
Undecsively fix the decisive fix for the numerical enum bug
benceruleanlu da3a467
Decisively fix the undecisive fix for the decisive fix for the numeri…
benceruleanlu 6653c92
Switch to useEventListener
benceruleanlu 20eb500
Switch to onDrawForeground
benceruleanlu 9fe3170
Switch to full mutable pointer state
benceruleanlu 7fd3ea1
Merge remote-tracking branch 'origin/bl-fix-monkey' into bl-make-slot…
benceruleanlu 98afaf8
nit
benceruleanlu 18e37cf
use canvasStore
benceruleanlu 0eacdb8
use NodeId type
benceruleanlu cabcd58
move folders to links
benceruleanlu 3980484
remove unneeded type assertations
benceruleanlu a093c29
use cn
benceruleanlu 70c9bbf
remove unneeded type assertations
benceruleanlu 5ca4cd8
Force return if readonly
benceruleanlu bfcf72c
Merge remote-tracking branch 'origin/main' into bl-make-slots-work
benceruleanlu 4baee30
use Point over MutablePoint
benceruleanlu 2bc5993
Refactor readonly noop
benceruleanlu 6044394
Group into pointer session
benceruleanlu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import type { CanvasColour, ISlotType } from '../interfaces' | ||
| import { LiteGraph } from '../litegraph' | ||
|
|
||
| /** | ||
| * Resolve the colour used while rendering or previewing a connection of a given slot type. | ||
| */ | ||
| export function resolveConnectingLinkColor( | ||
| type: ISlotType | undefined | ||
| ): CanvasColour { | ||
| return type === LiteGraph.EVENT | ||
| ? LiteGraph.EVENT_LINK_COLOR | ||
| : LiteGraph.CONNECTING_LINK_COLOR | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| import { getActivePinia } from 'pinia' | ||
|
|
||
| import type { | ||
| INodeInputSlot, | ||
| INodeOutputSlot | ||
| } from '@/lib/litegraph/src/interfaces' | ||
| import type { LGraphNode, NodeId } from '@/lib/litegraph/src/litegraph' | ||
| import { useCanvasStore } from '@/renderer/core/canvas/canvasStore' | ||
| import type { | ||
| SlotDragSource, | ||
| SlotDropCandidate | ||
| } from '@/renderer/core/canvas/links/slotLinkDragState' | ||
| import { app } from '@/scripts/app' | ||
|
|
||
| interface CompatibilityResult { | ||
| allowable: boolean | ||
| targetNode?: LGraphNode | ||
| targetSlot?: INodeInputSlot | INodeOutputSlot | ||
| } | ||
|
|
||
| function resolveNode(nodeId: NodeId) { | ||
| const pinia = getActivePinia() | ||
| const canvasStore = pinia ? useCanvasStore() : null | ||
| const graph = canvasStore?.canvas?.graph ?? app.canvas?.graph | ||
| if (!graph) return null | ||
| const id = typeof nodeId === 'string' ? Number(nodeId) : nodeId | ||
| if (Number.isNaN(id)) return null | ||
| return graph.getNodeById(id) | ||
| } | ||
|
|
||
| export function evaluateCompatibility( | ||
| source: SlotDragSource, | ||
| candidate: SlotDropCandidate | ||
| ): CompatibilityResult { | ||
| if (candidate.layout.nodeId === source.nodeId) { | ||
| return { allowable: false } | ||
| } | ||
|
|
||
| const isOutputToInput = | ||
| source.type === 'output' && candidate.layout.type === 'input' | ||
| const isInputToOutput = | ||
| source.type === 'input' && candidate.layout.type === 'output' | ||
|
|
||
| if (!isOutputToInput && !isInputToOutput) { | ||
| return { allowable: false } | ||
| } | ||
|
|
||
| const sourceNode = resolveNode(source.nodeId) | ||
| const targetNode = resolveNode(candidate.layout.nodeId) | ||
| if (!sourceNode || !targetNode) { | ||
| return { allowable: false } | ||
| } | ||
|
|
||
| if (isOutputToInput) { | ||
| const outputSlot = sourceNode.outputs?.[source.slotIndex] | ||
| const inputSlot = targetNode.inputs?.[candidate.layout.index] | ||
| if (!outputSlot || !inputSlot) { | ||
| return { allowable: false } | ||
| } | ||
|
|
||
| const allowable = sourceNode.canConnectTo(targetNode, inputSlot, outputSlot) | ||
| return { allowable, targetNode, targetSlot: inputSlot } | ||
| } | ||
|
|
||
| const inputSlot = sourceNode.inputs?.[source.slotIndex] | ||
| const outputSlot = targetNode.outputs?.[candidate.layout.index] | ||
| if (!inputSlot || !outputSlot) { | ||
| return { allowable: false } | ||
| } | ||
|
|
||
| const allowable = targetNode.canConnectTo(sourceNode, inputSlot, outputSlot) | ||
| return { allowable, targetNode, targetSlot: outputSlot } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| import { reactive, readonly } from 'vue' | ||
|
|
||
| import type { LinkDirection } from '@/lib/litegraph/src/types/globalEnums' | ||
| import { getSlotKey } from '@/renderer/core/layout/slots/slotIdentifier' | ||
| import { layoutStore } from '@/renderer/core/layout/store/layoutStore' | ||
| import type { Point, SlotLayout } from '@/renderer/core/layout/types' | ||
|
|
||
| type SlotDragType = 'input' | 'output' | ||
|
|
||
| export interface SlotDragSource { | ||
| nodeId: string | ||
| slotIndex: number | ||
| type: SlotDragType | ||
| direction: LinkDirection | ||
| position: Readonly<Point> | ||
| } | ||
|
|
||
| export interface SlotDropCandidate { | ||
| layout: SlotLayout | ||
| compatible: boolean | ||
| } | ||
|
|
||
| interface PointerPosition { | ||
| client: Point | ||
| canvas: Point | ||
| } | ||
|
|
||
| interface SlotDragState { | ||
| active: boolean | ||
| pointerId: number | null | ||
| source: SlotDragSource | null | ||
| pointer: PointerPosition | ||
| candidate: SlotDropCandidate | null | ||
| } | ||
|
|
||
| const state = reactive<SlotDragState>({ | ||
| active: false, | ||
| pointerId: null, | ||
| source: null, | ||
| pointer: { | ||
| client: { x: 0, y: 0 }, | ||
| canvas: { x: 0, y: 0 } | ||
| }, | ||
| candidate: null | ||
| }) | ||
|
|
||
| function updatePointerPosition( | ||
| clientX: number, | ||
| clientY: number, | ||
| canvasX: number, | ||
| canvasY: number | ||
| ) { | ||
| state.pointer.client.x = clientX | ||
| state.pointer.client.y = clientY | ||
| state.pointer.canvas.x = canvasX | ||
| state.pointer.canvas.y = canvasY | ||
| } | ||
|
|
||
| function setCandidate(candidate: SlotDropCandidate | null) { | ||
| state.candidate = candidate | ||
| } | ||
|
|
||
| function beginDrag(source: SlotDragSource, pointerId: number) { | ||
| state.active = true | ||
| state.source = source | ||
| state.pointerId = pointerId | ||
| state.candidate = null | ||
| } | ||
|
|
||
| function endDrag() { | ||
| state.active = false | ||
| state.pointerId = null | ||
| state.source = null | ||
| state.pointer.client.x = 0 | ||
| state.pointer.client.y = 0 | ||
| state.pointer.canvas.x = 0 | ||
| state.pointer.canvas.y = 0 | ||
| state.candidate = null | ||
| } | ||
|
|
||
| function getSlotLayout(nodeId: string, slotIndex: number, isInput: boolean) { | ||
| const slotKey = getSlotKey(nodeId, slotIndex, isInput) | ||
| return layoutStore.getSlotLayout(slotKey) | ||
| } | ||
|
|
||
| export function useSlotLinkDragState() { | ||
| return { | ||
| state: readonly(state), | ||
| beginDrag, | ||
| endDrag, | ||
| updatePointerPosition, | ||
| setCandidate, | ||
| getSlotLayout | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| import type { LGraphCanvas } from '@/lib/litegraph/src/LGraphCanvas' | ||
| import type { | ||
| INodeInputSlot, | ||
| INodeOutputSlot, | ||
| ReadOnlyPoint | ||
| } from '@/lib/litegraph/src/interfaces' | ||
| import { LinkDirection } from '@/lib/litegraph/src/types/globalEnums' | ||
| import { resolveConnectingLinkColor } from '@/lib/litegraph/src/utils/linkColors' | ||
| import { | ||
| type SlotDragSource, | ||
| useSlotLinkDragState | ||
| } from '@/renderer/core/canvas/links/slotLinkDragState' | ||
| import type { LinkRenderContext } from '@/renderer/core/canvas/litegraph/litegraphLinkAdapter' | ||
|
|
||
| function buildContext(canvas: LGraphCanvas): LinkRenderContext { | ||
| return { | ||
| renderMode: canvas.links_render_mode, | ||
| connectionWidth: canvas.connections_width, | ||
| renderBorder: canvas.render_connections_border, | ||
| lowQuality: canvas.low_quality, | ||
| highQualityRender: canvas.highquality_render, | ||
| scale: canvas.ds.scale, | ||
| linkMarkerShape: canvas.linkMarkerShape, | ||
| renderConnectionArrows: canvas.render_connection_arrows, | ||
| highlightedLinks: new Set(Object.keys(canvas.highlighted_links)), | ||
| defaultLinkColor: canvas.default_link_color, | ||
| linkTypeColors: (canvas.constructor as typeof LGraphCanvas) | ||
| .link_type_colors, | ||
| disabledPattern: canvas._pattern | ||
| } | ||
| } | ||
|
|
||
| export function attachSlotLinkPreviewRenderer(canvas: LGraphCanvas) { | ||
| const originalOnDrawForeground = canvas.onDrawForeground?.bind(canvas) | ||
| const patched = ( | ||
| ctx: CanvasRenderingContext2D, | ||
| area: LGraphCanvas['visible_area'] | ||
| ) => { | ||
| originalOnDrawForeground?.(ctx, area) | ||
|
|
||
| const { state } = useSlotLinkDragState() | ||
| if (!state.active || !state.source) return | ||
|
|
||
| const { pointer, source } = state | ||
| const start = source.position | ||
| const sourceSlot = resolveSourceSlot(canvas, source) | ||
|
|
||
| const linkRenderer = canvas.linkRenderer | ||
| if (!linkRenderer) return | ||
|
|
||
| const context = buildContext(canvas) | ||
|
|
||
| const from: ReadOnlyPoint = [start.x, start.y] | ||
| const to: ReadOnlyPoint = [pointer.canvas.x, pointer.canvas.y] | ||
|
|
||
| const startDir = source.direction ?? LinkDirection.RIGHT | ||
| const endDir = LinkDirection.CENTER | ||
|
|
||
| const colour = resolveConnectingLinkColor(sourceSlot?.type) | ||
|
|
||
| ctx.save() | ||
|
|
||
| linkRenderer.renderDraggingLink( | ||
| ctx, | ||
| from, | ||
| to, | ||
| colour, | ||
| startDir, | ||
| endDir, | ||
| context | ||
| ) | ||
|
|
||
| ctx.restore() | ||
| } | ||
|
|
||
| canvas.onDrawForeground = patched | ||
| } | ||
|
|
||
| function resolveSourceSlot( | ||
| canvas: LGraphCanvas, | ||
| source: SlotDragSource | ||
| ): INodeInputSlot | INodeOutputSlot | undefined { | ||
| const graph = canvas.graph | ||
| if (!graph) return undefined | ||
|
|
||
| const nodeId = Number(source.nodeId) | ||
| if (!Number.isFinite(nodeId)) return undefined | ||
|
|
||
| const node = graph.getNodeById(nodeId) | ||
| if (!node) return undefined | ||
|
|
||
| return source.type === 'output' | ||
| ? node.outputs?.[source.slotIndex] | ||
| : node.inputs?.[source.slotIndex] | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.