pvbemu/app/App.js

185 lines
5.3 KiB
JavaScript

"use strict";
// Top-level state and UI manager
globalThis.App = class App {
// Produce a new class instance
static async create() {
let ret = new App();
await ret.init();
return ret;
}
// Perform initial tasks
async init() {
// Initialization tasks
this.initEnv();
this.initMenus();
// WebAssembly core module
this.core = new Worker(Bundle.get("app/Emulator.js").toDataURL());
await new Promise((resolve,reject)=>{
this.core.onmessage = e=>{
this.core.onmessage = e=>this.onmessage(e.data);
resolve();
};
this.core.postMessage({
command: "Init",
wasm : Bundle.get("core.wasm").data.buffer
});
});
// Desktop pane
this.desktop = this.gui.newPanel({ layout: "desktop" });
this.desktop.setRole("group");
this.desktop.element.setAttribute("desktop", "");
this.gui.add(this.desktop);
// Debugging windows
this.debuggers = [
new Debugger(this, 0),
new Debugger(this, 1)
];
}
// Initialize environment settings
initEnv() {
// Configure themes
Bundle.get("app/theme/kiosk.css").style();
this.themes = {
dark : Bundle.get("app/theme/dark.css" ).style(false),
light : Bundle.get("app/theme/light.css" ).style(true ),
virtual: Bundle.get("app/theme/virtual.css").style(false)
};
this.theme = this.themes["light"];
// Produce toolkit instance
this.gui = new Toolkit.Application({
layout: "grid",
rows : "max-content auto"
});
document.body.appendChild(this.gui.element);
window.addEventListener("resize", ()=>{
this.gui.setSize(window.innerWidth+"px", window.innerHeight+"px");
});
window.dispatchEvent(new Event("resize"));
// Configure locales
this.gui.addLocale(Bundle.get("app/locale/en-US.js").toString());
this.gui.setLocale(navigator.language);
}
// Initialize main menu bar
initMenus() {
// Menu bar
this.mainMenu = this.gui.newMenuBar({ name: "{menu._}" });
this.gui.add(this.mainMenu);
this.gui.addPropagationListener(e=>this.mainMenu.restoreFocus());
// File menu
let menu = this.mainMenu.newMenu({ text: "{menu.file._}"});
let item = menu.newMenuItem({ text: "{menu.file.loadROM}"});
item.addClickListener(()=>this.loadROM());
// Debug menu
menu = this.mainMenu.newMenu({ text: "{menu.debug._}" });
item = menu.newMenuItem({ text: "{memory._}" });
item.addClickListener(
()=>this.debuggers[0].memory.setVisible(true, true));
item = menu.newMenuItem({ text: "{cpu._}" });
item.addClickListener(
()=>this.debuggers[0].cpu.setVisible(true, true));
// Theme menu
menu = this.mainMenu.newMenu({ text: "{menu.theme._}" });
item = menu.newMenuItem({ text: "{menu.theme.light}" });
item.addClickListener(()=>this.setTheme("light"));
item = menu.newMenuItem({ text: "{menu.theme.dark}" });
item.addClickListener(()=>this.setTheme("dark"));
item = menu.newMenuItem({ text: "{menu.theme.virtual}" });
item.addClickListener(()=>this.setTheme("virtual"));
}
///////////////////////////// Message Methods /////////////////////////////
// Message received
onmessage(msg) {
if ("debug" in msg) {
this.debuggers[msg.sim].message(msg);
return;
}
switch (msg.command) {
case "SetROM": this.setROM(msg); break;
}
}
// ROM buffer has been configured
setROM(msg) {
let dbg = this.debuggers[msg.sim];
dbg.memory.setVisible(true, true);
dbg.refresh();
}
///////////////////////////// Private Methods /////////////////////////////
// Prompt the user to select a ROM file
loadROM() {
let file = document.createElement("input");
file.type = "file";
file.addEventListener("input", ()=>this.selectROM(file.files[0]));
file.click();
}
// Specify a ROM file
async selectROM(file) {
// No file is specified (perhaps the user canceled)
if (file == null)
return;
// Check the file's size
if (
file.size < 1024 ||
file.size > 0x1000000 ||
(file.size - 1 & file.size) != 0
) {
alert(this.gui.translate("{app.romNotVB}"));
return;
}
// Load the file data into a byte buffer
let filename = file.name;
try { file = await file.arrayBuffer(); }
catch {
alert(this.gui.translate("{app.readFileError}"));
return;
}
// Send the ROM to the WebAssembly core module
this.core.postMessage({
command: "SetROM",
rom : file,
sim : 0
}, file);
}
// Specify the current color theme
setTheme(key) {
let theme = this.themes[key];
if (theme == this.theme)
return;
let old = this.theme;
this.theme = theme;
theme.setEnabled(true);
old.setEnabled(false);
}
};