231 lines
6.7 KiB
Java
231 lines
6.7 KiB
Java
package dev.kske.chess.ui;
|
|
|
|
import java.awt.*;
|
|
|
|
import javax.swing.*;
|
|
|
|
import dev.kske.chess.board.*;
|
|
import dev.kske.chess.board.Piece.Color;
|
|
import dev.kske.chess.event.*;
|
|
import dev.kske.chess.game.*;
|
|
import dev.kske.eventbus.*;
|
|
import dev.kske.eventbus.Event;
|
|
|
|
/**
|
|
* 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 implements EventListener {
|
|
|
|
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;
|
|
private JList<MoveNode> pgnList;
|
|
|
|
/**
|
|
* 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);
|
|
|
|
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().registerListener(this);
|
|
}
|
|
|
|
@Event
|
|
public void onMove(MoveEvent evt) {
|
|
btnSwapColors.setEnabled(
|
|
evt.getBoardState() != BoardState.CHECKMATE
|
|
&& evt.getBoardState() != BoardState.STALEMATE
|
|
);
|
|
updateLog();
|
|
}
|
|
|
|
@Event
|
|
public void onGameStart(GameStartEvent evt) {
|
|
btnSwapColors.setEnabled(
|
|
game.getPlayers().get(Color.WHITE) instanceof NaturalPlayer ^ game.getPlayers().get(Color.BLACK) instanceof NaturalPlayer
|
|
);
|
|
updateLog();
|
|
}
|
|
|
|
private void updateLog() {
|
|
if (game.getBoard().getLog() == null)
|
|
return;
|
|
|
|
DefaultListModel<MoveNode> model = new DefaultListModel<>();
|
|
game.getBoard().getLog().forEach(model::addElement);
|
|
pgnList.setModel(model);
|
|
}
|
|
|
|
/**
|
|
* @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;
|
|
}
|
|
}
|