Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,6 @@ import { useVueNodeLifecycle } from '@/composables/graph/useVueNodeLifecycle'
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
import { useCanvasInteractions } from '@/renderer/core/canvas/useCanvasInteractions'
import { useNodeZIndex } from '@/renderer/extensions/vueNodes/composables/useNodeZIndex'
import { isLGraphNode } from '@/utils/litegraphUtil'

/**
* Check if multiple nodes are selected
* Optimized to return early when 2+ nodes found
*/
function hasMultipleNodesSelected(selectedItems: unknown[]): boolean {
let count = 0
for (let i = 0; i < selectedItems.length; i++) {
if (isLGraphNode(selectedItems[i])) {
count++
if (count >= 2) {
return true
}
}
}
return false
}

function useNodeEventHandlersIndividual() {
const canvasStore = useCanvasStore()
Expand All @@ -53,24 +35,12 @@ function useNodeEventHandlersIndividual() {
if (!node) return

const isMultiSelect = event.ctrlKey || event.metaKey || event.shiftKey
// Ctrl/Cmd+click -> toggle selection

if (isMultiSelect) {
// Ctrl/Cmd+click -> toggle selection
if (node.selected) {
canvasStore.canvas.deselect(node)
} else {
canvasStore.canvas.select(node)
}
} else {
const selectedMultipleNodes = hasMultipleNodesSelected(
canvasStore.selectedItems
)
if (!selectedMultipleNodes) {
// Single-select the node
canvasStore.canvas.deselectAll()
canvasStore.canvas.select(node)
}
if (!isMultiSelect) {
canvasStore.canvas.deselectAll()
}
canvasStore.canvas.select(node)

// Bring node to front when clicked (similar to LiteGraph behavior)
// Skip if node is pinned to avoid unwanted movement
Expand Down Expand Up @@ -237,6 +207,21 @@ function useNodeEventHandlersIndividual() {
canvasStore.updateSelectedItems()
}

/**
* Handle node click deselection
* Called when a node is clicked without dragging
*/
const handleNodeClickDeselect = (nodeId: string) => {
if (!shouldHandleNodePointerEvents.value) return

if (!canvasStore.canvas || !nodeManager.value) return

const node = nodeManager.value.getNode(nodeId)
if (!node) return

canvasStore.canvas.deselect(node)
}

return {
// Core event handlers
handleNodeSelect,
Expand All @@ -245,6 +230,7 @@ function useNodeEventHandlersIndividual() {
handleNodeDoubleClick,
handleNodeRightClick,
handleNodeDragStart,
handleNodeClickDeselect,

// Batch operations
selectNodes,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { VueNodeData } from '@/composables/graph/useGraphNodeManager'
import { useCanvasInteractions } from '@/renderer/core/canvas/useCanvasInteractions'
import { layoutStore } from '@/renderer/core/layout/store/layoutStore'
import { useNodeLayout } from '@/renderer/extensions/vueNodes/layout/useNodeLayout'
import { useNodeEventHandlers } from '@/renderer/extensions/vueNodes/composables/useNodeEventHandlers'

export function useNodePointerInteractions(
nodeDataMaybe: MaybeRefOrGetter<VueNodeData | null>,
Expand All @@ -28,6 +29,7 @@ export function useNodePointerInteractions(
// Use canvas interactions for proper wheel event handling and pointer event capture control
const { forwardEventToCanvas, shouldHandleNodePointerEvents } =
useCanvasInteractions()
const { handleNodeClickDeselect } = useNodeEventHandlers()

const forwardMiddlePointerIfNeeded = (event: PointerEvent) => {
if (!isMiddlePointerInput(event)) return false
Expand Down Expand Up @@ -130,6 +132,9 @@ export function useNodePointerInteractions(

if (isDragging.value) {
handleDragTermination(event, 'drag end')
} else if (nodeData.value) {
// Handle click without drag - deselect the node
handleNodeClickDeselect(nodeData.value.id)
}

// Don't handle pointer events when canvas is in panning mode - forward to canvas instead
Expand Down
Loading