import 'package:flutter/material.dart';

class SnapToGridCanvas extends StatefulWidget {
  @override
  _SnapToGridCanvasState createState() => _SnapToGridCanvasState();
}

class _SnapToGridCanvasState extends State<SnapToGridCanvas> {
  final double snappingThreshold = 10.0;
  final List<Rect> elements = []; // Store elements' bounds
  Offset selectedElementPosition = Offset(100, 100);
  Size selectedElementSize = Size(100, 100);

  Offset? snapToElementOrCanvas(Offset newPosition, Size canvasSize) {
    for (var element in elements) {
      // Snap to other elements
      if ((newPosition.dx - element.right).abs() <= snappingThreshold) {
        return Offset(element.right, newPosition.dy); // Snap to the right of another element
      } else if ((newPosition.dx - element.left).abs() <= snappingThreshold) {
        return Offset(element.left, newPosition.dy); // Snap to the left of another element
      } else if ((newPosition.dy - element.bottom).abs() <= snappingThreshold) {
        return Offset(newPosition.dx, element.bottom); // Snap to the bottom of another element
      } else if ((newPosition.dy - element.top).abs() <= snappingThreshold) {
        return Offset(newPosition.dx, element.top); // Snap to the top of another element
      }
    }

    // Snap to canvas center
    final canvasCenter = Offset(canvasSize.width / 2, canvasSize.height / 2);
    if ((newPosition.dx - canvasCenter.dx).abs() <= snappingThreshold) {
      return Offset(canvasCenter.dx, newPosition.dy); // Snap horizontally to canvas center
    } else if ((newPosition.dy - canvasCenter.dy).abs() <= snappingThreshold) {
      return Offset(newPosition.dx, canvasCenter.dy); // Snap vertically to canvas center
    }

    return null; // No snapping
  }

  @override
  Widget build(BuildContext context) {
    final canvasSize = MediaQuery.of(context).size;

    return Scaffold(
      appBar: AppBar(title: Text("Snap to Grid Canvas")),
      body: GestureDetector(
        onPanUpdate: (details) {
          setState(() {
            final newPosition = selectedElementPosition + details.delta;

            // Check for snapping
            final snappedPosition = snapToElementOrCanvas(newPosition, canvasSize);
            if (snappedPosition != null) {
              selectedElementPosition = snappedPosition;
            } else {
              selectedElementPosition = newPosition;
            }
          });
        },
        child: Stack(
          children: [
            // Canvas background
            Container(color: Colors.grey[200]),

            // Render all elements
            ...elements.map((element) {
              return Positioned(
                left: element.left,
                top: element.top,
                child: Container(
                  width: element.width,
                  height: element.height,
                  color: Colors.blue,
                ),
              );
            }).toList(),

            // Selected element
            Positioned(
              left: selectedElementPosition.dx,
              top: selectedElementPosition.dy,
              child: Container(
                width: selectedElementSize.width,
                height: selectedElementSize.height,
                color: Colors.red,
                child: Center(child: Text("Drag Me")),
              ),
            ),
          ],
        ),
      ),
    );
  }
}