no no , not like that, just i suppose to say that even an induvidual line should not be stright, it sohuld also be curve/bend in ripple effect , do slight change
import 'package:flutter/material.dart';
import 'dart:math';

class AmslerGridScreen extends StatefulWidget {
  const AmslerGridScreen({super.key});

  @override
  _AmslerGridScreenState createState() => _AmslerGridScreenState();
}

class _AmslerGridScreenState extends State<AmslerGridScreen> {
  // Variables for transformations
  double _scale = 1.0;
  late TransformationController _transformationController;
  TapDownDetails? _doubleTapDetails;

  // Variables for adjustable settings
  int _gridLines = 20;
  double _lineThickness = 1.0;
  Color _gridColor = Colors.black;
  Color _backgroundColor = Colors.white;
  bool _showCenterDot = true;

  // For contrast adjustment
  double _contrast = 1.0;

  // Variables for distortion effects
  double _distortionAmount = 50.0;   // 3D bending effect
  double _distortion2Amount = 50.0;  // Ripple effect
  double _darken = 1.0;

  @override
  void initState() {
    super.initState();
    _transformationController = TransformationController();
  }

  @override
  Widget build(BuildContext context) {
    // Get the screen size
    final screenSize = MediaQuery.of(context).size;

    // Determine if the device is a tablet based on screen width
    final bool isTablet = screenSize.shortestSide >= 600;

    // Calculate the desired margin based on the screen size
    final double marginWidth = screenSize.width * 0.04; // 4% of screen width as margin
    final double marginHeight = screenSize.height * 0.07; // 7% of screen height as margin

    return Scaffold(
      appBar: AppBar(
        title: const Text(
          'B+L Amsler Grid',
          style: TextStyle(
            color: Colors.teal,
            fontSize: 26,
          ),
        ),
        centerTitle: true,
        leading: IconButton(
          icon: const Icon(Icons.arrow_back_ios_new, color: Color.fromARGB(168, 21, 1, 1)),
          onPressed: () => Navigator.of(context).pop(),
        ),
        actions: [
          IconButton(
            icon: const Icon(Icons.refresh),
            onPressed: _resetView,
            tooltip: 'Reset All',
          ),
          IconButton(
            icon: Icon(_showCenterDot ? Icons.visibility : Icons.visibility_off),
            onPressed: () {
              setState(() {
                _showCenterDot = !_showCenterDot;
              });
            },
            tooltip: 'Toggle Center Dot',
          ),
        ],
      ),
      body: isTablet
          ? Row(
              children: [
                // Grid on the left side
                Expanded(
                  flex: 2,
                  child: _buildGrid(marginWidth, marginHeight),
                ),
                // Controls on the right side
                Expanded(
                  child: _buildControls(),
                ),
              ],
            )
          : Column(
              children: [
                // Grid at the top on phones
                Expanded(
                  child: _buildGrid(marginWidth, marginHeight),
                ),
                // Controls at the bottom on phones
                _buildControls(),
              ],
            ),
    );
  }

  Widget _buildGrid(double marginWidth, double marginHeight) {
    return LayoutBuilder(
      builder: (context, constraints) {
        return Container(
          color: _backgroundColor, // Apply the background color
          child: GestureDetector(
            onDoubleTapDown: (details) {
              _doubleTapDetails = details;
            },
            onDoubleTap: _handleDoubleTap,
            child: InteractiveViewer(
              transformationController: _transformationController,
              panEnabled: true,
              scaleEnabled: true,
              minScale: 1.0,
              maxScale: 5.0,
              onInteractionStart: (details) {
                // Store the focal point when interaction starts
                _doubleTapDetails = TapDownDetails(globalPosition: details.focalPoint);
              },
              onInteractionUpdate: (details) {
                // Update the scale while keeping the grid centered
                _onScaleChanged(details.scale);
              },
              child: CustomPaint(
                painter: BackgroundPaint(
                  marginWidth: marginWidth,
                  marginHeight: marginHeight,
                  gridLines: _gridLines,
                  lineThickness: _lineThickness,
                  gridColor: _gridColor,
                  backgroundColor: _backgroundColor,
                  showCenterDot: _showCenterDot,
                  contrast: _contrast,
                  distortionAmount: _distortionAmount,
                  distortion2Amount: _distortion2Amount,
                  darken: _darken,
                ),
                size: Size.infinite,
              ),
            ),
          ),
        );
      },
    );
  }

