task(CAD-5): mline tool (parallel double line with miter offsets + optional end caps) + block editor service (open copies / save back / discard) with block-edit tool

This commit is contained in:
Agent Zero
2026-08-31 00:53:08 +02:00
parent 7331f5fb88
commit 0ffe954559
4 changed files with 595 additions and 2 deletions
@@ -0,0 +1,94 @@
/**
* Task CAD-5 Block-Editor-Service.
*
* openBlockForEdit legt markierte KOPIEN der Block-Elemente ins
* Dokument (Original unangetastet); saveBlockEdit schreibt die
* bearbeiteten Kopien als neue Blockdefinition zurueck und
* raeumt die Edit-Kopien auf; discardBlockEdit verwirft alles.
* Marker: BLOCK_EDIT_MARKER (properties-Flag + __blockEdit-IDs).
*/
import type { CADElement, BlockDefinition } from '../types/cad.types';
import type { CADDocument } from '../kernel/document/CADDocument';
/** Marker-Flag in properties der Edit-Kopien. */
export const BLOCK_EDIT_MARKER = '__blockEdit';
/** Aktive Edit-Sitzung (Service-State). */
let editSession: { blockId: string; copyIds: string[] } | null = null;
/**
* Oeffnet einen Block zur Bearbeitung: Kopien aller Elemente mit
* Edit-Marker werden ins Dokument gelegt (Original bleibt).
* @returns true wenn geoeffnet, false bei unbekannter ID oder
* bereits offener Sitzung.
*/
export function openBlockForEdit(doc: CADDocument, blockId: string): boolean {
if (editSession) return false;
const block = doc.getBlock(blockId);
if (!block) return false;
const copyIds: string[] = [];
doc.transact(() => {
for (const el of block.elements) {
const copy: CADElement = {
...el,
id: `__blockEdit_${blockId}_${copyIds.length}`,
properties: {
...(el.properties as Record<string, unknown>),
[BLOCK_EDIT_MARKER]: true,
},
} as unknown as CADElement;
doc.addElement(copy);
copyIds.push(copy.id);
}
});
editSession = { blockId, copyIds };
return true;
}
/**
* Speichert die Bearbeitung: die markierten Kopien werden als
* neue Elementliste in die Blockdefinition geschrieben (Marker
* entfernt); Edit-Kopien werden aus dem Dokument geloescht.
* @returns blockId der gespeicherten Definition oder null.
*/
export function saveBlockEdit(doc: CADDocument): string | null {
if (!editSession) return null;
const { blockId, copyIds } = editSession;
const elements: CADElement[] = [];
for (const id of copyIds) {
const el = doc.getElement(id);
if (!el) continue;
const { [BLOCK_EDIT_MARKER]: _marker, ...cleanProps } =
el.properties as Record<string, unknown>;
elements.push({ ...el, id: uid('blk'), properties: cleanProps } as unknown as CADElement);
}
const block = doc.getBlock(blockId);
if (block) {
doc.addBlock({ ...block, elements });
}
doc.deleteElements(copyIds);
editSession = null;
return blockId;
}
/**
* Verwirft die Bearbeitung: Edit-Kopien werden geloescht, die
* Blockdefinition bleibt unveraendert.
* @returns true wenn verworfen, false ohne offene Sitzung.
*/
export function discardBlockEdit(doc: CADDocument): boolean {
if (!editSession) return false;
doc.deleteElements(editSession.copyIds);
editSession = null;
return true;
}
/** Ist gerade eine Block-Bearbeitung offen? */
export function isBlockEditOpen(): boolean {
return editSession !== null;
}
let uidCounter = 0;
function uid(prefix: string): string {
return `${prefix}_${Date.now().toString(36)}_${uidCounter++}_${Math.random().toString(36).slice(2, 8)}`;
}