/* ============================================================================= * B06_Section_UI_Page_Pick_Sync.ts * 횡단 보기 강조를 고름 한 칸에 묶음 (233-2 · 조사 AF (나) ④). * * 고름 한 칸(`structure-pick`)이 유일 원천이다. 횡단 보기가 보일 때 다른 곳(풀기 Esc 등)이 값을 * 바꾸면 구독으로 받아 카드 · 범위 테두리(`--span`) · 포장층 · 벽 · 세월교 · BOX 형상 강조를 그 값으로 * 다시 세운다 — 값이 비면 모두 풂, 값이 있으면 넘김 적용(`applyStructurePick`)과 같은 길로 다시 얹음. * 횡단 보기 안 누름(카드 · 목록 · 알약 · 형상)은 그 자리에서 그리고 값을 적으므로(from "b06") 되받지 않음. * 풀기(Esc · 카드 다시 누름 · 목록 다시 누름 · 보기 오감)는 `release` 한 길 — 카드 · 폼 · 범위 테두리 · * 형상까지 모두 끔(카드만 풀고 `--span` 이 남던 구멍 · a4). * 한 벌 배수유역도(관 마커 · 유역 · 측점 마름모)는 낸 쪽과 무관하게 늘 값대로 칠함 — 횡단 보기 안 * 누름(카드 · 목록)도 지도에 이어짐(270 · 종단 보기 `paintMapPick` 과 같은 규칙). * ========================================================================== */ import { subscribeSelection, type DesignSelection } from "../A00_Common/design/design_selection"; import { bindEscapeRelease } from "../A00_Common/design/design_pick_escape"; import type { CrossSection } from "./B06_Section_Api_Fetch"; import type { StationControls } from "./B06_Section_UI_Page_Station_Controls"; export interface CrossPickDeps { sections: () => ReadonlyArray; controls: Pick; /** 좌측 폼(구조물 · 관) 닫기. */ releaseForm: () => void; view: { focusStation: (stationId: string | null) => void; refreshCards: (chainages: ReadonlyArray) => void; selectMark: (structureId: string | null, span?: boolean) => void; }; /** 지금 값으로 카드 · 형상 · 폼을 다시 세움(넘김 적용 길). */ reapply: () => void; /** 배수유역도를 값으로 칠함(알림 없이 · 270). */ paintMap?: (selection: DesignSelection | null) => void; } let releasing = false; /** 횡단 보기 강조를 모두 끔 — 카드 · 벽 · 세월교 · BOX · 폼 관 · 범위 테두리 · 포장층(값은 안 건드림). * 카드를 풀면 카드 리스너가 다시 풀기를 부름 — 되돌아온 부름은 건너뜀. */ export function releaseCrossHighlights(deps: CrossPickDeps): void { if (releasing) return; releasing = true; try { releaseAll(deps); } finally { releasing = false; } } function releaseAll(deps: CrossPickDeps): void { const { revetOffset, ford, box } = deps.controls; const lit = deps .sections() .filter( (s) => revetOffset.highlightFor(s) || ford.selectedFor(s.chainage_m) || box.selectedFor(s.chainage_m), ); for (const s of lit) { if (revetOffset.selectedFor(s)) revetOffset.select(s.chainage_m, null); if (ford.selectedFor(s.chainage_m)) ford.select(s.chainage_m, null); if (box.selectedFor(s.chainage_m)) box.select(s.chainage_m, null); } deps.releaseForm(); deps.view.focusStation(null); deps.view.selectMark(null); deps.view.refreshCards(lit.map((s) => s.chainage_m)); } /** 횡단 보기를 고름 한 칸에 묶음 — 보일 때 · 다른 곳이 바꾼 값만 받음 · 보기를 떠나면 끊음. * `release` = 강조 모두 끔(값은 부르는 쪽이 비움). 지도는 보일 때 모든 값을 칠함 — 보기 전환 때는 * 종단 보기가 같은 값으로 칠해 둠 · 재계산 뒤는 횡단 보기 종단도 알림(`onPipesChanged`)이 다시 얹음. */ export function bindCrossPick( projectId: string | null, host: { visible: () => boolean; onDispose: (fn: () => void) => void }, deps: CrossPickDeps, ): { release: () => void } { host.onDispose( subscribeSelection(projectId, (selection, from) => { if (!host.visible()) return; deps.paintMap?.(selection); if (from === "b06") return; if (selection.chainageM === null) releaseCrossHighlights(deps); else deps.reapply(); }), ); bindEscapeRelease(projectId, host); // 풀기 한 길(233-3) return { release: () => releaseCrossHighlights(deps) }; }