import React from 'react'; import { Shape, Point, ShapeType } from 'l33t-lib'; import { Command, CommandContext, createShapeCommand } from './commands'; type SetStateAction = React.Dispatch>; export interface EventHandlerDependencies { shapes: { [id: string]: Shape }; currentShape: Shape | null; selectedShape: Shape | null; selectedPoint: { shapeId: string; pointIndex: number } | null; isDragging: boolean; isDraggingShape: boolean; draggedShapeId: string | null; setShapes: SetStateAction<{ [id: string]: Shape }>; setCurrentShape: SetStateAction; setSelectedShape: SetStateAction; setSelectedPoint: SetStateAction<{ shapeId: string; pointIndex: number } | null>; setIsDragging: SetStateAction; setIsDraggingShape: SetStateAction; setDraggedShapeId: SetStateAction; setHoveredPoint: SetStateAction<{ shapeId: string; pointIndex: number } | null>; drawingCanvasRef: React.RefObject; dragStartPosition: React.MutableRefObject; draggedShape: React.MutableRefObject; draggedPointInfo: React.MutableRefObject<{ shapeId: string; pointIndex: number } | null>; commandContext: () => CommandContext; executeCommand: (command: Command) => void; getCoordinates: (event: React.MouseEvent) => Point; isPointNearOtherPoint: (point1: Point, point2: Point) => boolean; isPointOnLine: (point: Point, lineStart: Point, lineEnd: Point) => boolean; _getShape: (point: Point) => Shape | null; } export const createCanvasEventHandlers = (deps: EventHandlerDependencies) => { const handleCanvasMouseMove = (event: React.MouseEvent) => { const point = deps.getCoordinates(event); const shapeUnderCursor = deps._getShape(point); let newHoveredPoint = null; let isHoveringLine = false; const shapesToCheck = [shapeUnderCursor, ...Object.values(deps.shapes)].filter(Boolean); for (const shape of shapesToCheck) { if (!shape) continue for (let i = 0; i < shape.points?.length; i++) { if (deps.isPointNearOtherPoint(point, shape!.points[i])) { newHoveredPoint = { shapeId: shape!.id, pointIndex: i }; break; } if (i < shape!.points.length - 1) { if (deps.isPointOnLine(point, shape!.points[i], shape!.points[i + 1])) { isHoveringLine = true; break; } } if (i === shape!.points.length - 1 && shape!.type === 'polygon' && shape!.isClosed) { if (deps.isPointOnLine(point, shape!.points[0], shape!.points[i])) { isHoveringLine = true; break; } } } if (newHoveredPoint || isHoveringLine) break; } deps.setHoveredPoint(newHoveredPoint); if (deps.drawingCanvasRef.current) { if (deps.isDragging || deps.isDraggingShape) { deps.drawingCanvasRef.current.style.cursor = 'grabbing'; } else if (newHoveredPoint) { deps.drawingCanvasRef.current.style.cursor = 'pointer'; } else if (isHoveringLine) { deps.drawingCanvasRef.current.style.cursor = 'crosshair'; } else if (shapeUnderCursor && shapeUnderCursor.type === 'polygon' && shapeUnderCursor.isClosed) { deps.drawingCanvasRef.current.style.cursor = 'move'; } else { deps.drawingCanvasRef.current.style.cursor = 'default'; } } if (deps.isDragging && deps.selectedPoint && deps.dragStartPosition.current) { const dx = point.x - deps.dragStartPosition.current.x; const dy = point.y - deps.dragStartPosition.current.y; const shapeBeingDragged = deps.shapes[deps.selectedPoint.shapeId] || deps.currentShape; if (shapeBeingDragged) { // Invece di modificare direttamente lo state, creiamo una copia temporanea // che verrĂ  usata solo per il visual feedback durante il drag const newPoints = [...shapeBeingDragged.points]; newPoints[deps.selectedPoint.pointIndex] = { x: shapeBeingDragged.points[deps.selectedPoint.pointIndex].x + dx, y: shapeBeingDragged.points[deps.selectedPoint.pointIndex].y + dy }; // Aggiornamento temporaneo solo per il visual feedback deps.setShapes(prevShapes => ({ ...prevShapes, [shapeBeingDragged.id]: { ...shapeBeingDragged, points: newPoints } })); // Aggiornamento della posizione di partenza per il prossimo movimento deps.dragStartPosition.current = point; } } else if (deps.isDraggingShape && deps.draggedShapeId && deps.dragStartPosition.current) { const dx = point.x - deps.dragStartPosition.current.x; const dy = point.y - deps.dragStartPosition.current.y; deps.setShapes({ ...deps.shapes, [deps.draggedShapeId]: { ...deps.shapes[deps.draggedShapeId], points: deps.shapes[deps.draggedShapeId].points.map(p => ({ x: p.x + dx, y: p.y + dy })) } }); deps.dragStartPosition.current = point; } }; const handleCanvasMouseDown = (event: React.MouseEvent) => { const point = deps.getCoordinates(event); let foundVertex = false; for (const shape of Object.values(deps.shapes)) { const pointIndex = shape.points?.findIndex(p => deps.isPointNearOtherPoint(point, p)); if (pointIndex !== -1) { // Abbiamo trovato un vertice deps.setSelectedPoint({ shapeId: shape.id, pointIndex }); deps.setSelectedShape(shape); deps.setIsDragging(true); deps.dragStartPosition.current = point; deps.draggedPointInfo.current = { shapeId: shape.id, pointIndex }; foundVertex = true; break; } } if (!foundVertex) { const clickedShape = deps._getShape(point); if (clickedShape) { deps.setSelectedShape(clickedShape); deps.setIsDraggingShape(true); deps.setDraggedShapeId(clickedShape.id); deps.dragStartPosition.current = point; deps.draggedShape.current = clickedShape; return; } deps.setSelectedPoint(null); deps.setSelectedShape(null); deps.setIsDragging(false); deps.setIsDraggingShape(false); deps.setDraggedShapeId(null); deps.dragStartPosition.current = null; deps.draggedShape.current = null; deps.draggedPointInfo.current = null; } if (deps.drawingCanvasRef.current) { deps.drawingCanvasRef.current.style.cursor = 'default'; } }; const handleCanvasMouseUp = (event: React.MouseEvent) => { const endPoint = deps.getCoordinates(event); if (deps.isDragging && deps.draggedPointInfo.current && deps.dragStartPosition.current) { const dx = endPoint.x - deps.dragStartPosition.current.x; const dy = endPoint.y - deps.dragStartPosition.current.y; const dragPointCommand = createShapeCommand('DragPoint', deps.commandContext(), { currentShape: deps.shapes[deps.draggedPointInfo.current.shapeId] || deps.currentShape, selectedPoint: deps.draggedPointInfo.current, dx, dy }); deps.executeCommand(dragPointCommand); } else if (deps.isDraggingShape && deps.draggedShape.current && deps.dragStartPosition.current) { const dx = endPoint.x - deps.dragStartPosition.current.x; const dy = endPoint.y - deps.dragStartPosition.current.y; const dragShapeCommand = createShapeCommand('DragShape', deps.commandContext(), { currentShape: deps.currentShape, shapeId: deps.draggedShape.current.id, dx, dy, canvasWidth: deps.drawingCanvasRef.current?.width || 0, canvasHeight: deps.drawingCanvasRef.current?.height || 0 }); deps.executeCommand(dragShapeCommand); } deps.setIsDragging(false); deps.setIsDraggingShape(false); deps.setDraggedShapeId(null); deps.dragStartPosition.current = null; deps.draggedShape.current = null; deps.draggedPointInfo.current = null; if (deps.drawingCanvasRef.current) { deps.drawingCanvasRef.current.style.cursor = 'default'; } }; return { handleCanvasMouseMove, handleCanvasMouseDown, handleCanvasMouseUp }; };