diff --git a/example/lib/main.dart b/example/lib/main.dart index 571203b..4a8845d 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -71,6 +71,7 @@ class _HomePageState extends State { bool drawMode = true; bool pieceAnimation = true; bool dragMagnify = true; + bool pieceShadow = true; Mode playMode = Mode.botPlay; Position? lastPos; ISet shapes = ISet(); @@ -165,6 +166,22 @@ class _HomePageState extends State { ), ], ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + children: [ + ElevatedButton( + child: Text( + 'Shadow under dragged piece: ${pieceShadow ? 'ON' : 'OFF'}'), + onPressed: () { + setState(() { + pieceShadow = !pieceShadow; + }); + } + ), + const SizedBox(width: 8), + ], + ), Row( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.max, @@ -194,11 +211,11 @@ class _HomePageState extends State { child: IconButton( onPressed: lastPos != null ? () => setState(() { - position = lastPos!; - fen = position.fen; - validMoves = makeLegalMoves(position); - lastPos = null; - }) + position = lastPos!; + fen = position.fen; + validMoves = makeLegalMoves(position); + lastPos = null; + }) : null, icon: const Icon(Icons.chevron_left_sharp))), ]; @@ -222,67 +239,67 @@ class _HomePageState extends State { return Scaffold( appBar: AppBar( title: switch (playMode) { - Mode.botPlay => const Text('Random Bot'), - Mode.inputMove => const Text('Enter opponent move'), - Mode.freePlay => const Text('Free Play'), - }), + Mode.botPlay => const Text('Random Bot'), + Mode.inputMove => const Text('Enter opponent move'), + Mode.freePlay => const Text('Free Play'), + }), drawer: Drawer( child: ListView( - children: [ - ListTile( - title: const Text('Random Bot'), - onTap: () { - setState(() { - playMode = Mode.botPlay; - }); - if (position.turn == Side.black) { - _playBlackMove(); - } - Navigator.pop(context); - }, - ), - ListTile( - title: const Text('Enter opponent move'), - onTap: () { - setState(() { - playMode = Mode.inputMove; - }); - Navigator.pop(context); - }, - ), - ListTile( - title: const Text('Free Play'), - onTap: () { - setState(() { - playMode = Mode.freePlay; - }); - Navigator.pop(context); - }, - ), - ListTile( - title: const Text('Board Editor'), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const BoardEditorPage(), - ), - ); - }, - ), - ListTile( - title: const Text('Board Thumbnails'), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const BoardThumbnailsPage(), - ), - ); - }, - ), - ], - )), + children: [ + ListTile( + title: const Text('Random Bot'), + onTap: () { + setState(() { + playMode = Mode.botPlay; + }); + if (position.turn == Side.black) { + _playBlackMove(); + } + Navigator.pop(context); + }, + ), + ListTile( + title: const Text('Enter opponent move'), + onTap: () { + setState(() { + playMode = Mode.inputMove; + }); + Navigator.pop(context); + }, + ), + ListTile( + title: const Text('Free Play'), + onTap: () { + setState(() { + playMode = Mode.freePlay; + }); + Navigator.pop(context); + }, + ), + ListTile( + title: const Text('Board Editor'), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const BoardEditorPage(), + ), + ); + }, + ), + ListTile( + title: const Text('Board Thumbnails'), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const BoardThumbnailsPage(), + ), + ); + }, + ), + ], + )), body: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ @@ -296,6 +313,7 @@ class _HomePageState extends State { ? const Duration(milliseconds: 200) : Duration.zero, dragFeedbackScale: dragMagnify ? 2.0 : 1.0, + pieceShadow: pieceShadow, drawShape: DrawShapeOptions( enable: drawMode, onCompleteShape: _onCompleteShape, @@ -316,21 +334,21 @@ class _HomePageState extends State { lastMove: lastMove, game: GameData( playerSide: - (playMode == Mode.botPlay || playMode == Mode.inputMove) - ? PlayerSide.white - : (position.turn == Side.white - ? PlayerSide.white - : PlayerSide.black), + (playMode == Mode.botPlay || playMode == Mode.inputMove) + ? PlayerSide.white + : (position.turn == Side.white + ? PlayerSide.white + : PlayerSide.black), validMoves: validMoves, sideToMove: position.turn == Side.white ? Side.white : Side.black, isCheck: position.isCheck, promotionMove: promotionMove, onMove: - playMode == Mode.botPlay ? _onUserMoveAgainstBot : _playMove, + playMode == Mode.botPlay ? _onUserMoveAgainstBot : _playMove, onPromotionSelection: _onPromotionSelection, premovable: ( - onSetPremove: _onSetPremove, - premove: premove, + onSetPremove: _onSetPremove, + premove: premove, ), ), shapes: shapes.isNotEmpty ? shapes : null, @@ -338,7 +356,7 @@ class _HomePageState extends State { Column( crossAxisAlignment: CrossAxisAlignment.center, children: - playMode == Mode.inputMove ? inputMoveWidgets : settingsWidgets, + playMode == Mode.inputMove ? inputMoveWidgets : settingsWidgets, ), ], ), @@ -367,12 +385,12 @@ class _HomePageState extends State { } void _showChoicesPicker( - BuildContext context, { - required List choices, - required T selectedItem, - required Widget Function(T choice) labelBuilder, - required void Function(T choice) onSelectedItemChanged, - }) { + BuildContext context, { + required List choices, + required T selectedItem, + required Widget Function(T choice) labelBuilder, + required void Function(T choice) onSelectedItemChanged, + }) { showDialog( context: context, builder: (context) { diff --git a/example/pubspec.lock b/example/pubspec.lock index 54fbda2..2fabe08 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -44,10 +44,10 @@ packages: dependency: transitive description: name: collection - sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.19.0" + version: "1.18.0" cupertino_icons: dependency: "direct main" description: @@ -195,10 +195,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.2.0" term_glyph: dependency: transitive description: @@ -211,10 +211,10 @@ packages: dependency: transitive description: name: test_api - sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.7.3" + version: "0.7.2" vector_math: dependency: transitive description: @@ -227,10 +227,10 @@ packages: dependency: transitive description: name: vm_service - sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.dev" source: hosted - version: "14.2.4" + version: "14.2.5" sdks: - dart: ">=3.4.0 <4.0.0" + dart: ">=3.3.0 <4.0.0" flutter: ">=3.18.0-18.0.pre.54" diff --git a/lib/src/board_settings.dart b/lib/src/board_settings.dart index f7c461e..14e7ef8 100644 --- a/lib/src/board_settings.dart +++ b/lib/src/board_settings.dart @@ -49,6 +49,7 @@ class ChessboardSettings { this.blindfoldMode = false, this.dragFeedbackScale = 2.0, this.dragFeedbackOffset = const Offset(0.0, -1.0), + this.pieceShadow = true, this.pieceOrientationBehavior = PieceOrientationBehavior.facingUser, // shape drawing @@ -94,6 +95,9 @@ class ChessboardSettings { // Offset for the piece currently under drag final Offset dragFeedbackOffset; + /// Whether the dark shadow under dragged pieces is enabled + final bool pieceShadow; + /// Controls if any pieces are displayed upside down. final PieceOrientationBehavior pieceOrientationBehavior; @@ -134,6 +138,7 @@ class ChessboardSettings { other.blindfoldMode == blindfoldMode && other.dragFeedbackScale == dragFeedbackScale && other.dragFeedbackOffset == dragFeedbackOffset && + other.pieceShadow == pieceShadow && other.pieceOrientationBehavior == pieceOrientationBehavior && other.enablePremoveCastling == enablePremoveCastling && other.autoQueenPromotion == autoQueenPromotion && @@ -144,24 +149,25 @@ class ChessboardSettings { @override int get hashCode => Object.hash( - colorScheme, - pieceAssets, - borderRadius, - boxShadow, - enableCoordinates, - animationDuration, - showLastMove, - showValidMoves, - blindfoldMode, - dragFeedbackScale, - dragFeedbackOffset, - pieceOrientationBehavior, - enablePremoveCastling, - autoQueenPromotion, - autoQueenPromotionOnPremove, - pieceShiftMethod, - drawShape, - ); + colorScheme, + pieceAssets, + borderRadius, + boxShadow, + enableCoordinates, + animationDuration, + showLastMove, + showValidMoves, + blindfoldMode, + dragFeedbackScale, + dragFeedbackOffset, + pieceShadow, + pieceOrientationBehavior, + enablePremoveCastling, + autoQueenPromotion, + autoQueenPromotionOnPremove, + pieceShiftMethod, + drawShape, + ); ChessboardSettings copyWith({ ChessboardColorScheme? colorScheme, @@ -175,6 +181,7 @@ class ChessboardSettings { bool? blindfoldMode, double? dragFeedbackScale, Offset? dragFeedbackOffset, + bool? pieceShadow, PieceOrientationBehavior? pieceOrientationBehavior, bool? enablePremoveCastling, bool? autoQueenPromotion, @@ -194,12 +201,13 @@ class ChessboardSettings { blindfoldMode: blindfoldMode ?? this.blindfoldMode, dragFeedbackScale: dragFeedbackScale ?? this.dragFeedbackScale, dragFeedbackOffset: dragFeedbackOffset ?? this.dragFeedbackOffset, + pieceShadow: pieceShadow ?? this.pieceShadow, pieceOrientationBehavior: - pieceOrientationBehavior ?? this.pieceOrientationBehavior, + pieceOrientationBehavior ?? this.pieceOrientationBehavior, enablePremoveCastling: - enablePremoveCastling ?? this.enablePremoveCastling, + enablePremoveCastling ?? this.enablePremoveCastling, autoQueenPromotionOnPremove: - autoQueenPromotionOnPremove ?? this.autoQueenPromotionOnPremove, + autoQueenPromotionOnPremove ?? this.autoQueenPromotionOnPremove, autoQueenPromotion: autoQueenPromotion ?? this.autoQueenPromotion, pieceShiftMethod: pieceShiftMethod ?? this.pieceShiftMethod, drawShape: drawShape ?? this.drawShape, @@ -224,6 +232,7 @@ class ChessboardEditorSettings { this.enableCoordinates = true, this.dragFeedbackScale = 2.0, this.dragFeedbackOffset = const Offset(0.0, -1.0), + this.pieceShadow = true, }); /// Theme of the board. @@ -247,6 +256,9 @@ class ChessboardEditorSettings { // Offset for the piece currently under drag. final Offset dragFeedbackOffset; + // Whether the dark shadow under dragged pieces is enabled. + final bool pieceShadow; + @override bool operator ==(Object other) { if (identical(this, other)) { @@ -262,19 +274,21 @@ class ChessboardEditorSettings { other.boxShadow == boxShadow && other.enableCoordinates == enableCoordinates && other.dragFeedbackScale == dragFeedbackScale && - other.dragFeedbackOffset == dragFeedbackOffset; + other.dragFeedbackOffset == dragFeedbackOffset && + other.pieceShadow == pieceShadow; } @override int get hashCode => Object.hash( - colorScheme, - pieceAssets, - borderRadius, - boxShadow, - enableCoordinates, - dragFeedbackScale, - dragFeedbackOffset, - ); + colorScheme, + pieceAssets, + borderRadius, + boxShadow, + enableCoordinates, + dragFeedbackScale, + dragFeedbackOffset, + pieceShadow, + ); /// Creates a copy of this [ChessboardEditorSettings] but with the given fields replaced with the new values. ChessboardEditorSettings copyWith({ @@ -285,6 +299,7 @@ class ChessboardEditorSettings { bool? enableCoordinates, double? dragFeedbackScale, Offset? dragFeedbackOffset, + bool? pieceShadow, }) { return ChessboardEditorSettings( colorScheme: colorScheme ?? this.colorScheme, @@ -294,6 +309,7 @@ class ChessboardEditorSettings { enableCoordinates: enableCoordinates ?? this.enableCoordinates, dragFeedbackScale: dragFeedbackScale ?? this.dragFeedbackScale, dragFeedbackOffset: dragFeedbackOffset ?? this.dragFeedbackOffset, + pieceShadow: pieceShadow ?? this.pieceShadow, ); } } diff --git a/lib/src/widgets/board.dart b/lib/src/widgets/board.dart index 553ced5..4f1a916 100644 --- a/lib/src/widgets/board.dart +++ b/lib/src/widgets/board.dart @@ -1,21 +1,22 @@ import 'dart:async'; + import 'package:chessground/src/widgets/geometry.dart'; import 'package:dartchess/dartchess.dart'; +import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/widgets.dart'; -import 'package:fast_immutable_collections/fast_immutable_collections.dart'; -import 'piece.dart'; +import '../board_settings.dart'; +import '../fen.dart'; +import '../models.dart'; +import '../premove.dart'; +import 'animation.dart'; +import 'board_annotation.dart'; import 'highlight.dart'; +import 'piece.dart'; import 'positioned_square.dart'; -import 'animation.dart'; import 'promotion.dart'; import 'shape.dart'; -import 'board_annotation.dart'; -import '../models.dart'; -import '../fen.dart'; -import '../premove.dart'; -import '../board_settings.dart'; /// Number of logical pixels that have to be dragged before a drag starts. const double _kDragDistanceThreshold = 3.0; @@ -169,12 +170,12 @@ class _BoardState extends State { Widget build(BuildContext context) { final colorScheme = widget.settings.colorScheme; final ISet moveDests = widget.settings.showValidMoves && - selected != null && - widget.game?.validMoves != null + selected != null && + widget.game?.validMoves != null ? widget.game?.validMoves[selected!] ?? _emptyValidMoves : _emptyValidMoves; final Set premoveDests = - widget.settings.showValidMoves ? _premoveDests ?? {} : {}; + widget.settings.showValidMoves ? _premoveDests ?? {} : {}; final shapes = widget.shapes ?? _emptyShapes; final annotations = widget.annotations ?? _emptyAnnotations; final checkSquare = widget.game?.isCheck == true ? _getKingSquare() : null; @@ -182,8 +183,8 @@ class _BoardState extends State { final background = widget.settings.enableCoordinates ? widget.orientation == Side.white - ? colorScheme.whiteCoordBackground - : colorScheme.blackCoordBackground + ? colorScheme.whiteCoordBackground + : colorScheme.blackCoordBackground : colorScheme.background; final List highlightedBackground = [ @@ -524,8 +525,8 @@ class _BoardState extends State { } else { _cancelShapesDoubleTapTimer = Timer(_kCancelShapesDoubleTapDelay, () { - _cancelShapesDoubleTapTimer = null; - }); + _cancelShapesDoubleTapTimer = null; + }); } } // selecting a piece to move should clear shapes @@ -782,14 +783,16 @@ class _BoardState extends State { overlayState: Overlay.of(context, debugRequiredFor: widget), initialPosition: origin.position, initialTargetPosition: - _squareTargetGlobalOffset(origin.localPosition, _renderBox!), + _squareTargetGlobalOffset(origin.localPosition, _renderBox!), squareTargetFeedback: Container( width: widget.squareSize * 2, height: widget.squareSize * 2, - decoration: const BoxDecoration( + decoration: widget.settings.pieceShadow + ? const BoxDecoration( color: Color(0x33000000), shape: BoxShape.circle, - ), + ) + : null, ), pieceFeedback: Transform.translate( offset: Offset( @@ -834,9 +837,9 @@ class _BoardState extends State { switch (widget.settings.pieceOrientationBehavior) { PieceOrientationBehavior.facingUser => false, PieceOrientationBehavior.opponentUpsideDown => - pieceColor == widget.orientation.opposite, + pieceColor == widget.orientation.opposite, PieceOrientationBehavior.sideToPlay => - widget.game?.sideToMove == widget.orientation.opposite, + widget.game?.sideToMove == widget.orientation.opposite, }; /// Whether the piece is movable by the current side to move. @@ -905,9 +908,9 @@ class _BoardState extends State { _canPremoveTo(selected!, square)) { final isPromoPremove = _isPromoMove(selectedPiece!, square); final premove = - widget.settings.autoQueenPromotionOnPremove && isPromoPremove - ? NormalMove(from: selected!, to: square, promotion: Role.queen) - : NormalMove(from: selected!, to: square); + widget.settings.autoQueenPromotionOnPremove && isPromoPremove + ? NormalMove(from: selected!, to: square, promotion: Role.queen) + : NormalMove(from: selected!, to: square); widget.game?.premovable?.onSetPremove.call(premove); return true; }