219 lines
6.6 KiB
Java
219 lines
6.6 KiB
Java
package app;
|
|
|
|
// Java imports
|
|
import java.awt.*;
|
|
import java.awt.image.*;
|
|
import java.io.*;
|
|
import javax.swing.*;
|
|
import javax.swing.filechooser.*;
|
|
|
|
// Project imports
|
|
import util.*;
|
|
|
|
// Main application window
|
|
class Window extends JFrame {
|
|
|
|
// Instance fields
|
|
private App app; // Containing application
|
|
private int number; // Window number within application
|
|
private boolean only; // This is the only application window
|
|
private File romFile; // Currently loaded ROM file
|
|
|
|
// UI components
|
|
private File pwd; // Most recent working directory
|
|
private JPanel video; // Video output
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Constants //
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Application icon
|
|
private static final BufferedImage APPICON;
|
|
|
|
// Static initializer
|
|
static {
|
|
APPICON = Util.imageRead("images/app_icon.png");
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Constructors //
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Default constructor
|
|
Window(App app) {
|
|
super();
|
|
|
|
// Configure instance fields
|
|
this.app = app;
|
|
|
|
// Configure video pane
|
|
video = new JPanel() {
|
|
public void paintComponent(Graphics g) {
|
|
super.paintComponent(g);
|
|
onPaintVideo((Graphics2D) g, getWidth(), getHeight());
|
|
}
|
|
};
|
|
video.setPreferredSize(new Dimension(384, 224));
|
|
|
|
// Configure window
|
|
addWindowListener(Util.onClose(e->onClose()));
|
|
setContentPane(video);
|
|
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
|
|
setIconImage(APPICON);
|
|
setJMenuBar(initMenus());
|
|
app.getLocalizer().add(this, "app.title.default");
|
|
|
|
// Display window
|
|
pack();
|
|
setLocationRelativeTo(null);
|
|
setVisible(true);
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Menu Constructors //
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Produce the window's menu bar
|
|
private JMenuBar initMenus() {
|
|
var bar = new JMenuBar();
|
|
var loc = app.getLocalizer();
|
|
bar.setBorder(null);
|
|
bar.add(initMenuFile(loc));
|
|
return bar;
|
|
}
|
|
|
|
// Initialize the File menu
|
|
private JMenu initMenuFile(Localizer loc) {
|
|
var mnuFile = new JMenu();
|
|
loc.add(mnuFile, "app.file.(menu)");
|
|
|
|
var mnuFileLoadRom = new JMenuItem();
|
|
loc.add(mnuFileLoadRom, "app.file.load_rom");
|
|
mnuFileLoadRom.addActionListener(e->onLoadROM());
|
|
mnuFile.add(mnuFileLoadRom);
|
|
|
|
mnuFile.addSeparator();
|
|
|
|
var mnuFileNewWindow = new JMenuItem();
|
|
loc.add(mnuFileNewWindow, "app.file.new_window");
|
|
mnuFileNewWindow.addActionListener(e->onNewWindow());
|
|
mnuFile.add(mnuFileNewWindow);
|
|
|
|
var mnuFileExit = new JMenuItem();
|
|
loc.add(mnuFileExit, "app.file.exit");
|
|
mnuFileExit.addActionListener(e->onClose());
|
|
mnuFile.add(mnuFileExit);
|
|
|
|
return mnuFile;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Package Methods //
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// A window has been added to or removed from the program state
|
|
void windowsChanged(int number, boolean only) {
|
|
this.number = number;
|
|
this.only = only;
|
|
app.getLocalizer().put(this, "ctrl.number", "" + number);
|
|
updateTitle();
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Event Handlers //
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Window close, File -> Exit
|
|
private void onClose() {
|
|
app.removeWindow(this);
|
|
dispose();
|
|
}
|
|
|
|
// File -> Load ROM
|
|
private void onLoadROM() {
|
|
var loc = app.getLocalizer();
|
|
|
|
// Prompt the user to select a file
|
|
var dlgFile = new JFileChooser(pwd);
|
|
dlgFile.addChoosableFileFilter(new FileNameExtensionFilter(
|
|
"Virtual Boy ROMs (*.vb)", "vb"));
|
|
dlgFile.addChoosableFileFilter(new FileNameExtensionFilter(
|
|
"ISX modules (*.isx)", "isx"));
|
|
dlgFile.setAcceptAllFileFilterUsed(true);
|
|
dlgFile.setDialogTitle(loc.get("dialog.load_rom"));
|
|
int option = dlgFile.showDialog(this, loc.get("dialog.load"));
|
|
|
|
// The user did not select a file
|
|
var file = dlgFile.getSelectedFile();
|
|
if (option != JFileChooser.APPROVE_OPTION || file == null)
|
|
return;
|
|
|
|
// Update the current directory
|
|
pwd = file.getParentFile();
|
|
|
|
// Attempt to load the ROM file
|
|
var data = Util.fileRead(file);
|
|
if (data == null) {
|
|
JOptionPane.showMessageDialog(this,
|
|
loc.get("dialog.load_rom_error"),
|
|
loc.get("dialog.load_rom"),
|
|
JOptionPane.ERROR_MESSAGE
|
|
);
|
|
return;
|
|
}
|
|
|
|
// Update the emulation state
|
|
romFile = file;
|
|
loc.put(this, "ctrl.filename", file.getName());
|
|
updateTitle();
|
|
}
|
|
|
|
// File -> New window
|
|
private void onNewWindow() {
|
|
app.addWindow();
|
|
}
|
|
|
|
// Video paint
|
|
private void onPaintVideo(Graphics2D g, int width, int height) {
|
|
int scale = Math.max(1, Math.min(width / 384, height / 224));
|
|
|
|
g.translate(
|
|
Math.max(0, (width - scale * 384) / 2),
|
|
Math.max(0, (height - scale * 224) / 2)
|
|
);
|
|
g.scale(scale, scale);
|
|
|
|
g.setColor(Color.black);
|
|
g.fillRect(0, 0, 384, 224);
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Private Methods //
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Update the window title
|
|
private void updateTitle() {
|
|
app.getLocalizer().add(this,
|
|
only ? romFile != null ?
|
|
"app.title.rom" :
|
|
"app.title.default"
|
|
: romFile != null ?
|
|
"app.title.mixed" :
|
|
"app.title.number"
|
|
);
|
|
}
|
|
|
|
}
|