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:
@@ -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)}`;
|
||||
}
|
||||
Reference in New Issue
Block a user