import { preload } from "react-dom"; import imgSmallClosedOff from "./small_closed_off.png"; import imgSmallClosedOn from "./small_closed_on.png"; import imgSmallOpenedOff from "./small_opened_off.png"; import imgSmallOpenedOn from "./small_opened_off.png"; import fontDigital from "../DigitalWatch/digital-font.ttf"; import sndBell from "./bell.wav"; import sndRunning from "./running.wav"; import { Plant } from "../Plant"; import { RaisedEvent } from "@/statecharts/runtime_types"; import { useEffect, useState } from "react"; import "./Microwave.css"; export type MagnetronState = "on" | "off"; export type DoorState = "open" | "closed"; export function toggleDoor(d: DoorState) { if (d === "open") { return "closed"; } else return "open"; } export function toggleMagnetron(m: MagnetronState) { if (m === "on") { return "off"; } return "on"; } export type MicrowaveState = { // Note: the door state is not part of the MicrowaveState because it is not controlled by the statechart, but by the plant. timeDisplay: number, bell: boolean, // whether the bell should ring magnetron: MagnetronState, } export type MicrowaveProps = { state: MicrowaveState, callbacks: { startPressed: () => void; stopPressed: () => void; incTimePressed: () => void; incTimeReleased: () => void; doorOpened: () => void; doorClosed: () => void; } } const imgs = { closed: { off: imgSmallClosedOff, on: imgSmallClosedOn }, open: { off: imgSmallOpenedOff, on: imgSmallOpenedOn }, } const BUTTON_HEIGHT = 18; const BUTTON_WIDTH = 60; const BUTTON_X0 = 412; const BUTTON_X1 = BUTTON_X0 + BUTTON_WIDTH; const START_X0 = BUTTON_X0; const START_Y0 = 234; const START_X1 = BUTTON_X1; const START_Y1 = START_Y0 + BUTTON_HEIGHT; const STOP_X0 = BUTTON_X0; const STOP_Y0 = 211; const STOP_X1 = BUTTON_X1; const STOP_Y1 = STOP_Y0 + BUTTON_HEIGHT; const INCTIME_X0 = BUTTON_X0; const INCTIME_Y0 = 188; const INCTIME_X1 = BUTTON_X1; const INCTIME_Y1 = INCTIME_Y0 + BUTTON_HEIGHT; const DOOR_X0 = 26; const DOOR_Y0 = 68; const DOOR_WIDTH = 353; const DOOR_HEIGHT = 217; export function Magnetron({state: {timeDisplay, bell, magnetron}, callbacks}: MicrowaveProps) { const [door, setDoor] = useState("closed"); const [playBell, setPlayBell] = useState(false); // a bit hacky: when the bell-state changes to true, we play the bell sound for 610 ms... useEffect(() => { let timeout: NodeJS.Timeout; if (bell) { setPlayBell(true); timeout = setTimeout(() => { setPlayBell(false); }, 610); } return () => { if (timeout) clearTimeout(timeout); }; }, [bell]); preload(imgSmallClosedOff, {as: "image"}); preload(imgSmallClosedOn, {as: "image"}); preload(imgSmallOpenedOff, {as: "image"}); preload(imgSmallOpenedOn, {as: "image"}); preload(sndBell, {as: "audio"}); preload(sndRunning, {as: "audio"}); const openDoor = () => { setDoor("open"); callbacks.doorOpened(); } const closeDoor = () => { setDoor("closed"); callbacks.doorClosed(); } return <> callbacks.startPressed()} /> callbacks.stopPressed()} /> callbacks.incTimePressed()} onMouseUp={() => callbacks.incTimeReleased()} /> door === "open" ? closeDoor() : openDoor()} /> {timeDisplay} {magnetron === "on" && } {playBell && } ; } export const MicrowavePlant: Plant = { inputEvents: [], outputEvents: [], initial: { timeDisplay: 0, magnetron: "off", bell: false, }, reduce: (inputEvent: RaisedEvent, state: MicrowaveState) => { if (inputEvent.name === "setMagnetron") { return { ...state, magnetron: inputEvent.param, bell: false }; } if (inputEvent.name === "setTimeDisplay") { return { ...state, timeDisplay: inputEvent.param, bell: false }; } if (inputEvent.name === "ringBell") { return { ...state, bell: true }; } return state; // unknown event - ignore it }, render: (state, raiseEvent) => raiseEvent({name: "startPressed"}), stopPressed: () => raiseEvent({name: "stopPressed"}), incTimePressed: () => raiseEvent({name: "incTimePressed"}), incTimeReleased: () => raiseEvent({name: "incTimeReleased"}), doorOpened: () => raiseEvent({name: "door", param: "open"}), doorClosed: () => raiseEvent({name: "door", param: "closed"}), }}/>, }