mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-10 10:25:36 +01:00
localize workingParams to wizard context
This commit is contained in:
parent
1df6de49a5
commit
b4305c5a16
7 changed files with 154 additions and 153 deletions
|
|
@ -1 +1,18 @@
|
|||
export const NOOP = () => {};
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
@ -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 <span>operation error</span>;
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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 <Wizard resolveOperation={resolve}
|
||||
return <Wizard key={wizardContext.ID}
|
||||
context={wizardContext}
|
||||
onCancel={changingHistory ? cancelHistoryEdit : cancel}
|
||||
onOK={applyWorkingRequest} />
|
||||
}
|
||||
|
||||
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
|
||||
}))
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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 = {};
|
||||
const INVALID_REQUEST = {};
|
||||
let REQUEST_COUNTER = 0;
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue