// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter/material.dart';

class _GesturePainter extends CustomPainter {
  const _GesturePainter({
    this.zoom,
    this.offset,
    this.swatch,
    this.forward,
    this.scaleEnabled,
    this.tapEnabled,
    this.doubleTapEnabled,
    this.longPressEnabled
  });

  final double zoom;
  final Offset offset;
  final Map<int, Color> swatch;
  final bool forward;
  final bool scaleEnabled;
  final bool tapEnabled;
  final bool doubleTapEnabled;
  final bool longPressEnabled;

  @override
  void paint(Canvas canvas, Size size) {
    Point center = (size.center(Point.origin).toOffset() * zoom + offset).toPoint();
    double radius = size.width / 2.0 * zoom;
    Gradient gradient = new RadialGradient(
      colors: forward ? <Color>[swatch[50], swatch[900]]
                      : <Color>[swatch[900], swatch[50]]
    );
    Paint paint = new Paint()
      ..shader = gradient.createShader(new Rect.fromLTWH(
        center.x - radius,
        center.y - radius,
        radius * 2.0,
        radius * 2.0
      ));
    canvas.drawCircle(center, radius, paint);
  }

  @override
  bool shouldRepaint(_GesturePainter oldPainter) {
    return oldPainter.zoom != zoom
        || oldPainter.offset != offset
        || oldPainter.swatch != swatch
        || oldPainter.forward != forward
        || oldPainter.scaleEnabled != scaleEnabled
        || oldPainter.tapEnabled != tapEnabled
        || oldPainter.doubleTapEnabled != doubleTapEnabled
        || oldPainter.longPressEnabled != longPressEnabled;
  }
}

class GestureDemo extends StatefulWidget {
  @override
  _GestureDemoState createState() => new _GestureDemoState();
}

class _GestureDemoState extends State<GestureDemo> {

  Point _startingFocalPoint;

  Offset _previousOffset;
  Offset _offset = Offset.zero;

  double _previousZoom;
  double _zoom = 1.0;

  Map<int, Color> _swatch = Colors.blue;

  bool _forward = true;
  bool _scaleEnabled = true;
  bool _tapEnabled = true;
  bool _doubleTapEnabled = true;
  bool _longPressEnabled = true;

  void _handleScaleStart(Point focalPoint) {
    setState(() {
      _startingFocalPoint = focalPoint;
      _previousOffset = _offset;
      _previousZoom = _zoom;
    });
  }

  void _handleScaleUpdate(double scale, Point focalPoint) {
    setState(() {
      _zoom = (_previousZoom * scale);

      // Ensure that item under the focal point stays in the same place despite zooming
      Offset normalizedOffset = (_startingFocalPoint.toOffset() - _previousOffset) / _previousZoom;
      _offset = focalPoint.toOffset() - normalizedOffset * _zoom;
    });
  }

  void _handleScaleReset() {
    setState(() {
      _zoom = 1.0;
      _offset = Offset.zero;
    });
  }

  void _handleColorChange() {
    setState(() {
      switch (_swatch) {
        case Colors.blueGrey:   _swatch = Colors.red; break;
        case Colors.red:        _swatch = Colors.pink; break;
        case Colors.pink:       _swatch = Colors.purple; break;
        case Colors.purple:     _swatch = Colors.deepPurple; break;
        case Colors.deepPurple: _swatch = Colors.indigo; break;
        case Colors.indigo:     _swatch = Colors.blue; break;
        case Colors.blue:       _swatch = Colors.lightBlue; break;
        case Colors.lightBlue:  _swatch = Colors.cyan; break;
        case Colors.cyan:       _swatch = Colors.teal; break;
        case Colors.teal:       _swatch = Colors.green; break;
        case Colors.green:      _swatch = Colors.lightGreen; break;
        case Colors.lightGreen: _swatch = Colors.lime; break;
        case Colors.lime:       _swatch = Colors.yellow; break;
        case Colors.yellow:     _swatch = Colors.amber; break;
        case Colors.amber:      _swatch = Colors.orange; break;
        case Colors.orange:     _swatch = Colors.deepOrange; break;
        case Colors.deepOrange: _swatch = Colors.brown; break;
        case Colors.brown:      _swatch = Colors.grey; break;
        case Colors.grey:       _swatch = Colors.blueGrey; break;
        default:                assert(false);
      }
    });
  }

  void _handleDirectionChange() {
    setState(() {
      _forward = !_forward;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Stack(
      children: <Widget>[
        new GestureDetector(
          onScaleStart: _scaleEnabled ? _handleScaleStart : null,
          onScaleUpdate: _scaleEnabled ? _handleScaleUpdate : null,
          onTap: _tapEnabled ? _handleColorChange : null,
          onDoubleTap: _doubleTapEnabled ? _handleScaleReset : null,
          onLongPress: _longPressEnabled ? _handleDirectionChange : null,
          child: new CustomPaint(
            painter: new _GesturePainter(
              zoom: _zoom,
              offset: _offset,
              swatch: _swatch,
              forward: _forward,
              scaleEnabled: _scaleEnabled,
              tapEnabled: _tapEnabled,
              doubleTapEnabled: _doubleTapEnabled,
              longPressEnabled: _longPressEnabled
            )
          )
        ),
        new Positioned(
          bottom: 0.0,
          left: 0.0,
          child: new Card(
            child: new Container(
              padding: new EdgeInsets.all(4.0),
              child: new Column(
                children: <Widget>[
                  new Row(
                    children: <Widget>[
                      new Checkbox(
                        value: _scaleEnabled,
                        onChanged: (bool value) { setState(() { _scaleEnabled = value; }); }
                      ),
                      new Text('Scale'),
                    ]
                  ),
                  new Row(
                    children: <Widget>[
                      new Checkbox(
                        value: _tapEnabled,
                        onChanged: (bool value) { setState(() { _tapEnabled = value; }); }
                      ),
                      new Text('Tap'),
                    ]
                  ),
                  new Row(
                    children: <Widget>[
                      new Checkbox(
                        value: _doubleTapEnabled,
                        onChanged: (bool value) { setState(() { _doubleTapEnabled = value; }); }
                      ),
                      new Text('Double Tap'),
                    ]
                  ),
                  new Row(
                    children: <Widget>[
                      new Checkbox(
                        value: _longPressEnabled,
                        onChanged: (bool value) { setState(() { _longPressEnabled = value; }); }
                      ),
                      new Text('Long Press'),
                    ]
                  ),
                ],
                crossAxisAlignment: CrossAxisAlignment.start
              )
            )
          )
        ),
      ]
    );
  }
}

void main() {
  runApp(new MaterialApp(
    theme: new ThemeData.dark(),
    home: new Scaffold(
      appBar: new AppBar(title: new Text('Gestures Demo')),
      body: new GestureDemo()
    )
  ));
}
