/** * core-drawing – Built-in V2-Plugin (Task A3 Pilot). * * Werkzeuge: line (Migrations-Pilot aus dem Legacy-Switch). * Elemente werden über CADDocument committed → kollaborativ korrektes Undo. * * Sitzungszustand (Startpunkt der aktuellen Linie) lebt als Modul-Member, * NICHT in options: Options sind geteilter UI-Store-Zustand. */ import type { PluginV2, ToolExtensionV2, FullToolContext } from '../../types'; import type { CADElement } from '../../../types/cad.types'; import type { Pt } from '../../../tools/modification/geometry'; const uid = (prefix: string): string => `${prefix}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 9)}`; /** Startpunkt der laufenden Linie (nur innerhalb einer down→up-Sitzung gesetzt). */ let lineStart: Pt | null = null; /** Startpunkt des laufenden Rechtecks (A4.2). */ let rectStart: Pt | null = null; function buildLine(start: Pt, end: Pt, ctx: FullToolContext): CADElement { const stroke = (ctx.options.strokeColor as string | undefined) ?? '#e0e0f0'; const layerId = (ctx.options.layerId as string | undefined) ?? 'layer-0'; return { id: uid('line'), type: 'line', layerId, x: (start.x + end.x) / 2, y: (start.y + end.y) / 2, width: Math.abs(end.x - start.x), height: Math.abs(end.y - start.y), properties: { x1: start.x, y1: start.y, x2: end.x, y2: end.y, stroke, strokeWidth: 1 }, } as unknown as CADElement; } function buildRect(cornerA: Pt, cornerB: Pt, ctx: FullToolContext): CADElement { const stroke = (ctx.options.strokeColor as string | undefined) ?? '#e0e0f0'; const layerId = (ctx.options.layerId as string | undefined) ?? 'layer-0'; const minX = Math.min(cornerA.x, cornerB.x); const minY = Math.min(cornerA.y, cornerB.y); const w = Math.abs(cornerB.x - cornerA.x); const h = Math.abs(cornerB.y - cornerA.y); return { id: uid('rect'), type: 'rect', layerId, x: minX + w / 2, // BBox-Zentrum (Legacy-Konvention) y: minY + h / 2, width: w, height: h, properties: { stroke, strokeWidth: 1 }, } as unknown as CADElement; } /** * line-Werkzeug: down setzt Startpunkt, move zeigt Live-Vorschau, * up committet via doc.transact (1 Linie = 1 Undo-Schritt). */ export const lineTool: ToolExtensionV2 = { manifest: { id: 'line', label: 'Linie', icon: '\u2571', ribbonTab: 'canvas', tags: ['basic'], description: 'Zeichnet eine Linie (Klick Start, Klick Ende)', }, optionsSchema: [ { key: 'strokeColor', label: 'Farbe', type: 'color' }, ], handlers: { down(e, ctx) { lineStart = e.world; ctx.setStatus(`Linie ab (${lineStart.x.toFixed(0)}, ${lineStart.y.toFixed(0)}) – Ende wählen`); }, move(e, ctx) { if (!lineStart) return; ctx.setPreview?.(buildLine(lineStart, e.world, ctx)); }, up(e, ctx) { const c = ctx as FullToolContext; if (!lineStart || !c.doc) { lineStart = null; return; } const el = buildLine(lineStart, e.world, c); c.doc.transact(() => { // addElement öffnet inneres transact — Yjs verschachtelt sie → EIN Undo-Schritt c.doc!.addElement(el); }); lineStart = null; ctx.setPreview?.(null); ctx.setStatus(`Linie erstellt (${el.id})`); }, cancel(ctx) { lineStart = null; ctx.setPreview?.(null); ctx.setStatus('Linie abgebrochen'); }, }, }; /** * rect-Werkzeug (A4.2): down setzt Ecke, move zeigt BBox-Vorschau, * up committet via doc.transact. Portiert aus Legacy case 'rect' * (BBox-Konvention: x/y = Zentrum, width/height absolut). */ export const rectTool: ToolExtensionV2 = { manifest: { id: 'rect', label: 'Rechteck', icon: '\u25ad', ribbonTab: 'canvas', tags: ['basic'], description: 'Zieht ein Rechteck auf (Klick Ecke, Klick Gegenecke)', }, optionsSchema: [ { key: 'strokeColor', label: 'Farbe', type: 'color' }, ], handlers: { down(e, ctx) { rectStart = e.world; ctx.setStatus(`Rechteck ab (${rectStart.x.toFixed(0)}, ${rectStart.y.toFixed(0)}) – Gegenecke wählen`); }, move(e, ctx) { if (!rectStart) return; ctx.setPreview?.(buildRect(rectStart, e.world, ctx)); }, up(e, ctx) { const c = ctx as FullToolContext; if (!rectStart || !c.doc) { rectStart = null; return; } const el = buildRect(rectStart, e.world, c); c.doc.transact(() => { c.doc!.addElement(el); }); rectStart = null; ctx.setPreview?.(null); ctx.setStatus(`Rechteck erstellt (${el.id})`); }, cancel(ctx) { rectStart = null; ctx.setPreview?.(null); ctx.setStatus('Rechteck abgebrochen'); }, }, }; /** V2-Plugin: Kern-Zeichenwerkzeuge (Pilot: line; A4.2: rect). */ export const coreDrawingPlugin: PluginV2 = { manifest: { id: 'core-drawing', name: 'Zeichnen (Kern)', version: '1.1.0', author: 'web-cad team', description: 'Grundlegende Zeichenwerkzeuge (V2: Linie, Rechteck).', category: 'tools', enabledByDefault: true, }, tools: [lineTool, rectTool], };