library flutterptcontrol;

import 'dart:math' as MATH;

import 'package:flutter/material.dart';

typedef void PtCallback(int status);

//pan-tilt Control
class PtControlWidget extends StatefulWidget {
  PtControlWidget(
      {@required this.innerRadius, @required this.outerRadius, @required this.callback});

  ///内径
  final double innerRadius;

  ///外径
  final double outerRadius;

  ///点击回调
  final PtCallback callback;

  @override
  State<StatefulWidget> createState() {
    return _PtControlWidgetState();
  }
}

class _PtControlWidgetState extends State<PtControlWidget> {
  int status = -1;

  /*
  3.获取控件的坐标：
  RenderBox renderBox = anchorKey.currentContext.findRenderObject();
  var offset =  renderBox.localToGlobal(Offset.zero);
  控件的横坐标：offset.dx
  控件的纵坐标：offset.dy

  如果想获得控件正下方的坐标：
   RenderBox renderBox = anchorKey.currentContext.findRenderObject();
   var offset =  renderBox.localToGlobal(Offset(0.0, renderBox.size.height));
     控件下方的横坐标：offset.dx
     控件下方的纵坐标：offset.dy
  ————————————————
  版权声明：本文为CSDN博主「笨鸟不飞 ≧０≦」的原创文章，遵循CC 4.0 BY-SA版权协议，转载请附上原文出处链接及本声明。
  原文链接：https://blog.csdn.net/baidu_34120295/article/details/86495861
  */

