task(D4): mtext tool - multiline text with line breaks, optional frame rect in same transaction (1 undo), fontSize option

This commit is contained in:
Agent Zero
2026-08-29 03:21:49 +02:00
parent b8b67ec7ec
commit fbc4978a40
2 changed files with 169 additions and 2 deletions
@@ -127,15 +127,81 @@ export const dimensionTool: ToolExtensionV2 = make2PointAnnotate('dimension', 'B
export const leaderTool: ToolExtensionV2 = make2PointAnnotate('leader', 'Leader', '\u21b1', buildLeader);
/** V2-Plugin: Beschriftung/Bemaßung (A4.4). */
// ─────────────────────────────────────────────────────────────
// Task D4: MTEXT — Mehrzeiliger Text mit optionalem Rahmen.
// Klick platziert Text (Inhalt aus Options, Zeilenumbrüche erhalten),
// frame-Option erzeugt ein rect in derselben Transaktion (1 Undo).
// ─────────────────────────────────────────────────────────────
export const mtextTool: ToolExtensionV2 = {
manifest: {
id: 'mtext',
label: 'Mehrzeilentext',
icon: '¶',
ribbonTab: 'format',
tags: ['basic'],
description: 'Mehrzeiligen Text platzieren (Rahmen optional, Task D4)',
},
optionsSchema: [
{ key: 'text', label: 'Text', type: 'text' },
{ key: 'fontSize', label: 'Größe', type: 'number', min: 6, max: 72 },
{ key: 'frame', label: 'Rahmen', type: 'checkbox' },
],
handlers: {
down(e, ctx) {
const c = ctx as FullToolContext;
if (!c.doc) return;
const layerId = (c.options.layerId as string | undefined) ?? 'layer-0';
const text = (c.options.text as string | undefined) ?? '';
const fontSize = (c.options.fontSize as number | undefined) ?? 12;
const frame = (c.options.frame as boolean | undefined) ?? false;
// Newline ohne Escape-Probleme: charCode 10
const NL = String.fromCharCode(10);
const lines = text.split(NL);
const lineCount = Math.max(1, lines.length);
const maxLen = lines.reduce((m, l) => Math.max(m, l.length), 0);
const textW = maxLen * fontSize * 0.6;
const textH = lineCount * fontSize * 1.4;
const els: CADElement[] = [{
id: uid('mtext'),
type: 'text',
layerId,
x: e.world.x,
y: e.world.y,
width: textW,
height: textH,
properties: { text, fontSize, mtext: true },
} as unknown as CADElement];
if (frame) {
const pad = fontSize * 0.4;
els.push({
id: uid('mtextframe'),
type: 'rect',
layerId,
x: e.world.x,
y: e.world.y,
width: textW + pad * 2,
height: textH + pad * 2,
properties: { stroke: '#9aa0a6', strokeWidth: 1, fill: 'none' },
} as unknown as CADElement);
}
c.doc.transact(() => {
for (const el of els) c.doc!.addElement(el);
});
ctx.setStatus(`Mehrzeilentext platziert (${lineCount} Zeile(n)${frame ? ', mit Rahmen' : ''})`);
},
},
};
export const coreAnnotatePlugin: PluginV2 = {
manifest: {
id: 'core-annotate',
name: 'Beschriftung (Kern)',
version: '1.0.0',
version: '1.1.0',
author: 'web-cad team',
description: 'Text, Bemaßung, Leader (V2).',
category: 'tools',
enabledByDefault: true,
},
tools: [textTool, dimensionTool, leaderTool],
tools: [textTool, dimensionTool, leaderTool, mtextTool],
};