mirror of
https://github.com/whscullin/apple2js.git
synced 2024-01-12 14:14:38 +00:00
parent
c648735b8a
commit
9a940935af
@ -606,6 +606,9 @@ button:focus {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
width: 42px;
|
width: 42px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
#reset:hover {
|
#reset:hover {
|
||||||
@ -614,8 +617,11 @@ button:focus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#reset:active {
|
#reset:active {
|
||||||
background: #22150A;
|
background-color: #22150A;
|
||||||
border: 5px outset #44372C;
|
border-left: 3px solid #44372C;
|
||||||
|
border-top: 3px solid #44372C;
|
||||||
|
border-right: 3px solid #000000;
|
||||||
|
border-bottom: 3px solid #000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
#keyboard .key-OPEN_APPLE.active div {
|
#keyboard .key-OPEN_APPLE.active div {
|
||||||
|
@ -49,8 +49,8 @@ export const Apple2 = (props: Apple2Props) => {
|
|||||||
...props,
|
...props,
|
||||||
};
|
};
|
||||||
const apple2 = new Apple2Impl(options);
|
const apple2 = new Apple2Impl(options);
|
||||||
setApple2(apple2);
|
|
||||||
apple2.ready.then(() => {
|
apple2.ready.then(() => {
|
||||||
|
setApple2(apple2);
|
||||||
const io = apple2.getIO();
|
const io = apple2.getIO();
|
||||||
const cpu = apple2.getCPU();
|
const cpu = apple2.getCPU();
|
||||||
setIO(io);
|
setIO(io);
|
||||||
|
51
js/components/AudioControl.tsx
Normal file
51
js/components/AudioControl.tsx
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { h } from 'preact';
|
||||||
|
import { useCallback, useContext, useEffect, useState } from 'preact/hooks';
|
||||||
|
import { ControlButton } from './ControlButton';
|
||||||
|
import { OptionsContext } from './OptionsContext';
|
||||||
|
import { Audio, SOUND_ENABLED_OPTION } from '../ui/audio';
|
||||||
|
import { Apple2 as Apple2Impl } from '../apple2';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AudioControl component properties.
|
||||||
|
*/
|
||||||
|
export interface AudioControlProps {
|
||||||
|
apple2: Apple2Impl | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control that instantiates the Audio object and provides
|
||||||
|
* a control to mute and unmute audio.
|
||||||
|
*
|
||||||
|
* @param apple2 The Apple2 object
|
||||||
|
* @returns AudioControl component
|
||||||
|
*/
|
||||||
|
export const AudioControl = ({ apple2 }: AudioControlProps) => {
|
||||||
|
const [audioEnabled, setAudioEnabled] = useState(false);
|
||||||
|
const [audio, setAudio] = useState<Audio>();
|
||||||
|
const options = useContext(OptionsContext);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (apple2) {
|
||||||
|
const io = apple2.getIO();
|
||||||
|
const audio = new Audio(io);
|
||||||
|
options.addOptions(audio);
|
||||||
|
setAudio(audio);
|
||||||
|
setAudioEnabled(audio.isEnabled());
|
||||||
|
}
|
||||||
|
}, [apple2]);
|
||||||
|
|
||||||
|
const doToggleSound = useCallback(() => {
|
||||||
|
const on = !audio?.isEnabled();
|
||||||
|
options.setOption(SOUND_ENABLED_OPTION, on);
|
||||||
|
setAudioEnabled(on);
|
||||||
|
}, [audio]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ControlButton
|
||||||
|
onClick={doToggleSound}
|
||||||
|
title="Toggle Sound"
|
||||||
|
disabled={!audio}
|
||||||
|
icon={audioEnabled ? 'volume-up' : 'volume-off'}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -6,6 +6,7 @@ import { h, JSX } from 'preact';
|
|||||||
export interface ControlButtonProps {
|
export interface ControlButtonProps {
|
||||||
icon: string;
|
icon: string;
|
||||||
title: string;
|
title: string;
|
||||||
|
disabled?: boolean;
|
||||||
onClick: JSX.MouseEventHandler<HTMLButtonElement>;
|
onClick: JSX.MouseEventHandler<HTMLButtonElement>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17,8 +18,8 @@ export interface ControlButtonProps {
|
|||||||
* @param onClick Click callback
|
* @param onClick Click callback
|
||||||
* @returns Control Button component
|
* @returns Control Button component
|
||||||
*/
|
*/
|
||||||
export const ControlButton = ({ icon, title, onClick }: ControlButtonProps) => (
|
export const ControlButton = ({ icon, title, onClick, ...props }: ControlButtonProps) => (
|
||||||
<button onClick={onClick} title={title}>
|
<button onClick={onClick} title={title} {...props} >
|
||||||
<i class={`fas fa-${icon}`}></i>
|
<i class={`fas fa-${icon}`}></i>
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
@ -3,11 +3,12 @@ import { useCallback, useContext, useEffect, useState } from 'preact/hooks';
|
|||||||
import { CPUMeter } from './CPUMeter';
|
import { CPUMeter } from './CPUMeter';
|
||||||
import { Inset } from './Inset';
|
import { Inset } from './Inset';
|
||||||
import { useHotKey } from './hooks/useHotKey';
|
import { useHotKey } from './hooks/useHotKey';
|
||||||
import { Apple2 as Apple2Impl } from '../apple2';
|
import { AudioControl } from './AudioControl';
|
||||||
import { Audio, SOUND_ENABLED_OPTION } from '../ui/audio';
|
|
||||||
import { OptionsModal} from './OptionsModal';
|
import { OptionsModal} from './OptionsModal';
|
||||||
import { OptionsContext } from './OptionsContext';
|
import { OptionsContext } from './OptionsContext';
|
||||||
|
import { PauseControl } from './PauseControl';
|
||||||
import { ControlButton } from './ControlButton';
|
import { ControlButton } from './ControlButton';
|
||||||
|
import { Apple2 as Apple2Impl } from '../apple2';
|
||||||
import { JoyStick } from '../ui/joystick';
|
import { JoyStick } from '../ui/joystick';
|
||||||
import { Screen, SCREEN_FULL_PAGE } from '../ui/screen';
|
import { Screen, SCREEN_FULL_PAGE } from '../ui/screen';
|
||||||
import { System } from '../ui/system';
|
import { System } from '../ui/system';
|
||||||
@ -29,51 +30,25 @@ interface ControlStripProps {
|
|||||||
* @returns ControlStrip component
|
* @returns ControlStrip component
|
||||||
*/
|
*/
|
||||||
export const ControlStrip = ({ apple2, e }: ControlStripProps) => {
|
export const ControlStrip = ({ apple2, e }: ControlStripProps) => {
|
||||||
const [running, setRunning] = useState(true);
|
|
||||||
const [audio, setAudio] = useState<Audio>();
|
|
||||||
const [audioEnabled, setAudioEnabled] = useState(false);
|
|
||||||
const [showOptions, setShowOptions] = useState(false);
|
const [showOptions, setShowOptions] = useState(false);
|
||||||
const options = useContext(OptionsContext);
|
const options = useContext(OptionsContext);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (apple2) {
|
if (apple2) {
|
||||||
apple2.ready.then(() => {
|
const io = apple2.getIO();
|
||||||
const io = apple2.getIO();
|
const vm = apple2.getVideoModes();
|
||||||
const vm = apple2.getVideoModes();
|
|
||||||
|
|
||||||
const system = new System(io, e);
|
const system = new System(io, e);
|
||||||
options.addOptions(system);
|
options.addOptions(system);
|
||||||
|
|
||||||
const joystick = new JoyStick(io);
|
const joystick = new JoyStick(io);
|
||||||
options.addOptions(joystick);
|
options.addOptions(joystick);
|
||||||
|
|
||||||
const screen = new Screen(vm);
|
const screen = new Screen(vm);
|
||||||
options.addOptions(screen);
|
options.addOptions(screen);
|
||||||
|
|
||||||
const audio = new Audio(io);
|
|
||||||
options.addOptions(audio);
|
|
||||||
setAudio(audio);
|
|
||||||
setAudioEnabled(audio.isEnabled());
|
|
||||||
}).catch(console.error);
|
|
||||||
}
|
}
|
||||||
}, [apple2]);
|
}, [apple2]);
|
||||||
|
|
||||||
const doPause = useCallback(() => {
|
|
||||||
apple2?.stop();
|
|
||||||
setRunning(false);
|
|
||||||
}, [apple2]);
|
|
||||||
|
|
||||||
const doRun = useCallback(() => {
|
|
||||||
apple2?.run();
|
|
||||||
setRunning(true);
|
|
||||||
}, [apple2]);
|
|
||||||
|
|
||||||
const doToggleSound = useCallback(() => {
|
|
||||||
const on = !audio?.isEnabled();
|
|
||||||
options.setOption(SOUND_ENABLED_OPTION, on);
|
|
||||||
setAudioEnabled(on);
|
|
||||||
}, [audio]);
|
|
||||||
|
|
||||||
const doReset = useCallback(() =>
|
const doReset = useCallback(() =>
|
||||||
apple2?.reset()
|
apple2?.reset()
|
||||||
, [apple2]);
|
, [apple2]);
|
||||||
@ -106,32 +81,16 @@ export const ControlStrip = ({ apple2, e }: ControlStripProps) => {
|
|||||||
<OptionsModal isOpen={showOptions} onClose={doCloseOptions} />
|
<OptionsModal isOpen={showOptions} onClose={doCloseOptions} />
|
||||||
<Inset>
|
<Inset>
|
||||||
<CPUMeter apple2={apple2} />
|
<CPUMeter apple2={apple2} />
|
||||||
{running ? (
|
<PauseControl apple2={apple2} />
|
||||||
<ControlButton
|
<AudioControl apple2={apple2} />
|
||||||
onClick={doPause}
|
|
||||||
title="Pause"
|
|
||||||
icon="pause"
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<ControlButton
|
|
||||||
onClick={doRun}
|
|
||||||
title="Run"
|
|
||||||
icon="play"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<ControlButton
|
|
||||||
onClick={doToggleSound}
|
|
||||||
title="Toggle Sound"
|
|
||||||
icon={audioEnabled ? 'volume-up' : 'volume-off'}
|
|
||||||
/>
|
|
||||||
<div style={{flexGrow: 1}} />
|
<div style={{flexGrow: 1}} />
|
||||||
<ControlButton onClick={doReadme} title="About" icon="info" />
|
<ControlButton onClick={doReadme} title="About" icon="info" />
|
||||||
<ControlButton onClick={doShowOptions} title="Options (F4)" icon="cog" />
|
<ControlButton onClick={doShowOptions} title="Options (F4)" icon="cog" />
|
||||||
</Inset>
|
</Inset>
|
||||||
{e && (
|
{e && (
|
||||||
<button id="reset" onClick={doReset}>
|
<div id="reset" onClick={doReset}>
|
||||||
Reset
|
Reset
|
||||||
</button>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
51
js/components/PauseControl.tsx
Normal file
51
js/components/PauseControl.tsx
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { h, Fragment } from 'preact';
|
||||||
|
import { useCallback, useState } from 'preact/hooks';
|
||||||
|
import { Apple2 as Apple2Impl } from 'js/apple2';
|
||||||
|
import { ControlButton } from './ControlButton';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PauseControl component properties.
|
||||||
|
*/
|
||||||
|
export interface PauseControlProps {
|
||||||
|
apple2: Apple2Impl | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a control to pause and unpause the CPU.
|
||||||
|
*
|
||||||
|
* @param apple2 The Apple2 object
|
||||||
|
* @returns PauseControl component
|
||||||
|
*/
|
||||||
|
export const PauseControl = ({ apple2 }: PauseControlProps) => {
|
||||||
|
const [running, setRunning] = useState(true);
|
||||||
|
|
||||||
|
const doPause = useCallback(() => {
|
||||||
|
apple2?.stop();
|
||||||
|
setRunning(false);
|
||||||
|
}, [apple2]);
|
||||||
|
|
||||||
|
const doRun = useCallback(() => {
|
||||||
|
apple2?.run();
|
||||||
|
setRunning(true);
|
||||||
|
}, [apple2]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{running ? (
|
||||||
|
<ControlButton
|
||||||
|
onClick={doPause}
|
||||||
|
disabled={!apple2}
|
||||||
|
title="Pause"
|
||||||
|
icon="pause"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<ControlButton
|
||||||
|
onClick={doRun}
|
||||||
|
disabled={!apple2}
|
||||||
|
title="Run"
|
||||||
|
icon="play"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user