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.
*
* Project: Chess
* File: GamePane.java
* Created: 23.08.2019
* * @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 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 model = new DefaultListModel<>(); game.getBoard().getLog().forEach(model::addElement); pgnList.setModel(model); } @Override public Set> 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; } }