diff --git a/modules/ui/components/controls/FormSection.jsx b/modules/ui/components/controls/FormSection.jsx index 37bc5739..10db5333 100644 --- a/modules/ui/components/controls/FormSection.jsx +++ b/modules/ui/components/controls/FormSection.jsx @@ -1,14 +1,19 @@ -import React from 'react'; +import React, {useState} from 'react'; import {Title} from '../Folder'; -export class StackSection extends React.Component { - - render() { - const {title, children, isClosed, onTitleClick} = this.props; - return - {title} - {!isClosed && children} - ; +export function StackSection(props) { + let {title, initialCollapse, collapsible, children} = props; + + if (collapsible === undefined) { + collapsible = true; } - + + const [visible, setVisible] = useState(!initialCollapse); + + const onTitleClick = collapsible ? () => setVisible(visible => !visible) : undefined; + + return + {title} + {visible && children} + ; } \ No newline at end of file diff --git a/modules/ui/components/controls/InputControl.jsx b/modules/ui/components/controls/InputControl.jsx index cca42838..88beae75 100644 --- a/modules/ui/components/controls/InputControl.jsx +++ b/modules/ui/components/controls/InputControl.jsx @@ -1,19 +1,30 @@ -import React from 'react'; +import React, {useEffect, useRef} from 'react'; import PropTypes from 'prop-types'; -export default class InputControl extends React.Component { +export default function InputControl(inprops) { - render() { - let {type, inputRef, ...props} = this.props; - - return
- + let {type, inputRef, width, onWheel, ...props} = inprops; + + const style = width&&{ + width + } + + const divRef = useRef() + + useEffect(() => { + if (onWheel && divRef.current) { + divRef.current.addEventListener('wheel', e => e.preventDefault(), {passive:false}) + } + }, [divRef.current]) + + return
+
; - } + } InputControl.propTypes = { - type: PropTypes.oneOf(['number', 'text']), + type: PropTypes.oneOf(['number', 'text']), }; InputControl.defaultProps = { diff --git a/modules/ui/components/controls/NumberControl.jsx b/modules/ui/components/controls/NumberControl.jsx index 91226655..4490e622 100644 --- a/modules/ui/components/controls/NumberControl.jsx +++ b/modules/ui/components/controls/NumberControl.jsx @@ -4,46 +4,36 @@ import InputControl from './InputControl'; export default function NumberControl(props) { - let {onChange, onFocus, value} = props; + let {onChange, onFocus, value, width, baseStep, round, min, max, accelerator, cycle} = props; const onChangeFromTarget = e => { onChange(e.target.value); }; - const attachWheelListener = useCallback((input) => { - if (!input) { - return; + const onWheel = (e) => { + let delta = e.shiftKey ? e.deltaX : e.deltaY; + let step = baseStep * (e.shiftKey ? accelerator : 1); + let val = parseFloat(e.target.value); + if (isNaN(val)) val = 0; + val = val + (delta < 0 ? -step : step); + if (min !== undefined && val < min) { + val = cycle ? max : min; } - const onWheel = (e) => { - let {baseStep, round, min, max, onChange, accelerator} = props; - let delta = e.shiftKey ? e.deltaX : e.deltaY; - let step = baseStep * (e.shiftKey ? accelerator : 1); - let val = parseFloat(e.target.value); - if (isNaN(val)) val = 0; - val = val + (delta < 0 ? -step : step); - if (min !== undefined && val < min) { - val = min; - } - if (max !== undefined && val > max) { - val = max; - } - if (round !== 0) { - val = val.toFixed(round); - } - input.value = val; - onChange(val); - e.preventDefault(); - e.stopPropagation(); - }; - input.addEventListener('wheel', onWheel, {passive: false}); - }, []); + if (max !== undefined && val > max) { + val = cycle ? min : max; + } + if (round !== 0) { + val = val.toFixed(round); + } + onChange(val); + }; return - + width={width} + onWheel={onWheel}/> } diff --git a/modules/ui/styles/global/form.less b/modules/ui/styles/global/form.less index f3a8b133..878e8e79 100644 --- a/modules/ui/styles/global/form.less +++ b/modules/ui/styles/global/form.less @@ -7,11 +7,15 @@ button { padding: 6px 10px; border: 0; background-color: @bg-color-9; - font-weight: bold; + //font-weight: bold; color: @font-color; white-space: nowrap; border-radius: 1px; + display: inline-flex; + align-items: center; + justify-content: center; + &.icon-button { display: inline-flex; diff --git a/web/app/cad/craft/craftPlugin.ts b/web/app/cad/craft/craftPlugin.ts index ddc1a9a9..87b99554 100644 --- a/web/app/cad/craft/craftPlugin.ts +++ b/web/app/cad/craft/craftPlugin.ts @@ -146,7 +146,10 @@ export function activate(ctx: CoreContext) { promise.then(({consumed, created}) => { consumed.forEach(m => models.delete(m)); - created.forEach(m => models.add(m)); + created.forEach(m => { + m.originatingOperation = i; + models.add(m) + }); models$.next(Array.from(models).sort((m1, m2) => (m1.id||'').localeCompare(m2.id))); runPromise(i + 1); diff --git a/web/app/cad/craft/datum/create/CreateDatumWizard.jsx b/web/app/cad/craft/datum/create/CreateDatumWizard.jsx index 7b55737b..10bee9b8 100644 --- a/web/app/cad/craft/datum/create/CreateDatumWizard.jsx +++ b/web/app/cad/craft/datum/create/CreateDatumWizard.jsx @@ -1,7 +1,14 @@ import React from 'react'; -import {Group} from '../../wizard/components/form/Form'; +import {attachToForm, Group} from '../../wizard/components/form/Form'; import {NumberField} from '../../wizard/components/form/Fields'; import EntityList from '../../wizard/components/form/EntityList'; +import {StackSection} from "ui/components/controls/FormSection"; +import Button from "ui/components/controls/Button"; +import {IoAddCircleOutline, IoIosRemoveCircleOutline} from "react-icons/all"; +import ls from './CreateDatumWizard.less' +import ComboBoxControl, {ComboBoxOption} from "ui/components/controls/ComboBoxControl"; +import NumberControl from "ui/components/controls/NumberControl"; +import produce from "immer"; export default function CreateDatumWizard() { return @@ -9,5 +16,60 @@ export default function CreateDatumWizard() { + ; +} + +const Rotations = attachToForm(RotationsImpl); + +function RotationsImpl({value, onChange}) { + + value = value || []; + + function add() { + + onChange([ + ...value, + { + axis: 'X', + angle: 0 + } + ]); + + } + + return + + {value.map((rot, i) =>
+ + axis: + { + onChange(produce(value, value => { + value[i].axis = axis + })); + }} value={rot.axis}> + X + Y + Z + + degree: + { + onChange(produce(value, value => { + value[i].angle = angle + })); + }} value={rot.angle} /> + + + + +
)} + +
+ +
+ +
+ } \ No newline at end of file diff --git a/web/app/cad/craft/datum/create/CreateDatumWizard.less b/web/app/cad/craft/datum/create/CreateDatumWizard.less new file mode 100644 index 00000000..f2019114 --- /dev/null +++ b/web/app/cad/craft/datum/create/CreateDatumWizard.less @@ -0,0 +1,14 @@ +.rot { + display: flex; + align-items: center; + justify-content: space-between; +} + +.rotControls { + display: flex; + align-items: center; + justify-content: space-between; + & > * { + margin-right: 5px; + } +} \ No newline at end of file diff --git a/web/app/cad/craft/datum/create/createDatumOpSchema.js b/web/app/cad/craft/datum/create/createDatumOpSchema.js index 2675626e..a9f67327 100644 --- a/web/app/cad/craft/datum/create/createDatumOpSchema.js +++ b/web/app/cad/craft/datum/create/createDatumOpSchema.js @@ -16,4 +16,22 @@ export default { type: 'number', defaultValue: 0 }, + rotations: { + type: 'array', + defaultValue: [], + items: { + type: 'object', + schema: { + axis: { + type: 'string', + enum: ['X', 'Y', 'Z'] + }, + angle: { + type: 'number', + min: 0, + max: 360 + } + } + } + } } \ No newline at end of file diff --git a/web/app/cad/craft/datum/create/createDatumOperation.js b/web/app/cad/craft/datum/create/createDatumOperation.js index 904137c6..d0d60c2e 100644 --- a/web/app/cad/craft/datum/create/createDatumOperation.js +++ b/web/app/cad/craft/datum/create/createDatumOperation.js @@ -7,6 +7,7 @@ import {MDatum} from '../../../model/mdatum'; import {roundInteractiveInput} from '../../wizard/roundUtils'; import {DatumParamsRenderer} from '../DatumParamsRenderer'; import {pointAsText} from 'renders'; +import {applyRotation} from "cad/craft/datum/rotate/rotateDatumOperation"; function updateCSys(csys, params, findFace) { csys.copy(CSys.ORIGIN); @@ -17,6 +18,12 @@ function updateCSys(csys, params, findFace) { } } + params.rotations.forEach(r => { + let axis = csys[r.axis.toLowerCase()]; + applyRotation(csys, csys, r.angle, axis); + }); + + csys.origin.x += params.x; csys.origin.y += params.y; csys.origin.z += params.z; @@ -33,7 +40,7 @@ function create(params, {cadRegistry}) { } function previewer(ctx, initialParams, updateParams) { - + let datum3D = new DatumObject3D(CSys.origin(), ctx.services.viewer); datum3D.onMove = (begin, end, delta) => { @@ -55,7 +62,7 @@ function previewer(ctx, initialParams, updateParams) { params.z = roundInteractiveInput(z); }) }; - + function update(params) { updateCSys(datum3D.csys, params, ctx.services.cadRegistry.findFace); } @@ -68,6 +75,23 @@ function previewer(ctx, initialParams, updateParams) { update(initialParams); SceneGraph.addToGroup(ctx.services.cadScene.workGroup, datum3D); + const modifications = ctx.craftService.modifications$.value; + const preDrag = modifications.hints?.preDrag; + if (preDrag) { + let axis; + if ('X' === preDrag.axis) { + axis = datum3D.csysObj.xAxis; + } else if ('Y' === preDrag.axis) { + axis = datum3D.csysObj.yAxis; + } else if ('Z' === preDrag.axis) { + axis = datum3D.csysObj.zAxis; + } + + if (axis) { + ctx.services.modelMouseEventSystem.dispatchMousedown(preDrag.event, [{object: axis.handle}]); + } + } + return { update, dispose } diff --git a/web/app/cad/craft/datum/csysObject.js b/web/app/cad/craft/datum/csysObject.js index dae11e0a..3fcb5651 100644 --- a/web/app/cad/craft/datum/csysObject.js +++ b/web/app/cad/craft/datum/csysObject.js @@ -11,7 +11,7 @@ export default class CSysObject3D extends Object3D { this.csys = csys; this.sceneSetup = sceneSetup; - function createBasisArrow(axis, color) { + function createBasisArrow(name, axis, color) { let meshArrow = new MeshArrow({ dir: axis, color, @@ -22,12 +22,13 @@ export default class CSysObject3D extends Object3D { materialCreate: p => new MeshLambertMaterial(p), ...arrowParams }); + meshArrow.name = name; return meshArrow; } - this.xAxis = createBasisArrow(AXIS.X, 0xFF0000); - this.yAxis = createBasisArrow(AXIS.Y, 0x00FF00); - this.zAxis = createBasisArrow(AXIS.Z, 0x0000FF); + this.xAxis = createBasisArrow('X', AXIS.X, 0xFF0000); + this.yAxis = createBasisArrow('Y', AXIS.Y, 0x00FF00); + this.zAxis = createBasisArrow('Z', AXIS.Z, 0x0000FF); this.add(this.xAxis); this.add(this.yAxis); diff --git a/web/app/cad/craft/datum/rotate/rotateDatumOperation.js b/web/app/cad/craft/datum/rotate/rotateDatumOperation.js index 8698b609..f2383b8d 100644 --- a/web/app/cad/craft/datum/rotate/rotateDatumOperation.js +++ b/web/app/cad/craft/datum/rotate/rotateDatumOperation.js @@ -57,7 +57,7 @@ function previewer(ctx, initialParams) { } } -function applyRotation(origCsys, csys, angle, axis) { +export function applyRotation(origCsys, csys, angle, axis) { auxMatrix.rotate(angle * DEG_RAD, axis, ORIGIN); auxMatrix.__apply(origCsys.x, csys.x); auxMatrix.__apply(origCsys.y, csys.y); diff --git a/web/app/cad/mdf/ui/SectionWidget.tsx b/web/app/cad/mdf/ui/SectionWidget.tsx index b42a5801..1097dbff 100644 --- a/web/app/cad/mdf/ui/SectionWidget.tsx +++ b/web/app/cad/mdf/ui/SectionWidget.tsx @@ -18,12 +18,8 @@ export interface SectionWidgetProps extends ContainerBasicProps { } export function SectionWidget(props: SectionWidgetProps) { - const [visible, setVisible] = useState(!props.initialCollapse); - - const onTitleClick = props.collapsible ? () => setVisible(visible => !visible) : undefined; - - return - {visible && } + return + } diff --git a/web/app/cad/model/mobject.ts b/web/app/cad/model/mobject.ts index e684cdce..c5f038ff 100644 --- a/web/app/cad/model/mobject.ts +++ b/web/app/cad/model/mobject.ts @@ -9,6 +9,7 @@ export abstract class MObject { TYPE: EntityKind; id: string; + originatingOperation: number = -1; ext: any = {}; protected constructor(TYPE, id) { diff --git a/web/app/cad/scene/views/datumView.js b/web/app/cad/scene/views/datumView.js index 2573b084..493b0fa1 100644 --- a/web/app/cad/scene/views/datumView.js +++ b/web/app/cad/scene/views/datumView.js @@ -105,12 +105,18 @@ export default class DatumView extends View { this.csysObj.add(this.menuButton); } - dragStart(e, axis) { - if (!isReadOnly() && !this.operationStarted) { - selectDatum(datum); - beginOperation('DATUM_MOVE'); - } - super.dragStart(e, axis); + dragStart(event, axis) { + ctx.craftService.historyTravel.setPointer(datum.originatingOperation - 1, { + preDrag: { + event, axis: axis.name + } + }); + // if (!isReadOnly() && !this.operationStarted) { + // const history = ctx.craftService.modifications$.value.history; + // selectDatum(datum); + // beginOperation('DATUM_MOVE'); + // } + // super.dragStart(event, axis); } beginOperation(freezeDragging = false) {