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:
Josh Ashton
2024-03-24 17:00:55 -06:00
parent 56f4fed7bc
commit bf5a54d500
5 changed files with 286 additions and 43 deletions
+37 -20
View File
@@ -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
View File
@@ -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());
}
}
}
+12
View File
@@ -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.
*/
+56 -1
View File
@@ -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();
}
+61 -1
View File
@@ -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;
}
}