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; package gui;
import java.awt.Dimension;
import java.awt.GridLayout; import java.awt.GridLayout;
import java.awt.LayoutManager; import java.awt.LayoutManager;
import java.awt.event.KeyAdapter; import java.awt.event.KeyAdapter;
@@ -29,6 +30,7 @@ import gui.backend.SudokuChecker;
public class Board extends JPanel { public class Board extends JPanel {
private Settings s; private Settings s;
private Cell[][] grid; private Cell[][] grid;
private Cell[][] solvedGrid;
private CellGUI[][] gridGUI; private CellGUI[][] gridGUI;
private SudokuChecker sc; private SudokuChecker sc;
private CellGUI selected; private CellGUI selected;
@@ -43,6 +45,8 @@ public class Board extends JPanel {
this.s = s; this.s = s;
this.grid = grid; this.grid = grid;
this.sc = sc; this.sc = sc;
solvedGrid = new SudokuChecker(Cell.copyGrid(grid)).getSolution();
style(); style();
createBoard(); createBoard();
} }
@@ -50,30 +54,42 @@ public class Board extends JPanel {
private KeyListener createKeyListener() { private KeyListener createKeyListener() {
return new KeyListener() { return new KeyListener() {
@Override @Override
public void keyTyped(KeyEvent e) { 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));
}
@Override @Override
public void keyPressed(KeyEvent e) {} public void keyPressed(KeyEvent e) {}
@Override @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( CellGUI cell = new CellGUI(
grid[i][j], grid[i][j],
s.getCellGUIStartMode(), s.getCellGUIStartMode(),
s.getTheme() s.getTheme(),
s.getCellDimensions()
); );
cell.addMouseListener(new MouseListener() { cell.addMouseListener(new MouseListener() {
@Override @Override
+118 -19
View File
@@ -1,6 +1,7 @@
package gui; package gui;
import java.awt.BorderLayout; import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout; import java.awt.GridLayout;
import javax.swing.JLabel; import javax.swing.JLabel;
@@ -19,9 +20,11 @@ class CellGUI extends JPanel {
private JPanel internalPanel = new JPanel(new BorderLayout()); private JPanel internalPanel = new JPanel(new BorderLayout());
private GridLayout noteLayout = new GridLayout(3, 3); private GridLayout noteLayout = new GridLayout(3, 3);
private GridLayout valueLayout = new GridLayout(0, 1); private GridLayout valueLayout = new GridLayout(0, 1);
private Dimension size;
private JLabel valueLabel; private JLabel valueLabel;
private Note[] notesLabels = new Note[9]; private Note[] notesLabels = new Note[9];
private Theme theme; private Theme theme;
private boolean incorrect;
// Data fields // Data fields
Cell cell; Cell cell;
@@ -36,7 +39,7 @@ class CellGUI extends JPanel {
* @param cell * @param cell
* @param startInNotesOrValueMode * @param startInNotesOrValueMode
*/ */
public CellGUI(Cell cell, boolean noteMode, Theme theme) { public CellGUI(Cell cell, boolean noteMode, Theme theme, Dimension size) {
super(); super();
this.cell = cell; this.cell = cell;
this.noteMode = !noteMode; // Flip for use with setNoteMode() this.noteMode = !noteMode; // Flip for use with setNoteMode()
@@ -45,7 +48,9 @@ class CellGUI extends JPanel {
setFocusable(true); setFocusable(true);
setLayout(valueLayout); setLayout(valueLayout);
valueLabel = new JLabel("", SwingConstants.CENTER); valueLabel = new JLabel("", SwingConstants.CENTER);
style(); this.size = size;
setSize(this.size);
defaultStyle();
// Populate the cell with the appropriate value or notes. // Populate the cell with the appropriate value or notes.
if(cell.getValue() == 0) { if(cell.getValue() == 0) {
@@ -59,6 +64,25 @@ class CellGUI extends JPanel {
add(internalPanel); 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. * Get the value of the underlying Cell object.
* *
@@ -81,6 +105,45 @@ class CellGUI extends JPanel {
internalPanel.revalidate(); 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. * Set the possible values of the underlying Cell object.
* *
@@ -96,8 +159,13 @@ class CellGUI extends JPanel {
* @param value * @param value
*/ */
public void addPossibleValue(int value) { public void addPossibleValue(int value) {
if(!selected) return;
cell.addPossibleValue(value); cell.addPossibleValue(value);
setNoteMode(); internalPanel.removeAll();
internalPanel.setLayout(noteLayout);
generateNotes();
highlightedStyle();
} }
/** /**
@@ -155,10 +223,45 @@ class CellGUI extends JPanel {
public void select() { public void select() {
selected = !selected; selected = !selected;
if(incorrect) {
errorStyle();
repaint();
revalidate();
return;
}
if(!selected) { if(!selected)
style(); defaultStyle();
} else {
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()); setBackground(theme.getSecondaryBackground());
setForeground(theme.getSecondaryText()); setForeground(theme.getSecondaryText());
internalPanel.setBackground(theme.getSecondaryBackground()); internalPanel.setBackground(theme.getSecondaryBackground());
@@ -174,25 +277,21 @@ class CellGUI extends JPanel {
} }
} }
repaint();
revalidate();
}
/** /**
* Style the cell with the appropriate colors from the theme. * Style the cell with the appropriate colors from the theme.
*/ */
private void style() { private void errorStyle() {
setBackground(theme.getPrimaryBackground()); setBackground(theme.getErrorBackground());
setForeground(theme.getPrimaryText()); setForeground(theme.getErrorText());
internalPanel.setBackground(theme.getPrimaryBackground()); internalPanel.setBackground(theme.getErrorBackground());
internalPanel.setForeground(theme.getPrimaryText()); internalPanel.setForeground(theme.getErrorText());
valueLabel.setForeground(theme.getPrimaryText()); valueLabel.setForeground(theme.getErrorText());
setBorder(new LineBorder(theme.getPrimaryBorder(), 2)); setBorder(new LineBorder(theme.getErrorBorder(), 2));
for(int i = 0; i < 9; i++) { for(int i = 0; i < 9; i++) {
if(notesLabels[i] != null) { if(notesLabels[i] != null) {
notesLabels[i].setBackground(theme.getPrimaryBackground()); notesLabels[i].setBackground(theme.getErrorBackground());
notesLabels[i].setForeground(theme.getPrimaryText()); notesLabels[i].setForeground(theme.getErrorText());
} }
} }
} }
+12
View File
@@ -126,6 +126,7 @@ public class Cell {
if(initValue) return; if(initValue) return;
if(possibleValues.contains(value)) { if(possibleValues.contains(value)) {
removePossibleValue(value);
return; return;
} else if(value < 1 || value > 9) { } else if(value < 1 || value > 9) {
return; return;
@@ -181,6 +182,17 @@ public class Cell {
return initValue; 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. * 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. // The default dimension of the application window.
private Dimension dimension; private Dimension dimension;
// The default dimension of the cells in the application window.
private Dimension cellDimension;
// Resizable setting // Resizable setting
private boolean resizable; private boolean resizable;
@@ -56,6 +59,9 @@ public class Settings {
// Auto-fill notes // Auto-fill notes
private boolean autoFillNotes; private boolean autoFillNotes;
// Auto check values
private boolean autoCheckValues;
/** /**
* Create a new Settings object, initializing the default settings * Create a new Settings object, initializing the default settings
* or reading in the settings from settings file if it exists. * or reading in the settings from settings file if it exists.
@@ -310,6 +316,53 @@ public class Settings {
updateSettingsFile(); 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. * Open and write the settings to the settings file.
* *
@@ -346,7 +399,9 @@ public class Settings {
cellGUIStartMode = false; cellGUIStartMode = false;
defaultOpenState = 0; defaultOpenState = 0;
theme = new Theme(new File(appDirectory + "default.theme")); theme = new Theme(new File(appDirectory + "default.theme"));
autoFillNotes = true; autoFillNotes = false;
autoCheckValues = true;
setCellDimensions();
updateSettingsFile(); updateSettingsFile();
} }
+61 -1
View File
@@ -32,6 +32,8 @@ import java.io.File;
* It provides colors for various GUI elements. * It provides colors for various GUI elements.
*/ */
public class Theme { public class Theme {
private File theme;
private Color primaryBackground; private Color primaryBackground;
private Color secondaryBackground; private Color secondaryBackground;
private Color primaryText; private Color primaryText;
@@ -46,6 +48,9 @@ public class Theme {
private Color secondaryButtonHighlight; private Color secondaryButtonHighlight;
private Color primaryButtonBorder; private Color primaryButtonBorder;
private Color secondaryButtonBorder; private Color secondaryButtonBorder;
private Color errorBackground;
private Color errorText;
private Color errorBorder;
/** /**
* Constructs a new Theme object with the given theme file. * Constructs a new Theme object with the given theme file.
@@ -77,6 +82,9 @@ public class Theme {
secondaryText = Color.decode("#4A245E"); secondaryText = Color.decode("#4A245E");
primaryBorder = Color.decode("#A76BCA"); primaryBorder = Color.decode("#A76BCA");
secondaryBorder = Color.decode("#DBABF7"); 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; 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;
}
} }