import { BaseTool } from './base-tool'; import type { PointerState, TransformHandle, TransformBounds } from '@/types'; import { useLayerStore } from '@/store/layer-store'; import { useTransformStore } from '@/store/transform-store'; import { getHandlePosition, isNearHandle, getHandleCursor, calculateScaleFromHandle, calculateRotationFromHandle, } from '@/lib/transform-utils'; const HANDLES: TransformHandle[] = [ 'top-left', 'top-center', 'top-right', 'middle-left', 'middle-right', 'bottom-left', 'bottom-center', 'bottom-right', 'rotate', ]; export class FreeTransformTool extends BaseTool { private activeHandle: TransformHandle | null = null; private dragStartX = 0; private dragStartY = 0; private originalState: any = null; constructor() { super('Free Transform'); } onPointerDown(pointer: PointerState): void { const { activeTransform } = useTransformStore.getState(); if (!activeTransform) { // Start new transform this.startTransform(pointer); return; } // Check if clicking on a handle const handle = this.getHandleAtPoint( pointer.x, pointer.y, activeTransform.originalBounds, activeTransform.currentState ); if (handle) { this.isActive = true; this.isDrawing = true; this.activeHandle = handle; this.dragStartX = pointer.x; this.dragStartY = pointer.y; this.originalState = { ...activeTransform.currentState }; } else { // Check if clicking inside bounds (move) const bounds = activeTransform.originalBounds; const state = activeTransform.currentState; if ( pointer.x >= bounds.x + state.x && pointer.x <= bounds.x + state.x + bounds.width * state.scaleX && pointer.y >= bounds.y + state.y && pointer.y <= bounds.y + state.y + bounds.height * state.scaleY ) { this.isActive = true; this.isDrawing = true; this.activeHandle = null; this.dragStartX = pointer.x; this.dragStartY = pointer.y; this.originalState = { ...activeTransform.currentState }; } } } onPointerMove(pointer: PointerState): void { if (!this.isDrawing) { // Update cursor based on hover this.updateCursor(pointer); return; } const { activeTransform, updateTransform, maintainAspectRatio } = useTransformStore.getState(); if (!activeTransform || !this.originalState) return; const dx = pointer.x - this.dragStartX; const dy = pointer.y - this.dragStartY; if (this.activeHandle === 'rotate') { // Rotation const bounds = activeTransform.originalBounds; const centerX = bounds.x + bounds.width / 2 + activeTransform.currentState.x; const centerY = bounds.y + bounds.height / 2 + activeTransform.currentState.y; const rotation = calculateRotationFromHandle(centerX, centerY, pointer.x, pointer.y); updateTransform({ rotation }); } else if (this.activeHandle) { // Scale const scale = calculateScaleFromHandle( this.activeHandle, this.dragStartX, this.dragStartY, pointer.x, pointer.y, activeTransform.originalBounds, maintainAspectRatio ); updateTransform({ scaleX: this.originalState.scaleX * scale.scaleX, scaleY: this.originalState.scaleY * scale.scaleY, }); } else { // Move updateTransform({ x: this.originalState.x + dx, y: this.originalState.y + dy, }); } } onPointerUp(): void { this.isDrawing = false; this.isActive = false; this.activeHandle = null; this.originalState = null; } getCursor(settings: any, pointer?: PointerState): string { const { activeTransform } = useTransformStore.getState(); if (!activeTransform || !pointer) return 'default'; const handle = this.getHandleAtPoint( pointer.x, pointer.y, activeTransform.originalBounds, activeTransform.currentState ); if (handle) { return getHandleCursor(handle, activeTransform.currentState.rotation); } // Check if inside bounds const bounds = activeTransform.originalBounds; const state = activeTransform.currentState; if ( pointer.x >= bounds.x + state.x && pointer.x <= bounds.x + state.x + bounds.width * state.scaleX && pointer.y >= bounds.y + state.y && pointer.y <= bounds.y + state.y + bounds.height * state.scaleY ) { return 'move'; } return 'default'; } private startTransform(pointer: PointerState): void { const layer = this.getActiveLayer(); if (!layer?.canvas) return; const bounds: TransformBounds = { x: layer.x, y: layer.y, width: layer.canvas.width, height: layer.canvas.height, }; const { startTransform } = useTransformStore.getState(); startTransform(layer.id, bounds); } private getHandleAtPoint( x: number, y: number, bounds: TransformBounds, state: any ): TransformHandle | null { for (const handle of HANDLES) { if (isNearHandle(x, y, handle, bounds, state, 10)) { return handle; } } return null; } private updateCursor(pointer: PointerState): void { // This would update the canvas cursor dynamically // Implementation depends on canvas component integration } private getActiveLayer() { const { activeLayerId, layers } = useLayerStore.getState(); return layers.find((l) => l.id === activeLayerId); } }