Files
Aislo/B07_DesignDetail/openwebcad/src/tools/annotate/text-tools.ts
T
eomsangdonandClaude Opus 5 9bf6de9b10 fix(B07): 잠금 도면층을 집던 경로 다섯 곳을 마저 닫는다
앞선 감사가 불완전했다. 같은 부류로 도각·원지반을 건드리던 곳이 더 있었다.

- select-tool.helpers pickEntityAt: 클릭 선택 후보에 잠금 객체가 섞여
  도각을 물면 아무 일도 안 일어나는 죽은 클릭이 됐다.
- eraser-tool: 자르기의 교차점 계산이 도각 선을 절단 경계로 썼다.
- property-tools OVERKILL: 선택이 없으면 전체가 대상이라 도각까지 지웠다.
- text-tools 찾기/바꾸기: 도각 표제란 글자를 바꿔 버렸다.
- selection-tools 유형/유사 선택: 잠금 객체까지 세어 토스트 개수가 틀렸다.

전부 getPickableEntities()로 바꾼다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-31 15:48:08 +09:00

114 lines
3.7 KiB
TypeScript

/** 문자 명령 — 여러 줄 문자·단일 행 문자·편집·찾기 (조사표 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}개 문자를 찾았습니다.`);
},
});