From 67797ec2bc797c9732a5a1142a3d2b22357a686e Mon Sep 17 00:00:00 2001 From: Leptopoda-GitHub Date: Tue, 23 Nov 2021 19:07:13 +0100 Subject: [PATCH] cleanup painters fix --- src/ui/flutter_app/lib/mill/game.dart | 10 +- src/ui/flutter_app/lib/mill/position.dart | 10 +- src/ui/flutter_app/lib/mill/types.dart | 2 - .../lib/screens/game_page/game_page.dart | 9 +- .../lib/shared/painters/board_painter.dart | 314 ------------------ .../lib/shared/painters/painters.dart | 31 ++ .../lib/shared/painters/pieces_painter.dart | 214 ------------ .../shared/painters/src/board_painter.dart | 266 +++++++++++++++ .../painters/{ => src}/painter_base.dart | 17 +- .../shared/painters/src/pieces_painter.dart | 166 +++++++++ 10 files changed, 487 insertions(+), 552 deletions(-) delete mode 100644 src/ui/flutter_app/lib/shared/painters/board_painter.dart create mode 100644 src/ui/flutter_app/lib/shared/painters/painters.dart delete mode 100644 src/ui/flutter_app/lib/shared/painters/pieces_painter.dart create mode 100644 src/ui/flutter_app/lib/shared/painters/src/board_painter.dart rename src/ui/flutter_app/lib/shared/painters/{ => src}/painter_base.dart (69%) create mode 100644 src/ui/flutter_app/lib/shared/painters/src/pieces_painter.dart diff --git a/src/ui/flutter_app/lib/mill/game.dart b/src/ui/flutter_app/lib/mill/game.dart index 4eda4100..5ec95d86 100644 --- a/src/ui/flutter_app/lib/mill/game.dart +++ b/src/ui/flutter_app/lib/mill/game.dart @@ -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 isSearching = { PieceColor.white: false, @@ -113,7 +113,7 @@ class Game { void select(int pos) { focusIndex = pos; - blurIndex = invalidIndex; + blurIndex = null; } Future doMove(String move) async { diff --git a/src/ui/flutter_app/lib/mill/position.dart b/src/ui/flutter_app/lib/mill/position.dart index 9939d21f..6ad2d403 100644 --- a/src/ui/flutter_app/lib/mill/position.dart +++ b/src/ui/flutter_app/lib/mill/position.dart @@ -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; } diff --git a/src/ui/flutter_app/lib/mill/types.dart b/src/ui/flutter_app/lib/mill/types.dart index f38061ba..88662f8d 100644 --- a/src/ui/flutter_app/lib/mill/types.dart +++ b/src/ui/flutter_app/lib/mill/types.dart @@ -301,8 +301,6 @@ int makeMove(int from, int to) { return (from << 8) + to; } -const invalidIndex = -1; - Map squareToIndex = { 8: 17, 9: 18, diff --git a/src/ui/flutter_app/lib/screens/game_page/game_page.dart b/src/ui/flutter_app/lib/screens/game_page/game_page.dart index 2e6bb26a..72bb375d 100644 --- a/src/ui/flutter_app/lib/screens/game_page/game_page.dart +++ b/src/ui/flutter_app/lib/screens/game_page/game_page.dart @@ -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 late Animation animation; bool disposed = false; late bool ltr; + late double boardWidth; + static const String _tag = "[game_page]"; Future _setReadyState() async { diff --git a/src/ui/flutter_app/lib/shared/painters/board_painter.dart b/src/ui/flutter_app/lib/shared/painters/board_painter.dart deleted file mode 100644 index 9bb982fe..00000000 --- a/src/ui/flutter_app/lib/shared/painters/board_painter.dart +++ /dev/null @@ -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 . -*/ - -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, - ); - } -} diff --git a/src/ui/flutter_app/lib/shared/painters/painters.dart b/src/ui/flutter_app/lib/shared/painters/painters.dart new file mode 100644 index 00000000..99f8b582 --- /dev/null +++ b/src/ui/flutter_app/lib/shared/painters/painters.dart @@ -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 . +*/ + +/// 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'; diff --git a/src/ui/flutter_app/lib/shared/painters/pieces_painter.dart b/src/ui/flutter_app/lib/shared/painters/pieces_painter.dart deleted file mode 100644 index f7c67fb6..00000000 --- a/src/ui/flutter_app/lib/shared/painters/pieces_painter.dart +++ /dev/null @@ -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 . -*/ - -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 = []; - - 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, - ); - } - } -} diff --git a/src/ui/flutter_app/lib/shared/painters/src/board_painter.dart b/src/ui/flutter_app/lib/shared/painters/src/board_painter.dart new file mode 100644 index 00000000..2bc79257 --- /dev/null +++ b/src/ui/flutter_app/lib/shared/painters/src/board_painter.dart @@ -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 . +*/ + +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 points, Canvas canvas, Paint paint) { + final double pointRadius = LocalDatabaseService.display.pointWidth; + + for (final point in points) { + canvas.drawCircle(point, pointRadius, paint); + } + } +} diff --git a/src/ui/flutter_app/lib/shared/painters/painter_base.dart b/src/ui/flutter_app/lib/shared/painters/src/painter_base.dart similarity index 69% rename from src/ui/flutter_app/lib/shared/painters/painter_base.dart rename to src/ui/flutter_app/lib/shared/painters/src/painter_base.dart index b8c62b3e..2770b75f 100644 --- a/src/ui/flutter_app/lib/shared/painters/painter_base.dart +++ b/src/ui/flutter_app/lib/shared/painters/src/painter_base.dart @@ -16,16 +16,21 @@ along with this program. If not, see . */ -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); + } } diff --git a/src/ui/flutter_app/lib/shared/painters/src/pieces_painter.dart b/src/ui/flutter_app/lib/shared/painters/src/pieces_painter.dart new file mode 100644 index 00000000..60ef49a4 --- /dev/null +++ b/src/ui/flutter_app/lib/shared/painters/src/pieces_painter.dart @@ -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 . +*/ + +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, + ); + } + } +}