From 6284fa35c0bd58c6d7a38c6bcb1e802ec17f1781 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Magalh=C3=A3es?= <joamag@gmail.com> Date: Sat, 5 Nov 2022 11:11:07 +0000 Subject: [PATCH] feat: logic frequency control using ui --- CHANGELOG.md | 2 +- examples/web/index.ts | 12 ++++++++--- examples/web/react/app.tsx | 21 ++++++++++++++----- .../button-increment/button-increment.tsx | 19 +++++++++++------ 4 files changed, 39 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c3e07b9..52fd01b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -* +* Logic frequency control using on click UI and keyboard ### Changed diff --git a/examples/web/index.ts b/examples/web/index.ts index c055b7b6..c9222e5f 100644 --- a/examples/web/index.ts +++ b/examples/web/index.ts @@ -21,7 +21,7 @@ const LOGIC_HZ = 4194304; const VISUAL_HZ = 59.7275; const IDLE_HZ = 10; -const FREQUENCY_DELTA = 350000; +const FREQUENCY_DELTA = 400000; const SAMPLE_RATE = 2; @@ -344,11 +344,11 @@ class GameboyEmulator extends EmulatorBase implements Emulator { switch (event.key) { case "+": - this.logicFrequency += FREQUENCY_DELTA; + this.frequency += FREQUENCY_DELTA; break; case "-": - this.logicFrequency -= FREQUENCY_DELTA; + this.frequency -= FREQUENCY_DELTA; break; } }); @@ -430,6 +430,12 @@ class GameboyEmulator extends EmulatorBase implements Emulator { return this.logicFrequency; } + set frequency(value: number) { + value = Math.max(value, 0); + this.logicFrequency = value; + this.trigger("frequency", value); + } + get framerate(): number { return this.fps; } diff --git a/examples/web/react/app.tsx b/examples/web/react/app.tsx index 57d3508f..b3c190b0 100644 --- a/examples/web/react/app.tsx +++ b/examples/web/react/app.tsx @@ -28,7 +28,7 @@ import { import "./app.css"; -export type Callback<T> = (owner: T, params?: Record<string, any>) => void; +export type Callback<T> = (owner: T, params?: any) => void; /** * Abstract class that implements the basic functionality @@ -54,7 +54,7 @@ export class Observable { this.events[event] = callbacks; } - trigger(event: string, params?: Record<string, any>) { + trigger(event: string, params?: any) { const callbacks = this.events[event] ?? []; callbacks.forEach((c) => c(this, params)); } @@ -123,7 +123,7 @@ export interface Emulator extends ObservableI { * The name of the current execution engine being used * by the emulator. */ - get engine(): string; + get engine(): string | null; /** * The pixel format of the emulator's display @@ -152,6 +152,7 @@ export interface Emulator extends ObservableI { * should impact other elements of the emulator. */ get frequency(): number; + set frequency(value: number); /** * The current logic framerate of the running emulator. @@ -410,6 +411,14 @@ export const App: FC<AppProps> = ({ emulator, backgrounds = ["264653"] }) => { `${emulator.device} running in engine "${engine}" from now on!` ); }; + const onFrequencyChange = (value: number) => { + emulator.frequency = value * 1000 * 1000; + }; + const onFrequencyReady = (handler: (value: number) => void) => { + emulator.bind("frequency", (emulator: Emulator, frequency: number) => { + handler(frequency / 1000000); + }); + }; const onMinimize = () => { setFullscreen(!fullscreen); }; @@ -558,11 +567,13 @@ export const App: FC<AppProps> = ({ emulator, backgrounds = ["264653"] }) => { name={"CPU Frequency"} valueNode={ <ButtonIncrement - value={4.19} - delta={0.1} + value={emulator.frequency / 1000 / 1000} + delta={0.4} min={0} suffix={"MHz"} decimalPlaces={2} + onChange={onFrequencyChange} + onReady={onFrequencyReady} /> } /> diff --git a/examples/web/react/components/button-increment/button-increment.tsx b/examples/web/react/components/button-increment/button-increment.tsx index 62a9071a..f8060938 100644 --- a/examples/web/react/components/button-increment/button-increment.tsx +++ b/examples/web/react/components/button-increment/button-increment.tsx @@ -1,4 +1,4 @@ -import React, { FC, useState } from "react"; +import React, { FC, useEffect, useState } from "react"; import Button from "../button/button"; import "./button-increment.css"; @@ -16,6 +16,7 @@ type ButtonIncrementProps = { onClick?: () => void; onBeforeChange?: (value: number) => boolean; onChange?: (value: number) => void; + onReady?: (setValue: (value: number) => void) => void; }; export const ButtonIncrement: FC<ButtonIncrementProps> = ({ @@ -30,25 +31,31 @@ export const ButtonIncrement: FC<ButtonIncrementProps> = ({ style = ["simple", "border"], onClick, onBeforeChange, - onChange + onChange, + onReady }) => { const [valueState, setValue] = useState(value); const classes = () => ["button-increment", size, ...style].join(" "); + useEffect(() => { + onReady && onReady((value) => setValue(value)); + }, []); const _onMinusClick = () => { - const valueNew = valueState - delta; + let valueNew = valueState - delta; if (onBeforeChange) { if (!onBeforeChange(valueNew)) return; } - if (min !== undefined && valueNew < min) return; + if (min !== undefined) valueNew = Math.max(min, valueNew); + if (valueNew === valueState) return; setValue(valueNew); if (onChange) onChange(valueNew); }; const _onPlusClick = () => { - const valueNew = valueState + delta; + let valueNew = valueState + delta; if (onBeforeChange) { if (!onBeforeChange(valueNew)) return; } - if (max !== undefined && valueNew > max) return; + if (max !== undefined) valueNew = Math.min(max, valueNew); + if (valueNew === valueState) return; setValue(valueNew); if (onChange) onChange(valueNew); }; -- GitLab