328 lines
9.0 KiB
Java
328 lines
9.0 KiB
Java
package gui;
|
|
|
|
// GUI imports
|
|
import javax.swing.JLabel;
|
|
import javax.swing.JPanel;
|
|
import javax.swing.border.LineBorder;
|
|
import java.awt.Dimension;
|
|
import java.awt.Font;
|
|
import java.awt.GridLayout;
|
|
|
|
// Processing & backend imports
|
|
import gui.backend.Cell;
|
|
import gui.backend.Settings;
|
|
import gui.backend.Theme;
|
|
|
|
/**
|
|
* GUI representation of a single cell in the Sudoku grid.
|
|
*/
|
|
class CellGUI extends JPanel {
|
|
// GUI fields
|
|
private GridLayout noteLayout = new GridLayout(3, 3);
|
|
private GridLayout valueLayout = new GridLayout(0, 1);
|
|
private JPanel internalPanel = new JPanel(valueLayout);
|
|
private JLabel valueLabel;
|
|
private Label[] notesLabels = new Label[9];
|
|
|
|
// GUI data fields read from a Settings object.
|
|
private Dimension size;
|
|
private Theme theme;
|
|
private Font font;
|
|
|
|
// Data fields
|
|
Cell cell;
|
|
private boolean noteMode; // true to display notes, or display value
|
|
private boolean selected = false; // true if the cell is selected
|
|
private boolean incorrect = false; // true if the cell has an invalid value
|
|
|
|
/**
|
|
* Create a new CellGUI object with the given single cell.
|
|
*
|
|
* Start blank cells in notes mode if startInNotesOrValueMode is true.
|
|
*
|
|
* @param cell
|
|
* @param startInNotesOrValueMode
|
|
*/
|
|
public CellGUI(Cell cell, Settings s) {
|
|
super();
|
|
this.cell = cell;
|
|
|
|
// Set the initial state of the cell based off the settings.
|
|
noteMode = s.getCellGUIStartMode();
|
|
theme = s.getTheme();
|
|
font = s.getFont();
|
|
selected = false;
|
|
size = s.getCellDimensions();
|
|
|
|
// Set the layout and size of the cell.
|
|
setFocusable(true);
|
|
setLayout(valueLayout);
|
|
valueLabel = new Label("", theme, font);
|
|
setSize(size);
|
|
internalPanel.setSize(size);
|
|
defaultStyle();
|
|
|
|
// Populate the cell with the appropriate value or notes.
|
|
if(cell.getValue() == 0) {
|
|
internalPanel.setLayout(noteLayout);
|
|
generateNotes(s.getAutoFillNotes());
|
|
} else {
|
|
internalPanel.setLayout(valueLayout);
|
|
valueLabel.setText(Integer.toString(cell.getValue()));
|
|
internalPanel.add(valueLabel);
|
|
}
|
|
add(internalPanel);
|
|
}
|
|
|
|
/**
|
|
* Get the value of the underlying Cell object.
|
|
*
|
|
* @return int
|
|
*/
|
|
public int getValue() {
|
|
return cell.getValue();
|
|
}
|
|
|
|
/**
|
|
* Set the value of the underlying Cell object.
|
|
*
|
|
* @param value
|
|
*/
|
|
public void setValue(int value) {
|
|
if(!selected) return;
|
|
|
|
cell.setValue(value);
|
|
// Update the GUI with the actual Cell value (unchanged if invalid)
|
|
valueLabel.setText(Integer.toString(cell.getValue()));
|
|
refresh();
|
|
}
|
|
|
|
/**
|
|
* 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();
|
|
} else refresh();
|
|
}
|
|
|
|
/**
|
|
* 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();
|
|
}
|
|
|
|
/**
|
|
* Add a possible value to the cell.
|
|
*
|
|
* @param value
|
|
*/
|
|
public void addPossibleValue(int value) {
|
|
if(!selected) return;
|
|
|
|
cell.addPossibleValue(value);
|
|
internalPanel.removeAll();
|
|
internalPanel.setLayout(noteLayout);
|
|
noteMode = true;
|
|
generateNotes(true);
|
|
highlightedStyle();
|
|
}
|
|
|
|
/**
|
|
* Remove a possible value from the cell.
|
|
*
|
|
* @return
|
|
*/
|
|
public void removePossibleValue(int value) {
|
|
cell.removePossibleValue(value);
|
|
}
|
|
|
|
/**
|
|
* Get the status of the cell in notes mode.
|
|
*
|
|
* @return
|
|
*/
|
|
public boolean isInNotesMode() {
|
|
return noteMode;
|
|
}
|
|
|
|
/**
|
|
* Toggle the mode of the cell between value and note, including the
|
|
* layout of the cell.
|
|
*
|
|
* If the current mode is value, switch to note mode, and vice versa.
|
|
*/
|
|
public void setNoteMode() {
|
|
if(cell.isInitValue()) return;
|
|
|
|
internalPanel.removeAll();
|
|
if(noteMode) {
|
|
internalPanel.setLayout(valueLayout);
|
|
internalPanel.add(valueLabel);
|
|
} else {
|
|
internalPanel.setLayout(noteLayout);
|
|
noteMode = true;
|
|
generateNotes(true);
|
|
}
|
|
|
|
refresh();
|
|
|
|
noteMode = !noteMode;
|
|
}
|
|
|
|
/**
|
|
* Select the cell, and style it for error, highlight, or default.
|
|
*/
|
|
public void select() {
|
|
selected = !selected;
|
|
if(incorrect) {
|
|
errorStyle();
|
|
return;
|
|
}
|
|
|
|
if(!selected)
|
|
defaultStyle();
|
|
|
|
else highlightedStyle();
|
|
}
|
|
|
|
/**
|
|
* Style the CellGUI with the primary colors from the Theme.
|
|
*
|
|
* @see Theme.java
|
|
*/
|
|
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());
|
|
}
|
|
}
|
|
|
|
refresh();
|
|
}
|
|
|
|
/**
|
|
* Style the CellGUI with the secondary colors from the Theme.
|
|
*
|
|
* @see Theme.java
|
|
*/
|
|
private void highlightedStyle() {
|
|
setBackground(theme.getSecondaryBackground());
|
|
setForeground(theme.getSecondaryText());
|
|
internalPanel.setBackground(theme.getSecondaryBackground());
|
|
internalPanel.setForeground(theme.getSecondaryText());
|
|
valueLabel.setForeground(theme.getSecondaryText());
|
|
setBorder(new LineBorder(theme.getSecondaryBorder(), 2));
|
|
|
|
for(int i = 0; i < 9; i++) {
|
|
if(notesLabels[i] != null) {
|
|
notesLabels[i].setBackground(theme.getSecondaryBackground());
|
|
notesLabels[i].setForeground(theme.getSecondaryText());
|
|
}
|
|
}
|
|
|
|
refresh();
|
|
}
|
|
|
|
/**
|
|
* Style the CellGUI with the error colors from the Theme.
|
|
*
|
|
* @see Theme.java
|
|
*/
|
|
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.getErrorBackground());
|
|
notesLabels[i].setForeground(theme.getErrorText());
|
|
}
|
|
}
|
|
|
|
refresh();
|
|
}
|
|
|
|
/**
|
|
* Helper method to repaint and revalidate the internal panel and CellGUI.
|
|
*/
|
|
private void refresh() {
|
|
internalPanel.repaint();
|
|
internalPanel.revalidate();
|
|
repaint();
|
|
revalidate();
|
|
}
|
|
|
|
/**
|
|
* Create the GUI components for the cell's notes.
|
|
*
|
|
* If autoFill is true, then the CellGUI will automatically switch to
|
|
* noteMode.
|
|
*
|
|
* @param autoFill
|
|
*/
|
|
private void generateNotes(boolean autoFill) {
|
|
int[] possibleValues = cell.getPossibleValues();
|
|
|
|
// Prepare the internalPanel for noteMode.
|
|
if(autoFill) {
|
|
internalPanel.removeAll();
|
|
noteMode = true;
|
|
}
|
|
|
|
// Handle cases where there are no possible values stored.
|
|
if(possibleValues.length == 0) {
|
|
for(int i = 0; i < 9; i++) {
|
|
notesLabels[i] = new Label("", theme, font);
|
|
|
|
if(autoFill) internalPanel.add(notesLabels[i]);
|
|
}
|
|
return;
|
|
}
|
|
|
|
int index = 0;
|
|
// Add the noted possible values to the cell.
|
|
for(int i = 1; i <= 9 && index < possibleValues.length; i++) {
|
|
// Add the possible value if it exists.
|
|
if(possibleValues[index] == i) {
|
|
notesLabels[i - 1] = new Label(Integer.toString(i), theme, font);
|
|
index++;
|
|
|
|
// Otherwise, add a blank value.
|
|
} else
|
|
notesLabels[i - 1] = new Label("", theme, font);
|
|
|
|
if(autoFill) internalPanel.add(notesLabels[i - 1]);
|
|
}
|
|
}
|
|
} |