/** 문자 명령 — 여러 줄 문자·단일 행 문자·편집·찾기 (조사표 5절 문자 패널) */ import { Point } from '@flatten-js/core'; import { toast } from 'react-toastify'; import { getAnnotationScale } from '../../commands/dim-settings'; import { EntityName } from '../../entities/Entity'; import type { Entity } from '../../entities/Entity'; import type { TextEntity } from '../../entities/TextEntity'; import { addEntities, getActiveTextStyle, getEntities, getPickableEntities, setEntities, } from '../../state'; import { Tool } from '../../tools'; import { textEntity } from '../factories/entity-factory'; import { createSequenceTool } from '../factories/sequence-tool'; /** AutoCAD 여러 줄 문자의 줄바꿈 표기(\P)와 \n을 모두 받는다 */ const splitLines = (text: string): string[] => text .replace(/\\P/gi, '\n') .split('\n') .map((line) => line.trim()) .filter((line) => line.length > 0); function buildTextLines(lines: string[], basePoint: Point): Entity[] { const lineHeight = getActiveTextStyle().fontSize * getAnnotationScale() * 1.35; const groupId = lines.length > 1 ? crypto.randomUUID() : undefined; return lines.map((line, index) => { const entity = textEntity(line, new Point(basePoint.x, basePoint.y - lineHeight * index), { textAlign: 'left', fontSize: getActiveTextStyle().fontSize * getAnnotationScale(), }); entity.groupId = groupId; return entity; }); } export const textToolStateMachine = createSequenceTool({ tool: Tool.TEXT, steps: [ { kind: 'point', instructions: '문자의 시작점을 지정하십시오.' }, { kind: 'text', instructions: '문자를 입력하십시오.' }, ], commit: (input) => { const lines = splitLines(input.text(1)); if (!lines.length) return; addEntities(buildTextLines(lines.slice(0, 1), input.point(0)), true); }, }); export const mtextToolStateMachine = createSequenceTool({ tool: Tool.MTEXT, steps: [ { kind: 'point', instructions: '여러 줄 문자의 첫 코너를 지정하십시오.' }, { kind: 'text', instructions: '문자를 입력하십시오 (줄바꿈은 \\P).' }, ], commit: (input) => { const lines = splitLines(input.text(1)); if (!lines.length) return; addEntities(buildTextLines(lines, input.point(0)), true); }, }); export const textEditToolStateMachine = createSequenceTool({ tool: Tool.TEXTEDIT, helpers: false, steps: [ { kind: 'entity', instructions: '편집할 문자를 선택하십시오.' }, { kind: 'text', instructions: '새 문자를 입력하십시오.' }, ], commit: (input) => { const entity = input.entity(0); if (entity.getType() !== EntityName.Text) { toast.warn('문자 객체를 선택하십시오.'); return; } (entity as TextEntity).setLabel(input.text(1)); setEntities([...getEntities()], true); }, }); export const findToolStateMachine = createSequenceTool({ tool: Tool.FIND, helpers: false, steps: [ { kind: 'text', instructions: '찾을 문자열을 입력하십시오.' }, { kind: 'text', instructions: '바꿀 문자열을 입력하십시오 (그대로 두려면 ENTER).', defaultValue: '', }, ], commit: (input) => { const needle = input.text(0); const replacement = input.text(1); let found = 0; let replaced = 0; for (const entity of getPickableEntities()) { if (entity.getType() !== EntityName.Text) continue; const text = entity as TextEntity; if (!text.getLabel().includes(needle)) continue; found += 1; if (replacement) { text.setLabel(text.getLabel().split(needle).join(replacement)); replaced += 1; } } if (replaced) setEntities([...getEntities()], true); toast.info(replaced ? `${replaced}개 문자를 바꿨습니다.` : `${found}개 문자를 찾았습니다.`); }, });