  Widget _buildControls() {
    // Controls in a scrollable view
    return Container(
      color: Colors.grey[200],
      height: 420, // Adjusted height to accommodate the new slider
      child: SingleChildScrollView(
        child: Column(
          children: [
            // Zoom level slider
            ListTile(
              title: Text('Zoom Level: ${_scale.toStringAsFixed(1)}x'),
              subtitle: Slider(
                value: _scale,
                min: 1.0,
                max: 5.0,
                divisions: 40,
                label: 'Zoom',
                onChanged: (value) {
                  setState(() {
                    _scale = value;
                    _onScaleChanged(_scale);
                  });
                },
              ),
            ),
            // Grid size adjustment
            ListTile(
              title: Text('Grid Size: $_gridLines x $_gridLines'),
              subtitle: Slider(
                value: _gridLines.toDouble(),
                min: 10,
                max: 40,
                divisions: 30,
                label: 'Grid Lines',
                onChanged: (value) {
                  setState(() {
                    _gridLines = value.toInt();
                  });
                },
              ),
            ),
            // Line thickness adjustment
            ListTile(
              title: Text('Line Thickness: ${_lineThickness.toStringAsFixed(1)}'),
              subtitle: Slider(
                value: _lineThickness,
                min: 0.5,
                max: 5.0,
                divisions: 9,
                label: 'Line Thickness',
                onChanged: (value) {
                  setState(() {
                    _lineThickness = value;
                  });
                },
              ),
            ),
            // Contrast adjustment
            ListTile(
              title: Text('Contrast: ${(_contrast * 100).toInt()}%'),
              subtitle: Slider(
                value: _contrast,
                min: 0.1,
                max: 1.0,
                divisions: 9,
                label: 'Contrast',
                onChanged: (value) {
                  setState(() {
                    _contrast = value;
                  });
                },
              ),
            ),
            // Distortion amount adjustment (3D bending)
            ListTile(
              title: Text('Distortion 1 (3D Bend): ${_distortionAmount.toInt()}%'),
              subtitle: Slider(
                value: _distortionAmount,
                min: 0.0,
                max: 100.0,
                divisions: 100,
                label: 'Distortion 1',
                onChanged: (value) {
                  setState(() {
                    _distortionAmount = value;
                  });
                },
              ),
            ),
            // Distortion 2 amount adjustment (Ripple)
            ListTile(
              title: Text('Distortion 2 (Ripple): ${_distortion2Amount.toInt()}%'),
              subtitle: Slider(
                value: _distortion2Amount,
                min: 0.0,
                max: 100.0,
                divisions: 100,
                label: 'Distortion 2',
                onChanged: (value) {
                  setState(() {
                    _distortion2Amount = value;
                  });
                },
              ),
            ),
            // Darken adjustment
            ListTile(
              title: Text('Darken: ${(_darken * 100).toInt()}%'),
              subtitle: Slider(
                value: _darken,
                min: 0.1,
                max: 1.0,
                divisions: 9,
                label: 'Darken',
                onChanged: (value) {
                  setState(() {
                    _darken = value;
                  });
                },
              ),
            ),
            // Color options for grid and background
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 4.0),
              child: Row(
                children: [
                  const Text('Grid Color:'),
                  const SizedBox(width: 10),
                  DropdownButton<Color>(
                    value: _gridColor,
                    items: [
                      DropdownMenuItem(
                        value: Colors.black,
                        child: const Text('Black'),
                      ),
                      DropdownMenuItem(
                        value: Colors.white,
                        child: const Text('White'),
                      ),
                    ],
                    onChanged: (value) {
                      setState(() {
                        _gridColor = value!;
                      });
                    },
                  ),
                  const SizedBox(width: 20),
                  const Text('Background Color:'),
                  const SizedBox(width: 10),
                  DropdownButton<Color>(
                    value: _backgroundColor,
                    items: [
                      DropdownMenuItem(
                        value: Colors.white,
                        child: const Text('White'),
                      ),
                      DropdownMenuItem(
                        value: Colors.black,
                        child: const Text('Black'),
                      ),
                    ],
                    onChanged: (value) {
                      setState(() {
                        _backgroundColor = value!;
                      });
                    },
                  ),
                ],
              ),
            ),
            const SizedBox(height: 10),
          ],
        ),
      ),
    );
  }

  void _resetView() {
    setState(() {
      _scale = 1.0;
      _transformationController.value = Matrix4.identity();

      // Reset other variables to default values
      _gridLines = 20;
      _lineThickness = 1.0;
      _gridColor = Colors.black;
      _backgroundColor = Colors.white;
      _showCenterDot = true;
      _contrast = 1.0;
      _distortionAmount = 50.0;   // default to 50 (no distortion)
      _distortion2Amount = 50.0;  // default to 50 (no ripple)
      _darken = 1.0;
    });
  }

  void _handleDoubleTap() {
    if (_doubleTapDetails != null) {
      final position = _doubleTapDetails!.localPosition;
      // Zoom in or out on double tap
      setState(() {
        if (_scale == 1.0) {
          _scale = 2.0;
        } else {
          _scale = 1.0;
        }
        _onScaleChanged(_scale);
      });
    }
  }

  void _onScaleChanged(double scale) {
    final matrix = Matrix4.identity();
    matrix.translate(
      (1 - scale) * MediaQuery.of(context).size.width / 2,
      (1 - scale) * MediaQuery.of(context).size.height / 2,
    );
    matrix.scale(scale);
    _transformationController.value = matrix;
  }
}

