calcPosition method
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;
}