# Phase 3: Drawing Tools — React Wiring & State Management ## Goal Wire Phase 1 canvas/interaction engines to React state so drawing tools actually create, render, and manage elements. Implement undo/redo, command-line shortcuts, and drawing flow improvements. ## Requirements Covered - F-CAD-01: Zeichnen von Grundelementen (Linie, Kreis, Bogen, Rechteck, Polygon, Polylinie) - F-CAD-03: Bemaßung - F-CAD-05: Command Line (L, C, PL, R, A, T, DIM shortcuts) - F-CAD-09: Undo/Redo mit History - F-CAD-11: Text ## Current State - `src/interaction/index.ts` (591 lines): InteractionEngine with drawing logic for all types, callbacks (onElementCreated, onElementsDeleted, onToolStateChanged, onCursorMoved, onCommandTrigger) - `src/canvas/RenderEngine.ts` (588 lines): Renders all element types - `src/components/CanvasArea.tsx` (103 lines): Creates engine instances in useEffect but does NOT wire callbacks to React state - `src/App.tsx` (223 lines): Has mock state but no element management, no engine ref, no undo/redo ## Tasks ### Task 1: Refactor CanvasArea to expose engine instances File: `src/components/CanvasArea.tsx` Current: engines created in useEffect, no external access. Required: - Use `useRef` to hold engine instances (InteractionEngine, RenderEngine, ZoomPanController, etc.) - Accept new props: `onElementCreated`, `onElementsDeleted`, `onCursorMoved`, `onToolStateChanged`, `onToolChange` (tool from App → engine), `elements` (element array → engine.setElements), `snapEnabled`, `orthoEnabled`, `gridEnabled` (from App → engine state) - In useEffect: create engines, wire all callbacks to props, call `interaction.setCallbacks({...})` - Add a separate useEffect for `elements` changes → `interaction.setElements(elements)` + `spatialIndex.bulkInsert(elements)` + `renderEngine.render()` - Add a separate useEffect for `snapEnabled/orthoEnabled/gridEnabled` → update engine state + renderEngine options - Add a separate useEffect for `activeTool` → `interaction.setTool(tool)` - Expose zoomPan via ref callback prop `onZoomPanReady` so App can call zoomFit - Add `onZoomIn`, `onZoomOut`, `onZoomFit` to actually call zoomPan methods (not just log) - Add double-click handler: on dblclick, if drawing polyline/polygon → call confirmDraw via interaction New CanvasAreaProps (add to `src/types/ui.types.ts`): ```typescript export interface CanvasAreaProps { cursorPos: CursorPos; viewMode: ViewMode; onViewChange: (mode: ViewMode) => void; gridEnabled: boolean; orthoEnabled: boolean; snapEnabled: boolean; activeTool: string; elements: CADElement[]; onElementCreated: (el: CADElement) => void; onElementsDeleted: (ids: string[]) => void; onCursorMoved: (x: number, y: number) => void; onToolStateChanged: (state: ToolState) => void; onToggleGrid: () => void; onToggleOrtho: () => void; onToggleSnap: () => void; onZoomIn: () => void; onZoomOut: () => void; onZoomFit: () => void; } ``` ### Task 2: Implement undo/redo stack in App.tsx File: `src/App.tsx` Required: - Add `elements` state: `useState([])` - Add `undoStack` and `redoStack` as `useState` - `handleElementCreated`: push current elements to undoStack, add new element, clear redoStack - `handleElementsDeleted`: push current elements to undoStack, remove deleted, clear redoStack - `handleUndo`: if undoStack not empty, push current to redoStack, pop undoStack → set elements - `handleRedo`: if redoStack not empty, push current to undoStack, pop redoStack → set elements - Pass `elements` to CanvasArea - Pass `onElementCreated`, `onElementsDeleted` to CanvasArea - Wire `onCursorMoved` to update `cursorPos` state - Wire `onToolStateChanged` to update any relevant UI state ### Task 3: Wire tool selection from LeftSidebar to CanvasArea File: `src/App.tsx` Required: - `activeTool` state already exists in App.tsx - Pass `activeTool` to CanvasArea as prop - CanvasArea useEffect watches `activeTool` → calls `interaction.setTool(tool as ToolType)` - LeftSidebar `onToolChange` already updates `activeTool` in App ### Task 4: Command line shortcuts (F-CAD-05) File: `src/App.tsx` Required: - In `handleCommand(cmd)`, parse command and map to tool: - `L` or `LINE` → setTool('line') - `C` or `CIRCLE` → setTool('circle') - `A` or `ARC` → setTool('arc') - `R` or `RECT` or `RECTANGLE` → setTool('rect') - `PL` or `POLYLINE` → setTool('polyline') - `POL` or `POLYGON` → setTool('polygon') - `T` or `TEXT` → setTool('text') - `DIM` or `DIMENSION` → setTool('dimension') - `V` or `SELECT` → setTool('select') - `P` or `PAN` → setTool('pan') - `M` or `MOVE` → setTool('move') - `CO` or `COPY` → setTool('copy') - `RO` or `ROTATE` → setTool('rotate') - `SC` or `SCALE` → setTool('scale') - `MI` or `MIRROR` → setTool('mirror') - `DEL` or `ERASE` → setTool('delete') - `UNDO` or `U` → handleUndo() - `REDO` → handleRedo() - Add command to history with prefix '›' - Add response to history with prefix '·' (e.g. 'Linie-Werkzeug aktiv · Klicken zum Starten') ### Task 5: Drawing flow improvements File: `src/interaction/index.ts` Required: - **Polyline/Polygon**: Add `handleDoubleClick` method — if activeTool is polyline/polygon and phase is drawing, call confirmDraw() - Wire dblclick event in `attach()`: `this.addListener('dblclick', this.onDoubleClick.bind(this))` - **Arc**: Improve 3-point arc — first click = center, second click = start point (sets radius + startAngle), third click = end point (sets endAngle). Update handleDrawDown to handle multi-point arc. - **Text**: After placing text element, trigger an inline edit prompt. For now, use a simple `prompt()` dialog or add `onTextEdit` callback. ### Task 6: Grid/Snap/Ortho toggle wiring File: `src/components/CanvasArea.tsx` Required: - When `gridEnabled` prop changes: `renderEngine.setOptions({ showGrid: gridEnabled })` + re-render - When `snapEnabled` prop changes: `interaction.state.snapEnabled = snapEnabled` + `renderEngine.setOptions({ showSnapPoints: snapEnabled })` + re-render - When `orthoEnabled` prop changes: `interaction.state.ortho = orthoEnabled` + `renderEngine.setOptions({ showOrtho: orthoEnabled })` + re-render ## Constraints - TypeScript functional components, no inline styles (except where mockup uses style) - No styled-components, no Tailwind - `npx tsc --noEmit` must pass with 0 errors - `npx vite build` must succeed - Minimal changes — extend existing files, don't rewrite - Keep all existing CSS class names - Import ToolState type from interaction/index.ts where needed ## File Summary 1. `src/types/ui.types.ts` — update CanvasAreaProps 2. `src/components/CanvasArea.tsx` — expose engines, wire callbacks, add useEffects 3. `src/App.tsx` — element state, undo/redo, command shortcuts, wire all callbacks 4. `src/interaction/index.ts` — double-click handler, arc 3-point, text edit callback ## Test Criteria 1. `npx tsc --noEmit` — 0 errors 2. `npx vite build` — success 3. Drawing a line: select Line tool → click start → move mouse → Enter → element appears 4. Drawing a rect: select Rect tool → click corner → move mouse → Enter → element appears 5. Drawing a circle: select Circle tool → click center → move mouse → Enter → element appears 6. Polyline: select Polyline → click multiple points → double-click → element appears 7. Command line: type 'L' → line tool activates 8. Undo/Redo: draw element → Ctrl+Z → element disappears → Ctrl+Y → element reappears 9. Grid toggle: click grid button → grid appears/disappears 10. Snap toggle: click snap button → snap points appear/disappear on hover