diff --git a/web/app/cad/dom/components/WebApplication.jsx b/web/app/cad/dom/components/WebApplication.jsx
index a57a796b..d82a780b 100644
--- a/web/app/cad/dom/components/WebApplication.jsx
+++ b/web/app/cad/dom/components/WebApplication.jsx
@@ -3,6 +3,8 @@ import PropTypes from 'prop-types';
import 'ui/styles/init/index.less';
import AppTabs from "./AppTabs";
+import {StreamsContext} from "../../../../../modules/ui/streamsContext";
+import {AppContext} from "./AppContext";
export default class WebApplication extends React.Component {
@@ -14,7 +16,12 @@ export default class WebApplication extends React.Component {
render() {
- return
+ const {appContext} = this.props;
+ return
+
+
+
+
}
getChildContext() {
diff --git a/web/app/cad/dom/menu/MenuHolder.jsx b/web/app/cad/dom/menu/MenuHolder.jsx
index 8eaab2fa..cfdc4100 100644
--- a/web/app/cad/dom/menu/MenuHolder.jsx
+++ b/web/app/cad/dom/menu/MenuHolder.jsx
@@ -2,11 +2,10 @@ import React from 'react';
import Menu, {MenuItem, MenuSeparator} from 'ui/components/Menu';
import Filler from 'ui/components/Filler';
import Fa from 'ui/components/Fa';
-import {mapActionBehavior} from '../../actions/actionButtonBehavior';
+import {ActionButtonBehavior} from '../../actions/ActionButtonBehavior';
import connect from 'ui/connect';
import {combine, merger} from 'lstream';
-import mapContext from 'ui/mapContext';
-import decoratorChain from 'ui/decoratorChain';
+import {useStream} from "../../../../../modules/ui/effects";
function MenuHolder({menus}) {
return menus.map(({id, actions}) =>
);
@@ -55,17 +54,21 @@ const ConnectedActionMenu = connect((streams, props) =>
.map(([s, keymap]) => ({...s, keymap})))
(ActionMenu);
+export function ConnectedMenuItem(props) {
-let ConnectedMenuItem = decoratorChain(
+ const actionId = props.actionId;
+ const stream = useStream(ctx => combine(ctx.streams.action.appearance[actionId], ctx.streams.action.state[actionId]));
+ if (!stream) {
+ return null;
+ }
+ const [actionAppearance, actionState] = stream;
+
+ return
+ {behaviourProps => }
+ ;
+
+}
- connect((streams, {actionId}) =>
- combine(
- streams.action.state[actionId],
- streams.action.appearance[actionId]).map(merger)),
-
- mapContext(mapActionBehavior(props => props.actionId))
-)
-(ActionMenuItem);
export default connect(streams => streams.ui.menu.all.map(menus => ({menus})))(MenuHolder);
diff --git a/web/app/cad/dom/uiPlugin.js b/web/app/cad/dom/uiPlugin.js
index 199e97c4..4555456a 100644
--- a/web/app/cad/dom/uiPlugin.js
+++ b/web/app/cad/dom/uiPlugin.js
@@ -9,6 +9,7 @@ export function defineStreams({streams}) {
},
toolbars: {
headsUp: state([]),
+ headsUpShowTitles: state(true),
headsUpQuickActions: state([]),
sketcherGeneral: state([]),
sketcherConstraints: state([]),
diff --git a/web/app/cad/part/uiConfigPlugin.js b/web/app/cad/part/uiConfigPlugin.js
index 7614ebde..7a0b447a 100644
--- a/web/app/cad/part/uiConfigPlugin.js
+++ b/web/app/cad/part/uiConfigPlugin.js
@@ -8,6 +8,9 @@ import React from 'react';
import OperationHistory from '../craft/ui/OperationHistory';
import Expressions from '../expressions/Expressions';
+export const STANDARD_MODE_HEADS_UP_TOOLBAR = ['DATUM_CREATE', 'PLANE', 'EditFace', 'EXTRUDE', 'CUT', 'REVOLVE', 'LOFT',
+ '-', 'FILLET', '-', 'INTERSECTION', 'SUBTRACT', 'UNION'];
+
export function activate({services, streams}) {
streams.ui.controlBars.left.value = ['menu.file', 'menu.craft', 'menu.boolean', 'menu.primitives', 'menu.views', 'Donate', 'GitHub'];
streams.ui.controlBars.right.value = [
@@ -16,8 +19,7 @@ export function activate({services, streams}) {
['ShowSketches', {label: 'sketches'}], ['DeselectAll', {label: null}], ['ToggleCameraMode', {label: null}]
];
- streams.ui.toolbars.headsUp.value = ['DATUM_CREATE', 'PLANE', 'EditFace', 'EXTRUDE', 'CUT', 'REVOLVE', 'LOFT',
- '-', 'FILLET', '-', 'INTERSECTION', 'SUBTRACT', 'UNION'];
+ streams.ui.toolbars.headsUp.value = STANDARD_MODE_HEADS_UP_TOOLBAR;
streams.ui.toolbars.headsUpQuickActions.value = ['Save', 'StlExport'];
services.action.registerActions(CoreActions);
diff --git a/web/app/cad/sketch/components/InplaceSketcher.jsx b/web/app/cad/sketch/components/InplaceSketcher.jsx
new file mode 100644
index 00000000..246839a2
--- /dev/null
+++ b/web/app/cad/sketch/components/InplaceSketcher.jsx
@@ -0,0 +1,20 @@
+import React from 'react';
+import {useStream} from "../../../../../modules/ui/effects";
+import {StreamsContext} from "../../../../../modules/ui/streamsContext";
+import {SketcherAppContext} from "../../../sketcher/components/SketcherAppContext";
+import {Scope} from "../../../sketcher/components/Scope";
+
+export function InplaceSketcher({children}) {
+
+ const sketcherAppContext = useStream(ctx => ctx.streams.sketcher.sketcherAppContext);
+
+ if (sketcherAppContext === null) {
+ return null;
+ }
+
+ return
+
+ {children}
+
+
+}
\ No newline at end of file
diff --git a/web/app/cad/sketch/components/SketcherMode.jsx b/web/app/cad/sketch/components/SketcherMode.jsx
new file mode 100644
index 00000000..bccde382
--- /dev/null
+++ b/web/app/cad/sketch/components/SketcherMode.jsx
@@ -0,0 +1,13 @@
+import React from 'react';
+import {useStream} from "../../../../../modules/ui/effects";
+
+export default function SketcherMode({children}) {
+
+ const visible = useStream(ctx => ctx.streams.sketcher.sketchingMode);
+
+ if (!visible) {
+ return null;
+ }
+
+ return children;
+}
\ No newline at end of file
diff --git a/web/app/cad/dom/components/SketcherToolbars.jsx b/web/app/cad/sketch/components/SketcherToolbars.jsx
similarity index 85%
rename from web/app/cad/dom/components/SketcherToolbars.jsx
rename to web/app/cad/sketch/components/SketcherToolbars.jsx
index f3da1a40..1832d345 100644
--- a/web/app/cad/dom/components/SketcherToolbars.jsx
+++ b/web/app/cad/sketch/components/SketcherToolbars.jsx
@@ -1,6 +1,7 @@
import React from 'react';
import ls from './SketcherToolbars.less';
-import {createPlugableToolbar} from './PlugableToolbar';
+import {createPlugableToolbar} from '../../dom/components/PlugableToolbar';
+import '../../../sketcher/actions';
export default function SketcherToolbars({visible}) {
return
diff --git a/web/app/cad/dom/components/SketcherToolbars.less b/web/app/cad/sketch/components/SketcherToolbars.less
similarity index 100%
rename from web/app/cad/dom/components/SketcherToolbars.less
rename to web/app/cad/sketch/components/SketcherToolbars.less
diff --git a/web/app/cad/sketch/inPlaceSketcher.js b/web/app/cad/sketch/inPlaceSketcher.js
index efd1d23d..30a15ab2 100644
--- a/web/app/cad/sketch/inPlaceSketcher.js
+++ b/web/app/cad/sketch/inPlaceSketcher.js
@@ -1,18 +1,22 @@
-import {Viewer} from '../../sketcher/viewer2d';
-import {IO} from '../../sketcher/io';
import {DelegatingPanTool} from '../../sketcher/tools/pan';
import {Matrix4} from 'three/src/math/Matrix4';
import {ORIGIN} from '../../math/l3space';
import {CAMERA_MODE} from '../scene/viewer';
import DPR from 'dpr';
-import sketcherStreams from '../../sketcher/sketcherStreams';
+import {SKETCHER_MODE_HEADS_UP_ACTIONS} from "./sketcherUIContrib";
+import {createEssentialAppContext} from "../../sketcher/sketcherContext";
+import {STANDARD_MODE_HEADS_UP_TOOLBAR} from "../part/uiConfigPlugin";
export class InPlaceSketcher {
constructor(ctx) {
this.face = null; // should be only one in the state
this.ctx = ctx;
- this.viewer = null;
+ this.sketcherAppContext = null;
+ }
+
+ get viewer() {
+ return this.sketcherAppContext ? this.sketcherAppContext.viewer : null;
}
get inEditMode() {
@@ -33,18 +37,21 @@ export class InPlaceSketcher {
canvas.style.bottom = 0;
container.appendChild(canvas);
- this.viewer = new Viewer(canvas, IO);
+ this.sketcherAppContext = createEssentialAppContext(canvas);
this.viewer.parametricManager.externalConstantResolver = this.ctx.services.expressions.evaluateExpression;
- this.ctx.streams.sketcherApp = this.viewer.streams;
this.syncWithCamera();
this.viewer.toolManager.setDefaultTool(new DelegatingPanTool(this.viewer, viewer3d.sceneSetup.renderer.domElement));
viewer3d.sceneSetup.trackballControls.addEventListener( 'change', this.onCameraChange);
+ this.ctx.streams.ui.toolbars.headsUp.next(SKETCHER_MODE_HEADS_UP_ACTIONS);
+ this.ctx.streams.ui.toolbars.headsUpShowTitles.next(false);
+
let sketchData = this.ctx.services.storage.get(this.sketchStorageKey);
this.viewer.historyManager.init(sketchData);
this.viewer.io.loadSketch(sketchData);
- this.ctx.streams.sketcher.sketchingFace.value = face;
+ this.ctx.streams.sketcher.sketchingFace.next(face);
+ this.ctx.streams.sketcher.sketcherAppContext.next(this.sketcherAppContext);
}
get sketchStorageKey() {
@@ -60,9 +67,11 @@ export class InPlaceSketcher {
this.face = null;
this.viewer.canvas.parentNode.removeChild(this.viewer.canvas);
this.viewer.dispose();
- this.viewer = null;
- this.ctx.streams.sketcher.sketchingFace.value = null;
- this.ctx.streams.sketcherApp = null;
+ this.sketcherAppContext = null;
+ this.ctx.streams.sketcher.sketchingFace.next(null);
+ this.ctx.streams.sketcher.sketcherAppContext.next(null);
+ this.ctx.streams.ui.toolbars.headsUp.next(STANDARD_MODE_HEADS_UP_TOOLBAR);
+ this.ctx.streams.ui.toolbars.headsUpShowTitles.next(true);
viewer3d.requestRender();
}
diff --git a/web/app/cad/sketch/sketcherControlActions.js b/web/app/cad/sketch/sketcherControlActions.js
index 15fa9d28..a8d316b2 100644
--- a/web/app/cad/sketch/sketcherControlActions.js
+++ b/web/app/cad/sketch/sketcherControlActions.js
@@ -1,10 +1,14 @@
+import {FcCancel, FcCheckmark} from "react-icons/fc";
+import {RiExternalLinkLine} from "react-icons/ri";
+
export default [
{
id: 'sketchSaveAndExit',
appearance: {
info: 'save sketch changes and exit',
label: 'commit',
- cssIcons: ['check'],
+ icon: FcCheckmark,
+
},
invoke: ({services}) => {
services.sketcher.inPlaceEditor.save();
@@ -16,7 +20,7 @@ export default [
appearance: {
info: 'drop sketch changes and exit',
label: 'exit sketch',
- cssIcons: ['times'],
+ icon: FcCancel,
},
invoke: ({services}) => {
services.sketcher.inPlaceEditor.exit();
@@ -27,7 +31,7 @@ export default [
appearance: {
info: 'save changes and open sketch 2D in a tab',
label: '2D',
- cssIcons: ['external-link'],
+ icon: RiExternalLinkLine,
},
invoke: ({services}) => {
let face = services.sketcher.inPlaceEditor.face;
diff --git a/web/app/cad/sketch/sketcherPlugin.js b/web/app/cad/sketch/sketcherPlugin.js
index e78b24af..bf3da83c 100644
--- a/web/app/cad/sketch/sketcherPlugin.js
+++ b/web/app/cad/sketch/sketcherPlugin.js
@@ -12,7 +12,8 @@ import {DelegatingPanTool} from "../../sketcher/tools/pan";
export function defineStreams(ctx) {
ctx.streams.sketcher = {
update: stream(),
- sketchingFace: state(null)
+ sketchingFace: state(null),
+ sketcherAppContext: state(null)
};
ctx.streams.sketcher.sketchingMode = ctx.streams.sketcher.sketchingFace.map(face => !!face);
}
diff --git a/web/app/cad/sketch/sketcherUIContrib.js b/web/app/cad/sketch/sketcherUIContrib.js
index 10547a3a..05df7663 100644
--- a/web/app/cad/sketch/sketcherUIContrib.js
+++ b/web/app/cad/sketch/sketcherUIContrib.js
@@ -1,54 +1,61 @@
-import SketcherToolActions from './sketcherToolActions';
-import SketcherConstrainsActions from './sketcherConstraintsActions';
-import SketcherControlActions from './sketcherControlActions';
-import {state} from '../../../../modules/lstream';
+import {startOperation} from "../../sketcher/actions";
+import objectToolActions from '../../sketcher/actions/objectToolActions';
+import measureActions from '../../sketcher/actions/measureActions';
+import {insertAfter} from '../../../../modules/gems/iterables';
+import operationActions from "../../sketcher/actions/operationActions";
+import constraintGlobalActions from "../../sketcher/actions/constraintGlobalActions";
+import generalToolActions from "../../sketcher/actions/generalToolActions";
+import sketcherControlActions from "./sketcherControlActions";
export default function ({services, streams}) {
+ services.action.registerActions(sketcherControlActions);
+ services.action.registerActions([
+ ...constraintGlobalActions,
+ ...measureActions,
+ ...generalToolActions,
+ ...objectToolActions,
+ ...operationActions,
+
+ ].map(convertSketcherAction));
+
+}
+
+const SKETCHER_PREFIX = 'sketcher.';
+
+function toSketcherActionId(id) {
+ return SKETCHER_PREFIX + id;
+}
+
+function convertSketcherAction(action) {
+
+ return {
+ id: toSketcherActionId(action.id),
+ appearance: {
+ icon: action.icon,
+ label: action.shortName,
+ info: action.description,
+ },
+ invoke: ({services}, e) => action.invoke(services.sketcher.inPlaceEditor.sketcherAppContext)
+ }
+}
+export const SKETCHER_MODE_HEADS_UP_ACTIONS = [
+ ['sketchSaveAndExit', 'sketchExit'],
+ '-',
+ generalToolActions.map(a => toSketcherActionId(a.id)),
+ '-',
+ [
+ ...objectToolActions.map(a => toSketcherActionId(a.id)),
+ toSketcherActionId('Offset'),
+ ],
+ '-',
+ measureActions.map(a => toSketcherActionId(a.id)),
+ '-',
+ constraintGlobalActions.map(a => toSketcherActionId(a.id)),
+ '-',
+ ['sketchOpenInTab']
+];
+
+insertAfter(SKETCHER_MODE_HEADS_UP_ACTIONS, SKETCHER_PREFIX + 'Export', '-');
+insertAfter(SKETCHER_MODE_HEADS_UP_ACTIONS, SKETCHER_PREFIX + 'PanTool', '-');
+insertAfter(SKETCHER_MODE_HEADS_UP_ACTIONS, SKETCHER_PREFIX + 'BezierTool', '-');
- services.action.registerActions(SketcherToolActions);
- services.action.registerActions(SketcherConstrainsActions);
- services.action.registerActions(SketcherControlActions);
-
- streams.ui.toolbars.sketcherGeneral.value = [
- 'sketchReferencePoint',
- 'sketchPanTool',
- 'sketchAddPoint',
- 'sketchAddSegment',
- 'sketchAddMultiSegment',
- 'sketchAddArc',
- 'sketchAddCircle',
- 'sketchAddEllipse',
- 'sketchAddEllipticalArc',
- 'sketchAddCubicBezierSpline',
- 'sketchAddRectangle',
- 'sketchOffsetTool',
- 'sketchAddFillet',
- 'sketchAddDim',
- 'sketchAddHDim',
- 'sketchAddVDim',
- 'sketchCircleDim',
- ];
- streams.ui.toolbars.sketcherConstraints.value = [
- 'sketchConstraint_coincident',
- 'sketchConstraint_verticalConstraint',
- 'sketchConstraint_horizontalConstraint',
- 'sketchConstraint_parallelConstraint',
- 'sketchConstraint_perpendicularConstraint',
- 'sketchConstraint_P2LDistanceConstraint',
- 'sketchConstraint_P2PDistanceConstraint',
- 'sketchConstraint_RadiusConstraint',
- 'sketchConstraint_EntityEqualityConstraint',
- 'sketchConstraint_tangentConstraint',
- 'sketchConstraint_lockConstraint',
- 'sketchConstraint_pointOnLine',
- 'sketchConstraint_pointOnArc',
- 'sketchConstraint_pointInMiddle',
- 'sketchConstraint_llAngle',
- 'sketchConstraint_symmetry',
- 'sketchConstraint_mirror',
- 'sketchConstraint_lockConvex'
- ];
- streams.ui.toolbars.sketcherControl.value = [
- 'sketchSaveAndExit', 'sketchOpenInTab', 'sketchExit'
- ];
-}
\ No newline at end of file
diff --git a/web/app/sketcher/actions/generalToolActions.js b/web/app/sketcher/actions/generalToolActions.js
new file mode 100644
index 00000000..d810b22c
--- /dev/null
+++ b/web/app/sketcher/actions/generalToolActions.js
@@ -0,0 +1,31 @@
+import {ReferencePointTool} from "../tools/origin";
+import {IoIosHand} from "react-icons/io";
+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));
+ }
+
+ },
+]
\ No newline at end of file
diff --git a/web/app/sketcher/actions/index.js b/web/app/sketcher/actions/index.js
index 9d8034a0..f03044d0 100644
--- a/web/app/sketcher/actions/index.js
+++ b/web/app/sketcher/actions/index.js
@@ -4,9 +4,10 @@ import {toast} from "react-toastify";
import operationActions from "./operationActions";
import constraintGlobalActions from "./constraintGlobalActions";
import measureActions from "./measureActions";
-import toolActions from "./toolActions";
+import objectToolActions from "./objectToolActions";
import commonActions from "./commonActions";
import exportActions from "./exportActions";
+import generalToolActions from "./generalToolActions";
const ALL_CONTEXTUAL_ACTIONS = [
...constraintActions,
@@ -16,7 +17,8 @@ const ALL_CONTEXTUAL_ACTIONS = [
const ACTIONS = [
...constraintGlobalActions,
...measureActions,
- ...toolActions,
+ ...generalToolActions,
+ ...objectToolActions,
...commonActions,
...exportActions
//keep going here
diff --git a/web/app/sketcher/actions/toolActions.js b/web/app/sketcher/actions/objectToolActions.js
similarity index 82%
rename from web/app/sketcher/actions/toolActions.js
rename to web/app/sketcher/actions/objectToolActions.js
index 419f0f29..5d6c7e0b 100644
--- a/web/app/sketcher/actions/toolActions.js
+++ b/web/app/sketcher/actions/objectToolActions.js
@@ -16,39 +16,9 @@ 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',
diff --git a/web/app/sketcher/components/ConstraintEditor.jsx b/web/app/sketcher/components/ConstraintEditor.jsx
index 33c51d84..b4862284 100644
--- a/web/app/sketcher/components/ConstraintEditor.jsx
+++ b/web/app/sketcher/components/ConstraintEditor.jsx
@@ -8,8 +8,8 @@ import CheckboxControl from "ui/components/controls/CheckboxControl";
import Window from "ui/components/Window";
import Field from "ui/components/controls/Field";
import Label from "../../../../modules/ui/components/controls/Label";
-import {SketcherAppContext} from "./SketcherApp";
import {EMPTY_OBJECT} from "../../../../modules/gems/objects";
+import {SketcherAppContext} from "./SketcherAppContext";
export function ConstraintEditor() {
diff --git a/web/app/sketcher/components/ConstraintExplorer.jsx b/web/app/sketcher/components/ConstraintExplorer.jsx
index 8a78a834..6fde72a2 100644
--- a/web/app/sketcher/components/ConstraintExplorer.jsx
+++ b/web/app/sketcher/components/ConstraintExplorer.jsx
@@ -2,11 +2,10 @@ import React, {useContext, useEffect} from 'react';
import ls from './ConstraintExplorer.less';
import Fa from 'ui/components/Fa';
import {useStream} from "ui/effects";
-import {SketcherAppContext} from "./SketcherApp";
import cx from 'classnames';
import {editConstraint} from "./ConstraintEditor";
import {NoIcon} from "../icons/NoIcon";
-
+import {SketcherAppContext} from "./SketcherAppContext";
export function ConstraintExplorer(props) {
return
diff --git a/web/app/sketcher/components/ContextualControls.jsx b/web/app/sketcher/components/ContextualControls.jsx
index 4e7d045f..35d48ea2 100644
--- a/web/app/sketcher/components/ContextualControls.jsx
+++ b/web/app/sketcher/components/ContextualControls.jsx
@@ -2,11 +2,11 @@ import React, {useContext} from 'react';
import ls from './ContextualControls.less';
import {matchAvailableActions} from "../actions";
import {useStream} from "../../../../modules/ui/effects";
-import {SketcherAppContext} from "./SketcherApp";
import {MatchIndex, matchSelection} from "../selectionMatcher";
import {ConstraintButton, GeneratorButton} from "./ConstraintExplorer";
import {Columnizer} from "../../../../modules/ui/components/Columnizer";
import {NoIcon} from "../icons/NoIcon";
+import {SketcherAppContext} from "./SketcherAppContext";
export function ContextualControls() {
diff --git a/web/app/sketcher/components/SketchManager.jsx b/web/app/sketcher/components/SketchManager.jsx
index c3b57ece..a7c538de 100644
--- a/web/app/sketcher/components/SketchManager.jsx
+++ b/web/app/sketcher/components/SketchManager.jsx
@@ -1,12 +1,11 @@
import React, {useContext, useMemo, useState} from 'react';
-import {SketcherAppContext} from "./SketcherApp";
import {useStreamWithUpdater} from "ui/effects";
import Window, {DIRECTIONS} from "ui/components/Window";
-import App2D from "../sketcherContext";
import Stack from "ui/components/Stack";
import Button from "ui/components/controls/Button";
import {RiDeleteBinLine} from "react-icons/ri";
import {SKETCHER_STORAGE_PREFIX} from "../project";
+import {SketcherAppContext} from "./SketcherAppContext";
export function SketchManager() {
diff --git a/web/app/sketcher/components/SketchObjectExplorer.jsx b/web/app/sketcher/components/SketchObjectExplorer.jsx
index 6d05941d..f39e2576 100644
--- a/web/app/sketcher/components/SketchObjectExplorer.jsx
+++ b/web/app/sketcher/components/SketchObjectExplorer.jsx
@@ -1,84 +1,85 @@
-import React from 'react';
+import React, {useContext, useState} from 'react';
import cx from 'classnames';
import ls from './SketchObjectExplorer.less'
-
-import connect from 'ui/connect';
import {combine} from 'lstream';
-import mapContext from '../../../../modules/ui/mapContext';
+import {useStream} from "../../../../modules/ui/effects";
+import {SketcherAppContext} from "./SketcherAppContext";
-@connect(streams => combine(streams.sketcherApp.objects, streams.sketcherApp.selection)
- .map(([objects, selection]) => ({
- objects,
- selection
- })))
-@mapContext(ctx => ({
- select: (obj, exclusive) => {
- let viewer = ctx.services.sketcher.inPlaceEditor.viewer;
+
+export function SketchObjectExplorer() {
+
+ const [modification, setModification] = useState(0);
+ const stream = useStream(ctx => combine(ctx.viewer.streams.objects, ctx.viewer.streams.selection));
+ const ctx = useContext(SketcherAppContext);
+ if (!stream) {
+ return null
+ }
+ const [objects, selection] = stream;
+
+ const select = (obj, exclusive) => {
+ let viewer = ctx.viewer;
viewer.select([obj], exclusive);
viewer.refresh();
- },
- deselect: obj => {
- let viewer = ctx.services.sketcher.inPlaceEditor.viewer;
+ };
+ const deselect = obj => {
+ let viewer = ctx.viewer;
viewer.deselect(obj);
viewer.refresh();
- },
- setRole: (obj, role) => {
- let viewer = ctx.services.sketcher.inPlaceEditor.viewer;
+ };
+ const setRole = (obj, role) => {
+ let viewer = ctx.viewer;
if (obj.aux) {
return;
}
obj.role = role;
viewer.refresh();
- }
-}))
-export class SketchObjectExplorer extends React.Component {
+ };
- render() {
- const {objects} = this.props;
- return
- Objects
-
- {objects.map(o =>
-

- {this.getObjectRole(o)}
-
this.tweakSelection(o, e.shiftKey)} className={cx(ls.objectTag, o.marked&&ls.selected)}>{o.simpleClassName} {o.id}
-
...
-
)}
-
-
- }
-
- tweakSelection(obj, shiftKey) {
+ const tweakSelection = (obj, shiftKey) => {
if (obj.marked) {
- this.props.deselect(obj);
+ deselect(obj);
} else {
- this.props.select(obj, !shiftKey);
+ select(obj, !shiftKey);
}
- }
-
- tweakRole(obj) {
- if (obj.role === 'construction') {
- this.props.setRole(obj, null);
- } else if (obj.role === null) {
- this.props.setRole(obj, 'construction');
- }
- this.forceUpdate();
- }
+ };
- getObjectRole(o) {
+ const tweakRole = (obj) => {
+ if (obj.role === 'construction') {
+ setRole(obj, null);
+ } else if (obj.role === null) {
+ setRole(obj, 'construction');
+ }
+ setModification(count => count + 1);
+ };
+
+ const getObjectRole = (o) => {
if (o.aux) {
return B
} else if (o.role === 'construction') {
- return this.tweakRole(o)} title="construction object not used for 3D operations" className={cx(ls.objectRole, ls.construction)}>C
+ return tweakRole(o)} title="construction object not used for 3D operations"
+ className={cx(ls.objectRole, ls.construction)}>C
} else {
- return this.tweakRole(o)} title="sketch object participates in 3D operations" className={cx(ls.objectRole, ls.sketch)}>S
+ return tweakRole(o)} title="sketch object participates in 3D operations"
+ className={cx(ls.objectRole, ls.sketch)}>S
}
- }
+ };
+ return
+ Objects
+
+ {objects.map(o =>
+

+ {getObjectRole(o)}
+
tweakSelection(o, e.shiftKey)}
+ className={cx(ls.objectTag, o.marked && ls.selected)}>{o.simpleClassName} {o.id}
+
...
+
)}
+
+
}
function ObjectIcon({object}) {
-
+
return null;
}
diff --git a/web/app/sketcher/components/SketcherActionButton.jsx b/web/app/sketcher/components/SketcherActionButton.jsx
index 0fb70fe9..0a36de2f 100644
--- a/web/app/sketcher/components/SketcherActionButton.jsx
+++ b/web/app/sketcher/components/SketcherActionButton.jsx
@@ -1,6 +1,6 @@
import {getSketcherAction} from "../actions";
import React, {useContext} from "react";
-import {SketcherAppContext} from "./SketcherApp";
+import {SketcherAppContext} from "./SketcherAppContext";
export function SketcherActionButton({actionId, text=false}) {
diff --git a/web/app/sketcher/components/SketcherApp.jsx b/web/app/sketcher/components/SketcherApp.jsx
index af3b393d..f5962f7b 100644
--- a/web/app/sketcher/components/SketcherApp.jsx
+++ b/web/app/sketcher/components/SketcherApp.jsx
@@ -17,7 +17,9 @@ import {SketcherPropertiesView} from "./SketcherPropertiesView";
import {SketcherDimensionView} from "./SketcherDimensionsView";
import {SketcherTerminal} from "./TerminalView";
-export const SketcherAppContext = React.createContext({});
+import {SketcherAppContext} from './SketcherAppContext';
+
+export {SketcherAppContext};
export function SketcherApp({applicationContext}) {
return
diff --git a/web/app/sketcher/components/SketcherAppContext.js b/web/app/sketcher/components/SketcherAppContext.js
new file mode 100644
index 00000000..61c8c651
--- /dev/null
+++ b/web/app/sketcher/components/SketcherAppContext.js
@@ -0,0 +1,3 @@
+import React from "react";
+
+export const SketcherAppContext = React.createContext({});
\ No newline at end of file
diff --git a/web/app/sketcher/components/SketcherOperationWizard.jsx b/web/app/sketcher/components/SketcherOperationWizard.jsx
index 7f1629dc..25475802 100644
--- a/web/app/sketcher/components/SketcherOperationWizard.jsx
+++ b/web/app/sketcher/components/SketcherOperationWizard.jsx
@@ -5,8 +5,8 @@ import Window from "ui/components/Window";
import Stack from "ui/components/Stack";
import ButtonGroup from "ui/components/controls/ButtonGroup";
import Button from "ui/components/controls/Button";
-import {SketcherAppContext} from "./SketcherApp";
import {useStreamWithUpdater} from "../../../../modules/ui/effects";
+import {SketcherAppContext} from "./SketcherAppContext";
export default function SketcherOperationWizard({}) {
diff --git a/web/app/sketcher/components/StageControl.jsx b/web/app/sketcher/components/StageControl.jsx
index 4fb1fddd..7b8c7c5d 100644
--- a/web/app/sketcher/components/StageControl.jsx
+++ b/web/app/sketcher/components/StageControl.jsx
@@ -1,7 +1,7 @@
import React, {useContext} from 'react';
-import {useStream, useStreamWithUpdater} from "../../../../modules/ui/effects";
+import {useStreamWithUpdater} from "../../../../modules/ui/effects";
import ls from "./ContextualControls.less";
-import {SketcherAppContext} from "./SketcherApp";
+import {SketcherAppContext} from "./SketcherAppContext";
export function StageControl() {
diff --git a/web/app/sketcher/components/TerminalView.jsx b/web/app/sketcher/components/TerminalView.jsx
index bc9663ff..4a18b0cf 100644
--- a/web/app/sketcher/components/TerminalView.jsx
+++ b/web/app/sketcher/components/TerminalView.jsx
@@ -1,11 +1,11 @@
import React, {useCallback, useContext, useEffect, useRef, useState} from 'react';
import {useStreamWithUpdater} from "ui/effects";
import Window from "ui/components/Window";
-import {SketcherAppContext} from "./SketcherApp";
import {getAllSketcherActions} from "../actions";
import {memoize} from "lodash/function";
import ls from './TerminalView.less';
import {DIRECTIONS} from "ui/components/Window";
+import {SketcherAppContext} from "./SketcherAppContext";
export function TerminalView({visible, output, addToOutput, onClose, variantsSupplier, commandProcessor}) {
diff --git a/web/app/sketcher/sketcherContext.js b/web/app/sketcher/sketcherContext.js
index 23fba3e4..f3d340d5 100644
--- a/web/app/sketcher/sketcherContext.js
+++ b/web/app/sketcher/sketcherContext.js
@@ -7,13 +7,16 @@ import {Project} from "./project";
export function createAppContext() {
+ const ctx = createEssentialAppContext(document.getElementById('viewer'));
+ ctx.project = new Project(ctx.viewer);
+ return ctx;
+}
- const viewer = new Viewer(document.getElementById('viewer'), IO);
+export function createEssentialAppContext(canvas) {
return {
- viewer,
- project: new Project(viewer),
+ viewer: new Viewer(canvas, IO),
get actions() {
return getSketcherActionIndex();
@@ -35,4 +38,3 @@ export function createAppContext() {
}
-
diff --git a/web/app/sketcher/uiConfig.js b/web/app/sketcher/uiConfig.js
index 9b329d31..f76d0552 100644
--- a/web/app/sketcher/uiConfig.js
+++ b/web/app/sketcher/uiConfig.js
@@ -1,14 +1,16 @@
import constraintGlobalActions from "./actions/constraintGlobalActions";
import measureActions from "./actions/measureActions";
-import toolActions from "./actions/toolActions";
+import objectToolActions from "./actions/objectToolActions";
import commonActions from "./actions/commonActions";
-import {removeInPlace} from "../../../modules/gems/iterables";
+import {insertAfter, removeInPlace} from "../../../modules/gems/iterables";
+import generalToolActions from "./actions/generalToolActions";
export const sketcherRightToolbarConfig = constraintGlobalActions.map(a => a.id);
export const sketcherTopToolbarConfig = [
...commonActions.map(a => a.id),
- ...toolActions.map(a => a.id),
+ ...generalToolActions.map(a => a.id),
+ ...objectToolActions.map(a => a.id),
'Offset',
'-',
...measureActions.map(a => a.id)
@@ -18,11 +20,4 @@ insertAfter(sketcherTopToolbarConfig, 'Export', '-');
insertAfter(sketcherTopToolbarConfig, 'PanTool', '-');
insertAfter(sketcherTopToolbarConfig, 'BezierTool', '-');
-function insertAfter(arr, item, toAdd) {
- const index = arr.indexOf(item);
- if (index !== -1) {
- arr.splice(index+1, 0, toAdd);
- }
-}
-
removeInPlace(sketcherTopToolbarConfig, 'ToggleTerminal');
\ No newline at end of file