datum rework

This commit is contained in:
Val Erastov 2022-03-25 18:39:24 -07:00
parent f6c75d9c23
commit 9e548409b0
14 changed files with 205 additions and 70 deletions

View file

@ -1,14 +1,19 @@
import React from 'react';
import React, {useState} from 'react';
import {Title} from '../Folder';
export class StackSection extends React.Component {
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;
render() {
const {title, children, isClosed, onTitleClick} = this.props;
return <React.Fragment>
<Title isClosed={isClosed} onClick={onTitleClick}>{title}</Title>
{!isClosed && children}
<Title isClosed={!visible} onClick={onTitleClick}>{title}</Title>
{visible && children}
</React.Fragment>;
}
}

View file

@ -1,15 +1,26 @@
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;
let {type, inputRef, width, onWheel, ...props} = inprops;
return <div className={type}>
<input type='text' ref={inputRef} {...props} spellCheck='false' />
</div>;
const style = width&&{
width
}
const divRef = useRef()
useEffect(() => {
if (onWheel && divRef.current) {
divRef.current.addEventListener('wheel', e => e.preventDefault(), {passive:false})
}
}, [divRef.current])
return <div className={type} ref={divRef}>
<input type='text' ref={inputRef} {...props} spellCheck='false' style={style} onWheel={onWheel}/>
</div>;
}
InputControl.propTypes = {

View file

@ -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 {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;
val = cycle ? max : min;
}
if (max !== undefined && val > max) {
val = max;
val = cycle ? min : max;
}
if (round !== 0) {
val = val.toFixed(round);
}
input.value = val;
onChange(val);
e.preventDefault();
e.stopPropagation();
};
input.addEventListener('wheel', onWheel, {passive: false});
}, []);
return <InputControl type='number'
value={value}
onChange={onChangeFromTarget}
onFocus={onFocus}
inputRef={attachWheelListener}/>
width={width}
onWheel={onWheel}/>
}

View file

@ -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;

View file

@ -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);

View file

@ -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 <Group>
@ -9,5 +16,60 @@ export default function CreateDatumWizard() {
<NumberField name='y' label='Y' />
<NumberField name='z' label='Z' />
<EntityList name='originatingFace' label='off of' entity='face' />
<Rotations name='rotations' />
</Group>;
}
const Rotations = attachToForm(RotationsImpl);
function RotationsImpl({value, onChange}) {
value = value || [];
function add() {
onChange([
...value,
{
axis: 'X',
angle: 0
}
]);
}
return <StackSection title='rotations' collapsible>
{value.map((rot, i) => <div className={ls.rot} key={i}>
<span className={ls.rotControls}>
<span>axis:</span>
<ComboBoxControl onChange={axis => {
onChange(produce(value, value => {
value[i].axis = axis
}));
}} value={rot.axis}>
<ComboBoxOption value='X'>X</ComboBoxOption>
<ComboBoxOption value='Y'>Y</ComboBoxOption>
<ComboBoxOption value='Z'>Z</ComboBoxOption>
</ComboBoxControl>
<span>degree:</span>
<NumberControl width={50} min={0} max={360} cycle onChange={angle => {
onChange(produce(value, value => {
value[i].angle = angle
}));
}} value={rot.angle} />
</span>
<Button onClick={() => onChange(produce(value, value => {
value.splice(i, 1);
}))} compact type='danger'><IoIosRemoveCircleOutline /></Button>
</div>)}
<div>
<Button onClick={add} compact><IoAddCircleOutline /> add rotation</Button>
</div>
</StackSection>
}

View file

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

View file

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

View file

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

View file

@ -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);

View file

@ -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);

View file

@ -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 <StackSection title={props.title} onTitleClick={onTitleClick} isClosed={!visible}>
{visible && <ContainerWidget content={props.content} />}
return <StackSection title={props.title}>
<ContainerWidget content={props.content} />
</StackSection>
}

View file

@ -9,6 +9,7 @@ export abstract class MObject {
TYPE: EntityKind;
id: string;
originatingOperation: number = -1;
ext: any = {};
protected constructor(TYPE, id) {

View file

@ -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');
dragStart(event, axis) {
ctx.craftService.historyTravel.setPointer(datum.originatingOperation - 1, {
preDrag: {
event, axis: axis.name
}
super.dragStart(e, axis);
});
// if (!isReadOnly() && !this.operationStarted) {
// const history = ctx.craftService.modifications$.value.history;
// selectDatum(datum);
// beginOperation('DATUM_MOVE');
// }
// super.dragStart(event, axis);
}
beginOperation(freezeDragging = false) {