diff --git a/components/canvas/canvas-with-tools.tsx b/components/canvas/canvas-with-tools.tsx index 2b6b98c..5b06e15 100644 --- a/components/canvas/canvas-with-tools.tsx +++ b/components/canvas/canvas-with-tools.tsx @@ -74,6 +74,7 @@ export function CanvasWithTools({ onCursorMove }: CanvasWithToolsProps = {}) { prevY: 0, pressure: 1, }); + const [cropOverlayNeedsUpdate, setCropOverlayNeedsUpdate] = useState(0); // Touch gesture support for mobile useTouchGestures(containerRef, { @@ -216,7 +217,30 @@ export function CanvasWithTools({ onCursorMove }: CanvasWithToolsProps = {}) { // Restore context state ctx.restore(); - }, [layers, width, height, zoom, offsetX, offsetY, showGrid, gridSize, backgroundColor, selection, pointer, activeSelection, isMarching, marchingOffset, textObjects, editingTextId]); + + // Draw crop tool overlay if crop tool is active + if (activeTool === 'crop') { + const cropTool = toolsCache.current['crop']; + if (cropTool && typeof (cropTool as any).drawCropOverlay === 'function') { + ctx.save(); + ctx.translate(offsetX + canvas.width / 2, offsetY + canvas.height / 2); + ctx.scale(zoom, zoom); + ctx.translate(-width / 2, -height / 2); + + // Create a temporary canvas context that matches the full canvas size + const tempCanvas = document.createElement('canvas'); + tempCanvas.width = width; + tempCanvas.height = height; + const tempCtx = tempCanvas.getContext('2d'); + if (tempCtx) { + (cropTool as any).drawCropOverlay(tempCtx); + ctx.drawImage(tempCanvas, 0, 0); + } + + ctx.restore(); + } + } + }, [layers, width, height, zoom, offsetX, offsetY, showGrid, gridSize, backgroundColor, selection, pointer, activeSelection, isMarching, marchingOffset, textObjects, editingTextId, activeTool, cropOverlayNeedsUpdate]); // Marching ants animation useEffect(() => { @@ -283,6 +307,38 @@ export function CanvasWithTools({ onCursorMove }: CanvasWithToolsProps = {}) { return; } + // Crop tool + if (e.button === 0 && !e.shiftKey && activeTool === 'crop') { + const cropTool = toolsCache.current['crop']; + if (!cropTool) return; // Tool not loaded yet + + const newPointer: PointerState = { + isDown: true, + x: canvasPos.x, + y: canvasPos.y, + prevX: canvasPos.x, + prevY: canvasPos.y, + pressure: e.pressure || 1, + altKey: e.altKey, + ctrlKey: e.ctrlKey, + shiftKey: e.shiftKey, + metaKey: e.metaKey, + }; + + setPointer(newPointer); + + // Create a temporary canvas for the crop tool + const tempCanvas = document.createElement('canvas'); + tempCanvas.width = width; + tempCanvas.height = height; + const tempCtx = tempCanvas.getContext('2d'); + if (tempCtx) { + cropTool.onPointerDown(newPointer, tempCtx, settings); + setCropOverlayNeedsUpdate(prev => prev + 1); + } + return; + } + // Text tool - only handle if editor is not already active if (activeTool === 'text') { // If editor is active, let it handle its own events (selection, dragging, click-outside) @@ -394,6 +450,35 @@ export function CanvasWithTools({ onCursorMove }: CanvasWithToolsProps = {}) { return; } + // Crop tool + if (pointer.isDown && activeTool === 'crop') { + const cropTool = toolsCache.current['crop']; + if (!cropTool) return; + + const newPointer: PointerState = { + ...pointer, + x: canvasPos.x, + y: canvasPos.y, + pressure: e.pressure || 1, + altKey: e.altKey, + ctrlKey: e.ctrlKey, + shiftKey: e.shiftKey, + metaKey: e.metaKey, + }; + + setPointer(newPointer); + + const tempCanvas = document.createElement('canvas'); + tempCanvas.width = width; + tempCanvas.height = height; + const tempCtx = tempCanvas.getContext('2d'); + if (tempCtx) { + cropTool.onPointerMove(newPointer, tempCtx, settings); + setCropOverlayNeedsUpdate(prev => prev + 1); + } + return; + } + // Drawing if (pointer.isDown && ['pencil', 'brush', 'eraser', 'eyedropper', 'shape', 'clone', 'smudge', 'dodge'].includes(activeTool)) { const activeLayer = getActiveLayer(); @@ -429,6 +514,23 @@ export function CanvasWithTools({ onCursorMove }: CanvasWithToolsProps = {}) { return; } + // Crop tool + if (pointer.isDown && activeTool === 'crop') { + const cropTool = toolsCache.current['crop']; + if (cropTool) { + const tempCanvas = document.createElement('canvas'); + tempCanvas.width = width; + tempCanvas.height = height; + const tempCtx = tempCanvas.getContext('2d'); + if (tempCtx) { + cropTool.onPointerUp(pointer, tempCtx, settings); + setCropOverlayNeedsUpdate(prev => prev + 1); + } + } + setPointer({ ...pointer, isDown: false }); + return; + } + if (pointer.isDown && ['pencil', 'brush', 'eraser', 'fill', 'eyedropper', 'shape'].includes(activeTool)) { const activeLayer = getActiveLayer(); if (!activeLayer || !activeLayer.canvas) return;