Make Vue nodes read-only when in panning mode (#5574)

## Summary

Integrated Vue node components with canvas panning mode to prevent UI
interference during navigation.

## Changes

- **What**: Added
[canCapturePointerEvents](https://docs.comfy.org/guide/vue-nodes)
computed property to `useCanvasInteractions` composable that checks
canvas read-only state
- **What**: Modified Vue node components (LGraphNode, NodeWidgets) to
conditionally handle pointer events based on canvas navigation mode
- **What**: Updated node event handlers to respect panning mode and
forward events to canvas when appropriate

## Review Focus

Event forwarding logic in panning mode and pointer event capture state
management across Vue node hierarchy.

```mermaid
graph TD
    A[User Interaction] --> B{Canvas in Panning Mode?}
    B -->|Yes| C[Forward to Canvas]
    B -->|No| D[Handle in Vue Component]
    C --> E[Canvas Navigation]
    D --> F[Node Selection/Widget Interaction]

    G[canCapturePointerEvents] --> H{read_only === false}
    H -->|Yes| I[Allow Vue Events]
    H -->|No| J[Block Vue Events]

    style A fill:#f9f9f9,stroke:#333,color:#000
    style E fill:#f9f9f9,stroke:#333,color:#000
    style F fill:#f9f9f9,stroke:#333,color:#000
    style I fill:#e1f5fe,stroke:#01579b,color:#000
    style J fill:#ffebee,stroke:#c62828,color:#000
```

## Screenshots




https://github.com/user-attachments/assets/00dc5e4a-2b56-43be-b92e-eaf511e52542

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5574-Make-Vue-nodes-read-only-when-in-panning-mode-26f6d73d3650818c951cd82c8fe58972)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
Christian Byrne
2025-09-18 15:43:35 -07:00
committed by GitHub
parent 7585444ce6
commit bc85d4e87b
11 changed files with 123 additions and 13 deletions

View File

@@ -1,102 +0,0 @@
import { computed } from 'vue'
import { useSettingStore } from '@/platform/settings/settingStore'
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
import { app } from '@/scripts/app'
/**
* Composable for handling canvas interactions from Vue components.
* This provides a unified way to forward events to the LiteGraph canvas
* and will be the foundation for migrating canvas interactions to Vue.
*/
export function useCanvasInteractions() {
const settingStore = useSettingStore()
const { getCanvas } = useCanvasStore()
const isStandardNavMode = computed(
() => settingStore.get('Comfy.Canvas.NavigationMode') === 'standard'
)
/**
* Handles wheel events from UI components that should be forwarded to canvas
* when appropriate (e.g., Ctrl+wheel for zoom in standard mode)
*/
const handleWheel = (event: WheelEvent) => {
// In standard mode, Ctrl+wheel should go to canvas for zoom
if (isStandardNavMode.value && (event.ctrlKey || event.metaKey)) {
forwardEventToCanvas(event)
return
}
// In legacy mode, all wheel events go to canvas for zoom
if (!isStandardNavMode.value) {
forwardEventToCanvas(event)
return
}
// Otherwise, let the component handle it normally
}
/**
* Handles pointer events from media elements that should potentially
* be forwarded to canvas (e.g., space+drag for panning)
*/
const handlePointer = (event: PointerEvent) => {
// Check if canvas exists using established pattern
const canvas = getCanvas()
if (!canvas) return
// Check conditions for forwarding events to canvas
const isSpacePanningDrag = canvas.read_only && event.buttons === 1 // Space key pressed + left mouse drag
const isMiddleMousePanning = event.buttons === 4 // Middle mouse button for panning
if (isSpacePanningDrag || isMiddleMousePanning) {
event.preventDefault()
event.stopPropagation()
forwardEventToCanvas(event)
return
}
}
/**
* Forwards an event to the LiteGraph canvas
*/
const forwardEventToCanvas = (
event: WheelEvent | PointerEvent | MouseEvent
) => {
const canvasEl = app.canvas?.canvas
if (!canvasEl) return
event.preventDefault()
event.stopPropagation()
if (event instanceof WheelEvent) {
const { clientX, clientY, deltaX, deltaY, ctrlKey, metaKey, shiftKey } =
event
canvasEl.dispatchEvent(
new WheelEvent('wheel', {
clientX,
clientY,
deltaX,
deltaY,
ctrlKey,
metaKey,
shiftKey
})
)
return
}
// Create new event with same properties
const EventConstructor = event.constructor as
| typeof MouseEvent
| typeof PointerEvent
const newEvent = new EventConstructor(event.type, event)
canvasEl.dispatchEvent(newEvent)
}
return {
handleWheel,
handlePointer,
forwardEventToCanvas
}
}

View File

@@ -1,5 +1,5 @@
import { useCanvasInteractions } from '@/composables/graph/useCanvasInteractions'
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
import { useCanvasInteractions } from '@/renderer/core/canvas/useCanvasInteractions'
import { useNodeOutputStore } from '@/stores/imagePreviewStore'
import { fitDimensionsToNodeWidth } from '@/utils/imageUtil'