import { 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(null); const cssPositions = useFloatingPositions(370); return props.floatConfig ? ( {props.children} ) : ( {props.children} ); } 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 ( {floatingPanel && ( (e.currentTarget.style.cursor = "grabbing")} onMouseUp={(e) => (e.currentTarget.style.cursor = "grab")} className="drag-handle" > )} {controlActions.map( ({ icon: Icon, label, disabled, onClick, options: sub }) => { const button = ( ); if (!sub) return button; return ( {button} {sub.map(({ label, icon: Icon, onClick }, i) => ( } onClick={onClick} > {label} ))} ); }, )} ); } export default DebuggerControls;