task(A4.6): migrate move/copy tools to v2 with selection-based workflow

This commit is contained in:
Agent Zero
2026-08-27 00:53:16 +02:00
parent 0c852d18ee
commit ca1c3c08f3
2 changed files with 172 additions and 4 deletions
@@ -6,6 +6,7 @@
* Marquee/Box-Auswahl Migration folgt in A4 (Legacy bleibt parallel aktiv).
*/
import type { PluginV2, ToolExtensionV2 } from '../../types';
import type { CADElement } from '../../../types/cad.types';
/**
* select-Werkzeug: Klick wählt Element direkt (Shift=additiv, Ctrl=subtraktiv).
@@ -85,16 +86,98 @@ export const hatchTool: ToolExtensionV2 = {
},
};
/** V2-Plugin: Kern-Bearbeitungswerkzeuge (Pilot: select; A4.5: hatch). */
/**
* Move/Copy-Basispunkt (A4.6): erster down setzt ihn, zweiter down committet.
* Gemeinsam für beide Tools (klick-progressiv wie arc-Lektion).
*/
let modBasePoint: import('../../../tools/modification/geometry').Pt | null = null;
/**
* Fabrik für move/copy-Werkzeuge (A4.6).
* Wirkt auf die AKTUELLE SELEKTION (SelectionBridge):
* - Klick 1: Basispunkt setzen
* - Klick 2: Commit — move: updateElement(x±dx,y±dy); copy: addElement der
* versetzten Kopien (neue IDs). Alles in EINER Transaktion = 1 Undo-Schritt.
* Legacy-Konvention: Versatzvektor = zweiterKlick basis.
*/
function makeMoveCopyTool(mode: 'move' | 'copy'): ToolExtensionV2 {
const label = mode === 'move' ? 'Verschieben' : 'Kopieren';
return {
manifest: {
id: mode,
label,
icon: mode === 'move' ? '\u27a4' : '\u29c9',
ribbonTab: 'canvas',
tags: ['basic'],
description: `${label}: Auswahl treffen, dann Basis→Ziel klicken`,
},
optionsSchema: [],
handlers: {
down(e, ctx) {
const c = ctx as import('../../types').FullToolContext;
if (!c.doc || !c.selection) return;
if (!modBasePoint) {
const ids = c.selection.getIds();
if (ids.length === 0) {
// Komfort: nichts selektiert → hitTest und sofort auswählen
const hit = c.selection.hitTest(e.world.x, e.world.y, 5);
if (!hit) {
ctx.setStatus(`${label}: zuerst Element(e) auswählen`);
return;
}
c.selection.setIds([hit.id]);
}
modBasePoint = e.world;
ctx.setStatus(`${label}: Zielklick zum ${mode === 'move' ? 'Verschieben' : 'Kopieren'} (${c.selection.getIds().length} Elemente)`);
return;
}
// Zweiter Klick → Commit
const dx = e.world.x - modBasePoint.x;
const dy = e.world.y - modBasePoint.y;
const ids = c.selection.getIds();
c.doc.transact(() => {
for (const id of ids) {
const el = c.doc!.getElement(id);
if (!el) continue;
if (mode === 'move') {
c.doc!.updateElement(id, { x: el.x + dx, y: el.y + dy });
} else {
const copy: CADElement = {
...el,
id: `cp_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}_${ids.indexOf(id)}`,
x: el.x + dx,
y: el.y + dy,
};
c.doc!.addElement(copy);
}
}
});
ctx.setStatus(`${label}: ${ids.length} Element(e), \u0394(${dx.toFixed(0)}, ${dy.toFixed(0)})`);
modBasePoint = null;
},
cancel(ctx) {
modBasePoint = null;
ctx.setStatus(`${label} abgebrochen`);
},
},
};
}
export const moveTool: ToolExtensionV2 = makeMoveCopyTool('move');
export const copyTool: ToolExtensionV2 = makeMoveCopyTool('copy');
/** V2-Plugin: Kern-Bearbeitungswerkzeuge (select, hatch; A4.6: move/copy). */
export const coreModifyPlugin: PluginV2 = {
manifest: {
id: 'core-modify',
name: 'Bearbeiten (Kern)',
version: '1.1.0',
version: '1.2.0',
author: 'web-cad team',
description: 'Auswahl und Bearbeitung (V2: Selektion, Schraffur).',
description: 'Auswahl, Schraffur, Verschieben, Kopieren (V2).',
category: 'tools',
enabledByDefault: true,
},
tools: [selectTool, hatchTool],
tools: [selectTool, hatchTool, moveTool, copyTool],
};