Procházet zdrojové kódy

Manual renderer shows changelog + always JSON.stringify() displayed node IDs (so the user can distinguish between numbers and strings)

Joeri Exelmans před 2 roky
rodič
revize
e29b2c2760

+ 1 - 1
src/frontend/d3_state.ts

@@ -28,7 +28,7 @@ export class D3GraphStateUpdater implements GraphStateListener {
     this.setGraph(prevGraph => ({
       nodes: [...prevGraph.nodes, {
         id: nodeNodeId(ns.creation.id.value),
-        label: ns.creation.id.value.toString(),
+        label: JSON.stringify(ns.creation.id.value),
         x: this.x,
         y: this.y,
         color: "darkturquoise",

+ 10 - 27
src/frontend/help_icons.tsx

@@ -17,30 +17,13 @@ export function makeInfoHoverCardIcon(contents) {
   );
 }
 
-export const graphEditor = makeInfoHoverCardIcon(<>
-  <Text><b>Left-Drag</b>: Drag Node</Text>
-  <Text><b>Middle-Click</b>: Delete Node</Text>
-  <Text><b>Right-Click</b>: Create Node or Edge</Text>
-  <Text><b>Wheel</b>: Zoom</Text>
-</>);
-
-export const graphEditorReadonly = makeInfoHoverCardIcon(<>
-  <Text><b>Left-Drag</b>: Drag Node</Text>
-  <Text><b>Wheel</b>: Zoom</Text>
-</>);
-
-export const rountangleEditor = makeInfoHoverCardIcon(<>
-  <Text><b>Alt + Left-Click</b>: Create/Delete Rountangle</Text>
-  <Text><b>Left-Drag</b>: Move Rountangle / Pan Canvas</Text>
-</>);
-
-export const depGraph = makeInfoHoverCardIcon(<>
-  <Text><b>Left-Drag</b>: Drag Node</Text>
-  <Text>Active deltas are <b>bold</b>.</Text>
-</>);
-
-export const historyGraph = makeInfoHoverCardIcon(<>
-  <Text><b>Left-Drag</b>: Drag Node</Text>
-  <Text><b>Right-Click</b>: Goto Version</Text>
-  <Text>Current version is <b>bold</b>.</Text>
-</>);
+export function makeOverlayHelpIcon(background, overlayText) {
+  return (
+    <div style={{position:"relative"}}>
+      {background}
+      <div style={{position: "absolute", top: 0, right: 0}}>
+        {makeInfoHoverCardIcon(overlayText)}
+      </div>
+    </div>
+  );
+}

+ 31 - 24
src/frontend/manual_renderer.tsx

@@ -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">

+ 1 - 1
src/frontend/rountangleEditor/RountangleComponent.tsx

@@ -160,7 +160,7 @@ export class RountangleComponent extends React.Component<RountangleProps, Rounta
                         className={'re-rountangle-id'}
                         title={this.props.id.toString()}
                     >
-                        <span>ID<sub>CS</sub>: {this.props.id}</span>
+                        <span>ID<sub>CS</sub>: {JSON.stringify(this.props.id)}</span>
                     </div>
                 </foreignObject>
                 <RountangleResizeHandleComponent

+ 1 - 1
src/frontend/rountangleEditor/RountangleEditor.tsx

@@ -262,7 +262,7 @@ export class RountangleEditor extends React.Component<RountangleEditorProps, Rou
                 // if (newRountangleName) {
                     this.dispatch({
                         tag: 'createRountangle',
-                        id: this.props.generateUUID().value.toString(),
+                        id: this.props.generateUUID().value,
                         posX: cursorPoint.x,
                         posY: cursorPoint.y,
                         posZ: 10,

+ 32 - 17
src/frontend/versioned_model.tsx

@@ -23,7 +23,7 @@ import {
 import {d3Types, Graph} from "./graph"
 import {emptyGraph, graphForces} from "./constants";
 import {RountangleEditor} from "./rountangleEditor/RountangleEditor";
-import * as HelpIcons from "./help_icons";
+import {makeOverlayHelpIcon} from "./help_icons";
 
 import {embed, Version, VersionRegistry} from "../onion/version";
 import {PrimitiveDelta, PrimitiveRegistry} from "../onion/primitive_delta";
@@ -32,6 +32,32 @@ import {CompositeDelta, CompositeLevel} from "../onion/composite_delta";
 import {GraphState} from "../onion/graph_state"; 
 import {Delta} from "../onion/delta";
 
+const helpText = {
+  graphEditor: <>
+    <Mantine.Text><b>Left-Drag</b>: Drag Node</Mantine.Text>
+    <Mantine.Text><b>Middle-Click</b>: Delete Node</Mantine.Text>
+    <Mantine.Text><b>Right-Click</b>: Create Node or Edge</Mantine.Text>
+    <Mantine.Text><b>Wheel</b>: Zoom</Mantine.Text>
+  </>,
+  graphEditorReadonly: <>
+    <Mantine.Text><b>Left-Drag</b>: Drag Node</Mantine.Text>
+    <Mantine.Text><b>Wheel</b>: Zoom</Mantine.Text>
+  </>,
+  rountangleEditor: <>
+    <Mantine.Text><b>Alt + Left-Click</b>: Create/Delete Rountangle</Mantine.Text>
+    <Mantine.Text><b>Left-Drag</b>: Move/Resize Rountangle / Pan Canvas</Mantine.Text>
+  </>,
+  depGraph: <>
+    <Mantine.Text><b>Left-Drag</b>: Drag Node</Mantine.Text>
+    <Mantine.Text>Active deltas are <b>bold</b>.</Mantine.Text>
+  </>,
+  historyGraph: <>
+    <Mantine.Text><b>Left-Drag</b>: Drag Node</Mantine.Text>
+    <Mantine.Text><b>Right-Click</b>: Goto Version</Mantine.Text>
+    <Mantine.Text>Current version is <b>bold</b>.</Mantine.Text>
+  </>,
+};
+
 export interface VersionedModelState {
   version: Version; // the 'current version'
   graph: GraphType; // the state what is displayed in the leftmost panel
@@ -47,17 +73,6 @@ interface VersionedModelCallbacks {
   onVersionClicked?: (Version) => void;
 }
 
-function makeOverlayHelpIcon(background, helpIcon) {
-  return (
-    <div style={{position:"relative"}}>
-      {background}
-      <div style={{position: "absolute", top: 0, right: 0}}>
-        {helpIcon}
-      </div>
-    </div>
-  );
-}
-
 // Basically everything we need to construct the React components for:
 //  - Graph state (+ optionally, a Rountangle Editor)
 //  - History graph (+undo/redo buttons)
@@ -208,19 +223,19 @@ export function newVersionedModel({generateUUID, primitiveRegistry, readonly}) {
           primitiveRegistry={primitiveRegistry}
           setNextNodePosition={(newX,newY) => {x = newX; y = newY;}}
           onUserEdit={callbacks.onUserEdit}
-        />, readonly ? HelpIcons.graphEditorReadonly : HelpIcons.graphEditor);
+        />, readonly ? helpText.graphEditorReadonly : helpText.graphEditor);
 
     const depGraphL1Component = makeOverlayHelpIcon(
       <Graph graph={state.dependencyGraphL1} forces={graphForces} />,
-      HelpIcons.depGraph);
+      helpText.depGraph);
     const depGraphL0Component = makeOverlayHelpIcon(
       <Graph graph={state.dependencyGraphL0} forces={graphForces} />,
-      HelpIcons.depGraph);
+      helpText.depGraph);
 
     const historyComponent = makeOverlayHelpIcon(
       <Graph graph={state.historyGraph} forces={graphForces}
         mouseUpHandler={(e, {x, y}, node) => node ? callbacks.onVersionClicked?.(node.obj) : undefined} />,
-      HelpIcons.historyGraph);
+      helpText.historyGraph);
 
     const rountangleEditor = makeOverlayHelpIcon(
       <RountangleEditor
@@ -230,7 +245,7 @@ export function newVersionedModel({generateUUID, primitiveRegistry, readonly}) {
         graphState={graphState}
         onUserEdit={callbacks.onUserEdit}
       />,
-      HelpIcons.rountangleEditor);
+      helpText.rountangleEditor);
 
     const makeUndoOrRedoButton = (parentsOrChildren, text, leftIcon?, rightIcon?, callback?) => {
       if (parentsOrChildren.length === 0) {

+ 2 - 2
src/parser/trivial_parser.ts

@@ -248,7 +248,7 @@ export class TrivialParser  {
                 const otherGeometry = getGeometry(sourceState, otherNodeId);
                 if (otherGeometry === undefined || !isInside(updatedGeometry, otherGeometry)) {
                   // parent relation no longer holds
-                  console.log("deleting outgoing link...")
+                  // console.log("deleting outgoing link...")
                   // CORRECT: we'll find updatedAsNode's new parent in step 2.
                   const deleteLink = updatedAsNode.getDeltasForSetEdge(this.primitiveRegistry, "hasParent", null); // deletes the edge
                   applyToState(corrState, deleteLink);
@@ -304,7 +304,7 @@ export class TrivialParser  {
                       return otherCurrentParentGeometry.w * otherCurrentParentGeometry.h;
                     })();
                     if (updatedSurface < otherCurrentParentSurface) {
-                      console.log("updated geometry is on outside...");
+                      // console.log("updated geometry is on outside...");
                       const asParentLink = otherAsNode.getDeltasForSetEdge(this.primitiveRegistry, "hasParent", updatedAsNode.asTarget());
                       applyToState(corrState, asParentLink);
                       targetDeltas.push(...asParentLink);