class BackgroundPaint extends CustomPainter {
  final double marginWidth;
  final double marginHeight;
  final int gridLines;
  final double lineThickness;
  final Color gridColor;
  final Color backgroundColor;
  final bool showCenterDot;
  final double contrast;
  final double distortionAmount;
  final double distortion2Amount;
  final double darken;

  BackgroundPaint({
    required this.marginWidth,
    required this.marginHeight,
    required this.gridLines,
    required this.lineThickness,
    required this.gridColor,
    required this.backgroundColor,
    required this.showCenterDot,
    required this.contrast,
    required this.distortionAmount,
    required this.distortion2Amount,
    required this.darken,
  });

  @override
  void paint(Canvas canvas, Size size) {
    // Apply background color
    final bgPaint = Paint()..color = backgroundColor;
    canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height), bgPaint);

    // Adjust grid color for contrast and darken
    Color adjustedGridColor = gridColor.withOpacity(contrast.clamp(0.1, 1.0) * darken);

    final paint = Paint()
      ..color = adjustedGridColor
      ..strokeWidth = lineThickness;

    // Calculates the size of each grid box based on the smaller dimension
    final availableWidth = size.width - marginWidth * 2;
    final availableHeight = size.height - marginHeight * 2;
    final gridSize =
        (availableWidth < availableHeight ? availableWidth : availableHeight) / gridLines;

    final adjustedSize = Size(gridSize * gridLines, gridSize * gridLines);

    // Center the grid
    final dx = (size.width - adjustedSize.width) / 2;
    final dy = (size.height - adjustedSize.height) / 2;
    canvas.translate(dx, dy);

    // Center of the grid for distortion calculations
    final Offset center = Offset(adjustedSize.width / 2, adjustedSize.height / 2);

    // Maximum radius from the center to the corner
    final double maxRadius = center.distance;

    // Function to apply combined distortions to a point
    Offset distortPoint(Offset point) {
      final dx = point.dx - center.dx;
      final dy = point.dy - center.dy;
      final double r = sqrt(dx * dx + dy * dy);
      final double theta = atan2(dy, dx);

      // ---------- 3D Bending Effect (Distortion 1) ----------
      double effectiveDistortion = (distortionAmount - 50) / 50.0; // From -1 to 1
      double distortionStrength = effectiveDistortion * 0.5; // Adjust strength as needed
      double z = distortionStrength * (1 - (r / maxRadius) * (r / maxRadius));
      double d = 500.0; // Distance from the viewer to the grid
      double scale3D = d / (d - z * 100); // Adjust z scaling as needed

      double distortedX = dx * scale3D;
      double distortedY = dy * scale3D;

      // ---------- Ripple Effect (Distortion 2) ----------
      double effectiveRipple = (distortion2Amount - 50) / 50.0; // From -1 to 1
      double rippleStrength = effectiveRipple * 10.0; // Adjust ripple strength as needed
      double rippleFrequency = 0.1; // Adjust ripple frequency as needed

      double ripple = rippleStrength * sin(r * rippleFrequency);

      // Apply ripple to the distorted coordinates
      distortedX += ripple * cos(theta);
      distortedY += ripple * sin(theta);

      // Translate back to canvas coordinates
      return Offset(center.dx + distortedX, center.dy + distortedY);
    }

    // Draw the distorted vertical lines
    for (int i = 0; i <= gridLines; i++) {
      List<Offset> points = [];
      for (int j = 0; j <= gridLines; j++) {
        final point = Offset(i * gridSize, j * gridSize);
        final distortedPoint = distortPoint(point);
        points.add(distortedPoint);
      }
      canvas.drawPoints(PointMode.polygon, points, paint);
    }

    // Draw the distorted horizontal lines
    for (int j = 0; j <= gridLines; j++) {
      List<Offset> points = [];
      for (int i = 0; i <= gridLines; i++) {
        final point = Offset(i * gridSize, j * gridSize);
        final distortedPoint = distortPoint(point);
        points.add(distortedPoint);
      }
      canvas.drawPoints(PointMode.polygon, points, paint);
    }

    // Draw the center dot
    if (showCenterDot) {
      final centerDotPaint = Paint()
        ..color = adjustedGridColor
        ..style = PaintingStyle.fill;

      final dotRadius = 4.0;

      // Apply distortion to center point if distortion is present
      final distortedCenter = (distortionAmount != 50.0 || distortion2Amount != 50.0)
          ? distortPoint(center)
          : center;

      canvas.drawCircle(distortedCenter, dotRadius, centerDotPaint);
    }
  }

  @override
  bool shouldRepaint(covariant BackgroundPaint oldDelegate) {
    return oldDelegate.gridLines != gridLines ||
        oldDelegate.lineThickness != lineThickness ||
        oldDelegate.gridColor != gridColor ||
        oldDelegate.backgroundColor != backgroundColor ||
        oldDelegate.showCenterDot != showCenterDot ||
        oldDelegate.contrast != contrast ||
        oldDelegate.distortionAmount != distortionAmount ||
        oldDelegate.distortion2Amount != distortion2Amount ||
        oldDelegate.darken != darken;
  }
}