import { commandIds } from "@commands/ids"; import type { Dispatch } from "@commands/dispatcher"; import type { ImageDocument } from "@core/document"; import type { Layer } from "@core/layer"; import { resolveTransformTargetBounds } from "@editor/transform-targets"; import type { ViewportState } from "@editor/state"; import type { PointerInputEvent } from "./pointer"; export function handleArtboardSelection(options: { event: PointerInputEvent; document: ImageDocument; viewport: ViewportState; dispatch: Dispatch; }): boolean { if (options.event.pointerType !== "mouse" || (options.event.buttons & 1) !== 1) return false; const point = viewportPointToDocumentPoint(options.event.position, options.viewport); const layerHit = findTopmostLayerAtPoint(options.document, point); if (layerHit) { options.dispatch(commandIds.selectionSet, { artboardId: layerHit.artboardId, layerIds: [layerHit.layerId] }); return true; } const artboard = [...options.document.artboards].reverse().find((candidate) => { const bounds = candidate.bounds; return point.x >= bounds.x && point.x <= bounds.x + bounds.w && point.y >= bounds.y && point.y <= bounds.y + bounds.h; }); if (!artboard) { options.dispatch(commandIds.selectionClear, undefined); return true; } options.dispatch(commandIds.selectionSet, { artboardId: artboard.id, layerIds: [] }); return true; } function findTopmostLayerAtPoint(document: ImageDocument, point: { x: number; y: number }) { for (const artboard of [...document.artboards].reverse()) { const layerId = findTopmostLayerInTreeAtPoint(document, [...artboard.layers].reverse(), point); if (layerId) return { artboardId: artboard.id, layerId }; } return undefined; } function findTopmostLayerInTreeAtPoint(document: ImageDocument, layers: Layer[], point: { x: number; y: number }): string | undefined { for (const layer of layers) { if (layer.type === "group") { const childId = findTopmostLayerInTreeAtPoint(document, [...layer.children].reverse(), point); if (childId) return childId; } const bounds = resolveTransformTargetBounds(document, { type: "layer", id: layer.id }); if (bounds && point.x >= bounds.x && point.x <= bounds.x + bounds.w && point.y >= bounds.y && point.y <= bounds.y + bounds.h) { return layer.id; } } return undefined; } function viewportPointToDocumentPoint(point: PointerInputEvent["position"], viewport: ViewportState) { return { x: viewport.center.x + (point.x - viewport.size.w / 2) / viewport.zoom, y: viewport.center.y + (point.y - viewport.size.h / 2) / viewport.zoom, }; }