cleanup painters

fix
This commit is contained in:
Leptopoda-GitHub 2021-11-23 19:07:13 +01:00 committed by Nikolas Rimikis
parent f5feea1db6
commit 67797ec2bc
10 changed files with 487 additions and 552 deletions

View File

@ -34,7 +34,7 @@ class Game {
void init() {
// TODO: [Leptopoda] _position is already initialized with Position(). seems like duplicate code
_position = Position();
focusIndex = blurIndex = invalidIndex;
focusIndex = blurIndex = null;
}
void start() {
@ -47,7 +47,7 @@ class Game {
position.phase = Phase.ready;
start();
position.init();
focusIndex = blurIndex = invalidIndex;
focusIndex = blurIndex = null;
moveHistory = [""];
sideToMove = PieceColor.white;
}
@ -64,8 +64,8 @@ class Game {
Position _position = Position();
Position get position => _position;
int focusIndex = invalidIndex;
int blurIndex = invalidIndex;
int? focusIndex;
int? blurIndex;
Map<String, bool> isSearching = {
PieceColor.white: false,
@ -113,7 +113,7 @@ class Game {
void select(int pos) {
focusIndex = pos;
blurIndex = invalidIndex;
blurIndex = null;
}
Future<bool> doMove(String move) async {

View File

@ -522,7 +522,7 @@ class Position {
} else {
changeSideToMove();
}
gameInstance.focusIndex = squareToIndex[s] ?? invalidIndex;
gameInstance.focusIndex = squareToIndex[s];
await Audios.playTone(Sound.place);
} else {
pieceToRemoveCount = rule.mayRemoveMultiple ? n : 1;
@ -558,7 +558,7 @@ class Position {
action = Act.remove;
}
gameInstance.focusIndex = squareToIndex[s] ?? invalidIndex;
gameInstance.focusIndex = squareToIndex[s];
await Audios.playTone(Sound.mill);
}
} else if (phase == Phase.moving) {
@ -606,14 +606,14 @@ class Position {
if (isGameOver()) {
return true;
} else {
gameInstance.focusIndex = squareToIndex[s] ?? invalidIndex;
gameInstance.focusIndex = squareToIndex[s];
await Audios.playTone(Sound.place);
}
} else {
pieceToRemoveCount = rule.mayRemoveMultiple ? n : 1;
updateKeyMisc();
action = Act.remove;
gameInstance.focusIndex = squareToIndex[s] ?? invalidIndex;
gameInstance.focusIndex = squareToIndex[s];
await Audios.playTone(Sound.mill);
}
} else {
@ -716,7 +716,7 @@ class Position {
currentSquare = sq;
action = Act.place;
gameInstance.blurIndex = squareToIndex[sq]!;
gameInstance.blurIndex = squareToIndex[sq];
return 0;
}

View File

@ -301,8 +301,6 @@ int makeMove(int from, int to) {
return (from << 8) + to;
}
const invalidIndex = -1;
Map<int, int> squareToIndex = {
8: 17,
9: 18,

View File

@ -40,17 +40,12 @@ import 'package:sanmill/shared/custom_spacer.dart';
import 'package:sanmill/shared/dialog.dart';
import 'package:sanmill/shared/game_toolbar/game_toolbar.dart';
import 'package:sanmill/shared/number_picker.dart';
import 'package:sanmill/shared/painters/painters.dart';
import 'package:sanmill/shared/snackbar.dart';
import 'package:sanmill/shared/theme/app_theme.dart';
import 'package:stack_trace/stack_trace.dart';
part 'package:sanmill/screens/game_page/board.dart';
part 'package:sanmill/shared/painters/board_painter.dart';
part 'package:sanmill/shared/painters/painter_base.dart';
part 'package:sanmill/shared/painters/pieces_painter.dart';
// TODO: [Leptopoda] remove variables that are not part of an object
double boardWidth = 0.0;
class GamePage extends StatefulWidget {
final EngineType engineType;
@ -77,6 +72,8 @@ class _GamePageState extends State<GamePage>
late Animation<double> animation;
bool disposed = false;
late bool ltr;
late double boardWidth;
static const String _tag = "[game_page]";
Future<void> _setReadyState() async {

View File

@ -1,314 +0,0 @@
/*
This file is part of Sanmill.
Copyright (C) 2019-2021 The Sanmill developers (see AUTHORS file)
Sanmill is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Sanmill is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
part of 'package:sanmill/screens/game_page/game_page.dart';
class BoardPainter extends PiecesBasePainter {
BoardPainter({required double width}) : super(width: width);
@override
void paint(Canvas canvas, Size size) {
doPaint(
canvas,
thePaint,
gridWidth,
squareWidth,
offsetX: AppTheme.boardPadding + squareWidth / 2,
offsetY: AppTheme.boardPadding + squareWidth / 2,
);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return false;
}
static void doPaint(
Canvas canvas,
Paint paint,
double gridWidth,
double squareWidth, {
required double offsetX,
required double offsetY,
}) {
paint.color = LocalDatabaseService.colorSettings.boardLineColor;
paint.style = PaintingStyle.stroke;
final left = offsetX;
final top = offsetY;
paint.strokeWidth = LocalDatabaseService.display.boardBorderLineWidth;
if (LocalDatabaseService.display.isPieceCountInHandShown) {
var pieceInHandCount =
gameInstance.position.pieceInHandCount[PieceColor.black];
if (gameInstance.position.pieceOnBoardCount[PieceColor.white] == 0 &&
gameInstance.position.pieceOnBoardCount[PieceColor.black] == 0) {
pieceInHandCount = LocalDatabaseService.rules.piecesCount;
}
var pieceInHandCountStr = "";
// TODO: [Leptopoda] only paint it when the phase is placing.
if (gameInstance.position.phase == Phase.placing) {
pieceInHandCountStr = pieceInHandCount.toString();
}
final TextSpan textSpan = TextSpan(
style: TextStyle(
fontSize: 48,
color: LocalDatabaseService.colorSettings.boardLineColor,
), // TODO
text: pieceInHandCountStr,
);
final TextPainter textPainter = TextPainter(
text: textSpan,
textAlign: TextAlign.center,
textDirection: TextDirection.ltr,
);
textPainter.layout();
textPainter.paint(
canvas,
Offset(
left + squareWidth * 3 - textPainter.width / 2,
top + squareWidth * 3 - textPainter.height / 2,
),
);
}
if (LocalDatabaseService.display.isNotationsShown) {
const String verticalNotations = "abcdefg";
const String horizontalNotations = "7654321";
String notationV = "";
String notationH = "";
for (int i = 0; i < 7; i++) {
notationV = verticalNotations[i];
notationH = horizontalNotations[i];
final TextSpan notationSpanV = TextSpan(
style: AppTheme.notationTextStyle, // TODO
text: notationV,
);
final TextSpan notationSpanH = TextSpan(
style: AppTheme.notationTextStyle, // TODO
text: notationH,
);
final TextPainter notationPainterV = TextPainter(
text: notationSpanV,
textAlign: TextAlign.center,
textDirection: TextDirection.ltr,
);
final TextPainter notationPainterH = TextPainter(
text: notationSpanH,
textAlign: TextAlign.center,
textDirection: TextDirection.ltr,
);
notationPainterV.layout();
notationPainterH.layout();
final offset = (boardWidth - squareWidth * 6) / 4;
// Show notations "a b c d e f" on board
if (LocalDatabaseService.preferences.developerMode) {
notationPainterV.paint(
canvas,
Offset(
left + squareWidth * i - notationPainterV.width / 2,
top - offset - notationPainterV.height / 2,
),
);
}
notationPainterV.paint(
canvas,
Offset(
left + squareWidth * i - notationPainterV.width / 2,
top + squareWidth * 6 + offset - notationPainterV.height / 2,
),
);
// Show notations "1 2 3 4 5 6 7" on board
notationPainterH.paint(
canvas,
Offset(
left - offset - notationPainterH.width / 2,
top + squareWidth * i - notationPainterH.height / 2,
),
);
if (LocalDatabaseService.preferences.developerMode) {
notationPainterH.paint(
canvas,
Offset(
left + squareWidth * 6 + offset - notationPainterH.width / 2,
top + squareWidth * i - notationPainterH.height / 2,
),
);
}
}
}
// File C
canvas.drawRect(
Rect.fromLTWH(left, top, squareWidth * 6, squareWidth * 6),
paint,
);
paint.strokeWidth = LocalDatabaseService.display.boardInnerLineWidth;
final double bias = paint.strokeWidth / 2;
// File B
canvas.drawRect(
Rect.fromLTWH(
left + squareWidth * 1,
top + squareWidth * 1,
squareWidth * 4,
squareWidth * 4,
),
paint,
);
// File A
canvas.drawRect(
Rect.fromLTWH(
left + squareWidth * 2,
top + squareWidth * 2,
squareWidth * 2,
squareWidth * 2,
),
paint,
);
// Middle horizontal lines (Left to Right)
canvas.drawLine(
Offset(left - bias, top + squareWidth * 3),
Offset(left + squareWidth * 2 + bias, top + squareWidth * 3),
paint,
);
canvas.drawLine(
Offset(left + squareWidth * 4 - bias, top + squareWidth * 3),
Offset(left + squareWidth * 6 + bias, top + squareWidth * 3),
paint,
);
// Middle horizontal lines (Top to Bottom)
canvas.drawLine(
Offset(left + squareWidth * 3, top - bias),
Offset(left + squareWidth * 3, top + squareWidth * 2 + bias),
paint,
);
canvas.drawLine(
Offset(left + squareWidth * 3, top + squareWidth * 4 - bias),
Offset(left + squareWidth * 3, top + squareWidth * 6 + bias),
paint,
);
// Point
if (LocalDatabaseService.display.pointStyle != 0) {
if (LocalDatabaseService.display.pointStyle == 1) {
paint.style = PaintingStyle.fill;
} else if (LocalDatabaseService.display.pointStyle == 2) {
paint.style = PaintingStyle.stroke; // TODO: WIP
}
final double pointRadius = LocalDatabaseService.display.pointWidth;
final points = [
[0, 0],
[0, 3],
[0, 6],
[1, 1],
[1, 3],
[1, 5],
[2, 2],
[2, 3],
[2, 4],
[3, 0],
[3, 1],
[3, 2],
[3, 4],
[3, 5],
[3, 6],
[4, 2],
[4, 3],
[4, 4],
[5, 1],
[5, 3],
[5, 5],
[6, 0],
[6, 3],
[6, 6],
];
for (final point in points) {
canvas.drawCircle(
Offset(left + squareWidth * point[0], top + squareWidth * point[1]),
pointRadius,
paint,
);
}
}
if (!LocalDatabaseService.rules.hasDiagonalLines) {
return;
}
// top left diagonal line
canvas.drawLine(
Offset(left + 0, top),
Offset(left + squareWidth * 2, top + squareWidth * 2),
paint,
);
// lower right diagonal line
canvas.drawLine(
Offset(left + squareWidth * 4, top + squareWidth * 4),
Offset(left + squareWidth * 6, top + squareWidth * 6),
paint,
);
// top right diagonal line
canvas.drawLine(
Offset(left + squareWidth * 6, top),
Offset(left + squareWidth * 4, top + squareWidth * 2),
paint,
);
// lower left diagonal line
canvas.drawLine(
Offset(left + squareWidth * 2, top + squareWidth * 4),
Offset(left + squareWidth * 0, top + squareWidth * 6),
paint,
);
}
}

View File

@ -0,0 +1,31 @@
/*
This file is part of Sanmill.
Copyright (C) 2019-2021 The Sanmill developers (see AUTHORS file)
Sanmill is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Sanmill is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/// Although marked as a library this package is tightly integrated into the app
library painters;
import 'package:flutter/material.dart';
import 'package:sanmill/mill/game.dart';
import 'package:sanmill/mill/position.dart';
import 'package:sanmill/mill/types.dart';
import 'package:sanmill/services/storage/storage.dart';
import 'package:sanmill/shared/theme/app_theme.dart';
part 'src/board_painter.dart';
part 'src/painter_base.dart';
part 'src/pieces_painter.dart';

View File

@ -1,214 +0,0 @@
/*
This file is part of Sanmill.
Copyright (C) 2019-2021 The Sanmill developers (see AUTHORS file)
Sanmill is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Sanmill is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
part of 'package:sanmill/screens/game_page/game_page.dart';
class PiecePaintParam {
final String piece;
final Offset pos;
final bool animated;
PiecePaintParam({
required this.piece,
required this.pos,
required this.animated,
});
}
class PiecesPainter extends PiecesBasePainter {
final Position position;
final int focusIndex;
final int blurIndex;
final double animationValue;
int pointStyle = 0;
double pointWidth = 10.0;
double pieceWidth = 0.0;
double animatedPieceWidth = 0.0;
PiecesPainter({
required double width,
required this.position,
this.focusIndex = invalidIndex,
this.blurIndex = invalidIndex,
required this.animationValue,
}) : super(width: width) {
pointStyle = LocalDatabaseService.display.pointStyle;
pointWidth = LocalDatabaseService.display.pointWidth;
pieceWidth = squareWidth * LocalDatabaseService.display.pieceWidth;
animatedPieceWidth =
squareWidth * LocalDatabaseService.display.pieceWidth * animationValue;
}
@override
void paint(Canvas canvas, Size size) {
doPaint(
canvas,
thePaint,
position: position,
gridWidth: gridWidth,
squareWidth: squareWidth,
pointStyle: pointStyle,
pointWidth: pointWidth,
pieceWidth: pieceWidth,
animatedPieceWidth: animatedPieceWidth,
offsetX: AppTheme.boardPadding + squareWidth / 2,
offsetY: AppTheme.boardPadding + squareWidth / 2,
focusIndex: focusIndex,
blurIndex: blurIndex,
);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
static void doPaint(
Canvas canvas,
Paint paint, {
required Position position,
required double gridWidth,
required double squareWidth,
required int pointStyle,
required double pointWidth,
required double pieceWidth,
required double animatedPieceWidth,
required double offsetX,
required double offsetY,
int focusIndex = invalidIndex,
int blurIndex = invalidIndex,
}) {
final left = offsetX;
final top = offsetY;
final shadowPath = Path();
final piecesToDraw = <PiecePaintParam>[];
late Color blurPositionColor;
Color focusPositionColor;
// Draw pieces on board
for (var row = 0; row < 7; row++) {
for (var col = 0; col < 7; col++) {
final index = row * 7 + col;
final piece = position.pieceOnGrid(index); // No Pieces when initial
if (piece == Piece.noPiece) continue;
final pos = Offset(left + squareWidth * col, top + squareWidth * row);
final animated = focusIndex == index;
piecesToDraw
.add(PiecePaintParam(piece: piece, pos: pos, animated: animated));
shadowPath.addOval(
Rect.fromCenter(center: pos, width: pieceWidth, height: pieceWidth),
);
}
}
// Draw shadow of piece
canvas.drawShadow(shadowPath, Colors.black, 2, true);
paint.style = PaintingStyle.fill;
for (final pps in piecesToDraw) {
final pieceRadius = pieceWidth / 2;
final pieceInnerRadius = pieceRadius * 0.99;
final animatedPieceRadius = animatedPieceWidth / 2;
final animatedPieceInnerRadius = animatedPieceRadius * 0.99;
// Draw Border of Piece
switch (pps.piece) {
case Piece.whiteStone:
paint.color = AppTheme.whitePieceBorderColor;
canvas.drawCircle(
pps.pos,
pps.animated ? animatedPieceRadius : pieceRadius,
paint,
);
paint.color = LocalDatabaseService.colorSettings.whitePieceColor;
canvas.drawCircle(
pps.pos,
pps.animated ? animatedPieceInnerRadius : pieceInnerRadius,
paint,
);
blurPositionColor = LocalDatabaseService.colorSettings.whitePieceColor
.withOpacity(0.1);
break;
case Piece.blackStone:
paint.color = AppTheme.blackPieceBorderColor;
canvas.drawCircle(
pps.pos,
pps.animated ? animatedPieceRadius : pieceRadius,
paint,
);
paint.color = LocalDatabaseService.colorSettings.blackPieceColor;
canvas.drawCircle(
pps.pos,
pps.animated ? animatedPieceInnerRadius : pieceInnerRadius,
paint,
);
blurPositionColor = LocalDatabaseService.colorSettings.blackPieceColor
.withOpacity(0.1);
break;
case Piece.ban:
//print("pps.piece is Ban");
break;
default:
assert(false);
break;
}
}
// draw focus and blur position
final int row = focusIndex ~/ 7;
final int column = focusIndex % 7;
if (focusIndex != invalidIndex) {
focusPositionColor =
LocalDatabaseService.colorSettings.pieceHighlightColor;
paint.color = focusPositionColor;
paint.style = PaintingStyle.stroke;
paint.strokeWidth = 2;
canvas.drawCircle(
Offset(left + column * squareWidth, top + row * squareWidth),
animatedPieceWidth / 2,
paint,
);
}
if (blurIndex != invalidIndex) {
final row = blurIndex ~/ 7;
final column = blurIndex % 7;
paint.color = blurPositionColor;
paint.style = PaintingStyle.fill;
canvas.drawCircle(
Offset(left + column * squareWidth, top + row * squareWidth),
animatedPieceWidth / 2 * 0.8,
paint,
);
}
}
}

View File

@ -0,0 +1,266 @@
/*
This file is part of Sanmill.
Copyright (C) 2019-2021 The Sanmill developers (see AUTHORS file)
Sanmill is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Sanmill is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
part of '../painters.dart';
class BoardPainter extends PiecesBasePainter {
BoardPainter({required double width}) : super(width: width);
@override
void paint(Canvas canvas, Size size) => _doPaint(canvas, thePaint);
@override
bool shouldRepaint(CustomPainter oldDelegate) => false;
void _doPaint(Canvas canvas, Paint paint) {
paint.strokeWidth = LocalDatabaseService.display.boardBorderLineWidth;
paint.color = LocalDatabaseService.colorSettings.boardLineColor;
paint.style = PaintingStyle.stroke;
if (LocalDatabaseService.display.isPieceCountInHandShown &&
gameInstance.position.phase == Phase.placing) {
final int pieceInHandCount;
if (gameInstance.position.pieceOnBoardCount[PieceColor.white] == 0 &&
gameInstance.position.pieceOnBoardCount[PieceColor.black] == 0) {
pieceInHandCount = LocalDatabaseService.rules.piecesCount;
} else {
pieceInHandCount =
gameInstance.position.pieceInHandCount[PieceColor.black]!;
}
final TextSpan textSpan = TextSpan(
style: TextStyle(
fontSize: 48,
color: LocalDatabaseService.colorSettings.boardLineColor,
), // TODO
text: pieceInHandCount.toString(),
);
final TextPainter textPainter = TextPainter(
text: textSpan,
textAlign: TextAlign.center,
textDirection: TextDirection.ltr,
);
textPainter.layout();
textPainter.paint(
canvas,
_offset.translate(
_squareWidth * 3 - textPainter.width / 2,
_squareWidth * 3 - textPainter.height / 2,
),
);
}
if (LocalDatabaseService.display.isNotationsShown) {
const String verticalNotations = "abcdefg";
const String horizontalNotations = "7654321";
for (int i = 0; i < 7; i++) {
final String notationV = verticalNotations[i];
final String notationH = horizontalNotations[i];
final TextSpan notationSpanV = TextSpan(
style: AppTheme.notationTextStyle, // TODO
text: notationV,
);
final TextSpan notationSpanH = TextSpan(
style: AppTheme.notationTextStyle, // TODO
text: notationH,
);
final TextPainter notationPainterV = TextPainter(
text: notationSpanV,
textAlign: TextAlign.center,
textDirection: TextDirection.ltr,
);
final TextPainter notationPainterH = TextPainter(
text: notationSpanH,
textAlign: TextAlign.center,
textDirection: TextDirection.ltr,
);
notationPainterV.layout();
notationPainterH.layout();
final offset = (width - _squareWidth * 6) / 4;
// Show notations "a b c d e f" on board
if (LocalDatabaseService.preferences.developerMode) {
notationPainterV.paint(
canvas,
_offset.translate(
_squareWidth * i - notationPainterV.width / 2,
-offset - notationPainterV.height / 2,
),
);
}
notationPainterV.paint(
canvas,
_offset.translate(
_squareWidth * i - notationPainterV.width / 2,
_squareWidth * 6 + offset - notationPainterV.height / 2,
),
);
// Show notations "1 2 3 4 5 6 7" on board
notationPainterH.paint(
canvas,
_offset.translate(
-offset - notationPainterH.width / 2,
_squareWidth * i - notationPainterH.height / 2,
),
);
if (LocalDatabaseService.preferences.developerMode) {
notationPainterH.paint(
canvas,
_offset.translate(
_squareWidth * 6 + offset - notationPainterH.width / 2,
_squareWidth * i - notationPainterH.height / 2,
),
);
}
}
}
final points = [
_offset + Offset(_squareWidth * 0, _squareWidth * 0), // 0
_offset + Offset(_squareWidth * 0, _squareWidth * 3), // 1
_offset + Offset(_squareWidth * 0, _squareWidth * 6), // 2
_offset + Offset(_squareWidth * 1, _squareWidth * 1), // 3
_offset + Offset(_squareWidth * 1, _squareWidth * 3), // 4
_offset + Offset(_squareWidth * 1, _squareWidth * 5), // 5
_offset + Offset(_squareWidth * 2, _squareWidth * 2), // 6
_offset + Offset(_squareWidth * 2, _squareWidth * 3), // 7
_offset + Offset(_squareWidth * 2, _squareWidth * 4), // 8
_offset + Offset(_squareWidth * 3, _squareWidth * 0), // 9
_offset + Offset(_squareWidth * 3, _squareWidth * 1), // 10
_offset + Offset(_squareWidth * 3, _squareWidth * 2), // 11
_offset + Offset(_squareWidth * 3, _squareWidth * 4), // 12
_offset + Offset(_squareWidth * 3, _squareWidth * 5), // 13
_offset + Offset(_squareWidth * 3, _squareWidth * 6), // 14
_offset + Offset(_squareWidth * 4, _squareWidth * 2), // 15
_offset + Offset(_squareWidth * 4, _squareWidth * 3), // 16
_offset + Offset(_squareWidth * 4, _squareWidth * 4), // 17
_offset + Offset(_squareWidth * 5, _squareWidth * 1), // 18
_offset + Offset(_squareWidth * 5, _squareWidth * 3), // 19
_offset + Offset(_squareWidth * 5, _squareWidth * 5), // 20
_offset + Offset(_squareWidth * 6, _squareWidth * 0), // 21
_offset + Offset(_squareWidth * 6, _squareWidth * 3), // 22
_offset + Offset(_squareWidth * 6, _squareWidth * 6), // 23
];
// File C
canvas.drawRect(
Rect.fromLTWH(_offset.dx, _offset.dy, _squareWidth * 6, _squareWidth * 6),
paint,
);
paint.strokeWidth = LocalDatabaseService.display.boardInnerLineWidth;
final double bias = paint.strokeWidth / 2;
// File B
canvas.drawRect(
Rect.fromLTWH(
_offset.dx + _squareWidth * 1,
_offset.dy + _squareWidth * 1,
_squareWidth * 4,
_squareWidth * 4,
),
paint,
);
// File A
canvas.drawRect(
Rect.fromLTWH(
_offset.dx + _squareWidth * 2,
_offset.dy + _squareWidth * 2,
_squareWidth * 2,
_squareWidth * 2,
),
paint,
);
// Middle horizontal lines (offsetX to Right)
canvas.drawLine(
points[1].translate(-bias, 0),
points[7].translate(bias, 0),
paint,
);
canvas.drawLine(
points[16].translate(-bias, 0),
points[22].translate(bias, 0),
paint,
);
// Middle horizontal lines (offsetY to Bottom)
canvas.drawLine(
points[9].translate(0, -bias),
points[11].translate(0, bias),
paint,
);
canvas.drawLine(
points[12].translate(0, -bias),
points[14].translate(0, bias),
paint,
);
// TODO: [Leptopoda] use enum or so :)
// Point
switch (LocalDatabaseService.display.pointStyle) {
case 0:
break;
case 1:
paint.style = PaintingStyle.fill;
_drawPoint(points, canvas, paint);
break;
case 2:
paint.style = PaintingStyle.stroke;
_drawPoint(points, canvas, paint);
}
if (LocalDatabaseService.rules.hasDiagonalLines) {
// offsetY offsetX diagonal line
canvas.drawLine(points[0], points[6], paint);
// lower right diagonal line
canvas.drawLine(points[17], points[23], paint);
// offsetY right diagonal line
canvas.drawLine(points[21], points[15], paint);
// lower offsetX diagonal line
canvas.drawLine(points[8], points[2], paint);
}
}
static void _drawPoint(List<Offset> points, Canvas canvas, Paint paint) {
final double pointRadius = LocalDatabaseService.display.pointWidth;
for (final point in points) {
canvas.drawCircle(point, pointRadius, paint);
}
}
}

View File

@ -16,16 +16,21 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
part of 'package:sanmill/screens/game_page/game_page.dart';
part of '../painters.dart';
abstract class PiecesBasePainter extends CustomPainter {
final double width;
final thePaint = Paint();
final double gridWidth;
final double squareWidth;
late final double _squareWidth;
late final Offset _offset;
PiecesBasePainter({required this.width})
: gridWidth = width - AppTheme.boardPadding * 2,
squareWidth = (width - AppTheme.boardPadding * 2) / 7;
PiecesBasePainter({required this.width}) {
_squareWidth = (width - AppTheme.boardPadding * 2) / 7;
// equivalent to (width + 12 * AppTheme.boardPadding) / 14
final offset = AppTheme.boardPadding + _squareWidth / 2;
_offset = Offset(offset, offset);
}
}

View File

@ -0,0 +1,166 @@
/*
This file is part of Sanmill.
Copyright (C) 2019-2021 The Sanmill developers (see AUTHORS file)
Sanmill is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Sanmill is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
part of '../painters.dart';
class _PiecePaintParam {
final String piece;
final Offset pos;
final bool animated;
const _PiecePaintParam({
required this.piece,
required this.pos,
required this.animated,
});
}
class PiecesPainter extends PiecesBasePainter {
final Position position;
final int? focusIndex;
final int? blurIndex;
final double animationValue;
late final int pointStyle;
late final double pointWidth;
late final double pieceWidth;
late final double animatedPieceWidth;
PiecesPainter({
required double width,
required this.position,
this.focusIndex,
this.blurIndex,
required this.animationValue,
}) : super(width: width) {
pointStyle = LocalDatabaseService.display.pointStyle;
pointWidth = LocalDatabaseService.display.pointWidth;
pieceWidth = _squareWidth * LocalDatabaseService.display.pieceWidth;
animatedPieceWidth =
_squareWidth * LocalDatabaseService.display.pieceWidth * animationValue;
}
@override
void paint(Canvas canvas, Size size) => _doPaint(canvas, thePaint);
@override
bool shouldRepaint(CustomPainter oldDelegate) => true;
void _doPaint(Canvas canvas, Paint paint) {
final shadowPath = Path();
final piecesToDraw = <_PiecePaintParam>[];
// Draw pieces on board
for (var row = 0; row < 7; row++) {
for (var col = 0; col < 7; col++) {
final index = row * 7 + col;
final piece = position.pieceOnGrid(index); // No Pieces when initial
if (piece == Piece.noPiece) continue;
final pos = _offset.translate(_squareWidth * col, _squareWidth * row);
final animated = focusIndex == index;
piecesToDraw
.add(_PiecePaintParam(piece: piece, pos: pos, animated: animated));
shadowPath.addOval(
Rect.fromCenter(center: pos, width: pieceWidth, height: pieceWidth),
);
}
}
// Draw shadow of piece
canvas.drawShadow(shadowPath, Colors.black, 2, true);
paint.style = PaintingStyle.fill;
late Color blurPositionColor;
for (final pps in piecesToDraw) {
final pieceRadius = pieceWidth / 2;
final pieceInnerRadius = pieceRadius * 0.99;
final animatedPieceRadius = animatedPieceWidth / 2;
final animatedPieceInnerRadius = animatedPieceRadius * 0.99;
// TODO: [Leptopoda] move the following attributes into [_PiecePaintParam]
// Draw Border of Piece
late final Color border;
late final Color piece;
switch (pps.piece) {
case Piece.whiteStone:
border = AppTheme.whitePieceBorderColor;
piece = LocalDatabaseService.colorSettings.whitePieceColor;
blurPositionColor = LocalDatabaseService.colorSettings.whitePieceColor
.withOpacity(0.1);
break;
case Piece.blackStone:
border = AppTheme.blackPieceBorderColor;
piece = LocalDatabaseService.colorSettings.blackPieceColor;
blurPositionColor = LocalDatabaseService.colorSettings.blackPieceColor
.withOpacity(0.1);
break;
case Piece.ban:
//print("pps.piece is Ban");
continue;
}
paint.color = border;
canvas.drawCircle(
pps.pos,
pps.animated ? animatedPieceRadius : pieceRadius,
paint,
);
paint.color = piece;
canvas.drawCircle(
pps.pos,
pps.animated ? animatedPieceInnerRadius : pieceInnerRadius,
paint,
);
}
// draw focus and blur position
if (focusIndex != null) {
final row = focusIndex! ~/ 7;
final column = focusIndex! % 7;
paint.color = LocalDatabaseService.colorSettings.pieceHighlightColor;
paint.style = PaintingStyle.stroke;
paint.strokeWidth = 2;
canvas.drawCircle(
_offset.translate(column * _squareWidth, row * _squareWidth),
animatedPieceWidth / 2,
paint,
);
}
if (blurIndex != null) {
final row = blurIndex! ~/ 7;
final column = blurIndex! % 7;
paint.color = blurPositionColor;
paint.style = PaintingStyle.fill;
canvas.drawCircle(
_offset.translate(column * _squareWidth, row * _squareWidth),
animatedPieceWidth / 2 * 0.8,
paint,
);
}
}
}