diff --git a/package-lock.json b/package-lock.json
index 198602ff..0979222c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8437,6 +8437,21 @@
}
}
},
+ "react-icons": {
+ "version": "3.9.0",
+ "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-3.9.0.tgz",
+ "integrity": "sha512-gKbYKR+4QsD3PmIHLAM9TDDpnaTsr3XZeK1NTAb6WQQ+gxEdJ0xuCgLq0pxXdS7Utg2AIpcVhM1ut/jlDhcyNg==",
+ "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=="
+ }
+ }
+ },
"react-is": {
"version": "16.12.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz",
diff --git a/package.json b/package.json
index c42cb601..5c0e7fb3 100644
--- a/package.json
+++ b/package.json
@@ -67,6 +67,7 @@
"prop-types": "15.6.0",
"react": "^16.8.6",
"react-dom": "^16.8.6",
+ "react-icons": "3.9.0",
"react-toastify": "^5.5.0",
"sprintf": "0.1.5",
"three": "0.89.0"
diff --git a/web/app/sketcher/actions/commonActions.js b/web/app/sketcher/actions/commonActions.js
new file mode 100644
index 00000000..3396416f
--- /dev/null
+++ b/web/app/sketcher/actions/commonActions.js
@@ -0,0 +1,85 @@
+import {MdZoomOutMap} from "react-icons/md";
+import {AiOutlineCopy, AiOutlineExport, AiOutlineFile, AiOutlineFolderOpen, AiOutlineSave} from "react-icons/ai";
+import * as ui from "../../ui/ui";
+
+export default [
+
+ {
+ id: 'New',
+ shortName: 'New',
+ kind: 'Common',
+ description: 'Create new sketch',
+ icon: AiOutlineFile,
+
+ invoke: (ctx) => {
+ ctx.app.newSketch();
+ }
+ },
+
+ {
+ id: 'Clone',
+ shortName: 'Clone',
+ kind: 'Common',
+ description: 'Clone sketch',
+ icon: AiOutlineCopy,
+
+ invoke: (ctx, e) => {
+ ctx.app.cloneSketch();
+ }
+ },
+
+ {
+ id: 'Open',
+ shortName: 'Open',
+ kind: 'Common',
+ description: 'Open sketch',
+ icon: AiOutlineFolderOpen,
+
+ invoke: (ctx, e) => {
+ ctx.app._sketchesList.refresh();
+ ui.openWin(ctx.app._sketchesWin, e);
+ }
+ },
+
+ {
+ id: 'Save',
+ shortName: 'Save',
+ kind: 'Common',
+ description: 'Save sketch',
+ icon: AiOutlineSave,
+
+ invoke: (ctx) => {
+ const sketchData = ctx.viewer.io.serializeSketch();
+ const sketchId = ctx.app.getSketchId();
+ localStorage.setItem(sketchId, sketchData);
+ }
+ },
+
+ {
+ id: 'Export',
+ shortName: 'Export',
+ kind: 'Common',
+ description: 'Export sketch to other formats',
+ icon: AiOutlineExport,
+
+ invoke: (ctx, e) => {
+ ui.openWin(ctx.app._exportWin, e);
+ }
+
+ },
+
+ {
+ id: 'Fit',
+ shortName: 'Fit',
+ kind: 'Common',
+ description: 'Fit Sketch On Screen',
+ icon: MdZoomOutMap,
+
+ invoke: (ctx) => {
+ ctx.viewer.toolManager.releaseControl();
+ ctx.app.fit();
+ ctx.viewer.refresh();
+ }
+
+ },
+]
\ No newline at end of file
diff --git a/web/app/sketcher/actions/index.js b/web/app/sketcher/actions/index.js
index 5430323b..0775d677 100644
--- a/web/app/sketcher/actions/index.js
+++ b/web/app/sketcher/actions/index.js
@@ -3,16 +3,30 @@ import {getDescription, MatchIndex, matchSelection} from "../selectionMatcher";
import {toast} from "react-toastify";
import operationActions from "./operationActions";
import constraintGlobalActions from "./constraintGlobalActions";
+import measureActions from "./measureActions";
+import toolActions from "./toolActions";
+import commonActions from "./commonActions";
const ALL_CONTEXTUAL_ACTIONS = [
...constraintActions,
...operationActions,
- ...constraintGlobalActions
+];
+
+const ACTIONS = [
+ ...constraintGlobalActions,
+ ...measureActions,
+ ...toolActions,
+ ...commonActions
//keep going here
];
+const ALL_ACTIONS = [
+ ...ALL_CONTEXTUAL_ACTIONS,
+ ...ACTIONS
+];
+
const index = {};
-ALL_CONTEXTUAL_ACTIONS.forEach(a => index[a.id] = a);
+ALL_ACTIONS.forEach(a => index[a.id] = a);
Object.freeze(index);
export function matchAvailableActions(selection) {
diff --git a/web/app/sketcher/actions/measureActions.js b/web/app/sketcher/actions/measureActions.js
new file mode 100644
index 00000000..fbeb614d
--- /dev/null
+++ b/web/app/sketcher/actions/measureActions.js
@@ -0,0 +1,65 @@
+import {MirrorGeneratorIcon} from "../icons/generators/GeneratorIcons";
+import {MirrorGeneratorSchema} from "../generators/mirrorGenerator";
+import {AddCircleDimTool, AddFreeDimTool, AddHorizontalDimTool, AddVerticalDimTool} from "../tools/dim";
+import {
+ MeasureCircleToolIcon,
+ MeasureFreeToolIcon,
+ MeasureHorizontalToolIcon,
+ MeasureVerticalToolIcon
+} from "../icons/tools/ToolIcons";
+
+export default [
+
+ {
+ id: 'MeasureDistance',
+ shortName: 'Measure Distance',
+ kind: 'Tool',
+ description: 'Measure distance between two points',
+ icon: MeasureFreeToolIcon,
+
+ invoke: (ctx) => {
+ ctx.viewer.toolManager.takeControl(new AddFreeDimTool(ctx.viewer, ctx.viewer.dimLayer));
+ }
+
+ },
+
+
+ {
+ id: 'MeasureHDistance',
+ shortName: 'Measure Horizontal Distance',
+ kind: 'Tool',
+ description: 'Measure horizontal distance between two points',
+ icon: MeasureHorizontalToolIcon,
+
+ invoke: (ctx) => {
+ ctx.viewer.toolManager.takeControl(new AddHorizontalDimTool(ctx.viewer, ctx.viewer.dimLayer));
+ }
+
+ },
+
+ {
+ id: 'MeasureVDistance',
+ shortName: 'Measure Vertical Distance',
+ kind: 'Tool',
+ description: 'Measure vertical distance between two points',
+ icon: MeasureVerticalToolIcon,
+
+ invoke: (ctx) => {
+ ctx.viewer.toolManager.takeControl(new AddVerticalDimTool(ctx.viewer, ctx.viewer.dimLayer));
+ }
+
+ },
+
+ {
+ id: 'MeasureCircle',
+ shortName: 'Measure Circle',
+ kind: 'Tool',
+ description: 'Measure circle diameter',
+ icon: MeasureCircleToolIcon,
+
+ invoke: (ctx) => {
+ ctx.viewer.toolManager.takeControl(new AddCircleDimTool(ctx.viewer, ctx.viewer.dimLayer));
+ }
+
+ },
+];
\ No newline at end of file
diff --git a/web/app/sketcher/actions/operationActions.js b/web/app/sketcher/actions/operationActions.js
index 70d0295a..0a22a9fd 100644
--- a/web/app/sketcher/actions/operationActions.js
+++ b/web/app/sketcher/actions/operationActions.js
@@ -1,7 +1,8 @@
import {Generator} from "../id-generator";
import {SketchGenerator} from "../generators/sketchGenerator";
import {MirrorGeneratorSchema} from "../generators/mirrorGenerator";
-import {MirrorGeneratorIcon} from "../icons/generators/GeneratorIcons";
+import {MirrorGeneratorIcon, OffsetGeneratorIcon} from "../icons/generators/GeneratorIcons";
+import {OffsetTool} from "../tools/offset";
export default [
@@ -12,7 +13,7 @@ export default [
description: 'Mirror Objects',
icon: MirrorGeneratorIcon,
- wizard: MirrorGeneratorSchema.params ,
+ wizard: MirrorGeneratorSchema.params,
invoke: (ctx, params) => {
@@ -24,5 +25,20 @@ export default [
},
+
+ {
+ id: 'Offset',
+ shortName: 'Offset',
+ kind: 'Generator',
+ description: 'Offset',
+ icon: OffsetGeneratorIcon,
+
+ invoke: (ctx) => {
+ ctx.viewer.toolManager.takeControl(new OffsetTool(ctx.viewer));
+ }
+
+ },
+
+
];
diff --git a/web/app/sketcher/actions/toolActions.js b/web/app/sketcher/actions/toolActions.js
new file mode 100644
index 00000000..419f0f29
--- /dev/null
+++ b/web/app/sketcher/actions/toolActions.js
@@ -0,0 +1,177 @@
+import {RectangleTool} from "../tools/rectangle";
+import {
+ ArcToolIcon,
+ BezierToolIcon,
+ CircleToolIcon,
+ EllipseArcToolIcon,
+ EllipseToolIcon,
+ LineToolIcon,
+ MultiLineToolIcon,
+ PointToolIcon,
+ RectangleToolIcon
+} from "../icons/tools/ToolIcons";
+import {AddSegmentTool} from "../tools/segment";
+import {BezierCurveTool} from "../tools/bezier-curve";
+import {EllipseTool} from "../tools/ellipse";
+import {AddPointTool} from "../tools/point";
+import {AddArcTool} from "../tools/arc";
+import {EditCircleTool} from "../tools/circle";
+import {IoIosHand} from "react-icons/io";
+import {ReferencePointTool} from "../tools/origin";
+import {GiCrosshair} from "react-icons/gi";
+
+export default [
+
+ {
+ id: 'PanTool',
+ shortName: 'Pan',
+ kind: 'Tool',
+ description: 'Pan mode',
+ icon: IoIosHand,
+
+ invoke: (ctx) => {
+ ctx.viewer.toolManager.releaseControl();
+
+ }
+
+ },
+
+ {
+ id: 'ReferencePointTool',
+ shortName: 'Set Origin',
+ kind: 'Tool',
+ description: 'Sets reference point for commands',
+ icon: GiCrosshair,
+ command: 'origin',
+ invoke: (ctx) => {
+ ctx.viewer.toolManager.takeControl(new ReferencePointTool(ctx.viewer));
+ }
+
+ },
+
+ {
+ id: 'PointTool',
+ shortName: 'Point',
+ kind: 'Tool',
+ description: 'Add a point',
+ icon: PointToolIcon,
+ command: 'point',
+ invoke: (ctx) => {
+ ctx.viewer.toolManager.takeControl(new AddPointTool(ctx.viewer));
+
+ }
+
+ },
+
+
+ {
+ id: 'SegmentTool',
+ shortName: 'Segment',
+ kind: 'Tool',
+ description: 'Add a segment',
+ icon: LineToolIcon,
+ command: 'line',
+
+ invoke: (ctx) => {
+ ctx.viewer.toolManager.takeControl(new AddSegmentTool(ctx.viewer, false));
+
+ },
+ },
+
+ {
+ id: 'MultiLineTool',
+ shortName: 'Multi Line',
+ kind: 'Tool',
+ description: 'Multi line',
+ icon: MultiLineToolIcon,
+ command: 'mline',
+
+ invoke: (ctx) => {
+ ctx.viewer.toolManager.takeControl(new AddSegmentTool(ctx.viewer, true));
+
+ }
+
+ },
+
+ {
+ id: 'CircleTool',
+ shortName: 'Circle',
+ kind: 'Tool',
+ description: 'Add a circle',
+ icon: CircleToolIcon,
+ command: 'circle',
+
+ invoke: (ctx) => {
+ ctx.viewer.toolManager.takeControl(new EditCircleTool(ctx.viewer));
+ }
+
+ },
+
+ {
+ id: 'ArcTool',
+ shortName: 'Arc',
+ kind: 'Tool',
+ description: 'Add an arc',
+ icon: ArcToolIcon,
+ command: 'arc',
+
+ invoke: (ctx) => {
+ ctx.viewer.toolManager.takeControl(new AddArcTool(ctx.viewer));
+ }
+
+ },
+
+ {
+ id: 'EllipseTool',
+ shortName: 'Ellipse',
+ kind: 'Tool',
+ description: 'Add an ellipse',
+ icon: EllipseToolIcon,
+
+ invoke: (ctx) => {
+ ctx.viewer.toolManager.takeControl(new EllipseTool(ctx.viewer, false));
+ }
+
+ },
+
+ {
+ id: 'EllipseArcTool',
+ shortName: 'Elliptical Arc',
+ kind: 'Tool',
+ description: 'Add elliptical arc',
+ icon: EllipseArcToolIcon,
+
+ invoke: (ctx) => {
+ ctx.viewer.toolManager.takeControl(new EllipseTool(ctx.viewer, true));
+ }
+
+ },
+
+ {
+ id: 'BezierTool',
+ shortName: 'Bezier',
+ kind: 'Tool',
+ description: 'Add a bezier curve',
+ icon: BezierToolIcon,
+
+ invoke: (ctx) => {
+ ctx.viewer.toolManager.takeControl(new BezierCurveTool(ctx.viewer));
+ }
+
+ },
+
+ {
+ id: 'RectangleTool',
+ shortName: 'Rectangle',
+ kind: 'Tool',
+ description: 'Creates rectangle',
+ icon: RectangleToolIcon,
+ command: 'rect',
+
+ invoke: (ctx) => {
+ ctx.viewer.toolManager.takeControl(new RectangleTool(ctx.viewer));
+ }
+
+ },
+];
+
diff --git a/web/app/sketcher/components/SketcherApp.jsx b/web/app/sketcher/components/SketcherApp.jsx
index de6231f8..23d13106 100644
--- a/web/app/sketcher/components/SketcherApp.jsx
+++ b/web/app/sketcher/components/SketcherApp.jsx
@@ -10,7 +10,7 @@ import SketcherOperationWizard from "./SketcherOperationWizard";
import {StageControl} from "./StageControl";
import {Scope} from "./Scope";
import {SketcherToolbar} from "./SketcherToolbar";
-import {sketcherRightToolbarConfig} from "../uiConfig";
+import {sketcherRightToolbarConfig, sketcherTopToolbarConfig} from "../uiConfig";
export const SketcherAppContext = React.createContext({});
@@ -27,6 +27,10 @@ export function SketcherApp({applicationContext}) {
,
document.getElementById('right-toolbar')
)}
+ {ReactDOM.createPortal(
+ ,
+ document.getElementById('top-toolbar')
+ )}
;
diff --git a/web/app/sketcher/components/SketcherToolbar.jsx b/web/app/sketcher/components/SketcherToolbar.jsx
index a4223e53..110cda82 100644
--- a/web/app/sketcher/components/SketcherToolbar.jsx
+++ b/web/app/sketcher/components/SketcherToolbar.jsx
@@ -2,11 +2,17 @@ import React, {useContext} from 'react';
import {getSketcherAction} from "../actions";
import {SketcherAppContext} from "./SketcherApp";
import ls from './SketcherToolbar.less';
+import cx from 'classnames';
-export function SketcherToolbar({actions}) {
+export function SketcherToolbar({actions, horizontal=false, compact}) {
- return
- {actions.map(action =>
)}
+ return
+ {actions.map((action, index) => {
+ if (action === '-') {
+ return
+ }
+ return
+ })}
;
}
@@ -22,7 +28,7 @@ export function SketcherActionButton({actionId}) {
const Icon = action.icon;
- return