diff --git a/src/components/session/SessionView.tsx b/src/components/session/SessionView.tsx
index 87cb684c..4007da1b 100644
--- a/src/components/session/SessionView.tsx
+++ b/src/components/session/SessionView.tsx
@@ -9,7 +9,7 @@ import { useSessionDragDrop, type SessionDragState, type SessionDropTarget } fro
import { ContextMenuWrapper, ContextMenuSeparator, ContextMenuItem } from '../ui/ContextMenu';
import { ColorSwatchPalette } from '../ui/ColorSwatchPalette';
import { SessionMixer } from './SessionMixer';
-import type { Clip, Track, SessionLaunchQuantization, SessionLaunchMode, SessionClipSlot, SessionPendingLaunch, SessionScene, SceneFollowActionType } from '../../types/project';
+import type { Clip, Track, SessionLaunchQuantization, SessionLaunchMode, SessionClipSlot, SessionPendingLaunch, SessionScene, SceneFollowActionType, FollowActionType, FollowActionConfig } from '../../types/project';
const LAUNCH_MODE_OPTIONS: SessionLaunchMode[] = ['trigger', 'gate', 'toggle', 'repeat'];
@@ -80,8 +80,20 @@ interface SlotContextMenuState {
currentColor: string | null;
legato: boolean;
currentLaunchMode: SessionLaunchMode;
+ followAction?: FollowActionConfig;
}
+const CLIP_FOLLOW_ACTION_OPTIONS: { value: FollowActionType; label: string }[] = [
+ { value: 'stop', label: 'Stop' },
+ { value: 'again', label: 'Again' },
+ { value: 'previous', label: 'Previous' },
+ { value: 'next', label: 'Next' },
+ { value: 'first', label: 'First' },
+ { value: 'last', label: 'Last' },
+ { value: 'any', label: 'Any' },
+ { value: 'other', label: 'Other' },
+];
+
export function SessionView() {
const project = useProjectStore((s) => s.project);
@@ -94,6 +106,8 @@ export function SessionView() {
const setSessionSlotColor = useProjectStore((s) => s.setSessionSlotColor);
const setSessionSlotLegato = useProjectStore((s) => s.setSessionSlotLegato);
const setSessionSlotLaunchMode = useProjectStore((s) => s.setSessionSlotLaunchMode);
+ const setSessionSlotFollowAction = useProjectStore((s) => s.setSessionSlotFollowAction);
+ const setSessionFollowActionsEnabled = useProjectStore((s) => s.setSessionFollowActionsEnabled);
const selectedSessionSlot = useUIStore((s) => s.selectedSessionSlot);
const setSelectedSessionSlot = useUIStore((s) => s.setSelectedSessionSlot);
const setKeyboardContext = useUIStore((s) => s.setKeyboardContext);
@@ -135,6 +149,20 @@ export function SessionView() {
}
}, [colorMenu, setSessionSlotLaunchMode]);
+ const handleFollowActionChange = useCallback((field: string, value: string | number | boolean) => {
+ if (!colorMenu) return;
+ setSessionSlotFollowAction(colorMenu.slotId, { [field]: value });
+ // Update local state to reflect change immediately
+ setColorMenu((prev) => {
+ if (!prev) return null;
+ const defaultFA: FollowActionConfig = { actionA: 'next', actionB: 'stop', chanceA: 1, time: 4, enabled: true };
+ return {
+ ...prev,
+ followAction: { ...(prev.followAction ?? defaultFA), [field]: value },
+ };
+ });
+ }, [colorMenu, setSessionSlotFollowAction]);
+
// Set keyboard context to 'session' on mount, restore previous on unmount
useEffect(() => {
const previousScope = useUIStore.getState().keyboardContext.scope;
@@ -166,6 +194,7 @@ export function SessionView() {
const sessionSlots = project.session?.slots ?? [];
const pendingLaunches = project.session?.pendingLaunches ?? [];
const scenes = project.session?.scenes ?? [];
+ const followActionsEnabled = project.session?.followActionsEnabled !== false;
return (
@@ -190,6 +219,17 @@ export function SessionView() {
))}
+