work on MDF

This commit is contained in:
xibyte 2022-02-19 23:44:42 -08:00 committed by Val Erastov
parent e07fd2c5e6
commit 31032051fc
23 changed files with 312 additions and 408 deletions

View file

@ -1,6 +1,11 @@
import React from 'react'; 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 <span className='img-icon' style={{ return <span className='img-icon' style={{
display: 'inline-block', display: 'inline-block',
backgroundImage: 'url('+url+')', backgroundImage: 'url('+url+')',
@ -10,4 +15,4 @@ export default function ImgIcon({url, size, style, ...props}) {
height: size + 'px', height: size + 'px',
...style ...style
}} {...props} /> }} {...props} />
}; }

View file

@ -1,23 +1,20 @@
import { roundValueForPresentation as r } from 'cad/craft/operationHelper'; import {roundValueForPresentation as r} from 'cad/craft/operationHelper';
import { MFace } from "cad/model/mface"; import {ApplicationContext} from "context";
import { ApplicationContext } from "context"; import {EntityKind} from "cad/model/entities";
import { MDFCommand } from "cad/mdf/mdf"; import {BooleanDefinition} from "cad/craft/schema/common/BooleanDefinition";
import { EntityKind } from "cad/model/entities"; import {OperationDescriptor} from "cad/craft/operationPlugin";
import Vector from "math/vector";
import { BooleanDefinition } from "cad/craft/schema/common/BooleanDefinition";
import { MShell } from 'cad/model/mshell';
interface BooleanParams { interface BooleanParams {
tools: []; tools: [];
boolean: BooleanDefinition boolean: BooleanDefinition
} }
const BooleanOperation: MDFCommand<BooleanParams> = { const BooleanOperation: OperationDescriptor<BooleanParams> = {
id: 'boolean_tool', id: 'boolean_tool',
label: 'Boolean', label: 'Boolean',
icon: 'img/cad/Boolean', icon: 'img/cad/Boolean',
info: 'Booleans 2D sketch', info: 'Booleans 2D sketch',
paramsInfo: ({ tools, boolean }) => `(${r(tools)} ${r(boolean)})`, paramsInfo: ({tools, boolean}) => `(${r(tools)} ${r(boolean)})`,
run: (params: BooleanParams, ctx: ApplicationContext) => { run: (params: BooleanParams, ctx: ApplicationContext) => {
console.log(params); console.log(params);
let occ = ctx.occService; let occ = ctx.occService;

View file

@ -1,10 +1,10 @@
import {roundValueForPresentation as r} from 'cad/craft/operationHelper'; import {roundValueForPresentation as r} from 'cad/craft/operationHelper';
import {MFace} from "cad/model/mface"; import {MFace} from "cad/model/mface";
import {ApplicationContext} from "context"; import {ApplicationContext} from "context";
import {MDFCommand} from "cad/mdf/mdf";
import {EntityKind} from "cad/model/entities"; import {EntityKind} from "cad/model/entities";
import {BooleanDefinition} from "cad/craft/schema/common/BooleanDefinition"; import {BooleanDefinition} from "cad/craft/schema/common/BooleanDefinition";
import {UnitVector} from "math/vector"; import {UnitVector} from "math/vector";
import {OperationDescriptor} from "cad/craft/operationPlugin";
interface ExtrudeParams { interface ExtrudeParams {
@ -14,13 +14,12 @@ interface ExtrudeParams {
boolean: BooleanDefinition boolean: BooleanDefinition
} }
const ExtrudeOperation: MDFCommand<ExtrudeParams> = { const ExtrudeOperation: OperationDescriptor<ExtrudeParams> = {
id: 'EXTRUDE', id: 'EXTRUDE',
label: 'Extrude', label: 'Extrude',
icon: 'img/cad/extrude', icon: 'img/cad/extrude',
info: 'extrudes 2D sketch', info: 'extrudes 2D sketch',
paramsInfo: ({length}) => `(${r(length)})`, paramsInfo: ({length}) => `(${r(length)})`,
mutualExclusiveFields: ['datumAxisVector', 'edgeVector', 'sketchSegmentVector'],
run: (params: ExtrudeParams, ctx: ApplicationContext) => { run: (params: ExtrudeParams, ctx: ApplicationContext) => {
let occ = ctx.occService; let occ = ctx.occService;

View file

@ -1,137 +1,140 @@
import { roundValueForPresentation as r } from 'cad/craft/operationHelper'; import {roundValueForPresentation as r} from 'cad/craft/operationHelper';
import { MFace } from "cad/model/mface"; import {ApplicationContext} from "context";
import { ApplicationContext } from "context"; import {EntityKind} from "cad/model/entities";
import { MDFCommand } from "cad/mdf/mdf"; import {OperationDescriptor} from "cad/craft/operationPlugin";
import { EntityKind } from "cad/model/entities";
interface HoleParams { interface HoleParams {
diameter: number; diameter: number;
depth: number; depth: number;
counterBoreDiameter: number; counterBoreDiameter: number;
counterBoreDepth: number; counterBoreDepth: number;
countersinkDiameter: number; countersinkDiameter: number;
countersinkAngle: number; countersinkAngle: number;
holeType: string; holeType: string;
} }
const HoleOperation: MDFCommand<HoleParams> = { const HoleOperation: OperationDescriptor<HoleParams> = {
id: 'hole_tool', id: 'hole_tool',
label: 'hole', label: 'hole',
icon: 'img/cad/Shell', icon: 'img/cad/Shell',
info: 'creates hole features', info: 'creates hole features',
paramsInfo: ({ diameter, depth, counterBoreDiameter, counterBoreDepth, countersinkDiameter, countersinkAngle, holeType, }) => `(${r(depth)} ${r(counterBoreDiameter)}) ${r(counterBoreDepth)})`, paramsInfo: ({
diameter,
depth,
counterBoreDiameter,
counterBoreDepth,
countersinkDiameter,
countersinkAngle,
holeType,
}) => `(${r(depth)} ${r(counterBoreDiameter)}) ${r(counterBoreDepth)})`,
run: (params: HoleParams, ctx: ApplicationContext) => { run: (params: HoleParams, ctx: ApplicationContext) => {
console.log(params); console.log(params);
let occ = ctx.occService; let occ = ctx.occService;
const oci = occ.commandInterface; const oci = occ.commandInterface;
var returnObject = { var returnObject = {
consumed: [], consumed: [],
created: [] created: []
}; };
oci.pcylinder("basehole", params.diameter / 2, params.depth); oci.pcylinder("basehole", params.diameter / 2, params.depth);
if (params.holeType == "normal") { if (params.holeType == "normal") {
returnObject.created.push(occ.io.getShell("basehole")); returnObject.created.push(occ.io.getShell("basehole"));
} }
if (params.holeType == "counterbore") { if (params.holeType == "counterbore") {
oci.pcylinder("counterbore", params.counterBoreDiameter / 2, params.counterBoreDepth); oci.pcylinder("counterbore", params.counterBoreDiameter / 2, params.counterBoreDepth);
oci.bop("basehole", "counterbore"); oci.bop("basehole", "counterbore");
oci.bopfuse("result"); 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.pcone("countersink", params.countersinkDiameter / 2, 0, heightFromDiameterAndAngle);
oci.bop("basehole", "countersink"); oci.bop("basehole", "countersink");
oci.bopfuse("result"); oci.bopfuse("result");
returnObject.created.push(occ.io.getShell("result")); returnObject.created.push(occ.io.getShell("result"));
} }
console.log(returnObject);
return returnObject;
console.log(returnObject); },
form: [
return returnObject; {
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', type: 'choice',
label: 'HoleType', label: 'HoleType',
name: "holeType", name: "holeType",
style: "dropdown", style: "dropdown",
defaultValue: "counterbore", defaultValue: "counterbore",
values: ['counterbore', 'countersink', 'normal',], values: ['counterbore', 'countersink', 'normal',],
}, },
{ {
type: 'number', type: 'number',
name: "diameter", name: "diameter",
defaultValue: 10, defaultValue: 10,
label: 'Hole ⌀' label: 'Hole ⌀'
}, },
{ {
type: 'number', type: 'number',
name: "depth", name: "depth",
defaultValue: 100, defaultValue: 100,
label: 'Hole ↧' label: 'Hole ↧'
}, },
{
{ type: 'number',
type: 'number', name: "counterBoreDiameter",
name: "counterBoreDiameter", defaultValue: 20,
defaultValue: 20, label: '⌴ ⌀'
label: '⌴ ⌀' },
}, {
{ type: 'number',
type: 'number', name: "counterBoreDepth",
name: "counterBoreDepth", defaultValue: 10,
defaultValue: 10, label: '⌴ ↧'
label: '⌴ ↧' },
},
{
{ type: 'number',
type: 'number', name: "countersinkDiameter",
name: "countersinkDiameter", defaultValue: 20,
defaultValue: 20, label: '⌵ ⌀'
label: '⌵ ⌀' },
}, {
{ type: 'number',
type: 'number', name: "countersinkAngle",
name: "countersinkAngle", defaultValue: 90,
defaultValue: 90, label: '⌵ Angle'
label: '⌵ Angle' },
}, ],
],
} }
export default HoleOperation; export default HoleOperation;

View file

@ -1,83 +1,77 @@
import { ApplicationContext } from 'context'; import {ApplicationContext} from 'context';
import { roundValueForPresentation as r } from 'cad/craft/operationHelper'; import {roundValueForPresentation as r} from 'cad/craft/operationHelper';
import {EntityKind} from "cad/model/entities";
import { MDFCommand } from "cad/mdf/mdf"; import {BooleanDefinition} from "cad/craft/schema/common/BooleanDefinition";
import { EntityKind } from "cad/model/entities"; import {OperationDescriptor} from "cad/craft/operationPlugin";
import { BooleanDefinition } from "cad/craft/schema/common/BooleanDefinition";
interface PrimitiveBoxParams { interface PrimitiveBoxParams {
x: Number, x: Number,
y: Number, y: Number,
z: Number, z: Number,
locations: {}, locations: {},
boolean: BooleanDefinition, boolean: BooleanDefinition,
} }
const PrimitiveBoxOperation: MDFCommand<PrimitiveBoxParams> = { const PrimitiveBoxOperation: OperationDescriptor<PrimitiveBoxParams> = {
id: 'primitive_box', id: 'primitive_box',
label: 'Primitive Box', label: 'Primitive Box',
icon: 'img/cad/extrude', icon: 'img/cad/extrude',
info: 'Primitive Box', info: 'Primitive Box',
paramsInfo: ({ x, y, z }) => `(${r(x)} , ${r(y)} , ${r(z)})`, paramsInfo: ({x, y, z}) => `(${r(x)} , ${r(y)} , ${r(z)})`,
form: [ form: [
{ {
type: 'number', type: 'number',
label: 'X', label: 'X',
name: 'x', name: 'x',
defaultValue: 50, 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);
}, },
{
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; export default PrimitiveBoxOperation;

View file

@ -1,12 +1,10 @@
import { roundValueForPresentation as r } from 'cad/craft/operationHelper'; import {roundValueForPresentation as r} from 'cad/craft/operationHelper';
import { MFace } from "cad/model/mface"; import {MFace} from "cad/model/mface";
import { ApplicationContext } from "context"; import {ApplicationContext} from "context";
import { MDFCommand } from "cad/mdf/mdf"; import {EntityKind} from "cad/model/entities";
import { EntityKind } from "cad/model/entities"; import {BooleanDefinition} from "cad/craft/schema/common/BooleanDefinition";
import Vector from "math/vector";
import { BooleanDefinition } from "cad/craft/schema/common/BooleanDefinition";
import * as vec from "math/vec";
import Axis from "math/axis"; import Axis from "math/axis";
import {OperationDescriptor} from "cad/craft/operationPlugin";
interface RevolveParams { interface RevolveParams {
angle: number; angle: number;
@ -14,14 +12,13 @@ interface RevolveParams {
axis: Axis, axis: Axis,
boolean: BooleanDefinition boolean: BooleanDefinition
} }
const RevolveOperation: MDFCommand<RevolveParams> = { const RevolveOperation: OperationDescriptor<RevolveParams> = {
id: 'Revolve', id: 'Revolve',
label: 'Revolve', label: 'Revolve',
icon: 'img/cad/Revolve', icon: 'img/cad/Revolve',
info: 'Revolves 2D sketch', info: 'Revolves 2D sketch',
paramsInfo: ({ angle }) => `(${r(angle)})`, paramsInfo: ({angle}) => `(${r(angle)})`,
mutualExclusiveFields: ['datumAxisVector', 'edgeVector', 'sketchSegmentVector'],
run: (params: RevolveParams, ctx: ApplicationContext) => { run: (params: RevolveParams, ctx: ApplicationContext) => {
console.log(params); console.log(params);
let occ = ctx.occService; let occ = ctx.occService;
@ -43,12 +40,6 @@ const RevolveOperation: MDFCommand<RevolveParams> = {
}); });
return occ.utils.applyBooleanModifier(tools, params.boolean); return occ.utils.applyBooleanModifier(tools, params.boolean);
}, },

View file

@ -1,8 +1,8 @@
import { roundValueForPresentation as r } from 'cad/craft/operationHelper'; import {roundValueForPresentation as r} from 'cad/craft/operationHelper';
import { MFace } from "cad/model/mface"; import {MFace} from "cad/model/mface";
import { ApplicationContext } from "context"; import {ApplicationContext} from "context";
import { MDFCommand } from "cad/mdf/mdf"; import {EntityKind} from "cad/model/entities";
import { EntityKind } from "cad/model/entities"; import {OperationDescriptor} from "cad/craft/operationPlugin";
interface ShellParams { interface ShellParams {
@ -10,21 +10,18 @@ interface ShellParams {
faces: [MFace]; faces: [MFace];
} }
const ShellOperation: MDFCommand<ShellParams> = { const ShellOperation: OperationDescriptor<ShellParams> = {
id: 'shell_tool', id: 'shell_tool',
label: 'Shell', label: 'Shell',
icon: 'img/cad/Shell', icon: 'img/cad/Shell',
info: 'Shells 2D sketch', info: 'Shells 2D sketch',
paramsInfo: ({ thickness }) => `(${r(thickness)})`, paramsInfo: ({thickness}) => `(${r(thickness)})`,
run: (params: ShellParams, ctx: ApplicationContext) => { run: (params: ShellParams, ctx: ApplicationContext) => {
console.log(params); console.log(params);
let occ = ctx.occService; let occ = ctx.occService;
const oci = occ.commandInterface; const oci = occ.commandInterface;
var bodiesToShell = []; var bodiesToShell = [];
var returnObject = { var returnObject = {
consumed: [], consumed: [],

View file

@ -5,10 +5,13 @@ import {ActionAppearance} from "../actions/actionSystemPlugin";
import {ApplicationContext, CoreContext} from "context"; import {ApplicationContext, CoreContext} from "context";
import {OperationResult} from "./craftPlugin"; import {OperationResult} from "./craftPlugin";
import {OperationSchema, SchemaField, schemaIterator, unwrapMetadata} from "cad/craft/schema/schema"; 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 {Types} from "cad/craft/schema/types";
import {EntityTypeSchema} from "cad/craft/schema/types/entityType"; import {EntityTypeSchema} from "cad/craft/schema/types/entityType";
import {FlattenPath, ParamsPath} from "cad/craft/wizard/wizardTypes"; 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) { export function activate(ctx: ApplicationContext) {
@ -19,7 +22,14 @@ export function activate(ctx: ApplicationContext) {
}; };
function addOperation(descriptor: OperationDescriptor<any>, actions) { function addOperation(descriptor: OperationDescriptor<any>, 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 = { let appearance: ActionAppearance = {
label, label,
info info
@ -28,7 +38,7 @@ export function activate(ctx: ApplicationContext) {
appearance.icon32 = icon + '32.png'; appearance.icon32 = icon + '32.png';
appearance.icon96 = icon + '96.png'; appearance.icon96 = icon + '96.png';
} else { } else {
appearance.icon = icon; appearance.icon = resolveIcon(icon);
} }
let opAction = { let opAction = {
id: id, id: id,
@ -38,10 +48,16 @@ export function activate(ctx: ApplicationContext) {
}; };
actions.push(opAction); actions.push(opAction);
let schemaIndex = createSchemaIndex(descriptor.schema); let schemaIndex = createSchemaIndex(schema);
registry$.mutate(registry => registry[id] = Object.assign({appearance, schemaIndex}, descriptor, {
run: (request, opContext) => runOperation(request, descriptor, opContext) let operation = {
})); appearance,
schemaIndex,
...descriptor,
schema, form
};
registry$.mutate(registry => registry[id] = operation);
} }
function registerOperations(operations) { function registerOperations(operations) {
@ -60,22 +76,9 @@ export function activate(ctx: ApplicationContext) {
return op; 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 = { ctx.operationService = {
registerOperations, registerOperations,
get, get
handlers
}; };
ctx.services.operation = ctx.operationService; ctx.services.operation = ctx.operationService;
@ -90,31 +93,28 @@ export interface Operation<R> extends OperationDescriptor<R>{
icon96: string; icon96: string;
icon: string|IconType; icon: string|IconType;
}; };
schemaIndex: SchemaIndex schemaIndex: SchemaIndex;
form: () => React.ReactNode;
schema: OperationSchema;
} }
export interface OperationDescriptor<R> { export interface OperationDescriptor<R> {
id: string; id: string;
label: string; label: string;
info: string; info: string;
icon: IconType | string | ((props: any) => JSX.Element); icon: IconDeclaration | IconType | string | ((props: any) => JSX.Element);
actionParams?: any; actionParams?: any;
run: (request: R, opContext: CoreContext) => OperationResult | Promise<OperationResult>; run: (request: R, opContext: CoreContext) => OperationResult | Promise<OperationResult>;
paramsInfo: (params: R) => string, paramsInfo: (params: R) => string,
previewGeomProvider?: (params: R) => OperationGeometryProvider, previewGeomProvider?: (params: R) => OperationGeometryProvider,
form: () => React.ReactNode, form: FormDefinition | (() => React.ReactNode),
schema: OperationSchema, schema?: OperationSchema,
onParamsUpdate?: (params, name, value) => void, onParamsUpdate?: (params, name, value) => void,
} }
export interface OperationService { export interface OperationService {
registerOperations(descriptior: OperationDescriptor<any>[]); registerOperations(descriptior: OperationDescriptor<any>[]);
get<T>(operationId: string): Operation<T>; get<T>(operationId: string): Operation<T>;
handlers: ((
id: string,
request: any,
opContext: CoreContext
) => void)[]
} }
export type Index<T> = { export type Index<T> = {

View file

@ -10,8 +10,8 @@ export default function initializeBySchema(schema: OperationSchema, context: App
let md = schema[field] as SchemaField; let md = schema[field] as SchemaField;
if (md.type === Types.array) { if (md.type === Types.array) {
if (md.items.type === Types.entity && md.items.defaultValue !== undefined) { if (md.items.type === Types.entity && md.defaultValue !== undefined) {
const defaultValue = md.items.defaultValue; const defaultValue = md.defaultValue;
if (defaultValue.usePreselection === true) { if (defaultValue.usePreselection === true) {
const entitySchema = md.items; const entitySchema = md.items;
const currentSelection = const currentSelection =

View file

@ -33,12 +33,14 @@ function materializeParamsImpl(ctx: CoreContext,
result: any, result: any,
parentReportError: OperationParamsErrorReporter) { parentReportError: OperationParamsErrorReporter) {
const notProvided = value => value === undefined || value === null || value === '';
for (let field of Object.keys(schema)) { for (let field of Object.keys(schema)) {
const reportError = parentReportError.dot(field); const reportError = parentReportError.dot(field);
const md = schema[field]; const md = schema[field];
let value = params[field]; let value = params[field];
if (value === undefined || value === null || value === '') { if (notProvided(value)) {
if (!md.optional) { if (!md.optional) {
reportError('required'); reportError('required');
} }
@ -50,6 +52,9 @@ function materializeParamsImpl(ctx: CoreContext,
value = md.resolve( value = md.resolve(
ctx, value, md as any, reportError ctx, value, md as any, reportError
) )
if (notProvided(value) && !md.optional) {
reportError('required');
}
} }
// if (md.type === Types.NUMBER) { // if (md.type === Types.NUMBER) {

View file

@ -28,7 +28,7 @@ export type OperationFlattenSchema = {
}; };
export interface BaseSchemaField { export interface BaseSchemaField {
defaultValue: OperationParamValue, defaultValue?: OperationParamValue,
optional: boolean, optional: boolean,
label?: string, label?: string,
resolve?: ValueResolver<any, any> resolve?: ValueResolver<any, any>

View file

@ -11,6 +11,10 @@ export interface ArrayTypeSchema extends BaseSchemaField {
min: number; min: number;
max: number; max: number;
defaultValue: {
usePreselection: boolean;
}
} }
export const ArrayType: Type<any[], any[], ArrayTypeSchema> = { export const ArrayType: Type<any[], any[], ArrayTypeSchema> = {

View file

@ -10,7 +10,10 @@ export interface EntityTypeSchema extends BaseSchemaField {
allowedKinds: EntityKind[]; allowedKinds: EntityKind[];
initializeBySelection: boolean | number; defaultValue?: {
usePreselection: boolean;
preselectionIndex: number;
}
} }
export const EntityType: Type<string, MObject, EntityTypeSchema> = { export const EntityType: Type<string, MObject, EntityTypeSchema> = {

View file

@ -4,7 +4,7 @@ import React from 'react';
import { AiOutlineQuestion } from 'react-icons/ai'; import { AiOutlineQuestion } from 'react-icons/ai';
import { IconType } from 'react-icons/lib'; import { IconType } from 'react-icons/lib';
export function resolveMDFIcon(iconDef: IconDeclaration | IconType) { export function resolveIcon(iconDef: IconDeclaration | IconType) {
if (iconDef.iconType || iconDef.iconSet) { if (iconDef.iconType || iconDef.iconSet) {
return (props) => <DeclaredIcon {...iconDef} {...props}/> return (props) => <DeclaredIcon {...iconDef} {...props}/>
} else { } else {

View file

@ -111,14 +111,15 @@ function createPickHandlerFromSchema(wizCtx: WizardContext) {
function deselectIfNeeded(id) { function deselectIfNeeded(id) {
for (let entityRef of schemaIndex.entities) { for (let entityRef of schemaIndex.entities) {
const val = wizCtx.readParam(entityRef.field.path); let val = wizCtx.readParam(entityRef.field.path);
if (val === id) { if (val === id) {
update(entityRef.field.path, undefined, entityRef.field.flattenedPath); update(entityRef.field.path, undefined, entityRef.field.flattenedPath);
return true; return true;
} else if (Array.isArray(val)) { } else if (Array.isArray(val)) {
let index = val.indexOf(id); let index = val.indexOf(id);
if (index !== -1) { 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; return true;
} }
} }

View file

@ -8,12 +8,12 @@ interface IconRenderProps {
size: IconSize size: IconSize
} }
export function DeclaredIcon(props: IconRenderProps & IconDeclaration & React.HTMLAttributes<HTMLDivElement>) { export function DeclaredIcon({iconSet, iconType, ...props}: IconRenderProps & IconDeclaration & React.HTMLAttributes<HTMLDivElement>) {
if (props.iconSet) { if (iconSet) {
return <IconSet {...props} /> return <IconSet iconSet={iconSet} {...props} />
} else { } else {
return <Icon {...props} /> return <Icon iconType={iconType} {...props} />
} }
} }

View file

@ -4,7 +4,7 @@ export enum IconSize {
small = 'small', small = 'small',
medium = 'medium', medium = 'medium',
large = 'large' large = 'large'
}; }
export interface IconSetDef { export interface IconSetDef {
iconType: IconType; iconType: IconType;

View file

@ -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 {OperationSchema} from "cad/craft/schema/schema";
import { import {
DynamicWidgetProps, DynamicWidgetProps,
FieldWidgetProps, FieldWidgetProps,
FormDefinition, FormDefinition,
isContainerWidgetProps, isContainerWidgetProps,
isFieldWidgetProps, isSubFormWidgetProps, isFieldWidgetProps,
isSubFormWidgetProps,
UIDefinition UIDefinition
} from "cad/mdf/ui/uiDefinition"; } from "cad/mdf/ui/uiDefinition";
import {uiDefinitionToReact} from "cad/mdf/ui/render"; import {uiDefinitionToReact} from "cad/mdf/ui/render";
import {ComponentLibrary, DynamicComponents} from "cad/mdf/ui/componentRegistry"; import {ComponentLibrary, DynamicComponents} from "cad/mdf/ui/componentRegistry";
export interface MDFCommand<R> {
id: string;
label: string;
info: string;
icon: IconType | IconDeclaration;
run: (request: R, opContext: CoreContext) => OperationResult | Promise<OperationResult>;
paramsInfo: (params: R) => string,
mutualExclusiveFields?: string[],
form: FormDefinition
}
export function loadDeclarativeForm(form: FormDefinition) {
export function loadMDFCommand<R>(mdfCommand: MDFCommand<R>): OperationDescriptor<R> {
const uiDefinition: UIDefinition = { const uiDefinition: UIDefinition = {
type: 'group', type: 'group',
content: mdfCommand.form content: form
} }
const derivedSchema = deriveSchema(uiDefinition); const derivedSchema = deriveSchema(uiDefinition);
return { 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), form: uiDefinitionToReact(uiDefinition),
schema: derivedSchema schema: derivedSchema
} }
@ -95,14 +65,3 @@ export function deriveSchema(uiDefinition: UIDefinition): OperationSchema {
return schema; return schema;
} }
export function handleMutualExclusiveFields(mutualExclusiveFields, params, name, value) {
if (mutualExclusiveFields.includes(name)) {
mutualExclusiveFields.forEach(param => {
if (param !== name) {
delete params[param];
}
})
}
}

View file

@ -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,
}
}
}

View file

@ -40,7 +40,6 @@ export interface AxisWidgetProps extends FieldBasicProps {
type: 'axis'; type: 'axis';
resolve: ValueResolver<AxisInput, any>;
} }
const ENTITY_CAPTURE = [EntityKind.EDGE, EntityKind.SKETCH_OBJECT, EntityKind.DATUM_AXIS, EntityKind.FACE]; 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', type: 'sub-form',
name: props.name, name: props.name,
resolve: props.resolve, resolve: props.resolve,
optional: props.optional,
content: [ content: [
{ {
name: "vectorEntity", name: "vectorEntity",

View file

@ -1,9 +1,10 @@
import {ComboBoxField, NumberField} from "cad/craft/wizard/components/form/Fields"; import {ComboBoxField, NumberField} from "cad/craft/wizard/components/form/Fields";
import React from "react"; 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 {FieldBasicProps, fieldToSchemaGeneric} from "cad/mdf/ui/field";
import {Types} from "cad/craft/schema/types"; import {Types} from "cad/craft/schema/types";
import {ComboBoxOption} from "ui/components/controls/ComboBoxControl"; import {ComboBoxOption} from "ui/components/controls/ComboBoxControl";
import {FormContext, FormContextData} from "cad/craft/wizard/components/form/Form";
export interface ChoiceWidgetProps extends FieldBasicProps { export interface ChoiceWidgetProps extends FieldBasicProps {
@ -17,9 +18,22 @@ export interface ChoiceWidgetProps extends FieldBasicProps {
export function ChoiceWidget(props: ChoiceWidgetProps) { export function ChoiceWidget(props: ChoiceWidgetProps) {
if (!props.style || props.style === 'dropdown') { if (!props.style || props.style === 'dropdown') {
return <ComboBoxField name={props.name} defaultValue={props.defaultValue} label={props.label} >
{props.values.map(value => <ComboBoxOption value={value} key={value}>{value}</ComboBoxOption>)} return <FormContext.Consumer>
</ComboBoxField> {
(ctx: FormContextData) => {
const value = ctx.readParam(props.name);
let nonExistent = null;
if (!props.values.includes(value as any)) {
nonExistent = <ComboBoxOption value={value}>{value ? value+'' : '<empty>'}</ComboBoxOption>
}
return <ComboBoxField name={props.name} defaultValue={props.defaultValue} label={props.label} >
{nonExistent}
{props.values.map(value => <ComboBoxOption value={value} key={value}>{value}</ComboBoxOption>)}
</ComboBoxField>;
}
}
</FormContext.Consumer>
} else { } else {
throw 'implement me'; throw 'implement me';
} }

View file

@ -30,7 +30,6 @@ SelectionWidget.propsToSchema = (props: SelectionWidgetProps) => {
let value = { let value = {
type: Types.entity, type: Types.entity,
allowedKinds: props.capture, allowedKinds: props.capture,
initializeBySelection: true,
} as SchemaField; } as SchemaField;
if (props.multi) { if (props.multi) {

View file

@ -1,4 +1,3 @@
import extrudeOperation from '../craft/cutExtrude/extrudeOperation';
import cutOperation from '../craft/cutExtrude/cutOperation'; import cutOperation from '../craft/cutExtrude/cutOperation';
import planeOperation from '../craft/primitives/simplePlane/simplePlaneOperation'; import planeOperation from '../craft/primitives/simplePlane/simplePlaneOperation';
import filletOperation from '../craft/fillet/filletOperation'; import filletOperation from '../craft/fillet/filletOperation';
@ -15,32 +14,31 @@ import coneOperation from '../craft/primitives/cone/coneOperation';
import spatialCurveOperation from '../craft/spatialCurve/spatialCurveOperation'; import spatialCurveOperation from '../craft/spatialCurve/spatialCurveOperation';
import loftOperation from '../craft/loft/loftOperation'; import loftOperation from '../craft/loft/loftOperation';
import {intersectionOperation, subtractOperation, unionOperation} from '../craft/boolean/booleanOperation'; import {intersectionOperation, subtractOperation, unionOperation} from '../craft/boolean/booleanOperation';
import { loadMDFCommand } from '../mdf/mdf';
import WorkbenchRegistry from 'workbenches/registry'; import WorkbenchRegistry from 'workbenches/registry';
export function activate({services}) { export function activate({services}) {
services.operation.registerOperations([ services.operation.registerOperations([
planeOperation, planeOperation,
boxOperation, boxOperation,
// extrudeOperation, // extrudeOperation,
cutOperation, cutOperation,
revolveOperation, revolveOperation,
filletOperation, filletOperation,
createDatumOperation, createDatumOperation,
moveDatumOperation, moveDatumOperation,
rotateDatumOperation, rotateDatumOperation,
datumOperation, datumOperation,
sphereOperation, sphereOperation,
cylinderOperation, cylinderOperation,
torusOperation, torusOperation,
coneOperation, coneOperation,
spatialCurveOperation, spatialCurveOperation,
loftOperation, loftOperation,
intersectionOperation, intersectionOperation,
subtractOperation, subtractOperation,
unionOperation, unionOperation,
]); ]);
WorkbenchRegistry.forEach(w => { WorkbenchRegistry.forEach(w => {
services.operation.registerOperations(w.features.map(loadMDFCommand)); services.operation.registerOperations(w.features);
}); });
} }