refactor App2d class(terminal and property view), remove legacy UI toolkit and its helpers

This commit is contained in:
Val Erastov (xibyte) 2020-03-22 17:33:06 -07:00
parent 557b3474ee
commit 13eb317c89
35 changed files with 748 additions and 1305 deletions

View file

@ -12,7 +12,7 @@ export default class Window extends React.Component {
resizeHelper = new ResizeHelper();
render() {
let {initWidth, initHeight, initLeft, initTop, setFocus, className,
let {initWidth, initHeight, initLeft, initTop, initRight, initBottom, setFocus, className,
resizeCapturingBuffer, resize,
children, title, icon, minimizable, onClose, ...props} = this.props;
return <div className={cx(ls.root, className)} {...props} ref={this.keepRef}>
@ -97,7 +97,7 @@ export default class Window extends React.Component {
if (el === null) {
return;
}
let {initWidth, initHeight, initLeft, initTop, resize, resizeCapturingBuffer, onResize, ...props} = this.props;
let {initWidth, initHeight, initLeft, initTop, initRight, initBottom, resize, resizeCapturingBuffer, onResize, ...props} = this.props;
if (initWidth) {
el.style.width = initWidth + 'px';
}
@ -106,10 +106,13 @@ export default class Window extends React.Component {
}
if (initLeft) {
el.style.left = initLeft + 'px';
} else if (initRight) {
el.style.left = (window.innerWidth - el.offsetWidth - initRight) + 'px';
}
if (initTop) {
el.style.top = initTop + 'px';
} else if (initBottom) {
el.style.top = (window.innerHeight - el.offsetHeight - initBottom) + 'px';
}
this.resizeHelper.registerResize(el, resize, resizeCapturingBuffer);
this.el = el;
@ -121,10 +124,11 @@ Window.defaultProps = {
minimizable: false,
};
class ResizeHelper {
export class ResizeHelper {
constructor () {
constructor (controlGlobalListeners = false) {
this.moveHandler = null;
this.controlGlobalListeners = controlGlobalListeners;
}
captureResize(el, dirMask, e, onResize) {
@ -166,6 +170,20 @@ class ResizeHelper {
if (onResize !== undefined) {
onResize();
}
};
if (this.controlGlobalListeners) {
const moveListener = e => {
if (this.moveHandler) {
this.moveHandler(e);
}
};
const quitListener = e => {
this.moveHandler = null;
document.removeEventListener("mousemove", moveListener);
document.removeEventListener("mouseup", quitListener);
};
document.addEventListener("mousemove", moveListener);
document.addEventListener("mouseup", quitListener);
}
};

View file

@ -36,7 +36,7 @@ export default class NumberControl extends React.Component {
}
this.input.value = val;
onChange(val);
e.preventDefault();
// e.preventDefault();
e.stopPropagation();
}
}

View file

@ -1,3 +1,3 @@
.radioButton {
margin-left: 1px;
margin-left: 5px;
}

View file

@ -8,10 +8,12 @@
.button-behavior(@color) {
&:hover {
background-color: @color;
background-color: @color;
border-color: @color;
}
&:active {
background-color: darken(@color, 20%);
border-color: darken(@color, 20%);
}
}

View file

@ -152,7 +152,7 @@ export default [
appearance: {
info: 'Point On Line',
label: 'point & line',
icon32: 'ui.styles.init.svg'
icon32: 'img/vec/pointOnLine.svg'
},
invoke: ({services}) => {
let viewer = services.sketcher.inPlaceEditor.viewer;
@ -165,7 +165,7 @@ export default [
appearance: {
info: 'Point On Arc / Ellipse',
label: 'point & arc',
icon32: 'ui.styles.init.svg'
icon32: 'img/vec/pointOnArc.svg'
},
invoke: ({services}) => {
let viewer = services.sketcher.inPlaceEditor.viewer;
@ -178,7 +178,7 @@ export default [
appearance: {
info: 'Point In the Middle',
label: 'point @ middle',
icon32: 'ui.styles.init.svg'
icon32: 'img/vec/pointInMiddle.svg'
},
invoke: ({services}) => {
let viewer = services.sketcher.inPlaceEditor.viewer;
@ -191,7 +191,7 @@ export default [
appearance: {
info: 'Angle Between 2 Lines',
label: 'angle',
icon32: 'ui.styles.init.svg'
icon32: 'img/vec/angle.svg'
},
invoke: ({services}) => {
let viewer = services.sketcher.inPlaceEditor.viewer;
@ -204,7 +204,7 @@ export default [
appearance: {
info: 'Symmetry',
label: 'symmetry',
icon32: 'ui.styles.init.svg'
icon32: 'img/vec/symmetry.svg'
},
invoke: ({services}) => {
let viewer = services.sketcher.inPlaceEditor.viewer;
@ -228,7 +228,7 @@ export default [
appearance: {
info: 'Lock Convexity',
label: 'convex',
icon32: 'ui.styles.init.svg'
icon32: 'img/vec/convex.svg'
},
invoke: ({services}) => {
let viewer = services.sketcher.inPlaceEditor.viewer;

View file

@ -1,24 +1,20 @@
import '../css/app.less'
import 'ui/styles/init/index.less';
import '../css/app.less'
import App2D from './sketcher/sketcher-app';
import {Layer} from './sketcher/viewer2d';
import * as ui from './ui/ui.js';
import * as toolkit from './ui/toolkit';
import {Constraints} from './sketcher/parametric'
import './utils/jqueryfy'
import ReactDOM from "react-dom";
import {SketcherApp} from "./sketcher/components/SketcherApp";
import React from "react";
import {stream} from "lstream";
import {loadUIState, saveUIState} from "./sketcher/uiState";
import {Scope} from "./sketcher/components/Scope";
import {createElement} from "./utils/domUtils";
function initializeSketcherApplication() {
var app = new App2D();
const app = new App2D();
window.__CAD_APP = app;
var sketchId = app.getSketchId();
const sketchId = app.getSketchId();
if (sketchId === App2D.STORAGE_PREFIX + '__sample2D__') {
// var sample = '{"layers":[{"name":"_dim","style":{"lineWidth":1,"strokeStyle":"#bcffc1","fillStyle":"#00FF00"},"data":[{"id":0,"_class":"TCAD.TWO.DiameterDimension","obj":90},{"id":1,"_class":"TCAD.TWO.DiameterDimension","obj":95},{"id":2,"_class":"TCAD.TWO.DiameterDimension","obj":42},{"id":3,"_class":"TCAD.TWO.Dimension","a":5,"b":8,"flip":false},{"id":4,"_class":"TCAD.TWO.DiameterDimension","obj":105}]},{"name":"sketch","style":{"lineWidth":2,"strokeStyle":"#ffffff","fillStyle":"#000000"},"data":[{"id":11,"_class":"TCAD.TWO.Segment","points":[[5,[6,110.1295615870824],[7,313.66509156975803]],[8,[9,419.44198895058975],[10,516.7065215258621]]]},{"id":18,"_class":"TCAD.TWO.Segment","points":[[12,[13,489.1218947877601],[14,477.98601743930897]],[15,[16,481.90945628911174],[17,182.9391540301952]]]},{"id":25,"_class":"TCAD.TWO.Segment","points":[[19,[20,427.6872468325118],[21,163.96220645927505]],[22,[23,349.9023145352797],[24,256.7344291384989]]]},{"id":32,"_class":"TCAD.TWO.Segment","points":[[26,[27,306.81261277555075],[28,273.1404656521002]],[29,[30,135.09050734792822],[31,247.98348666778958]]]},{"id":42,"_class":"TCAD.TWO.Arc","points":[[33,[34,489.1218947877601],[35,477.98601743930897]],[36,[37,419.44198895058975],[38,516.7065215258621]],[39,[40,444.1353623657045],[41,479.08688157090376]]]},{"id":53,"_class":"TCAD.TWO.Arc","points":[[44,[45,427.6872468325118],[46,163.96220645927505]],[47,[48,481.90945628911174],[49,182.9391540301952]],[50,[51,451.2148840882273],[52,183.68960424767275]]]},{"id":64,"_class":"TCAD.TWO.Arc","points":[[55,[56,349.9023145352797],[57,256.7344291384989]],[58,[59,306.81261277555075],[60,273.1404656521002]],[61,[62,313.6665992835383],[63,226.35256652594512]]]},{"id":75,"_class":"TCAD.TWO.Arc","points":[[66,[67,110.1295615870824],[68,313.66509156975803]],[69,[70,135.09050734792822],[71,247.98348666778958]],[72,[73,129.8749213918784],[74,283.58516027516237]]]},{"id":80,"_class":"TCAD.TWO.Circle","c":[77,[78,444.1353623657045],[79,479.08688157090376]],"r":17},{"id":85,"_class":"TCAD.TWO.Circle","c":[82,[83,451.2148840882273],[84,183.68960424767275]],"r":17},{"id":90,"_class":"TCAD.TWO.Circle","c":[87,[88,129.8749213918784],[89,283.58516027516237]],"r":17},{"id":95,"_class":"TCAD.TWO.Circle","c":[92,[93,364.7627927122075],[94,358.27520724354514]],"r":50},{"id":100,"_class":"TCAD.TWO.Circle","c":[97,[98,450.6425914465028],[99,356.1758703461729]],"r":13},{"id":105,"_class":"TCAD.TWO.Circle","c":[102,[103,281.1241663120215],[104,360.3197585470608]],"r":13}]},{"name":"_construction_","style":{"lineWidth":1,"strokeStyle":"#aaaaaa","fillStyle":"#000000"},"data":[{"id":113,"_class":"TCAD.TWO.Segment","points":[[107,[108,366.96497096679207],[109,448.36204633886825]],[110,[111,362.6842565514955],[112,273.2463262825022]]]},{"id":120,"_class":"TCAD.TWO.Segment","points":[[114,[115,254.60331148100178],[116,360.9680624545806]],[117,[118,474.9222739434132],[119,355.5823520325097]]]}]}],"constraints":[["Tangent",[42,18]],["Tangent",[42,11]],["coi",[33,12]],["coi",[36,8]],["Tangent",[53,25]],["Tangent",[53,18]],["coi",[44,19]],["coi",[47,15]],["Tangent",[64,25]],["Tangent",[64,32]],["coi",[55,22]],["coi",[58,26]],["Tangent",[75,11]],["Tangent",[75,32]],["coi",[66,5]],["coi",[69,29]],["coi",[77,39]],["coi",[82,50]],["coi",[87,72]],["RR",[80,85]],["RR",[85,90]],["parallel",[113,18]],["perpendicular",[120,113]],["Symmetry",[92,120]],["PointOnLine",[92,113]],["PointOnLine",[102,120]],["PointOnLine",[97,120]],["RR",[105,100]]]}';
// localStorage.setItem(sketchId, sample);
@ -27,111 +23,12 @@ function initializeSketcherApplication() {
app.fit();
const constraintsView = app.dock.views['Constraints'];
// function configureConstraintsFilter() {
// var constraintsCaption = constraintsView.node.find('.tool-caption');
// var constraintsFilterBtn = ui.faBtn("filter");
// constraintsFilterBtn.css({'float': 'right', 'margin-right': '10px', cursor: 'pointer'});
// constraintsCaption.append(constraintsFilterBtn);
// var constraintsFilterWin = new ui.Window($('#constrFilter'), app.winManager);
// ui.bindOpening(constraintsFilterBtn, constraintsFilterWin);
// var content = constraintsFilterWin.root.find('.content');
//
// var constrTypes = [], constrType;
// for (var cname in Constraints) {
// c = Constraints[cname];
// if (c.prototype !== undefined && c.prototype.UI_NAME !== undefined && !c.prototype.aux) {
// constrTypes.push(c);
// }
// }
// constrTypes.sort(function (a, b) {
// if (a.prototype.NAME == 'coi') {
// return b.prototype.NAME == 'coi' ? 0 : -1;
// }
// return a.prototype.UI_NAME.localeCompare(b.prototype.UI_NAME)
// });
// for (var i = 0; i < constrTypes.length; i++) {
// var c = constrTypes[i];
// if (c.prototype !== undefined && c.prototype.UI_NAME !== undefined && !c.prototype.aux) {
// var checkbox = $('<input>', {type : 'checkbox', checked : 'checked', value : c.prototype.NAME});
// content.append(
// $('<label>', { css : {display : 'block', 'white-space' : 'nowrap'}})
// .append(checkbox)
// .append(c.prototype.UI_NAME)
// );
// checkbox.change(function(){
// var checkbox = $(this);
// app.constraintFilter[checkbox.val()] = checkbox.is(':checked') != true;
// constrList.refresh();
// });
// }
// }
// }
// configureConstraintsFilter();
constraintsView.node.append($('<div id="constraint-list"></div>'));
var addingModeRadio = new toolkit.InlineRadio(['sketch', 'construction'], ['sketch', 'construction'], 0);
app.dock.views['Properties'].node.append('<div>Adding Mode</div>').append(addingModeRadio.root);
addingModeRadio.root.find('input:radio').change(() => {
app.viewer.addingRoleMode = addingModeRadio.getValue();
});
var layerSelection = new toolkit.Combo('layerSelection', 'Layer');
app.dock.views['Properties'].node.append(layerSelection.root);
var updateLayersList = function () {
var options = '';
for (var i = 0; i < app.viewer.layers.length; i++) {
var layer = app.viewer.layers[i];
options += "<option value='"+layer.name+"'>"+layer.name+"</option>"
}
layerSelection.select.html(options).val(app.viewer.activeLayer.name);
};
updateLayersList();
app.viewer.bus.subscribe("activeLayer", function() {
updateLayersList();
});
layerSelection.select
.mousedown(updateLayersList)
.change(function () {
var layer = app.viewer.findLayerByName(layerSelection.select.val());
if (layer != null) {
app.viewer.activeLayer = layer;
}
});
var dimScale = new toolkit.Number("Dim Scale", 1, 0.1, 1);
dimScale.min = 0.1;
app.dock.views['Properties'].node.append(dimScale.root);
dimScale.input.on('t-change', function() {
app.viewer.dimScale = $(this).val();
});
app.viewer.bus.subscribe('dimScale', function(value) {
dimScale.input.val(value);
});
var constantTextArea = $('<textarea />', {id: 'dimTextArea', placeholder : 'for example: A = 50', css: {
width: '100%',
resize: 'vertical',
height: 100,
background: 'inherit',
border : 'none',
color: '#C4E1A4'
} });
app.viewer.params.subscribe('constantDefinition', 'constantTextArea', function(value) {
constantTextArea.val(value);
})();
constantTextArea.bind("change", function() {
app.viewer.params.set('constantDefinition', $(this).val(), 'constantTextArea');
});
app.dock.views['Dimensions'].node.append(constantTextArea);
constraintsView.node.append(createElement("div", "constraint-list"));
app.dock.views['Properties'].node.append(createElement("div", "properties-view"));
app.dock.views['Dimensions'].node.append(createElement("div", "dimension-view"));
loadUIState(app.dock);
app.dock.show('Constraints');
window.addEventListener("beforeunload", () => {
saveUIState(app.dock);
@ -153,4 +50,5 @@ function startReact(appCtx) {
);
}
$( () => initializeSketcherApplication() );
window.addEventListener('DOMContentLoaded', () => initializeSketcherApplication());

View file

@ -1,6 +1,6 @@
import {MdZoomOutMap} from "react-icons/md";
import {AiOutlineCopy, AiOutlineExport, AiOutlineFile, AiOutlineFolderOpen, AiOutlineSave} from "react-icons/ai";
import * as ui from "../../ui/ui";
import {NoIcon} from "../icons/NoIcon";
export default [
@ -86,4 +86,17 @@ export default [
}
},
{
id: 'ToggleTerminal',
shortName: 'Toggle Terminal',
kind: 'Common',
description: 'Open/Close Terminal Window',
icon: NoIcon,
invoke: (ctx) => {
ctx.ui.$showTerminalRequest.update(shown => shown ? null : 'please open');
}
},
]

View file

@ -22,10 +22,11 @@ const ACTIONS = [
//keep going here
];
const ALL_ACTIONS = [
export const ALL_ACTIONS = [
...ALL_CONTEXTUAL_ACTIONS,
...ACTIONS
];
Object.freeze(ALL_ACTIONS);
const index = {};
ALL_ACTIONS.forEach(a => index[a.id] = a);
@ -51,6 +52,10 @@ export function getSketcherAction(actionId) {
return index[actionId];
}
export function getAllSketcherActions() {
return ALL_ACTIONS;
}
//For backward compatibility
export function runActionOrToastWhyNot(actionId, ctx, silent) {
const selection = ctx.viewer.selected;

View file

@ -127,4 +127,46 @@ export function GeneratorButton({prefix='', generator: c, ...props}) {
</div>
}
}
// function configureConstraintsFilter() {
// var constraintsCaption = constraintsView.node.find('.tool-caption');
// var constraintsFilterBtn = ui.faBtn("filter");
// constraintsFilterBtn.css({'float': 'right', 'margin-right': '10px', cursor: 'pointer'});
// constraintsCaption.append(constraintsFilterBtn);
// var constraintsFilterWin = new ui.Window($('#constrFilter'), app.winManager);
// ui.bindOpening(constraintsFilterBtn, constraintsFilterWin);
// var content = constraintsFilterWin.root.find('.content');
//
// var constrTypes = [], constrType;
// for (var cname in Constraints) {
// c = Constraints[cname];
// if (c.prototype !== undefined && c.prototype.UI_NAME !== undefined && !c.prototype.aux) {
// constrTypes.push(c);
// }
// }
// constrTypes.sort(function (a, b) {
// if (a.prototype.NAME == 'coi') {
// return b.prototype.NAME == 'coi' ? 0 : -1;
// }
// return a.prototype.UI_NAME.localeCompare(b.prototype.UI_NAME)
// });
// for (var i = 0; i < constrTypes.length; i++) {
// var c = constrTypes[i];
// if (c.prototype !== undefined && c.prototype.UI_NAME !== undefined && !c.prototype.aux) {
// var checkbox = $('<input>', {type : 'checkbox', checked : 'checked', value : c.prototype.NAME});
// content.append(
// $('<label>', { css : {display : 'block', 'white-space' : 'nowrap'}})
// .append(checkbox)
// .append(c.prototype.UI_NAME)
// );
// checkbox.change(function(){
// var checkbox = $(this);
// app.constraintFilter[checkbox.val()] = checkbox.is(':checked') != true;
// constrList.refresh();
// });
// }
// }
// }
// configureConstraintsFilter();

View file

@ -0,0 +1,88 @@
import {createElement} from "../../utils/domUtils";
export class Dock {
constructor(dockEl, switcherEl, viewDefinitions) {
this.views = {};
this.dockEl = dockEl;
function bindClick(dock, switchEl, viewName) {
switchEl.addEventListener('click', e => {
if (dock.isVisible(viewName)) {
dock.hide(viewName);
} else {
dock.show(viewName);
}
});
}
for (let i = 0; i < viewDefinitions.length; i++) {
let viewDef = viewDefinitions[i];
let view = {};
this.views[viewDef.name] = view;
view.node = createElement('div', undefined, 'dock-node');
let caption = createElement('div', undefined, 'tool-caption');
caption.appendChild(createElement('span', undefined, 'txt', viewDef.name.toUpperCase()));
caption.appendChild(createElement('i', undefined, 'fa fa-'+viewDef.icon));
view.node.appendChild(caption);
// view.node.style.display = 'none';
this.dockEl.appendChild(view.node);
view.switchBtn = dockBtn(viewDef.name, viewDef.icon);
bindClick(this, view.switchBtn, viewDef.name);
switcherEl.appendChild(view.switchBtn);
}
}
show(viewName) {
let view = this.views[viewName];
if (view.switchBtn.classList.contains('selected')) {
return;
}
if (this.dockEl.style.display === 'none') {
this.dockEl.style.display = 'block';
document.body.dispatchEvent(new Event('layout'));
}
view.node.style.display = 'block';
view.switchBtn.classList.add('selected');
}
hide(viewName) {
let view = this.views[viewName];
if (!view.switchBtn.classList.contains('selected')) {
return;
}
view.node.style.display = 'none';
view.switchBtn.classList.remove('selected');
if (Array.from(this.dockEl.querySelectorAll('.dock-node').values()).findIndex(node => node.style.display !== 'none') === -1) {
this.dockEl.style.display = 'none';
document.body.dispatchEvent(new Event('layout'));
}
}
isVisible(viewName) {
return this.views[viewName].switchBtn.classList.contains('selected');
}
setState(state) {
state.forEach(viewName => this.show(viewName));
}
getState() {
const state = [];
Object.keys(this.views).forEach(viewName => {
if (this.isVisible(viewName)) {
state.push(viewName);
}
});
return state;
}
}
export function dockBtn(name, icon) {
const btn = createElement('span', undefined, 'dock-btn');
btn.appendChild(createElement('i', undefined, 'fa fa-' + icon));
btn.appendChild(createElement('span', undefined, 'txt', name));
return btn;
}

View file

@ -1,12 +1,10 @@
import React, {useContext, useEffect, useMemo, useState} from 'react';
import React, {useContext, useMemo, useState} from 'react';
import {SketcherAppContext} from "./SketcherApp";
import {useStreamWithUpdater} from "ui/effects";
import Window from "../../../../modules/ui/components/Window";
import * as ui from "../../ui/ui";
import Window, {DIRECTIONS} from "ui/components/Window";
import App2D from "../sketcher-app";
import Stack from "../../../../modules/ui/components/Stack";
import {DIRECTIONS} from "../../ui/ui";
import Button from "../../../../modules/ui/components/controls/Button";
import Stack from "ui/components/Stack";
import Button from "ui/components/controls/Button";
import {RiDeleteBinLine} from "react-icons/ri";
export function SketchManager() {

View file

@ -13,6 +13,9 @@ import {SketcherToolbar} from "./SketcherToolbar";
import {sketcherRightToolbarConfig, sketcherTopToolbarConfig} from "../uiConfig";
import {SketchManager} from "./SketchManager";
import {ExportDialog} from "./ExportDialog";
import {SketcherPropertiesView} from "./SketcherPropertiesView";
import {SketcherDimensionView} from "./SketcherDimensionsView";
import {SketcherTerminal} from "./TerminalView";
export const SketcherAppContext = React.createContext({});
@ -25,6 +28,14 @@ export function SketcherApp({applicationContext}) {
<Scope><ConstraintList /></Scope>,
document.getElementById('constraint-list')
)}
{ReactDOM.createPortal(
<Scope><SketcherPropertiesView /></Scope>,
document.getElementById('properties-view')
)}
{ReactDOM.createPortal(
<Scope><SketcherDimensionView /></Scope>,
document.getElementById('dimension-view')
)}
{ReactDOM.createPortal(
<Scope><SketcherToolbar actions={sketcherRightToolbarConfig}/></Scope>,
document.getElementById('right-toolbar')
@ -37,6 +48,7 @@ export function SketcherApp({applicationContext}) {
<React.Fragment>
<Scope><SketchManager /></Scope>
<Scope><ExportDialog /></Scope>
<Scope><SketcherTerminal /></Scope>
</React.Fragment>,
document.getElementById('global-windows')
)}

View file

@ -0,0 +1,19 @@
import React from 'react';
import {useStreamWithUpdater} from "ui/effects";
const style = {
width: '100%',
resize: 'vertical',
height: 100,
background: 'inherit',
border : 'none',
color: '#C4E1A4'
};
export function SketcherDimensionView() {
const [definitions, setDefinitions] = useStreamWithUpdater(ctx => ctx.viewer.parametricManager.$constantDefinition);
return <textarea style={style} id='dimTextArea' placeholder='for example: A = 50' value={definitions||''} onChange={e => setDefinitions(e.target.value||null)}/>
}

View file

@ -0,0 +1,27 @@
import React from 'react';
import NumberControl from "ui/components/controls/NumberControl";
import {useStreamWithUpdater} from "ui/effects";
import RadioButtons, {RadioButton} from "ui/components/controls/RadioButtons";
import Stack from "ui/components/Stack";
import Label from "ui/components/controls/Label";
import Field from "ui/components/controls/Field";
export function SketcherPropertiesView() {
const [dimScale, setDimScale] = useStreamWithUpdater(ctx => ctx.viewer.streams.dimScale);
const [addingMode, setAddingMode] = useStreamWithUpdater(ctx => ctx.viewer.streams.addingRoleMode);
return <Stack >
<Field >
<Label>Adding Mode</Label>
<RadioButtons value={addingMode||''} onChange={val => setAddingMode(val||null)}>
<RadioButton value={''} label='sketch' />
<RadioButton value='construction' />
</RadioButtons>
</Field>
<Field >
<Label>Dimension Scale</Label>
<NumberControl min={0.1} baseStep={0.1} round={1} onChange={setDimScale} value={dimScale} />
</Field>
</Stack>;
}

View file

@ -1,3 +1,5 @@
@import "~ui/styles/theme.less";
@import "~ui/styles/mixins.less";
@focus-color: #0065dc;
@focus-color-secondary: rgba(3, 102, 214, .3);
@ -38,6 +40,8 @@
box-shadow: 0 0 0 2px @focus-color-secondary;
outline: none;
}
.button-behavior(@color-neutral);
padding: 1px;
flex-basis: 36px;
display: flex;

View file

@ -0,0 +1,226 @@
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";
export function TerminalView({visible, output, addToOutput, onClose, variantsSupplier, commandProcessor}) {
const [history, setHistory] = useState([]);
const [historyPtr, setHistoryPtr] = useState([]);
const [input, setInput] = useState('');
const [autocomplete, setAutocomplete] = useState([]);
const [shown, setShown] = useState(false);
const outputRef = useRef(null);
const inputRef = useRef(null);
useEffect(() => {
if (outputRef.current) {
outputRef.current.scrollTop = outputRef.current.scrollHeight;
}
}, [autocomplete, output.length]);
useEffect(() => {
if (inputRef.current && visible) {
inputRef.current.focus();
}
});
//deferring creation until first time open
useEffect(() => {
if (visible && !shown) {
setShown(true);
}
}, [visible]);
if (!shown) {
return null;
}
const LIMIT = 20;
const value = historyPtr === history.length ? input : value;
return <Window title='Commands' initWidth={700} initHeight={200} initRight={60} initBottom={35}
className='sketcher-window'
resize={DIRECTIONS.NORTH | DIRECTIONS.SOUTH | DIRECTIONS.WEST | DIRECTIONS.EAST}
onClose={onClose}
style={{
display: visible ? 'flex' : 'none'
}}>
<div className={`${ls.content} panel`} style={{padding: 0}}>
<div className='scroll' ref={outputRef}>
{output.map(({kind, text}, key) => <React.Fragment key={key}>
<div className={ls[kind || 'text']}>{ kind === 'command' ? '> ' : ''} {text}</div>
</React.Fragment>)}
{
autocomplete.length > 0 && <div className={ls.autocompleteArea}>
{autocomplete.slice(0, LIMIT).map(variant => <span key={variant}>{variant}</span>)}
{autocomplete.length > LIMIT && <span>... and {autocomplete.length - LIMIT} more</span>}
</div>
}
</div>
<div className={ls.terminalInput}>
<input type="text" placeholder="(type a command)"
ref={inputRef}
value={input}
onChange={e => {
setHistoryPtr(history.length);
setInput(e.target.value)
}}
onKeyDown={e => {
function consumeEvent() {
e.preventDefault();
e.stopPropagation();
}
if (e.keyCode === 9) {
const text = e.target.value;
let variants = variantsSupplier().filter(v => v.startsWith(text));
variants.sort();
if (variants.length !== 0) {
const shared = sharedStartOfSortedArray(variants);
if (shared.length !== text.length) {
setInput(shared);
}
}
setAutocomplete(variants);
consumeEvent();
} else if (e.keyCode === 38) {
setHistoryPtr(ptr => Math.max(ptr - 1, 0));
consumeEvent();
} else if (e.keyCode === 40) {
setHistoryPtr(ptr => {
if (ptr !== history.length) {
Math.min(ptr + 1, history.length - 1)
}
});
consumeEvent();
}
}}
onKeyUp={e => {
if (e.keyCode === 13) {
const command = e.target.value;
setAutocomplete([]);
setInput('');
addToOutput(
{
kind: 'command',
text: command
}
);
const commandStr = command.trim();
if (commandStr) {
commandProcessor(commandStr, addToOutput);
if (history.length === 0 || command !== history[history.length - 1]) {
setHistory(history => [...history, command]);
}
}
setHistoryPtr(history.length);
}
}}
/>
</div>
</div>
</Window>
}
// ----------------------------------------------------------------------------------------------- //
const getCommands = memoize(allActions => ([
...allActions.filter(a => a.command).map(a => a.command),
'help'
]));
const byCommand = memoize(allActions => {
const out = {};
allActions.forEach(a => {
if (a.command) {
out[a.command] = a;
}
});
return out;
});
const variantsSupplier = () => getCommands(getAllSketcherActions());
const DEFAULT_COMMAND_HANDLER = (command, println, ctx) => {
if (command === 'help') {
println({text: getCommands(getAllSketcherActions()).join(', ')});
}
if (ctx.viewer.toolManager.tool.processCommand) {
ctx.viewer.toolManager.tool.processCommand(command);
return;
}
let action = byCommand(getAllSketcherActions())[command];
if (action) {
println({text: action.shortName});
action.invoke(ctx);
} else {
try {
const output = eval(command);
println({text: output});
} catch (e) {
}
}
};
function printToSketchTerminal(text, ctx) {
ctx.ui.$terminalOutput.update(output => ([...output, {
text
}]));
}
const commandHandlerStack = [DEFAULT_COMMAND_HANDLER];
export function captureSketcherTerminal(handler) {
commandHandlerStack.push(handler);
}
export function releaseSketcherTerminal(handler) {
if (commandHandlerStack.length > 1) {
commandHandlerStack.pop();
}
}
export function SketcherTerminal() {
const [request, setRequest] = useStreamWithUpdater(ctx => ctx.ui.$showTerminalRequest);
const [output, setOutput] = useStreamWithUpdater(ctx => ctx.ui.$terminalOutput);
const ctx = useContext(SketcherAppContext);
const addToOutput = useCallback(line => setOutput(output => {
output.push(line);
return output;
}), [setOutput]);
useEffect(() => {
ctx.viewer.referencePoint.visible = !!request;
ctx.viewer.refresh();
}, [request]);
return <TerminalView visible={!!request}
onClose={() => setRequest(null)}
variantsSupplier={variantsSupplier}
output={output}
addToOutput={addToOutput}
commandProcessor={(command, println) => commandHandlerStack[commandHandlerStack.length - 1](command, println, ctx)}
/>
}
function sharedStartOfSortedArray(array) {
let a1 = array[0], a2 = array[array.length - 1], L = a1.length, i = 0;
while (i < L && a1.charAt(i) === a2.charAt(i)) i++;
return a1.substring(0, i);
}

View file

@ -0,0 +1,39 @@
.content {
font-family: Monaco, monospace;
color: #C4E1A4;
font-size: 11px;
display: flex;
flex-direction: column;
height: 100%;
justify-content: flex-end;
}
.terminalInput input {
color: #C4E1A4;
background: inherit;
outline: none;
border: 0;
margin-top: 4px;
padding: 3px;
width: 100%;
box-sizing: border-box;
padding-left: 0;
}
.terminalInput input::-webkit-input-placeholder {
color: #777777;
font-style: italic;
}
.command {
color: #777777;
}
.autocompleteArea {
font-style: italic;
display: flex;
span {
padding-right: 5px;
}
}

View file

@ -244,7 +244,7 @@ IO.prototype._loadSketch = function(sketch) {
}
let constants = sketch.constants;
if (constants !== undefined) {
this.viewer.params.constantDefinition = constants;
this.viewer.parametricManager.$constantDefinition.next(constants);
}
this.viewer.parametricManager.finishTransaction();
@ -421,10 +421,15 @@ IO.prototype._serializeSketch = function(metadata) {
sketch.stages.push(stageOut);
}
var constantDefinition = this.viewer.params.constantDefinition;
const constantDefinition = this.viewer.parametricManager.constantDefinition;
if (constantDefinition !== undefined && constantDefinition != null && !/^\s*$/.test(constantDefinition)) {
sketch.constants = constantDefinition;
}
sketch.scene = {
dx: this.viewer.translate.x,
dy: this.viewer.translate.y,
scale: this.viewer.scale,
};
sketch.metadata = metadata;
sketch.version = 2;
return sketch;

View file

@ -28,10 +28,12 @@ class ParametricManager {
pointer: -1
});
$constantDefinition = state('');
constructor(viewer) {
this.viewer = viewer;
this.viewer.params.define('constantDefinition', null);
this.viewer.params.subscribe('constantDefinition', 'parametricManager', this.onConstantsExternalChange, this)();
this.$constantDefinition.attach((def) => this.rebuildConstantTable(def))
this.reset();
@ -61,6 +63,10 @@ class ParametricManager {
return this.stage.algNumSystem;
}
get constantDefinition() {
return this.$constantDefinition.value;
}
startTransaction() {
this.inTransaction = true;
for (let stage of this.stages) {
@ -110,7 +116,6 @@ class ParametricManager {
this.constantTable[constant] = value;
prefix += "const " + constant + " = " + value + ";\n"
} catch(e) {
console.log(e);
}
}
}
@ -122,16 +127,14 @@ class ParametricManager {
};
defineNewConstant(name, value) {
let constantDefinition = this.viewer.params.constantDefinition;
let constantDefinition = this.constantDefinition;
let constantText = name + ' = ' + value;
if (constantDefinition) {
constantDefinition += '\n' + constantText;
} else {
constantDefinition = constantText;
}
this.rebuildConstantTable(constantDefinition);
//disabling onConstantsExternalChange since we don't need re-solve
this.viewer.params.set('constantDefinition', constantDefinition, 'parametricManager');
this.$constantDefinition.next(constantDefinition);
};
updateConstraintConstants(constr) {

View file

@ -1,105 +1,162 @@
import {Viewer} from './viewer2d.js'
import * as ui from '../ui/ui'
import {Terminal} from '../ui/terminal'
import {BBox, IO} from './io'
import {InputManager} from './input-manager'
import genSerpinski from '../utils/genSerpinski';
import React from "react";
import {stream} from "../../../modules/lstream";
import {stream, state} from "lstream";
import {Dock, dockBtn} from "./components/Dock";
import {DIRECTIONS, ResizeHelper} from "../../../modules/ui/components/Window";
import {getSketcherAction} from "./actions";
function App2D() {
var app = this;
class App2D {
this.viewer = new Viewer(document.getElementById('viewer'), IO);
this.context = createAppContext(this.viewer, this);
this.winManager = new ui.WinManager();
this.inputManager = new InputManager(this);
constructor() {
this.constraintFilter = {};
this.actions = {};
this.commands = {};
this.viewer = new Viewer(document.getElementById('viewer'), IO);
this.context = createAppContext(this.viewer, this);
this.inputManager = new InputManager(this);
//For debug view
this._actionsOrder = [];
this.actions = {};
var dockEl = $('#dock');
var buttonGroup = $('#status .button-group');
this.dock = new ui.Dock(dockEl, buttonGroup, App2D.views);
this.dock.show('Constraints');
var consoleBtn = ui.dockBtn('Commands', 'list');
buttonGroup.append(consoleBtn);
this.commandsWin = new ui.Window($('#commands'), this.winManager);
this.commandsWin.tileUpRelative = $('#viewer');
consoleBtn.click((e) => {
this.actions['terminal'].action(e)
});
$(document).on('mousemove', '#viewer', (e) => {
let coord = this.viewer.screenToModel(e);
$('.coordinates-info').text(this.viewer.roundToPrecision(coord.x) + " : " + this.viewer.roundToPrecision(coord.y));
});
this.terminalHandler = undefined;
this.terminal = new Terminal(this.commandsWin, (command) => this.handleTerminalInput(command), () => this.getAllCommandList());
this.bindToolsToTerminal();
this.winManager.registerResize(dockEl, ui.DIRECTIONS.EAST, function() {$('body').trigger('layout'); });
$('body').on('layout', this.viewer.onWindowResize);
this.registerAction = function(id, desc, action, command) {
app.actions[id] = {id, desc, action};
if (command) {
app.commands[command] = id;
}
app._actionsOrder.push(id);
};
function checkForTerminalVisibility() {
const terminalVisible = app.commandsWin.root.is(':visible');
if (terminalVisible) {
app.terminal.scrollToTheEnd();
}
app.viewer.referencePoint.visible = terminalVisible;
this.initNonReactUIParts();
}
checkForTerminalVisibility();
this.registerAction('terminal', "Open/Close Terminal Window", function () {
app.commandsWin.toggle();
checkForTerminalVisibility();
app.viewer.refresh();
});
fit() {
this.registerAction('undo', "Undo", function () {
app.viewer.historyManager.undo();
});
const bbox = new BBox();
this.viewer.accept(obj => {
bbox.check(obj);
return true;
});
if (!bbox.isValid()) {
return;
}
this.registerAction('redo', "Redo", function () {
app.viewer.historyManager.redo();
});
const bounds = bbox.bbox;
this.viewer.showBounds(bounds[0], bounds[1], bounds[2], bounds[3]);
bbox.inc(20 / this.viewer.scale);
this.viewer.showBounds(bounds[0], bounds[1], bounds[2], bounds[3]);
}
this.registerAction('checkpoint', "Checkpoint", function () {
app.viewer.historyManager.checkpoint();
});
cloneSketch() {
let name = prompt("Name for sketch clone");
if (name != null) {
if (this.isSketchExists(name)) {
alert("Sorry, a sketch with the name '" + name + "' already exists. Won't override it.");
return;
}
localStorage.setItem(App2D.STORAGE_PREFIX + name, this.viewer.io.serializeSketch());
this.openSketch(name);
}
}
isSketchExists(name) {
return localStorage.getItem(App2D.STORAGE_PREFIX + name) != null;
}
openSketch(name) {
let uri = window.location.href.split("#")[0];
if (name !== "untitled") {
uri += "#" + name;
}
let win = window.open(uri, '_blank');
win.focus();
}
this.registerAction('solve', "Solve System", function () {
app.viewer.parametricManager.solve();
app.viewer.refresh();
});
newSketch() {
let name = prompt("Name for sketch");
if (name != null) {
if (this.isSketchExists(name)) {
alert("Sorry, a sketch with the name '" + name + "' already exists. Won't override it.");
return;
}
this.openSketch(name);
}
}
this.registerAction('CLEAN UP', "Clean All Draw", function () {
app.cleanUpData();
app.viewer.refresh();
});
loadFromLocalStorage() {
let sketchId = this.getSketchId();
let sketchData = localStorage.getItem(sketchId);
if (sketchData != null) {
this.viewer.historyManager.init(sketchData);
this.viewer.io.loadSketch(sketchData);
}
this.viewer.repaint();
}
getSketchId() {
let id = window.location.hash.substring(1);
if (!id) {
id = "untitled";
}
return App2D.STORAGE_PREFIX + id;
}
this.registerAction('genSerpinski', "Generate Serpinki Triangle off of a segment", function () {
genSerpinski(app.viewer);
});
printToTerminal(text) {
this.context.ui.$terminalOutput.mutate(output => output.push({
text
}));
}
initNonReactUIParts() {
//Keep all legacy UI artifacts here.
const dockEl = document.getElementById('dock');
const bottomButtonGroup = document.querySelector('#status .button-group');
this.dock = new Dock(dockEl, bottomButtonGroup, AppDockViews);
this.dock.show('Constraints');
const resizeHelper = new ResizeHelper(true);
resizeHelper.registerResize(dockEl, DIRECTIONS.EAST, 5, () => document.body.dispatchEvent(new Event('layout')));
document.body.addEventListener('layout', this.viewer.onWindowResize);
const consoleBtn = dockBtn('Commands', 'list');
bottomButtonGroup.appendChild(consoleBtn);
consoleBtn.addEventListener('click', () => {
getSketcherAction('ToggleTerminal').invoke(this.context);
});
this.context.ui.$showTerminalRequest.attach(show => {
if (show) {
consoleBtn.classList.add('selected');
} else {
consoleBtn.classList.remove('selected');
}
});
const coordInfo = document.querySelector('.coordinates-info');
this.viewer.canvas.addEventListener('mousemove', e => {
const coord = this.viewer.screenToModel(e);
coordInfo.innerText = this.viewer.roundToPrecision(coord.x) + " : " + this.viewer.roundToPrecision(coord.y);
});
this.atatchToToolStreams();
}
atatchToToolStreams() {
this.viewer.streams.tool.$change.attach(tool => {
document.querySelectorAll('.tool-info').forEach(e => e.innerText = tool.name);
document.querySelectorAll('.tool-hint').forEach(e => e.innerText = '');
});
this.viewer.streams.tool.$change.attach(tool => {
document.querySelectorAll('.tool-info').forEach(e => e.innerText = tool.name);
document.querySelectorAll('.tool-hint').forEach(e => e.innerText = '');
});
this.viewer.streams.tool.$message.attach((message) => {
this.printToTerminal(message);
});
this.viewer.streams.tool.$hint.attach((message) => {
this.printToTerminal(message);
document.querySelectorAll('.tool-hint').forEach(e => e.innerText = message);
});
};
}
App2D.views = [
const AppDockViews = [
{
name: 'Dimensions',
icon: 'arrows-v'
@ -111,136 +168,9 @@ App2D.views = [
{
name: 'Constraints',
icon: 'cogs'
},
{
name: 'Mirroring',
icon: 'mirror'
}
];
App2D.prototype.fit = function() {
var bbox = new BBox();
for (var l = 0; l < this.viewer.layers.length; ++l) {
var layer = this.viewer.layers[l];
for (var i = 0; i < layer.objects.length; ++i) {
var obj = layer.objects[i];
bbox.check(obj);
}
}
if (!bbox.isValid()) {
return;
}
var bounds = bbox.bbox;
this.viewer.showBounds(bounds[0], bounds[1], bounds[2], bounds[3]);
bbox.inc(20 / this.viewer.scale);
this.viewer.showBounds(bounds[0], bounds[1], bounds[2], bounds[3]);
};
App2D.prototype.cloneSketch = function() {
var name = prompt("Name for sketch clone");
if (name != null) {
if (this.isSketchExists(name)) {
alert("Sorry, a sketch with the name '" + name + "' already exists. Won't override it.");
return;
}
localStorage.setItem(App2D.STORAGE_PREFIX + name, this.viewer.io.serializeSketch());
this.openSketch(name);
}
};
App2D.prototype.isSketchExists = function(name) {
return localStorage.getItem(App2D.STORAGE_PREFIX + name) != null;
};
App2D.prototype.openSketch = function(name) {
var uri = window.location.href.split("#")[0];
if (name !== "untitled") {
uri += "#" + name;
}
var win = window.open(uri, '_blank');
win.focus();
};
App2D.prototype.newSketch = function() {
var name = prompt("Name for sketch");
if (name != null) {
if (this.isSketchExists(name)) {
alert("Sorry, a sketch with the name '" + name + "' already exists. Won't override it.");
return;
}
this.openSketch(name);
}
};
App2D.prototype.loadFromLocalStorage = function() {
var sketchId = this.getSketchId();
var sketchData = localStorage.getItem(sketchId);
if (sketchData != null) {
this.viewer.historyManager.init(sketchData);
this.viewer.io.loadSketch(sketchData);
}
this.viewer.repaint();
};
App2D.prototype.getSketchId = function() {
var id = window.location.hash.substring(1);
if (!id) {
id = "untitled";
}
return App2D.STORAGE_PREFIX + id;
};
App2D.prototype.bindToolsToTerminal = function() {
const toolCommandProcessor = (command) => this.viewer.toolManager.tool.processCommand(command);
this.viewer.bus.subscribe('tool-change', () => {
var tool = this.viewer.toolManager.tool;
this.terminalHandler = tool.processCommand ? toolCommandProcessor : undefined;
$('.tool-info').text('tool: ' + tool.name);
$('.tool-hint').text('');
})();
this.viewer.bus.subscribe('tool-message', (message) => {
this.terminal.print(message);
});
this.viewer.bus.subscribe('tool-hint', (message) => {
this.terminal.print(message);
$('.tool-hint').text(message);
});
};
App2D.STATIC_COMMANDS = {
"time" : () => new Date(),
"help" : (app) => app.getAllCommandList().join(", ")
};
App2D.prototype.getAllCommandList = function() {
const commands = Object.keys(this.commands);
commands.push.apply(commands, Object.keys(App2D.STATIC_COMMANDS));
commands.sort();
return commands;
};
App2D.prototype.handleTerminalInput = function(commandStr) {
commandStr = commandStr.trim();
if (this.terminalHandler) {
return this.terminalHandler(commandStr);
} else {
let cmd = App2D.STATIC_COMMANDS[commandStr];
if (cmd) {
return cmd(this);
}
let actionId = this.commands[commandStr];
if (actionId) {
this.actions[actionId].action();
} else {
try {
return eval(commandStr);
} catch(e) {
}
}
}
};
function createAppContext(viewer, app) {
return {
@ -250,7 +180,9 @@ function createAppContext(viewer, app) {
$constraintEditRequest: stream(),
$wizardRequest: stream(),
$sketchManagerRequest: stream(),
$exportDialogRequest: stream()
$exportDialogRequest: stream(),
$showTerminalRequest: state(null),
$terminalOutput: state([])
}
};
}

View file

@ -14,6 +14,12 @@ export default function(viewer) {
streams.addingRoleMode = state(null);
streams.selection = state([]);
streams.objectUpdate = stream();
streams.dimScale = state(1);
streams.tool = {
$change: stream(),
$message: stream(),
$hint: stream()
};
return streams;
};

View file

@ -79,7 +79,7 @@ export class ToolManager {
switchTool(tool) {
this.tool = tool;
this.viewer.bus.dispatch("tool-change");
this.viewer.streams.tool.$change.next(tool);
}
releaseControl() {

View file

@ -26,11 +26,11 @@ export class Tool {
keyup(e) {};
sendMessage(text) {
this.viewer.bus.dispatch('tool-message', text);
this.viewer.streams.tool.$message.next(text);
};
sendHint(hint) {
this.viewer.bus.dispatch('tool-hint', hint);
this.viewer.streams.tool.$hint.next(hint);
};
sendSpecifyPointHint() {

View file

@ -2,6 +2,7 @@ import constraintGlobalActions from "./actions/constraintGlobalActions";
import measureActions from "./actions/measureActions";
import toolActions from "./actions/toolActions";
import commonActions from "./actions/commonActions";
import {removeInPlace} from "../../../modules/gems/iterables";
export const sketcherRightToolbarConfig = constraintGlobalActions.map(a => a.id);
@ -22,4 +23,6 @@ function insertAfter(arr, item, toAdd) {
if (index !== -1) {
arr.splice(index+1, 0, toAdd);
}
}
}
removeInPlace(sketcherTopToolbarConfig, 'ToggleTerminal');

View file

@ -3,8 +3,8 @@ export function saveUIState(dock) {
const state = {
};
state.dockWidth = Math.round(dock.dockEl.get(0).offsetWidth);
state.views = dock.getState();
state.dockWidth = Math.round(dock.dockEl.offsetWidth);
// state.views = dock.getState();
const dimTextArea = document.getElementById('dimTextArea');
if (dimTextArea) {
@ -24,7 +24,7 @@ export function loadUIState(dock) {
const state = JSON.parse(stateStr);
if (state.dockWidth) {
dock.dockEl.css({width: state.dockWidth + 'px'});;
dock.dockEl.style.width = state.dockWidth + 'px';
}
const dimTextArea = document.getElementById('dimTextArea');
@ -32,9 +32,9 @@ export function loadUIState(dock) {
dimTextArea.style.height = state.dimTextAreaHeight + 'px';
}
if (state.views) {
dock.setState(state.views);
}
// if (state.views) {
// dock.setState(state.views);
// }
} catch (e) {
console.error(e);

View file

@ -1,5 +1,4 @@
import {Styles} from './styles';
import {Bus, Parameters} from '../ui/toolkit';
import {ParametricManager} from './parametric';
import {HistoryManager} from './history';
import {ToolManager} from './tools/manager';
@ -25,15 +24,14 @@ class Viewer {
// used to keep all internal data with such precision transforming the input from user
this.presicion = 3;
this.canvas = canvas;
this.params = new Parameters();
this.io = new IO(this);
this.streams = sketcherStreams(this);
var viewer = this;
const viewer = this;
this.retinaPxielRatio = window.devicePixelRatio > 1 ? window.devicePixelRatio : 1;
function updateCanvasSize() {
var canvasWidth = canvas.parentNode.offsetWidth;
var canvasHeight = canvas.parentNode.offsetHeight;
const canvasWidth = canvas.parentNode.offsetWidth;
const canvasHeight = canvas.parentNode.offsetHeight;
canvas.width = canvasWidth * viewer.retinaPxielRatio;
canvas.height = canvasHeight * viewer.retinaPxielRatio;
@ -54,7 +52,6 @@ class Viewer {
set: viewer.setActiveLayer
});
this.bus = new Bus();
this.ctx = this.canvas.getContext("2d");
this._activeLayer = null;
this.layers = [
@ -63,10 +60,7 @@ class Viewer {
];
this.dimLayer = this.createLayer("_dim", Styles.DIM);
this.dimLayers = [this.dimLayer];
this.bus.defineObservable(this, 'dimScale', 1);
this.bus.subscribe('dimScale', function () {
viewer.refresh();
});
this.streams.dimScale.attach(() => this.refresh());
this._workspace = [this.layers, this.dimLayers];
@ -90,6 +84,10 @@ class Viewer {
this.refresh();
}
get dimScale() {
return this.streams.dimScale.value;
}
get selected() {
return this.captured.selection;
}
@ -304,10 +302,12 @@ class Viewer {
showBounds(x1, y1, x2, y2, offset) {
const dx = Math.max(x2 - x1, 1);
const dy = Math.max(y2 - y1, 1);
if (dx > dy) {
this.scale = this.canvas.height / dx;
const cRatio = this.canvas.width / this.canvas.height;
if (dy * cRatio >= dx) {
this.scale = this.canvas.height / dy;
} else {
this.scale = this.canvas.width / dy;
this.scale = this.canvas.width / dx;
}
this.translate.x = -x1 * this.scale;
this.translate.y = -y1 * this.scale;
@ -473,7 +473,6 @@ class Viewer {
setActiveLayer(layer) {
if (!layer.readOnly) {
this._activeLayer = layer;
this.bus.dispatch("activeLayer");
}
};

View file

@ -1,7 +0,0 @@
export default function( map, block ) {
let out = '';
Object.keys( map ).map(function( prop ) {
out += block.fn( {key: prop, value: map[ prop ]} );
});
return out;
};

View file

@ -1,111 +0,0 @@
export function Terminal(win, commandProcessor, variantsSupplier) {
this.win = win;
this.out = win.root.find('.terminal-output');
const input = win.root.find('.terminal-input input');
this.input = input;
win.onShowCallback = function() {
input.focus();
};
this.makeAlwaysFocusable();
this.history = [];
this.historyPointer = 0;
const setHistory = () => {
if (this.history.length == 0) return;
input.val(this.history[this.historyPointer]);
};
input.keydown((e) => {
function consumeEvent() {
e.preventDefault();
e.stopPropagation();
}
if (e.keyCode == 9) {
const text = input.val();
let variants = variantsSupplier().filter(v => v.startsWith(text));
variants.sort();
if (variants.length == 0) {
} else {
const shared = sharedStartOfSortedArray(variants);
if (shared.length != text.length) {
input.val(shared);
} else {
let autocompleteArea = this.out.find('.autocomplete-area');
if (autocompleteArea.length == 0) {
autocompleteArea = $('<div>', {'class': 'terminal-commandText autocomplete-area'});
this.out.append(autocompleteArea);
}
let more = '';
const limit = 20;
if (variants.length > limit) {
more = '... and ' + (variants.length - limit) + ' more';
variants = variants.slice(0,limit);
}
autocompleteArea.text(variants.join(' ') + more);
this.scrollToTheEnd();
}
}
consumeEvent();
} else if (e.keyCode == 38) {
this.historyPointer = Math.max(this.historyPointer - 1, 0);
setHistory();
consumeEvent();
} else if (e.keyCode == 40) {
if (this.historyPointer != this.history.length) {
this.historyPointer = Math.min(this.historyPointer + 1, this.history.length - 1);
setHistory();
}
consumeEvent();
}
});
input.keyup((e) => {
if(e.keyCode == 13) {
const command = input.val();
this.out.find('.autocomplete-area').remove();
input.val('');
this.out.append($('<div>', {text: '> '+command, 'class': 'terminal-commandText'}));
if (command != null && command.trim().length != 0) {
const result = commandProcessor(command);
this.print(result);
if (this.history.length == 0 || command != this.history[this.history.length - 1]) {
this.history.push(command);
}
this.historyPointer = this.history.length;
}
this.scrollToTheEnd();
}
});
}
Terminal.prototype.makeAlwaysFocusable = function() {
let wasMove = false;
this.win.root.mousedown(() => {
wasMove = false;
return true;
});
this.win.root.mousemove(() => {
wasMove = true;
return true;
});
this.win.root.mouseup(() => {
if (!wasMove) this.input.focus();
return true;
});
};
Terminal.prototype.scrollToTheEnd = function() {
this.out.parent().scrollTop(this.out.height());
};
Terminal.prototype.print = function(text) {
this.out.append($('<div>', {text, 'class': 'terminal-commandResult'}));
this.scrollToTheEnd();
};
function sharedStartOfSortedArray(array){
var a1= array[0], a2= array[array.length-1], L= a1.length, i= 0;
while(i<L && a1.charAt(i)=== a2.charAt(i)) i++;
return a1.substring(0, i);
}

View file

@ -1,341 +0,0 @@
export function add(parent, child) {
parent.content.append(child.root);
}
export function methodRef(_this, methodName, args) {
return function() {
_this[methodName].apply(_this, args);
};
}
export function Box(parent) {
this.root = this.content = $('<div class="tc-box" />');
this.root.addClass('tc-box tc-scroll');
this.root.appendTo(parent ? parent : 'body');
}
Box.prototype.close = function() {
this.root.remove();
};
export function Panel() {
this.root = this.content = $('<div />');
this.root.addClass('tc-panel tc-scroll');
}
Panel.prototype.close = function() {
this.root.remove();
};
export function Folder(title) {
this.root = $('<div/>', {'class': 'tc-folder'});
this.content = $('<div/>');
this.root.append($('<div/>', {text: title, 'class': 'tc-row tc-title'}));
this.root.append(this.content);
}
export function Button(title) {
this.root = $('<div/>',
{'class': 'tc-row tc-ctrl tc-ctrl-btn', text: title});
}
export function CheckBox(title, checked) {
this.root = $('<div/>',
{'class': 'tc-row tc-ctrl'});
this.root.append('<label><input type="checkbox">' + title + '</label>')
this.input = this.root.find("input");
this.input.prop('checked', !!checked);
}
export function InlineRadio(choiceLabels, choiceValues, checkedIndex) {
var name = 'TCAD.toolkit.InlineRadio_' + (InlineRadio.COUNTER++)
this.root = $('<div/>',
{'class': 'tc-row tc-ctrl tc-inline-radio'});
this.inputs = [];
for (var i = 0; i < choiceLabels.length; i++) {
var checked = checkedIndex === i ? "checked" : '';
var label = $('<label><input type="radio" name="' + name + '" value="' + choiceValues[i] + '"><span>' + choiceLabels[i] + '</span></label>');
this.inputs.push(label.find("input"));
this.root.append(label);
}
this.inputs[checkedIndex].prop('checked', true);
}
InlineRadio.prototype.getValue = function() {
for (var i = 0; i < this.inputs.length; i++) {
if (this.inputs[i].prop('checked')) {
return this.inputs[i].attr('value');
}
}
return null;
};
InlineRadio.prototype.setValue = function(v) {
this.root.find('input[value='+v+']').prop('checked', true);
};
InlineRadio.COUNTER = 0;
export function propLayout(root, name, valueEl) {
root.append($('<span/>', {'class': 'tc-prop-name', text: name}))
.append($('<div/>', {'class': 'tc-prop-value'})
.append(valueEl));
}
function NumberWidget(name, initValue, baseStep, round) {
this.root = $('<div/>', {'class': 'tc-row tc-ctrl tc-ctrl-number'});
this.input = $("<input type='text' value='"+initValue+"' />");
this.slide = false;
baseStep = baseStep || 1;
round = round || 0;
this.min = null;
this.max = null;
this.accelerator = 100;
var scope = this;
var lastValue = null;
function trigger() {
if ($(this).val() !== lastValue) {
$(this).trigger('t-change');
lastValue = $(this).val();
}
}
this.input.on('input', function(e) {
var val = $(this).val();
//var floatRegex = /[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/;
//if (!floatRegex.test(val)) {
// $(this).val(val.replace(/[^0-9\.-]/g, ''));
//}
trigger.call(this);
});
this.input.get(0).addEventListener('mousewheel', function (e) {
var delta = 0;
if ( e.wheelDelta ) { // WebKit / Opera / Explorer 9
delta = e.wheelDelta;
} else if ( e.detail ) { // Firefox
delta = - e.detail;
}
var val = $(this).val();
if (!val) val = 0;
var step = baseStep * (e.shiftKey ? scope.accelerator : 1);
val = parseFloat(val) + (delta < 0 ? -step : step);
if (scope.min != null && val < scope.min) {
val = scope.min;
}
if (scope.max != null && val > scope.max) {
val = scope.max;
}
if (round !== 0) {
val = val.toFixed(round);
}
$(this).val(val);
e.preventDefault();
e.stopPropagation();
trigger.call(this);
}, false);
propLayout(this.root, name, this.input);
}
NumberWidget.prototype.val = function() {
return Number(this.input.val());
};
export function Text(name, initValue) {
this.root = $('<div/>', {'class': 'tc-row tc-ctrl'});
this.input = $("<input type='text' value='"+initValue+"' />");
propLayout(this.root, name, this.input);
}
export function Combo(id, labelText) {
this.root = $('<div/>', {'class': 'tc-row tc-ctrl tc-ctrl-combo'});
var label = $('<span/>', {'class': 'tc-prop-name', text: labelText});
this.select = $('<select>', {id : id});
this.root.append(label)
.append($('<div/>', {'class': 'tc-prop-value'}).append(this.select));
}
export function ButtonRow(captions, actions) {
this.root = $('<div/>',
{'class': 'tc-row tc-ctrl tc-buttons-block'});
function withAction(btn, action) {
return btn.click(function(){
action.call()
});
}
for (var i = 0; i < captions.length; i++) {
var caption = captions[i];
var btn = $('<span/>', {
text: caption,
'class': 'tc-block-btn active-btn'
});
withAction(btn, actions[i]);
this.root.append(btn);
}
}
export function List() {
this.root = $('<div/>', {'class': 'tc-list'});
}
List.prototype.addRow = function(name) {
var row = $('<div/>', {
text: name, 'class': 'tc-row tc-pseudo-btn'
});
this.root.append(row);
return row;
};
List.setIconForRow = function(row, icon) {
row.css({
'background-image' : 'url('+icon+')'
});
};
export function Tree() {
this.root = $('<div/>', {'class': 'tc-tree'});
}
Tree.prototype.set = function(data) {
this.root.empty();
this._fill(data, 0);
};
Tree.prototype._fill = function(data, level) {
var notLeaf = data.children !== undefined && data.children.length !== 0;
if (data.name !== undefined) {
this.root.append($('<div/>', {
text: data.name, 'class': 'tc-row' + (notLeaf ? ' tc-chevron-open' : ''),
css: {'margin-left': level * (notLeaf ? 10 : 16) + 'px'}
}));
}
if (notLeaf) {
for (var i = 0; i < data.children.length; i++) {
var child = data.children[i];
this._fill(child, level + 1);
}
}
};
export function Parameters() {
this.listeners = {};
}
Parameters.prototype.define = function(name, initValue) {
function fn(name) {
return '___' + name;
}
this[fn(name)] = initValue;
return Object.defineProperty(this, name, {
get: function() { return this[fn(name)]},
set: function(value) {
var oldValue = this[fn(name)];
this[fn(name)] = value;
this.notify(name, value, oldValue);
}
});
};
Parameters.prototype.subscribe = function(name, listenerId, callback, scope) {
var listenerList = this.listeners[name];
if (listenerList === undefined) {
listenerList = [];
this.listeners[name] = listenerList;
}
var callbackFunc = scope === undefined ? callback : function() {
callback.apply(scope, arguments);
};
listenerList.push([listenerId, callbackFunc]);
var params = this;
return (function () { callbackFunc(params[name], undefined, null) }); // return init function
};
Parameters.prototype.notify = function(name, newValue, oldValue) {
var listenerList = this.listeners[name];
if (listenerList !== undefined) {
for (var i = 0; i < listenerList.length; i++) {
var listenerId = listenerList[i][0];
var callback = listenerList[i][1];
if (listenerId == null || this.__currentSender == null || listenerId != this.__currentSender) {
callback(newValue, oldValue, this.__currentSender);
}
}
}
this.__currentSender = null;
};
Parameters.prototype.set = function(name, value, sender) {
this.__currentSender = sender;
this[name] = value;
};
export function Bus() {
this.listeners = {};
}
Bus.prototype.subscribe = function(event, callback, listenerId) {
var listenerList = this.listeners[event];
if (listenerList === undefined) {
listenerList = [];
this.listeners[event] = listenerList;
}
if (listenerId == undefined) listenerId = null;
listenerList.push([callback, listenerId]);
return callback;
};
Bus.prototype.unsubscribe = function(event, callback) {
const listenerList = this.listeners[event];
for (let i = 0; i < listenerList.length; i++) {
if (listenerList[i][0] === callback) {
listenerList.splice(i, 1);
return;
}
}
};
Bus.prototype.dispatch = function(event, data, sender) {
var listenerList = this.listeners[event];
if (listenerList !== undefined) {
for (var i = 0; i < listenerList.length; i++) {
const callback = listenerList[i][0];
const listenerId = listenerList[i][1];
if (sender == undefined || listenerId == null || listenerId != sender) {
try {
callback(data);
} catch(e) {
console.error(e);
}
}
}
}
};
Bus.Observable = function(initValue) {
this.value = initValue;
};
Bus.prototype.defineObservable = function(scope, name, initValue, eventName) {
if (eventName == undefined) eventName = name;
var observable = new Bus.Observable(initValue);
var bus = this;
return Object.defineProperty(scope, name, {
get: function() { return observable.value;},
set: function(value) {
observable.value = value;
bus.dispatch(eventName, value);
}
});
};
export function config(obj, props) {
for (var key in props) {
obj[key] = props[key];
}
return obj;
}
export {NumberWidget as Number}

View file

@ -1,404 +0,0 @@
/** @constructor */
function Window(el, winManager) {
this.root = el;
this.neverOpened = !this.root.is(':visible');
this.tileUpRelative = $('body');
this.onShowCallback = null;
var root = this.root;
var caption = this.root.find('.tool-caption');
caption.each(function() {
var closeBtn = '<span class="btn rm" style="float: right;"><i class="fa fa-remove"></i></span>';
$(this).append(closeBtn);
});
this.root.find('.tool-caption .rm').click(function() {
root.hide();
});
var DIRS = DIRECTIONS;
winManager.registerResize(this.root, DIRS.NORTH | DIRS.SOUTH | DIRS.WEST | DIRS.EAST);
winManager.registerDrag(this.root, caption);
}
Window.prototype.show = function() {
this.root.show();
}
Window.prototype.toggle = function() {
var aboutToShow = !this.root.is(':visible');
if (aboutToShow) {
this.tileUpPolicy(this.neverOpened, this.tileUpRelative);
}
this.neverOpened = false ;
this.root.toggle();
if (aboutToShow && this.onShowCallback != null) {
this.onShowCallback(this);
}
};
Window.prototype.tileUpPolicy = function(firstTime, relativeEl) {
var span = 20;
var relOff = relativeEl.offset();
var off = this.root.offset();
off = {
left: parseInt(this.root.css('left')),
top: parseInt(this.root.css('top'))
};
if (firstTime) {
off = {
left: relOff.left + relativeEl.width() - this.root.width() - span,
top: relOff.top + relativeEl.height() - this.root.height() - span
};
this.root.css({
left: off.left + 'px',
top: off.top + 'px'
});
}
var needToSet = false;
if (off.left < relOff.left || off.left >= relOff.left + relativeEl.width() - span) {
off.left = relOff.left + span;
needToSet = true;
}
if (off.top < relOff.top || off.top >= relOff.top + relativeEl.height() - span) {
off.top = relOff.top + span;
needToSet = true;
}
if (needToSet) {
this.root.css({
left: off.left + 'px',
top: off.top + 'px'
});
}
//var fixedWidth = null;
//var fixedHeight = null;
//
//if (off.left + this.root.width() > relOff.left + relativeEl.width()) {
// fixedWidth = this.root.width() - span * 2;
//}
//if (off.top + this.root.height() > relOff.top + relativeEl.height()) {
// fixedHeight = this.root.width() - span * 2;
//}
//if (fixedWidth != null) {
// console.log(fixedWidth)
// this.root.css({ width : fixedWidth + 'px'});
//}
//if (fixedHeight != null) {
// this.root.css({ height : fixedHeight + 'px'});
//}
};
function WinManager() {
this.moveHandler = null;
var wm = this;
document.body.addEventListener("mousemove", function( e ) {
if (wm.moveHandler != null) {
wm.moveHandler(e);
e.preventDefault();
}
}, false);
document.body.addEventListener("mouseup", function( e ) {
wm.moveHandler = null;
}, false);
}
WinManager.prototype.captureDrag = function(el, e) {
var origin = {x : e.pageX, y : e.pageY};
var originLocation = el.offset();
this.moveHandler = function(e) {
var dx = e.pageX - origin.x;
var dy = e.pageY - origin.y;
el.offset({left : originLocation.left + dx, top : originLocation.top + dy});
};
};
WinManager.prototype.captureResize = function(el, dirMask, e, onResize) {
var origin = {x : e.pageX, y : e.pageY};
var originSize = {x : el.outerWidth(), y : el.height()};
var originLocation = el.offset();
var north = _maskTest(dirMask, DIRECTIONS.NORTH);
var south = _maskTest(dirMask, DIRECTIONS.SOUTH);
var west = _maskTest(dirMask, DIRECTIONS.WEST);
var east = _maskTest(dirMask, DIRECTIONS.EAST);
this.moveHandler = function(e) {
var dx = e.pageX - origin.x;
var dy = e.pageY - origin.y;
if (east) {
el.css('width', Math.round(originSize.x + dx) + 'px');
}
var top = originLocation.top;
var left = originLocation.left;
var setLoc = false;
if (west) {
el.css('width', Math.round(originSize.x - dx) + 'px');
left += dx;
setLoc = true;
}
if (south) {
el.css('height', Math.round(originSize.y + dy) + 'px');
}
if (north) {
el.css('height', Math.round(originSize.y - dy) + 'px');
top += dy;
setLoc = true;
}
if (setLoc) {
el.offset({left : left, top: top});
}
if (onResize !== undefined) {
onResize();
}
}
};
var DIRECTIONS = {
NORTH : 0x0001,
SOUTH : 0x0010,
WEST : 0x0100,
EAST : 0x1000,
};
WinManager.prototype.registerResize = function(el, dirMask, onResize) {
var wm = this;
var north = _maskTest(dirMask, DIRECTIONS.NORTH);
var south = _maskTest(dirMask, DIRECTIONS.SOUTH);
var west = _maskTest(dirMask, DIRECTIONS.WEST);
var east = _maskTest(dirMask, DIRECTIONS.EAST);
var borderTop = parseInt(el.css('borderTopWidth'), 10);
var borderLeft = parseInt(el.css('borderLeftWidth'), 10);
function onNorthEdge(e, el) {
var offset = el.offset();
return e.pageY < offset.top + borderTop;
}
function onSouthEdge(e, el) {
var offset = el.offset();
var height = el.height();
return e.pageY > offset.top + height + borderTop;
}
function onWestEdge(e, el) {
var offset = el.offset();
return e.pageX < offset.left + borderLeft;
}
function onEastEdge(e, el) {
var offset = el.offset();
var width = el.width();
return e.pageX > offset.left + width + borderLeft;
}
el.mousedown(function(e) {
var $this = $(this);
if (north && east && onNorthEdge(e, $this) && onEastEdge(e, $this)) {
wm.captureResize(el, DIRECTIONS.NORTH | DIRECTIONS.EAST, e, onResize);
} else if (north && west && onNorthEdge(e, $this) && onWestEdge(e, $this)) {
wm.captureResize(el, DIRECTIONS.NORTH | DIRECTIONS.WEST, e, onResize);
} else if (south && east && onSouthEdge(e, $this) && onEastEdge(e, $this)) {
wm.captureResize(el, DIRECTIONS.SOUTH | DIRECTIONS.EAST, e, onResize);
} else if (south && west && onSouthEdge(e, $this) && onWestEdge(e, $this)) {
wm.captureResize(el, DIRECTIONS.SOUTH | DIRECTIONS.WEST, e, onResize);
} else if (north && onNorthEdge(e, $this)) {
wm.captureResize(el, DIRECTIONS.NORTH, e, onResize);
} else if (south && onSouthEdge(e, $this)) {
wm.captureResize(el, DIRECTIONS.SOUTH, e, onResize);
} else if (west && onWestEdge(e, $this)) {
wm.captureResize(el, DIRECTIONS.WEST, e, onResize);
} else if (east && onEastEdge(e, $this)) {
wm.captureResize(el, DIRECTIONS.EAST, e, onResize);
}
});
el.mousemove(function(e) {
var $this = $(this);
if (north && east && onNorthEdge(e, $this) && onEastEdge(e, $this)) {
el.css('cursor', 'nesw-resize');
} else if (north && west && onNorthEdge(e, $this) && onWestEdge(e, $this)) {
el.css('cursor', 'nwse-resize');
} else if (south && east && onSouthEdge(e, $this) && onEastEdge(e, $this)) {
el.css('cursor', 'nwse-resize');
} else if (south && west && onSouthEdge(e, $this) && onWestEdge(e, $this)) {
el.css('cursor', 'nesw-resize');
} else if (south && onSouthEdge(e, $this)) {
el.css('cursor', 'ns-resize');
} else if (north && onNorthEdge(e, $this)) {
el.css('cursor', 'ns-resize');
} else if (east && onEastEdge(e, $this)) {
el.css('cursor', 'ew-resize');
} else if (west && onWestEdge(e, $this)) {
el.css('cursor', 'ew-resize');
} else {
el.css('cursor', "");
}
});
};
WinManager.prototype.registerDrag = function(el, dragger) {
var wm = this;
dragger.mousedown(function(e) {
wm.captureDrag(el, e);
});
};
function bindOpening(btn, win) {
btn.click(function(e) {
openWin(win, e);
});
}
function createActionsWinBuilder(win) {
var content = win.root.find('.content');
var template = content.html();
content.empty();
return function(name, action) {
content.append(template.replace("$value$", name));
content.find('div:last input').click(action);
};
}
function closeWin(win) {
win.root.hide();
}
function openWin(win, mouseEvent) {
var x = mouseEvent.pageX;
var y = mouseEvent.pageY;
var pageW = $(window).width();
var pageH = $(window).height();
var winW = win.root.width();
var winH = win.root.height();
var left = x < pageW / 2 ? x : x - winW;
var top = y < pageH / 2 ? y : y - winH;
win.root.show();
win.root.offset({top : top, left : left});
}
/** @constructor */
function List(id, model) {
this.ul = $('<ul>', { 'class' : 'tlist', id : id});
this.model = model;
this.template = '<li>$name$<span class="btn rm" style="float: right;"><i class="fa fa-remove"></i></span></li>';
}
List.prototype.refresh = function() {
this.ul.empty();
var items = this.model.items();
var model = this.model;
function makeCallbacks(li, item, index) {
li.find('.rm').click(function(e) {
model.remove(item, index);
e.stopPropagation();
e.preventDefault();
});
li.hover(function() {model.hover(item, index)});
li.mouseleave(function() {model.mouseleave(item, index)});
li.click(function() {model.click(item, index)});
}
for (var i = 0; i < items.length; ++i) {
var item = items[i];
var li = $(this.template.replace('$name$', item.name));
this.ul.append(li);
makeCallbacks(li, item, i)
}
};
function dockBtn(name, icon) {
var btn = $('<span>', {'class': 'dock-btn'});
btn.append(faBtn(icon));
btn.append($('<span>', {'class': 'txt'}).text(name));
return btn;
}
function faBtn (iconName) {
return $('<i>', {'class' : 'fa fa-'+iconName});
}
function Dock(dockEl, switcherEl, viewDefinitions) {
this.views = {};
this.dockEl = dockEl;
function bindClick(dock, switchEl, viewName) {
switchEl.click(function(e) {
if (dock.isVisible(viewName)) {
dock.hide(viewName);
} else {
dock.show(viewName);
}
});
}
for (var i = 0; i < viewDefinitions.length; i++) {
var viewDef = viewDefinitions[i];
var view = {};
this.views[viewDef.name] = view;
view.node = $('<div>', {'class': 'dock-node'});
var caption = $('<div>', {'class': 'tool-caption'});
caption.append($('<span>', {'class': 'txt'}).text(viewDef.name.toUpperCase()));
caption.append(faBtn(viewDef.icon));
view.node.append(caption);
view.node.hide();
this.dockEl.append(view.node);
view.switchBtn = dockBtn(viewDef.name, viewDef.icon);
bindClick(this, view.switchBtn, viewDef.name);
switcherEl.append(view.switchBtn);
}
}
Dock.prototype.show = function(viewName) {
var view = this.views[viewName];
if (view.switchBtn.hasClass('selected')) {
return;
}
if (!this.dockEl.is(":visible")) {
this.dockEl.show();
$('body').trigger('layout');
}
view.node.show();
view.switchBtn.addClass('selected');
};
Dock.prototype.hide = function(viewName) {
var view = this.views[viewName];
if (!view.switchBtn.hasClass('selected')) {
return;
}
view.node.hide();
view.switchBtn.removeClass('selected');
if (this.dockEl.find('.dock-node:visible').length == 0) {
this.dockEl.hide();
$('body').trigger('layout');
}
};
Dock.prototype.isVisible = function(viewName) {
return this.views[viewName].switchBtn.hasClass('selected');
};
Dock.prototype.setState = function(state) {
state.forEach(viewName => this.show(viewName));
};
Dock.prototype.getState = function() {
const state = [];
Object.keys(this.views).forEach(viewName => {
if (this.isVisible(viewName)) {
state.push(viewName);
}
});
return state;
};
function _maskTest(mask, value) {
return (mask & value) === value;
}
export { WinManager, Window, List, Dock, dockBtn, faBtn, openWin, closeWin, bindOpening, createActionsWinBuilder, DIRECTIONS };

23
web/app/utils/domUtils.js Normal file
View file

@ -0,0 +1,23 @@
export function createElement(type, id, className, text) {
const el = document.createElement(type);
if (id) {
el.id = id;
}
if (className) {
el.className = className;
}
if (text) {
el.innerText = text;
}
return el;
}
export function select(query) {
return document.querySelector(query)
}
export function selectAll(query) {
return document.querySelectorAll(query)
}

View file

@ -1,6 +0,0 @@
import $ from 'jquery'
// Usage of jquery is absolutely deprecated. It exists only to support legacy code(2d sketcher and test framework) and
// will be gone soon after complete transition to React. Main application never uses jquery.
window.jQuery = window.$ = $;

View file

@ -18,10 +18,6 @@ html, body {
font-family: 'Helvetica Neue Light', HelveticaNeue-Light, 'Helvetica Neue', Helvetica, sans-serif;
}
.mono {
font-family: Monaco, monospace;
}
.logo {
color: #bbb;
font-size: 16px;
@ -275,62 +271,6 @@ html, body {
color: #fff;
}
#commands {
.mono;
}
#commands .content {
color: #C4E1A4;
font-size: 11px
}
.terminal-output-area {
height: ~"calc(100% - 30px)"; //escape less processing
display: flex;
flex-direction: column;
}
.terminal-output {
flex: 1;
}
.terminal-pusher {
height: 100%;
}
.terminal-input {
height: 30px;
}
.terminal-input input {
color: #C4E1A4;
background: inherit;
outline: none;
border: 0;
margin-top: 4px;
padding: 3px;
width: 100%;
box-sizing: border-box;
padding-left: 0;
}
.terminal-input input::-webkit-input-placeholder {
color: #777777;
font-style: italic;
}
.terminal-commandText {
color: #777777;
}
.autocomplete-area {
font-style: italic;
}
input[type=checkbox], input[type=radio] {
vertical-align: middle;
}
#status {
.helvetica;
color: #fff;
@ -357,3 +297,11 @@ input[type=checkbox], input[type=radio] {
cursor: default;
pointer-events: none;
}
#top-toolbar:empty {
height: 40px;
}
#right-toolbar:empty {
width: 50px;
}

View file

@ -14,8 +14,8 @@
<body>
<a id="downloader" style="display: none;" ></a>
<div class="panel b-bot" style="width: 100%; display: flex; justify-content: space-between">
<span class="logo" style="float:left">sketcher <sup> 2D</sup></span>
<div style="display: flex" id="top-toolbar"></div>
<span class="logo" style="float:left">sketcher <sup> 2D</sup></span>
<div style="display: flex" id="top-toolbar"></div>
</div>
<div style="width: 100%; height: calc(100% - 65px); display: flex;">

View file

@ -5,7 +5,9 @@ import suites from './suites'
import {Menu} from './menu'
import {TestEnv} from './test'
import DurationFormat from './utils/duration-format'
import $ from "jquery";
window.jQuery = window.$ = $;
$(() => {
$(document).on('click', '.action-item', (e) => {