better adaptive layout

This commit is contained in:
Joeri Exelmans 2025-10-19 23:28:18 +02:00
parent 3f9f2affd3
commit 8144a3ec78
3 changed files with 93 additions and 92 deletions

View file

@ -53,6 +53,10 @@ summary {
height: 26px; height: 26px;
} }
.toolbarGroup {
display: inline-block;
}
button.active { button.active {
border: solid blue 2px; border: solid blue 2px;
background-color: rgba(0,0,255,0.2); background-color: rgba(0,0,255,0.2);

View file

@ -193,7 +193,7 @@ export function App() {
borderColor: "divider", borderColor: "divider",
flex: '0 0 content', flex: '0 0 content',
overflow: "auto", overflow: "auto",
maxWidth: 350, maxWidth: '30vw',
}}> }}>
<ShowAST {...{...ast, rt: rt.at(rtIdx!), highlightActive}}/> <ShowAST {...{...ast, rt: rt.at(rtIdx!), highlightActive}}/>
<ShowOutputEvents outputEvents={ast.outputEvents}/> <ShowOutputEvents outputEvents={ast.outputEvents}/>

View file

@ -14,11 +14,13 @@ import StopIcon from '@mui/icons-material/Stop';
import UndoIcon from '@mui/icons-material/Undo'; import UndoIcon from '@mui/icons-material/Undo';
import RedoIcon from '@mui/icons-material/Redo'; import RedoIcon from '@mui/icons-material/Redo';
import InfoOutlineIcon from '@mui/icons-material/InfoOutline'; import InfoOutlineIcon from '@mui/icons-material/InfoOutline';
import KeyboardIcon from '@mui/icons-material/Keyboard';
import { formatTime } from "./util"; import { formatTime } from "./util";
import { InsertMode } from "../VisualEditor/VisualEditor"; import { InsertMode } from "../VisualEditor/VisualEditor";
import { KeyInfoHidden, KeyInfoVisible } from "./KeyInfo"; import { KeyInfoHidden, KeyInfoVisible } from "./KeyInfo";
import { About } from "./About"; import { About } from "./About";
import { Stack } from "@mui/material";
export type TopPanelProps = { export type TopPanelProps = {
rt?: BigStep, rt?: BigStep,
@ -199,96 +201,104 @@ export function TopPanel({rt, rtIdx, time, setTime, onInit, onClear, onRaise, on
return <> return <>
<div className="toolbar"> <div className="toolbar">
{/* shortcuts / about */}
<div className="toolbarGroup">
<KeyInfo keyInfo={<kbd>~</kbd>}>
<button title="show/hide keyboard shortcuts" className={showKeys?"active":""} onClick={() => setShowKeys(s => !s)}><KeyboardIcon fontSize="small"/></button>
</KeyInfo>
<button title="about StateBuddy" onClick={() => setModal(<About setModal={setModal}/>)}><InfoOutlineIcon fontSize="small"/></button>
</div>
<div style={{display:'inline-block'}}> &emsp;
<div style={{display:'inline-block'}}> {/* undo / redo */}
<KeyInfo keyInfo={<><kbd>Ctrl</kbd>+<kbd>Z</kbd></>}> <div className="toolbarGroup">
<button title="undo"><UndoIcon fontSize="small"/></button> <KeyInfo keyInfo={<><kbd>Ctrl</kbd>+<kbd>Z</kbd></>}>
</KeyInfo> <button title="undo"><UndoIcon fontSize="small"/></button>
<KeyInfo keyInfo={<><kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>Z</kbd></>}> </KeyInfo>
<button title="redo"><RedoIcon fontSize="small"/></button> <KeyInfo keyInfo={<><kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>Z</kbd></>}>
</KeyInfo> <button title="redo"><RedoIcon fontSize="small"/></button>
</div> </KeyInfo>
</div>
&emsp; &emsp;
<div style={{display:'inline-block'}}> {/* insert rountangle / arrow / ... */}
{([ <div className="toolbarGroup">
["and", "AND-states", <RountangleIcon kind="and"/>, <kbd>A</kbd>], {([
["or", "OR-states", <RountangleIcon kind="or"/>, <kbd>O</kbd>], ["and", "AND-states", <RountangleIcon kind="and"/>, <kbd>A</kbd>],
["pseudo", "pseudo-states", <PseudoStateIcon/>, <kbd>P</kbd>], ["or", "OR-states", <RountangleIcon kind="or"/>, <kbd>O</kbd>],
["shallow", "shallow history", <HistoryIcon kind="shallow"/>, <kbd>H</kbd>], ["pseudo", "pseudo-states", <PseudoStateIcon/>, <kbd>P</kbd>],
["deep", "deep history", <HistoryIcon kind="deep"/>, <></>], ["shallow", "shallow history", <HistoryIcon kind="shallow"/>, <kbd>H</kbd>],
["transition", "transitions", <TrendingFlatIcon fontSize="small"/>, <kbd>T</kbd>], ["deep", "deep history", <HistoryIcon kind="deep"/>, <></>],
["text", "text", <>&nbsp;T&nbsp;</>, <kbd>X</kbd>], ["transition", "transitions", <TrendingFlatIcon fontSize="small"/>, <kbd>T</kbd>],
] as [InsertMode, string, ReactElement, ReactElement][]).map(([m, hint, buttonTxt, keyInfo]) => ["text", "text", <>&nbsp;T&nbsp;</>, <kbd>X</kbd>],
<KeyInfo keyInfo={keyInfo}> ] as [InsertMode, string, ReactElement, ReactElement][]).map(([m, hint, buttonTxt, keyInfo]) =>
<button <KeyInfo keyInfo={keyInfo}>
title={"insert "+hint} <button
disabled={mode===m} title={"insert "+hint}
className={mode===m ? "active":""} disabled={mode===m}
onClick={() => setMode(m)} className={mode===m ? "active":""}
>{buttonTxt}</button></KeyInfo>)} onClick={() => setMode(m)}
</div> >{buttonTxt}</button></KeyInfo>)}
</div>
&emsp; &emsp;
<div style={{display:'inline-block'}}> {/* execution */}
<div className="toolbarGroup">
<KeyInfo keyInfo={<kbd>I</kbd>}> {/* init / clear / pause / real time */}
<button title="(re)initialize simulation" onClick={onInit} ><PlayArrowIcon fontSize="small"/><CachedIcon fontSize="small"/></button> <div className="toolbarGroup">
</KeyInfo> <KeyInfo keyInfo={<kbd>I</kbd>}>
<KeyInfo keyInfo={<kbd>C</kbd>}> <button title="(re)initialize simulation" onClick={onInit} ><PlayArrowIcon fontSize="small"/><CachedIcon fontSize="small"/></button>
<button title="clear the simulation" onClick={onClear} disabled={!rt}><StopIcon fontSize="small"/></button> </KeyInfo>
</KeyInfo> <KeyInfo keyInfo={<kbd>C</kbd>}>
<button title="clear the simulation" onClick={onClear} disabled={!rt}><StopIcon fontSize="small"/></button>
</KeyInfo>
&emsp;
<KeyInfo keyInfo={<><kbd>Space</kbd> toggles</>}>
<button title="pause the simulation" disabled={!rt || time.kind==="paused"} className={(rt && time.kind==="paused") ? "active":""} onClick={() => onChangePaused(true, Math.round(performance.now()))}><PauseIcon fontSize="small"/></button>
<button title="run the simulation in real time" disabled={!rt || time.kind==="realtime"} className={(rt && time.kind==="realtime") ? "active":""} onClick={() => onChangePaused(false, Math.round(performance.now()))}><PlayArrowIcon fontSize="small"/></button>
</KeyInfo>
</div>
&emsp; &emsp;
<KeyInfo keyInfo={<><kbd>Space</kbd> toggles</>}> {/* speed */}
<button title="pause the simulation" disabled={!rt || time.kind==="paused"} className={(rt && time.kind==="paused") ? "active":""} onClick={() => onChangePaused(true, Math.round(performance.now()))}><PauseIcon fontSize="small"/></button> <div className="toolbarGroup">
<button title="run the simulation in real time" disabled={!rt || time.kind==="realtime"} className={(rt && time.kind==="realtime") ? "active":""} onClick={() => onChangePaused(false, Math.round(performance.now()))}><PlayArrowIcon fontSize="small"/></button> <label htmlFor="number-timescale">speed</label>&nbsp;
</KeyInfo> <KeyInfo keyInfo={<kbd>S</kbd>}>
<button title="slower" onClick={onSlower}>÷2</button>
</KeyInfo>
<input title="controls how fast the simulation should run in real time mode - larger than 1 means: faster than wall-clock time" id="number-timescale" value={timescale.toFixed(3)} style={{width:40}} readOnly onChange={e => onTimeScaleChange(e.target.value, Math.round(performance.now()))}/>
<KeyInfo keyInfo={<kbd>F</kbd>}>
<button title="faster" onClick={onFaster}>×2</button>
</KeyInfo>
</div>
&emsp; &emsp;
<label htmlFor="number-timescale">speed</label>&nbsp; {/* time, next */}
<KeyInfo keyInfo={<kbd>S</kbd>}> <div className="toolbarGroup">
<button title="slower" onClick={onSlower}>÷2</button> <div className="toolbarGroup">
</KeyInfo> <label htmlFor="time">time (s)</label>&nbsp;
<input title="controls how fast the simulation should run in real time mode - larger than 1 means: faster than wall-clock time" id="number-timescale" value={timescale.toFixed(3)} style={{width:40}} readOnly onChange={e => onTimeScaleChange(e.target.value, Math.round(performance.now()))}/> <input title="the current simulated time" id="time" disabled={!rt} value={displayTime} readOnly={true} className="readonlyTextBox" />
<KeyInfo keyInfo={<kbd>F</kbd>}> &emsp;
<button title="faster" onClick={onFaster}>×2</button> </div>
</KeyInfo> <div className="toolbarGroup">
<label htmlFor="next-timeout">next (s)</label>&nbsp;
&emsp; <input title="next point in simulated time where a timed transition may fire" id="next-timeout" disabled={!rt} value={nextTimedTransition ? formatTime(nextTimedTransition[0]) : '+inf'} readOnly={true} className="readonlyTextBox"/>
<KeyInfo keyInfo={<kbd>Tab</kbd>}>
<label htmlFor="time">time (s)</label>&nbsp; <button title="advance time just enough for the next timer to elapse" disabled={nextTimedTransition===undefined} onClick={onSkip}><SkipNextIcon fontSize="small"/><AccessAlarmIcon fontSize="small"/></button>
<input title="the current simulated time" id="time" disabled={!rt} value={displayTime} readOnly={true} className="readonlyTextBox" /> </KeyInfo>
</div>
</div>
&emsp; </div>
<KeyInfo> <div className="toolbarGroup">
<label htmlFor="next-timeout">next (s)</label>&nbsp;
<input title="next point in simulated time where a timed transition may fire" id="next-timeout" disabled={!rt} value={nextTimedTransition ? formatTime(nextTimedTransition[0]) : '+inf'} readOnly={true} className="readonlyTextBox"/>
</KeyInfo>
<KeyInfo keyInfo={<kbd>Tab</kbd>}>
<button title="advance time just enough for the next timer to elapse" disabled={nextTimedTransition===undefined} onClick={onSkip}><SkipNextIcon fontSize="small"/><AccessAlarmIcon fontSize="small"/></button>
</KeyInfo>
&emsp;
<KeyInfo keyInfo={<kbd>Backspace</kbd>}>
<button title="undo last step (go back in time)"
disabled={rtIdx===undefined || rtIdx===0} onClick={onBack}><SkipPreviousIcon fontSize="small"/></button>
</KeyInfo>
</div>
&emsp;
</div>
<div style={{display:'inline-block'}}>
{ast.inputEvents && {ast.inputEvents &&
<> <>
@ -316,20 +326,7 @@ export function TopPanel({rt, rtIdx, time, setTime, onInit, onClear, onRaise, on
</> </>
} }
&emsp;
<div style={{display:"inline-block"}}>
<KeyInfo keyInfo={<kbd>~</kbd>}>
<input id="checkbox-keys" type="checkbox" checked={showKeys} onChange={e => setShowKeys(e.target.checked)}></input>
<label htmlFor="checkbox-keys">see shortcuts</label>
</KeyInfo>
</div> </div>
</div>
</div> </>;
&emsp;
<button onClick={() => setModal(<About setModal={setModal}/>)}><InfoOutlineIcon fontSize="small"/></button>
</div></>;
} }