This repository has been archived on 2021-02-18. You can view files and clone it, but cannot push or open issues or pull requests.
chess/src/main/java/dev/kske/chess/ui/GamePane.java

240 lines
7.1 KiB
Java

package dev.kske.chess.ui;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.swing.*;
import dev.kske.chess.board.BoardState;
import dev.kske.chess.board.MoveNode;
import dev.kske.chess.board.Piece.Color;
import dev.kske.chess.event.*;
import dev.kske.chess.game.Game;
import dev.kske.chess.game.NaturalPlayer;
/**
* The part of this application's {@link MainWindow} that displays {@link Game}s
* and other components allowing to manipulate them.<br>
* <br>
* Project: <strong>Chess</strong><br>
* File: <strong>GamePane.java</strong><br>
* Created: <strong>23.08.2019</strong><br>
*
* @since Chess v0.4-alpha
* @author Kai S. K. Engelbart
*/
public class GamePane extends JComponent {
private static final long serialVersionUID = 4349772338239617477L;
private JButton btnRestart, btnSwapColors;
private BoardPane boardPane;
private Game game;
private Color activeColor;
private JPanel moveSelectionPanel;
private JButton btnFirst, btnPrevious, btnNext, btnLast;
/**
* Creates an instance of {@link GamePane}.
*/
public GamePane() {
activeColor = Color.WHITE;
GridBagLayout gridBagLayout = new GridBagLayout();
gridBagLayout.columnWidths = new int[] {
450, 1, 0
};
gridBagLayout.rowHeights = new int[] {
33, 267, 1, 0
};
gridBagLayout.columnWeights = new double[] {
0.0, 1.0, 1.0
};
gridBagLayout.rowWeights = new double[] {
1.0, 1.0, 1.0, Double.MIN_VALUE
};
setLayout(gridBagLayout);
JPanel toolPanel = new JPanel();
btnRestart = new JButton("Restart");
btnRestart.addActionListener(evt -> {
if (game != null) {
game.reset();
game.start();
}
});
btnSwapColors = new JButton("Play as black");
btnSwapColors.addActionListener(evt -> {
game.swapColors();
btnSwapColors
.setText("Play as " + activeColor.toString().toLowerCase());
activeColor = activeColor.opposite();
});
toolPanel.add(btnRestart);
toolPanel.add(btnSwapColors);
GridBagConstraints gbc_toolPanel = new GridBagConstraints();
gbc_toolPanel.anchor = GridBagConstraints.NORTH;
gbc_toolPanel.fill = GridBagConstraints.HORIZONTAL;
gbc_toolPanel.gridx = 0;
gbc_toolPanel.gridy = 0;
gbc_toolPanel.gridwidth = 2;
add(toolPanel, gbc_toolPanel);
moveSelectionPanel = new JPanel();
GridBagConstraints gbc_moveSelectionPanel = new GridBagConstraints();
gbc_moveSelectionPanel.fill = GridBagConstraints.BOTH;
gbc_moveSelectionPanel.gridx = 2;
gbc_moveSelectionPanel.gridy = 0;
add(moveSelectionPanel, gbc_moveSelectionPanel);
btnFirst = new JButton("First");
btnFirst.setEnabled(false);
moveSelectionPanel.add(btnFirst);
btnPrevious = new JButton("Previous");
btnPrevious.addActionListener(evt -> {
if (game != null) {
game.getBoard().selectPreviousNode();
getBoardPane().getOverlayComponent().clearArrow();
repaint();
}
});
moveSelectionPanel.add(btnPrevious);
btnNext = new JButton("Next");
btnNext.addActionListener(evt -> {
if (game != null) {
int numVariations
= game.getBoard().getLog().getLast().getVariations().size();
int index;
if (numVariations == 1)
index = 1;
else
index
= Integer.parseInt(
JOptionPane
.showInputDialog("Enter the variation index.")
);
game.getBoard().selectNextNode(index);
getBoardPane().getOverlayComponent().clearArrow();
repaint();
}
});
moveSelectionPanel.add(btnNext);
btnLast = new JButton("Last");
btnLast.setEnabled(false);
moveSelectionPanel.add(btnLast);
boardPane = new BoardPane();
GridBagConstraints gbc_boardPane = new GridBagConstraints();
gbc_boardPane.fill = GridBagConstraints.BOTH;
gbc_boardPane.gridx = 0;
gbc_boardPane.gridy = 1;
add(boardPane, gbc_boardPane);
JPanel numberPanel = new JPanel(new GridLayout(8, 1));
GridBagConstraints gbc_numberPanel = new GridBagConstraints();
gbc_numberPanel.anchor = GridBagConstraints.WEST;
gbc_numberPanel.fill = GridBagConstraints.VERTICAL;
gbc_numberPanel.gridx = 1;
gbc_numberPanel.gridy = 1;
add(numberPanel, gbc_numberPanel);
JPanel letterPanel = new JPanel(new GridLayout(1, 8));
GridBagConstraints gbc_letterPanel = new GridBagConstraints();
gbc_letterPanel.anchor = GridBagConstraints.NORTH;
gbc_letterPanel.fill = GridBagConstraints.HORIZONTAL;
gbc_letterPanel.gridx = 0;
gbc_letterPanel.gridy = 2;
add(letterPanel, gbc_letterPanel);
// Initialize board coordinates
for (int i = 0; i < 8; i++) {
numberPanel.add(new JLabel(String.valueOf(8 - i)));
JLabel letterLabel = new JLabel(String.valueOf((char) (65 + i)));
letterLabel.setHorizontalAlignment(SwingConstants.CENTER);
letterPanel.add(letterLabel);
}
JScrollPane scrollPane = new JScrollPane();
GridBagConstraints gbc_scrollPane = new GridBagConstraints();
gbc_scrollPane.fill = GridBagConstraints.BOTH;
gbc_scrollPane.gridx = 2;
gbc_scrollPane.gridy = 1;
add(scrollPane, gbc_scrollPane);
JList<MoveNode> pgnList = new JList<>();
pgnList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
pgnList.setLayoutOrientation(JList.HORIZONTAL_WRAP);
pgnList.setVisibleRowCount(0);
pgnList.setCellRenderer(new MoveNodeRenderer());
scrollPane.setViewportView(pgnList);
// Listen to moves and game (re-)starts and update the move list or
// disable the
// color switching buttons if necessary
EventBus.getInstance().register(new Subscriber() {
@Override
public void handle(Event<?> event) {
if (
event instanceof MoveEvent && (((MoveEvent) event)
.getBoardState() == BoardState.CHECKMATE
|| ((MoveEvent) event)
.getBoardState() == BoardState.STALEMATE)
)
btnSwapColors.setEnabled(false);
else
if (event instanceof GameStartEvent)
btnSwapColors.setEnabled(
game.getPlayers().get(Color.WHITE) instanceof NaturalPlayer ^ game.getPlayers().get(Color.BLACK) instanceof NaturalPlayer
);
if (game.getBoard().getLog() == null)
return;
DefaultListModel<MoveNode> model = new DefaultListModel<>();
game.getBoard().getLog().forEach(model::addElement);
pgnList.setModel(model);
}
@Override
public Set<Class<?>> supports() {
return new HashSet<>(
Arrays.asList(MoveEvent.class, GameStartEvent.class)
);
}
});
}
/**
* @return The {@link BoardPane} instance associated with this game pane
*/
public BoardPane getBoardPane() { return boardPane; }
/**
* @return The {@link Game} instance associated with this game pane
*/
public Game getGame() { return game; }
/**
* Assigns a new {@link Game} instance to this game pane. If exactly one of
* the
* players is natural, color swapping functionality is enabled.
*
* @param game The {@link Game} to assign to this game pane.
*/
public void setGame(Game game) {
if (this.game != null)
this.game.stop();
this.game = game;
}
}