import type { ConditionKind, Entrance, LayoutState, RoomConfig } from '../types'; interface ControlPanelProps { state: LayoutState; onStateChange: (state: LayoutState) => void; mode: 'layout' | 'optimize'; onModeChange: (mode: 'layout' | 'optimize') => void; selectedId: string | null; onSelect: (id: string | null) => void; onOptimize: () => void; optimizing: boolean; timeLeft: number; } export function ControlPanel({ state, onStateChange, mode, onModeChange, selectedId, onSelect, onOptimize, optimizing, timeLeft, }: ControlPanelProps) { const setRoom = (room: Partial) => { onStateChange({ ...state, room: { ...state.room, ...room } }); }; const setEntrance = (entrance: Partial) => { if (!state.entrance) return; onStateChange({ ...state, entrance: { ...state.entrance, ...entrance } }); }; const placeEntrance = () => { onStateChange({ ...state, entrance: { x: 20, y: 20, width: 20, height: 20 } }); }; const toggleLock = () => { if (!selectedId) return; const updated = state.furniture.map((f) => f.id === selectedId ? { ...f, lockedForOptimization: !f.lockedForOptimization } : f, ); onStateChange({ ...state, furniture: updated }); }; const updateSelectedCondition = (kind: ConditionKind, enabled: boolean) => { if (!selectedId) return; const updated = state.furniture.map((f) => { if (f.id !== selectedId) return f; const has = f.conditions.some((c) => c.kind === kind); if (enabled && !has) { const params = kind === 'near_object' ? { targetId: '' } : {}; return { ...f, conditions: [...f.conditions, { kind, weight: 1, params }] }; } if (!enabled && has) { return { ...f, conditions: f.conditions.filter((c) => c.kind !== kind) }; } return f; }); onStateChange({ ...state, furniture: updated }); }; const setNearObjectTarget = (targetId: string) => { if (!selectedId) return; const updated = state.furniture.map((f) => { if (f.id !== selectedId) return f; return { ...f, conditions: f.conditions.map((c) => (c.kind === 'near_object' ? { ...c, params: { ...c.params, targetId } } : c)), }; }); onStateChange({ ...state, furniture: updated }); }; const updateSelectedSize = (width: number, height: number) => { if (!selectedId) return; const updated = state.furniture.map((f) => f.id === selectedId ? { ...f, shape: { ...f.shape, width: Math.max(10, width), height: Math.max(10, height) } } : f, ); onStateChange({ ...state, furniture: updated }); }; const selected = state.furniture.find((f) => f.id === selectedId); return (
{mode === 'layout' && (

Room

{state.entrance && (
)}

Premade Objects

Tables: onStateChange({ ...state, objectAmounts: { ...(state.objectAmounts || {}), table: Math.max(0, Number(e.target.value)) }, }) } style={{ width: 60 }} />
Chairs: onStateChange({ ...state, objectAmounts: { ...(state.objectAmounts || {}), chair: Math.max(0, Number(e.target.value)) }, }) } style={{ width: 60 }} />

Objects

{state.entrance && (
onSelect('__entrance__')} style={{ padding: 4, background: selectedId === '__entrance__' ? '#eee' : 'transparent', cursor: 'pointer', }} > Entrance
)} {state.furniture.map((f) => (
onSelect(f.id)} style={{ padding: 4, background: selectedId === f.id ? '#eee' : 'transparent', cursor: 'pointer', }} > {f.name} {f.lockedForOptimization ? '(locked)' : ''}
))}
{selectedId === '__entrance__' && state.entrance && (
Entrance Settings
)} {selected && (
Size:
Conditions:
{(['walk_to_and_sit', 'around_open_area', 'near_entrance', 'near_object', 'accessible', 'not_blocking_path', 'open_circulation'] as ConditionKind[]).map( (k) => (
{k === 'near_object' && selected.conditions.some((c) => c.kind === 'near_object') && ( )}
), )}
)}
)} {mode === 'optimize' && (

Optimize

Runs random search (15s) then NN-informed placement heuristic.

{optimizing &&
Randomizing layouts, keeping best...
}
)}
); }