import { BaseTool } from './base-tool'; import type { PointerState } from '@/types'; import { useSelectionStore } from '@/store/selection-store'; import { useLayerStore } from '@/store/layer-store'; import { createEllipticalMask, createSelection, combineMasks, } from '@/lib/selection-utils'; export class EllipticalSelectionTool extends BaseTool { private startX = 0; private startY = 0; private currentX = 0; private currentY = 0; constructor() { super('Elliptical Selection'); } onPointerDown(pointer: PointerState): void { this.isActive = true; this.isDrawing = true; this.startX = pointer.x; this.startY = pointer.y; this.currentX = pointer.x; this.currentY = pointer.y; } onPointerMove(pointer: PointerState, ctx: CanvasRenderingContext2D): void { if (!this.isDrawing) return; this.currentX = pointer.x; this.currentY = pointer.y; // Draw preview ellipse const layer = this.getActiveLayer(); if (!layer?.canvas) return; ctx.clearRect(0, 0, layer.canvas.width, layer.canvas.height); ctx.save(); ctx.strokeStyle = '#000'; ctx.lineWidth = 1; ctx.setLineDash([4, 4]); const cx = (this.startX + this.currentX) / 2; const cy = (this.startY + this.currentY) / 2; const rx = Math.abs(this.currentX - this.startX) / 2; const ry = Math.abs(this.currentY - this.startY) / 2; ctx.beginPath(); ctx.ellipse(cx, cy, rx, ry, 0, 0, Math.PI * 2); ctx.stroke(); ctx.strokeStyle = '#fff'; ctx.lineDashOffset = 4; ctx.stroke(); ctx.restore(); } onPointerUp(): void { if (!this.isDrawing) return; const layer = this.getActiveLayer(); if (!layer?.canvas) return; const cx = (this.startX + this.currentX) / 2; const cy = (this.startY + this.currentY) / 2; const rx = Math.abs(this.currentX - this.startX) / 2; const ry = Math.abs(this.currentY - this.startY) / 2; if (rx > 0 && ry > 0) { const { selectionMode, feather, activeSelection } = useSelectionStore.getState(); const newMask = createEllipticalMask( cx, cy, rx, ry, layer.canvas.width, layer.canvas.height ); let finalMask = newMask; // Combine with existing selection if needed if (activeSelection && selectionMode !== 'new') { finalMask = combineMasks(activeSelection.mask, newMask, selectionMode); } const selection = createSelection(layer.id, finalMask, feather); useSelectionStore.getState().setActiveSelection(selection); } this.isDrawing = false; this.isActive = false; } getCursor(): string { return 'crosshair'; } private getActiveLayer() { const { activeLayerId, layers } = useLayerStore.getState(); return layers.find((l) => l.id === activeLayerId); } }