wrote thorough documentation and made minor fixes for highlighting/selection
This commit is contained in:
+178
-88
@@ -1,17 +1,16 @@
|
||||
package gui;
|
||||
|
||||
import java.awt.Dimension;
|
||||
// GUI imports
|
||||
import javax.swing.JPanel;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.LayoutManager;
|
||||
import java.awt.event.KeyAdapter;
|
||||
|
||||
// Event & action imports
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.KeyListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.Box;
|
||||
|
||||
// Processing & backend imports
|
||||
import gui.backend.Cell;
|
||||
import gui.backend.Settings;
|
||||
import gui.backend.SudokuChecker;
|
||||
@@ -22,6 +21,8 @@ import gui.backend.SudokuChecker;
|
||||
* It contains all other related GUI components, and is the main JPanel for
|
||||
* the board. Accessible information from the Board includes:
|
||||
* - the current state of the board, including filled values and notes;
|
||||
*
|
||||
* TODO: Future features:
|
||||
* - the current difficulty;
|
||||
* - the current time since the puzzle was started;
|
||||
* - the current hints available; and
|
||||
@@ -36,9 +37,41 @@ public class Board extends JPanel {
|
||||
private CellGUI selected;
|
||||
|
||||
/**
|
||||
* Create a new Board object with the default styling from settings.
|
||||
* Create a new Board object.
|
||||
*
|
||||
* Board requires a Settings object for styling, sizing, and for different
|
||||
* toggleable features.
|
||||
*
|
||||
* A 2D Cell array is required to abstract the data away from the Board,
|
||||
* and the GUI in general.
|
||||
*
|
||||
* @param s
|
||||
* @param grid
|
||||
*/
|
||||
public Board(Settings s, Cell[][] grid) {
|
||||
super(new GridLayout(9, 9));
|
||||
this.s = s;
|
||||
this.grid = grid;
|
||||
solvedGrid = new SudokuChecker(Cell.copyGrid(grid)).getSolution();
|
||||
|
||||
style();
|
||||
createBoard();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Board object.
|
||||
*
|
||||
* Board requires a Settings object for styling, sizing, and for different
|
||||
* toggleable features.
|
||||
*
|
||||
* A 2D Cell array is required to abstract the data away from the Board,
|
||||
* and the GUI in general.
|
||||
*
|
||||
* A SudokuChecker is required if Settings.getAutoCheckValues() is true.
|
||||
*
|
||||
* @param s
|
||||
* @param grid
|
||||
* @param sc
|
||||
*/
|
||||
public Board(Settings s, Cell[][] grid, SudokuChecker sc) {
|
||||
super(new GridLayout(9, 9));
|
||||
@@ -51,48 +84,6 @@ public class Board extends JPanel {
|
||||
createBoard();
|
||||
}
|
||||
|
||||
private KeyListener createKeyListener() {
|
||||
return new KeyListener() {
|
||||
@Override
|
||||
public void keyTyped(KeyEvent e) {}
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {}
|
||||
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e) {
|
||||
char key = e.getKeyChar();
|
||||
if(selected.cell.isInitValue()) return;
|
||||
|
||||
// Backspace key code is 0
|
||||
if(e.getKeyCode() == e.VK_BACK_SPACE) {
|
||||
selected.removeValue();
|
||||
selected.repaint();
|
||||
selected.revalidate();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!Character.isDigit(key)) return;
|
||||
|
||||
if(!selected.isInNotesMode()) {
|
||||
if(s.getAutoCheckValues()) {
|
||||
int row = selected.cell.getRow();
|
||||
int col = selected.cell.getCol();
|
||||
int expected = solvedGrid[row][col].getValue();
|
||||
selected.setValue(Character.getNumericValue(key), expected);
|
||||
} else {
|
||||
selected.setValue(Character.getNumericValue(key));
|
||||
}
|
||||
} else {
|
||||
selected.addPossibleValue(Character.getNumericValue(key));
|
||||
}
|
||||
|
||||
selected.repaint();
|
||||
selected.revalidate();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the grid of the Board.
|
||||
*
|
||||
@@ -137,6 +128,8 @@ public class Board extends JPanel {
|
||||
* @param cell
|
||||
*/
|
||||
private void select(Cell cell) {
|
||||
// Select the CellGUI objects in the same row and column, but not in
|
||||
// the same box.
|
||||
for(int n = 0; n < 9; n++) {
|
||||
int row = cell.getRow();
|
||||
int col = cell.getCol();
|
||||
@@ -148,18 +141,22 @@ public class Board extends JPanel {
|
||||
(gridGUI[row][n].cell.getBox() ==
|
||||
cell.getBox());
|
||||
|
||||
// Handling edge cases where the column or row are in the box.
|
||||
if(colInSameBox && !rowInSameBox) {
|
||||
gridGUI[row][n].select();
|
||||
continue;
|
||||
} else if(!colInSameBox && rowInSameBox) {
|
||||
gridGUI[n][col].select();
|
||||
continue;
|
||||
|
||||
// Skip the cell if it is in the same box.
|
||||
} else if(colInSameBox && rowInSameBox) continue;
|
||||
|
||||
gridGUI[n][col].select();
|
||||
gridGUI[row][n].select();
|
||||
}
|
||||
|
||||
// Select every cell in the box.
|
||||
int boxRow = cell.getRow() / 3;
|
||||
int boxCol = cell.getCol() / 3;
|
||||
for(int n = 0; n < 3; n++) {
|
||||
@@ -177,6 +174,12 @@ public class Board extends JPanel {
|
||||
|
||||
/**
|
||||
* Create the Board Panel with the appropriate cells.
|
||||
*
|
||||
* Every CellGUI object is created with the appropriate Cell object and
|
||||
* Settings object. The CellGUI objects are then added to the Board Panel.
|
||||
*
|
||||
* Each CellGUI object is also given a MouseListener to handle user input,
|
||||
* and a KeyListener to handle keyboard input if/when the cell is selected.
|
||||
*/
|
||||
private void createBoard() {
|
||||
if(s.getAutoFillNotes()) grid = sc.getPossibleValues(grid);
|
||||
@@ -184,50 +187,137 @@ public class Board extends JPanel {
|
||||
|
||||
for(int i = 0; i < 9; i++) {
|
||||
for(int j = 0; j < 9; j++) {
|
||||
CellGUI cell = new CellGUI(
|
||||
grid[i][j],
|
||||
s
|
||||
);
|
||||
cell.addMouseListener(new MouseListener() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
// Left click
|
||||
if(e.getButton() == 1) {
|
||||
if(selected != null) select(selected.cell);
|
||||
|
||||
// Deselect the cell if it is already selected.
|
||||
if(selected == cell) {
|
||||
selected = null;
|
||||
return;
|
||||
}
|
||||
// Create a new CellGUI object with the appropriate Cell object.
|
||||
CellGUI cell = new CellGUI(grid[i][j], s);
|
||||
|
||||
select(cell.cell);
|
||||
selected = cell;
|
||||
selected.requestFocusInWindow();
|
||||
selected.addKeyListener(createKeyListener());
|
||||
} else if(e.getButton() == 3) {
|
||||
cell.setNoteMode();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {}
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e) {}
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
cell.select();
|
||||
}
|
||||
@Override
|
||||
public void mouseExited(MouseEvent e) {
|
||||
cell.select();
|
||||
}
|
||||
|
||||
});
|
||||
// Add a MouseListener to the cell.
|
||||
cell.addMouseListener(createMouseListener(cell));
|
||||
|
||||
// Add the CellGUI object to the Board Panel.
|
||||
gridGUI[i][j] = cell;
|
||||
add(gridGUI[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a MouseListener for CellGUI objects.
|
||||
*
|
||||
* This MouseListener listens for mouse clicks, and selects the cell
|
||||
* if it is clicked. If the cell is already selected, it is deselected.
|
||||
*
|
||||
* Additionally, adds hover highlighting for the cell.
|
||||
*
|
||||
* mouseClicked() is implemented for cell selection functionality.
|
||||
* mouseEntered() and mouseExited() are implemented for hover functionality.
|
||||
* Other methods are not implemented.
|
||||
*
|
||||
* @param cell
|
||||
* @return MouseListener
|
||||
*/
|
||||
private MouseListener createMouseListener(CellGUI cell) {
|
||||
return new MouseListener() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
// Left click
|
||||
if(e.getButton() == 1) {
|
||||
// Deselect the already selected cell.
|
||||
if(selected != null) select(selected.cell);
|
||||
|
||||
// Deselect the cell if it is already selected.
|
||||
if(selected == cell) {
|
||||
selected = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// Select the cell and add a KeyListener for input.
|
||||
select(cell.cell);
|
||||
selected = cell;
|
||||
selected.requestFocusInWindow();
|
||||
selected.addKeyListener(createKeyListener());
|
||||
|
||||
// Right click
|
||||
} else if(e.getButton() == 3) {
|
||||
cell.setNoteMode();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {}
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e) {}
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
if(selected == null) cell.select();
|
||||
}
|
||||
@Override
|
||||
public void mouseExited(MouseEvent e) {
|
||||
if(selected == null) cell.select();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a KeyListener for CellGUI objects.
|
||||
*
|
||||
* This KeyListener listens for key releases, and updates the
|
||||
* selected cell with additional possible values or a new value.
|
||||
*
|
||||
* Only keyReleased is implemented, as keyTyped does not allow for
|
||||
* certain features regarding key codes.
|
||||
*
|
||||
* @return KeyListener
|
||||
*/
|
||||
private KeyListener createKeyListener() {
|
||||
return new KeyListener() {
|
||||
@Override
|
||||
public void keyTyped(KeyEvent e) {}
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {}
|
||||
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e) {
|
||||
// If a CellGUI is not selected, do nothing.
|
||||
if(selected == null) return;
|
||||
|
||||
char key = e.getKeyChar();
|
||||
Cell c = selected.cell;
|
||||
|
||||
// If the Cell is an initial value read from the starting file
|
||||
// then skip it.
|
||||
if(c.isInitValue()) return;
|
||||
|
||||
// Backspace support for removing values.
|
||||
if(e.getKeyCode() == KeyEvent.VK_BACK_SPACE) {
|
||||
selected.removeValue();
|
||||
selected.repaint();
|
||||
selected.revalidate();
|
||||
return;
|
||||
}
|
||||
|
||||
// Only allow digits to be entered.
|
||||
if(!Character.isDigit(key)) return;
|
||||
|
||||
// Enter the value from the keyboard.
|
||||
if(!selected.isInNotesMode()) {
|
||||
|
||||
// Set the value of the cell and check if it is correct.
|
||||
if(s.getAutoCheckValues()) {
|
||||
int row = c.getRow();
|
||||
int col = c.getCol();
|
||||
int expected = solvedGrid[row][col].getValue();
|
||||
selected.setValue(Character.getNumericValue(key), expected);
|
||||
|
||||
// Set the value of the cell.
|
||||
} else selected.setValue(Character.getNumericValue(key));
|
||||
|
||||
// Add the possible value to the cell.
|
||||
} else selected.addPossibleValue(Character.getNumericValue(key));
|
||||
|
||||
selected.repaint();
|
||||
selected.revalidate();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user