Add interval setter UI
This commit is contained in:
parent
7d9fb457ff
commit
c9346da331
@ -3,7 +3,11 @@ import { CodeEditor, CodeEditorRef } from "../ui/code-editor";
|
||||
import { InputEditor, InputEditorRef } from "../ui/input-editor";
|
||||
import { MainLayout } from "../ui/MainLayout";
|
||||
import { useExecController } from "../ui/use-exec-controller";
|
||||
import { DocumentRange, LanguageProvider } from "../engines/types";
|
||||
import {
|
||||
DocumentRange,
|
||||
LanguageProvider,
|
||||
StepExecutionResult,
|
||||
} from "../engines/types";
|
||||
import BrainfuckProvider from "../engines/brainfuck";
|
||||
import { OutputViewer } from "../ui/output-viewer";
|
||||
import { ExecutionControls } from "./execution-controls";
|
||||
@ -15,12 +19,20 @@ export const Mainframe = () => {
|
||||
const execController = useExecController();
|
||||
|
||||
// UI states used in execution time
|
||||
const [execInterval, setExecInterval] = React.useState(20);
|
||||
const [rendererState, setRendererState] = React.useState<any>(null);
|
||||
const [output, setOutput] = React.useState<string | null>(null);
|
||||
const [codeHighlights, setCodeHighlights] = React.useState<
|
||||
DocumentRange | undefined
|
||||
>();
|
||||
|
||||
/** Utility that updates UI with the provided execution result */
|
||||
const updateWithResult = (result: StepExecutionResult<any>) => {
|
||||
setRendererState(result.rendererState);
|
||||
setCodeHighlights(result.nextStepLocation || undefined);
|
||||
setOutput((o) => (o || "") + (result.output || ""));
|
||||
};
|
||||
|
||||
/** Reset and begin a new execution */
|
||||
const runProgram = async () => {
|
||||
// Check if controller is free for execution
|
||||
@ -40,11 +52,7 @@ export const Mainframe = () => {
|
||||
);
|
||||
|
||||
// Begin execution
|
||||
await execController.execute((result) => {
|
||||
setRendererState(result.rendererState);
|
||||
setCodeHighlights(result.nextStepLocation || undefined);
|
||||
setOutput((o) => (o || "") + (result.output || ""));
|
||||
}, 40);
|
||||
await execController.execute(updateWithResult, execInterval);
|
||||
};
|
||||
|
||||
/** Pause the ongoing execution */
|
||||
@ -67,9 +75,7 @@ export const Mainframe = () => {
|
||||
|
||||
// Run and update execution states
|
||||
const result = await execController.executeStep();
|
||||
setRendererState(result.rendererState);
|
||||
setCodeHighlights(result.nextStepLocation || undefined);
|
||||
setOutput((o) => (o || "") + (result.output || ""));
|
||||
updateWithResult(result);
|
||||
};
|
||||
|
||||
/** Resume the currently paused execution */
|
||||
@ -81,11 +87,7 @@ export const Mainframe = () => {
|
||||
}
|
||||
|
||||
// Begin execution
|
||||
await execController.execute((result) => {
|
||||
setRendererState(result.rendererState);
|
||||
setCodeHighlights(result.nextStepLocation || undefined);
|
||||
setOutput((o) => (o || "") + (result.output || ""));
|
||||
}, 40);
|
||||
await execController.execute(updateWithResult, execInterval);
|
||||
};
|
||||
|
||||
/** Stop the currently active execution */
|
||||
@ -142,6 +144,7 @@ export const Mainframe = () => {
|
||||
onResume={resumeExecution}
|
||||
onStep={executeStep}
|
||||
onStop={stopExecution}
|
||||
onChangeInterval={setExecInterval}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
@ -1,11 +1,52 @@
|
||||
import { Button, ButtonGroup, Icon } from "@blueprintjs/core";
|
||||
import {
|
||||
Button,
|
||||
ButtonGroup,
|
||||
Icon,
|
||||
NumericInput,
|
||||
Tag,
|
||||
} from "@blueprintjs/core";
|
||||
|
||||
const styles = {
|
||||
container: {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
paddingRight: 5,
|
||||
marginRight: -15,
|
||||
},
|
||||
inputWrapper: {
|
||||
/**
|
||||
* As of Dec'21, NumericInput doesn't have `small` prop yet,
|
||||
* so we instead use `transform` to hack up a smaller input.
|
||||
*/
|
||||
transform: "scale(0.8)",
|
||||
},
|
||||
input: {
|
||||
width: 125,
|
||||
},
|
||||
};
|
||||
|
||||
/** Input field for changing execution interval */
|
||||
const IntervalInput = (props: {
|
||||
disabled: boolean;
|
||||
onChange: (v: number) => void;
|
||||
}) => {
|
||||
return (
|
||||
<div style={styles.inputWrapper}>
|
||||
<NumericInput
|
||||
min={20}
|
||||
defaultValue={20}
|
||||
stepSize={10}
|
||||
minorStepSize={null}
|
||||
leftIcon="time"
|
||||
clampValueOnBlur
|
||||
style={styles.input}
|
||||
disabled={props.disabled}
|
||||
onValueChange={(v) => props.onChange(v)}
|
||||
rightElement={<Tag minimal>ms</Tag>}
|
||||
allowNumericCharactersOnly
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
/** Button for starting code execution */
|
||||
@ -59,6 +100,7 @@ type Props = {
|
||||
onResume: () => void;
|
||||
onStep: () => void;
|
||||
onStop: () => void;
|
||||
onChangeInterval: (value: number) => void;
|
||||
};
|
||||
|
||||
export const ExecutionControls = (props: Props) => {
|
||||
@ -75,6 +117,10 @@ export const ExecutionControls = (props: Props) => {
|
||||
onStop={props.onStop}
|
||||
/>
|
||||
)}
|
||||
<IntervalInput
|
||||
disabled={props.state === "running"}
|
||||
onChange={props.onChangeInterval}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user