  //获得本组件中心点对象：Point(offset.dx, offset.dy)
  //Another exception was thrown: type 'Point<num>' is not a subtype of type 'Point<double>'
  MATH.Point getCenterPoint() {
    RenderBox renderBox = context.findRenderObject();
    //控件中心坐标：(offset.dx, offset.dy)
    var offset =
        renderBox.localToGlobal(Offset(renderBox.size.width / 2, renderBox.size.height / 2));
    print('(offset.dx, offset.dy) = (${offset.dx}, ${offset.dy})');
    return MATH.Point<num>(offset.dx.toInt(), offset.dy.toInt());
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onPanDown: (details) {
        //坐标系转换
        var x = details.localPosition.dx - widget.outerRadius;
        var y = -(details.localPosition.dy - widget.outerRadius);

        //判断点击位置是否超出范围
        var dis = MATH.Point(x, y).distanceTo(MATH.Point(0, 0));

        /*
        计算圆周上坐标点的公式，其中圆心坐标(xo,yo)，r为圆半径，α为0～2π，(x,y)为圆上的点
        x = xo + r * cos(α)
        y = yo + r * sin(α)

        原点坐标为(0, 0)，x轴向左为正，y轴向上为正，逆时针方向的8个点的弧度为
        0   π * 1/8
        1   π * 3/8
        2   π * 5/8
        3   π * 7/8
        4   π * 9/8
        5   π * 11/8
        6   π * 13/8
        7   π * 15/8
        */

        // dart 计算原点坐标为(0, 0)，x轴向左为正，y轴向上为正，逆时针方向的8个点的坐标
        List listInnerPoint = List.generate(8, (index) {
          double _radians = MATH.pi * (index * 2 + 1) / 8;
          //print('index = $index');
          return {
            'x': MATH.cos(_radians) * widget.innerRadius,
            'y': MATH.sin(_radians) * widget.innerRadius,
          };
        });

        // dart 计算原点坐标为(0, 0)，x轴向左为正，y轴向上为正，逆时针方向的8个点的坐标
        List listOuterPoint = List.generate(8, (index) {
          double _radians = MATH.pi * (index * 2 + 1) / 8;
          //print('index = $index');
          return {
            'x': MATH.cos(_radians) * widget.outerRadius,
            'y': MATH.sin(_radians) * widget.outerRadius,
          };
        });

        print('listInnerPoint = ${listInnerPoint}');
        print('[x, y] = [$x, $y]');
        //超出范围
        if (dis > widget.outerRadius) {
          status = -1;
        } else if (dis < widget.innerRadius) {
          //还原
          status = 8;
        } else if (x > listOuterPoint[1]['x'] ||
            (y > 0 &&
                x > listInnerPoint[1]['x'] &&
                y <
                    listInnerPoint[1]['y'] +
                        (x - listInnerPoint[1]['x']) / MATH.tan(MATH.pi / 8)) ||
            (y < 0 &&
                x > listInnerPoint[6]['x'] &&
                y >
                    listInnerPoint[6]['y'] -
                        (x - listInnerPoint[6]['x']) / MATH.tan(MATH.pi / 8))) {
          if (y > listOuterPoint[0]['y'] ||
              y > listInnerPoint[0]['y'] &&
                  x <
                      listInnerPoint[0]['x'] +
                          (y - listInnerPoint[0]['y']) / MATH.tan(MATH.pi / 8)) {
            //右上
            status = 1;
          } else if (y > listInnerPoint[7]['y'] ||
              y > listOuterPoint[7]['y'] &&
                  x >
                      listInnerPoint[7]['x'] +
                          (listInnerPoint[7]['y'] - y) / MATH.tan(MATH.pi / 8)) {
            //右
            status = 0;
          } else {
            //右下
            status = 7;
          }
        } else if (x > listInnerPoint[2]['x'] ||
            y > 0 &&
                x > listOuterPoint[2]['x'] &&
                y > listInnerPoint[2]['y'] + (listInnerPoint[2]['x'] - x) / MATH.tan(MATH.pi / 8) ||
            y < 0 &&
                x < listInnerPoint[5]['x'] &&
                y < listInnerPoint[5]['y'] - (listInnerPoint[5]['x'] - x) / MATH.tan(MATH.pi / 8)) {
          if (y > 0) {
            //上
            status = 2;
          } else {
            //下
            status = 6;
          }
        } else {
          if (y > listOuterPoint[3]['y'] ||
              y > listInnerPoint[3]['y'] &&
                  x >
                      listOuterPoint[3]['x'] -
                          (y - listOuterPoint[3]['y']) / MATH.tan(MATH.pi / 8)) {
            //左上
            status = 3;
          } else if (y > listInnerPoint[4]['y'] ||
              y > listOuterPoint[4]['y'] &&
                  x <
                      listOuterPoint[4]['x'] +
                          (listInnerPoint[4]['y'] - y) / MATH.tan(MATH.pi / 8)) {
            //左
            status = 4;
          } else {
            //左下
            status = 5;
          }
        }
        widget.callback(status);
        setState(() {});
      },
      onPanEnd: (details) {
        status = -1;
        setState(() {});
      },

      ///点击回调
      /// status == -1 超出范围
      /// status == 0 右
      /// status == 1 右上
      /// status == 2 上
      /// status == 3 左上
      /// status == 4 左
      /// status == 5 左下
      /// status == 6 下
      /// status == 7 右下
      /// status == 8 还原

      /// color: Colors.black12
      child: Stack(
        children: <Widget>[
          Image.asset(
              null == widget.callback
                  ? 'images/pt_background_disable.png'
                  : 'images/pt_background_enable.png',
              package: 'flutterptcontrol'),
          status == 0
              ? Image.asset('images/pt_right.png', package: 'flutterptcontrol')
              : SizedBox.shrink(),
          status == 1
              ? Image.asset('images/pt_right_top.png', package: 'flutterptcontrol')
              : SizedBox.shrink(),
          status == 2
              ? Image.asset('images/pt_top.png', package: 'flutterptcontrol')
              : SizedBox.shrink(),
          status == 3
              ? Image.asset('images/pt_left_top.png', package: 'flutterptcontrol')
              : SizedBox.shrink(),
          status == 4
              ? Image.asset('images/pt_left.png', package: 'flutterptcontrol')
              : SizedBox.shrink(),
          status == 5
              ? Image.asset('images/pt_left_bottom.png', package: 'flutterptcontrol')
              : SizedBox.shrink(),
          status == 6
              ? Image.asset('images/pt_bottom.png', package: 'flutterptcontrol')
              : SizedBox.shrink(),
          status == 7
              ? Image.asset('images/pt_right_bottom.png', package: 'flutterptcontrol')
              : SizedBox.shrink(),
          // status == 8
          //     ? Image.asset('images/pt_center.png', package: 'flutterptcontrol')
          //     : SizedBox.shrink(),
        ],
      ),
    );
  }
}
