macro-clips slice 4d: button canvas runtime + pointer handling
- ButtonInstance gains optional x/y; new instances default to stage center and setButtonInstancePosition updates them - useButtonRuntime composable holds per-instance state/disabled overrides (runtime-only, not persisted). getState layers the runtime disabled override on top of the persisted initial flag. - store.actionRuntime's setButtonState/setButtonDisabled now drive useButtonRuntime instead of mutating the scene, so script-triggered state changes stay ephemeral - CanvasStage renders each visible (playhead >= startTime) button instance inside a <v-group> at (bi.x, bi.y), drawing the current state's layer stack with draggable/listening disabled plus a transparent hit-rect sized to the clip's hitArea or the bbox of the first rect/circle layer. The group wires mouseenter/leave/ down/up into the state machine and fires onClick via evalAction. - exportPlayer runtime mirrors the same thing: getEffectiveButtonState, per-frame buttonHits array, canvas-level mousemove/down/up handlers do their own hit testing in scene space. RUNTIME_VERSION bumped to 5. - tests cover useButtonRuntime defaults/overrides and the store.actionRuntime → runtime-state roundtrip via label resolution. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
024883943b
commit
f61f90d613
6 files changed
+412
-8
No files matched your search
@@ -1,5 +1,6 @@
|
||||
import { createApp, h, nextTick, type Component, type Slot } from 'vue'
|
||||
import { createBlankScene, useSceneStore } from '@/stores/scene'
|
||||
import { useButtonRuntime } from '@/composables/useButtonRuntime'
|
||||
import {
|
||||
buildMarkerMap,
|
||||
evalAction,
|
||||
@@ -3521,6 +3522,45 @@ export function registerAllTests(): void {
|
||||
})
|
||||
})
|
||||
|
||||
suite('button runtime — state machine + action wiring', () => {
|
||||
test('default state is normal; set/clear round-trip works', () => {
|
||||
const rt = useButtonRuntime()
|
||||
rt.reset()
|
||||
expect(rt.getState('b1')).toBe('normal')
|
||||
rt.setState('b1', 'pressed')
|
||||
expect(rt.getState('b1')).toBe('pressed')
|
||||
rt.setState('b1', 'normal') // normal uses delete internally
|
||||
expect(rt.getState('b1')).toBe('normal')
|
||||
})
|
||||
|
||||
test('persisted disabled surfaces as state=disabled until runtime overrides', () => {
|
||||
const rt = useButtonRuntime()
|
||||
rt.reset()
|
||||
expect(rt.getState('b1', true)).toBe('disabled')
|
||||
rt.setDisabled('b1', false) // runtime enables
|
||||
expect(rt.getState('b1', true)).toBe('normal')
|
||||
rt.setDisabled('b1', true)
|
||||
expect(rt.getState('b1', false)).toBe('disabled')
|
||||
})
|
||||
|
||||
test('store.actionRuntime resolves labels and drives useButtonRuntime', () => {
|
||||
const s = makeFreshStore()
|
||||
const rt = useButtonRuntime()
|
||||
rt.reset()
|
||||
const bc = s.addButtonClip('B')
|
||||
const ct = s.addClipTrack()
|
||||
const inst = s.addButtonInstance(bc.id, ct.id, 0)!
|
||||
s.setButtonInstanceLabel(inst.id, 'play')
|
||||
const ar = s.actionRuntime()
|
||||
ar.setButtonState('play', 'pressed')
|
||||
expect(rt.getState(inst.id)).toBe('pressed')
|
||||
ar.setButtonDisabled('play', true)
|
||||
expect(rt.getState(inst.id)).toBe('disabled')
|
||||
ar.setButtonDisabled('play', false)
|
||||
expect(rt.getState(inst.id, inst.disabled)).toBe('pressed')
|
||||
})
|
||||
})
|
||||
|
||||
suite('scene store — macro model normalization', () => {
|
||||
test('loadScene initializes new arrays when missing', () => {
|
||||
const s = makeFreshStore()
|
||||
|
||||
Reference in new issue
Block a user