calcPosition method

List<Matrix4> calcPosition()

Implementation

List<Matrix4> calcPosition() {
  final ret =
      List<Matrix4>.generate(_items.length, (index) => Matrix4.identity());
  var newCenter = widget.params.useScreenCenter
      ? Offset(
          screenSize!.width / 2 + widget.params.centerOffset.dx,
          screenSize!.height / 2 + widget.params.centerOffset.dy,
        )
      : parentBounds.center + widget.params.centerOffset;
  if (widget.params.useTouchAsCenter && touchLocalPoint != Offset.zero) {
    newCenter = Offset(
      parentBounds.left + touchLocalPoint.dx,
      parentBounds.top + touchLocalPoint.dy,
    );
  }
  offsetToFitMenuIntoScreen = Offset.zero;

  switch (widget.params.shape) {
    case MenuShape.circle:
      // if the circle isn't complete, the last item should
      // be positioned at the ending angle. Otherwise on the ending
      // angle there is already the 1st item
      final nItems = (circleEndAngleRAD - circleStartAngleRAD < 2 * pi)
          ? _items.length - 1
          : _items.length;

      ret.asMap().forEach((index, mat) {
        mat.translate(
          newCenter.dx +
              cos(
                    (circleEndAngleRAD - circleStartAngleRAD) /
                            nItems *
                            index +
                        circleStartAngleRAD,
                  ) *
                  widget.params.circleShapeParams.radiusX,
          newCenter.dy -
              sin(
                    (circleEndAngleRAD - circleStartAngleRAD) /
                            nItems *
                            index +
                        circleStartAngleRAD,
                  ) *
                  widget.params.circleShapeParams.radiusY,
        );
      });

    case MenuShape.linear:
      var radius = 0.0;
      final rotate = lineAngleRAD;
      var itemDiameter = 0.0;
      var firstItemHalfWidth = 0.0;
      var firstItemHalfHeight = 0.0;
      var halfWidth = 0.0;
      var halfHeight = 0.0;
      double secH;
      double secV;

      ret.asMap().forEach((index, mat) {
        halfWidth = itemsParams[index].rect.width / 2;
        halfHeight = itemsParams[index].rect.height / 2;

        // itemDiameter is calculated by the segment length that intersect
        // the item bounding box passing through the center of the item
        // and intersect the opposite edges by m_startingAngle angle
        secH = (halfHeight / sin(rotate)).abs();
        secV = (halfWidth / sin(pi / 2 - rotate)).abs();

        // checks if the line intersect horizontal or vertical edges
        if (secH < secV) {
          itemDiameter = secH * 2.0;
        } else {
          itemDiameter = secV * 2.0;
        }

        // These checks if the line is perfectly vertical or horizontal
        if ((rotate + pi / 2) / pi == ((rotate + pi / 2) / pi).ceil()) {
          itemDiameter = halfHeight * 2;
        }
        if (rotate / pi == (rotate / pi).ceil()) itemDiameter = halfWidth * 2;

        if (index == 0) {
          firstItemHalfWidth = halfWidth;
          firstItemHalfHeight = halfHeight;
          mat.translate(newCenter.dx, newCenter.dy);
        } else {
          var alignmentShiftX = 0.0;
          var alignmentShiftY = 0.0;
          if (widget.params.linearShapeParams.alignment ==
              LinearAlignment.left) {
            alignmentShiftX = halfWidth - firstItemHalfWidth;
          }
          if (widget.params.linearShapeParams.alignment ==
              LinearAlignment.right) {
            alignmentShiftX = -halfWidth + firstItemHalfWidth;
          }
          if (widget.params.linearShapeParams.alignment ==
              LinearAlignment.top) {
            alignmentShiftY = halfHeight - firstItemHalfHeight;
          }
          if (widget.params.linearShapeParams.alignment ==
              LinearAlignment.bottom) {
            alignmentShiftY = -halfHeight + firstItemHalfHeight;
          }
          mat.translate(
            cos(lineAngleRAD) * (radius + halfWidth - firstItemHalfWidth) +
                newCenter.dx +
                alignmentShiftX,
            -sin(lineAngleRAD) * (radius + halfHeight - firstItemHalfHeight) +
                newCenter.dy +
                alignmentShiftY,
          );
        }

        radius += itemDiameter + widget.params.linearShapeParams.space;
      });

    case MenuShape.grid:
      var j = 0;
      var k = 0;
      var n = 0;
      var x = 0.0;
      var y = 0.0;
      var count = 0;
      var hMax = 0.0;
      var wMax = 0.0;
      double itemWidth;
      double itemHeight;
      final rowsWidth = <double>[];
      final itemPos = <Point>[];

      // Calculating the grid
      while (j * widget.params.gridShapeParams.columns + k < _items.length) {
        count = 0;
        hMax = 0;
        x = 0;
        // Calculate x position and rows height
        while (k < widget.params.gridShapeParams.columns &&
            j * widget.params.gridShapeParams.columns + k < _items.length) {
          itemWidth =
              itemsParams[widget.params.gridShapeParams.columns * j + k]
                  .rect
                  .width;
          itemHeight =
              itemsParams[widget.params.gridShapeParams.columns * j + k]
                  .rect
                  .height;
          itemPos.add(Point(x + itemWidth / 2, y));
          // hMax = max item height in this row
          hMax = max(hMax, itemHeight);
          x += itemWidth + widget.params.gridShapeParams.columnsSpaceH;
          count++;
          k++;
        }
        // wMax = max width of all rows
        wMax = max(wMax, x);
        rowsWidth.add(x - widget.params.gridShapeParams.columnsSpaceH);
        // Calculate y position for items in current row
        for (var i = 0; i < count; i++) {
          itemHeight = itemsParams[
                  widget.params.gridShapeParams.columns * j + k - i - 1]
              .rect
              .height;
          final x1 = itemPos[itemPos.length - i - 1].x.toDouble();
          final y1 = y + hMax / 2;
          itemPos[itemPos.length - i - 1] = Point(x1, y1);
        }
        y += hMax + widget.params.gridShapeParams.columnsSpaceV;
        k = 0;
        j++;
      }

      y -= widget.params.gridShapeParams.columnsSpaceV;
      // At this point:
      //    y = grid height
      //    wMax = grid width
      //    rowsWidth = list containing all the rows width
      //    it is now possible to center rows and
      //    center the grid in parent item
      n = 0;
      int dx;
      while (n < _items.length) {
        dx = ((wMax -
                    rowsWidth[(n / widget.params.gridShapeParams.columns)
                        .floor()]) /
                2)
            .floor();
        ret[n] = Matrix4.identity()
          ..translate(
            (itemPos[n].x + dx - wMax / 2) + newCenter.dx,
            (itemPos[n].y - y / 2) + newCenter.dy,
          );
        n++;
      }
  }

  return ret;
}