Something went wrong. Try again.
Hopefully a GameBoy Advance emulator... luckasranarison.github.io/boya
gameboy-advance nintendo rust wasm emulator
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205import { ActionIcon, Box, Card, Flex, Group, Menu, Portal, ThemeIcon,} from "@mantine/core";import { IconArrowBack, IconFoldDown, IconFoldUp, IconFrame, IconGripVertical, IconPlayerPause, IconPlayerPlay, IconPlus, IconRestore, IconSortDescending, IconStepInto, IconStepOut, IconTimelineEventExclamation,} from "@tabler/icons-react";import Draggable from "react-draggable";import { useViewActions, useViewStore } from "@/stores/viewStore";import { useRef } from "react";import { useRuntimeStore } from "@/stores/runtimeStore";import { useDebuggerStore } from "@/stores/debuggerStore";import { useFloatingPositions, type Position,} from "@/hooks/useFloatingPositions";import { useDebuggerControls } from "@/hooks/useDebuggerControls";
function Wrapper(props: { children: React.ReactNode; floatConfig?: { position: Position };}) { const nodeRef = useRef<HTMLDivElement>(null); const cssPositions = useFloatingPositions(370);
return props.floatConfig ? ( <Portal> <Draggable key={props.floatConfig.position} // force re-render on position change nodeRef={nodeRef} handle=".drag-handle" > <Card ref={nodeRef} style={{ zIndex: 1000, position: "fixed", ...cssPositions[props.floatConfig.position], }} withBorder > {props.children} </Card> </Draggable> </Portal> ) : ( <Box>{props.children}</Box> );}
function DebuggerControls(props: { position?: Position }) { const floatingWindows = useViewStore((state) => state.floatingWindows); const running = useRuntimeStore((state) => state.running); const callstack = useDebuggerStore((state) => state.callstack); const rom = useRuntimeStore((state) => state.rom !== undefined); const floatingPanel = floatingWindows.includes("panel");
const { toggleWindow } = useViewActions(); const dbg = useDebuggerControls();
const controlActions = [ { icon: IconRestore, label: "Reset", onClick: dbg.reset, disabled: running || !rom, }, { icon: IconPlus, label: "Navigate", disabled: running || !rom, options: [ { label: "Step Scanline", onClick: dbg.stepScanline, icon: IconSortDescending, }, { label: "Step Frame", onClick: dbg.stepFrame, icon: IconFrame, }, { label: "Step IRQ", onClick: dbg.stepIrq, icon: IconTimelineEventExclamation, }, ], }, { icon: IconArrowBack, label: "Step Back", onClick: () => alert("Not yet implemented!"), disabled: true, }, { icon: running ? IconPlayerPause : IconPlayerPlay, label: running ? "Pause" : "Continue", onClick: dbg.toggleRun, disabled: !rom, }, { icon: IconStepInto, label: "Step into", onClick: dbg.stepInto, disabled: running || !rom, }, { icon: IconStepOut, label: "Step out", onClick: dbg.stepOut, disabled: running || !callstack.length, }, { icon: floatingPanel ? IconFoldDown : IconFoldUp, label: floatingPanel ? "Dock" : "Detach", onClick: () => toggleWindow("panel"), disabled: false, }, ];
return ( <Wrapper floatConfig={props.position ? { position: props.position } : undefined} > <Group w="100%" align="center" justify="center"> {floatingPanel && ( <ThemeIcon c="gray" variant="transparent" style={{ cursor: "grab" }} onMouseDown={(e) => (e.currentTarget.style.cursor = "grabbing")} onMouseUp={(e) => (e.currentTarget.style.cursor = "grab")} className="drag-handle" > <IconGripVertical /> </ThemeIcon> )}
{controlActions.map( ({ icon: Icon, label, disabled, onClick, options: sub }) => { const button = ( <ActionIcon key={label} title={label} variant="subtle" onClick={onClick} disabled={disabled} bg={disabled ? "none" : undefined} > <Icon /> </ActionIcon> );
if (!sub) return button;
return ( <Menu key={label} offset={30}> <Menu.Target> <Flex>{button}</Flex> </Menu.Target> <Menu.Dropdown> {sub.map(({ label, icon: Icon, onClick }, i) => ( <Menu.Item key={i} leftSection={ <ThemeIcon variant="subtle" c="indigo"> <Icon size={18} /> </ThemeIcon> } onClick={onClick} > {label} </Menu.Item> ))} </Menu.Dropdown> </Menu> ); }, )} </Group> </Wrapper> );}
export default DebuggerControls;