|
@@ -3,17 +3,26 @@ import * as Mantine from "@mantine/core";
|
|
|
import * as Icons from "@tabler/icons";
|
|
|
|
|
|
import {newVersionedModel, VersionedModelState} from "./versioned_model";
|
|
|
+import {emptyGraph, graphForces} from "./constants";
|
|
|
+import {ManualRendererProps} from "./manual_renderer";
|
|
|
+import {D3GraphStateUpdater} from "./d3_state";
|
|
|
import {TrivialParser} from "../parser/trivial_parser";
|
|
|
import {Version} from "../onion/version";
|
|
|
import {GraphState} from "../onion/graph_state";
|
|
|
import {CompositeDelta} from "../onion/composite_delta";
|
|
|
+import {PrimitiveDelta} from "../onion/primitive_delta";
|
|
|
|
|
|
// Pure function
|
|
|
// Replays all deltas in a version to compute the graph state of that version.
|
|
|
-function getGraphState(version: Version): GraphState {
|
|
|
+function getGraphState(version: Version, listener?): GraphState {
|
|
|
const graphState = new GraphState();
|
|
|
for (const d of [...version].reverse()) {
|
|
|
- graphState.exec(d);
|
|
|
+ if (listener !== undefined) {
|
|
|
+ graphState.exec(d, listener);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ graphState.exec(d);
|
|
|
+ }
|
|
|
}
|
|
|
return graphState;
|
|
|
}
|
|
@@ -42,40 +51,40 @@ export function newCorrespondence({generateUUID, primitiveRegistry, cs, as}) {
|
|
|
redo,
|
|
|
} = getReducerOrig(setCorrState);
|
|
|
|
|
|
- const parse = (csDeltas, description: string) => {
|
|
|
- const csParentVersion = cs.getCurrentVersion();
|
|
|
- const corrParentVersion = parseMap.get(csParentVersion)!;
|
|
|
- const asParentVersion = corrMap.get(corrParentVersion)!.asVersion;
|
|
|
+ // const parse = (csDeltas, description: string) => {
|
|
|
+ // const csParentVersion = cs.getCurrentVersion();
|
|
|
+ // const corrParentVersion = parseMap.get(csParentVersion)!;
|
|
|
+ // const asParentVersion = corrMap.get(corrParentVersion)!.asVersion;
|
|
|
|
|
|
- const [csGS, corrGS, asGS] = [csParentVersion, corrParentVersion, asParentVersion].map(getGraphState);
|
|
|
+ // const [csGS, corrGS, asGS] = [csParentVersion, corrParentVersion, asParentVersion].map(getGraphState);
|
|
|
|
|
|
- const {corrDeltas, asDeltas} = parser.parse(csDeltas, csGS, corrGS, asGS);
|
|
|
+ // const {corrDeltas, asDeltas} = parser.parse(csDeltas, csGS, corrGS, asGS); // may throw MissingInformation
|
|
|
|
|
|
- const csVersion = csReducer.createAndGotoNewVersion(csDeltas, description);
|
|
|
- const corrVersion = createAndGotoNewVersion(corrDeltas, "cs:"+description, corrParentVersion);
|
|
|
- const asVersion = asDeltas.length > 0 ? asReducer.createAndGotoNewVersion(asDeltas, "parse:"+description, asParentVersion) : asParentVersion;
|
|
|
+ // const csVersion = csReducer.createAndGotoNewVersion(csDeltas, description);
|
|
|
+ // const corrVersion = createAndGotoNewVersion(corrDeltas, "cs:"+description, corrParentVersion);
|
|
|
+ // const asVersion = asDeltas.length > 0 ? asReducer.createAndGotoNewVersion(asDeltas, "parse:"+description, asParentVersion) : asParentVersion;
|
|
|
|
|
|
- corrMap.set(corrVersion, {csVersion, asVersion});
|
|
|
- parseMap.set(csVersion, corrVersion);
|
|
|
- renderMap.set(asVersion, corrVersion);
|
|
|
- };
|
|
|
- const render = (asDeltas, description: string) => {
|
|
|
- const asParentVersion = as.getCurrentVersion();
|
|
|
- const corrParentVersion = renderMap.get(asParentVersion)!;
|
|
|
- const csParentVersion = corrMap.get(corrParentVersion)!.csVersion;
|
|
|
+ // corrMap.set(corrVersion, {csVersion, asVersion});
|
|
|
+ // parseMap.set(csVersion, corrVersion);
|
|
|
+ // renderMap.set(asVersion, corrVersion);
|
|
|
+ // };
|
|
|
+ // const render = (asDeltas, description: string) => {
|
|
|
+ // const asParentVersion = as.getCurrentVersion();
|
|
|
+ // const corrParentVersion = renderMap.get(asParentVersion)!;
|
|
|
+ // const csParentVersion = corrMap.get(corrParentVersion)!.csVersion;
|
|
|
|
|
|
- const [csGS, corrGS, asGS] = [csParentVersion, corrParentVersion, asParentVersion].map(getGraphState);
|
|
|
+ // const [csGS, corrGS, asGS] = [csParentVersion, corrParentVersion, asParentVersion].map(getGraphState);
|
|
|
|
|
|
- const {corrDeltas, csDeltas} = parser.render(asDeltas, csGS, corrGS, asGS);
|
|
|
+ // const {corrDeltas, csDeltas} = parser.render(asDeltas, csGS, corrGS, asGS);
|
|
|
|
|
|
- const csVersion = csDeltas.length > 0 ? csReducer.createAndGotoNewVersion(csDeltas, "render:"+description) : csParentVersion;
|
|
|
- const corrVersion = createAndGotoNewVersion(corrDeltas, "as:"+description);
|
|
|
- const asVersion = asReducer.createAndGotoNewVersion(asDeltas, description);
|
|
|
+ // const csVersion = csDeltas.length > 0 ? csReducer.createAndGotoNewVersion(csDeltas, "render:"+description) : csParentVersion;
|
|
|
+ // const corrVersion = createAndGotoNewVersion(corrDeltas, "as:"+description);
|
|
|
+ // const asVersion = asReducer.createAndGotoNewVersion(asDeltas, description);
|
|
|
|
|
|
- corrMap.set(corrVersion, {csVersion, asVersion});
|
|
|
- parseMap.set(csVersion, corrVersion);
|
|
|
- renderMap.set(asVersion, corrVersion);
|
|
|
- };
|
|
|
+ // corrMap.set(corrVersion, {csVersion, asVersion});
|
|
|
+ // parseMap.set(csVersion, corrVersion);
|
|
|
+ // renderMap.set(asVersion, corrVersion);
|
|
|
+ // };
|
|
|
const parseExistingVersion = (csVersion: Version) => {
|
|
|
for (const [csParentVersion, compositeDelta] of csVersion.parents) {
|
|
|
|
|
@@ -97,7 +106,7 @@ export function newCorrespondence({generateUUID, primitiveRegistry, cs, as}) {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- const [csGS, corrGS, asGS] = [csParentVersion, corrParentVersion, asParentVersion].map(getGraphState);
|
|
|
+ const [csGS, corrGS, asGS] = [csParentVersion, corrParentVersion, asParentVersion].map(v => getGraphState(v));
|
|
|
|
|
|
const {corrDeltas, asDeltas} = parser.parse(csDeltas, csGS, corrGS, asGS);
|
|
|
const corrVersion = createAndGotoNewVersion(corrDeltas, "cs:"+description, corrParentVersion);
|
|
@@ -108,14 +117,14 @@ export function newCorrespondence({generateUUID, primitiveRegistry, cs, as}) {
|
|
|
renderMap.set(asVersion, corrVersion);
|
|
|
}
|
|
|
};
|
|
|
- const renderExistingVersion = (asVersion: Version) => {
|
|
|
+ const renderExistingVersion = (asVersion: Version, manualRenderCallback) => {
|
|
|
for (const [asParentVersion, compositeDelta] of asVersion.parents) {
|
|
|
|
|
|
const asDeltas = (compositeDelta as CompositeDelta).deltas;
|
|
|
const description = compositeDelta.getDescription();
|
|
|
|
|
|
if (!renderMap.has(asParentVersion)) {
|
|
|
- renderExistingVersion(asParentVersion);
|
|
|
+ renderExistingVersion(asParentVersion, manualRenderCallback);
|
|
|
}
|
|
|
|
|
|
const corrParentVersion = renderMap.get(asParentVersion);
|
|
@@ -129,15 +138,44 @@ export function newCorrespondence({generateUUID, primitiveRegistry, cs, as}) {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- const [csGS, corrGS, asGS] = [csParentVersion, corrParentVersion, asParentVersion].map(getGraphState);
|
|
|
+ const [csGS, corrGS, asGS] = [csParentVersion, corrParentVersion, asParentVersion].map(v => getGraphState(v));
|
|
|
|
|
|
- const {corrDeltas, csDeltas} = parser.render(asDeltas, csGS, corrGS, asGS);
|
|
|
- const corrVersion = createAndGotoNewVersion(corrDeltas, "as:"+description, corrParentVersion);
|
|
|
- const csVersion = csDeltas.length > 0 ? csReducer.createAndGotoNewVersion(csDeltas, "parse:"+description, csParentVersion) : asParentVersion;
|
|
|
+ const {corrDeltas, csDeltas, complete} = parser.render(asDeltas, csGS, corrGS, asGS);
|
|
|
|
|
|
- corrMap.set(corrVersion, {csVersion, asVersion});
|
|
|
- parseMap.set(csVersion, corrVersion);
|
|
|
- renderMap.set(asVersion, corrVersion);
|
|
|
+ function finishRender({corrDeltas, csDeltas}) {
|
|
|
+ const corrVersion = createAndGotoNewVersion(corrDeltas, "as:"+description, corrParentVersion);
|
|
|
+ const csVersion = csDeltas.length > 0 ? csReducer.createAndGotoNewVersion(csDeltas, "parse:"+description, csParentVersion) : csParentVersion;
|
|
|
+
|
|
|
+ corrMap.set(corrVersion, {csVersion, asVersion});
|
|
|
+ parseMap.set(csVersion, corrVersion);
|
|
|
+ renderMap.set(asVersion, corrVersion);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (complete) {
|
|
|
+ finishRender({corrDeltas, csDeltas});
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ function getD3State(version: Version, additionalDeltas: PrimitiveDelta[] = []) {
|
|
|
+ let graph = emptyGraph;
|
|
|
+ const setGraph = callback => (graph = callback(graph));
|
|
|
+ const d3Updater = new D3GraphStateUpdater(setGraph, 0, 0);
|
|
|
+ const graphState = getGraphState(version, d3Updater);
|
|
|
+ for (const d of additionalDeltas) {
|
|
|
+ graphState.exec(d, d3Updater);
|
|
|
+ }
|
|
|
+ return {graph, graphState};
|
|
|
+ }
|
|
|
+
|
|
|
+ const {graph: asGraph} = getD3State(asVersion);
|
|
|
+ const {graph: csParentGraph, graphState: csParentGraphState} = getD3State(csParentVersion, csDeltas);
|
|
|
+
|
|
|
+ manualRenderCallback({asGraph, csParentGraph, csParentGraphState, asDeltasToRender: asDeltas})
|
|
|
+ .then(additionalCsDeltas => {
|
|
|
+ finishRender({corrDeltas, csDeltas: csDeltas.concat(additionalCsDeltas)});
|
|
|
+ })
|
|
|
+ .catch();
|
|
|
+ }
|
|
|
}
|
|
|
};
|
|
|
const gotoVersion = (corrVersion: Version) => {
|
|
@@ -146,6 +184,18 @@ export function newCorrespondence({generateUUID, primitiveRegistry, cs, as}) {
|
|
|
gotoVersionOrig(corrVersion);
|
|
|
asReducer.gotoVersion(asVersion);
|
|
|
};
|
|
|
+ const getManualRenderCallback = (setManualRendererState) => {
|
|
|
+ return props => {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ setManualRendererState({
|
|
|
+ ...props,
|
|
|
+ resolve,
|
|
|
+ reject,
|
|
|
+ });
|
|
|
+ })
|
|
|
+ .finally(() => setManualRendererState(null));
|
|
|
+ }
|
|
|
+ }
|
|
|
const getParseButton = (csVersion, dir: "left"|"right" = "right") => {
|
|
|
return <Mantine.Button compact
|
|
|
disabled={parseMap.has(csVersion)}
|
|
@@ -154,10 +204,10 @@ export function newCorrespondence({generateUUID, primitiveRegistry, cs, as}) {
|
|
|
leftIcon={dir === "left" ? <Icons.IconChevronsLeft/>: null}
|
|
|
>Parse</Mantine.Button>;
|
|
|
};
|
|
|
- const getRenderButton = (asVersion, dir: "left"|"right" = "left") => {
|
|
|
+ const getRenderButton = (asVersion, setManualRendererState, dir: "left"|"right" = "left") => {
|
|
|
return <Mantine.Button compact
|
|
|
disabled={renderMap.has(asVersion)}
|
|
|
- onClick={() => renderExistingVersion(asVersion)}
|
|
|
+ onClick={() => renderExistingVersion(asVersion, getManualRenderCallback(setManualRendererState))}
|
|
|
rightIcon={dir === "right" ? <Icons.IconChevronsRight/>: null}
|
|
|
leftIcon={dir === "left" ? <Icons.IconChevronsLeft/>: null}
|
|
|
>Render</Mantine.Button>;
|
|
@@ -176,13 +226,13 @@ export function newCorrespondence({generateUUID, primitiveRegistry, cs, as}) {
|
|
|
return <Mantine.Group>{sw}{button}</Mantine.Group>;
|
|
|
}
|
|
|
};
|
|
|
- const getCaptionWithRenderButton = (autoRenderState, setAutoRenderState, asVersion, dir: "left"|"right" = "left") => {
|
|
|
+ const getCaptionWithRenderButton = (autoRenderState, setAutoRenderState, asVersion, setManualRendererState, dir: "left"|"right" = "left") => {
|
|
|
const sw = <Mantine.Switch label="Auto"
|
|
|
labelPosition={dir}
|
|
|
checked={autoRenderState}
|
|
|
onChange={(event) => setAutoRenderState(event.currentTarget.checked)}
|
|
|
/>
|
|
|
- const button = getRenderButton(asVersion, dir);
|
|
|
+ const button = getRenderButton(asVersion, setManualRendererState, dir);
|
|
|
if (dir === "left") {
|
|
|
return <Mantine.Group>{button}{sw}</Mantine.Group>;
|
|
|
}
|
|
@@ -192,8 +242,6 @@ export function newCorrespondence({generateUUID, primitiveRegistry, cs, as}) {
|
|
|
};
|
|
|
|
|
|
return {
|
|
|
- parse,
|
|
|
- render,
|
|
|
parseExistingVersion,
|
|
|
renderExistingVersion,
|
|
|
gotoVersion,
|