jsketcher/web/app/cad/craft/wizard/wizardSelectionPlugin.ts
2022-06-25 15:19:48 -07:00

177 lines
5.4 KiB
TypeScript

import {FACE, SHELL} from 'cad/model/entities';
import {OperationRequest} from "cad/craft/craftPlugin";
import {FlattenPath, ParamsPath, WizardService} from "cad/craft/wizard/wizardTypes";
import {OperationParamValue} from "cad/craft/schema/schema";
import {EntityReference} from "cad/craft/operationPlugin";
import {ContextSpec, Plugin, Spec} from "plugable/pluginSystem";
import {MarkerPluginOutputContext} from "cad/scene/selectionMarker/markerPlugin";
import {WizardOutputContext} from "cad/craft/wizard/wizardPlugin";
import {PickControlOutputContext} from "cad/scene/controls/pickControlPlugin";
export type WizardSelectionInputContext = MarkerPluginOutputContext & WizardOutputContext & PickControlOutputContext;
export interface WizardSelectionOutputContext {
}
export type WizardSelectionContext = WizardSelectionInputContext & WizardSelectionOutputContext;
export const WizardSelectionPlugin: Plugin<WizardSelectionInputContext, WizardSelectionOutputContext, WizardSelectionContext> = {
inputContextSpec: {
markerService: 'required',
pickControlService: 'required',
wizardService: 'required'
},
outputContextSpec: {
},
activate(ctx: WizardSelectionContext) {
const wizardService = ctx.wizardService;
wizardService.workingRequest$.attach((opRequest: OperationRequest) => {
ctx.markerService.clear();
if (opRequest) {
const wizardPickHandler = createPickHandlerFromSchema(wizardService);
ctx.pickControlService.setPickHandler(wizardPickHandler);
const marker = ctx.markerService;
marker.startSession();
let {schemaIndex} = wizardService.operation;
schemaIndex.entities.forEach(entityRef => {
//TODO: move to uiDefinition
let color = entityRef.metadata.markColor;
let val = wizardService.readParam(entityRef.field.path);
if (Array.isArray(val)) {
val.forEach(id => marker.mark(id, color));
} else {
if (val) {
marker.mark(val, color);
}
}
});
marker.commit();
} else {
ctx.pickControlService.setPickHandler(null);
}
});
},
}
const singleValue = (id, current) => id;
const arrayValue = (id, arr) => {
if (!arr) {
return [id];
}
if (arr.indexOf(id) === -1) {
arr.push(id);
}
return arr;
};
function createPickHandlerFromSchema(wizardService: WizardService) {
function update(param: ParamsPath, value: OperationParamValue, paramToMakeActive: FlattenPath) {
wizardService.updateParam(param, value);
wizardService.updateState(state => {
state.activeParam = paramToMakeActive;
});
}
return model => {
const modelType = model.TYPE;
let {schemaIndex} = wizardService.operation;
let activeEntityRef = () => {
const state = wizardService.state$.value;
return schemaIndex.entitiesByFlattenedPaths[state.activeParam];
}
function activeCanTakeIt(kind) {
let activeRef: EntityReference = activeEntityRef();
if (!activeRef) {
return false;
}
const activeMd = activeRef?.metadata;
return activeMd && activeMd.allowedKinds.includes(kind);
}
function select(entityRef: EntityReference, id: string) {
const param = entityRef.field;
const valueGetter = entityRef.isArray ? arrayValue : singleValue;
let paramToMakeActive = getNextActiveParam(entityRef);
const currentValue = wizardService.readParam(param.path);
update(param.path, valueGetter(id, currentValue), paramToMakeActive.field.flattenedPath);
}
function getNextActiveParam(entityRef: EntityReference): EntityReference {
if (!entityRef.isArray) {
const index = schemaIndex.entities.indexOf(entityRef);
const nextIndex = (index + 1) % schemaIndex.entities.length;
return schemaIndex.entities[nextIndex];
}
return entityRef;
}
function selectActive(id: string) {
select(activeEntityRef(), id);
}
function selectToFirst(entity, id) {
for (let eRef of schemaIndex.entities) {
if (eRef.metadata.allowedKinds.includes(entity)) {
select(eRef, id);
}
}
return true;
}
function deselectIfNeeded(id) {
for (let entityRef of schemaIndex.entities) {
let val = wizardService.readParam(entityRef.field.path);
if (val === id) {
update(entityRef.field.path, undefined, entityRef.field.flattenedPath);
return true;
} else if (Array.isArray(val)) {
let index = val.indexOf(id);
if (index !== -1) {
val = val.slice(index, 1);
update(entityRef.field.path, val, entityRef.field.flattenedPath);
return true;
}
}
}
}
if (deselectIfNeeded(model.id)) {
return false;
} else if (model.shell) {
if (deselectIfNeeded(model.shell.id)) {
return false;
}
}
if (modelType === FACE) {
if (activeCanTakeIt(SHELL)) {
selectActive(model.shell.id);
} else if (activeCanTakeIt(FACE)) {
selectActive(model.id);
} else {
if (!selectToFirst(FACE, model.id)) {
selectToFirst(SHELL, model.shell.id)
}
}
} else{
if (activeCanTakeIt(modelType)) {
selectActive(model.id);
} else {
selectToFirst(modelType, model.id);
}
}
return false;
};
}