Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a new setting to show a border around the board #57

Merged
merged 5 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class _HomePageState extends State<HomePage> {
Mode playMode = Mode.botPlay;
Position<Chess>? lastPos;
ISet<Shape> shapes = ISet();
bool showBorder = false;

@override
Widget build(BuildContext context) {
Expand Down Expand Up @@ -170,8 +171,8 @@ class _HomePageState extends State<HomePage> {
mainAxisSize: MainAxisSize.max,
children: [
ElevatedButton(
child: Text(
'Piece shift method: ${pieceShiftMethodLabel(pieceShiftMethod)}'),
child:
Text('Piece Shift: ${pieceShiftMethodLabel(pieceShiftMethod)}'),
onPressed: () => _showChoicesPicker<PieceShiftMethod>(
context,
choices: PieceShiftMethod.values,
Expand All @@ -187,6 +188,14 @@ class _HomePageState extends State<HomePage> {
),
),
const SizedBox(width: 8),
ElevatedButton(
child: Text("Show border: ${showBorder ? 'ON' : 'OFF'}"),
onPressed: () {
setState(() {
showBorder = !showBorder;
});
},
),
],
),
if (playMode == Mode.freePlay)
Expand Down Expand Up @@ -291,6 +300,12 @@ class _HomePageState extends State<HomePage> {
settings: ChessboardSettings(
pieceAssets: pieceSet.assets,
colorScheme: boardTheme.colors,
border: showBorder
? BoardBorder(
width: 16.0,
color: _darken(boardTheme.colors.darkSquare, 0.2),
)
: null,
enableCoordinates: true,
animationDuration: pieceAnimation
? const Duration(milliseconds: 200)
Expand Down Expand Up @@ -505,3 +520,8 @@ class _HomePageState extends State<HomePage> {
(move.to.rank == Rank.eighth && position.turn == Side.white));
}
}

Color _darken(Color c, [double amount = .1]) {
assert(amount >= 0 && amount <= 1);
return Color.lerp(c, const Color(0xFF000000), amount) ?? c;
}
2 changes: 1 addition & 1 deletion example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ packages:
path: ".."
relative: true
source: path
version: "5.3.0"
version: "5.4.0"
clock:
dependency: transitive
description:
Expand Down
53 changes: 53 additions & 0 deletions lib/src/board_settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,47 @@ enum PieceOrientationBehavior {
sideToPlay,
}

@immutable

/// Describes the border of the board.
class BoardBorder {
/// Creates a new border with the provided values.
const BoardBorder({
required this.color,
required this.width,
});

/// Color of the border
final Color color;

/// Width of the border
final double width;

@override
bool operator ==(Object other) {
if (identical(this, other)) {
return true;
}
if (other.runtimeType != runtimeType) {
return false;
}
return other is BoardBorder && other.color == color && other.width == width;
}

@override
int get hashCode => Object.hash(color, width);

BoardBorder copyWith({
Color? color,
double? width,
}) {
return BoardBorder(
color: color ?? this.color,
width: width ?? this.width,
);
}
}

/// Board settings that controls visual aspects and behavior of the board.
///
/// This is meant for fixed settings that don't change during a game. Sensible
Expand All @@ -40,6 +81,7 @@ class ChessboardSettings {
this.colorScheme = ChessboardColorScheme.brown,
this.pieceAssets = PieceSet.cburnettAssets,
// visual settings
this.border,
this.borderRadius = BorderRadius.zero,
this.boxShadow = const <BoxShadow>[],
this.enableCoordinates = true,
Expand Down Expand Up @@ -67,6 +109,9 @@ class ChessboardSettings {
/// Piece set
final PieceAssets pieceAssets;

/// Optional border of the board
final BoardBorder? border;

/// Border radius of the board
final BorderRadiusGeometry borderRadius;

Expand Down Expand Up @@ -125,6 +170,7 @@ class ChessboardSettings {
return other is ChessboardSettings &&
other.colorScheme == colorScheme &&
other.pieceAssets == pieceAssets &&
other.border == border &&
other.borderRadius == borderRadius &&
other.boxShadow == boxShadow &&
other.enableCoordinates == enableCoordinates &&
Expand All @@ -146,6 +192,7 @@ class ChessboardSettings {
int get hashCode => Object.hash(
colorScheme,
pieceAssets,
border,
borderRadius,
boxShadow,
enableCoordinates,
Expand Down Expand Up @@ -219,6 +266,7 @@ class ChessboardEditorSettings {
this.colorScheme = ChessboardColorScheme.brown,
this.pieceAssets = PieceSet.cburnettAssets,
// visual settings
this.border,
this.borderRadius = BorderRadius.zero,
this.boxShadow = const <BoxShadow>[],
this.enableCoordinates = true,
Expand All @@ -232,6 +280,9 @@ class ChessboardEditorSettings {
/// Piece set.
final PieceAssets pieceAssets;

/// Optional border of the board
final BoardBorder? border;

/// Border radius of the board.
final BorderRadiusGeometry borderRadius;

Expand All @@ -258,6 +309,7 @@ class ChessboardEditorSettings {
return other is ChessboardEditorSettings &&
other.colorScheme == colorScheme &&
other.pieceAssets == pieceAssets &&
other.border == border &&
other.borderRadius == borderRadius &&
other.boxShadow == boxShadow &&
other.enableCoordinates == enableCoordinates &&
Expand All @@ -269,6 +321,7 @@ class ChessboardEditorSettings {
int get hashCode => Object.hash(
colorScheme,
pieceAssets,
border,
borderRadius,
boxShadow,
enableCoordinates,
Expand Down
4 changes: 2 additions & 2 deletions lib/src/images.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import 'widgets/piece.dart';
/// the piece image using the [RawImage] widget.
///
/// This is the responsibility of the user to dispose of the cache when it is no
/// longer needed, or when changing the piece set, using the [clearCache] method.
/// longer needed, or when changing the piece set, using the [clear] method.
class ChessgroundImages {
ChessgroundImages._();

Expand Down Expand Up @@ -65,7 +65,7 @@ class ChessgroundImages {
/// Removes all cached images.
///
/// This calls [ui.Image.dispose] for all images in the cache, so make sure that
/// you don't use any of the previously cached images once [clearCache] has
/// you don't use any of the previously cached images once [clear] has
/// been called.
void clear() {
_assets.forEach((_, asset) => asset.dispose());
Expand Down
155 changes: 78 additions & 77 deletions lib/src/widgets/background.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class SolidColorChessboardBackground extends ChessboardBackground {
@override
Widget build(BuildContext context) {
return CustomPaint(
size: Size.infinite,
painter: _SolidColorChessboardPainter(
lightSquare: lightSquare,
darkSquare: darkSquare,
Expand Down Expand Up @@ -139,101 +140,101 @@ class ImageChessboardBackground extends ChessboardBackground {
@override
Widget build(BuildContext context) {
if (coordinates) {
return LayoutBuilder(
builder: (context, constraints) {
final squareSize = constraints.biggest.shortestSide / 8;
return Stack(
alignment: Alignment.topLeft,
clipBehavior: Clip.none,
children: [
Image(image: image),
for (var rank = 0; rank < 8; rank++)
for (var file = 0; file < 8; file++)
if (file == 7 || rank == 7)
Positioned(
left: file * squareSize,
top: rank * squareSize,
child: SizedBox(
width: squareSize,
height: squareSize,
child: _Coordinate(
rank: rank,
file: file,
orientation: orientation,
color:
(rank + file).isEven ? darkSquare : lightSquare,
),
),
),
],
);
},
return Stack(
alignment: Alignment.topLeft,
clipBehavior: Clip.none,
children: [
Image(image: image),
CustomPaint(
size: Size.infinite,
painter: _ImageBackgroundCoordinatePainter(
lightSquare: lightSquare,
darkSquare: darkSquare,
orientation: orientation,
),
),
],
);
} else {
return Image(image: image);
}
}
}

class _Coordinate extends StatelessWidget {
const _Coordinate({
required this.rank,
required this.file,
required this.color,
class _ImageBackgroundCoordinatePainter extends CustomPainter {
_ImageBackgroundCoordinatePainter({
required this.lightSquare,
required this.darkSquare,
required this.orientation,
});

final int rank;
final int file;
final Color color;
final Side orientation;
final Color lightSquare;
final Color darkSquare;

@override
Widget build(BuildContext context) {
final coordStyle = TextStyle(
inherit: false,
fontWeight: FontWeight.bold,
fontSize: 10.0,
color: color,
fontFamily: 'Roboto',
height: 1.0,
);
return Stack(
alignment: Alignment.topLeft,
children: [
if (file == 7)
Positioned(
top: 2.0,
right: 2.0,
child: Align(
alignment: Alignment.topRight,
child: Text(
textDirection: TextDirection.ltr,
orientation == Side.white ? '${8 - rank}' : '${rank + 1}',
void paint(Canvas canvas, Size size) {
final squareSize = size.shortestSide / 8;
for (var rank = 0; rank < 8; rank++) {
for (var file = 0; file < 8; file++) {
if (file == 7 || rank == 7) {
final coordStyle = TextStyle(
inherit: false,
fontWeight: FontWeight.bold,
fontSize: 10.0,
color: (rank + file).isEven ? darkSquare : lightSquare,
fontFamily: 'Roboto',
height: 1.0,
);
final square = Rect.fromLTWH(
file * squareSize,
rank * squareSize,
squareSize,
squareSize,
);
final paint = Paint()..color = const Color(0x00000000);
canvas.drawRect(square, paint);
if (file == 7) {
final coord = TextPainter(
text: TextSpan(
text: orientation == Side.white ? '${8 - rank}' : '${rank + 1}',
style: coordStyle,
textScaler: TextScaler.noScaling,
textAlign: TextAlign.center,
),
),
),
if (rank == 7)
Positioned(
bottom: 2.0,
left: 2.0,
child: Align(
alignment: Alignment.bottomLeft,
child: Text(
textDirection: TextDirection.ltr,
orientation == Side.white
textDirection: TextDirection.ltr,
);
coord.layout();
const edgeOffset = 2.0;
final offset = Offset(
file * squareSize + (squareSize - coord.width) - edgeOffset,
rank * squareSize + edgeOffset,
);
coord.paint(canvas, offset);
}
if (rank == 7) {
final coord = TextPainter(
text: TextSpan(
text: orientation == Side.white
? String.fromCharCode(97 + file)
: String.fromCharCode(97 + 7 - file),
style: coordStyle,
textScaler: TextScaler.noScaling,
textAlign: TextAlign.center,
),
),
),
],
);
textDirection: TextDirection.ltr,
);
coord.layout();
const edgeOffset = 2.0;
final offset = Offset(
file * squareSize + edgeOffset,
rank * squareSize + (squareSize - coord.height) - edgeOffset,
);
coord.paint(canvas, offset);
}
}
}
}
}

@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false;
}
}
Loading
Loading