185 lines
5.3 KiB
JavaScript
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);
|
|
}
|
|
|
|
};
|