158 lines
4.8 KiB
Java
158 lines
4.8 KiB
Java
package gui.widget;
|
|
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
|
|
import common.ConsumerSignal;
|
|
import common.Signal;
|
|
import gui.ColorGenerator;
|
|
import gui.ColorGenerator.Color;
|
|
import gui.RenderableMultidoku;
|
|
import gui.constants.Fonts;
|
|
import gui.constants.Options;
|
|
import gui.constants.Symbols;
|
|
import imgui.ImGui;
|
|
import imgui.ImVec2;
|
|
import imgui.ImVec4;
|
|
import imgui.flag.ImGuiCol;
|
|
import imgui.flag.ImGuiStyleVar;
|
|
import sudoku.constraint.Constraint;
|
|
import sudoku.structure.Block;
|
|
import sudoku.structure.Cell;
|
|
import sudoku.structure.MultiDoku;
|
|
import sudoku.structure.Sudoku;
|
|
|
|
public class SudokuRenderer {
|
|
|
|
private final RenderableMultidoku doku;
|
|
private Cell currentCell = null;
|
|
private final Map<Block, Color> colorPalette;
|
|
|
|
private static final ImVec4 BLACK = new ImVec4(0, 0, 0, 1);
|
|
private static final ImVec4 TRANSPARENT = new ImVec4();
|
|
private static final ImVec4 WHITE = new ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
|
|
private static final ImVec2 cellSize = new ImVec2(50, 50);
|
|
|
|
private final Set<Cell> diagonals = new HashSet<>();
|
|
|
|
public final Signal onResolve = new Signal();
|
|
public final ConsumerSignal<Cell> onCellChange = new ConsumerSignal<>();
|
|
|
|
public SudokuRenderer(MultiDoku doku) {
|
|
this.doku = RenderableMultidoku.fromMultidoku(doku);
|
|
this.colorPalette = initColors();
|
|
initDiagonals();
|
|
}
|
|
|
|
private void initDiagonals() {
|
|
for (Sudoku sudoku : this.doku.getDoku().getSubGrids()) {
|
|
if (sudoku.hasConstraint(Constraint.Diagonal)) {
|
|
for (int i = 0; i < sudoku.getSize(); i++) {
|
|
this.diagonals.add(sudoku.getCell(i, i));
|
|
this.diagonals.add(sudoku.getCell(sudoku.getSize() - i - 1, i));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private Map<Block, Color> initColors() {
|
|
List<Color> colors = ColorGenerator.greatPalette(doku.getBlocks().size());
|
|
Map<Block, Color> colorPalette = new HashMap<>();
|
|
int index = 0;
|
|
for (Block block : doku.getBlocks()) {
|
|
colorPalette.put(block, colors.get(index));
|
|
index++;
|
|
}
|
|
return colorPalette;
|
|
}
|
|
|
|
private void renderPopup() {
|
|
if (ImGui.beginPopup("editPopup")) {
|
|
Block block = currentCell.getBlock();
|
|
int symbolCount = block.getCells().size();
|
|
for (int i = 0; i < symbolCount; i++) {
|
|
if ((i + 1) % (int) (Math.sqrt(symbolCount)) != 1)
|
|
ImGui.sameLine();
|
|
if (currentCell.getSymbolIndex() == i) {
|
|
if (ImGui.button("X", cellSize)) {
|
|
currentCell.setSymbolIndex(Cell.NOSYMBOL);
|
|
this.onCellChange.emit(currentCell);
|
|
ImGui.closeCurrentPopup();
|
|
}
|
|
} else {
|
|
if (ImGui.button(Options.Symboles.getSymbols().get(i), cellSize)) {
|
|
currentCell.setSymbolIndex(i);
|
|
this.onCellChange.emit(currentCell);
|
|
if (this.doku.getDoku().isSolved())
|
|
this.onResolve.emit();
|
|
ImGui.closeCurrentPopup();
|
|
}
|
|
}
|
|
}
|
|
ImGui.endPopup();
|
|
}
|
|
}
|
|
|
|
public void render() {
|
|
if (Options.Symboles == Symbols.Russian) {
|
|
ImGui.pushFont(Fonts.ARIAL);
|
|
}
|
|
final float sudokuViewWidth = cellSize.x * doku.getWidth();
|
|
final float displayWidth = ImGui.getIO().getDisplaySizeX();
|
|
float offsetX = displayWidth / 2.0f - sudokuViewWidth / 2.0f;
|
|
// if the grid is too big, don't offset it
|
|
if (offsetX > 0) {
|
|
ImGui.setCursorPosX(offsetX);
|
|
}
|
|
ImGui.beginChild("sudokuChild", new ImVec2(cellSize.x * doku.getWidth(), cellSize.y * doku.getHeight()));
|
|
|
|
ImGui.pushStyleVar(ImGuiStyleVar.FrameBorderSize, 2.0f);
|
|
ImGui.pushStyleVar(ImGuiStyleVar.ItemSpacing, new ImVec2(0.0f, 0.0f));
|
|
for (int y = 0; y < doku.getHeight(); y++) {
|
|
for (int x = 0; x < doku.getWidth(); x++) {
|
|
if (x > 0)
|
|
ImGui.sameLine();
|
|
int index = y * doku.getWidth() + x;
|
|
Cell cell = doku.getCell(x, y);
|
|
ImGui.beginDisabled(cell == null);
|
|
if (cell == null) {
|
|
ImGui.pushStyleColor(ImGuiCol.Border, TRANSPARENT);
|
|
ImGui.pushStyleColor(ImGuiCol.Button, TRANSPARENT);
|
|
ImGui.button("##" + index, cellSize);
|
|
} else {
|
|
if (diagonals.contains(cell)) {
|
|
ImGui.pushStyleColor(ImGuiCol.Border, WHITE);
|
|
} else {
|
|
ImGui.pushStyleColor(ImGuiCol.Border, BLACK);
|
|
}
|
|
int symbol = cell.getSymbolIndex();
|
|
Color blockColor = colorPalette.get(cell.getBlock());
|
|
if (!cell.isMutable()) {
|
|
blockColor = new Color(blockColor.r - 0.20f, blockColor.g - 0.20f, blockColor.b - 0.20f);
|
|
}
|
|
ImGui.pushStyleColor(ImGuiCol.Button, new ImVec4(blockColor.r, blockColor.g, blockColor.b, 1.0f));
|
|
String cellText = "";
|
|
if (symbol != -1)
|
|
cellText += Options.Symboles.getSymbols().get(symbol);
|
|
if (ImGui.button(cellText + "##" + index, cellSize) && cell.isMutable()) {
|
|
ImGui.openPopup("editPopup");
|
|
currentCell = cell;
|
|
}
|
|
}
|
|
ImGui.endDisabled();
|
|
ImGui.popStyleColor(2);
|
|
}
|
|
}
|
|
ImGui.popStyleVar(2);
|
|
renderPopup();
|
|
ImGui.endChild();
|
|
if (Options.Symboles == Symbols.Russian) {
|
|
ImGui.popFont();
|
|
}
|
|
}
|
|
|
|
}
|