diff --git a/src/hooks/useTuioIntegration.ts b/src/hooks/useTuioIntegration.ts index 6cd66af..5dc5f59 100644 --- a/src/hooks/useTuioIntegration.ts +++ b/src/hooks/useTuioIntegration.ts @@ -136,8 +136,9 @@ function handleTangibleRemove(hardwareId: string): void { // Handle removal based on tangible mode if (tangibleConfig.mode === 'filter') { removeFilterTangible(tangibleConfig); + } else if (tangibleConfig.mode === 'state' || tangibleConfig.mode === 'stateDial') { + removeStateTangible(hardwareId); } - // State mode: Don't revert on removal (stay in current state) } /** @@ -199,17 +200,44 @@ function applyStateTangible(tangible: TangibleConfig, hardwareId: string): void return; } - const { lastStateChangeSource } = useTuioStore.getState(); + console.log('[TUIO Integration] Applying state tangible:', hardwareId, 'stateId:', tangible.stateId); - // Only switch if this is a different tangible than the last state change - // (Last added wins strategy) - if (lastStateChangeSource === hardwareId) { - return; // Same tangible, don't re-switch - } + // Add to active state tangibles list (at the end) + useTuioStore.getState().addActiveStateTangible(hardwareId); - // Switch to state - useTimelineStore.getState().switchToState(tangible.stateId); + // Always switch to this tangible's state (last added wins) + // Pass fromTangible=true to prevent clearing the active state tangibles list + useTimelineStore.getState().switchToState(tangible.stateId, true); - // Track this as the last state change source - useTuioStore.getState().setLastStateChangeSource(hardwareId); + console.log('[TUIO Integration] Active state tangibles:', useTuioStore.getState().activeStateTangibles); +} + +/** + * Remove state tangible - switch to next active state tangible if any + */ +function removeStateTangible(hardwareId: string): void { + console.log('[TUIO Integration] Removing state tangible:', hardwareId); + + // Remove from active state tangibles list + useTuioStore.getState().removeActiveStateTangible(hardwareId); + + const activeStateTangibles = useTuioStore.getState().activeStateTangibles; + console.log('[TUIO Integration] Remaining active state tangibles:', activeStateTangibles); + + // If there are other state tangibles still active, switch to the last one + if (activeStateTangibles.length > 0) { + const lastActiveHwId = activeStateTangibles[activeStateTangibles.length - 1]; + console.log('[TUIO Integration] Switching to last active state tangible:', lastActiveHwId); + + // Find the tangible config for this hardware ID + const tangibles = useGraphStore.getState().tangibles; + const tangibleConfig = tangibles.find((t) => t.hardwareId === lastActiveHwId); + + if (tangibleConfig && tangibleConfig.stateId) { + // Pass fromTangible=true to prevent clearing the active state tangibles list + useTimelineStore.getState().switchToState(tangibleConfig.stateId, true); + } + } else { + console.log('[TUIO Integration] No more active state tangibles, staying in current state'); + } } diff --git a/src/stores/timelineStore.ts b/src/stores/timelineStore.ts index 26c651c..7f07dff 100644 --- a/src/stores/timelineStore.ts +++ b/src/stores/timelineStore.ts @@ -11,6 +11,7 @@ import { useGraphStore } from "./graphStore"; import { useWorkspaceStore } from "./workspaceStore"; import { useToastStore } from "./toastStore"; import { useHistoryStore } from "./historyStore"; +import { useTuioStore } from "./tuioStore"; /** * Timeline Store @@ -235,7 +236,7 @@ export const useTimelineStore = create( return newStateId; }, - switchToState: (stateId: StateId) => { + switchToState: (stateId: StateId, fromTangible: boolean = false) => { const state = get(); const { activeDocumentId } = state; @@ -257,6 +258,12 @@ export const useTimelineStore = create( return; } + // If this is a manual state switch (not from tangible), clear active state tangibles + if (!fromTangible) { + console.log('[Timeline] Manual state switch detected, clearing active state tangibles'); + useTuioStore.getState().clearActiveStateTangibles(); + } + // Don't push history if already on this state if (timeline.currentStateId !== stateId) { // Push to history BEFORE making changes diff --git a/src/stores/tuioStore.ts b/src/stores/tuioStore.ts index 48b31c7..aee586f 100644 --- a/src/stores/tuioStore.ts +++ b/src/stores/tuioStore.ts @@ -29,12 +29,14 @@ interface TuioState { // Active tangibles (runtime only - not persisted) activeTangibles: Map; - lastStateChangeSource: string | null; + activeStateTangibles: string[]; // Hardware IDs of active state tangibles in order addActiveTangible: (hardwareId: string, info: TuioTangibleInfo) => void; updateActiveTangible: (hardwareId: string, info: TuioTangibleInfo) => void; removeActiveTangible: (hardwareId: string) => void; clearActiveTangibles: () => void; - setLastStateChangeSource: (hardwareId: string | null) => void; + addActiveStateTangible: (hardwareId: string) => void; + removeActiveStateTangible: (hardwareId: string) => void; + clearActiveStateTangibles: () => void; } const DEFAULT_WEBSOCKET_URL = 'ws://localhost:3333'; @@ -60,7 +62,7 @@ export const useTuioStore = create()( // Active tangibles activeTangibles: new Map(), - lastStateChangeSource: null, + activeStateTangibles: [], addActiveTangible: (hardwareId: string, info: TuioTangibleInfo) => set((state) => { @@ -88,11 +90,27 @@ export const useTuioStore = create()( clearActiveTangibles: () => set({ activeTangibles: new Map(), - lastStateChangeSource: null, + activeStateTangibles: [], }), - setLastStateChangeSource: (hardwareId: string | null) => - set({ lastStateChangeSource: hardwareId }), + addActiveStateTangible: (hardwareId: string) => + set((state) => { + // Add to end of list if not already present + if (!state.activeStateTangibles.includes(hardwareId)) { + return { activeStateTangibles: [...state.activeStateTangibles, hardwareId] }; + } + return state; + }), + + removeActiveStateTangible: (hardwareId: string) => + set((state) => { + return { + activeStateTangibles: state.activeStateTangibles.filter((id) => id !== hardwareId), + }; + }), + + clearActiveStateTangibles: () => + set({ activeStateTangibles: [] }), }), { name: 'constellation-tuio-settings', diff --git a/src/types/timeline.ts b/src/types/timeline.ts index 2fb9ecc..8d83034 100644 --- a/src/types/timeline.ts +++ b/src/types/timeline.ts @@ -70,7 +70,7 @@ export interface TimelineActions { createState: (label: string, description?: string, cloneFromCurrent?: boolean) => StateId; // Switch to different state - switchToState: (stateId: StateId) => void; + switchToState: (stateId: StateId, fromTangible?: boolean) => void; // Update state metadata updateState: (stateId: StateId, updates: Partial>) => void;