package GUI;
import Game.Player;
import java.awt.*;
import javax.swing.*;
/**
* View of the Chess game model managed by GameManager and Board
*/
public class View{
/**
* Directory containing piece images.
*/
private static String graphicsPath = "Graphics/";
private String timeString;
/**
* The board containing the squares
*/
private JPanel chessBoard;
private JPanel gameTimer;
/**
* The main JFrame of the view.
*/
private JFrame window;
/**
* The layered pane containing the board, and the pieces on top.
*/
private JLayeredPane layeredBoardPane;
/**
* The text area storing the move historn in PGN format (portable game notation).
*/
private JTextArea histBox;
/**
* Text panel displaying the name of the white player and his score.
*/
private textPanel whitePanel;
/**
* Text panel displaying the name of the black player and his score.
*/
private textPanel blackPanel;
private textPanel timer;
/**
* Text panel displaying the name of the player whose turn it is.
*/
private textPanel currentTurn;
/**
* Reference to the controller.
*/
Controller controller;
/**
* Defined colors
*/
private static Color lightBrown = new Color(255, 206, 158);
/**
* Defined colors
*/
private static Color darkBrown = new Color(209, 139, 71);
/**
* Defined colors
*/
private static Color lightBlue = new Color(192, 231, 255);
/**
* Defined colors
*/
private static Color darkBlue = new Color(105, 180, 209);
/**
* Name of player playing as white.
*/
private String whiteName;
/**
* Name of player playing as black.
*/
private String blackName;
/**
* Construct the view.
*
* @param width width of the view in pixels.
* @param height height of the view in pixels.
* @param controller reference to the controller
*/
public View(int width, int height, Controller controller) {
this.controller = controller;
timeString = "Game timer: 0:00";
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
//silently ignore
}
window = new JFrame("Chess");
window.setSize(width, height);
JPanel myPanel = initializePanel();
JPanel chessHist = initializeRightPanel();
myPanel.add(chessHist, BorderLayout.EAST);
JLayeredPane rowNumbers = initializeNumbers();
myPanel.add(rowNumbers, BorderLayout.WEST);
JLayeredPane colLetters = initializeLetters();
myPanel.add(colLetters, BorderLayout.SOUTH);
initializeBoard();
layeredBoardPane.addMouseListener(controller);
layeredBoardPane.addMouseMotionListener(controller);
myPanel.add(layeredBoardPane);
setUpMenu();
window.setContentPane(myPanel);
window.setVisible(true);
window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
/**
* Set up and return a new JPanel.
*
* @return the new JPanel.
*/
private JPanel initializePanel() {
JPanel myPanel = new JPanel();
myPanel.setLayout(new BorderLayout());
return myPanel;
}
/**
* Set up the board as a JLayeredPane.
*
*/
private void initializeBoard() {
Dimension boardSize = new Dimension(900, 900);
layeredBoardPane = new JLayeredPane();
layeredBoardPane.setPreferredSize(boardSize);
}
/**
* Add a piece to the board's view.
*
* @param image image to display.
* @param component section of the board.
*/
private void addPiece(ImageIcon image, int component) {
JLabel piece = new JLabel(image);
JPanel panel = (JPanel) chessBoard.getComponent(component);
panel.add(piece);
}
/**
* Initialize the row numbers.
*
* @return JLayeredPane containing the row numbers.
*/
private JLayeredPane initializeNumbers() {
JLayeredPane numberPane = new JLayeredPane();
JPanel numberPanel = new JPanel();
numberPanel.setLayout(new GridLayout(8, 1));
Dimension boardSize = new Dimension(40, 900);
numberPane.setPreferredSize(boardSize);
numberPanel.setPreferredSize(boardSize);
numberPanel.setBounds(0, 27, boardSize.width, boardSize.height);
for (int i = 8; i > 0; i--)
numberPanel.add(new textPanel("" + i, 36));
numberPane.add(numberPanel);
return numberPane;
}
/**
* Initialize the column letters.
*
* @return JLayeredPane containing the column letters.
*/
private JLayeredPane initializeLetters() {
JLayeredPane letterPane = new JLayeredPane();
Dimension boardSize = new Dimension(900, 50);
letterPane.setPreferredSize(boardSize);
JPanel letterPanel = new JPanel();
letterPanel.setLayout(new GridLayout(1, 8));
letterPanel.setPreferredSize(boardSize);
letterPanel.setBounds(37, 0, boardSize.width, boardSize.height);
for (int i = 0; i < 8; i++)
letterPanel.add(new textPanel(Character.toString((char) (97 + i)), 36));
letterPane.add(letterPanel);
return letterPane;
}
/**
* Initialize the panel on the right with the timer, game history, and buttons
*/
private JPanel initializeRightPanel() {
JPanel pane = new JPanel(new BorderLayout());
gameTimer = new JPanel(new BorderLayout());
JPanel players = new JPanel(new BorderLayout());
whitePanel = new textPanel("", 24);
blackPanel = new textPanel("", 24);
timer = new textPanel(timeString, 24);
currentTurn = new textPanel("White's Turn", 24);
players.add(whitePanel, BorderLayout.NORTH);
players.add(blackPanel, BorderLayout.SOUTH);
gameTimer.add(timer, BorderLayout.NORTH);
gameTimer.add(players, BorderLayout.CENTER);
gameTimer.add(currentTurn, BorderLayout.SOUTH);
pane.add(gameTimer, BorderLayout.NORTH);
histBox = new JTextArea();
histBox.setEditable(false);
pane.add(histBox);
JPanel buttonPanel = new JPanel(new BorderLayout());
JButton undo = new JButton("Propose Takeback");
JButton draw = new JButton("Offer Draw");
JButton resign = new JButton("Resign");
undo.setPreferredSize(new Dimension(340, 50));
draw.setPreferredSize(new Dimension(340, 50));
resign.setPreferredSize(new Dimension(340, 50));
undo.addActionListener(controller);
draw.addActionListener(controller);
resign.addActionListener(controller);
buttonPanel.add(undo, BorderLayout.NORTH);
buttonPanel.add(draw);
buttonPanel.add(resign, BorderLayout.SOUTH);
pane.add(buttonPanel, BorderLayout.AFTER_LAST_LINE);
return pane;
}
/**
* Set up the title bar menu.
*/
private void setUpMenu() {
JMenuBar menubar = new JMenuBar();
JMenu file = new JMenu("File");
JMenu edit = new JMenu("Edit");
JMenu game = new JMenu("Game");
JMenu help = new JMenu("Help");
JMenuItem newGame = new JMenuItem("New Window");
JMenuItem newCustomGame = new JMenuItem("New Window (Custom)");
JMenuItem save = new JMenuItem("Save Board");
JMenuItem load = new JMenuItem("Load Board");
JMenuItem exit = new JMenuItem("Exit");
newGame.addActionListener(controller);
newCustomGame.addActionListener(controller);
exit.addActionListener(controller);
JMenuItem undo = new JMenuItem("Propose Takeback");
JMenuItem draw = new JMenuItem("Offer Draw");
JMenuItem resign = new JMenuItem("Resign");
undo.addActionListener(controller);
draw.addActionListener(controller);
resign.addActionListener(controller);
JMenuItem settings = new JMenuItem("Settings");
JMenuItem about = new JMenuItem("About");
about.addActionListener(controller);
file.add(newGame);
file.add(newCustomGame);
file.add(save);
file.add(load);
file.add(exit);
game.add(undo);
game.add(resign);
game.add(draw);
edit.add(settings);
help.add(about);
menubar.add(file);
menubar.add(game);
menubar.add(edit);
menubar.add(help);
window.setJMenuBar(menubar);
}
/**
* Set players' names and scores. Called from controller when the controller recieves this data from the user.
* @param whiteName name of white player
* @param blackName name of black player
* @param whiteScore score of white
* @param blackScore score of black
*/
public void setNames(String whiteName, String blackName, int whiteScore, int blackScore){
this.whiteName = whiteName;
this.blackName = blackName;
whitePanel.setText(whiteName+ " (White), score: " + whiteScore);
blackPanel.setText(blackName+ " (Black), score: " + blackScore);
}
/**
* Set players' scores. Called from controller when a game ends.
* @param whiteScore score of white
* @param blackScore score of black
*/
public void setScore(int whiteScore, int blackScore){
whitePanel.setText(whiteName+ " (White), score: " + whiteScore);
blackPanel.setText(blackName+ " (Black), score: " + blackScore);
}
/**
* View deconstructor.
*/
public void quit(){
window.dispose();
}
/**
* Set the text to the player's turn. Called from controller when a turn ends.
*/
public void setTurn(Player current){
if (current == Player.WHITE) {
currentTurn.setText("White's Turn");
} else {
currentTurn.setText("Black's Turn");
}
}
/**
* Give boardWidth to controller.
* @return the boardWidth
*/
public int boardWidth(){
return layeredBoardPane.getWidth();
}
/**
* Give boardHeight to controller.
* @return the boardHeight
*/
public int boardHeight(){
return layeredBoardPane.getHeight();
}
/**
* Remove the image of a piece from the board.
* @param chessPiece piece to remove.
*/
public void removePieceGraphic(JLabel chessPiece){
layeredBoardPane.remove(chessPiece);
}
/**
* Return component at x,y on the view of the board.
* @param x x-coord
* @param y y-coord
* @return the component.
*/
public Component findPieceAt(int x, int y){
return chessBoard.findComponentAt(x, y);
}
/**
* Add the string to the move history panel.
* @param s string to append.
*/
public void addToHistory(String s) {
histBox.append(s);
}
/**
* Return the text in the history panel.
* @return the text in the history panel.
*/
public String getHistory(){
return histBox.getText();
}
/**
* Set the history panel.
* @param history string to store.
*/
public void setHistory(String history) {
histBox.setText(history);
}
/**
* Return the main JFrame. Used by controller to send dialogue messages with a yes/no option.
* @return the main JFrame.
*/
JFrame getWindow(){
return window;
}
/**
* Wipe the board, and re initialize it. Used to set up the view for a new game.
*/
public void clearAndResetBoard() {
Dimension boardSize = new Dimension(900, 900);
layeredBoardPane.removeAll();
//Add a chess board to the Layered Pane
chessBoard = new JPanel();
chessBoard.setLayout(new GridLayout(8, 8));
chessBoard.setPreferredSize(boardSize);
chessBoard.setBounds(0, 0, boardSize.width, boardSize.height);
layeredBoardPane.add(chessBoard, JLayeredPane.DEFAULT_LAYER);
}
/**
* Hide the cursor over the board.
*/
public void hideCursor() {
layeredBoardPane.setCursor(null);
}
/**
* Place a piece on a square.
* @param i index of the component.
* @param owner owner of the piece to determine color of the image.
* @param imageName name of the image.
*/
public void placePiece(int i, Player owner, String imageName) {
if (imageName != null) {
String color = (owner == Player.WHITE) ? "white" : "black";
addPiece(new ImageIcon(graphicsPath + color + imageName), 64 - i);
}
}
/**
* Build the default colored squares.
*/
public void buildDefaultSquares() {
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
JPanel square = new JPanel(new BorderLayout());
square.setBackground((i + j) % 2 == 0 ? lightBrown: darkBrown);
chessBoard.add(square);
}
}
}
/**
* Build a highlighted square.
* @param i index of the component.
* @param x x-coord to determine color.
* @param y y-coord to determine color.
*/
public void buildHighlightedSquare(int i, int x, int y) {
chessBoard.remove(64 - i);
JPanel square = new JPanel(new BorderLayout());
square.setBackground((x + y - 1) % 2 == 0 ? lightBlue : darkBlue);
chessBoard.add(square, 64 - i);
}
/**
* Set the main window to visible.
*/
public void setBoardVisible() {
window.setVisible(true);
}
/**
* Get a component at index i on the board.
* @param i the index.
* @return the component
*/
Component getPiece(int i) {
return chessBoard.getComponent(64 - i);
}
/**
* Adds the component storing a piece image to the mouse.
* @param controller the component with the image.
*/
public void addPieceToCursor(Controller controller) {
layeredBoardPane.add(controller.chessPiece, JLayeredPane.DRAG_LAYER);
layeredBoardPane.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
}
}