diff --git a/modules/gems/func.js b/modules/gems/func.js
index 33f334bf..94fe8bb0 100644
--- a/modules/gems/func.js
+++ b/modules/gems/func.js
@@ -1 +1,18 @@
-export const NOOP = () => {};
\ No newline at end of file
+export const NOOP = () => {};
+
+export function createFunctionList() {
+ const fnList = [];
+ const add = fn => fnList.push(fn);
+ const call = () => {
+ fnList.forEach(fn => {
+ try {
+ fn();
+ } catch(e) {
+ console.error(e);
+ }
+ });
+ };
+ return {
+ add, call
+ }
+}
\ No newline at end of file
diff --git a/web/app/cad/craft/wizard/components/Wizard.jsx b/web/app/cad/craft/wizard/components/Wizard.jsx
index bdbe5ec4..80fbc880 100644
--- a/web/app/cad/craft/wizard/components/Wizard.jsx
+++ b/web/app/cad/craft/wizard/components/Wizard.jsx
@@ -8,27 +8,26 @@ import ls from './Wizard.less';
import CadError from '../../../../utils/errors';
import {FormContext} from './form/Form';
import connect from 'ui/connect';
-import mapContext from 'ui/mapContext';
+import {combine} from 'lstream';
-@connect(streams => streams.wizard.workingRequest)
-@mapContext(ctx => ({
- updateParam: (name, value) => {
- let workingRequest$ = ctx.streams.wizard.workingRequest;
- if (workingRequest$.value.params && workingRequest$.value.type) {
- workingRequest$.mutate(data => {
- data.params[name] = value;
- data.state.activeParam = name;
- })
- }
- },
- setActiveParam: name => ctx.streams.wizard.workingRequest.mutate(data => data.state && (data.state.activeParam = name))
-}))
+@connect((streams, props) => combine(props.context.workingRequest$, props.context.state$)
+ .map(([workingRequest, state]) => ({
+ ...workingRequest,
+ activeParam: state.activeParam
+ })))
export default class Wizard extends React.Component {
state = {
hasError: false,
};
+ updateParam = (name, value) => {
+ this.props.context.updateParams(params => params[name] = value);
+ };
+
+ setActiveParam = param => {
+ this.props.context.updateState(state => state.activeParam = param);
+ };
componentDidCatch() {
this.setState({hasInternalError: true});
@@ -39,24 +38,16 @@ export default class Wizard extends React.Component {
return operation error;
}
- let {left, type, params, state, resolveOperation, updateParam, setActiveParam} = this.props;
- if (!type) {
- return null;
- }
-
- let operation = resolveOperation(type);
- if (!operation) {
- console.error('unknown operation ' + type);
- return null;
- }
+ let {left, type, params, state, context} = this.props;
+ let operation = context.operation;
let title = (operation.label || type).toUpperCase();
let formContext = {
data: params,
- activeParam: state.activeParam,
- setActiveParam,
- updateParam
+ activeParam: this.props.activeParam,
+ setActiveParam: this.setActiveParam,
+ updateParam: this.updateParam
};
let Form = operation.form;
@@ -127,7 +118,7 @@ export default class Wizard extends React.Component {
let {code, userMessage, kind} = error;
printError = !code;
if (CadError.ALGORITMTHM_ERROR_KINDS.includes(kind)) {
- stateUpdate.algorithmError = true
+ stateUpdate.algorithmError = true;
}
if (code && kind === CadError.KIND.INTERNAL_ERROR) {
console.warn('Operation Error Code: ' + code);
diff --git a/web/app/cad/craft/wizard/components/WizardManager.jsx b/web/app/cad/craft/wizard/components/WizardManager.jsx
index 43bba870..8f6e4d11 100644
--- a/web/app/cad/craft/wizard/components/WizardManager.jsx
+++ b/web/app/cad/craft/wizard/components/WizardManager.jsx
@@ -3,23 +3,21 @@ import Wizard from './Wizard';
import connect from 'ui/connect';
import decoratorChain from 'ui/decoratorChain';
import mapContext from 'ui/mapContext';
-import {finishHistoryEditing} from '../../craftHistoryUtils';
-function WizardManager({type, changingHistory, resolve, cancel, stepHistory, insertOperation, cancelHistoryEdit, applyWorkingRequest}) {
- if (!type) {
+function WizardManager({wizardContext, type, changingHistory, cancel, cancelHistoryEdit, applyWorkingRequest}) {
+ if (!wizardContext) {
return null;
}
- return
}
export default decoratorChain(
- connect(streams => streams.wizard.effectiveOperation),
- mapContext((ctx, props) => ({
+ connect(streams => streams.wizard.wizardContext.map(wizardContext => ({wizardContext}))),
+ mapContext(ctx => ({
cancel: ctx.services.wizard.cancel,
- resolve: type => ctx.services.operation.get(type),
- cancelHistoryEdit: () => ctx.streams.craft.modifications.update(modifications => finishHistoryEditing(modifications)),
applyWorkingRequest: ctx.services.wizard.applyWorkingRequest
}))
)
diff --git a/web/app/cad/craft/wizard/wizardPlugin.js b/web/app/cad/craft/wizard/wizardPlugin.js
index 9ae104d6..7b766ca7 100644
--- a/web/app/cad/craft/wizard/wizardPlugin.js
+++ b/web/app/cad/craft/wizard/wizardPlugin.js
@@ -1,7 +1,8 @@
-import {stream, state} from 'lstream';
+import {state} from 'lstream';
import initializeBySchema from '../intializeBySchema';
import {clone, EMPTY_OBJECT} from 'gems/objects';
import materializeParams from '../materializeParams';
+import {createFunctionList} from 'gems/func';
export function activate(ctx) {
@@ -46,12 +47,12 @@ export function activate(ctx) {
gotoEditHistoryModeIfNeeded(mod);
});
- streams.wizard.workingRequestChanged = stream();
-
- streams.wizard.workingRequest = streams.wizard.effectiveOperation.map(opRequest => {
- let request = EMPTY_OBJECT;
+ streams.wizard.wizardContext = streams.wizard.effectiveOperation.map(opRequest => {
+ let wizCtx = null;
if (opRequest.type) {
+
let operation = ctx.services.operation.get(opRequest.type);
+
let params;
if (opRequest.changingHistory) {
params = clone(opRequest.params)
@@ -61,34 +62,45 @@ export function activate(ctx) {
applyOverrides(params, opRequest.initialOverrides);
}
}
- request = {
+
+ let workingRequest$ = state({
type: opRequest.type,
- params,
- state: {}
- };
- }
- streams.wizard.workingRequestChanged.next(request);
- return request
- }).remember(EMPTY_OBJECT);
-
- streams.wizard.materializedWorkingRequest = streams.wizard.workingRequest.map(req => {
- if (req.type) {
- let operation = ctx.services.operation.get(req.type);
- let params = {};
- let errors = [];
- materializeParams(ctx.services, req.params, operation.schema, params, errors, []);
- if (errors.length !== 0) {
- console.log(errors);
- return INVALID_REQUEST;
- }
- return {
- type: req.type,
params
+ });
+
+ let materializedWorkingRequest$ = workingRequest$.map(req => {
+ let params = {};
+ let errors = [];
+ materializeParams(ctx.services, req.params, operation.schema, params, errors, []);
+ if (errors.length !== 0) {
+ console.log(errors);
+ return INVALID_REQUEST;
+ }
+ return {
+ type: req.type,
+ params
+ };
+ }).filter(r => r !== INVALID_REQUEST).remember();
+ const state$ = state({});
+ const updateParams = mutator => workingRequest$.mutate(data => mutator(data.params));
+ const updateState = mutator => state$.mutate(state => mutator(state));
+ const disposerList = createFunctionList();
+ wizCtx = {
+ workingRequest$, materializedWorkingRequest$, state$, operation, updateParams, updateState,
+ addDisposer: disposerList.add,
+ dispose: disposerList.call,
+ ID: ++REQUEST_COUNTER,
};
}
- return EMPTY_OBJECT;
- }).filter(r => r !== INVALID_REQUEST).remember();
+ return wizCtx;
+ }).remember(null);
+ streams.wizard.wizardContext.pairwise().attach(([oldContext, newContext]) => {
+ if (oldContext) {
+ oldContext.dispose();
+ }
+ });
+
services.wizard = {
open: (type, initialOverrides) => {
@@ -104,7 +116,7 @@ export function activate(ctx) {
},
applyWorkingRequest: () => {
- let {type, params} = streams.wizard.workingRequest.value;
+ let {type, params} = streams.wizard.wizardContext.value.workingRequest$.value;
let request = clone({type, params});
if (streams.wizard.insertOperation.value.type) {
ctx.services.craft.modify(request, () => streams.wizard.insertOperation.value = EMPTY_OBJECT);
@@ -119,4 +131,5 @@ function applyOverrides(params, initialOverrides) {
Object.assign(params, initialOverrides);
}
-const INVALID_REQUEST = {};
\ No newline at end of file
+const INVALID_REQUEST = {};
+let REQUEST_COUNTER = 0;
\ No newline at end of file
diff --git a/web/app/cad/craft/wizard/wizardSelectionPlugin.js b/web/app/cad/craft/wizard/wizardSelectionPlugin.js
index 1cddee32..f359f9b6 100644
--- a/web/app/cad/craft/wizard/wizardSelectionPlugin.js
+++ b/web/app/cad/craft/wizard/wizardSelectionPlugin.js
@@ -1,37 +1,34 @@
-import {DATUM, EDGE, FACE, SHELL, SKETCH_OBJECT} from '../../scene/entites';
+import {EDGE, FACE, SHELL, SKETCH_OBJECT} from '../../scene/entites';
export function activate(ctx) {
- const wizardPickHandler = createPickHandlerFromSchema(ctx);
-
- ctx.streams.wizard.workingRequestChanged.attach(({type, params}) => {
+ ctx.streams.wizard.wizardContext.attach(wizCtx => {
ctx.services.marker.clear();
- if (type) {
+ if (wizCtx) {
+ const wizardPickHandler = createPickHandlerFromSchema(wizCtx);
ctx.services.pickControl.setPickHandler(wizardPickHandler);
+ wizCtx.workingRequest$.attach(({type, params}) => {
+ const marker = ctx.services.marker;
+ marker.startSession();
+ let {schema, schemaIndex} = wizCtx.operation;
+ schemaIndex.entityParams.forEach(param => {
+ let color = schema[param].markColor;
+ let val = params[param];
+ let entity = schemaIndex.entitiesByParam[param];
+ if (Array.isArray(val)) {
+ val.forEach(id => marker.mark(entity, id, color));
+ } else {
+ if (val) {
+ marker.mark(entity, val, color);
+ }
+ }
+ });
+ marker.commit();
+ });
+
} else {
ctx.services.pickControl.setPickHandler(null);
}
});
-
- ctx.streams.wizard.workingRequest.attach(({type, params}) => {
- const marker = ctx.services.marker;
- marker.startSession();
- if (type && params) {
- let {schema, schemaIndex} = ctx.services.operation.get(type);
- schemaIndex.entityParams.forEach(param => {
- let color = schema[param].markColor;
- let val = params[param];
- let entity = schemaIndex.entitiesByParam[param];
- if (Array.isArray(val)) {
- val.forEach(id => marker.mark(entity, id, color));
- } else {
- if (val) {
- marker.mark(entity, val, color);
- }
- }
- });
- }
- marker.commit();
- });
}
const singleUpdater = (params, param, id) => params[param] = id;
@@ -45,11 +42,20 @@ const arrayUpdater = (params, param, id) => {
}
};
-function createPickHandlerFromSchema(ctx) {
+function createPickHandlerFromSchema(wizCtx) {
+ function update(paramsMutator, paramToMakeActive) {
+ wizCtx.updateParams(paramsMutator);
+ wizCtx.updateState(state => {
+ state.activeParam = paramToMakeActive;
+ });
+ }
return model => {
const modelType = model.TYPE;
- const {type: opType, state, params} = ctx.streams.wizard.workingRequest.value;
- let {schema, schemaIndex} = ctx.services.operation.get(opType);
+
+ const params = wizCtx.workingRequest$.value.params;
+ const state = wizCtx.state$.value;
+
+ let {schema, schemaIndex} = wizCtx.operation;
const {entitiesByType, entitiesByParam, entityParams} = schemaIndex;
const activeMd = state.activeParam && schema[state.activeParam];
@@ -58,15 +64,14 @@ function createPickHandlerFromSchema(ctx) {
function select(param, entity, md, id) {
const updater = md.type === 'array' ? arrayUpdater : singleUpdater;
let paramToMakeActive = getNextActiveParam(param, md);
- ctx.streams.wizard.workingRequest.mutate(r => {
- updater(r.params, param, id);
- r.state.activeParam = paramToMakeActive;
- });
+ update(params => {
+ updater(params, param, id);
+ }, paramToMakeActive);
}
function getNextActiveParam(currParam, currMd) {
if (currMd.type !== 'array') {
- let entityGroup = entitiesByType[currMd.type];
+ let entityGroup = entitiesByType[activeEntity];
if (entityGroup) {
const index = entityGroup.indexOf(currParam);
const nextIndex = (index + 1) % entityGroup.length;
@@ -93,23 +98,20 @@ function createPickHandlerFromSchema(ctx) {
for (let param of entityParams) {
let val = params[param];
if (val === id) {
- ctx.streams.wizard.workingRequest.mutate(r => {
- r.params[param] = undefined;
- r.state.activeParam = param;
- });
+ update(params => {
+ params[param] = undefined;
+ }, param);
return true;
} else if (Array.isArray(val)) {
let index = val.indexOf(id);
if (index !== -1) {
- ctx.streams.wizard.workingRequest.mutate(r => {
- r.params[param].splice(index, 1);
- r.state.activeParam = param;
- });
+ update(params => {
+ params[param].splice(index, 1)
+ }, param);
return true;
}
}
}
-
}
if (deselectIfNeeded(model.id)) {
@@ -142,12 +144,6 @@ function createPickHandlerFromSchema(ctx) {
} else {
selectToFirst(EDGE, model.id);
}
- } else if (modelType === DATUM) {
- if (activeEntity === DATUM) {
- selectActive(model.id);
- } else {
- selectToFirst(DATUM, model.id);
- }
}
return false;
};
diff --git a/web/app/cad/preview/previewPlugin.js b/web/app/cad/preview/previewPlugin.js
index 78344a8a..e96d03c5 100644
--- a/web/app/cad/preview/previewPlugin.js
+++ b/web/app/cad/preview/previewPlugin.js
@@ -3,46 +3,29 @@ import {createPreviewer} from './scenePreviewer';
export function activate(ctx) {
let {streams, services} = ctx;
- const updateParams = mutator => streams.wizard.workingRequest.mutate(data => mutator(data.params));
-
- let previewContext = {
- operation: null,
- previewer: null
- };
-
- streams.wizard.materializedWorkingRequest.attach(({type, params}) => {
- if (!type) {
- if (previewContext.previewer) {
- previewContext.previewer.dispose();
- previewContext.previewer = null;
- previewContext.operation = null;
- ctx.services.viewer.requestRender();
- }
+ streams.wizard.wizardContext.attach(wizCtx => {
+ if (!wizCtx) {
return;
}
- if (type !== previewContext.operation) {
- if (previewContext.previewer != null) {
- previewContext.previewer.dispose();
+ let {operation, materializedWorkingRequest$} = wizCtx;
+ if (operation.previewGeomProvider || operation.previewer) {
+ let previewer = null;
+ materializedWorkingRequest$.attach(({type, params}) => {
+ if (previewer === null) {
+ if (operation.previewGeomProvider) {
+ previewer = createPreviewer(operation.previewGeomProvider, services, params);
+ } else if (operation.previewer) {
+ previewer = operation.previewer(ctx, params, wizCtx.updateParams);
+ }
+ wizCtx.addDisposer(() => {
+ previewer.dispose();
+ ctx.services.viewer.requestRender();
+ });
+ } else {
+ previewer.update(params);
+ }
ctx.services.viewer.requestRender();
- previewContext.previewer = null;
- }
- let operation = services.operation.get(type);
-
- if (operation.previewGeomProvider) {
- previewContext.previewer = createPreviewer(operation.previewGeomProvider, services, params);
- ctx.services.viewer.requestRender();
- } else if (operation.previewer) {
- previewContext.previewer = operation.previewer(ctx, params, updateParams);
- ctx.services.viewer.requestRender();
- } else {
- previewContext.previewer = null;
- }
- previewContext.operation = type;
- } else {
- if (previewContext.previewer) {
- previewContext.previewer.update(params);
- ctx.services.viewer.requestRender();
- }
+ });
}
});
}
\ No newline at end of file
diff --git a/web/app/cad/scene/selectionMarker/markerPlugin.js b/web/app/cad/scene/selectionMarker/markerPlugin.js
index 028d6259..aa45bcc8 100644
--- a/web/app/cad/scene/selectionMarker/markerPlugin.js
+++ b/web/app/cad/scene/selectionMarker/markerPlugin.js
@@ -21,6 +21,9 @@ function createMarker(findEntity, requestRender) {
function doMark(entity, id, color) {
let mObj = findEntity(entity, id);
+ if (!mObj) {
+ throw 'illegal state';
+ }
marked.set(id, mObj);
mObj.ext.view && mObj.ext.view.mark(color);
}