|
@@ -1,10 +1,11 @@
|
|
|
import * as React from "react";
|
|
|
-import {IconChevronLeft, IconChevronRight, IconAlertCircle, IconCircleCheck, IconArrowsHorizontal} from "@tabler/icons";
|
|
|
+import {IconChevronLeft, IconChevronRight, IconAlertCircle, IconCircleCheck, IconArrowsHorizontal, IconInfoCircle} from "@tabler/icons";
|
|
|
import {SimpleGrid, Group, Grid, Stack, Title, Button, Text, Modal, Center, List, Space, Table} from "@mantine/core";
|
|
|
|
|
|
import {RountangleEditor} from "./rountangleEditor/RountangleEditor";
|
|
|
import {Version} from "../onion/version";
|
|
|
import {emptyGraph, graphForces} from "./constants";
|
|
|
+import {makeOverlayHelpIcon} from "./help_icons";
|
|
|
import {d3Types, Graph} from "./graph";
|
|
|
import {PrimitiveDelta, EdgeCreation, EdgeUpdate, PrimitiveRegistry, NodeCreation, NodeDeletion} from "../onion/primitive_delta";
|
|
|
import {GraphType} from "./editable_graph";
|
|
@@ -105,31 +106,34 @@ export function newManualRenderer({generateUUID, primitiveRegistry}) {
|
|
|
|
|
|
const [undone, setUndone] = React.useState<PrimitiveDelta[]>([]);
|
|
|
|
|
|
- const lines = props.asDeltasToRender.filter(d => !(d instanceof NodeDeletion)).map(d => {
|
|
|
+ const changelog = props.asDeltasToRender.filter(d => !(d instanceof NodeDeletion)).map(d => {
|
|
|
if (d instanceof NodeCreation) {
|
|
|
- return "Newly created AS state " + JSON.stringify(d.id.value) + " needs CS geometry";
|
|
|
+ return "Newly created rountangle " + JSON.stringify(props.asToCs.get(d.id.value)!) + " needs geometry";
|
|
|
}
|
|
|
else if (d instanceof EdgeCreation) {
|
|
|
- return "Newly created parent link from " + JSON.stringify(d.source.id.value) + " to " + JSON.stringify((d.target.getTarget() as NodeCreation).id.value) + " needs to be reflected by geometric 'insideness'";
|
|
|
+ return "Rountangle " + JSON.stringify(props.asToCs.get(d.source.id.value)!) + " needs to be moved inside rountangle " + JSON.stringify((props.asToCs.get((d.target.getTarget() as NodeCreation).id.value)!));
|
|
|
}
|
|
|
else if (d instanceof EdgeUpdate) {
|
|
|
const oldTarget = d.overwrites.target.getTarget();
|
|
|
const newTarget = d.target.getTarget();
|
|
|
- const sourceId = JSON.stringify(d.getCreation().source.id.value);
|
|
|
+ const sourceId = d.getCreation().source.id.value;
|
|
|
if (oldTarget === null && newTarget !== null) {
|
|
|
- return "Newly created parent link from " + sourceId + " to " + JSON.stringify((newTarget as NodeCreation).id.value) + " needs to be reflected by geometric 'insideness'";
|
|
|
+ return "Rountangle " + JSON.stringify(props.asToCs.get(sourceId)!) + " needs to be moved inside rountangle " + JSON.stringify(props.asToCs.get((newTarget as NodeCreation).id.value));
|
|
|
}
|
|
|
else if (oldTarget !== null && newTarget === null) {
|
|
|
- return "Deleted parent link from " + sourceId + " to " + JSON.stringify((oldTarget as NodeCreation).id.value);
|
|
|
+ return "Rountangle " + JSON.stringify(props.asToCs.get(sourceId)!) + " is no longer inside rountangle " + JSON.stringify(props.asToCs.get((oldTarget as NodeCreation).id.value)!);
|
|
|
}
|
|
|
else if (oldTarget !== null && newTarget !== null) {
|
|
|
- return "Updated parent link from source " + sourceId + " to " + JSON.stringify((newTarget as NodeCreation).id.value);
|
|
|
+ return "Rountangle " + JSON.stringify(props.asToCs.get(sourceId)!) + " is no longer inside rountangle " + JSON.stringify(props.asToCs.get((oldTarget as NodeCreation).id.value)!) + " but instead inside rountangle " + JSON.stringify(props.asToCs.get((newTarget as NodeCreation).id.value)!);
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
|
|
|
return <>
|
|
|
<Stack>
|
|
|
+ <List icon={<IconInfoCircle/>}>
|
|
|
+ {changelog.map((line, i) => <List.Item key={i}>{line}</List.Item>)}
|
|
|
+ </List>
|
|
|
<Group>
|
|
|
<Stack>
|
|
|
<Group position="apart">
|
|
@@ -149,20 +153,23 @@ export function newManualRenderer({generateUUID, primitiveRegistry}) {
|
|
|
}} compact rightIcon={<IconChevronRight/>}>Redo</Button>
|
|
|
</Group>
|
|
|
</Group>
|
|
|
- <RountangleEditor
|
|
|
- graph={csGraph}
|
|
|
- generateUUID={generateUUID}
|
|
|
- primitiveRegistry={primitiveRegistry}
|
|
|
- graphState={csGraphState}
|
|
|
- onUserEdit={(deltas: PrimitiveDelta[], description: string) => {
|
|
|
- // the user is not allowed to create/remove rountangles, so we only respond to EdgeUpdates
|
|
|
- const filteredDeltas = deltas.filter(d => d instanceof EdgeUpdate);
|
|
|
- setCsDeltas(prevCsDeltas => prevCsDeltas.concat(filteredDeltas));
|
|
|
- setUndone([]);
|
|
|
- filteredDeltas.forEach(d => csGraphState.exec(d, new D3GraphStateUpdater(setCsGraph, 0, 0)));
|
|
|
- setInconsistencies(findInconsistencies(csGraphState, props.asGraphState));
|
|
|
- }}
|
|
|
- />
|
|
|
+ {makeOverlayHelpIcon(
|
|
|
+ <RountangleEditor
|
|
|
+ graph={csGraph}
|
|
|
+ generateUUID={generateUUID}
|
|
|
+ primitiveRegistry={primitiveRegistry}
|
|
|
+ graphState={csGraphState}
|
|
|
+ onUserEdit={(deltas: PrimitiveDelta[], description: string) => {
|
|
|
+ // the user is not allowed to create/remove rountangles, so we only respond to EdgeUpdates
|
|
|
+ const filteredDeltas = deltas.filter(d => d instanceof EdgeUpdate);
|
|
|
+ setCsDeltas(prevCsDeltas => prevCsDeltas.concat(filteredDeltas));
|
|
|
+ setUndone([]);
|
|
|
+ filteredDeltas.forEach(d => csGraphState.exec(d, new D3GraphStateUpdater(setCsGraph, 0, 0)));
|
|
|
+ setInconsistencies(findInconsistencies(csGraphState, props.asGraphState));
|
|
|
+ }}
|
|
|
+ />,
|
|
|
+ <Text><b>Left-Drag</b>: Move/Resize Rountangle / Pan Canvas</Text>
|
|
|
+ )}
|
|
|
</Stack>
|
|
|
<Stack align="flex-start">
|
|
|
<Stack style={{height:"100%"}}>
|
|
@@ -182,10 +189,10 @@ export function newManualRenderer({generateUUID, primitiveRegistry}) {
|
|
|
</Stack>
|
|
|
<Stack>
|
|
|
<Title order={5}>Abstract Syntax (read-only)</Title>
|
|
|
- <Graph
|
|
|
+ {makeOverlayHelpIcon(<Graph
|
|
|
graph={props.asGraph}
|
|
|
forces={graphForces}
|
|
|
- />
|
|
|
+ />, <Text><b>Left-Drag</b>: Drag Node</Text>)}
|
|
|
</Stack>
|
|
|
</Group>
|
|
|
<Group position="apart">
|