/** * 부모 화면 ↔ CAD 표 메시지(M02 41장 · 면적산출 범위 → 도면 표). 짝 = `ui_template/cad_host/cad_host.ts`. * place-table{entity, link} 표 JSON(TableEntity 꼴) → `style.연결 = link` 로 표 놓기 도구(PLACETABLE) 시작 * update-table{link, cells, preview?} `style.연결 === link` 인 표의 칸만 갈아 끼움(자리 · 크기 그대로 · 되돌리기 한 걸음) * → 부모에 table-updated{link, count} · preview 면 보기 전용이어도 갈음(M02 면적 도면 패널 · 112-1) * place-cancelled{} (CAD → 부모) 표를 놓지 않고 Esc 로 끝남 * 놓기 · 갈기 모두 `setEntities(…, true)` 를 거쳐 drawing-changed 가 간다. 확정 · 보기 전용이면 안 함. */ import { toast } from 'react-toastify'; import { runCommandInput } from '../commands/run-command.ts'; import type { JsonEntity } from '../entities/Entity.ts'; import { TableEntity } from '../entities/TableEntity.ts'; import type { TableCells } from '../helpers/table-geometry.ts'; import { getEntities, isDrawingReadOnly, isViewOnly, setEntities } from '../state.ts'; import { setPendingTable, setPlaceCancelHandler } from '../tools/annotate/place-table-tool.ts'; export const AISLO_PLACE_TABLE_MESSAGE = 'aislo:b08:place-table'; export const AISLO_UPDATE_TABLE_MESSAGE = 'aislo:b08:update-table'; export const AISLO_TABLE_UPDATED_MESSAGE = 'aislo:b08:table-updated'; export const AISLO_PLACE_CANCELLED_MESSAGE = 'aislo:b08:place-cancelled'; /** 두 메시지를 한 꼴로 받음 — place = entity · link · update = link · cells */ interface TableMessage { type?: string; entity?: JsonEntity; link?: string; cells?: TableCells; /** update 전용 — 보기 전용 미리보기 패널이 저장 전 값을 비춤(도면 문서는 안 고침 · 보기 전용이어도 갈음) */ preview?: boolean; } /** 이 표가 그 연결의 것인가 */ export const isLinkedTable = (entity: unknown, link: string): entity is TableEntity => entity instanceof TableEntity && entity.getStyle().연결 === link; /** 연결 표마다 칸을 갈아 끼움 — 바꾼 표 수(0 이면 도면을 건드리지 않음) */ export function updateLinkedTables(link: string, cells: TableCells): number { const tables = getEntities().filter((entity) => isLinkedTable(entity, link)); for (const table of tables) table.replaceCells(cells); if (tables.length) setEntities([...getEntities()], true); return tables.length; } /** 표 JSON 을 놓기 도구에 맡기고 도구를 켬 */ export async function startPlaceTable(entity: JsonEntity, link: string): Promise { const table = await TableEntity.fromJson(entity as Parameters[0]); const linked = new TableEntity( table.layerId, table.getOrigin(), table.getColumnWidths(), table.getRowHeights(), table.getCells(), { ...table.getStyle(), 연결: link } ); linked.lineColor = table.lineColor; // 보낸 선 색 · 굵기 그대로 linked.lineWidth = table.lineWidth; setPendingTable(linked); runCommandInput('PLACETABLE'); } const blocked = (): boolean => { if (!isDrawingReadOnly() && !isViewOnly()) return false; toast.info('보기 전용 도면 — 표를 넣거나 고치려면 [수정]을 먼저 누르세요.'); return true; }; /** 표 메시지면 처리하고 true — 아니면 false(다른 메시지 갈래로) */ export async function handleTableMessage( data: unknown, notify: (type: string, payload: Record) => void ): Promise { const message = data as TableMessage | null; if (!message || typeof message !== 'object') return false; if (message.type === AISLO_PLACE_TABLE_MESSAGE && message.entity && message.link) { if (!blocked()) { setPlaceCancelHandler(() => notify(AISLO_PLACE_CANCELLED_MESSAGE, {})); await startPlaceTable(message.entity, message.link); } return true; } if (message.type === AISLO_UPDATE_TABLE_MESSAGE && message.link && message.cells) { const count = message.preview || !blocked() ? updateLinkedTables(message.link, message.cells) : 0; notify(AISLO_TABLE_UPDATED_MESSAGE, { link: message.link, count }); return true; } return false; }