Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
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
3 changes: 3 additions & 0 deletions src/lib/litegraph/src/LGraphCanvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -401,8 +401,11 @@ export class LGraphCanvas implements CustomEventDispatcher<LGraphCanvasEventMap>
set read_only(value: boolean) {
this.state.readOnly = value
this._updateCursorStyle()
this.onReadOnlyChanged?.(value)
}

onReadOnlyChanged?: (readOnly: boolean) => void

get isDragging(): boolean {
return this.state.draggingItems
}
Expand Down
81 changes: 81 additions & 0 deletions src/renderer/core/canvas/canvasStore.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { createTestingPinia } from '@pinia/testing'
import { setActivePinia } from 'pinia'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { nextTick } from 'vue'

import type { LGraphCanvas } from '@/lib/litegraph/src/litegraph'
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'

vi.mock('@/scripts/app', () => ({
app: { canvas: null }
}))

vi.mock('@vueuse/core', async (importOriginal) => {
const actual = await importOriginal()
return {
...(actual as Record<string, unknown>),
useEventListener: vi.fn()
}
})

function createMockCanvas(
readOnly = false
): LGraphCanvas & { onReadOnlyChanged?: (v: boolean) => void } {
return {
read_only: readOnly,
canvas: document.createElement('canvas'),
onReadOnlyChanged: undefined
} as unknown as LGraphCanvas & {
onReadOnlyChanged?: (v: boolean) => void
}
}

describe('useCanvasStore', () => {
beforeEach(() => {
setActivePinia(createTestingPinia({ stubActions: false }))
vi.clearAllMocks()
})

describe('isReadOnly', () => {
it('syncs initial read_only value when canvas is set', async () => {
const store = useCanvasStore()
const mockCanvas = createMockCanvas(true)

store.canvas = mockCanvas as unknown as LGraphCanvas
await nextTick()

expect(store.isReadOnly).toBe(true)
})

it('updates isReadOnly when onReadOnlyChanged callback fires', async () => {
const store = useCanvasStore()
const mockCanvas = createMockCanvas(false)

store.canvas = mockCanvas as unknown as LGraphCanvas
await nextTick()

expect(store.isReadOnly).toBe(false)

// Simulate space key press → LGraphCanvas sets read_only = true
mockCanvas.onReadOnlyChanged?.(true)

expect(store.isReadOnly).toBe(true)

// Simulate space key release
mockCanvas.onReadOnlyChanged?.(false)

expect(store.isReadOnly).toBe(false)
})

it('registers onReadOnlyChanged callback on the canvas', async () => {
const store = useCanvasStore()
const mockCanvas = createMockCanvas(false)

store.canvas = mockCanvas as unknown as LGraphCanvas
await nextTick()

expect(mockCanvas.onReadOnlyChanged).toBeDefined()
expect(typeof mockCanvas.onReadOnlyChanged).toBe('function')
})
})
})
7 changes: 7 additions & 0 deletions src/renderer/core/canvas/canvasStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export const useCanvasStore = defineStore('canvas', () => {
const appScalePercentage = ref(100)

const linearMode = ref(false)
const isReadOnly = ref(false)

// Set up scale synchronization when canvas is available
let originalOnChanged: ((scale: number, offset: Point) => void) | undefined =
Expand Down Expand Up @@ -115,6 +116,11 @@ export const useCanvasStore = defineStore('canvas', () => {
whenever(
() => canvas.value,
(newCanvas) => {
isReadOnly.value = newCanvas.read_only
newCanvas.onReadOnlyChanged = (value: boolean) => {
isReadOnly.value = value
}
Comment on lines +119 to +122
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This cannot be the best way to do this.


useEventListener(
newCanvas.canvas,
'litegraph:set-graph',
Expand All @@ -141,6 +147,7 @@ export const useCanvasStore = defineStore('canvas', () => {
rerouteSelected,
appScalePercentage,
linearMode,
isReadOnly,
updateSelectedItems,
getCanvas,
setAppZoomFromPercentage,
Expand Down
3 changes: 2 additions & 1 deletion src/renderer/core/canvas/useCanvasInteractions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ vi.mock('@/renderer/core/canvas/canvasStore', () => {
return {
useCanvasStore: vi.fn(() => ({
getCanvas,
setCursorStyle
setCursorStyle,
isReadOnly: false
}))
}
})
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/core/canvas/useCanvasInteractions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function useCanvasInteractions() {
* Returns false when canvas is in read-only/panning mode (e.g., space key held for panning).
*/
const shouldHandleNodePointerEvents = computed(
() => !(canvasStore.canvas?.read_only ?? false)
() => !canvasStore.isReadOnly
)

/**
Expand Down
Loading