diff --git a/modules/ui/components/controls/FileControl.tsx b/modules/ui/components/controls/FileControl.tsx new file mode 100644 index 00000000..fad079fd --- /dev/null +++ b/modules/ui/components/controls/FileControl.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import InputControl from './InputControl'; + +export interface LocalFile { + + fileName: string; + content: string; +} + +export default class FileControl extends React.Component { + + render() { + let {type, inputRef, onChange, value, ...props} = this.props; + + function fileChanged(files, name) { + + if (!files || !files[0]) { + onChange(null); + } + + const file = files[0]; + + file.text().then(content => { + onChange({ + fileName: name, + content + }) + }); + } + + return
+ fileChanged(e.target.files, e.target.value) } ref={inputRef} {...props} /> +
; + } +} diff --git a/package-lock.json b/package-lock.json index d609feef..fd983e4f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9514,19 +9514,9 @@ } }, "react-icons": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-3.10.0.tgz", - "integrity": "sha512-WsQ5n1JToG9VixWilSo1bHv842Cj5aZqTGiS3Ud47myF6aK7S/IUY2+dHcBdmkQcCFRuHsJ9OMUI0kTDfjyZXQ==", - "requires": { - "camelcase": "^5.0.0" - }, - "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" - } - } + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.2.0.tgz", + "integrity": "sha512-rmzEDFt+AVXRzD7zDE21gcxyBizD/3NqjbX6cmViAgdqfJ2UiLer8927/QhhrXQV7dEj/1EGuOTPp7JnLYVJKQ==" }, "react-is": { "version": "16.12.0", diff --git a/package.json b/package.json index 25a0e835..04b8711d 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "prop-types": "15.6.0", "react": "^16.13.1", "react-dom": "^16.13.1", - "react-icons": "^3.10.0", + "react-icons": "^4.2.0", "react-toastify": "^5.5.0", "sprintf": "0.1.5", "three": "^0.118.3" diff --git a/web/app/cad/actions/coreActions.js b/web/app/cad/actions/coreActions.js index 8ea7c787..16dc1a15 100644 --- a/web/app/cad/actions/coreActions.js +++ b/web/app/cad/actions/coreActions.js @@ -1,4 +1,5 @@ import * as ActionHelpers from './actionHelpers' +import {AiOutlineExport} from "react-icons/ai"; export default [ { @@ -197,6 +198,18 @@ export default [ appearance: { label: 'no icon' } - } + }, + + { + id: 'ExportFaceToDXF', + appearance: { + icon: AiOutlineExport, + label: 'export face DXF', + info: 'export a selected face to a DXF file', + }, + listens: ctx => ctx.streams.selection.face, + update: ActionHelpers.checkForSelectedFaces(1), + invoke: ({services}) => services.sketcher.exportFaceToDXF(services.selection.face.single) + }, ] diff --git a/web/app/cad/craft/wizard/components/form/Fields.jsx b/web/app/cad/craft/wizard/components/form/Fields.jsx index ca209b16..f13118fe 100644 --- a/web/app/cad/craft/wizard/components/form/Fields.jsx +++ b/web/app/cad/craft/wizard/components/form/Fields.jsx @@ -6,6 +6,7 @@ import RadioButtons from 'ui/components/controls/RadioButtons'; import CheckboxControl from 'ui/components/controls/CheckboxControl'; import ReadOnlyValueControl from 'ui/components/controls/ReadOnlyValueControl'; import ComboBoxControl from 'ui/components/controls/ComboBoxControl'; +import FileControl from 'ui/components/controls/FileControl'; export const NumberField = attachToForm(formField(NumberControl)); export const TextField = attachToForm(formField(TextControl)); @@ -13,3 +14,4 @@ export const RadioButtonsField = attachToForm(formField(RadioButtons)); export const CheckboxField = attachToForm(formField(CheckboxControl)); export const ComboBoxField = attachToForm(formField(ComboBoxControl)); export const ReadOnlyValueField = attachToForm(formField(ReadOnlyValueControl)); +export const FileField = attachToForm(formField(FileControl)); diff --git a/web/app/cad/part/uiConfigPlugin.js b/web/app/cad/part/uiConfigPlugin.js index 6371d5a5..5167ce90 100644 --- a/web/app/cad/part/uiConfigPlugin.js +++ b/web/app/cad/part/uiConfigPlugin.js @@ -11,7 +11,8 @@ import {SelectionView} from "../dom/components/SelectionView"; import {GrSelect} from "react-icons/gr"; export const STANDARD_MODE_HEADS_UP_TOOLBAR = ['DATUM_CREATE', 'PLANE', 'EditFace', 'EXTRUDE', 'CUT', 'REVOLVE', 'LOFT', - '-', 'FILLET', '-', 'INTERSECTION', 'SUBTRACT', 'UNION', '-', 'IMPORT_PART', "IMPORT_STEP_FILE"]; + '-', 'FILLET', '-', 'INTERSECTION', 'SUBTRACT', 'UNION', '-', 'IMPORT_PART', "IMPORT_STEP_FILE", "IMPORT_STEP_LOCAL_FILE", + "ExportFaceToDXF"]; export function activate({services, streams}) { streams.ui.controlBars.left.value = ['menu.file', 'menu.craft', 'menu.boolean', 'menu.primitives', 'menu.views', 'Donate', 'GitHub']; diff --git a/web/app/cad/partImport/importStepOperation/ImportStepLocalForm.tsx b/web/app/cad/partImport/importStepOperation/ImportStepLocalForm.tsx new file mode 100644 index 00000000..4ffe2ea0 --- /dev/null +++ b/web/app/cad/partImport/importStepOperation/ImportStepLocalForm.tsx @@ -0,0 +1,10 @@ +import React from 'react'; +import {Group} from "../../craft/wizard/components/form/Form"; +import {FileField} from "../../craft/wizard/components/form/Fields"; + +export function ImportStepLocalForm() { + + return + + ; +} \ No newline at end of file diff --git a/web/app/cad/partImport/importStepOperation/importStepOperation.ts b/web/app/cad/partImport/importStepOperation/importStepOperation.ts index 9b270c65..76fa41f0 100644 --- a/web/app/cad/partImport/importStepOperation/importStepOperation.ts +++ b/web/app/cad/partImport/importStepOperation/importStepOperation.ts @@ -4,12 +4,22 @@ import {OperationDescriptor} from "../../craft/operationPlugin"; import {ApplicationContext} from "context"; import {OperationResult} from "../../craft/craftPlugin"; import {GiLunarModule} from "react-icons/gi"; +import {BiCubeAlt} from "react-icons/bi"; import {checkHttpResponseStatus} from "network/checkHttpResponseStatus"; +import { LocalFile } from "ui/components/controls/FileControl"; +import { ImportStepLocalForm } from "./ImportStepLocalForm"; +import { string } from "prop-types"; export interface ImportStepOperationParams { url: string, } +export interface ImportStepFromLocalOperationParams { + + file: LocalFile; + +} + export const ImportStepOperation: OperationDescriptor = { id: 'IMPORT_STEP_FILE', @@ -23,6 +33,30 @@ export const ImportStepOperation: OperationDescriptor schema: importStepSchema }; +export const ImportStepFromLocalFileOperation: OperationDescriptor = { + + id: 'IMPORT_STEP_LOCAL_FILE', + label: 'import local step file', + icon: BiCubeAlt, + info: 'import step file from local file', + paramsInfo: ({file}) => file && file.fileName, + previewGeomProvider: null, + run: importStepLocalFile, + form: ImportStepLocalForm, + schema: { + file: { + type: 'object', + schema: { + fileName: { + type: 'string', + }, + constent: { + type: 'string', + } + } + } + } +}; function importStepFile(params: ImportStepOperationParams, ctx: ApplicationContext): Promise { @@ -39,4 +73,17 @@ function importStepFile(params: ImportStepOperationParams, ctx: ApplicationConte }) +} + +function importStepLocalFile(params: ImportStepFromLocalOperationParams, ctx: ApplicationContext): Promise { + + const {cadRegistry, remotePartsService} = ctx; + + console.log(params.file.content); + FS.writeFile('/tmp/test', params.file.content); + + return ctx.services.craftEngine.stepImport({ + file: '/tmp/test' + }); + } \ No newline at end of file diff --git a/web/app/cad/partImport/remotePartsPlugin.ts b/web/app/cad/partImport/remotePartsPlugin.ts index c3d4b378..b8f7fa05 100644 --- a/web/app/cad/partImport/remotePartsPlugin.ts +++ b/web/app/cad/partImport/remotePartsPlugin.ts @@ -16,13 +16,13 @@ import {activate as activateExpressionsPlugin} from '../expressions/expressionsP import {activate as activateCadRegistryPlugin} from '../craft/cadRegistryPlugin'; import {activate as activateStoragePlugin} from '../storage/storagePlugin'; import {activate as activateSketchStoragePlugin} from '../sketch/sketchStoragePlugin'; -import {ImportStepOperation} from "./importStepOperation/importStepOperation"; +import {ImportStepFromLocalFileOperation, ImportStepOperation} from "./importStepOperation/importStepOperation"; export function activate(ctx: ApplicationContext) { ctx.domService.contributeComponent(CatalogPartChooser); - ctx.operationService.registerOperations([ImportPartOperation, ImportStepOperation]); + ctx.operationService.registerOperations([ImportPartOperation, ImportStepOperation, ImportStepFromLocalFileOperation]); function loadDefinedCatalogs(): Promise<[CatalogCategory, PartsCatalog][]> { diff --git a/web/app/cad/sketch/sketcherPlugin.ts b/web/app/cad/sketch/sketcherPlugin.ts index 989c8e9c..be7f58aa 100644 --- a/web/app/cad/sketch/sketcherPlugin.ts +++ b/web/app/cad/sketch/sketcherPlugin.ts @@ -62,7 +62,7 @@ export function activate(ctx) { if (sketch && (!sketch.metadata || sketch.metadata.expressionsSignature !== signature)) { try { const viewer = new Viewer(headlessCanvas, IO); - viewer.parametricManager.externalConstantResolver = services.expressions.evaluateExpression; + viewer.parametricManager.externalConstantResolver = ctx.expressionService.evaluateExpression; // viewer.historyManager.init(savedSketch); viewer.io._loadSketch(sketch); viewer.parametricManager.refresh(); @@ -77,6 +77,40 @@ export function activate(ctx) { } } + function exportFaceToDXF(sceneFace) { + const sketchId = sceneFace.id; + updateSketchBoundaries(sceneFace); + + let savedSketch = ctx.sketchStorageService.getSketchData(sketchId); + + if (savedSketch === null) { + return null; + } + + let sketch; + try { + sketch = JSON.parse(savedSketch); + } catch (e) { + console.error(e); + return null; + } + + if (sketch) { + try { + const viewer = new Viewer(headlessCanvas, IO); + + viewer.parametricManager.externalConstantResolver = ctx.expressionService.evaluateExpression; + // viewer.historyManager.init(savedSketch); + viewer.io._loadSketch(sketch); + IO.exportTextData(viewer.io.dxfExport(), ctx.projectService.id + "_" + sketchId + ".dxf"); + Generator.resetIDGenerator(); + } catch (e) { + console.error(e); + return null; + } + } + } + function updateSketchForFace(mFace) { let sketch = ctx.sketchStorageService.readSketch(mFace.defaultSketchId); mFace.setSketch(sketch); @@ -146,6 +180,7 @@ export function activate(ctx) { services.sketcher = { sketchFace, sketchFace2D, updateAllSketches, inPlaceEditor, reassignSketch, + exportFaceToDXF, reassignSketchMode: initReassignSketchMode(ctx) }; ctx.sketcherService = services.sketcher;