Skip to content

Commit

Permalink
Add support for custom screen sizes
Browse files Browse the repository at this point in the history
The current behavior (of picking the nearest screen size that fits into
the window with bezels) is still the default ("auto") mode, but we
now also support the following options:
- "window": As big as the current window, with no bezels
- "fullscreen": As big as the current screen, with no bezels
- custom (width x height): arbitrary sizes, with bezels

Fixes #263
  • Loading branch information
mihaip committed Dec 9, 2023
1 parent 75bb9ed commit 5560875
Show file tree
Hide file tree
Showing 12 changed files with 260 additions and 43 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# CHANGELOG

2023-12-09: Custom instances now support custom screen sizes.

2023-09-09: Added the Saved HD as a way to persist data. Its contents can also be imported and exported.

2023-08-13: Custom instances now support overriding the RAM size of the emulated machine.
Expand Down
7 changes: 6 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,12 @@ function App() {
<RunDefMac runDef={runDef} onDone={handleDone} />
</Suspense>
);
footer = <Footer onLogoClick={handleDone} />;
footer = (
<Footer
onLogoClick={handleDone}
showFullscreenButton={runDef.screenSize === "fullscreen"}
/>
);
} else {
contents = (
<React.StrictMode>
Expand Down
1 change: 1 addition & 0 deletions src/Browser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ function DiskContents({disk, onRun, setBezelStyle}: DiskContentsProps) {
const run = (event: React.MouseEvent) => {
const runDef = {
disks: [disk],
screenSize: "auto",
includeInfiniteHD: true,
includeSavedHD: canSaveDisks(),
machine: disk.machines[0],
Expand Down
11 changes: 11 additions & 0 deletions src/Custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,14 @@
width: 20px;
margin-left: 4px;
}

.Custom-Dialog-ScreenSize {
display: inline-flex;
gap: 4px;
}

.Custom-Dialog-ScreenSize input[type="number"] {
width: 32px;
height: 10px;
font-size: 12px;
}
101 changes: 100 additions & 1 deletion src/Custom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import "./Custom.css";
import {useCallback, useEffect, useState} from "react";
import {Dialog} from "./controls/Dialog";
import * as varz from "./varz";
import {type RunDef} from "./run-def";
import {type ScreenSize, type RunDef} from "./run-def";
import {
ALL_MACHINES,
MACHINES_BY_NAME,
Expand Down Expand Up @@ -47,6 +47,7 @@ export function Custom({
const [runDef, setRunDef] = useState<RunDef>({
machine: defaultDisk.machines[0] ?? QUADRA_650,
ramSize: undefined,
screenSize: "auto",
disks: [defaultDisk],
cdromURLs: [],
includeInfiniteHD: true,
Expand Down Expand Up @@ -162,6 +163,27 @@ export function Custom({
amount of RAM.
</div>
</label>
<label className="Custom-Dialog-Row">
<span className="Custom-Dialog-Label">Screen Size:</span>
{runDef.machine.fixedScreenSize ? (
<>
{runDef.machine.fixedScreenSize.width} x{" "}
{runDef.machine.fixedScreenSize.height}
</>
) : (
<ScreenSizePicker
appearance={appearance}
value={runDef.screenSize}
onChange={screenSize =>
setRunDef({...runDef, screenSize})
}
/>
)}
<div className="Custom-Dialog-Description Dialog-Description">
Not all machines support custom screen sizes, some sizes may
result in crashes.
</div>
</label>

<div className="Custom-Dialog-Row">
{runDef.disks.map((disk, i) => (
Expand Down Expand Up @@ -472,3 +494,80 @@ function CDROMOption({
</label>
);
}

function ScreenSizePicker({
appearance,
value,
onChange,
}: {
appearance: Appearance;
value: ScreenSize;
onChange: (value: ScreenSize) => void;
}) {
const [width, setWidth] = useState(
typeof value === "string" ? 640 : value.width
);
const [height, setHeight] = useState(
typeof value === "string" ? 480 : value.height
);

return (
<div className="Custom-Dialog-ScreenSize">
<Select
appearance={appearance}
value={typeof value === "string" ? value : "custom"}
onChange={e => {
const option = e.target.value;
if (option === "custom") {
onChange({width, height});
} else {
onChange(option as ScreenSize);
}
}}>
{Object.entries({
"auto": "Automatic",
"window": "Window",
"fullscreen": "Full Screen",
"custom": "Custom",
}).map(([value, label]) => (
<option key={value} value={value}>
{label}
</option>
))}
</Select>
{typeof value !== "string" && (
<>
<Input
appearance={appearance}
type="number"
min={2}
max={4096}
step={2}
value={width}
onChange={e => {
const width = parseInt(e.target.value);
setWidth(width);
onChange({width, height});
}}
size={4}
/>{" "}
×{" "}
<Input
appearance={appearance}
type="number"
min={2}
max={4096}
step={2}
value={height}
onChange={e => {
const height = parseInt(e.target.value);
setHeight(height);
onChange({width, height});
}}
size={4}
/>
</>
)}
</div>
);
}
5 changes: 5 additions & 0 deletions src/Footer.css
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@
width: 36px;
}

.Footer .Footer-Fullscreen {
background-image: url(./Images/Footer-Fullscreen.png);
width: 68px;
}

.Footer .Footer-Donate {
background-image: url(./Images/Footer-Donate.png);
width: 44px;
Expand Down
25 changes: 20 additions & 5 deletions src/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,19 @@ import {About} from "./About";
import {Donate} from "./Donate";
import "./Footer.css";

export function Footer({onLogoClick}: {onLogoClick?: () => void}) {
export function Footer({
onLogoClick,
showFullscreenButton,
}: {
onLogoClick?: () => void;
showFullscreenButton?: boolean;
}) {
const [aboutVisible, setAboutVisible] = useState(false);
const [donateVisible, setDonateVisible] = useState(false);
const handleFullScreenClick = () => {
document.body.requestFullscreen?.() ||
document.body.webkitRequestFullscreen?.();
};

return (
<div className="Footer">
Expand All @@ -14,16 +24,21 @@ export function Footer({onLogoClick}: {onLogoClick?: () => void}) {
<span onClick={onLogoClick} className="Footer-Logo">
Infinite Mac
</span>
{showFullscreenButton && (
<span
onClick={handleFullScreenClick}
className="Footer-Fullscreen">
Full Screen
</span>
)}
<span
onClick={() => setAboutVisible(true)}
className="Footer-About"
>
className="Footer-About">
About
</span>
<span
onClick={() => setDonateVisible(true)}
className="Footer-Donate"
>
className="Footer-Donate">
Donate
</span>
</div>
Expand Down
Binary file added src/Images/Footer-Fullscreen.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 5560875

Please sign in to comment.