diff --git a/modules/ui/components/ImgIcon.jsx b/modules/ui/components/ImgIcon.tsx similarity index 61% rename from modules/ui/components/ImgIcon.jsx rename to modules/ui/components/ImgIcon.tsx index ad6f9b76..f7c8d8eb 100644 --- a/modules/ui/components/ImgIcon.jsx +++ b/modules/ui/components/ImgIcon.tsx @@ -1,6 +1,11 @@ import React from 'react'; -export default function ImgIcon({url, size, style, ...props}) { +type ImgIconParams = { url: string; size: string|number; style?: any; }; + +export default function ImgIcon(inprops: ImgIconParams) { + + const {url, size, style, ...props} = inprops; + return -}; \ No newline at end of file +} \ No newline at end of file diff --git a/modules/workbenches/modeler/features/boolean_tool/boolean.operation.ts b/modules/workbenches/modeler/features/boolean_tool/boolean.operation.ts index 9d9ee51e..58a247a1 100644 --- a/modules/workbenches/modeler/features/boolean_tool/boolean.operation.ts +++ b/modules/workbenches/modeler/features/boolean_tool/boolean.operation.ts @@ -1,23 +1,20 @@ -import { roundValueForPresentation as r } from 'cad/craft/operationHelper'; -import { MFace } from "cad/model/mface"; -import { ApplicationContext } from "context"; -import { MDFCommand } from "cad/mdf/mdf"; -import { EntityKind } from "cad/model/entities"; -import Vector from "math/vector"; -import { BooleanDefinition } from "cad/craft/schema/common/BooleanDefinition"; -import { MShell } from 'cad/model/mshell'; +import {roundValueForPresentation as r} from 'cad/craft/operationHelper'; +import {ApplicationContext} from "context"; +import {EntityKind} from "cad/model/entities"; +import {BooleanDefinition} from "cad/craft/schema/common/BooleanDefinition"; +import {OperationDescriptor} from "cad/craft/operationPlugin"; interface BooleanParams { tools: []; boolean: BooleanDefinition } -const BooleanOperation: MDFCommand = { +const BooleanOperation: OperationDescriptor = { id: 'boolean_tool', label: 'Boolean', icon: 'img/cad/Boolean', info: 'Booleans 2D sketch', - paramsInfo: ({ tools, boolean }) => `(${r(tools)} ${r(boolean)})`, + paramsInfo: ({tools, boolean}) => `(${r(tools)} ${r(boolean)})`, run: (params: BooleanParams, ctx: ApplicationContext) => { console.log(params); let occ = ctx.occService; diff --git a/modules/workbenches/modeler/features/extrude/extrude.operation.ts b/modules/workbenches/modeler/features/extrude/extrude.operation.ts index 1844a32e..1ab77cf4 100644 --- a/modules/workbenches/modeler/features/extrude/extrude.operation.ts +++ b/modules/workbenches/modeler/features/extrude/extrude.operation.ts @@ -1,10 +1,10 @@ import {roundValueForPresentation as r} from 'cad/craft/operationHelper'; import {MFace} from "cad/model/mface"; import {ApplicationContext} from "context"; -import {MDFCommand} from "cad/mdf/mdf"; import {EntityKind} from "cad/model/entities"; import {BooleanDefinition} from "cad/craft/schema/common/BooleanDefinition"; import {UnitVector} from "math/vector"; +import {OperationDescriptor} from "cad/craft/operationPlugin"; interface ExtrudeParams { @@ -14,13 +14,12 @@ interface ExtrudeParams { boolean: BooleanDefinition } -const ExtrudeOperation: MDFCommand = { +const ExtrudeOperation: OperationDescriptor = { id: 'EXTRUDE', label: 'Extrude', icon: 'img/cad/extrude', info: 'extrudes 2D sketch', paramsInfo: ({length}) => `(${r(length)})`, - mutualExclusiveFields: ['datumAxisVector', 'edgeVector', 'sketchSegmentVector'], run: (params: ExtrudeParams, ctx: ApplicationContext) => { let occ = ctx.occService; diff --git a/modules/workbenches/modeler/features/hole_tool/index.ts b/modules/workbenches/modeler/features/hole_tool/index.ts index a0c25e0a..a186cc10 100644 --- a/modules/workbenches/modeler/features/hole_tool/index.ts +++ b/modules/workbenches/modeler/features/hole_tool/index.ts @@ -1,137 +1,140 @@ -import { roundValueForPresentation as r } from 'cad/craft/operationHelper'; -import { MFace } from "cad/model/mface"; -import { ApplicationContext } from "context"; -import { MDFCommand } from "cad/mdf/mdf"; -import { EntityKind } from "cad/model/entities"; +import {roundValueForPresentation as r} from 'cad/craft/operationHelper'; +import {ApplicationContext} from "context"; +import {EntityKind} from "cad/model/entities"; +import {OperationDescriptor} from "cad/craft/operationPlugin"; interface HoleParams { - diameter: number; - depth: number; - counterBoreDiameter: number; - counterBoreDepth: number; - countersinkDiameter: number; - countersinkAngle: number; - holeType: string; + diameter: number; + depth: number; + counterBoreDiameter: number; + counterBoreDepth: number; + countersinkDiameter: number; + countersinkAngle: number; + holeType: string; } -const HoleOperation: MDFCommand = { - id: 'hole_tool', - label: 'hole', - icon: 'img/cad/Shell', - info: 'creates hole features', - paramsInfo: ({ diameter, depth, counterBoreDiameter, counterBoreDepth, countersinkDiameter, countersinkAngle, holeType, }) => `(${r(depth)} ${r(counterBoreDiameter)}) ${r(counterBoreDepth)})`, +const HoleOperation: OperationDescriptor = { + id: 'hole_tool', + label: 'hole', + icon: 'img/cad/Shell', + info: 'creates hole features', + paramsInfo: ({ + diameter, + depth, + counterBoreDiameter, + counterBoreDepth, + countersinkDiameter, + countersinkAngle, + holeType, + }) => `(${r(depth)} ${r(counterBoreDiameter)}) ${r(counterBoreDepth)})`, - run: (params: HoleParams, ctx: ApplicationContext) => { - console.log(params); - let occ = ctx.occService; - const oci = occ.commandInterface; + run: (params: HoleParams, ctx: ApplicationContext) => { + console.log(params); + let occ = ctx.occService; + const oci = occ.commandInterface; - var returnObject = { - consumed: [], - created: [] - }; + var returnObject = { + consumed: [], + created: [] + }; - oci.pcylinder("basehole", params.diameter / 2, params.depth); + oci.pcylinder("basehole", params.diameter / 2, params.depth); - if (params.holeType == "normal") { - returnObject.created.push(occ.io.getShell("basehole")); - } + if (params.holeType == "normal") { + returnObject.created.push(occ.io.getShell("basehole")); + } - if (params.holeType == "counterbore") { - oci.pcylinder("counterbore", params.counterBoreDiameter / 2, params.counterBoreDepth); + if (params.holeType == "counterbore") { + oci.pcylinder("counterbore", params.counterBoreDiameter / 2, params.counterBoreDepth); - oci.bop("basehole", "counterbore"); - oci.bopfuse("result"); + oci.bop("basehole", "counterbore"); + oci.bopfuse("result"); - returnObject.created.push(occ.io.getShell("result")); - } + returnObject.created.push(occ.io.getShell("result")); + } - if (params.holeType == "countersink") { + if (params.holeType == "countersink") { - let heightFromDiameterAndAngle = (params.countersinkDiameter - params.diameter) / (Math.tan((params.countersinkAngle / 180 * Math.PI) / 2)); + let heightFromDiameterAndAngle = (params.countersinkDiameter - params.diameter) / (Math.tan((params.countersinkAngle / 180 * Math.PI) / 2)); - oci.pcone("countersink", params.countersinkDiameter / 2, 0, heightFromDiameterAndAngle); - oci.bop("basehole", "countersink"); - oci.bopfuse("result"); - returnObject.created.push(occ.io.getShell("result")); - } + oci.pcone("countersink", params.countersinkDiameter / 2, 0, heightFromDiameterAndAngle); + oci.bop("basehole", "countersink"); + oci.bopfuse("result"); + returnObject.created.push(occ.io.getShell("result")); + } + console.log(returnObject); + return returnObject; - console.log(returnObject); - - return returnObject; - + }, + form: [ + { + type: 'selection', + name: 'sketch', + capture: [EntityKind.FACE], + label: 'faces', + multi: true, + defaultValue: { + usePreselection: true, + preselectionIndex: 0 + }, }, - form: [ - { - type: 'selection', - name: 'sketch', - capture: [EntityKind.FACE], - label: 'faces', - multi: true, - defaultValue: { - usePreselection: true, - preselectionIndex: 0 - }, - }, - { - type: 'choice', - label: 'HoleType', - name: "holeType", - style: "dropdown", - defaultValue: "counterbore", - values: ['counterbore', 'countersink', 'normal',], - }, + { + type: 'choice', + label: 'HoleType', + name: "holeType", + style: "dropdown", + defaultValue: "counterbore", + values: ['counterbore', 'countersink', 'normal',], + }, - { - type: 'number', - name: "diameter", - defaultValue: 10, - label: 'Hole ⌀' - }, - { - type: 'number', - name: "depth", - defaultValue: 100, - label: 'Hole ↧' - }, + { + type: 'number', + name: "diameter", + defaultValue: 10, + label: 'Hole ⌀' + }, + { + type: 'number', + name: "depth", + defaultValue: 100, + label: 'Hole ↧' + }, - - { - type: 'number', - name: "counterBoreDiameter", - defaultValue: 20, - label: '⌴ ⌀' - }, - { - type: 'number', - name: "counterBoreDepth", - defaultValue: 10, - label: '⌴ ↧' - }, + { + type: 'number', + name: "counterBoreDiameter", + defaultValue: 20, + label: '⌴ ⌀' + }, + { + type: 'number', + name: "counterBoreDepth", + defaultValue: 10, + label: '⌴ ↧' + }, - - { - type: 'number', - name: "countersinkDiameter", - defaultValue: 20, - label: '⌵ ⌀' - }, - { - type: 'number', - name: "countersinkAngle", - defaultValue: 90, - label: '⌵ Angle' - }, - ], + { + type: 'number', + name: "countersinkDiameter", + defaultValue: 20, + label: '⌵ ⌀' + }, + { + type: 'number', + name: "countersinkAngle", + defaultValue: 90, + label: '⌵ Angle' + }, + ], } export default HoleOperation; \ No newline at end of file diff --git a/modules/workbenches/modeler/features/primitive_box/index.ts b/modules/workbenches/modeler/features/primitive_box/index.ts index 21f19ced..e260930e 100644 --- a/modules/workbenches/modeler/features/primitive_box/index.ts +++ b/modules/workbenches/modeler/features/primitive_box/index.ts @@ -1,83 +1,77 @@ -import { ApplicationContext } from 'context'; -import { roundValueForPresentation as r } from 'cad/craft/operationHelper'; - -import { MDFCommand } from "cad/mdf/mdf"; -import { EntityKind } from "cad/model/entities"; -import { BooleanDefinition } from "cad/craft/schema/common/BooleanDefinition"; - - +import {ApplicationContext} from 'context'; +import {roundValueForPresentation as r} from 'cad/craft/operationHelper'; +import {EntityKind} from "cad/model/entities"; +import {BooleanDefinition} from "cad/craft/schema/common/BooleanDefinition"; +import {OperationDescriptor} from "cad/craft/operationPlugin"; interface PrimitiveBoxParams { - x: Number, - y: Number, - z: Number, - locations: {}, - boolean: BooleanDefinition, + x: Number, + y: Number, + z: Number, + locations: {}, + boolean: BooleanDefinition, } -const PrimitiveBoxOperation: MDFCommand = { - id: 'primitive_box', - label: 'Primitive Box', - icon: 'img/cad/extrude', - info: 'Primitive Box', - paramsInfo: ({ x, y, z }) => `(${r(x)} , ${r(y)} , ${r(z)})`, - form: [ - { - type: 'number', - label: 'X', - name: 'x', - defaultValue: 50, - }, - { - type: 'number', - label: 'Y', - name: 'y', - defaultValue: 50, - }, - { - type: 'number', - label: 'Z', - name: 'z', - defaultValue: 50, - }, - { - type: 'selection', - name: 'locations', - capture: [EntityKind.DATUM], - label: 'locations', - multi: false, - optional: true, - defaultValue: { - usePreselection: true, - preselectionIndex: 0 - }, - }, - - { - type: 'boolean', - name: 'boolean', - label: 'boolean', - optional: true, - } - - ], - - - - - - run: (params: PrimitiveBoxParams, ctx: ApplicationContext) => { - - let occ = ctx.occService; - const oci = occ.commandInterface; - - - oci.box("b", params.x,params.y,params.z); - - return occ.utils.applyBooleanModifier(["b"], params.boolean); - +const PrimitiveBoxOperation: OperationDescriptor = { + id: 'primitive_box', + label: 'Primitive Box', + icon: 'img/cad/extrude', + info: 'Primitive Box', + paramsInfo: ({x, y, z}) => `(${r(x)} , ${r(y)} , ${r(z)})`, + form: [ + { + type: 'number', + label: 'X', + name: 'x', + defaultValue: 50, }, + { + type: 'number', + label: 'Y', + name: 'y', + defaultValue: 50, + }, + { + type: 'number', + label: 'Z', + name: 'z', + defaultValue: 50, + }, + { + type: 'selection', + name: 'locations', + capture: [EntityKind.DATUM], + label: 'locations', + multi: false, + optional: true, + defaultValue: { + usePreselection: true, + preselectionIndex: 0 + }, + }, + + { + type: 'boolean', + name: 'boolean', + label: 'boolean', + optional: true, + } + + ], + + + run: (params: PrimitiveBoxParams, ctx: ApplicationContext) => { + + let occ = ctx.occService; + const oci = occ.commandInterface; + + + oci.box("b", params.x, params.y, params.z); + + return occ.utils.applyBooleanModifier(["b"], params.boolean); + + }, } export default PrimitiveBoxOperation; \ No newline at end of file diff --git a/modules/workbenches/modeler/features/revolve_tool/revolve.operation.ts b/modules/workbenches/modeler/features/revolve_tool/revolve.operation.ts index f1993437..287c746e 100644 --- a/modules/workbenches/modeler/features/revolve_tool/revolve.operation.ts +++ b/modules/workbenches/modeler/features/revolve_tool/revolve.operation.ts @@ -1,12 +1,10 @@ -import { roundValueForPresentation as r } from 'cad/craft/operationHelper'; -import { MFace } from "cad/model/mface"; -import { ApplicationContext } from "context"; -import { MDFCommand } from "cad/mdf/mdf"; -import { EntityKind } from "cad/model/entities"; -import Vector from "math/vector"; -import { BooleanDefinition } from "cad/craft/schema/common/BooleanDefinition"; -import * as vec from "math/vec"; +import {roundValueForPresentation as r} from 'cad/craft/operationHelper'; +import {MFace} from "cad/model/mface"; +import {ApplicationContext} from "context"; +import {EntityKind} from "cad/model/entities"; +import {BooleanDefinition} from "cad/craft/schema/common/BooleanDefinition"; import Axis from "math/axis"; +import {OperationDescriptor} from "cad/craft/operationPlugin"; interface RevolveParams { angle: number; @@ -14,14 +12,13 @@ interface RevolveParams { axis: Axis, boolean: BooleanDefinition } - -const RevolveOperation: MDFCommand = { + +const RevolveOperation: OperationDescriptor = { id: 'Revolve', label: 'Revolve', icon: 'img/cad/Revolve', info: 'Revolves 2D sketch', - paramsInfo: ({ angle }) => `(${r(angle)})`, - mutualExclusiveFields: ['datumAxisVector', 'edgeVector', 'sketchSegmentVector'], + paramsInfo: ({angle}) => `(${r(angle)})`, run: (params: RevolveParams, ctx: ApplicationContext) => { console.log(params); let occ = ctx.occService; @@ -43,12 +40,6 @@ const RevolveOperation: MDFCommand = { }); - - - - - - return occ.utils.applyBooleanModifier(tools, params.boolean); }, diff --git a/modules/workbenches/modeler/features/shell_tool/shell.operation.ts b/modules/workbenches/modeler/features/shell_tool/shell.operation.ts index 94388fa3..099aaa33 100644 --- a/modules/workbenches/modeler/features/shell_tool/shell.operation.ts +++ b/modules/workbenches/modeler/features/shell_tool/shell.operation.ts @@ -1,8 +1,8 @@ -import { roundValueForPresentation as r } from 'cad/craft/operationHelper'; -import { MFace } from "cad/model/mface"; -import { ApplicationContext } from "context"; -import { MDFCommand } from "cad/mdf/mdf"; -import { EntityKind } from "cad/model/entities"; +import {roundValueForPresentation as r} from 'cad/craft/operationHelper'; +import {MFace} from "cad/model/mface"; +import {ApplicationContext} from "context"; +import {EntityKind} from "cad/model/entities"; +import {OperationDescriptor} from "cad/craft/operationPlugin"; interface ShellParams { @@ -10,21 +10,18 @@ interface ShellParams { faces: [MFace]; } -const ShellOperation: MDFCommand = { +const ShellOperation: OperationDescriptor = { id: 'shell_tool', label: 'Shell', icon: 'img/cad/Shell', info: 'Shells 2D sketch', - paramsInfo: ({ thickness }) => `(${r(thickness)})`, + paramsInfo: ({thickness}) => `(${r(thickness)})`, run: (params: ShellParams, ctx: ApplicationContext) => { console.log(params); let occ = ctx.occService; const oci = occ.commandInterface; - - - var bodiesToShell = []; var returnObject = { consumed: [], diff --git a/web/app/cad/craft/operationPlugin.ts b/web/app/cad/craft/operationPlugin.ts index 9d2896b2..23be7cea 100644 --- a/web/app/cad/craft/operationPlugin.ts +++ b/web/app/cad/craft/operationPlugin.ts @@ -5,10 +5,13 @@ import {ActionAppearance} from "../actions/actionSystemPlugin"; import {ApplicationContext, CoreContext} from "context"; import {OperationResult} from "./craftPlugin"; import {OperationSchema, SchemaField, schemaIterator, unwrapMetadata} from "cad/craft/schema/schema"; -import {FieldWidgetProps} from "cad/mdf/ui/uiDefinition"; +import {FormDefinition} from "cad/mdf/ui/uiDefinition"; import {Types} from "cad/craft/schema/types"; import {EntityTypeSchema} from "cad/craft/schema/types/entityType"; import {FlattenPath, ParamsPath} from "cad/craft/wizard/wizardTypes"; +import {IconDeclaration} from "cad/icons/IconDeclaration"; +import {resolveIcon} from "cad/craft/ui/iconResolver"; +import {loadDeclarativeForm} from "cad/mdf/declarativeFormLoader"; export function activate(ctx: ApplicationContext) { @@ -19,7 +22,14 @@ export function activate(ctx: ApplicationContext) { }; function addOperation(descriptor: OperationDescriptor, actions) { - let {id, label, info, icon, actionParams} = descriptor; + let {id, label, info, icon, actionParams, form, schema} = descriptor; + + if (!schema) { + let {schema: derivedSchema, form: loadedForm} = loadDeclarativeForm(form as FormDefinition); + schema = derivedSchema; + form = loadedForm; + } + let appearance: ActionAppearance = { label, info @@ -28,7 +38,7 @@ export function activate(ctx: ApplicationContext) { appearance.icon32 = icon + '32.png'; appearance.icon96 = icon + '96.png'; } else { - appearance.icon = icon; + appearance.icon = resolveIcon(icon); } let opAction = { id: id, @@ -38,10 +48,16 @@ export function activate(ctx: ApplicationContext) { }; actions.push(opAction); - let schemaIndex = createSchemaIndex(descriptor.schema); - registry$.mutate(registry => registry[id] = Object.assign({appearance, schemaIndex}, descriptor, { - run: (request, opContext) => runOperation(request, descriptor, opContext) - })); + let schemaIndex = createSchemaIndex(schema); + + let operation = { + appearance, + schemaIndex, + ...descriptor, + schema, form + }; + + registry$.mutate(registry => registry[id] = operation); } function registerOperations(operations) { @@ -60,22 +76,9 @@ export function activate(ctx: ApplicationContext) { return op; } - let handlers = []; - - function runOperation(request, descriptor, opContext) { - for (let handler of handlers) { - let result = handler(descriptor.id, request, opContext); - if (result) { - return result; - } - } - return descriptor.run(request, opContext); - } - ctx.operationService = { registerOperations, - get, - handlers + get }; ctx.services.operation = ctx.operationService; @@ -90,31 +93,28 @@ export interface Operation extends OperationDescriptor{ icon96: string; icon: string|IconType; }; - schemaIndex: SchemaIndex + schemaIndex: SchemaIndex; + form: () => React.ReactNode; + schema: OperationSchema; } export interface OperationDescriptor { id: string; label: string; info: string; - icon: IconType | string | ((props: any) => JSX.Element); + icon: IconDeclaration | IconType | string | ((props: any) => JSX.Element); actionParams?: any; run: (request: R, opContext: CoreContext) => OperationResult | Promise; paramsInfo: (params: R) => string, previewGeomProvider?: (params: R) => OperationGeometryProvider, - form: () => React.ReactNode, - schema: OperationSchema, + form: FormDefinition | (() => React.ReactNode), + schema?: OperationSchema, onParamsUpdate?: (params, name, value) => void, } export interface OperationService { registerOperations(descriptior: OperationDescriptor[]); get(operationId: string): Operation; - handlers: (( - id: string, - request: any, - opContext: CoreContext - ) => void)[] } export type Index = { diff --git a/web/app/cad/craft/schema/initializeBySchema.ts b/web/app/cad/craft/schema/initializeBySchema.ts index 0ddca6f3..ff96323b 100644 --- a/web/app/cad/craft/schema/initializeBySchema.ts +++ b/web/app/cad/craft/schema/initializeBySchema.ts @@ -10,8 +10,8 @@ export default function initializeBySchema(schema: OperationSchema, context: App let md = schema[field] as SchemaField; if (md.type === Types.array) { - if (md.items.type === Types.entity && md.items.defaultValue !== undefined) { - const defaultValue = md.items.defaultValue; + if (md.items.type === Types.entity && md.defaultValue !== undefined) { + const defaultValue = md.defaultValue; if (defaultValue.usePreselection === true) { const entitySchema = md.items; const currentSelection = diff --git a/web/app/cad/craft/schema/materializeParams.ts b/web/app/cad/craft/schema/materializeParams.ts index 0b3f56af..b1a3b758 100644 --- a/web/app/cad/craft/schema/materializeParams.ts +++ b/web/app/cad/craft/schema/materializeParams.ts @@ -33,12 +33,14 @@ function materializeParamsImpl(ctx: CoreContext, result: any, parentReportError: OperationParamsErrorReporter) { + const notProvided = value => value === undefined || value === null || value === ''; + for (let field of Object.keys(schema)) { const reportError = parentReportError.dot(field); const md = schema[field]; let value = params[field]; - if (value === undefined || value === null || value === '') { + if (notProvided(value)) { if (!md.optional) { reportError('required'); } @@ -50,6 +52,9 @@ function materializeParamsImpl(ctx: CoreContext, value = md.resolve( ctx, value, md as any, reportError ) + if (notProvided(value) && !md.optional) { + reportError('required'); + } } // if (md.type === Types.NUMBER) { diff --git a/web/app/cad/craft/schema/schema.ts b/web/app/cad/craft/schema/schema.ts index 3bb77d89..693f60cf 100644 --- a/web/app/cad/craft/schema/schema.ts +++ b/web/app/cad/craft/schema/schema.ts @@ -28,7 +28,7 @@ export type OperationFlattenSchema = { }; export interface BaseSchemaField { - defaultValue: OperationParamValue, + defaultValue?: OperationParamValue, optional: boolean, label?: string, resolve?: ValueResolver diff --git a/web/app/cad/craft/schema/types/arrayType.ts b/web/app/cad/craft/schema/types/arrayType.ts index a8df2004..05cdaea5 100644 --- a/web/app/cad/craft/schema/types/arrayType.ts +++ b/web/app/cad/craft/schema/types/arrayType.ts @@ -11,6 +11,10 @@ export interface ArrayTypeSchema extends BaseSchemaField { min: number; max: number; + + defaultValue: { + usePreselection: boolean; + } } export const ArrayType: Type = { diff --git a/web/app/cad/craft/schema/types/entityType.ts b/web/app/cad/craft/schema/types/entityType.ts index afed12c5..effbf7b0 100644 --- a/web/app/cad/craft/schema/types/entityType.ts +++ b/web/app/cad/craft/schema/types/entityType.ts @@ -10,7 +10,10 @@ export interface EntityTypeSchema extends BaseSchemaField { allowedKinds: EntityKind[]; - initializeBySelection: boolean | number; + defaultValue?: { + usePreselection: boolean; + preselectionIndex: number; + } } export const EntityType: Type = { diff --git a/web/app/cad/mdf/mdfIconResolver.tsx b/web/app/cad/craft/ui/iconResolver.tsx similarity index 88% rename from web/app/cad/mdf/mdfIconResolver.tsx rename to web/app/cad/craft/ui/iconResolver.tsx index 742921ae..4dd02e2f 100644 --- a/web/app/cad/mdf/mdfIconResolver.tsx +++ b/web/app/cad/craft/ui/iconResolver.tsx @@ -4,7 +4,7 @@ import React from 'react'; import { AiOutlineQuestion } from 'react-icons/ai'; import { IconType } from 'react-icons/lib'; -export function resolveMDFIcon(iconDef: IconDeclaration | IconType) { +export function resolveIcon(iconDef: IconDeclaration | IconType) { if (iconDef.iconType || iconDef.iconSet) { return (props) => } else { diff --git a/web/app/cad/craft/wizard/wizardSelectionPlugin.ts b/web/app/cad/craft/wizard/wizardSelectionPlugin.ts index 187e5b2a..5879aa1a 100644 --- a/web/app/cad/craft/wizard/wizardSelectionPlugin.ts +++ b/web/app/cad/craft/wizard/wizardSelectionPlugin.ts @@ -111,14 +111,15 @@ function createPickHandlerFromSchema(wizCtx: WizardContext) { function deselectIfNeeded(id) { for (let entityRef of schemaIndex.entities) { - const val = wizCtx.readParam(entityRef.field.path); + let val = wizCtx.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) { - update(entityRef.field.path, val.splice(index, 1), entityRef.field.flattenedPath); + val = val.slice(index, 1); + update(entityRef.field.path, val, entityRef.field.flattenedPath); return true; } } diff --git a/web/app/cad/icons/DeclarativeIcon.tsx b/web/app/cad/icons/DeclarativeIcon.tsx index 65876130..c05f6f0c 100644 --- a/web/app/cad/icons/DeclarativeIcon.tsx +++ b/web/app/cad/icons/DeclarativeIcon.tsx @@ -8,12 +8,12 @@ interface IconRenderProps { size: IconSize } -export function DeclaredIcon(props: IconRenderProps & IconDeclaration & React.HTMLAttributes) { +export function DeclaredIcon({iconSet, iconType, ...props}: IconRenderProps & IconDeclaration & React.HTMLAttributes) { - if (props.iconSet) { - return + if (iconSet) { + return } else { - return + return } } diff --git a/web/app/cad/icons/IconDeclaration.ts b/web/app/cad/icons/IconDeclaration.ts index 628f31cc..373669e9 100644 --- a/web/app/cad/icons/IconDeclaration.ts +++ b/web/app/cad/icons/IconDeclaration.ts @@ -4,7 +4,7 @@ export enum IconSize { small = 'small', medium = 'medium', large = 'large' -}; +} export interface IconSetDef { iconType: IconType; diff --git a/web/app/cad/mdf/mdf.ts b/web/app/cad/mdf/declarativeFormLoader.ts similarity index 52% rename from web/app/cad/mdf/mdf.ts rename to web/app/cad/mdf/declarativeFormLoader.ts index 39c6e82d..e4bc32b1 100644 --- a/web/app/cad/mdf/mdf.ts +++ b/web/app/cad/mdf/declarativeFormLoader.ts @@ -1,54 +1,24 @@ -import {IconDeclaration} from "cad/icons/IconDeclaration"; -import {CoreContext} from "context"; -import {IconType} from "react-icons"; -import {OperationResult} from "../craft/craftPlugin"; -import {OperationDescriptor} from "../craft/operationPlugin"; -import {resolveMDFIcon} from "./mdfIconResolver"; import {OperationSchema} from "cad/craft/schema/schema"; import { DynamicWidgetProps, FieldWidgetProps, FormDefinition, isContainerWidgetProps, - isFieldWidgetProps, isSubFormWidgetProps, + isFieldWidgetProps, + isSubFormWidgetProps, UIDefinition } from "cad/mdf/ui/uiDefinition"; import {uiDefinitionToReact} from "cad/mdf/ui/render"; import {ComponentLibrary, DynamicComponents} from "cad/mdf/ui/componentRegistry"; -export interface MDFCommand { - id: string; - label: string; - info: string; - icon: IconType | IconDeclaration; - run: (request: R, opContext: CoreContext) => OperationResult | Promise; - paramsInfo: (params: R) => string, - mutualExclusiveFields?: string[], - form: FormDefinition -} - -export function loadMDFCommand(mdfCommand: MDFCommand): OperationDescriptor { +export function loadDeclarativeForm(form: FormDefinition) { const uiDefinition: UIDefinition = { type: 'group', - content: mdfCommand.form + content: form } const derivedSchema = deriveSchema(uiDefinition); return { - id: mdfCommand.id, - label: mdfCommand.label, - icon: resolveMDFIcon(mdfCommand.icon), - info: mdfCommand.info, - paramsInfo: mdfCommand.paramsInfo, - onParamsUpdate: (params, name, value) => { - if (mdfCommand.mutualExclusiveFields) { - handleMutualExclusiveFields(mdfCommand.mutualExclusiveFields, params, name, value); - } - }, - run: mdfCommand.run, - // actionParams: { - // ...requiresFaceSelection(1) - // }, form: uiDefinitionToReact(uiDefinition), schema: derivedSchema } @@ -95,14 +65,3 @@ export function deriveSchema(uiDefinition: UIDefinition): OperationSchema { return schema; } - - -export function handleMutualExclusiveFields(mutualExclusiveFields, params, name, value) { - if (mutualExclusiveFields.includes(name)) { - mutualExclusiveFields.forEach(param => { - if (param !== name) { - delete params[param]; - } - }) - } -} \ No newline at end of file diff --git a/web/app/cad/mdf/mdfExtrudeExample.ts b/web/app/cad/mdf/mdfExtrudeExample.ts deleted file mode 100644 index a2a163f7..00000000 --- a/web/app/cad/mdf/mdfExtrudeExample.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { roundValueForPresentation as r } from '../craft/operationHelper'; - - -export const MDF_EXTRUDE_EXAMPLE = { - id: 'EXTRUDE', - label: 'Extrude', - icon: 'img/cad/extrude', - info: 'extrudes 2D sketch', - paramsInfo: ({ value }) => `(${r(value)})`, - mutualExclusiveFields: ['datumAxisVector', 'edgeVector', 'sketchSegmentVector'], - run: (params, ctx) => { - return ctx.craftEngine.cutExtrude(false, params); - }, - schema: { - value: { - type: 'number', - defaultValue: 50, - label: 'height' - }, - wierdField: { - type: 'number', - defaultValue: 50, - label: 'weird field' - }, - prism: { - type: 'number', - min: 0, - defaultValue: 1 - }, - angle: { - type: 'number', - defaultValue: 0 - }, - rotation: { - type: 'number', - defaultValue: 0 - }, - face: { - type: 'face', - initializeBySelection: 0 - }, - datumAxisVector: { - type: 'datumAxis', - optional: true, - label: 'datum axis' - }, - edgeVector: { - type: 'edge', - optional: true, - label: 'edge', - accept: edge => edge.brepEdge.curve.degree === 1 - }, - sketchSegmentVector: { - type: 'sketchObject', - optional: true, - label: 'sketch segment', - accept: obj => obj.isSegment - }, - flip: { - type: 'boolean', - defaultValue: false, - } - - } -} diff --git a/web/app/cad/mdf/ui/AxisWidget.tsx b/web/app/cad/mdf/ui/AxisWidget.tsx index 193dde2c..8dabd52d 100644 --- a/web/app/cad/mdf/ui/AxisWidget.tsx +++ b/web/app/cad/mdf/ui/AxisWidget.tsx @@ -40,7 +40,6 @@ export interface AxisWidgetProps extends FieldBasicProps { type: 'axis'; - resolve: ValueResolver; } const ENTITY_CAPTURE = [EntityKind.EDGE, EntityKind.SKETCH_OBJECT, EntityKind.DATUM_AXIS, EntityKind.FACE]; @@ -65,6 +64,7 @@ export const AxisBasedWidgetDefinition = (props: AxisBasedWidgetProps) => ({ type: 'sub-form', name: props.name, resolve: props.resolve, + optional: props.optional, content: [ { name: "vectorEntity", diff --git a/web/app/cad/mdf/ui/ChoiceWidget.tsx b/web/app/cad/mdf/ui/ChoiceWidget.tsx index 0e24a2ec..62af6f6d 100644 --- a/web/app/cad/mdf/ui/ChoiceWidget.tsx +++ b/web/app/cad/mdf/ui/ChoiceWidget.tsx @@ -1,9 +1,10 @@ import {ComboBoxField, NumberField} from "cad/craft/wizard/components/form/Fields"; import React from "react"; -import {OperationSchema} from "cad/craft/schema/schema"; +import {flattenPath, OperationSchema} from "cad/craft/schema/schema"; import {FieldBasicProps, fieldToSchemaGeneric} from "cad/mdf/ui/field"; import {Types} from "cad/craft/schema/types"; import {ComboBoxOption} from "ui/components/controls/ComboBoxControl"; +import {FormContext, FormContextData} from "cad/craft/wizard/components/form/Form"; export interface ChoiceWidgetProps extends FieldBasicProps { @@ -17,9 +18,22 @@ export interface ChoiceWidgetProps extends FieldBasicProps { export function ChoiceWidget(props: ChoiceWidgetProps) { if (!props.style || props.style === 'dropdown') { - return - {props.values.map(value => {value})} - + + return + { + (ctx: FormContextData) => { + const value = ctx.readParam(props.name); + let nonExistent = null; + if (!props.values.includes(value as any)) { + nonExistent = {value ? value+'' : ''} + } + return + {nonExistent} + {props.values.map(value => {value})} + ; + } + } + } else { throw 'implement me'; } diff --git a/web/app/cad/mdf/ui/SelectionWidget.tsx b/web/app/cad/mdf/ui/SelectionWidget.tsx index aaba4812..c2721398 100644 --- a/web/app/cad/mdf/ui/SelectionWidget.tsx +++ b/web/app/cad/mdf/ui/SelectionWidget.tsx @@ -30,7 +30,6 @@ SelectionWidget.propsToSchema = (props: SelectionWidgetProps) => { let value = { type: Types.entity, allowedKinds: props.capture, - initializeBySelection: true, } as SchemaField; if (props.multi) { diff --git a/web/app/cad/part/partOperationsPlugin.js b/web/app/cad/part/partOperationsPlugin.js index aefe7660..95be76ab 100644 --- a/web/app/cad/part/partOperationsPlugin.js +++ b/web/app/cad/part/partOperationsPlugin.js @@ -1,4 +1,3 @@ -import extrudeOperation from '../craft/cutExtrude/extrudeOperation'; import cutOperation from '../craft/cutExtrude/cutOperation'; import planeOperation from '../craft/primitives/simplePlane/simplePlaneOperation'; import filletOperation from '../craft/fillet/filletOperation'; @@ -15,32 +14,31 @@ import coneOperation from '../craft/primitives/cone/coneOperation'; import spatialCurveOperation from '../craft/spatialCurve/spatialCurveOperation'; import loftOperation from '../craft/loft/loftOperation'; import {intersectionOperation, subtractOperation, unionOperation} from '../craft/boolean/booleanOperation'; -import { loadMDFCommand } from '../mdf/mdf'; import WorkbenchRegistry from 'workbenches/registry'; export function activate({services}) { - services.operation.registerOperations([ - planeOperation, - boxOperation, - // extrudeOperation, - cutOperation, - revolveOperation, - filletOperation, - createDatumOperation, - moveDatumOperation, - rotateDatumOperation, - datumOperation, - sphereOperation, - cylinderOperation, - torusOperation, - coneOperation, - spatialCurveOperation, - loftOperation, - intersectionOperation, - subtractOperation, - unionOperation, - ]); - WorkbenchRegistry.forEach(w => { - services.operation.registerOperations(w.features.map(loadMDFCommand)); - }); + services.operation.registerOperations([ + planeOperation, + boxOperation, + // extrudeOperation, + cutOperation, + revolveOperation, + filletOperation, + createDatumOperation, + moveDatumOperation, + rotateDatumOperation, + datumOperation, + sphereOperation, + cylinderOperation, + torusOperation, + coneOperation, + spatialCurveOperation, + loftOperation, + intersectionOperation, + subtractOperation, + unionOperation, + ]); + WorkbenchRegistry.forEach(w => { + services.operation.registerOperations(w.features); + }); } \ No newline at end of file