| 📋 Menu Principal (BR) | ⌨️ Atalho | 📋 Main Menu (US) | ⌨️ Shortcut |
|------------------------|------------|-------------------|--------------|
| Jogar | `Alt + J` | Play | `Alt + P` |
| Instruções | `Alt + I` | Instructions | `Alt + I` |
| Configurações | `Alt + C` | Settings | `Alt + S` |
| Sobre | `Alt + S` | About | `Alt + A` |
| Encerrar | `Alt + E` | Exit | `Alt + E` |
| 🧮 Tabuleiro Sudoku (BR) | ⌨️ Atalho | 🧮 Sudoku Board (US) | ⌨️ Shortcut |
|--------------------------|------------|----------------------|--------------|
| Verificar | `Alt + V` | Check | `Alt + C` |
| Solucionar | `Alt + S` | Solve | `Alt + S` |
| Novo | `Alt + N` | New | `Alt + N` |
| Reiniciar | `Alt + R` | Restart | `Alt + R` |
package main;
import model.Board;
import model.BoardTemplate;
import model.InvalidBoardFormatException;
import model.PuzzleRepository;
import util.SudokuLanguage;
import util.SudokuSettings;
import view.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.net.URL;
import java.util.Locale;
public class SudokuSwingApp {
private static JFrame menuFrame;
private static JFrame currentFrame;
private static boolean isFullScreen;
private static Rectangle windowBounds;
private static final GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
private static boolean shortcutsRegistered = false;
private static int lastExtendedState = JFrame.NORMAL;
public static void main(String[] args) {
setLanguage(new Locale("pt", "BR"));
new SudokuSplash().showSplash(5000);
SudokuStyle.applyGlobalStyle();
SudokuSound.initSounds();
SwingUtilities.invokeLater(SudokuSwingApp::showMainMenu);
}
public static void setLanguage(Locale locale) {
SudokuLanguage.setLocale(locale);
if (currentFrame != null) updateFrameLanguage(currentFrame);
}
private static void updateFrameLanguage(JFrame frame) {
Container content = frame.getContentPane();
if (content instanceof SudokuMenu) {
frame.setContentPane(new SudokuMenu());
} else if (content instanceof SudokuSettings) {
frame.setContentPane(new SudokuSettings());
} else if (content instanceof SudokuInstructions) {
frame.setContentPane(new SudokuInstructions());
} else if (content instanceof SudokuPanel) {
Board board = ((SudokuPanel) content).getBoard();
frame.setContentPane(new SudokuPanel(board));
} else if (content instanceof SudokuAbout) {
frame.setContentPane(new SudokuAbout());
}
bindClickSoundToButtons(frame.getContentPane());
frame.revalidate();
frame.repaint();
}
public static void playClickSound() {
SudokuSound.playClickSound();
}
private static void bindClickSoundToButtons(Container container) {
for (Component comp : container.getComponents()) {
if (comp instanceof JButton button) {
ActionListener[] listeners = button.getActionListeners();
for (ActionListener listener : listeners) {
button.removeActionListener(listener);
button.addActionListener(e -> {
playClickSound();
listener.actionPerformed(e);
});
}
} else if (comp instanceof Container child) {
bindClickSoundToButtons(child);
}
}
}
private static void showMainMenu() {
if (menuFrame != null) menuFrame.dispose();
menuFrame = new JFrame("Sudoku");
currentFrame = menuFrame;
menuFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
menuFrame.setLayout(new BorderLayout());
applyAppIcon(menuFrame);
menuFrame.getContentPane().setBackground(SudokuStyle.COLOR_PRIMARY);
menuFrame.setContentPane(new SudokuMenu());
bindClickSoundToButtons(menuFrame.getContentPane());
applyPreviousWindowState(menuFrame);
applyFullscreenIfActive(menuFrame);
menuFrame.setVisible(true);
menuFrame.requestFocus();
menuFrame.toFront();
setupWindowShortcuts(menuFrame);
}
public static void startGame() {
Board board;
try {
board = BoardTemplate.of(PuzzleRepository.getPuzzleInicial()).build();
board.getSpaces().forEach(row ->
row.stream()
.filter(space -> !space.isFixed())
.forEach(space -> space.setActual(null))
);
} catch (InvalidBoardFormatException e) {
JOptionPane.showMessageDialog(null, "Erro ao carregar o puzzle.", "Erro", JOptionPane.ERROR_MESSAGE);
return;
}
showFrameWithContent("Sudoku", new SudokuPanel(board), SudokuSwingApp::showMainMenu);
}
private static void showFrameWithContent(String title, JComponent content, Runnable onClose) {
int previousState = currentFrame != null ? currentFrame.getExtendedState() : JFrame.NORMAL;
boolean wasFullScreen = isFullScreen;
if (currentFrame != null) currentFrame.dispose();
JFrame frame = new JFrame(title);
currentFrame = frame;
frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
frame.dispose();
if (onClose != null) onClose.run();
}
});
applyAppIcon(frame);
frame.setLayout(new BorderLayout());
frame.getContentPane().setBackground(SudokuStyle.COLOR_PRIMARY);
frame.setContentPane(content);
bindClickSoundToButtons(frame.getContentPane());
if (wasFullScreen) {
applyFullscreenIfActive(frame);
} else {
frame.setUndecorated(false);
frame.setExtendedState(previousState);
if (previousState == JFrame.NORMAL) {
frame.setSize(new Dimension(940, 660));
frame.setLocationRelativeTo(null);
}
}
frame.setVisible(true);
setupWindowShortcuts(frame);
frame.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
if (frame.getExtendedState() == JFrame.NORMAL) {
Dimension size = frame.getSize();
if (size.width < 940 || size.height < 660) {
frame.setSize(940, 660);
frame.setLocationRelativeTo(null);
}
}
}
});
}
public static void showInstructions() {
showFrameWithContent("Sudoku", new SudokuInstructions(), () -> reopenMainMenu(currentFrame));
}
public static void showSettings() {
showFrameWithContent("Sudoku", new SudokuSettings(), () -> reopenMainMenu(currentFrame));
}
public static void showAbout() {
showFrameWithContent("Sudoku", new SudokuAbout(), () -> reopenMainMenu(currentFrame));
}
public static void reopenMainMenu(JFrame closingFrame) {
saveWindowState(closingFrame);
closingFrame.dispose();
showMainMenu();
}
public static void applyAppIcon(JFrame frame) {
URL iconUrl = SudokuSwingApp.class.getResource("/images/icons/sudoku_icon.png");
if (iconUrl != null) {
Image image = new ImageIcon(iconUrl).getImage().getScaledInstance(32, 32, Image.SCALE_SMOOTH);
frame.setIconImage(image);
}
}
private static void setupWindowShortcuts(JFrame frame) {
if (shortcutsRegistered) return;
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(e -> {
if (e.getID() == KeyEvent.KEY_PRESSED && currentFrame != null) {
if (e.isAltDown() && e.getKeyCode() == KeyEvent.VK_ENTER) {
toggleFullscreen(currentFrame);
return true;
}
if (e.getKeyCode() == KeyEvent.VK_ESCAPE && isFullScreen) {
exitFullscreen(currentFrame);
return true;
}
if (e.isControlDown()) {
if (e.getKeyCode() == KeyEvent.VK_1) {
applyWindowedMode(currentFrame);
return true;
}
if (e.getKeyCode() == KeyEvent.VK_2) {
applyMaximizedMode(currentFrame);
return true;
}
}
}
return false;
});
shortcutsRegistered = true;
}
private static void applyWindowedMode(JFrame frame) {
if (isFullScreen) {
gd.setFullScreenWindow(null);
isFullScreen = false;
}
frame.dispose();
frame.setUndecorated(false);
lastExtendedState = JFrame.NORMAL;
applyPreviousWindowState(frame);
frame.setVisible(true);
}
private static void applyMaximizedMode(JFrame frame) {
if (isFullScreen) {
gd.setFullScreenWindow(null);
isFullScreen = false;
}
frame.dispose();
frame.setUndecorated(false);
lastExtendedState = JFrame.MAXIMIZED_BOTH;
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible(true);
}
private static void toggleFullscreen(JFrame frame) {
if (!isFullScreen && gd.isFullScreenSupported()) {
saveWindowState(frame);
frame.dispose();
frame.setUndecorated(true);
gd.setFullScreenWindow(frame);
frame.setVisible(true);
isFullScreen = true;
} else {
exitFullscreen(frame);
}
}
private static void exitFullscreen(JFrame frame) {
gd.setFullScreenWindow(null);
isFullScreen = false;
frame.dispose();
frame.setUndecorated(false);
frame.setSize(new Dimension(940, 660));
frame.setLocationRelativeTo(null);
frame.setExtendedState(JFrame.NORMAL);
frame.setVisible(true);
}
private static void applyFullscreenIfActive(JFrame frame) {
if (isFullScreen && gd.isFullScreenSupported()) {
frame.dispose();
frame.setUndecorated(true);
gd.setFullScreenWindow(frame);
frame.setVisible(true);
}
}
private static void saveWindowState(JFrame frame) {
if (!isFullScreen) {
windowBounds = frame.getBounds();
lastExtendedState = frame.getExtendedState();
}
}
private static void applyPreviousWindowState(JFrame frame) {
if (!isFullScreen && windowBounds != null) {
frame.setBounds(windowBounds);
frame.setExtendedState(lastExtendedState);
} else {
frame.setSize(new Dimension(940, 660));
frame.setLocationRelativeTo(null);
frame.setExtendedState(JFrame.NORMAL);
}
}
}