From 8cf334bd444cd1135b76387870c332f92cd02aee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Magalh=C3=A3es?= <joamag@gmail.com>
Date: Sat, 29 Oct 2022 02:17:04 +0100
Subject: [PATCH] refactor: more ROM information display

---
 examples/web/index.ts                         | 69 ++++++++++---------
 examples/web/react/app.tsx                    | 57 +++++++++++++--
 .../web/react/components/display/display.css  |  2 +-
 3 files changed, 89 insertions(+), 39 deletions(-)

diff --git a/examples/web/index.ts b/examples/web/index.ts
index f7951ea9..94712ccb 100644
--- a/examples/web/index.ts
+++ b/examples/web/index.ts
@@ -1,6 +1,18 @@
-import { Emulator, Observable, PixelFormat, startApp } from "./react/app";
-
-import { default as _wasm, GameBoy, PadKey, PpuMode } from "./lib/boytacean.js";
+import {
+    Emulator,
+    Observable,
+    PixelFormat,
+    RomInfo,
+    startApp
+} from "./react/app";
+
+import {
+    Cartridge,
+    default as _wasm,
+    GameBoy,
+    PadKey,
+    PpuMode
+} from "./lib/boytacean.js";
 import info from "./package.json";
 
 declare const require: any;
@@ -82,6 +94,7 @@ class GameboyEmulator extends Observable implements Emulator {
     private romName: string | null = null;
     private romData: Uint8Array | null = null;
     private romSize: number = 0;
+    private cartridge: Cartridge | null = null;
 
     async main() {
         // initializes the WASM module, this is required
@@ -90,7 +103,6 @@ class GameboyEmulator extends Observable implements Emulator {
 
         // initializes the complete set of sub-systems
         // and registers the event handlers
-        await this.buildVisuals();
         await this.init();
         await this.register();
 
@@ -309,7 +321,7 @@ class GameboyEmulator extends Observable implements Emulator {
         // updates the complete set of global information that
         // is going to be displayed
         this.setEngine(this.engine!);
-        this.setRom(romName!, romData!);
+        this.setRom(romName!, romData!, cartridge);
         this.setLogicFrequency(this.logicFrequency);
         this.setFps(this.fps);
 
@@ -318,26 +330,6 @@ class GameboyEmulator extends Observable implements Emulator {
         if (restore) this.resume();
     }
 
-    async buildVisuals() {
-        /*     KeyValue.create("ROM", "-", { id: "diag:rom-name" }).mount(".diag");
-        KeyValue.create("ROM Size", "-", { id: "diag:rom-size" }).mount(
-            ".diag"
-        );
-        KeyValue.create("Framerate", "-", { id: "diag:framerate" }).mount(
-            ".diag"
-        );
-        KeyValue.create("ROM Type", "-", { id: "diag:rom-type" }).mount(
-            ".diag"
-        );
-        KeySwitch.create("Tobias", ["1", "2", "3"], {
-            id: "diag:tobias"
-        }).mount(".diag");
-
-        Button.create("Tobias", require("./res/close.svg"))
-            .bind("click", () => alert("Hello World"))
-            .mount(".button-area");*/
-    }
-
     // @todo remove this method, or at least most of it
     async register() {
         await Promise.all([
@@ -916,13 +908,13 @@ class GameboyEmulator extends Observable implements Emulator {
         document.getElementById("engine")!.textContent = name;
     }
 
-    setRom(name: string, data: Uint8Array) {
+    setRom(name: string, data: Uint8Array, cartridge: Cartridge) {
         this.romName = name;
         this.romData = data;
         this.romSize = data.length;
-        //@todo update this one
-        //Component.get<KeyValue>("diag:rom-name").value = name;
-        //Component.get<KeyValue>("diag:rom-size").value = `${data.length} bytes`;
+        this.cartridge = cartridge;
+
+        this.trigger("rom:loaded");
     }
 
     setLogicFrequency(value: number) {
@@ -936,8 +928,6 @@ class GameboyEmulator extends Observable implements Emulator {
         if (value < 0) this.showToast("Invalid FPS value!", true);
         value = Math.max(value, 0);
         this.fps = value;
-        //@todo
-        //Component.get<KeyValue>("diag:framerate").value = `${value} FPS`;
     }
 
     getName() {
@@ -966,6 +956,23 @@ class GameboyEmulator extends Observable implements Emulator {
         return this.gameBoy!.frame_buffer_eager();
     }
 
+    getRomInfo(): RomInfo {
+        return {
+            name: this.romName || undefined,
+            data: this.romData || undefined,
+            size: this.romData?.length,
+            extra: {
+                romType: this.cartridge?.rom_type_s(),
+                romSize: this.cartridge?.rom_size_s(),
+                ramSize: this.cartridge?.ram_size_s()
+            }
+        };
+    }
+
+    getFramerate(): number {
+        return this.fps;
+    }
+
     toggleRunning() {
         if (this.paused) {
             this.resume();
diff --git a/examples/web/react/app.tsx b/examples/web/react/app.tsx
index dd4e852c..5b171ac9 100644
--- a/examples/web/react/app.tsx
+++ b/examples/web/react/app.tsx
@@ -46,17 +46,31 @@ export class Observable {
     }
 }
 
+export type RomInfo = {
+    name?: string;
+    data?: Uint8Array;
+    size?: number;
+    extra?: Record<string, string | undefined>;
+};
+
+export interface ObservableI {
+    bind(event: string, callback: Callback<this>): void;
+    trigger(event: string): void;
+}
+
 /**
  * Top level interface that declares the main abstract
  * interface of an emulator structured entity.
  * Should allow typical hardware operations to be performed.
  */
-export interface Emulator extends Observable {
+export interface Emulator extends ObservableI {
     getName(): string;
     getVersion(): string;
     getVersionUrl(): string;
     getPixelFormat(): PixelFormat;
     getImageBuffer(): Uint8Array;
+    getRomInfo(): RomInfo;
+    getFramerate(): number;
     toggleRunning(): void;
     pause(): void;
     resume(): void;
@@ -81,7 +95,9 @@ export const App: FC<AppProps> = ({ emulator, backgrounds = ["264653"] }) => {
     const [paused, setPaused] = useState(false);
     const [fullscreen, setFullscreen] = useState(false);
     const [backgroundIndex, setBackgroundIndex] = useState(0);
-    const intervalRef = useRef<number | undefined>(undefined);
+    const [romInfo, setRomInfo] = useState<RomInfo>({});
+    const [framerate, setFramerate] = useState(0);
+    const frameRef = useRef<boolean>(false);
     const getPauseText = () => (paused ? "Resume" : "Pause");
     const getPauseIcon = () =>
         paused ? require("../res/play.svg") : require("../res/pause.svg");
@@ -103,10 +119,11 @@ export const App: FC<AppProps> = ({ emulator, backgrounds = ["264653"] }) => {
         setFullscreen(!fullscreen);
     };
     const onDrawHandler = (handler: DrawHandler) => {
-        if (intervalRef.current) return;
-        intervalRef.current = 1;
+        if (frameRef.current) return;
+        frameRef.current = true;
         emulator.bind("frame", () => {
             handler(emulator.getImageBuffer(), PixelFormat.RGB);
+            setFramerate(emulator.getFramerate());
         });
     };
     useEffect(() => {
@@ -118,6 +135,10 @@ export const App: FC<AppProps> = ({ emulator, backgrounds = ["264653"] }) => {
                 setFullscreen(false);
             }
         });
+        emulator.bind("rom:loaded", () => {
+            const romInfo = emulator.getRomInfo();
+            setRomInfo(romInfo);
+        });
     }, []);
     return (
         <div className="app">
@@ -129,7 +150,7 @@ export const App: FC<AppProps> = ({ emulator, backgrounds = ["264653"] }) => {
             </Footer>
             <PanelSplit
                 left={
-                    <div style={{marginTop: 78}}>
+                    <div style={{ marginTop: 78 }}>
                         <Display
                             fullscreen={fullscreen}
                             onDrawHandler={onDrawHandler}
@@ -206,8 +227,30 @@ export const App: FC<AppProps> = ({ emulator, backgrounds = ["264653"] }) => {
                         />
                     </ButtonContainer>
                     <Info>
-                        <Pair key="tobias" name={"Tobias"} value={"Matias"} />
-                        <Pair key="matias" name={"Matias"} value={"3"} />
+                        <Pair
+                            key="rom"
+                            name={"ROM"}
+                            value={romInfo.name ?? "-"}
+                        />
+                        <Pair
+                            key="rom-size"
+                            name={"ROM Size"}
+                            value={romInfo.name ? `${romInfo.size} bytes` : "-"}
+                        />
+                        <Pair
+                            key="rom-type"
+                            name={"ROM Type"}
+                            value={
+                                romInfo.extra?.romType
+                                    ? `${romInfo.extra?.romType}`
+                                    : "-"
+                            }
+                        />
+                        <Pair
+                            key="framerate"
+                            name={"Framerate"}
+                            value={`${framerate} fps`}
+                        />
                         <Pair
                             key="button-tobias"
                             name={"Button Increment"}
diff --git a/examples/web/react/components/display/display.css b/examples/web/react/components/display/display.css
index 8965c18d..7ad04880 100644
--- a/examples/web/react/components/display/display.css
+++ b/examples/web/react/components/display/display.css
@@ -43,7 +43,7 @@
     font-size: 0px;
     padding: 8px 8px 8px 8px;
     box-sizing: content-box;
-    transition: width 0.35s cubic-bezier(0.075, 0.82, 0.165, 1), height 0.35s cubic-bezier(0.075, 0.82, 0.165, 1), top 0.35s cubic-bezier(0.075, 0.82, 0.165, 1), left 0.35s cubic-bezier(0.075, 0.82, 0.165, 1);
+    transition: width 0.35s cubic-bezier(0.075, 0.82, 0.165, 1), height 0.35s cubic-bezier(0.075, 0.82, 0.165, 1);
 }
 
 .display.fullscreen > .display-frame {
-- 
GitLab