added backspace support and basic error checking in settings and gui. 2 major bugs: empty cells always start in note mode, and the sizing is not constant.
This commit is contained in:
+37
-20
@@ -1,5 +1,6 @@
|
||||
package gui;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.LayoutManager;
|
||||
import java.awt.event.KeyAdapter;
|
||||
@@ -29,6 +30,7 @@ import gui.backend.SudokuChecker;
|
||||
public class Board extends JPanel {
|
||||
private Settings s;
|
||||
private Cell[][] grid;
|
||||
private Cell[][] solvedGrid;
|
||||
private CellGUI[][] gridGUI;
|
||||
private SudokuChecker sc;
|
||||
private CellGUI selected;
|
||||
@@ -43,6 +45,8 @@ public class Board extends JPanel {
|
||||
this.s = s;
|
||||
this.grid = grid;
|
||||
this.sc = sc;
|
||||
solvedGrid = new SudokuChecker(Cell.copyGrid(grid)).getSolution();
|
||||
|
||||
style();
|
||||
createBoard();
|
||||
}
|
||||
@@ -50,30 +54,42 @@ public class Board extends JPanel {
|
||||
private KeyListener createKeyListener() {
|
||||
return new KeyListener() {
|
||||
@Override
|
||||
public void keyTyped(KeyEvent e) {
|
||||
char key = e.getKeyChar();
|
||||
if(!Character.isDigit(key)) return;
|
||||
if(selected.cell.isInitValue()) return;
|
||||
|
||||
if(e.getKeyCode() == e.VK_BACK_SPACE) {
|
||||
if(selected.isInNotesMode()) {
|
||||
System.out.println("Remove all notes.");
|
||||
return;
|
||||
} else {
|
||||
selected.setValue(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(!selected.isInNotesMode())
|
||||
selected.setValue(Character.getNumericValue(key));
|
||||
}
|
||||
public void keyTyped(KeyEvent e) {}
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {}
|
||||
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e) {}
|
||||
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();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -171,7 +187,8 @@ public class Board extends JPanel {
|
||||
CellGUI cell = new CellGUI(
|
||||
grid[i][j],
|
||||
s.getCellGUIStartMode(),
|
||||
s.getTheme()
|
||||
s.getTheme(),
|
||||
s.getCellDimensions()
|
||||
);
|
||||
cell.addMouseListener(new MouseListener() {
|
||||
@Override
|
||||
|
||||
+118
-19
@@ -1,6 +1,7 @@
|
||||
package gui;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GridLayout;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
@@ -19,9 +20,11 @@ class CellGUI extends JPanel {
|
||||
private JPanel internalPanel = new JPanel(new BorderLayout());
|
||||
private GridLayout noteLayout = new GridLayout(3, 3);
|
||||
private GridLayout valueLayout = new GridLayout(0, 1);
|
||||
private Dimension size;
|
||||
private JLabel valueLabel;
|
||||
private Note[] notesLabels = new Note[9];
|
||||
private Theme theme;
|
||||
private boolean incorrect;
|
||||
|
||||
// Data fields
|
||||
Cell cell;
|
||||
@@ -36,7 +39,7 @@ class CellGUI extends JPanel {
|
||||
* @param cell
|
||||
* @param startInNotesOrValueMode
|
||||
*/
|
||||
public CellGUI(Cell cell, boolean noteMode, Theme theme) {
|
||||
public CellGUI(Cell cell, boolean noteMode, Theme theme, Dimension size) {
|
||||
super();
|
||||
this.cell = cell;
|
||||
this.noteMode = !noteMode; // Flip for use with setNoteMode()
|
||||
@@ -45,7 +48,9 @@ class CellGUI extends JPanel {
|
||||
setFocusable(true);
|
||||
setLayout(valueLayout);
|
||||
valueLabel = new JLabel("", SwingConstants.CENTER);
|
||||
style();
|
||||
this.size = size;
|
||||
setSize(this.size);
|
||||
defaultStyle();
|
||||
|
||||
// Populate the cell with the appropriate value or notes.
|
||||
if(cell.getValue() == 0) {
|
||||
@@ -59,6 +64,25 @@ class CellGUI extends JPanel {
|
||||
add(internalPanel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of the cell.
|
||||
*/
|
||||
public Dimension getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the size of the cell.
|
||||
*/
|
||||
public void setSize(Dimension size) {
|
||||
this.size = size;
|
||||
super.setSize(size);
|
||||
internalPanel.setSize(size);
|
||||
valueLabel.setSize(size);
|
||||
for(int i = 0; i < 9; i++)
|
||||
if(notesLabels[i] != null) notesLabels[i].setSize(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the underlying Cell object.
|
||||
*
|
||||
@@ -81,6 +105,45 @@ class CellGUI extends JPanel {
|
||||
internalPanel.revalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of the underlying Cell object.
|
||||
*
|
||||
* This implementation allows for incorrect values to be highlighted.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setValue(int value, int expected) {
|
||||
if(!selected) return;
|
||||
|
||||
cell.setValue(value);
|
||||
valueLabel.setText(Integer.toString(cell.getValue()));
|
||||
|
||||
if(value != expected) {
|
||||
incorrect = true;
|
||||
errorStyle();
|
||||
}
|
||||
|
||||
internalPanel.repaint();
|
||||
internalPanel.revalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the value of the underlying Cell object.
|
||||
*/
|
||||
public void removeValue() {
|
||||
if(!selected) return;
|
||||
|
||||
cell.setValue(0);
|
||||
if(!cell.isInitValue())
|
||||
valueLabel.setText("");
|
||||
|
||||
incorrect = false;
|
||||
highlightedStyle();
|
||||
|
||||
internalPanel.repaint();
|
||||
internalPanel.revalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the possible values of the underlying Cell object.
|
||||
*
|
||||
@@ -96,8 +159,13 @@ class CellGUI extends JPanel {
|
||||
* @param value
|
||||
*/
|
||||
public void addPossibleValue(int value) {
|
||||
if(!selected) return;
|
||||
|
||||
cell.addPossibleValue(value);
|
||||
setNoteMode();
|
||||
internalPanel.removeAll();
|
||||
internalPanel.setLayout(noteLayout);
|
||||
generateNotes();
|
||||
highlightedStyle();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,10 +223,45 @@ class CellGUI extends JPanel {
|
||||
|
||||
public void select() {
|
||||
selected = !selected;
|
||||
if(incorrect) {
|
||||
errorStyle();
|
||||
repaint();
|
||||
revalidate();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!selected) {
|
||||
style();
|
||||
} else {
|
||||
if(!selected)
|
||||
defaultStyle();
|
||||
|
||||
else highlightedStyle();
|
||||
|
||||
repaint();
|
||||
revalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Style the cell with the appropriate colors from the theme.
|
||||
*/
|
||||
private void defaultStyle() {
|
||||
setBackground(theme.getPrimaryBackground());
|
||||
setForeground(theme.getPrimaryText());
|
||||
internalPanel.setBackground(theme.getPrimaryBackground());
|
||||
internalPanel.setForeground(theme.getPrimaryText());
|
||||
valueLabel.setForeground(theme.getPrimaryText());
|
||||
setBorder(new LineBorder(theme.getPrimaryBorder(), 2));
|
||||
|
||||
for(int i = 0; i < 9; i++) {
|
||||
if(notesLabels[i] != null) {
|
||||
notesLabels[i].setBackground(theme.getPrimaryBackground());
|
||||
notesLabels[i].setForeground(theme.getPrimaryText());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Style the cell with the appropriate colors from the theme.
|
||||
*/
|
||||
private void highlightedStyle() {
|
||||
setBackground(theme.getSecondaryBackground());
|
||||
setForeground(theme.getSecondaryText());
|
||||
internalPanel.setBackground(theme.getSecondaryBackground());
|
||||
@@ -174,25 +277,21 @@ class CellGUI extends JPanel {
|
||||
}
|
||||
}
|
||||
|
||||
repaint();
|
||||
revalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Style the cell with the appropriate colors from the theme.
|
||||
*/
|
||||
private void style() {
|
||||
setBackground(theme.getPrimaryBackground());
|
||||
setForeground(theme.getPrimaryText());
|
||||
internalPanel.setBackground(theme.getPrimaryBackground());
|
||||
internalPanel.setForeground(theme.getPrimaryText());
|
||||
valueLabel.setForeground(theme.getPrimaryText());
|
||||
setBorder(new LineBorder(theme.getPrimaryBorder(), 2));
|
||||
private void errorStyle() {
|
||||
setBackground(theme.getErrorBackground());
|
||||
setForeground(theme.getErrorText());
|
||||
internalPanel.setBackground(theme.getErrorBackground());
|
||||
internalPanel.setForeground(theme.getErrorText());
|
||||
valueLabel.setForeground(theme.getErrorText());
|
||||
setBorder(new LineBorder(theme.getErrorBorder(), 2));
|
||||
|
||||
for(int i = 0; i < 9; i++) {
|
||||
if(notesLabels[i] != null) {
|
||||
notesLabels[i].setBackground(theme.getPrimaryBackground());
|
||||
notesLabels[i].setForeground(theme.getPrimaryText());
|
||||
notesLabels[i].setBackground(theme.getErrorBackground());
|
||||
notesLabels[i].setForeground(theme.getErrorText());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,6 +126,7 @@ public class Cell {
|
||||
if(initValue) return;
|
||||
|
||||
if(possibleValues.contains(value)) {
|
||||
removePossibleValue(value);
|
||||
return;
|
||||
} else if(value < 1 || value > 9) {
|
||||
return;
|
||||
@@ -181,6 +182,17 @@ public class Cell {
|
||||
return initValue;
|
||||
}
|
||||
|
||||
public static Cell[][] copyGrid(Cell[][] grid) {
|
||||
Cell[][] newGrid = new Cell[9][9];
|
||||
for(int row = 0; row < 9; row++) {
|
||||
for(int col = 0; col < 9; col++) {
|
||||
newGrid[row][col] = new Cell(row, col, grid[row][col].getValue());
|
||||
}
|
||||
}
|
||||
|
||||
return newGrid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the cell's row and column, set the box number for the cell.
|
||||
*/
|
||||
|
||||
@@ -41,6 +41,9 @@ public class Settings {
|
||||
// The default dimension of the application window.
|
||||
private Dimension dimension;
|
||||
|
||||
// The default dimension of the cells in the application window.
|
||||
private Dimension cellDimension;
|
||||
|
||||
// Resizable setting
|
||||
private boolean resizable;
|
||||
|
||||
@@ -56,6 +59,9 @@ public class Settings {
|
||||
// Auto-fill notes
|
||||
private boolean autoFillNotes;
|
||||
|
||||
// Auto check values
|
||||
private boolean autoCheckValues;
|
||||
|
||||
/**
|
||||
* Create a new Settings object, initializing the default settings
|
||||
* or reading in the settings from settings file if it exists.
|
||||
@@ -310,6 +316,53 @@ public class Settings {
|
||||
updateSettingsFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* The Auto-check values setting is a configurable setting, where the user
|
||||
* can specify whether values should be automatically checked when placed
|
||||
* in a cell.
|
||||
*
|
||||
* By default, the auto-check values setting is set to false.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean getAutoCheckValues() {
|
||||
return autoCheckValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the auto-check values setting and write it to the settings file.
|
||||
*
|
||||
* @param autoCheckValues
|
||||
*/
|
||||
public void setAutoCheckValues(boolean autoCheckValues) {
|
||||
this.autoCheckValues = autoCheckValues;
|
||||
updateSettingsFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* The default dimensions of the cells in the application window.
|
||||
*
|
||||
* The default dimensions are set to 50x50 pixels.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Dimension getCellDimensions() {
|
||||
return cellDimension;
|
||||
}
|
||||
|
||||
private void setCellDimensions() {
|
||||
int height;
|
||||
int width;
|
||||
|
||||
if(dimension.height < 500) height = 50;
|
||||
else height = dimension.height / 10;
|
||||
|
||||
if(dimension.width < 500) width = 50;
|
||||
else width = dimension.width / 10;
|
||||
|
||||
cellDimension = new Dimension(width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open and write the settings to the settings file.
|
||||
*
|
||||
@@ -346,7 +399,9 @@ public class Settings {
|
||||
cellGUIStartMode = false;
|
||||
defaultOpenState = 0;
|
||||
theme = new Theme(new File(appDirectory + "default.theme"));
|
||||
autoFillNotes = true;
|
||||
autoFillNotes = false;
|
||||
autoCheckValues = true;
|
||||
setCellDimensions();
|
||||
|
||||
updateSettingsFile();
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ import java.io.File;
|
||||
* It provides colors for various GUI elements.
|
||||
*/
|
||||
public class Theme {
|
||||
private File theme;
|
||||
|
||||
private Color primaryBackground;
|
||||
private Color secondaryBackground;
|
||||
private Color primaryText;
|
||||
@@ -46,6 +48,9 @@ public class Theme {
|
||||
private Color secondaryButtonHighlight;
|
||||
private Color primaryButtonBorder;
|
||||
private Color secondaryButtonBorder;
|
||||
private Color errorBackground;
|
||||
private Color errorText;
|
||||
private Color errorBorder;
|
||||
|
||||
/**
|
||||
* Constructs a new Theme object with the given theme file.
|
||||
@@ -77,6 +82,9 @@ public class Theme {
|
||||
secondaryText = Color.decode("#4A245E");
|
||||
primaryBorder = Color.decode("#A76BCA");
|
||||
secondaryBorder = Color.decode("#DBABF7");
|
||||
errorBackground = Color.decode("#FF0000");
|
||||
errorText = Color.decode("#FFFFFF");
|
||||
errorBorder = Color.decode("#FF0000");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -331,5 +339,57 @@ public class Theme {
|
||||
this.secondaryButtonBorder = secondaryButtonBorder;
|
||||
}
|
||||
|
||||
private File theme;
|
||||
/**
|
||||
* Gets the error background color.
|
||||
*
|
||||
* @return the error background color
|
||||
*/
|
||||
public Color getErrorBackground() {
|
||||
return errorBackground;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the error background color.
|
||||
*
|
||||
* @param errorBackground the error background color
|
||||
*/
|
||||
public void setErrorBackground(Color errorBackground) {
|
||||
this.errorBackground = errorBackground;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the error text color.
|
||||
*
|
||||
* @return the error text color
|
||||
*/
|
||||
public Color getErrorText() {
|
||||
return errorText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the error text color.
|
||||
*
|
||||
* @param errorText the error text color
|
||||
*/
|
||||
public void setErrorText(Color errorText) {
|
||||
this.errorText = errorText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the error border color.
|
||||
*
|
||||
* @return the error border color
|
||||
*/
|
||||
public Color getErrorBorder() {
|
||||
return errorBorder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the error border color.
|
||||
*
|
||||
* @param errorBorder the error border color
|
||||
*/
|
||||
public void setErrorBorder(Color errorBorder) {
|
||||
this.errorBorder = errorBorder;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user