better looking simulation
This commit is contained in:
parent
f80086727c
commit
b8bc977a8e
6 changed files with 44 additions and 39 deletions
|
|
@ -1,11 +1,17 @@
|
|||
details.active {
|
||||
background-color: rgba(255, 140, 0, 0.2);
|
||||
/* background-color: rgba(128, 72, 0, 0.855);
|
||||
color: white; */
|
||||
|
||||
box-shadow: rgba(128, 72, 0, 0.856) 0 0 8;
|
||||
}
|
||||
|
||||
details {
|
||||
border: 1px black solid;
|
||||
/* border-radius: 5px; */
|
||||
background-color: white;
|
||||
margin-bottom: 2px;
|
||||
margin-bottom: 4px;
|
||||
padding-right: 2px;
|
||||
color: black;
|
||||
width: fit-content;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
|
@ -58,13 +58,10 @@ export function App() {
|
|||
if (refRightSideBar.current) {
|
||||
|
||||
const el = refRightSideBar.current;
|
||||
// console.log('scrolling to', el.scrollHeight);
|
||||
console.log('scrolling to:', el);
|
||||
setTimeout(() => {
|
||||
el.scrollIntoView({block: "end", behavior: "smooth"});
|
||||
}, 100);
|
||||
|
||||
// el.scrollTo(0, el.scrollHeight+1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -106,6 +103,11 @@ export function App() {
|
|||
};
|
||||
}, []);
|
||||
|
||||
const highlightActive = (rtIdx !== undefined) && new Set([...rt[rtIdx].mode].filter(uid => {
|
||||
const state = ast.uid2State.get(uid);
|
||||
return state && state.parent?.kind !== "and";
|
||||
})) || new Set();
|
||||
|
||||
return <Stack sx={{height:'100vh'}}>
|
||||
{/* Top bar */}
|
||||
<Box
|
||||
|
|
@ -123,7 +125,7 @@ export function App() {
|
|||
<Stack direction="row" sx={{height:'calc(100vh - 64px)'}}>
|
||||
{/* main */}
|
||||
<Box sx={{flexGrow:1, overflow:'auto'}}>
|
||||
<VisualEditor {...{ast, setAST, rt: rt.at(rtIdx!), setRT, errors, setErrors, mode}}/>
|
||||
<VisualEditor {...{ast, setAST, rt: rt.at(rtIdx!), setRT, errors, setErrors, mode, highlightActive}}/>
|
||||
</Box>
|
||||
{/* right sidebar */}
|
||||
<Box
|
||||
|
|
@ -133,10 +135,8 @@ export function App() {
|
|||
flex: '0 0 content',
|
||||
height: 'calc(100vh-32px)',
|
||||
overflow: "auto",
|
||||
// paddingRight: 1,
|
||||
// paddingLeft: 1,
|
||||
}}>
|
||||
<ShowAST {...{...ast, rt: rt.at(rtIdx!)}}/>
|
||||
<ShowAST {...{...ast, rt: rt.at(rtIdx!), highlightActive}}/>
|
||||
<br/>
|
||||
<div ref={refRightSideBar}>
|
||||
<RTHistory {...{ast, rt, rtIdx, setTime, setRTIdx, refRightSideBar}}/>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Dispatch, SetStateAction } from "react";
|
||||
import { Dispatch, Ref, SetStateAction } from "react";
|
||||
import { Statechart, stateDescription } from "../statecharts/abstract_syntax";
|
||||
import { BigStep, Environment, Mode, RaisedEvent } from "../statecharts/runtime_types";
|
||||
import { formatTime } from "./util";
|
||||
|
|
@ -10,23 +10,26 @@ type RTHistoryProps = {
|
|||
ast: Statechart,
|
||||
setRTIdx: Dispatch<SetStateAction<number|undefined>>,
|
||||
setTime: Dispatch<SetStateAction<TimeMode>>,
|
||||
refRightSideBar: Ref<HTMLDivElement>,
|
||||
}
|
||||
|
||||
export function RTHistory({rt, rtIdx, ast, setRTIdx, setTime}: RTHistoryProps) {
|
||||
export function RTHistory({rt, rtIdx, ast, setRTIdx, setTime, refRightSideBar}: RTHistoryProps) {
|
||||
function gotoRt(idx: number, timestamp: number) {
|
||||
setRTIdx(idx);
|
||||
setTime({kind: "paused", simtime: timestamp});
|
||||
}
|
||||
|
||||
return rt.map((rt, idx) => <>
|
||||
<div className={"runtimeState"+(idx===rtIdx?" active":"")} onClick={() => gotoRt(idx, rt.simtime)}>
|
||||
<div>({formatTime(rt.simtime)}, {rt.inputEvent || "<init>"})</div>
|
||||
<ShowMode mode={rt.mode} statechart={ast}/>
|
||||
<ShowEnvironment environment={rt.environment}/>
|
||||
{rt.outputEvents.length>0 && <div>
|
||||
{rt.outputEvents.map((e:RaisedEvent) => '^'+e.name).join(', ')}
|
||||
</div>}
|
||||
</div></>);
|
||||
return <div>
|
||||
{rt.map((r, idx) => <>
|
||||
<div className={"runtimeState"+(idx===rtIdx?" active":"")} onClick={() => gotoRt(idx, r.simtime)}>
|
||||
<div>({formatTime(r.simtime)}, {r.inputEvent || "<init>"})</div>
|
||||
<ShowMode mode={r.mode} statechart={ast}/>
|
||||
<ShowEnvironment environment={r.environment}/>
|
||||
{r.outputEvents.length>0 && <div>
|
||||
{r.outputEvents.map((e:RaisedEvent) => '^'+e.name).join(', ')}
|
||||
</div>}
|
||||
</div></>)}
|
||||
</div>;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -45,13 +48,5 @@ function ShowMode(props: {mode: Mode, statechart: Statechart}) {
|
|||
}
|
||||
|
||||
function getActiveLeafs(mode: Mode, sc: Statechart) {
|
||||
const toDelete = [];
|
||||
for (const stateA of mode) {
|
||||
for (const stateB of mode) {
|
||||
if (sc.uid2State.get(stateA)!.parent === sc.uid2State.get(stateB)) {
|
||||
toDelete.push(stateB);
|
||||
}
|
||||
}
|
||||
}
|
||||
return mode.difference(new Set(toDelete));
|
||||
return new Set([...mode].filter(uid => sc.uid2State.get(uid)?.children?.length === 0));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,11 +32,11 @@ export function ShowAction(props: {action: Action}) {
|
|||
}
|
||||
}
|
||||
|
||||
export function ShowAST(props: {root: ConcreteState | PseudoState, transitions: Map<string, Transition[]>, rt: RT_Statechart | undefined}) {
|
||||
export function ShowAST(props: {root: ConcreteState | PseudoState, transitions: Map<string, Transition[]>, rt: RT_Statechart | undefined, highlightActive: Set<string>}) {
|
||||
const description = stateDescription(props.root);
|
||||
const outgoing = props.transitions.get(props.root.uid) || [];
|
||||
|
||||
return <details open={true} className={props.rt?.mode.has(props.root.uid) ? "active" : ""}>
|
||||
return <details open={true} className={props.highlightActive.has(props.root.uid) ? "active" : ""}>
|
||||
<summary>{props.root.kind}: {description}</summary>
|
||||
|
||||
{props.root.kind !== "pseudo" && props.root.entryActions.length>0 &&
|
||||
|
|
@ -51,7 +51,7 @@ export function ShowAST(props: {root: ConcreteState | PseudoState, transitions:
|
|||
}
|
||||
{props.root.kind !== "pseudo" && props.root.children.length>0 &&
|
||||
props.root.children.map(child =>
|
||||
<ShowAST root={child} transitions={props.transitions} rt={props.rt} />
|
||||
<ShowAST root={child} transitions={props.transitions} rt={props.rt} highlightActive={props.highlightActive} />
|
||||
)
|
||||
}
|
||||
{outgoing.length>0 &&
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@
|
|||
/* fill-opacity: 0.2; */
|
||||
/* stroke: rgb(100, 149, 237); */
|
||||
/* stroke: */
|
||||
filter: drop-shadow( 0px 0px 6px rgba(0, 150, 255, 0.8));
|
||||
filter: drop-shadow( 0px 0px 6px rgba(128, 72, 0, 0.856));
|
||||
/* stroke-width: 3px; */
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -61,14 +61,16 @@ export const sides: [RountanglePart, (r:Rect2D)=>Line2D][] = [
|
|||
export type InsertMode = "and"|"or"|"pseudo"|"shallow"|"deep"|"transition"|"text";
|
||||
|
||||
type VisualEditorProps = {
|
||||
ast: Statechart,
|
||||
setAST: Dispatch<SetStateAction<Statechart>>,
|
||||
rt: BigStep|undefined,
|
||||
errors: TraceableError[],
|
||||
setErrors: Dispatch<SetStateAction<TraceableError[]>>,
|
||||
mode: InsertMode,
|
||||
highlightActive: Set<string>,
|
||||
};
|
||||
|
||||
export function VisualEditor({setAST, rt, errors, setErrors, mode}: VisualEditorProps) {
|
||||
export function VisualEditor({ast, setAST, rt, errors, setErrors, mode, highlightActive}: VisualEditorProps) {
|
||||
const [historyState, setHistoryState] = useState<HistoryState>({current: emptyState, history: [], future: []});
|
||||
|
||||
const state = historyState.current;
|
||||
|
|
@ -680,6 +682,8 @@ export function VisualEditor({setAST, rt, errors, setErrors, mode}: VisualEditor
|
|||
|
||||
const active = rt?.mode || new Set();
|
||||
|
||||
console.log(highlightActive);
|
||||
|
||||
const rootErrors = errors.filter(({shapeUid}) => shapeUid === "root").map(({message}) => message);
|
||||
|
||||
return <svg width="4000px" height="4000px"
|
||||
|
|
@ -711,8 +715,8 @@ export function VisualEditor({setAST, rt, errors, setErrors, mode}: VisualEditor
|
|||
|
||||
{(rootErrors.length>0) && <text className="error" x={5} y={20}>{rootErrors.join(' ')}</text>}
|
||||
|
||||
{state.rountangles.map(rountangle =>
|
||||
<RountangleSVG
|
||||
{state.rountangles.map(rountangle => {
|
||||
return <RountangleSVG
|
||||
key={rountangle.uid}
|
||||
rountangle={rountangle}
|
||||
selected={selection.find(r => r.uid === rountangle.uid)?.parts || []}
|
||||
|
|
@ -720,8 +724,8 @@ export function VisualEditor({setAST, rt, errors, setErrors, mode}: VisualEditor
|
|||
errors={errors
|
||||
.filter(({shapeUid}) => shapeUid === rountangle.uid)
|
||||
.map(({message}) => message)}
|
||||
active={active.has(rountangle.uid)}
|
||||
/>)}
|
||||
active={highlightActive.has(rountangle.uid)}
|
||||
/>})}
|
||||
|
||||
{state.diamonds.map(diamond => <>
|
||||
<DiamondSVG
|
||||
|
|
@ -732,7 +736,7 @@ export function VisualEditor({setAST, rt, errors, setErrors, mode}: VisualEditor
|
|||
errors={errors
|
||||
.filter(({shapeUid}) => shapeUid === diamond.uid)
|
||||
.map(({message}) => message)}
|
||||
active={active.has(diamond.uid)}/>
|
||||
active={false}/>
|
||||
</>)}
|
||||
|
||||
{state.history.map(history => <>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue