mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-06 16:33:15 +01:00
edit constraint by its constraint annotation, dbl click or from the menu
This commit is contained in:
parent
583400ab33
commit
38cffa5e6c
17 changed files with 92 additions and 38 deletions
|
|
@ -14,7 +14,6 @@ export function GenericWizard({documentationLink, title, icon, left, top, classN
|
||||||
top?: number,
|
top?: number,
|
||||||
onCancel: () => any,
|
onCancel: () => any,
|
||||||
onOK: () => any,
|
onOK: () => any,
|
||||||
onKeyDown?: (e) => any,
|
|
||||||
infoText?: any,
|
infoText?: any,
|
||||||
icon?: any
|
icon?: any
|
||||||
} & WindowProps ) {
|
} & WindowProps ) {
|
||||||
|
|
@ -25,6 +24,8 @@ export function GenericWizard({documentationLink, title, icon, left, top, classN
|
||||||
title={(title||'').toUpperCase()}
|
title={(title||'').toUpperCase()}
|
||||||
icon={icon}
|
icon={icon}
|
||||||
className={cx('mid-typography', className)}
|
className={cx('mid-typography', className)}
|
||||||
|
onEscapePressed={onCancel}
|
||||||
|
onEnterPressed={onOK}
|
||||||
controlButtons={<>
|
controlButtons={<>
|
||||||
<WindowControlButton title='help' onClick={(e) => DocumentationTopic$.next({
|
<WindowControlButton title='help' onClick={(e) => DocumentationTopic$.next({
|
||||||
documentationLink: documentationLink,
|
documentationLink: documentationLink,
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,8 @@ export interface WindowProps {
|
||||||
props?: JSX.IntrinsicAttributes;
|
props?: JSX.IntrinsicAttributes;
|
||||||
footer?: JSX.Element;
|
footer?: JSX.Element;
|
||||||
compact?: boolean;
|
compact?: boolean;
|
||||||
|
onEscapePressed?: () => any,
|
||||||
|
onEnterPressed?: () => any
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Window extends React.Component<WindowProps> {
|
export default class Window extends React.Component<WindowProps> {
|
||||||
|
|
@ -47,9 +49,21 @@ export default class Window extends React.Component<WindowProps> {
|
||||||
|
|
||||||
const {initWidth, initHeight, initLeft, initTop, initRight, initBottom, centerScreen, setFocus, className, resizeCapturingBuffer,
|
const {initWidth, initHeight, initLeft, initTop, initRight, initBottom, centerScreen, setFocus, className, resizeCapturingBuffer,
|
||||||
resize, enableResize, children, title, icon, minimizable = false, onClose, controlButtons, footer, compact,
|
resize, enableResize, children, title, icon, minimizable = false, onClose, controlButtons, footer, compact,
|
||||||
|
onEscapePressed, onEnterPressed,
|
||||||
onResize, ...props} = this.props;
|
onResize, ...props} = this.props;
|
||||||
|
|
||||||
return <div className={cx(ls.root, this.resizeConfig&&ls.mandatoryBorder, compact&&ls.compact, className)} {...props} ref={this.keepRef}>
|
const onKeyDown = e => {
|
||||||
|
switch (e.keyCode) {
|
||||||
|
case 27 :
|
||||||
|
onEscapePressed ? onEscapePressed() : onClose();
|
||||||
|
break;
|
||||||
|
case 13 :
|
||||||
|
onEnterPressed();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return <div className={cx(ls.root, this.resizeConfig&&ls.mandatoryBorder, compact&&ls.compact, className)} {...props} ref={this.keepRef} onKeyDown={onKeyDown}>
|
||||||
<div className={ls.bar + ' disable-selection'} onMouseDown={this.startDrag} onMouseUp={this.stopDrag}>
|
<div className={ls.bar + ' disable-selection'} onMouseDown={this.startDrag} onMouseUp={this.stopDrag}>
|
||||||
<div className={ls.title}>{icon} <b>{title.toUpperCase()}</b></div>
|
<div className={ls.title}>{icon} <b>{title.toUpperCase()}</b></div>
|
||||||
<div className={ls.controlButtons}>
|
<div className={ls.controlButtons}>
|
||||||
|
|
|
||||||
|
|
@ -44,17 +44,6 @@ export default function Wizard(props: WizardProps) {
|
||||||
|
|
||||||
const error = state.error;
|
const error = state.error;
|
||||||
|
|
||||||
const onKeyDown = e => {
|
|
||||||
switch (e.keyCode) {
|
|
||||||
case 27 :
|
|
||||||
cancel();
|
|
||||||
break;
|
|
||||||
case 13 :
|
|
||||||
onOK();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const focusFirstInput = el => {
|
const focusFirstInput = el => {
|
||||||
if (props.noFocus) {
|
if (props.noFocus) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -86,7 +75,6 @@ export default function Wizard(props: WizardProps) {
|
||||||
title={title}
|
title={title}
|
||||||
icon={icon}
|
icon={icon}
|
||||||
onClose={cancel}
|
onClose={cancel}
|
||||||
onKeyDown={onKeyDown}
|
|
||||||
setFocus={focusFirstInput}
|
setFocus={focusFirstInput}
|
||||||
className='Wizard'
|
className='Wizard'
|
||||||
data-operation-id={operation.id}
|
data-operation-id={operation.id}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,10 @@ export function activate(ctx) {
|
||||||
//to attach to a dom element: Mousetrap(domElement).bind(...
|
//to attach to a dom element: Mousetrap(domElement).bind(...
|
||||||
for (const action of Object.keys(keymap)) {
|
for (const action of Object.keys(keymap)) {
|
||||||
const dataProvider = getDataProvider(action, services);
|
const dataProvider = getDataProvider(action, services);
|
||||||
Mousetrap.bind(keymap[action], () => ctx.actionService.run(action, dataProvider ? dataProvider() : undefined));
|
Mousetrap.bind(keymap[action], (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
ctx.actionService.run(action, dataProvider ? dataProvider() : undefined)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
Mousetrap.bind('esc', services.menu.closeAll)
|
Mousetrap.bind('esc', services.menu.closeAll)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ export function activate(ctx) {
|
||||||
const signature = ctx.expressionService.signature;
|
const signature = ctx.expressionService.signature;
|
||||||
if (sketch && (!sketch.metadata || sketch.metadata.expressionsSignature !== signature)) {
|
if (sketch && (!sketch.metadata || sketch.metadata.expressionsSignature !== signature)) {
|
||||||
try {
|
try {
|
||||||
const viewer = new Viewer(headlessCanvas, IO);
|
const viewer = new Viewer(headlessCanvas, IO, {});
|
||||||
viewer.parametricManager.externalConstantResolver = ctx.expressionService.evaluateExpression;
|
viewer.parametricManager.externalConstantResolver = ctx.expressionService.evaluateExpression;
|
||||||
// viewer.historyManager.init(savedSketch);
|
// viewer.historyManager.init(savedSketch);
|
||||||
viewer.io._loadSketch(sketch);
|
viewer.io._loadSketch(sketch);
|
||||||
|
|
@ -97,7 +97,7 @@ export function activate(ctx) {
|
||||||
|
|
||||||
if (sketch) {
|
if (sketch) {
|
||||||
try {
|
try {
|
||||||
const viewer = new Viewer(headlessCanvas, IO);
|
const viewer = new Viewer(headlessCanvas, IO, {});
|
||||||
|
|
||||||
viewer.parametricManager.externalConstantResolver = ctx.expressionService.evaluateExpression;
|
viewer.parametricManager.externalConstantResolver = ctx.expressionService.evaluateExpression;
|
||||||
// viewer.historyManager.init(savedSketch);
|
// viewer.historyManager.init(savedSketch);
|
||||||
|
|
|
||||||
|
|
@ -124,10 +124,6 @@ function atatchToToolStreams(context) {
|
||||||
function startReact(appCtx) {
|
function startReact(appCtx) {
|
||||||
|
|
||||||
const reactControls = document.getElementById('react-controls');
|
const reactControls = document.getElementById('react-controls');
|
||||||
reactControls.onkeydown = e => {
|
|
||||||
e.stopPropagation();
|
|
||||||
// e.preventDefault();
|
|
||||||
};
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Scope><SketcherApp applicationContext={appCtx} /></Scope>,
|
<Scope><SketcherApp applicationContext={appCtx} /></Scope>,
|
||||||
reactControls
|
reactControls
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import {Segment} from "../shapes/segment";
|
||||||
import {isInstanceOf, matchAll, matchTypes} from "./matchUtils";
|
import {isInstanceOf, matchAll, matchTypes} from "./matchUtils";
|
||||||
import {Arc} from "../shapes/arc";
|
import {Arc} from "../shapes/arc";
|
||||||
import {FilletTool} from "../tools/fillet";
|
import {FilletTool} from "../tools/fillet";
|
||||||
import {editConstraint as _editConstraint} from "../components/ConstraintEditor";
|
import {showConstraintEditorUI} from "../components/ConstraintEditor";
|
||||||
import {BezierCurve} from "../shapes/bezier-curve";
|
import {BezierCurve} from "../shapes/bezier-curve";
|
||||||
import {
|
import {
|
||||||
AngleBetweenConstraintIcon,
|
AngleBetweenConstraintIcon,
|
||||||
|
|
@ -648,6 +648,6 @@ export default [
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
function editConstraint(ctx, constraint, onApply) {
|
export function editConstraint(ctx, constraint, onApply) {
|
||||||
_editConstraint(ctx.ui.$constraintEditRequest, constraint, onApply)
|
showConstraintEditorUI(ctx.ui.$constraintEditRequest, constraint, onApply)
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import {BsTextareaT} from "react-icons/all";
|
import {BiPencil, BsTextareaT} from "react-icons/all";
|
||||||
import {Label} from "sketcher/shapes/label";
|
import {Label} from "sketcher/shapes/label";
|
||||||
|
import {isConstraintAnnotation} from "sketcher/constr/constraintAnnotation";
|
||||||
|
import {editConstraint} from "sketcher/actions/constraintActions";
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
|
|
||||||
|
|
@ -36,6 +38,24 @@ export default [
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: 'EditConstraintFromItsAnnotation',
|
||||||
|
shortName: 'Edit Constraint',
|
||||||
|
kind: 'Misc',
|
||||||
|
description: 'Edit the constraint the annotation refers to',
|
||||||
|
icon: BiPencil,
|
||||||
|
selectionMatcher: {
|
||||||
|
selector: 'function',
|
||||||
|
match: (selection) => isConstraintAnnotation(selection[0])
|
||||||
|
},
|
||||||
|
invoke: (ctx) => {
|
||||||
|
const [obj] = ctx.viewer.selected;
|
||||||
|
editConstraint(ctx, obj.constraint, () => {
|
||||||
|
ctx.viewer.parametricManager.constraintUpdated(obj.constraint);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,8 @@ export function ConstraintEditor() {
|
||||||
};
|
};
|
||||||
|
|
||||||
return <Window initWidth={250} initLeft={5} initTop={5} title={constraint.schema.name} onClose={onCancel}
|
return <Window initWidth={250} initLeft={5} initTop={5} title={constraint.schema.name} onClose={onCancel}
|
||||||
|
onEnterPressed={onApply}
|
||||||
|
onEscapePressed={onCancel}
|
||||||
onMouseEnter={highlight}
|
onMouseEnter={highlight}
|
||||||
onMouseLeave={unHighlight}>
|
onMouseLeave={unHighlight}>
|
||||||
|
|
||||||
|
|
@ -104,7 +106,7 @@ export function ConstraintEditor() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function editConstraint(rqStream, constraint, onApply) {
|
export function showConstraintEditorUI(rqStream, constraint, onApply) {
|
||||||
rqStream.next({
|
rqStream.next({
|
||||||
constraint,
|
constraint,
|
||||||
onCancel: () => rqStream.next(null),
|
onCancel: () => rqStream.next(null),
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import ls from './ConstraintExplorer.less';
|
||||||
import Fa from 'ui/components/Fa';
|
import Fa from 'ui/components/Fa';
|
||||||
import {useStream} from "ui/effects";
|
import {useStream} from "ui/effects";
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
import {editConstraint} from "./ConstraintEditor";
|
import {showConstraintEditorUI} from "./ConstraintEditor";
|
||||||
import {NoIcon} from "../icons/NoIcon";
|
import {NoIcon} from "../icons/NoIcon";
|
||||||
import {SketcherAppContext} from "./SketcherAppContext";
|
import {SketcherAppContext} from "./SketcherAppContext";
|
||||||
import {StageControl} from "./StageControl";
|
import {StageControl} from "./StageControl";
|
||||||
|
|
@ -50,9 +50,8 @@ export function ConstraintButton({prefix='', constraint: c, ...props}) {
|
||||||
|
|
||||||
const edit = (constraint) => {
|
const edit = (constraint) => {
|
||||||
if (constraint.editable) {
|
if (constraint.editable) {
|
||||||
editConstraint(ui.$constraintEditRequest, constraint, () => {
|
showConstraintEditorUI(ui.$constraintEditRequest, constraint, () => {
|
||||||
viewer.parametricManager.revalidateConstraint(c);
|
viewer.parametricManager.constraintUpdated(c);
|
||||||
viewer.parametricManager.invalidate();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,12 @@ export interface ConstraintAnnotation<T> {
|
||||||
save(): T;
|
save(): T;
|
||||||
|
|
||||||
load(data: T);
|
load(data: T);
|
||||||
|
|
||||||
|
isConstraintAnnotation: boolean;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function isConstraintAnnotation(obj: any): obj is ConstraintAnnotation<any> {
|
||||||
|
return obj&&obj.isConstraintAnnotation === true;
|
||||||
}
|
}
|
||||||
|
|
@ -290,6 +290,11 @@ class ParametricManager {
|
||||||
this.notify();
|
this.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constraintUpdated(constraint) {
|
||||||
|
this.revalidateConstraint(constraint);
|
||||||
|
this.invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
prepare(interactiveObjects) {
|
prepare(interactiveObjects) {
|
||||||
this.groundStage.prepare(interactiveObjects);
|
this.groundStage.prepare(interactiveObjects);
|
||||||
for (const stage of this.stages) {
|
for (const stage of this.stages) {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ export class AngleBetweenAnnotation extends AngleBetweenDimension implements Con
|
||||||
|
|
||||||
constraint: AlgNumConstraint;
|
constraint: AlgNumConstraint;
|
||||||
|
|
||||||
|
isConstraintAnnotation = true;
|
||||||
|
|
||||||
constructor(a, b, constraint) {
|
constructor(a, b, constraint) {
|
||||||
super(a, b);
|
super(a, b);
|
||||||
this.constraint = constraint;
|
this.constraint = constraint;
|
||||||
|
|
@ -35,6 +37,8 @@ export class AngleAbsoluteAnnotation extends AngleBetweenDimension implements Co
|
||||||
|
|
||||||
constraint: AlgNumConstraint;
|
constraint: AlgNumConstraint;
|
||||||
|
|
||||||
|
isConstraintAnnotation = true;
|
||||||
|
|
||||||
constructor(segment, constraint) {
|
constructor(segment, constraint) {
|
||||||
super({
|
super({
|
||||||
a: segment.a,
|
a: segment.a,
|
||||||
|
|
@ -100,6 +104,8 @@ export class LengthAnnotation extends LinearDimension implements ConstraintAnnot
|
||||||
|
|
||||||
constraint: AlgNumConstraint;
|
constraint: AlgNumConstraint;
|
||||||
|
|
||||||
|
isConstraintAnnotation = true;
|
||||||
|
|
||||||
constructor(segment, constraint) {
|
constructor(segment, constraint) {
|
||||||
super(segment.a, segment.b);
|
super(segment.a, segment.b);
|
||||||
this.constraint = constraint;
|
this.constraint = constraint;
|
||||||
|
|
@ -128,6 +134,8 @@ export class RadiusLengthAnnotation extends DiameterDimension implements Constra
|
||||||
|
|
||||||
constraint: AlgNumConstraint;
|
constraint: AlgNumConstraint;
|
||||||
|
|
||||||
|
isConstraintAnnotation = true;
|
||||||
|
|
||||||
constructor(obj, constraint) {
|
constructor(obj, constraint) {
|
||||||
super(obj);
|
super(obj);
|
||||||
this.constraint = constraint;
|
this.constraint = constraint;
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,7 @@ export function createAppContext() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createEssentialAppContext(canvas) {
|
export function createEssentialAppContext(canvas) {
|
||||||
|
const applicationContext = {
|
||||||
return {
|
|
||||||
|
|
||||||
viewer: new Viewer(canvas, IO),
|
|
||||||
|
|
||||||
get actions() {
|
get actions() {
|
||||||
return getSketcherActionIndex();
|
return getSketcherActionIndex();
|
||||||
},
|
},
|
||||||
|
|
@ -35,6 +31,8 @@ export function createEssentialAppContext(canvas) {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
applicationContext.viewer = new Viewer(canvas, IO, applicationContext);
|
||||||
|
return applicationContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import {Tool} from './tool'
|
import {Tool} from './tool'
|
||||||
import {GetShapeEditTool} from './edit-tools-map'
|
import {GetShapeEditTool} from './edit-tools-map'
|
||||||
|
import {isConstraintAnnotation} from "sketcher/constr/constraintAnnotation";
|
||||||
|
import {editConstraint} from "sketcher/actions/constraintActions";
|
||||||
|
|
||||||
export class BasePanTool extends Tool {
|
export class BasePanTool extends Tool {
|
||||||
|
|
||||||
|
|
@ -51,6 +53,15 @@ export class BasePanTool extends Tool {
|
||||||
this.startDragging(e);
|
this.startDragging(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dblclick() {
|
||||||
|
const [obj] = this.viewer.selected;
|
||||||
|
if (isConstraintAnnotation(obj)) {
|
||||||
|
editConstraint(this.viewer.applicationContext, obj.constraint, () => {
|
||||||
|
this.viewer.parametricManager.constraintUpdated(obj.constraint);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
startDragging(e) {}
|
startDragging(e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,9 +55,11 @@ export class Viewer {
|
||||||
interactiveScale: number;
|
interactiveScale: number;
|
||||||
unscale: number;
|
unscale: number;
|
||||||
customSelectionHandler: any;
|
customSelectionHandler: any;
|
||||||
|
applicationContext: any;
|
||||||
|
|
||||||
constructor(canvas, IO) {
|
constructor(canvas, IO, applicationContext) {
|
||||||
|
|
||||||
|
this.applicationContext = applicationContext;
|
||||||
this.presicion = 3;
|
this.presicion = 3;
|
||||||
this.canvas = canvas;
|
this.canvas = canvas;
|
||||||
this.io = new IO(this);
|
this.io = new IO(this);
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,10 @@
|
||||||
<div style="width: 100%; height: calc(100% - 65px); display: flex;">
|
<div style="width: 100%; height: calc(100% - 65px); display: flex;">
|
||||||
|
|
||||||
<div id="dock" class="panel b-right scroll" style="width: 245px; height: 100%; flex-shrink: 0;"></div>
|
<div id="dock" class="panel b-right scroll" style="width: 245px; height: 100%; flex-shrink: 0;"></div>
|
||||||
|
|
||||||
<div id="viewer-container" style="background: #808080; overflow: hidden; height: 100%; position: relative; flex-grow: 1;">
|
<div id="viewer-container" style="background: #808080; overflow: hidden; height: 100%; position: relative; flex-grow: 1;">
|
||||||
|
<div id="react-controls"></div>
|
||||||
<div class="tool-hint" style="position: absolute; bottom: 5px; right: 5px;"></div>
|
<div class="tool-hint" style="position: absolute; bottom: 5px; right: 5px;"></div>
|
||||||
<canvas width="300" height="300" id="viewer"></canvas>
|
<canvas width="300" height="300" id="viewer"></canvas>
|
||||||
<div id="react-controls" style="position: absolute; top: 0; right: 0; left: 0; height: 0;"></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="right-toolbar" class="panel b-left scroll" style="height: 100%; flex-shrink: 0"></div>
|
<div id="right-toolbar" class="panel b-left scroll" style="height: 100%; flex-shrink: 0"></div>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue