task(A4.1): wire dispatcher to canvas - doc bridge, selection bridge, activeTool sync

This commit is contained in:
Agent Zero
2026-08-26 23:10:20 +02:00
parent 09a120d800
commit d54a67662b
+36 -5
View File
@@ -14,6 +14,9 @@ import { GroupManager } from '../tools/modification/GroupTool';
import { formatCoordinate } from '../utils/format'; import { formatCoordinate } from '../utils/format';
import { InteractionDispatcher } from '../interaction/dispatcher'; import { InteractionDispatcher } from '../interaction/dispatcher';
import { logger } from '../utils/logger'; import { logger } from '../utils/logger';
import { CADDocument } from '../kernel/document/CADDocument';
import { YjsDocument } from '../crdt/YjsDocument';
import { pluginRegistry } from '../plugins';
const CanvasArea: React.FC<CanvasAreaProps> = ({ const CanvasArea: React.FC<CanvasAreaProps> = ({
cursorPos, viewMode, onViewChange, gridEnabled, orthoEnabled, snapEnabled, cursorPos, viewMode, onViewChange, gridEnabled, orthoEnabled, snapEnabled,
@@ -29,6 +32,8 @@ const CanvasArea: React.FC<CanvasAreaProps> = ({
const renderEngineRef = useRef<RenderEngine | null>(null); const renderEngineRef = useRef<RenderEngine | null>(null);
const interactionRef = useRef<InteractionEngine | null>(null); const interactionRef = useRef<InteractionEngine | null>(null);
const dispatcherRef = useRef<InteractionDispatcher | null>(null); const dispatcherRef = useRef<InteractionDispatcher | null>(null);
/** Bereits an onElementCreated gemeldete V2-Element-IDs (verhindert Doppelmeldung bei jedem onChanged-Frame). */
const announcedV2Ids = useRef<Set<string>>(new Set());
const spatialIndexRef = useRef<SpatialIndex | null>(null); const spatialIndexRef = useRef<SpatialIndex | null>(null);
const layerManagerRef = useRef<LayerManager | null>(null); const layerManagerRef = useRef<LayerManager | null>(null);
const selectionEngineRef = useRef<SelectionEngine | null>(null); const selectionEngineRef = useRef<SelectionEngine | null>(null);
@@ -47,17 +52,38 @@ const CanvasArea: React.FC<CanvasAreaProps> = ({
canvas, zoomPan, renderEngine, snapEngine, selectionEngine, spatialIndex, layerManager, canvas, zoomPan, renderEngine, snapEngine, selectionEngine, spatialIndex, layerManager,
); );
// ── Task A2: V2-Tool-Dispatcher hinter Feature-Flag ── // ── Task A2/A4: V2-Tool-Dispatcher hinter Feature-Flag ──
// Flag VITE_TOOL_DISPATCHER=v2 (in .env / Shell): aktiviert den neuen // Flag VITE_TOOL_DISPATCHER=v2: aktiviert den InteractionDispatcher UND
// InteractionDispatcher parallel zur Legacy InteractionEngine. // verdrahtet ihn mit einem lokalen CADDocument + SelectionBridge (Task A4.1).
// Tools mit handlers werden dann über die Plugin-API v2 geroutet.
if (import.meta.env.VITE_TOOL_DISPATCHER === 'v2') { if (import.meta.env.VITE_TOOL_DISPATCHER === 'v2') {
const ydoc = new YjsDocument();
ydoc.data.layers.set('layer-0', {
id: 'layer-0', name: 'Standard', visible: true, locked: false,
color: '#ffffff', lineType: 'solid', transparency: 0, sortOrder: 0, parentId: null,
} as never);
const v2Doc = new CADDocument(ydoc);
// Committete V2-Elemente fließen über den etablierten Kanal in UI/State:
v2Doc.onChanged(() => {
for (const el of v2Doc.getAllElements()) {
if (!announcedV2Ids.current.has(el.id)) {
announcedV2Ids.current.add(el.id);
onElementCreated(el);
}
}
});
dispatcherRef.current = new InteractionDispatcher(canvas, { dispatcherRef.current = new InteractionDispatcher(canvas, {
zoomPan, zoomPan,
setStatus: (msg) => { setStatus: (msg) => {
/* StatusBar-Bridge folgt in A3 */ /* StatusBar-Bridge folgt in A4 */
}, },
setPreview: (el) => renderEngine.setPreviewElement(el as CADElement | null), setPreview: (el) => renderEngine.setPreviewElement(el as CADElement | null),
getDoc: () => v2Doc,
getSelectionBridge: () => ({
getIds: () => Array.from(selectionEngine.getSelectedIds()),
setIds: (ids) => selectionEngine.selectByIds(ids, false),
hitTest: (wx, wy, tol) => renderEngine.hitTest(wx, wy, tol),
}),
}); });
logger.info('InteractionDispatcher v2 aktiviert (VITE_TOOL_DISPATCHER=v2)'); logger.info('InteractionDispatcher v2 aktiviert (VITE_TOOL_DISPATCHER=v2)');
} }
@@ -249,6 +275,11 @@ const CanvasArea: React.FC<CanvasAreaProps> = ({
const interaction = interactionRef.current; const interaction = interactionRef.current;
if (!interaction) return; if (!interaction) return;
interaction.setTool(activeTool as ToolType); interaction.setTool(activeTool as ToolType);
// Task A4.1: V2-Werkzeuge zusätzlich an den Dispatcher routen (Flag aktiv).
// Legacy bleibt parallel aktiv für noch nicht migrierte Tools.
dispatcherRef.current?.setActive(
pluginRegistry.getToolV2(activeTool) ? activeTool : null,
);
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [activeTool]); }, [activeTool]);