mirror of
https://github.com/OFFIS-ESC/constellation-analyzer
synced 2026-01-27 07:43:41 +00:00
Fix state tangible tracking and manual state switch behavior
Issues fixed: 1. State tangibles not working after manual state switch 2. No support for multiple simultaneous state tangibles Changes: - Replace lastStateChangeSource with activeStateTangibles array - Track active state tangibles in order of placement - When removing a state tangible, switch to the last remaining one - Clear activeStateTangibles on manual state switch - Add fromTangible parameter to switchToState to distinguish sources - Always switch to newly placed tangible's state (last added wins) New behavior: - Place tangible A -> switch to state A - Manually switch to state B -> clears active tangibles list - Place tangible A again -> switches back to state A - Place tangible A and B simultaneously -> shows state B (last wins) - Remove tangible B -> switches to state A - Remove tangible A -> stays in current state Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
d5450610f1
commit
520eef879e
4 changed files with 72 additions and 19 deletions
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<TimelineStore & TimelineActions>(
|
|||
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<TimelineStore & TimelineActions>(
|
|||
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
|
||||
|
|
|
|||
|
|
@ -29,12 +29,14 @@ interface TuioState {
|
|||
|
||||
// Active tangibles (runtime only - not persisted)
|
||||
activeTangibles: Map<string, TuioTangibleInfo>;
|
||||
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<TuioState>()(
|
|||
|
||||
// Active tangibles
|
||||
activeTangibles: new Map(),
|
||||
lastStateChangeSource: null,
|
||||
activeStateTangibles: [],
|
||||
|
||||
addActiveTangible: (hardwareId: string, info: TuioTangibleInfo) =>
|
||||
set((state) => {
|
||||
|
|
@ -88,11 +90,27 @@ export const useTuioStore = create<TuioState>()(
|
|||
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',
|
||||
|
|
|
|||
|
|
@ -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<Pick<ConstellationState, 'label' | 'description' | 'metadata'>>) => void;
|
||||
|
|
|
|||
Loading…
Reference in a new issue