diff --git a/modules/bus/index.js b/modules/bus/index.js index 50294b6b..5f9244a5 100644 --- a/modules/bus/index.js +++ b/modules/bus/index.js @@ -5,19 +5,16 @@ export default class Bus { this.state = {}; this.keepStateFor = new Set(); this.lock = new Set(); + this.stateConnections = new Map(); } - subscribe(key, callback) { - let listenerList = this.listeners[key]; + subscribe(token, callback) { + let listenerList = this.listeners[token]; if (listenerList === undefined) { listenerList = []; - this.listeners[key] = listenerList; + this.listeners[token] = listenerList; } listenerList.push(callback); - - if (this.keepStateFor.has(key)) { - callback(this.state[key]); - } return callback; }; @@ -30,7 +27,49 @@ export default class Bus { } } }; + + tokensToStates(tokens) { + return tokens.map( token => this.state[token] ); + } + connectToState(tokens, callback) { + if (!Array.isArray(tokens)) { + tokens = [tokens]; + } + + let connection = () => { + callback(this.tokensToStates(tokens)); + }; + tokens.forEach(token => { + if (!this.keepStateFor.has(token)) { + throw `unable to connect to stateless token ${token}. state for a token should be initialized before connecting`; + } + this.subscribe(token, connection); + }); + this.stateConnections.set(connection, tokens); + return connection; + } + + disconnectFromState(connection) { + this.stateConnections.get(connection).forEach(token => this.unSubscribe(token, connection)); + this.stateConnections.delete(connection); + } + + updateStates(tokens, updater) { + let updated = updater(this.tokensToStates(tokens)); + for (let i = 0; i < tokens.length; ++i) { + this.dispatch(tokens[i], updated[i]); + } + } + + updateState(token, updater) { + this.dispatch(token, updater(this.state[token])); + } + + setState(token, partialState) { + this.dispatch(token, Object.assign({}, this.state[token], partialState)); + } + dispatch(key, data) { if (this.lock.has(key)) { console.warn('recursive dispatch'); @@ -57,16 +96,14 @@ export default class Bus { } }; - enableState(forEvent, initValue) { - this.keepStateFor.add(forEvent); - this.state[forEvent] = initValue; + enableState(forToken, initValue) { + this.keepStateFor.add(forToken); + this.state[forToken] = initValue; } - disableState(forEvent) { - this.keepStateFor.delete(forEvent); - } } - - +export function createToken(...fqn) { + return fqn.join('.'); +} diff --git a/modules/ui/WindowSystem.jsx b/modules/ui/WindowSystem.jsx new file mode 100644 index 00000000..8df09111 --- /dev/null +++ b/modules/ui/WindowSystem.jsx @@ -0,0 +1,25 @@ +import React from 'react'; + +export default class WindowSystem extends React.Component { + + constructor() { + super(); + this.state = { + windows: [] + } + } + + render() { + return this.state.windows; + } + + addWindow(window) { + this.setState({windows: [...this.state.windows, window]}); + } + + removeWindow(window) { + let windows = [...this.state.windows]; + windows.splice(windows.indexOf(window), 1); + this.setState({windows}); + } +} diff --git a/modules/ui/components/Abs.jsx b/modules/ui/components/Abs.jsx new file mode 100644 index 00000000..55cd633b --- /dev/null +++ b/modules/ui/components/Abs.jsx @@ -0,0 +1,51 @@ +import React from 'react'; + +export default class Abs extends React.Component { + + fit() { + if (!this.el) { + return; + } + let w = this.el.offsetWidth; + let h = this.el.offsetHeight; + let holder = this.el.parentNode; + + const fit = (prop, dim, holderDim) => { + let pos = this.props[prop]; + if (pos !== undefined) { + if (pos + dim > holderDim) { + pos = holderDim - dim; + this.el.style[prop] = pos + 'px'; + } + } + }; + + fit('left', w, holder.offsetWidth); + fit('right', w, holder.offsetWidth); + fit('top', h, holder.offsetHeight); + fit('bottom', h, holder.offsetHeight); + } + + componentDidMount() { + this.fit(); + } + + componentDidUpdate() { + this.fit(); + } + + componentWillUnmount() { + this.el = undefined; + } + + render() { + let {left, top, right, bottom, children, style, ...props} = this.props; + return
this.el = el} + style={{position: 'absolute', left, top, right, bottom, zIndex: 999, ...style}} {...props}> + {children} +
; + } +} + + + diff --git a/modules/ui/components/AuxWidget.jsx b/modules/ui/components/AuxWidget.jsx new file mode 100644 index 00000000..a22e28db --- /dev/null +++ b/modules/ui/components/AuxWidget.jsx @@ -0,0 +1,11 @@ +import React from 'react'; +import Abs from "./Abs"; +import cx from 'classnames'; + +import ls from './AuxWidget.less'; + +export default function AuxWidget({flatTop, flatBottom, children, className, ...props}) { + return + {children} + +} \ No newline at end of file diff --git a/modules/ui/components/AuxWidget.less b/modules/ui/components/AuxWidget.less new file mode 100644 index 00000000..795da87d --- /dev/null +++ b/modules/ui/components/AuxWidget.less @@ -0,0 +1,16 @@ +@border-radius: 3px; + +.root { + color: #fff; + background-color: rgba(40, 40, 40, 0.95); + border: solid 1px #000; + border-radius: @border-radius; +} + +.flatBottom { + border-radius: @border-radius @border-radius 0 0; +} + +.flatTop { + border-radius: 0 0 @border-radius @border-radius; +} diff --git a/modules/ui/components/Card.jsx b/modules/ui/components/Card.jsx new file mode 100644 index 00000000..76bfffa4 --- /dev/null +++ b/modules/ui/components/Card.jsx @@ -0,0 +1,16 @@ +import React from 'react'; + +export default function Card({visible, children, ...props}) { + return
+ {children} +
+} \ No newline at end of file diff --git a/modules/ui/components/Fa.jsx b/modules/ui/components/Fa.jsx new file mode 100644 index 00000000..1865a972 --- /dev/null +++ b/modules/ui/components/Fa.jsx @@ -0,0 +1,16 @@ +import React from 'react'; +import cx from 'classnames'; + +export default function Fa({icon, fw, fa, stack, className, ...props}) { + let faCss = fa ? fa.map(s => 'fa-' + s) : []; + if (icon) { + icon = 'fa-' + icon; + } + if (fw) { + faCss.push('fa-fw'); + } + if (stack) { + faCss.push('fa-stack-' + stack); + } + return +} \ No newline at end of file diff --git a/modules/ui/components/Filler.jsx b/modules/ui/components/Filler.jsx new file mode 100644 index 00000000..0245ea49 --- /dev/null +++ b/modules/ui/components/Filler.jsx @@ -0,0 +1,12 @@ +import React from 'react'; + +export default function Filler({width, height, children, style, ...props}) { + return + {children} + +} \ No newline at end of file diff --git a/modules/ui/components/Folder.jsx b/modules/ui/components/Folder.jsx new file mode 100644 index 00000000..b408bbea --- /dev/null +++ b/modules/ui/components/Folder.jsx @@ -0,0 +1,35 @@ +import React from 'react'; + +import ls from './Folder.less' +import Fa from "./Fa"; + +export default class Folder extends React.Component{ + + constructor() { + super(); + this.state = { + closed: null + } + } + + isClosed() { + let {closable, defaultClosed} = this.props; + if (!closable) return false; + return closable && (this.state.closed === null ? defaultClosed : this.state.closed) + } + + tweakClose = () => { + this.setState({closed: !this.isClosed()}); + }; + + render() { + let {title, closable, children} = this.props; + return
+
+ + {title} +
+ {!this.isClosed() && children} +
+ } +} diff --git a/modules/ui/components/Folder.less b/modules/ui/components/Folder.less new file mode 100644 index 00000000..bf681ead --- /dev/null +++ b/modules/ui/components/Folder.less @@ -0,0 +1,16 @@ +.root { + color: #eee; + font: 11px 'Lucida Grande', sans-serif; + background-color: #1a1a1a; +} + +.title { + height: 27px; + line-height: 27px; + overflow: hidden; + padding: 0 4px 0 5px; + border-bottom: 1px solid #2c2c2c; + + padding-left: 16px; + +} \ No newline at end of file diff --git a/modules/ui/components/ImgIcon.jsx b/modules/ui/components/ImgIcon.jsx new file mode 100644 index 00000000..b2f2528a --- /dev/null +++ b/modules/ui/components/ImgIcon.jsx @@ -0,0 +1,13 @@ +import React from 'react'; + +export default function ImgIcon({url, size, style, ...props}) { + return +}; \ No newline at end of file diff --git a/modules/ui/components/Menu.jsx b/modules/ui/components/Menu.jsx new file mode 100644 index 00000000..e00b1e27 --- /dev/null +++ b/modules/ui/components/Menu.jsx @@ -0,0 +1,50 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import ls from './Menu.less'; +import AuxWidget from "./AuxWidget"; +import cx from 'classnames'; + +export default function Menu({children, visible, x, y, orientationUp, style, ...props}) { + return + {children} + ; +} + +export function MenuSeparator() { + return
+} + + +export function MenuItem({icon, label, hotKey, style, disabled, onClick}, {closeAllUpPopups}) { + + if (hotKey) { + hotKey = hotKey.replace(/\s/g, ''); + if (hotKey.length > 15) { + hotKey = null; + } + } + let clickHandler = disabled ? undefined : () => { + closeAllUpPopups(); + onClick(); + }; + return
e.stopPropagation()} style={style} onClick={clickHandler}> + {icon} + {label} + {hotKey && {hotKey}} +
; +} + +MenuItem.contextTypes = { + closeAllUpPopups: PropTypes.func +}; diff --git a/modules/ui/components/Menu.less b/modules/ui/components/Menu.less new file mode 100644 index 00000000..dfad12d9 --- /dev/null +++ b/modules/ui/components/Menu.less @@ -0,0 +1,48 @@ +@import '../styles/theme'; + +.root { + padding: 0.45em 0; +} + +.item { + padding: 0.45em 0.55em 0.45em 0.45em; + cursor: pointer; + text-transform: capitalize; + white-space: nowrap; + display: flex; + align-items: baseline; + + &:hover { + background-color: #0074D9; + } + &:active { + background-color: #000d7f; + } + + &.disabled:hover, &.disbaled:active { + background-color: #545454; + } + + + & .hotKey { + color: @font-color-suppressed; + font-size: 0.8em; + padding-left: 1.5em; + flex-grow: 1; + text-align: right; + } + + & .label { + padding-left: 0.45em; + padding-right: 0.25em; + } +} + +.separator { + border-top: solid 1px #777; +} + +.disabled { + color: @font-color-suppressed; +} + diff --git a/modules/ui/components/Row.jsx b/modules/ui/components/Row.jsx new file mode 100644 index 00000000..e69de29b diff --git a/modules/ui/components/TabSwitcher.less b/modules/ui/components/TabSwitcher.less new file mode 100644 index 00000000..0c95022d --- /dev/null +++ b/modules/ui/components/TabSwitcher.less @@ -0,0 +1,35 @@ +@import "../styles/theme"; + +.root { + color: @font-color-suppressed; +} + +.tab { + @border: 1px solid @border-color; + + padding: 0.3em 0.3em 0.4em 0.6em; + cursor: pointer; + border-right: @border; + display: inline-block; + &:hover { + color: @font-color; + } + &.active { + background-color: @bg-color-alt; + color: @font-color; + } + &:first-child { + border-left: @border; + } +} + +.expand:hover { + color: green; +} +.close:hover { + color: red; +} + + + + diff --git a/modules/ui/components/TabSwticher.jsx b/modules/ui/components/TabSwticher.jsx new file mode 100644 index 00000000..763e356a --- /dev/null +++ b/modules/ui/components/TabSwticher.jsx @@ -0,0 +1,21 @@ +import React, {Fragment} from 'react'; +import Fa from 'ui/components/Fa'; +import cx from 'classnames'; + +import ls from './TabSwitcher.less'; + +export default function TabSwitcher({children, className}) { + + return
+ {children} +
+} + +export function Tab({id, label, active, closable, onSwitch}) { + return onSwitch(id)}> + {label} + {closable && + + } + ; +} \ No newline at end of file diff --git a/modules/ui/components/Toolbar.jsx b/modules/ui/components/Toolbar.jsx new file mode 100644 index 00000000..a3ba7b7e --- /dev/null +++ b/modules/ui/components/Toolbar.jsx @@ -0,0 +1,16 @@ +import React from 'react'; +import cx from 'classnames'; + +import ls from './Toolbar.less'; + +export default function Toolbar({children, className, ...props}) { + return
+ {children} +
; +} + +export function ToolbarButton({children, disabled}) { + return
+ {children} +
; +} diff --git a/modules/ui/components/Toolbar.less b/modules/ui/components/Toolbar.less new file mode 100644 index 00000000..d2cd18ca --- /dev/null +++ b/modules/ui/components/Toolbar.less @@ -0,0 +1,36 @@ +@import "../styles/theme"; + +.root { + background-color: rgba(255, 255, 255, 0.5); + padding: 0.3em; + border-radius: 5px; +} + +.button { + border-radius: 5px; + text-align: center; + white-space: nowrap; + font-size: 0.8em; + padding: 0.3em 0.1em; + color: #555; + + &:hover { + cursor: pointer; + background-color: #333; + color: #fff; + } + + &.disabled { + color: #999; + } + + &.disabled:hover { + color: #aaa; + background-color: #888; + } +} + + + + + diff --git a/modules/ui/components/Window.jsx b/modules/ui/components/Window.jsx new file mode 100644 index 00000000..b927b83c --- /dev/null +++ b/modules/ui/components/Window.jsx @@ -0,0 +1,48 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import ls from './Window.less' +import Fa from "./Fa"; + +export default class Window extends React.Component { + + constructor({initWidth}) { + super(); + this.state = { + width: initWidth + } + } + + render() { + let {children, title, minimizable } = this.props; + return
+
+ {title} +
+ {minimizable && _} + +
+
+ {children} +
+ + } + + getStyle() { + return { + width: toPx(this.state.width), + height: toPx(this.state.height), + left: toPx(this.state.left), + top: toPx(this.state.top) + } + } +} + +Window.defaultProps = { + minimizable: false, +}; + +function toPx(val) { + return val === undefined ? undefined : val + 'px'; +} + diff --git a/modules/ui/components/Window.less b/modules/ui/components/Window.less new file mode 100644 index 00000000..4e5dcbdb --- /dev/null +++ b/modules/ui/components/Window.less @@ -0,0 +1,8 @@ +.root { + position: absolute; +} + +.bar { + display: flex; + justify-content: space-between; +} diff --git a/modules/ui/components/controls/Button.jsx b/modules/ui/components/controls/Button.jsx new file mode 100644 index 00000000..97469a94 --- /dev/null +++ b/modules/ui/components/controls/Button.jsx @@ -0,0 +1,9 @@ +import React from 'react'; + +import ls from './Button.less' + +export default function Button({text}) { + + return {text} + +} diff --git a/modules/ui/components/controls/Button.less b/modules/ui/components/controls/Button.less new file mode 100644 index 00000000..e69de29b diff --git a/modules/ui/components/controls/ButtonGroup.jsx b/modules/ui/components/controls/ButtonGroup.jsx new file mode 100644 index 00000000..c9435677 --- /dev/null +++ b/modules/ui/components/controls/ButtonGroup.jsx @@ -0,0 +1,9 @@ +import React from 'react'; + +import ls from './ButtonGroup.less' + +export default function ButtonGroup({children}) { + + return
{children}
+ +} diff --git a/modules/ui/components/controls/ButtonGroup.less b/modules/ui/components/controls/ButtonGroup.less new file mode 100644 index 00000000..e69de29b diff --git a/modules/ui/components/controls/Field.jsx b/modules/ui/components/controls/Field.jsx new file mode 100644 index 00000000..4c1c8b3b --- /dev/null +++ b/modules/ui/components/controls/Field.jsx @@ -0,0 +1,12 @@ +import React from 'react'; + +import ls from './Label.less' + +export default function Field({children}) { + + return
+ {children[0]} {children[1]} +
; + + +} diff --git a/modules/ui/components/controls/Field.less b/modules/ui/components/controls/Field.less new file mode 100644 index 00000000..e69de29b diff --git a/modules/ui/components/controls/Label.jsx b/modules/ui/components/controls/Label.jsx new file mode 100644 index 00000000..cbd2594f --- /dev/null +++ b/modules/ui/components/controls/Label.jsx @@ -0,0 +1,8 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import ls from './Label.less' + +export default function Label({children}) { + return {children} +} diff --git a/modules/ui/components/controls/Label.less b/modules/ui/components/controls/Label.less new file mode 100644 index 00000000..e69de29b diff --git a/modules/ui/components/controls/NumberControl.jsx b/modules/ui/components/controls/NumberControl.jsx new file mode 100644 index 00000000..097add1c --- /dev/null +++ b/modules/ui/components/controls/NumberControl.jsx @@ -0,0 +1,61 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import ls from './NumberControl.less' + +export default class NumberControl extends React.Component{ + + render() { + let {initValue, } = this.props; + + return
+ this.input = input} + onWheel={this.onWheel} + onChange={e => onChange(e.target.value)} /> +
; + } + + onWheel = (e) => { + let {baseStep, round, min, max, onChange, accelerator} = this.props; + let delta = 0; + if ( e.wheelDelta ) { // WebKit / Opera / Explorer 9 + delta = e.wheelDelta; + } else if ( e.detail ) { // Firefox + delta = - e.detail; + } + let val = e.target.value; + if (!val) val = 0; + let step = baseStep * (e.shiftKey ? accelerator : 1); + val = parseFloat(val) + (delta < 0 ? -step : step); + if (min !== undefined && val < min) { + val = min; + } + if (max !== undefined && val > max) { + val = max; + } + if (round !== 0) { + val = val.toFixed(round); + } + this.input.value = val; + onChange(val); + e.preventDefault(); + e.stopPropagation(); + } +} + +NumberControl.propTypes = { + baseStep: PropTypes.number, + round: PropTypes.number, + min: PropTypes.number, + max: PropTypes.number, + accelerator: PropTypes.number, + initValue: PropTypes.number.isRequired, + onChange: PropTypes.func.isRequired +}; + +NumberControl.defaultProps = { + baseStep: 1, + round: 0, + accelerator: 100 +}; \ No newline at end of file diff --git a/modules/ui/components/controls/NumberControl.less b/modules/ui/components/controls/NumberControl.less new file mode 100644 index 00000000..e69de29b diff --git a/modules/ui/connect.jsx b/modules/ui/connect.jsx new file mode 100644 index 00000000..456061d9 --- /dev/null +++ b/modules/ui/connect.jsx @@ -0,0 +1,82 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +export default function connect(tokens, WrappedComponent, staticProps, mapper, dispatchMapper) { + + if (!Array.isArray(tokens)) { + tokens = [tokens]; + } + + mapper = createMapper(mapper); + + dispatchMapper = dispatchMapper || function(dispatch) { + return dispatch; + }; + + return class StateConnector extends React.Component { + + constructor(context) { + super(); + this.mounted = false; + this.stateProps = {}; + this.dispatchProps = dispatchMapper(this.dispatch); + } + + componentWillMount() { + this.externalStateConnection = this.context.bus.connectToState(tokens, this.setExternalState); + this.externalStateConnection(); + } + + componentDidMount() { + this.mounted = true; + } + + componentWillUnmount() { + this.mounted = false; + this.context.bus.disconnectFromState(this.externalStateConnection); + } + + setExternalState = (state) => { + this.stateProps = mapper(state); + if (this.mounted) { + this.forceUpdate(); + } + }; + + dispatch = (event, data) => { + this.context.bus.dispatch(event, data); + }; + + render() { + return + } + + static contextTypes = { + bus: PropTypes.object + }; + } +} + +function createMapper(mapper) { + if (!mapper) { + return function (state) { + let props = {}; + state.forEach(stateItem => Object.assign(props, stateItem)); + return props; + }; + } else if (Array.isArray(mapper)) { + return function (state) { + let props = {}; + for (let i = 0; i < state.length; i++) { + let stateItem = state[i]; + let mapperItem = mapper[i]; + Object.assign(props, mapperItem ? mapperItem(stateItem) : stateItem) + } + return props; + }; + } + return mapper; +} + + + diff --git a/modules/ui/genId.js b/modules/ui/genId.js new file mode 100644 index 00000000..d7c35001 --- /dev/null +++ b/modules/ui/genId.js @@ -0,0 +1,7 @@ + +let COUNTER = 0; +const PREFIX = 'id_'; + +export default function genId() { + return `${PREFIX}_${COUNTER++}`; +} \ No newline at end of file diff --git a/modules/ui/styles/index.less b/modules/ui/styles/index.less new file mode 100644 index 00000000..e8aa69fd --- /dev/null +++ b/modules/ui/styles/index.less @@ -0,0 +1 @@ +@import "constants"; \ No newline at end of file diff --git a/modules/ui/styles/init/main.less b/modules/ui/styles/init/main.less new file mode 100644 index 00000000..63527263 --- /dev/null +++ b/modules/ui/styles/init/main.less @@ -0,0 +1,28 @@ +@import "../theme"; + +body { + background-color: @bg-color; + color: @font-color; + font: 11px 'Lucida Grande', sans-serif; +} + +table { + font-size: 1em; +} + +iframe { + border: 0; +} + +:global(.disable-selection) { + user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; +} + +:global(.compact-font) { + font-family: 'Helvetica Neue Light', HelveticaNeue-Light, 'Helvetica Neue', Helvetica, sans-serif; +} + + diff --git a/web/css/minireset.css b/modules/ui/styles/init/minireset.css similarity index 100% rename from web/css/minireset.css rename to modules/ui/styles/init/minireset.css diff --git a/modules/ui/styles/theme.less b/modules/ui/styles/theme.less new file mode 100644 index 00000000..17fd8398 --- /dev/null +++ b/modules/ui/styles/theme.less @@ -0,0 +1,20 @@ +@bg-color: #000; +@bg-color-alt: #1a1a1a; + +@font-color: #eee; +@font-color-minor: #ccc; + +@font-color-suppressed: #aaa; +@font-color-disabled: #888; + +@border-color: #2c2c2c; + +@work-area-color: #808080; + +@work-area-control-bar-bg-color: rgba(0, 0, 0, 0.5); +@work-area-control-bar-bg-color-active: #555; +@work-area-control-bar-font-color: @font-color-minor; + + +//@work-area-toolbar-bg-color: ; +//@work-area-toolbar-font-color: ; diff --git a/modules/ui/wizard/declarativeWizard.js b/modules/ui/wizard/declarativeWizard.js new file mode 100644 index 00000000..e69de29b diff --git a/package.json b/package.json index 993f867b..8ed1ab1c 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "dependencies": { "react": "16.2.0", "react-dom": "16.2.0", + "prop-types": "15.6.0", "clipper-lib": "6.2.1", "diff-match-patch": "1.0.0", "earcut": "2.1.1", diff --git a/web/app/3d/actions/all-actions.js b/web/app/3d/actions/all-actions.js deleted file mode 100644 index 5be41da0..00000000 --- a/web/app/3d/actions/all-actions.js +++ /dev/null @@ -1,3 +0,0 @@ -export * from './core-actions' -export * from './operation-actions' -export * from './history-actions' diff --git a/web/app/3d/actions/core-actions.js b/web/app/3d/actions/core-actions.js deleted file mode 100644 index e2149a18..00000000 --- a/web/app/3d/actions/core-actions.js +++ /dev/null @@ -1,89 +0,0 @@ -import * as ActionHelpers from './action-helpers' - -export const EditFace = { - cssIcons: ['file-picture-o'], - label: 'sketch', - icon96: 'img/3d/face-edit96.png', - info: 'open sketcher for a face/plane', - listens: ['selection_face'], - update: ActionHelpers.checkForSelectedFaces(1), - invoke: (app) => app.editFace() -}; - -export const Save = { - cssIcons: ['floppy-o'], - label: 'save', - info: 'save project to storage', - invoke: (app) => app.save() -}; - -export const StlExport = { - cssIcons: ['upload', 'flip-vertical'], - label: 'STL Export', - info: 'export model to STL file', - invoke: (app) => app.stlExport() -}; - -export const RefreshSketches = { - cssIcons: ['refresh'], - label: 'Refresh Sketches', - info: 'refresh all visible sketches', - invoke: (app) => app.refreshSketches() -}; - -export const DeselectAll = { - cssIcons: ['square-o'], - label: 'deselect all', - info: 'deselect everything', - invoke: (app) => app.viewer.selectionMgr.deselectAll() -}; - -export const ToggleCameraMode = { - cssIcons: ['video-camera'], - label: 'toggle camera', - info: 'switch camera mode between perspective and orthographic', - invoke: (app) => { - app.context.services.viewer.toggleCamera(); - app.context.services.viewer.render(); - } -}; - -export const Info = { - cssIcons: ['info-circle'], - label: 'info', - info: 'opens help dialog', - invoke: (app) => app.showInfo() -}; - -export const Donate = { - cssIcons: ['paypal'], - label: 'donate', - info: 'open paypal donate page', - invoke: (app, e) => window.open('https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=WADW7V7CC32CY&lc=US&item_name=web%2dcad%2eorg¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHosted', '_blank') -}; - -export const GitHub = { - cssIcons: ['github'], - label: 'GitHub', - info: 'open GitHub project page', - invoke: (app, e) => window.open('https://github.com/xibyte/jsketcher', '_blank') -}; - -export const ShowSketches = { - type: 'binary', - property: 'showSketches', - cssIcons: ['image'], - label: 'show sketches', - info: 'toggle whether to show sketches on a solid face' -}; - -export const LookAtSolid = { - cssIcons: ['crosshairs'], - label: 'look at solid', - info: 'position camera at the solid at zoom to fit it', - invoke: (app, e) => app.lookAtSolid(app.inputManager.context.attr('data-id')) -}; - -export const noIcon = { - label: 'no icon' -}; \ No newline at end of file diff --git a/web/app/3d/actions/history-actions.js b/web/app/3d/actions/history-actions.js deleted file mode 100644 index ecfdd808..00000000 --- a/web/app/3d/actions/history-actions.js +++ /dev/null @@ -1,57 +0,0 @@ -export const SetHistoryPointer = { - label: 'set history', - info: 'set history pointer to this modification item', - invoke: (app) => { - const mIndex = parseInt(modificationIndex(app)); - app.craft.historyPointer = mIndex; - } -}; - -export const OpenHistoryWizard = { - label: 'edit operation', - info: 'open wizard to change parameters of this operation', - invoke: (app) => { - const mIndex = parseInt(modificationIndex(app)); - if (mIndex != app.craft.historyPointer) { - app.craft.historyPointer = mIndex; - } else { - const modification = app.craft.history[mIndex]; - app.ui.createWizardForOperation(modification); - } - } -}; - -export const EditOperationSketch = { - cssIcons: ['image'], - label: 'sketch', - info: 'edit the sketch assigned to this operation', - invoke: (app) => { - - const mIndex = parseInt(modificationIndex(app)); - const modification = app.craft.history[mIndex]; - if (!modification.face) { - return; - } - if (mIndex != app.craft.historyPointer) { - app.craft.historyPointer = mIndex; - } - const face = app.findFace(modification.face); - app.sketchFace(face); - } -}; - -export const RemoveModification = { - label: 'remove modification', - info: 'remove this modification', - invoke: (app) => { - if (!confirm("This modification and all following modifications will be removed. Continue?")) { - return; - } - const mIndex = parseInt(modificationIndex(app)); - app.craft.remove(mIndex); - } -}; - -function modificationIndex(app) { - return app.inputManager.context.data('modification') -} \ No newline at end of file diff --git a/web/app/3d/actions/operation-actions.js b/web/app/3d/actions/operation-actions.js deleted file mode 100644 index 2bd7dd51..00000000 --- a/web/app/3d/actions/operation-actions.js +++ /dev/null @@ -1,73 +0,0 @@ -import * as Operations from '../craft/operations' -import * as ActionHelpers from './action-helpers' - -function mergeInfo(opName, action) { - const op = Operations[opName]; - action.label = op.label; - action.icon32 = op.icon + '32.png'; - action.icon96 = op.icon + '96.png'; - action.invoke = (app) => app.ui.initOperation(opName); - return action; -} - -export const CUT = mergeInfo('CUT', { - info: 'makes a cut based on 2D sketch' -}); - -export const EXTRUDE = mergeInfo('EXTRUDE', { - info: 'extrudes 2D sketch' -}); - -export const REVOLVE = mergeInfo('REVOLVE', { - info: 'revolve 2D sketch' -}); - -export const SHELL = mergeInfo('SHELL', { - info: 'makes shell using borders' -}); - -export const BOX = mergeInfo('BOX', { - info: 'creates new object box' -}); - -export const PLANE = mergeInfo('PLANE', { - info: 'creates new object plane' -}); - -export const SPHERE = mergeInfo('SPHERE', { - info: 'creates new object sphere' -}); - -export const INTERSECTION = mergeInfo('INTERSECTION', { - info: 'intersection operation on two solids' -}); - -export const DIFFERENCE = mergeInfo('DIFFERENCE', { - info: 'difference operation on two solids' -}); - -export const UNION = mergeInfo('UNION', { - info: 'union operation on two solids' -}); - -export const IMPORT_STL = mergeInfo('IMPORT_STL', { - info: 'import stl from external location' -}); - -requiresFaceSelection(CUT, 1); -requiresFaceSelection(EXTRUDE, 1); -requiresFaceSelection(REVOLVE, 1); - -requiresSolidSelection(INTERSECTION, 2); -requiresSolidSelection(DIFFERENCE, 2); -requiresSolidSelection(UNION, 2); - -function requiresFaceSelection(action, amount) { - action.listens = ['selection_face']; - action.update = ActionHelpers.checkForSelectedFaces(amount) -} - -function requiresSolidSelection(action, amount) { - action.listens = ['selection_face']; - action.update = ActionHelpers.checkForSelectedSolids(amount) -} diff --git a/web/app/3d/dom/WebApplication.jsx b/web/app/3d/dom/WebApplication.jsx deleted file mode 100644 index 3dc0a4ea..00000000 --- a/web/app/3d/dom/WebApplication.jsx +++ /dev/null @@ -1,27 +0,0 @@ -import React, {Fragment} from 'react'; - -export default class WebApplication extends React.Component { - - render() { - return -
-
-
-
-
-
-
-
-
-
-
-
-
- - - } -} \ No newline at end of file diff --git a/web/app/3d/dom/startReact.js b/web/app/3d/dom/startReact.js deleted file mode 100644 index f379893f..00000000 --- a/web/app/3d/dom/startReact.js +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import WebApplication from './WebApplication'; - -export default function startReact(callback) { - return ReactDOM.render( - , - document.getElementById('app'), - callback - ); -} \ No newline at end of file diff --git a/web/app/3d/menu/menu-config.js b/web/app/3d/menu/menu-config.js deleted file mode 100644 index 38c39eb4..00000000 --- a/web/app/3d/menu/menu-config.js +++ /dev/null @@ -1,40 +0,0 @@ -export const file = { - label: 'file', - cssIcons: ['file'], - actions: ['Save', 'StlExport', '-', 'IMPORT_STL'] -}; - -export const craft = { - label: 'craft', - cssIcons: ['magic'], - info: 'set of available craft operations on a solid', - actions: ['EXTRUDE', 'CUT', 'REVOLVE', 'SHELL'] -}; - -export const primitives = { - label: 'add', - cssIcons: ['cube', 'plus'], - info: 'set of available solid creation operations', - actions: ['PLANE', 'BOX', 'SPHERE'] -}; - -export const boolean = { - label: 'bool', - cssIcons: ['pie-chart'], - info: 'set of available boolean operations', - actions: ['INTERSECTION', 'DIFFERENCE', 'UNION'] -}; - -export const main = { - label: 'start', - cssIcons: ['rocket'], - info: 'common set of actions', - actions: ['EXTRUDE', 'CUT', 'SHELL', '-', 'INTERSECTION', 'DIFFERENCE', 'UNION', '-', 'PLANE', 'BOX', 'SPHERE', '-', - 'EditFace', '-', 'DeselectAll', 'RefreshSketches'] -}; - -export const SolidContext = { - label: 'solid-context', - info: 'solid context actions', - actions: ['LookAtSolid'] -}; diff --git a/web/app/brep/brep-builder.js b/web/app/brep/brep-builder.js index 71611bf8..85338a5a 100644 --- a/web/app/brep/brep-builder.js +++ b/web/app/brep/brep-builder.js @@ -6,7 +6,7 @@ import {Face} from './topo/face'; import {Loop} from './topo/loop'; import {Edge} from './topo/edge'; import {Vertex} from './topo/vertex'; -import {normalOfCCWSeq} from '../3d/cad-utils'; +import {normalOfCCWSeq} from '../cad/cad-utils'; import BBox from "../math/bbox"; export default class BrepBuilder { diff --git a/web/app/brep/brep-enclose.js b/web/app/brep/brep-enclose.js index eb69b74c..2ca4173e 100644 --- a/web/app/brep/brep-enclose.js +++ b/web/app/brep/brep-enclose.js @@ -8,7 +8,7 @@ import {NurbsSurface, NurbsCurve} from './geom/impl/nurbs' import {Plane} from './geom/impl/plane' import {Point} from './geom/point' import {BasisForPlane, Matrix3} from '../math/l3space' -import * as cad_utils from '../3d/cad-utils' +import * as cad_utils from '../cad/cad-utils' import * as math from '../math/math' import mergeNullFace from './null-face-merge' import {invert} from './operations/boolean' diff --git a/web/app/brep/brep-primitives.js b/web/app/brep/brep-primitives.js index 7e808099..b25f379e 100644 --- a/web/app/brep/brep-primitives.js +++ b/web/app/brep/brep-primitives.js @@ -2,7 +2,7 @@ import {Point} from './geom/point' import {Plane} from './geom/impl/plane' import {createPrism, enclose} from './brep-enclose' import {AXIS, Matrix3} from '../math/l3space' -import {Circle} from '../3d/craft/sketch/sketch-model' +import {Circle} from '../cad/craft/sketch/sketch-model' export function box(w, h, d, tr) { const wh = w * 0.5; diff --git a/web/app/brep/debug/debugger/brepDebugger.less b/web/app/brep/debug/debugger/brepDebugger.less index eb14d1a1..394fd8d8 100644 --- a/web/app/brep/debug/debugger/brepDebugger.less +++ b/web/app/brep/debug/debugger/brepDebugger.less @@ -1,3 +1,4 @@ +:global .brep-debugger { & .strike { diff --git a/web/app/brep/operations/evolve-face.js b/web/app/brep/operations/evolve-face.js index 03ef0565..37efa045 100644 --- a/web/app/brep/operations/evolve-face.js +++ b/web/app/brep/operations/evolve-face.js @@ -2,7 +2,7 @@ import {Face} from '../topo/face'; import {Vertex} from '../topo/vertex'; import Vector from 'math/vector'; import {isCCW} from '../../math/math'; -import PIP from '../../3d/tess/pip'; +import PIP from '../../cad/tess/pip'; export function evolveFace(originFace, loops) { let out = []; diff --git a/web/app/brep/operations/polyhedronify.js b/web/app/brep/operations/polyhedronify.js index b80a2f9c..d21f08a4 100644 --- a/web/app/brep/operations/polyhedronify.js +++ b/web/app/brep/operations/polyhedronify.js @@ -1,4 +1,4 @@ -import {TriangulateFace} from '../../3d/tess/triangulation' +import {TriangulateFace} from '../../cad/tess/triangulation' import {Shell} from '../topo/shell' import {HalfEdge} from '../topo/edge' import {Loop} from '../topo/loop' diff --git a/web/app/brep/topo/face.js b/web/app/brep/topo/face.js index 7c7be6d0..0b187a71 100644 --- a/web/app/brep/topo/face.js +++ b/web/app/brep/topo/face.js @@ -1,6 +1,6 @@ import {TopoObject} from './topo-object' import {Loop} from './loop' -import PIP from '../../3d/tess/pip'; +import PIP from '../../cad/tess/pip'; import {NurbsCurve} from "../geom/impl/nurbs"; import {eqSqTol, veq, veqNeg} from "../geom/tolerance"; import { diff --git a/web/app/3d/actions/action-helpers.js b/web/app/cad/actions/action-helpers.js similarity index 66% rename from web/app/3d/actions/action-helpers.js rename to web/app/cad/actions/action-helpers.js index eec3fe14..faf81169 100644 --- a/web/app/3d/actions/action-helpers.js +++ b/web/app/cad/actions/action-helpers.js @@ -1,6 +1,6 @@ export function checkForSelectedFaces(amount) { - return (state, app) => { - state.enabled = app.getFaceSelection().length >= amount; + return (state, context) => { + state.enabled = context.services.selection.face().length >= amount; if (!state.enabled) { state.hint = amount === 1 ? 'requires a face to be selected' : 'requires ' + amount + ' faces to be selected'; } @@ -8,8 +8,8 @@ export function checkForSelectedFaces(amount) { } export function checkForSelectedSolids(amount) { - return (state, app) => { - state.enabled = app.getFaceSelection().length >= amount; + return (state, context) => { + state.enabled = context.services.selection.face().length >= amount; if (!state.enabled) { state.hint = amount === 1 ? 'requires a solid to be selected' : 'requires ' + amount + ' solids to be selected'; } diff --git a/web/app/cad/actions/actionRef.jsx b/web/app/cad/actions/actionRef.jsx new file mode 100644 index 00000000..64eddc30 --- /dev/null +++ b/web/app/cad/actions/actionRef.jsx @@ -0,0 +1,8 @@ + +export function toIdAndOverrides(ref) { + if (Array.isArray(ref)) { + return ref; + } else { + return [ref, undefined] + } +} \ No newline at end of file diff --git a/web/app/cad/actions/actionSystemPlugin.js b/web/app/cad/actions/actionSystemPlugin.js new file mode 100644 index 00000000..bea2637d --- /dev/null +++ b/web/app/cad/actions/actionSystemPlugin.js @@ -0,0 +1,63 @@ +import {createToken} from 'bus'; + +export function activate(context) { + + let {bus} = context; + + function run(id, data) { + bus.dispatch(TOKENS.actionRun(id), data); + } + + function register(action) { + bus.enableState(TOKENS.actionAppearance(action.id), action.appearance); + + let stateToken = TOKENS.actionState(action.id); + let initialState = { + hint: '', + enabled: true, + visible: true + }; + if (action.update) { + action.update(initialState, context); + } + bus.enableState(stateToken, initialState); + + if (action.update && action.listens) { + + const stateUpdater = () => { + bus.updateState(stateToken, (actionState) => { + actionState.hint = ''; + actionState.enabled = true; + actionState.visible = true; + action.update(actionState, context); + return actionState; + }); + }; + + for (let event of action.listens) { + bus.subscribe(event, stateUpdater); + } + } + bus.subscribe(TOKENS.actionRun(action.id), (data) => action.invoke(context, data)); + } + + function registerAction(action) { + register(action); + } + + function registerActions(actions) { + actions.forEach(action => register(action)); + } + + context.services.action = {run, registerAction, registerActions} +} + +export const TOKENS = { + ACTION_STATE_NS: 'action.state', + ACTION_APPEARANCE_NS: 'action.appearance', + ACTION_RUN_NS: 'action.run', + + actionState: (actionId) => createToken(TOKENS.ACTION_STATE_NS, actionId), + actionAppearance: (actionId) => createToken(TOKENS.ACTION_APPEARANCE_NS, actionId), + actionRun: (actionId) => createToken(TOKENS.ACTION_RUN_NS, actionId), +}; \ No newline at end of file diff --git a/web/app/3d/actions/actions.js b/web/app/cad/actions/actions.js similarity index 100% rename from web/app/3d/actions/actions.js rename to web/app/cad/actions/actions.js diff --git a/web/app/cad/actions/coreActions.js b/web/app/cad/actions/coreActions.js new file mode 100644 index 00000000..7d4efacd --- /dev/null +++ b/web/app/cad/actions/coreActions.js @@ -0,0 +1,130 @@ +import * as ActionHelpers from './action-helpers' + +export default [ + { + id: 'EditFace', + appearance: { + cssIcons: ['file-picture-o'], + label: 'sketch', + icon96: 'img/cad/face-edit96.png', + info: 'open sketcher for a face/plane', + }, + listens: ['selection_face'], + update: ActionHelpers.checkForSelectedFaces(1), + invoke: (context) => context.services.sketcher.editFace(), + }, + + { + id: 'Save', + appearance: { + cssIcons: ['floppy-o'], + label: 'save', + info: 'save project to storage', + }, + invoke: (context) => context.services.project.save() + }, + + { + id: 'StlExport', + appearance: { + cssIcons: ['upload', 'flip-vertical'], + label: 'STL Export', + info: 'export model to STL file', + }, + invoke: (context) => context.services.project.stlExport() + }, + + + { + id: 'RefreshSketches', + appearance: { + cssIcons: ['refresh'], + label: 'Refresh Sketches', + info: 'refresh all visible sketches', + }, + invoke: (context) => context.services.sketcher.refreshSketches() + }, + + { + id: 'DeselectAll', + appearance: { + cssIcons: ['square-o'], + label: 'deselect all', + info: 'deselect everything', + }, + invoke: (context) => context.services.selection.deselectAll() + }, + + { + id: 'ToggleCameraMode', + appearance: { + cssIcons: ['video-camera'], + label: 'toggle camera', + info: 'switch camera mode between perspective and orthographic', + }, + invoke: (app) => { + let viewer = app.context.services.viewer; + viewer.toggleCamera(); + viewer.render(); + } + }, + + { + id: 'Info', + appearance: { + cssIcons: ['info-circle'], + label: 'info', + info: 'opens help dialog', + }, + invoke: (context) => context.services.help.showInfo() + }, + + { + id: 'Donate', + appearance: { + cssIcons: ['paypal'], + label: 'donate', + info: 'open paypal donate page', + }, + invoke: (context) => window.open('https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=WADW7V7CC32CY&lc=US&item_name=web%2dcad%2eorg¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHosted', '_blank') + }, + + { + id: 'GitHub', + appearance: { + cssIcons: ['github'], + label: 'GitHub', + info: 'open GitHub project page', + }, + invoke: (context) => window.open('https://github.com/xibyte/jsketcher', '_blank') + }, + + { + id: 'ShowSketches', + type: 'binary', + property: 'showSketches', + appearance: { + cssIcons: ['image'], + label: 'show sketches', + info: 'toggle whether to show sketches on a solid face' + } + }, + + { + id: 'LookAtSolid', + appearance: { + cssIcons: ['crosshairs'], + label: 'look at solid', + info: 'position camera at the solid at zoom to fit it', + }, + invoke: (context) => app.lookAtSolid(app.inputManager.context.attr('data-id')) + }, + + { + id: 'noIcon', + appearance: { + label: 'no icon' + } + } +] + diff --git a/web/app/cad/actions/historyActions.js b/web/app/cad/actions/historyActions.js new file mode 100644 index 00000000..34e9cc1f --- /dev/null +++ b/web/app/cad/actions/historyActions.js @@ -0,0 +1,68 @@ +export default [ + { + id: 'SetHistoryPointer', + appearance: { + label: 'set history', + info: 'set history pointer to this modification item', + }, + invoke: (app) => { + const mIndex = parseInt(modificationIndex(app)); + app.craft.historyPointer = mIndex; + } + }, + { + id: 'OpenHistoryWizard', + appearance: { + label: 'edit operation', + info: 'open wizard to change parameters of this operation', + }, + invoke: (app) => { + const mIndex = parseInt(modificationIndex(app)); + if (mIndex != app.craft.historyPointer) { + app.craft.historyPointer = mIndex; + } else { + const modification = app.craft.history[mIndex]; + app.ui.createWizardForOperation(modification); + } + } + }, + { + id: 'EditOperationSketch', + appearance: { + cssIcons: ['image'], + label: 'sketch', + info: 'edit the sketch assigned to this operation', + }, + invoke: (app) => { + + const mIndex = parseInt(modificationIndex(app)); + const modification = app.craft.history[mIndex]; + if (!modification.face) { + return; + } + if (mIndex != app.craft.historyPointer) { + app.craft.historyPointer = mIndex; + } + const face = app.findFace(modification.face); + app.sketchFace(face); + } + }, + { + id: 'RemoveModification', + appearance: { + label: 'remove modification', + info: 'remove this modification', + }, + invoke: (app) => { + if (!confirm("This modification and all following modifications will be removed. Continue?")) { + return; + } + const mIndex = parseInt(modificationIndex(app)); + app.craft.remove(mIndex); + } + } +] + +function modificationIndex(app) { + return app.inputManager.context.data('modification') +} \ No newline at end of file diff --git a/web/app/cad/actions/operationActions.js b/web/app/cad/actions/operationActions.js new file mode 100644 index 00000000..88fbee07 --- /dev/null +++ b/web/app/cad/actions/operationActions.js @@ -0,0 +1,105 @@ +import * as Operations from '../craft/operations' +import * as ActionHelpers from './action-helpers' + +const OPERATION_ACTIONS = [ + { + id: 'CUT', + appearance: { + info: 'makes a cut based on 2D sketch', + }, + ...requiresFaceSelection(1) + }, + { + id: 'EXTRUDE', + appearance: { + info: 'extrudes 2D sketch', + }, + }, + { + id: 'REVOLVE', + appearance: { + info: 'revolve 2D sketch', + }, + ...requiresFaceSelection(1) + }, + { + id: 'SHELL', + appearance: { + info: 'makes shell using borders', + }, + ...requiresFaceSelection(1) + }, + { + id: 'BOX', + appearance: { + info: 'creates new object box' + }, + }, + { + id: 'PLANE', + appearance: { + info: 'creates new object plane' + }, + }, + { + id: 'SPHERE', + appearance: { + info: 'creates new object sphere' + }, + }, + { + id: 'INTERSECTION', + appearance: { + info: 'intersection operation on two solids', + }, + ...requiresSolidSelection(2) + }, + { + id: 'DIFFERENCE', + appearance: { + info: 'difference operation on two solids', + }, + ...requiresSolidSelection(2) + }, + { + id: 'UNION', + appearance: { + info: 'union operation on two solids', + }, + ...requiresSolidSelection(2) + }, + { + id: 'IMPORT_STL', + appearance: { + info: 'import stl from external location' + } + } +]; + +function mergeInfo(action) { + const op = Operations[action.id]; + action.invoke = app => app.ui.initOperation(action.id); + Object.assign(action.appearance, { + label: op.label, + icon32: op.icon + '32.png', + icon96: op.icon + '96.png', + }); +} + +OPERATION_ACTIONS.forEach(action => mergeInfo(action)); + +function requiresFaceSelection(amount) { + return { + listens: ['selection_face'], + update: ActionHelpers.checkForSelectedFaces(amount) + } +} + +function requiresSolidSelection(amount) { + return { + listens: ['selection_face'], + update: ActionHelpers.checkForSelectedSolids(amount) + } +} + +export default OPERATION_ACTIONS; \ No newline at end of file diff --git a/web/app/3d/cad-utils.js b/web/app/cad/cad-utils.js similarity index 100% rename from web/app/3d/cad-utils.js rename to web/app/cad/cad-utils.js diff --git a/web/app/3d/counters.js b/web/app/cad/counters.js similarity index 100% rename from web/app/3d/counters.js rename to web/app/cad/counters.js diff --git a/web/app/3d/craft/brep/boolean-operation.js b/web/app/cad/craft/brep/boolean-operation.js similarity index 100% rename from web/app/3d/craft/brep/boolean-operation.js rename to web/app/cad/craft/brep/boolean-operation.js diff --git a/web/app/3d/craft/brep/cut-extrude.js b/web/app/cad/craft/brep/cut-extrude.js similarity index 100% rename from web/app/3d/craft/brep/cut-extrude.js rename to web/app/cad/craft/brep/cut-extrude.js diff --git a/web/app/3d/craft/brep/revolve.js b/web/app/cad/craft/brep/revolve.js similarity index 100% rename from web/app/3d/craft/brep/revolve.js rename to web/app/cad/craft/brep/revolve.js diff --git a/web/app/3d/craft/brep/wizards/box.js b/web/app/cad/craft/brep/wizards/box.js similarity index 100% rename from web/app/3d/craft/brep/wizards/box.js rename to web/app/cad/craft/brep/wizards/box.js diff --git a/web/app/3d/craft/brep/wizards/cut-extrude-wizard.js b/web/app/cad/craft/brep/wizards/cut-extrude-wizard.js similarity index 100% rename from web/app/3d/craft/brep/wizards/cut-extrude-wizard.js rename to web/app/cad/craft/brep/wizards/cut-extrude-wizard.js diff --git a/web/app/3d/craft/brep/wizards/plane-wizard.js b/web/app/cad/craft/brep/wizards/plane-wizard.js similarity index 100% rename from web/app/3d/craft/brep/wizards/plane-wizard.js rename to web/app/cad/craft/brep/wizards/plane-wizard.js diff --git a/web/app/3d/craft/brep/wizards/preview-wizard.js b/web/app/cad/craft/brep/wizards/preview-wizard.js similarity index 100% rename from web/app/3d/craft/brep/wizards/preview-wizard.js rename to web/app/cad/craft/brep/wizards/preview-wizard.js diff --git a/web/app/3d/craft/brep/wizards/revolve-wizard.js b/web/app/cad/craft/brep/wizards/revolve-wizard.js similarity index 100% rename from web/app/3d/craft/brep/wizards/revolve-wizard.js rename to web/app/cad/craft/brep/wizards/revolve-wizard.js diff --git a/web/app/3d/craft/brep/wizards/wizard.js b/web/app/cad/craft/brep/wizards/wizard.js similarity index 100% rename from web/app/3d/craft/brep/wizards/wizard.js rename to web/app/cad/craft/brep/wizards/wizard.js diff --git a/web/app/3d/craft/craft.js b/web/app/cad/craft/craft.js similarity index 100% rename from web/app/3d/craft/craft.js rename to web/app/cad/craft/craft.js diff --git a/web/app/3d/craft/mesh/revolve.js b/web/app/cad/craft/mesh/revolve.js similarity index 100% rename from web/app/3d/craft/mesh/revolve.js rename to web/app/cad/craft/mesh/revolve.js diff --git a/web/app/3d/craft/mesh/wizards/box.js b/web/app/cad/craft/mesh/wizards/box.js similarity index 100% rename from web/app/3d/craft/mesh/wizards/box.js rename to web/app/cad/craft/mesh/wizards/box.js diff --git a/web/app/3d/craft/mesh/wizards/extrude.js b/web/app/cad/craft/mesh/wizards/extrude.js similarity index 100% rename from web/app/3d/craft/mesh/wizards/extrude.js rename to web/app/cad/craft/mesh/wizards/extrude.js diff --git a/web/app/3d/craft/mesh/wizards/import.js b/web/app/cad/craft/mesh/wizards/import.js similarity index 100% rename from web/app/3d/craft/mesh/wizards/import.js rename to web/app/cad/craft/mesh/wizards/import.js diff --git a/web/app/3d/craft/mesh/wizards/plane.js b/web/app/cad/craft/mesh/wizards/plane.js similarity index 100% rename from web/app/3d/craft/mesh/wizards/plane.js rename to web/app/cad/craft/mesh/wizards/plane.js diff --git a/web/app/3d/craft/mesh/wizards/revolve.js b/web/app/cad/craft/mesh/wizards/revolve.js similarity index 100% rename from web/app/3d/craft/mesh/wizards/revolve.js rename to web/app/cad/craft/mesh/wizards/revolve.js diff --git a/web/app/3d/craft/mesh/wizards/sphere.js b/web/app/cad/craft/mesh/wizards/sphere.js similarity index 100% rename from web/app/3d/craft/mesh/wizards/sphere.js rename to web/app/cad/craft/mesh/wizards/sphere.js diff --git a/web/app/3d/craft/mesh/wizards/transform.js b/web/app/cad/craft/mesh/wizards/transform.js similarity index 100% rename from web/app/3d/craft/mesh/wizards/transform.js rename to web/app/cad/craft/mesh/wizards/transform.js diff --git a/web/app/3d/craft/mesh/wizards/wizard-commons.js b/web/app/cad/craft/mesh/wizards/wizard-commons.js similarity index 100% rename from web/app/3d/craft/mesh/wizards/wizard-commons.js rename to web/app/cad/craft/mesh/wizards/wizard-commons.js diff --git a/web/app/3d/craft/mesh/workbench.js b/web/app/cad/craft/mesh/workbench.js similarity index 100% rename from web/app/3d/craft/mesh/workbench.js rename to web/app/cad/craft/mesh/workbench.js diff --git a/web/app/3d/craft/operations.js b/web/app/cad/craft/operations.js similarity index 71% rename from web/app/3d/craft/operations.js rename to web/app/cad/craft/operations.js index b6b600d6..de88447d 100644 --- a/web/app/3d/craft/operations.js +++ b/web/app/cad/craft/operations.js @@ -1,39 +1,39 @@ -import {MESH_OPERATIONS} from './mesh/workbench' -import {Extrude, Cut} from './brep/cut-extrude' -import {Revolve} from './brep/revolve' -import {BREPSceneSolid} from '../scene/wrappers/brepSceneObject' -import {PlaneSceneObject} from '../scene/wrappers/planeSceneObject' -import {box} from '../../brep/brep-primitives' +// import {MESH_OPERATIONS} from './mesh/workbench' +// import {Extrude, Cut} from './brep/cut-extrude' +// import {Revolve} from './brep/revolve' +// import {BREPSceneSolid} from '../scene/wrappers/brepSceneObject' +// import {PlaneSceneObject} from '../scene/wrappers/planeSceneObject' +// import {box} from '../../brep/brep-primitives' export const CUT = { - icon: 'img/3d/cut', + icon: 'img/cad/cut', label: 'Cut', info: (p) => '(' + r(p.value) + ')', action: (app, params) => Cut(app, params) }; export const EXTRUDE = { - icon: 'img/3d/extrude', + icon: 'img/cad/extrude', label: 'Extrude', info: (p) => '(' + r(p.value) + ')', action: (app, params) => Extrude(app, params) }; export const REVOLVE = { - icon: 'img/3d/revolve', + icon: 'img/cad/revolve', label: 'Revolve', info: (p) => '(' + p.angle + ')', action: (app, params) => Revolve(app, params) }; export const SHELL = { - icon: 'img/3d/shell', + icon: 'img/cad/shell', label: 'Shell', info: (p) => '(' + p.d + ')' }; export const BOX = { - icon: 'img/3d/cube', + icon: 'img/cad/cube', label: 'Box', info: (p) => '(' + p.width + ', ' + p.height + ', ' + p.depth + ')', action: (app, request) => { @@ -45,7 +45,7 @@ export const BOX = { }; export const PLANE = { - icon: 'img/3d/plane', + icon: 'img/cad/plane', label: 'Plane', info: (p) => '(' + p.depth + ')', action: (app, request) => { @@ -57,7 +57,7 @@ export const PLANE = { }; export const SPHERE = { - icon: 'img/3d/sphere', + icon: 'img/cad/sphere', label: 'Sphere', info: (p) => '(' + p.radius + ')', action: (app, request) => { @@ -66,25 +66,25 @@ export const SPHERE = { }; export const INTERSECTION = { - icon: 'img/3d/intersection', + icon: 'img/cad/intersection', label: 'Intersection', info: (p) => null }; export const DIFFERENCE = { - icon: 'img/3d/difference', + icon: 'img/cad/difference', label: 'Difference', info: (p) => null }; export const UNION = { - icon: 'img/3d/union', + icon: 'img/cad/union', label: 'Union', info: (p) => null }; export const IMPORT_STL = { - icon: 'img/3d/stl', + icon: 'img/cad/stl', label: 'STL Import', info: (p) => '(' + p.url.substring(p.url.lastIndexOf('/') + 1 ) + ')', action: (app, request) => { diff --git a/web/app/3d/craft/sketch/sketch-model.js b/web/app/cad/craft/sketch/sketch-model.js similarity index 100% rename from web/app/3d/craft/sketch/sketch-model.js rename to web/app/cad/craft/sketch/sketch-model.js diff --git a/web/app/3d/craft/sketch/sketch-reader.js b/web/app/cad/craft/sketch/sketch-reader.js similarity index 100% rename from web/app/3d/craft/sketch/sketch-reader.js rename to web/app/cad/craft/sketch/sketch-reader.js diff --git a/web/app/3d/debug.js b/web/app/cad/debug.js similarity index 100% rename from web/app/3d/debug.js rename to web/app/cad/debug.js diff --git a/web/app/cad/dom/components/ControlBar.jsx b/web/app/cad/dom/components/ControlBar.jsx new file mode 100644 index 00000000..d7f3ca35 --- /dev/null +++ b/web/app/cad/dom/components/ControlBar.jsx @@ -0,0 +1,23 @@ +import React from 'react'; + +import ls from './ControlBar.less'; +import cx from 'classnames'; + +export default function ControlBar({left, right}) { + + return
+
+ {right} +
+
+ {left} +
+
+} + +export function ControlBarButton({onClick, onElement, disabled, children}) { + return + {children} + +} \ No newline at end of file diff --git a/web/app/cad/dom/components/ControlBar.less b/web/app/cad/dom/components/ControlBar.less new file mode 100644 index 00000000..95161e0c --- /dev/null +++ b/web/app/cad/dom/components/ControlBar.less @@ -0,0 +1,36 @@ +@import "~ui/styles/theme"; + +.root { + position: absolute; + bottom: 0; + left: 0; + right: 0; + display: flex; + justify-content: space-between; + background-color: @work-area-control-bar-bg-color; + color: @work-area-control-bar-font-color; +} + +.button { + display: inline-block; + cursor: pointer; + padding: 0.3em 0.3em 0.4em 0.6em; + + @border: 1px solid @border-color; + &.left { + border-right: @border; + } + &.right { + border-left: @border; + } + &:hover { + background-color: @work-area-control-bar-bg-color-active; + } +} + +.button.disabled { + color: @font-color-suppressed; + &:hover { + background-color: @work-area-control-bar-bg-color; + } +} diff --git a/web/app/cad/dom/components/ObjectExplorer.jsx b/web/app/cad/dom/components/ObjectExplorer.jsx new file mode 100644 index 00000000..9bf2ded7 --- /dev/null +++ b/web/app/cad/dom/components/ObjectExplorer.jsx @@ -0,0 +1,10 @@ +import React from 'react'; + +export default class ObjectExplorer extends React.Component { + + render() { + return
+ ObjectExplorer +
+ } +} \ No newline at end of file diff --git a/web/app/cad/dom/components/OperationHistory.jsx b/web/app/cad/dom/components/OperationHistory.jsx new file mode 100644 index 00000000..4a00b8df --- /dev/null +++ b/web/app/cad/dom/components/OperationHistory.jsx @@ -0,0 +1,10 @@ +import React from 'react'; + +export default class OperationHistory extends React.Component { + + render() { + return
+ OperationHistory +
+ } +} \ No newline at end of file diff --git a/web/app/cad/dom/components/PlugableControlBar.jsx b/web/app/cad/dom/components/PlugableControlBar.jsx new file mode 100644 index 00000000..b64259a4 --- /dev/null +++ b/web/app/cad/dom/components/PlugableControlBar.jsx @@ -0,0 +1,56 @@ +import React, {Fragment} from 'react'; +import ControlBar, {ControlBarButton} from './ControlBar'; +import connect from 'ui/connect'; +import Fa from 'ui/components/Fa'; +import {TOKENS as UI_TOKENS} from '../uiEntryPointsPlugin'; +import {TOKENS as ACTION_TOKENS} from '../../actions/actionSystemPlugin'; +import {toIdAndOverrides} from "../../actions/actionRef"; + + +export default function PlugableControlBar() { + return } right={}/>; +} + +function ButtonGroup({actions}) { + return actions.map(actionRef => { + let [id, overrides] = toIdAndOverrides(actionRef); + let actionRunToken = ACTION_TOKENS.actionRun(id); + let Comp = connect([ACTION_TOKENS.actionAppearance(id), ACTION_TOKENS.actionState(id)], + ActionButton, {actionId: id}, + ([appearance, state]) => Object.assign({}, appearance, state, overrides), + dispatch => ({runAction: (data) => dispatch(actionRunToken, data)}) + ); + return ; + }); +} + +function isMenuAction(actionId) { + return actionId.startsWith('menu.'); +} + +class ActionButton extends React.Component { + + render() { + let {label, cssIcons, runAction, enabled, visible, actionId} = this.props; + if (!visible) { + return null; + } + const onClick = e => runAction(isMenuAction(actionId) ? getMenuData(this.el) : undefined); + return this.el = el}> + {cssIcons && } {label} + ; + } +} + +const LeftGroup = connect(UI_TOKENS.CONTROL_BAR_LEFT, ButtonGroup, undefined, ([actions]) => ({actions})); +const RightGroup = connect(UI_TOKENS.CONTROL_BAR_RIGHT, ButtonGroup, undefined, ([actions]) => ({actions})); + +function getMenuData(el) { + //TODO: make more generic + return { + orientationUp: true, + flatBottom: true, + x: el.offsetParent.offsetParent.offsetLeft + el.offsetLeft, + y: el.offsetParent.offsetHeight - el.offsetTop + }; +} diff --git a/web/app/cad/dom/components/PlugableToolbar.jsx b/web/app/cad/dom/components/PlugableToolbar.jsx new file mode 100644 index 00000000..7838fb31 --- /dev/null +++ b/web/app/cad/dom/components/PlugableToolbar.jsx @@ -0,0 +1,44 @@ +import React, {Fragment} from 'react'; +import connect from 'ui/connect'; +import Fa from 'ui/components/Fa'; +import {TOKENS as UI_TOKENS} from '../uiEntryPointsPlugin'; +import {TOKENS as ACTION_TOKENS} from '../../actions/actionSystemPlugin'; +import Toolbar, {ToolbarButton} from "../../../../../modules/ui/components/Toolbar"; +import ImgIcon from "../../../../../modules/ui/components/ImgIcon"; +import {toIdAndOverrides} from "../../actions/actionRef"; + + +function ConfigurableToolbar({actions, small}) { + + return + {actions.map(actionRef => { + let [id, overrides] = toIdAndOverrides(actionRef); + let Comp = connect( + [ACTION_TOKENS.actionAppearance(id), ACTION_TOKENS.actionState(id)], + ActionButton, {small, }, + ([appearance, state]) => Object.assign({}, appearance, state, overrides)); + return + })} + +} + +function ActionButton({label, icon96, cssIcons, small, enabled, visible, onClick}) { + if (!visible) { + return null; + } + + let icon = small ? : ; + + return + {icon} + {!small &&
{label}
} +
+} + +export function createPlugableToolbar(configToken, small) { + return connect(configToken, ConfigurableToolbar, {small}, ([actions]) => ({actions}) ); +} + +export const PlugableToolbarLeft = createPlugableToolbar(UI_TOKENS.TOOLBAR_BAR_LEFT); +export const PlugableToolbarLeftSecondary = createPlugableToolbar(UI_TOKENS.TOOLBAR_BAR_LEFT_SECONDARY); +export const PlugableToolbarRight = createPlugableToolbar(UI_TOKENS.TOOLBAR_BAR_RIGHT, true); \ No newline at end of file diff --git a/web/app/cad/dom/components/View3d.jsx b/web/app/cad/dom/components/View3d.jsx new file mode 100644 index 00000000..d1445863 --- /dev/null +++ b/web/app/cad/dom/components/View3d.jsx @@ -0,0 +1,63 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import PlugableControlBar from './PlugableControlBar'; + +import ls from './View3d.less'; +import ObjectExplorer from './ObjectExplorer'; +import OperationHistory from './OperationHistory'; +import Toolbar, {ToolbarButton} from 'ui/components/Toolbar'; +import ImgIcon from 'ui/components/ImgIcon'; +import Fa from 'ui/components/Fa'; +import Abs from 'ui/components/Abs'; +import {PlugableToolbarLeft, PlugableToolbarLeftSecondary, PlugableToolbarRight} from "./PlugableToolbar"; +import MenuHolder from "../menu/MenuHolder"; +import {TOKENS as MENU_TOKENS} from '../menu/menuPlugin'; + + +export default class View3d extends React.PureComponent { + + render() { + return
+ +
+ + +
+
+ {/*
+
+ + + + + + + + +
+
+ } + + closeAllUpPopups = () => { + let openedMenus = this.context.bus.state[MENU_TOKENS.OPENED]; + if (openedMenus && openedMenus.length !== 0) { + this.context.bus.dispatch(MENU_TOKENS.CLOSE_ALL); + } + + }; + + getChildContext() { + return { + closeAllUpPopups: this.closeAllUpPopups + } + } + + static contextTypes = { + bus: PropTypes.object + }; + + static childContextTypes = { + closeAllUpPopups: PropTypes.func + }; +} \ No newline at end of file diff --git a/web/app/cad/dom/components/View3d.less b/web/app/cad/dom/components/View3d.less new file mode 100644 index 00000000..b8d79fb2 --- /dev/null +++ b/web/app/cad/dom/components/View3d.less @@ -0,0 +1,23 @@ +.root { + height: 100%; + display: flex; +} + +.viewer { + display: flex; + flex-direction: column; + flex: 1; + position: relative; +} + +.sideBar { + flex-basis: 250px; +} + +.leftToolbarGroup > * { + margin-bottom: 0.8em; +} + +.smallToolbar > * { + font-size: 2em; +} diff --git a/web/app/cad/dom/components/WebApplication.jsx b/web/app/cad/dom/components/WebApplication.jsx new file mode 100644 index 00000000..52268df0 --- /dev/null +++ b/web/app/cad/dom/components/WebApplication.jsx @@ -0,0 +1,88 @@ +import React, {Fragment} from 'react'; +import PropTypes from 'prop-types'; + +import 'ui/styles/init/minireset.css'; +import 'ui/styles/init/main.less'; +import '../../../../css/app3d-legacy.less'; + +import View3d from './View3d'; + +import WindowSystem from 'ui/WindowSystem'; +import Window from "ui/components/Window"; +import Folder from "ui/components/Folder"; +import Field from "ui/components/controls/Field"; +import Label from "ui/components/controls/Label"; +import NumberControl from "ui/components/controls/NumberControl"; +import ButtonGroup from "ui/components/controls/ButtonGroup"; +import Button from "ui/components/controls/Button"; + +import ls from './WebApplication.less'; +import TabSwitcher, {Tab} from 'ui/components/TabSwticher'; +import Card from 'ui/components/Card'; + +const DEFAULT_VIEW = {id: 'view3d', label: '3D View', Component: View3d}; + +export default class WebApplication extends React.Component { + + constructor({bus}) { + super(); + this.bus = bus; + this.views = [DEFAULT_VIEW, {id: 'XXX', label: '3D View2', Component: Fragment}]; + this.state = { + activeView: DEFAULT_VIEW + }; + } + + switchTab = (viewId) => { + this.setState({activeView: this.views.find(v => v.id === viewId)}); + }; + + render() { + let activeView = this.state.activeView; + return
+ } + + getChildContext() { + return {bus: this.bus}; + } + + static childContextTypes = { + bus: PropTypes.object + }; +} + +function render(Component) { + return ; +} \ No newline at end of file diff --git a/web/app/cad/dom/components/WebApplication.less b/web/app/cad/dom/components/WebApplication.less new file mode 100644 index 00000000..02df60cf --- /dev/null +++ b/web/app/cad/dom/components/WebApplication.less @@ -0,0 +1,21 @@ +@import "~ui/styles/theme"; + +.root { + height: 100%; + display: flex; + flex-direction: column; +} + +.content { + display: flex; + flex-direction: column; + flex: 1; + & > * { + flex: 1; + } + position: relative; +} + +.contentSwitcher { + border-top: 1px solid @border-color; +} \ No newline at end of file diff --git a/web/app/3d/dom/domPlugin.js b/web/app/cad/dom/domPlugin.js similarity index 100% rename from web/app/3d/dom/domPlugin.js rename to web/app/cad/dom/domPlugin.js diff --git a/web/app/cad/dom/menu/MenuHolder.jsx b/web/app/cad/dom/menu/MenuHolder.jsx new file mode 100644 index 00000000..fafdc003 --- /dev/null +++ b/web/app/cad/dom/menu/MenuHolder.jsx @@ -0,0 +1,66 @@ +import React, {Fragment} from 'react'; +import connect from 'ui/connect'; +import {TOKENS as MENU_TOKENS} from './menuPlugin'; +import {TOKENS as ACTION_TOKENS} from '../../actions/actionSystemPlugin'; +import Menu, {MenuItem, MenuSeparator} from "../../../../../modules/ui/components/Menu"; +import Fa from "../../../../../modules/ui/components/Fa"; +import Filler from "../../../../../modules/ui/components/Filler"; +import {TOKENS as KeyboardTokens} from "../../keyboard/keyboardPlugin"; + +function MenuHolder({menus}) { + return menus.map(({id, actions}) => { + let menuToken = MENU_TOKENS.menuState(id); + return React.createElement(connect([menuToken, KeyboardTokens.KEYMAP], + ActionMenu, {actions}, [,keymap => ({keymap})]), {key: id}); + }); +} + +function ActionMenu({actions, keymap, ...props}) { + return + {actions.map((action, index)=> { + if (action === '-') { + return + } + const runToken = ACTION_TOKENS.actionRun(action); + return React.createElement( + connect([ACTION_TOKENS.actionState(action), ACTION_TOKENS.actionAppearance(action)], + ActionMenuItem, + {hotKey: keymap[action]}, undefined, + dispatch => ({ + onClick: () => dispatch(runToken) + })), + {key: action}); + })} + ; +} + +function ActionMenuItem({label, cssIcons, icon32, icon96, onClick, enabled, hotKey, visible}) { + if (!visible) { + return null; + } + let icon, style; + if (icon32 || icon96) { + let size = 16; + icon = ; + style = { + backgroundImage: `url(${icon32 || icon96})`, + backgroundRepeat: 'no-repeat', + backgroundSize: `${size}px ${size}px`, + backgroundPositionY: 6, + backgroundPositionX: 5, + }; + if (!enabled) { + style.filter = 'grayscale(90%)'; + } + } else if (cssIcons) { + icon = ; + } + + return ; +} + + +export default connect(MENU_TOKENS.MENUS, MenuHolder, undefined, ([menus]) => ({menus})); + + + diff --git a/web/app/cad/dom/menu/menuPlugin.js b/web/app/cad/dom/menu/menuPlugin.js new file mode 100644 index 00000000..ea109858 --- /dev/null +++ b/web/app/cad/dom/menu/menuPlugin.js @@ -0,0 +1,50 @@ +import {createToken} from 'bus'; + +export function activate({bus, services}) { + + bus.enableState(TOKENS.MENUS, []); + bus.enableState(TOKENS.OPENED, []); + + function registerMenus(menus) { + let menusToAdd = []; + let showMenuActions = []; + menus.forEach(({id, actions, ...appearance}) => { + let stateToken = TOKENS.menuState(id); + bus.enableState(stateToken, { + visible: false, + orientationUp: false, + x: undefined, + y: undefined + }); + if (!appearance) { + appearance.label = id; + } + showMenuActions.push({ + id: 'menu.' + id, + appearance, + invoke: (ctx, hints) => bus.updateStates([stateToken, TOKENS.OPENED], + ([state, opened]) => [Object.assign(state, {visible: true}, hints), [id, ...opened]] + ) + }); + + menusToAdd.push({id, actions}); + }); + services.action.registerActions(showMenuActions); + bus.updateState(TOKENS.MENUS, menus => [...menus, ...menusToAdd]); + } + + bus.subscribe(TOKENS.CLOSE_ALL, () => { + bus.state[TOKENS.OPENED].forEach(openedMenu => bus.setState(TOKENS.menuState(openedMenu), {visible: false})); + bus.updateState(TOKENS.OPENED, () => []); + }); + + services.menu = { registerMenus } +} + +export const TOKENS = { + menuState: id => createToken('menu', 'state', id), + MENUS: createToken('menus'), + CLOSE_ALL: createToken('menus', 'closeAll'), + OPENED: createToken('menus', 'opened') +}; + diff --git a/web/app/cad/dom/startReact.jsx b/web/app/cad/dom/startReact.jsx new file mode 100644 index 00000000..a16cce39 --- /dev/null +++ b/web/app/cad/dom/startReact.jsx @@ -0,0 +1,11 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import WebApplication from './components/WebApplication'; + +export default function startReact(bus, callback) { + return ReactDOM.render( + , + document.getElementById('app'), + callback + ); +} \ No newline at end of file diff --git a/web/app/cad/dom/uiEntryPointsPlugin.js b/web/app/cad/dom/uiEntryPointsPlugin.js new file mode 100644 index 00000000..c4e9cb06 --- /dev/null +++ b/web/app/cad/dom/uiEntryPointsPlugin.js @@ -0,0 +1,25 @@ +import {createToken} from 'bus'; + + +export function activate({bus}) { + + bus.enableState(TOKENS.CONTROL_BAR_LEFT, []); + bus.enableState(TOKENS.CONTROL_BAR_RIGHT, []); + + bus.enableState(TOKENS.TOOLBAR_BAR_LEFT, []); + bus.enableState(TOKENS.TOOLBAR_BAR_LEFT_SECONDARY, []); + bus.enableState(TOKENS.TOOLBAR_BAR_RIGHT, []); + +} + +const NS = 'ui.config'; + +export const TOKENS = { + CONTROL_BAR_LEFT: createToken(NS, 'controlBar.left'), + CONTROL_BAR_RIGHT: createToken(NS, 'controlBar.right'), + + TOOLBAR_BAR_LEFT: createToken(NS, 'toolbar.left'), + TOOLBAR_BAR_LEFT_SECONDARY: createToken(NS, 'toolbar.left.secondary'), + TOOLBAR_BAR_RIGHT: createToken(NS, 'toolbar.right'), +}; + diff --git a/web/app/cad/init/startApplication.js b/web/app/cad/init/startApplication.js new file mode 100644 index 00000000..cd4f2048 --- /dev/null +++ b/web/app/cad/init/startApplication.js @@ -0,0 +1,53 @@ +import Bus from 'bus'; +import * as DomPlugin from '../dom/domPlugin'; +import * as PickControlPlugin from '../scene/controls/pickControlPlugin'; +import * as ScenePlugin from '../scene/scenePlugin'; +import * as SelectionMarkerPlugin from '../scene/selectionMarker/selectionMarkerPlugin'; +import * as ActionSystemPlugin from '../actions/actionSystemPlugin'; +import * as UiEntryPointsPlugin from '../dom/uiEntryPointsPlugin'; +import * as MenuPlugin from '../dom/menu/menuPlugin'; +import * as KeyboardPlugin from '../keyboard/keyboardPlugin'; + +import * as PartModellerPlugin from '../part/partModellerPlugin'; + +import startReact from "../dom/startReact"; + +export default function startApplication(callback) { + + let applicationPlugins = [PartModellerPlugin]; + + let preUIPlugins = [ + ActionSystemPlugin, + MenuPlugin, + UiEntryPointsPlugin, + KeyboardPlugin + ]; + + let plugins = [ + DomPlugin, + ScenePlugin, + PickControlPlugin, + SelectionMarkerPlugin, + ...applicationPlugins, + ]; + + let context = { + bus: new Bus(), + services: {} + }; + + activatePlugins(preUIPlugins, context); + + startReact(context.bus, () => { + activatePlugins(plugins, context); + context.services.viewer.render(); + callback(context); + }); +} + +function activatePlugins(plugins, context) { + for (let plugin of plugins) { + plugin.activate(context); + } +} + diff --git a/web/app/3d/io.js b/web/app/cad/io.js similarity index 100% rename from web/app/3d/io.js rename to web/app/cad/io.js diff --git a/web/app/cad/keyboard/keyboardPlugin.js b/web/app/cad/keyboard/keyboardPlugin.js new file mode 100644 index 00000000..d1803843 --- /dev/null +++ b/web/app/cad/keyboard/keyboardPlugin.js @@ -0,0 +1,11 @@ +import DefaultKeymap from './keymaps/default'; + +import {createToken} from "../../../../modules/bus/index"; + +export function activate({bus}) { + bus.enableState(TOKENS.KEYMAP, DefaultKeymap); +} + +export const TOKENS = { + KEYMAP: createToken('keymap') +}; \ No newline at end of file diff --git a/web/app/3d/ui/keymaps/default.js b/web/app/cad/keyboard/keymaps/default.js similarity index 90% rename from web/app/3d/ui/keymaps/default.js rename to web/app/cad/keyboard/keymaps/default.js index 2a7ca0fa..adc090f7 100644 --- a/web/app/3d/ui/keymaps/default.js +++ b/web/app/cad/keyboard/keymaps/default.js @@ -1,4 +1,4 @@ -export const keymap = { +export default { 'CUT': 'C', 'EXTRUDE': 'E', 'ZoomIn': '+', diff --git a/web/app/3d/menu/menu.js b/web/app/cad/menu/menu.js similarity index 100% rename from web/app/3d/menu/menu.js rename to web/app/cad/menu/menu.js diff --git a/web/app/3d/mesh.js b/web/app/cad/mesh.js similarity index 100% rename from web/app/3d/mesh.js rename to web/app/cad/mesh.js diff --git a/web/app/3d/modeler-app.js b/web/app/cad/modeler-app.js similarity index 98% rename from web/app/3d/modeler-app.js rename to web/app/cad/modeler-app.js index 7f4d2ac8..57e54d71 100644 --- a/web/app/3d/modeler-app.js +++ b/web/app/cad/modeler-app.js @@ -6,7 +6,7 @@ import TabSwitcher from './ui/tab-switcher' import ControlBar from './ui/control-bar' import {InputManager} from './ui/input-manager' import {ActionManager} from './actions/actions' -import * as AllActions from './actions/all-actions' +import * as AllActions from './actions/allActions' import Vector from 'math/vector'; import {Matrix3, AXIS, ORIGIN, IDENTITY_BASIS} from '../math/l3space' import {Craft} from './craft/craft' @@ -17,7 +17,6 @@ import * as math from '../math/math' import {IO} from '../sketcher/io' import {AddDebugSupport} from './debug' import {init as initSample} from './sample' -import '../../css/app3d.less' import BrepBuilder from '../brep/brep-builder' import * as BREPPrimitives from '../brep/brep-primitives' @@ -49,7 +48,7 @@ function App() { // this.viewer.workGroup = this.context.services.cadScene.workGroup; this.actionManager.registerActions(AllActions); - this.tabSwitcher = new TabSwitcher($('#tab-switcher'), $('#view-3d')); + // this.tabSwitcher = new TabSwitcher($('#tab-switcher'), $('#view-3d')); this.controlBar = new ControlBar(this, $('#control-bar')); this.TPI = TPI; @@ -94,7 +93,7 @@ function App() { App.prototype.createPluginContext = function() { return { bus: this.bus, - services: {} + services: {} }; }; @@ -104,6 +103,14 @@ App.prototype.initPlugins = function() { } }; +//temporary workaround before extracted to plugin +App.prototype.activateSketcherPlugin = function(context) { + context.services.sketcher = { + sketchFace: (sceneFace) => this.sketchFace(sceneFace), + editFace: () => this.editFace() + } +}; + App.prototype.getFaceSelection = function() { let selection = this.context.bus.state['selection_face']; return selection; diff --git a/web/app/cad/part/menuConfig.js b/web/app/cad/part/menuConfig.js new file mode 100644 index 00000000..2b415a7e --- /dev/null +++ b/web/app/cad/part/menuConfig.js @@ -0,0 +1,41 @@ +export default [ + { + id: 'file', + cssIcons: ['file'], + actions: ['Save', 'StlExport', '-', 'IMPORT_STL'] + }, + { + id: 'craft', + cssIcons: ['magic'], + info: 'set of available craft operations on a solid', + actions: ['EXTRUDE', 'CUT', 'REVOLVE', 'SHELL'] + }, + { + id: 'primitives', + label: 'add', + cssIcons: ['cube', 'plus'], + info: 'set of available solid creation operations', + actions: ['PLANE', 'BOX', 'SPHERE'] + }, + { + id: 'boolean', + label: 'bool', + cssIcons: ['pie-chart'], + info: 'set of available boolean operations', + actions: ['INTERSECTION', 'DIFFERENCE', 'UNION'] + }, + { + id: 'main', + label: 'start', + cssIcons: ['rocket'], + info: 'common set of actions', + actions: ['EXTRUDE', 'CUT', 'SHELL', '-', 'INTERSECTION', 'DIFFERENCE', 'UNION', '-', 'PLANE', 'BOX', 'SPHERE', '-', + 'EditFace', '-', 'DeselectAll', 'RefreshSketches'] + }, + { + id: 'SolidContext', + label: 'solid-context', + info: 'solid context actions', + actions: ['LookAtSolid'] + } +]; diff --git a/web/app/cad/part/partModellerPlugin.js b/web/app/cad/part/partModellerPlugin.js new file mode 100644 index 00000000..8ac5b70c --- /dev/null +++ b/web/app/cad/part/partModellerPlugin.js @@ -0,0 +1,25 @@ +import CoreActions from '../actions/coreActions'; +import OperationActions from '../actions/operationActions'; +import HistoryActions from '../actions/historyActions'; +import {TOKENS as UI_TOKENS} from '../dom/uiEntryPointsPlugin'; +import menuConfig from "./menuConfig"; + +export function activate({bus, services}) { + + services.action.registerActions(CoreActions); + services.action.registerActions(OperationActions); + services.action.registerActions(HistoryActions); + + services.menu.registerMenus(menuConfig); + + bus.dispatch(UI_TOKENS.CONTROL_BAR_LEFT, ['menu.file', 'menu.craft', 'menu.boolean', 'menu.primitives', 'Donate', 'GitHub']); + bus.dispatch(UI_TOKENS.CONTROL_BAR_RIGHT, [ + ['Info', {label: null}], + ['RefreshSketches', {label: null}], + ['ShowSketches', {label: 'sketches'}], ['DeselectAll', null], ['ToggleCameraMode', null] + ]); + + bus.dispatch(UI_TOKENS.TOOLBAR_BAR_LEFT, ['PLANE', 'EditFace', 'EXTRUDE', 'CUT', 'REVOLVE']); + bus.dispatch(UI_TOKENS.TOOLBAR_BAR_LEFT_SECONDARY, ['INTERSECTION', 'DIFFERENCE', 'UNION']); + bus.dispatch(UI_TOKENS.TOOLBAR_BAR_RIGHT, ['Save', 'StlExport']); +} \ No newline at end of file diff --git a/web/app/3d/plugins.js b/web/app/cad/plugins.js similarity index 100% rename from web/app/3d/plugins.js rename to web/app/cad/plugins.js diff --git a/web/app/3d/sample.js b/web/app/cad/sample.js similarity index 100% rename from web/app/3d/sample.js rename to web/app/cad/sample.js diff --git a/web/app/3d/scene/cadScene.js b/web/app/cad/scene/cadScene.js similarity index 100% rename from web/app/3d/scene/cadScene.js rename to web/app/cad/scene/cadScene.js diff --git a/web/app/3d/scene/controls/pickControlPlugin.js b/web/app/cad/scene/controls/pickControlPlugin.js similarity index 91% rename from web/app/3d/scene/controls/pickControlPlugin.js rename to web/app/cad/scene/controls/pickControlPlugin.js index 9ba960a9..973154ef 100644 --- a/web/app/3d/scene/controls/pickControlPlugin.js +++ b/web/app/cad/scene/controls/pickControlPlugin.js @@ -9,13 +9,9 @@ export const PICK_KIND = { export function activate(context) { - let {bus} = context; + initStateAndServices(context); let domElement = context.services.viewer.sceneSetup.domElement(); - bus.enableState('selection_solid', []); - bus.enableState('selection_face', []); - bus.enableState('selection_edge', []); - bus.enableState('selection_sketchObject', []); - + domElement.addEventListener('mousedown', mousedown, false); domElement.addEventListener('mouseup', mouseup, false); @@ -113,6 +109,19 @@ export function activate(context) { } } +function initStateAndServices({bus, services}) { + bus.enableState('selection_solid', []); + bus.enableState('selection_face', []); + bus.enableState('selection_edge', []); + bus.enableState('selection_sketchObject', []); + + services.selection = { + solid: () => bus.state.selection_solid, + face: () => bus.state.selection_face, + edge: () => bus.state.selection_edge, + sketchObject: () => bus.state.selection_sketchObject + }; +} diff --git a/web/app/3d/scene/scenePlugin.js b/web/app/cad/scene/scenePlugin.js similarity index 100% rename from web/app/3d/scene/scenePlugin.js rename to web/app/cad/scene/scenePlugin.js diff --git a/web/app/3d/scene/selectionMarker/abstractSelectionMarker.js b/web/app/cad/scene/selectionMarker/abstractSelectionMarker.js similarity index 100% rename from web/app/3d/scene/selectionMarker/abstractSelectionMarker.js rename to web/app/cad/scene/selectionMarker/abstractSelectionMarker.js diff --git a/web/app/3d/scene/selectionMarker/edgeSelectionMarker.js b/web/app/cad/scene/selectionMarker/edgeSelectionMarker.js similarity index 100% rename from web/app/3d/scene/selectionMarker/edgeSelectionMarker.js rename to web/app/cad/scene/selectionMarker/edgeSelectionMarker.js diff --git a/web/app/3d/scene/selectionMarker/lineMarker.js b/web/app/cad/scene/selectionMarker/lineMarker.js similarity index 100% rename from web/app/3d/scene/selectionMarker/lineMarker.js rename to web/app/cad/scene/selectionMarker/lineMarker.js diff --git a/web/app/3d/scene/selectionMarker/selectionMarker.js b/web/app/cad/scene/selectionMarker/selectionMarker.js similarity index 100% rename from web/app/3d/scene/selectionMarker/selectionMarker.js rename to web/app/cad/scene/selectionMarker/selectionMarker.js diff --git a/web/app/3d/scene/selectionMarker/selectionMarkerPlugin.js b/web/app/cad/scene/selectionMarker/selectionMarkerPlugin.js similarity index 100% rename from web/app/3d/scene/selectionMarker/selectionMarkerPlugin.js rename to web/app/cad/scene/selectionMarker/selectionMarkerPlugin.js diff --git a/web/app/3d/scene/selectionMarker/sketchSelectionMarker.js b/web/app/cad/scene/selectionMarker/sketchSelectionMarker.js similarity index 100% rename from web/app/3d/scene/selectionMarker/sketchSelectionMarker.js rename to web/app/cad/scene/selectionMarker/sketchSelectionMarker.js diff --git a/web/app/3d/scene/viewer.js b/web/app/cad/scene/viewer.js similarity index 100% rename from web/app/3d/scene/viewer.js rename to web/app/cad/scene/viewer.js diff --git a/web/app/3d/scene/wrappers/brepSceneObject.js b/web/app/cad/scene/wrappers/brepSceneObject.js similarity index 100% rename from web/app/3d/scene/wrappers/brepSceneObject.js rename to web/app/cad/scene/wrappers/brepSceneObject.js diff --git a/web/app/3d/scene/wrappers/meshSceneObject.js b/web/app/cad/scene/wrappers/meshSceneObject.js similarity index 100% rename from web/app/3d/scene/wrappers/meshSceneObject.js rename to web/app/cad/scene/wrappers/meshSceneObject.js diff --git a/web/app/3d/scene/wrappers/planeSceneObject.js b/web/app/cad/scene/wrappers/planeSceneObject.js similarity index 100% rename from web/app/3d/scene/wrappers/planeSceneObject.js rename to web/app/cad/scene/wrappers/planeSceneObject.js diff --git a/web/app/3d/scene/wrappers/sceneObject.js b/web/app/cad/scene/wrappers/sceneObject.js similarity index 100% rename from web/app/3d/scene/wrappers/sceneObject.js rename to web/app/cad/scene/wrappers/sceneObject.js diff --git a/web/app/3d/stl/stl-ascii-reader.js b/web/app/cad/stl/stl-ascii-reader.js similarity index 100% rename from web/app/3d/stl/stl-ascii-reader.js rename to web/app/cad/stl/stl-ascii-reader.js diff --git a/web/app/3d/stl/stl-binary-reader.js b/web/app/cad/stl/stl-binary-reader.js similarity index 100% rename from web/app/3d/stl/stl-binary-reader.js rename to web/app/cad/stl/stl-binary-reader.js diff --git a/web/app/3d/stl/stl-data-structure.js b/web/app/cad/stl/stl-data-structure.js similarity index 100% rename from web/app/3d/stl/stl-data-structure.js rename to web/app/cad/stl/stl-data-structure.js diff --git a/web/app/3d/stl/stl-reader.js b/web/app/cad/stl/stl-reader.js similarity index 100% rename from web/app/3d/stl/stl-reader.js rename to web/app/cad/stl/stl-reader.js diff --git a/web/app/3d/tess/brep-tess.js b/web/app/cad/tess/brep-tess.js similarity index 100% rename from web/app/3d/tess/brep-tess.js rename to web/app/cad/tess/brep-tess.js diff --git a/web/app/3d/tess/nested-loops.js b/web/app/cad/tess/nested-loops.js similarity index 100% rename from web/app/3d/tess/nested-loops.js rename to web/app/cad/tess/nested-loops.js diff --git a/web/app/3d/tess/pip.js b/web/app/cad/tess/pip.js similarity index 100% rename from web/app/3d/tess/pip.js rename to web/app/cad/tess/pip.js diff --git a/web/app/3d/tess/triangulation.js b/web/app/cad/tess/triangulation.js similarity index 100% rename from web/app/3d/tess/triangulation.js rename to web/app/cad/tess/triangulation.js diff --git a/web/app/3d/tpi.js b/web/app/cad/tpi.js similarity index 100% rename from web/app/3d/tpi.js rename to web/app/cad/tpi.js diff --git a/web/app/3d/ui/bind.js b/web/app/cad/ui/bind.js similarity index 100% rename from web/app/3d/ui/bind.js rename to web/app/cad/ui/bind.js diff --git a/web/app/3d/ui/control-bar.js b/web/app/cad/ui/control-bar.js similarity index 100% rename from web/app/3d/ui/control-bar.js rename to web/app/cad/ui/control-bar.js diff --git a/web/app/3d/ui/ctrl.js b/web/app/cad/ui/ctrl.js similarity index 100% rename from web/app/3d/ui/ctrl.js rename to web/app/cad/ui/ctrl.js diff --git a/web/app/3d/ui/input-manager.js b/web/app/cad/ui/input-manager.js similarity index 98% rename from web/app/3d/ui/input-manager.js rename to web/app/cad/ui/input-manager.js index ee7d131e..e805a8c3 100644 --- a/web/app/3d/ui/input-manager.js +++ b/web/app/cad/ui/input-manager.js @@ -1,5 +1,5 @@ import {jwerty} from 'jwerty' -import {keymap} from './keymaps/default' +import {keymap} from '../keyboard/keymaps/default' import {Bind} from './bind' import {MessageSink} from './message-sink' import {LoadTemplate, DefaultMouseEvent, EventData, fit} from './utils' diff --git a/web/app/3d/ui/message-sink.js b/web/app/cad/ui/message-sink.js similarity index 100% rename from web/app/3d/ui/message-sink.js rename to web/app/cad/ui/message-sink.js diff --git a/web/app/3d/ui/modifications-panel.js b/web/app/cad/ui/modifications-panel.js similarity index 100% rename from web/app/3d/ui/modifications-panel.js rename to web/app/cad/ui/modifications-panel.js diff --git a/web/app/3d/ui/solid-list.js b/web/app/cad/ui/solid-list.js similarity index 100% rename from web/app/3d/ui/solid-list.js rename to web/app/cad/ui/solid-list.js diff --git a/web/app/3d/ui/tab-switcher.js b/web/app/cad/ui/tab-switcher.js similarity index 100% rename from web/app/3d/ui/tab-switcher.js rename to web/app/cad/ui/tab-switcher.js diff --git a/web/app/3d/ui/tmpl/action-info.html b/web/app/cad/ui/tmpl/action-info.html similarity index 100% rename from web/app/3d/ui/tmpl/action-info.html rename to web/app/cad/ui/tmpl/action-info.html diff --git a/web/app/3d/ui/tmpl/modifications.html b/web/app/cad/ui/tmpl/modifications.html similarity index 100% rename from web/app/3d/ui/tmpl/modifications.html rename to web/app/cad/ui/tmpl/modifications.html diff --git a/web/app/3d/ui/tmpl/solid-list.html b/web/app/cad/ui/tmpl/solid-list.html similarity index 100% rename from web/app/3d/ui/tmpl/solid-list.html rename to web/app/cad/ui/tmpl/solid-list.html diff --git a/web/app/3d/ui/toolbar.js b/web/app/cad/ui/toolbar.js similarity index 100% rename from web/app/3d/ui/toolbar.js rename to web/app/cad/ui/toolbar.js diff --git a/web/app/3d/ui/utils.js b/web/app/cad/ui/utils.js similarity index 100% rename from web/app/3d/ui/utils.js rename to web/app/cad/ui/utils.js diff --git a/web/app/index.js b/web/app/index.js index 16d30e60..0c492d14 100644 --- a/web/app/index.js +++ b/web/app/index.js @@ -1,7 +1,6 @@ -//import './utils/jqueryfy' -import App from './3d/modeler-app' -import startReact from './3d/dom/startReact'; -startReact(() =>{ - window._TCAD_APP = new App(); +import startApplication from "./cad/init/startApplication"; + +startApplication(context => { + window.__CAD_APP = context; }); diff --git a/web/app/sketcher.js b/web/app/sketcher.js index 9141f342..76aa78fc 100644 --- a/web/app/sketcher.js +++ b/web/app/sketcher.js @@ -10,7 +10,7 @@ import '../css/app.less' function initializeSketcherApplication() { var app = new App2D(); - window._TCAD_APP = app; + window.__CAD_APP = app; var 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]]]}'; diff --git a/web/app/utils/jqueryfy.js b/web/app/utils/jqueryfy.js index 4b250de0..74ce9c95 100644 --- a/web/app/utils/jqueryfy.js +++ b/web/app/utils/jqueryfy.js @@ -1,2 +1,6 @@ import $ from 'jquery' + +// Usage of jquery is totally deprecated. It exists only to support legacy code and +// will be gone soon after complete transition to React. + window.jQuery = window.$ = $; diff --git a/web/css/app3d.less b/web/css/app3d-legacy.less similarity index 57% rename from web/css/app3d.less rename to web/css/app3d-legacy.less index 090bcaac..86cf651b 100644 --- a/web/css/app3d.less +++ b/web/css/app3d-legacy.less @@ -1,16 +1,7 @@ @import 'brep-debugger.less'; -@tab-switcher-inner-height: 20px; -@tab-switcher-top-border: 1px; -@tab-switcher-height: @tab-switcher-inner-height + @tab-switcher-top-border; - @tab-border-color: #2c2c2c; - -@right-panel-width: 250px; - -@control-button-border: 1px solid #2c2c2c; @menu-border-radius: 3px; - @suppressed-color: #888; .no-selection { @@ -20,136 +11,14 @@ -ms-user-select: none; } -body { - background-color: #808080; - .main-font; -} - -iframe { - border: 0; -} - -.main-font { - font: 11px 'Lucida Grande', sans-serif; -} - .history-selected, .history-selected:hover { background-color: #780000; } -.app-tab-view { - position: absolute; - top: 0; - bottom: @tab-switcher-height; - width: 100%; -} - -#tab-switcher { - position: absolute; - height: @tab-switcher-inner-height; - bottom: 0; - background-color: #000; - width: 100%; - border-top: 1px solid @tab-border-color; - color: #eee; - text-align: center; - .no-selection; -} - -#tab-switcher .tab { - padding: 2px 5px 0 5px; - height: 100%; - float: left; - cursor: pointer; - border-right: 1px solid #2c2c2c; - color: #aaa; -} - -#tab-switcher .tab:hover { - color: #eee; -} - -#tab-switcher .tab-selected { - background-color: #222; - color: #eee; -} - -.tab .expand:hover { - color: green; -} - -.tab .close:hover { - color: red; -} - -#viewer-container { - position: absolute; - left: @right-panel-width; - right: 0; - top: 0; - bottom: 0; -} - -#control-bar { - position: absolute; - left: @right-panel-width; - right: 0; - bottom: 0; - height: 20px; - background-color: rgba(0, 0, 0, 0.5); - color: #ccc; -} - -#control-bar .left-group { - text-align: left; - float: left; -} - -#control-bar .right-group { - text-align: right; -} - -#control-bar .left-group .button { - float: left; - border-right: @control-button-border; -} - -#control-bar .right-group .button { - float: right; - border-left: @control-button-border; -} - .button .fa { line-height: 1.5; } -#control-bar .button { - padding: 3px 7px 0 5px; - height: 100%; - vertical-align: baseline; - cursor: pointer; - .no-selection -} - -#control-bar .button:hover { - background-color: #555; -} - -#control-bar .button-selected { - background-color: #666; -} - -#control-bar .button-selected:hover { - background-color: #666; -} - -#right-panel { - position: absolute; - height: 100%; - background-color: #000; - width: @right-panel-width; -} - .aux-win { color: #fff; background-color: rgba(40,40,40,0.95); diff --git a/web/img/3d/cube32.png b/web/img/cad/cube32.png similarity index 100% rename from web/img/3d/cube32.png rename to web/img/cad/cube32.png diff --git a/web/img/3d/cube96.png b/web/img/cad/cube96.png similarity index 100% rename from web/img/3d/cube96.png rename to web/img/cad/cube96.png diff --git a/web/img/3d/cut32.png b/web/img/cad/cut32.png similarity index 100% rename from web/img/3d/cut32.png rename to web/img/cad/cut32.png diff --git a/web/img/3d/cut96.png b/web/img/cad/cut96.png similarity index 100% rename from web/img/3d/cut96.png rename to web/img/cad/cut96.png diff --git a/web/img/3d/difference32.png b/web/img/cad/difference32.png similarity index 100% rename from web/img/3d/difference32.png rename to web/img/cad/difference32.png diff --git a/web/img/3d/difference96.png b/web/img/cad/difference96.png similarity index 100% rename from web/img/3d/difference96.png rename to web/img/cad/difference96.png diff --git a/web/img/3d/extrude32.png b/web/img/cad/extrude32.png similarity index 100% rename from web/img/3d/extrude32.png rename to web/img/cad/extrude32.png diff --git a/web/img/3d/extrude96.png b/web/img/cad/extrude96.png similarity index 100% rename from web/img/3d/extrude96.png rename to web/img/cad/extrude96.png diff --git a/web/img/3d/face-edit96.png b/web/img/cad/face-edit96.png similarity index 100% rename from web/img/3d/face-edit96.png rename to web/img/cad/face-edit96.png diff --git a/web/img/3d/intersection32.png b/web/img/cad/intersection32.png similarity index 100% rename from web/img/3d/intersection32.png rename to web/img/cad/intersection32.png diff --git a/web/img/3d/intersection96.png b/web/img/cad/intersection96.png similarity index 100% rename from web/img/3d/intersection96.png rename to web/img/cad/intersection96.png diff --git a/web/img/3d/plane32.png b/web/img/cad/plane32.png similarity index 100% rename from web/img/3d/plane32.png rename to web/img/cad/plane32.png diff --git a/web/img/3d/plane96.png b/web/img/cad/plane96.png similarity index 100% rename from web/img/3d/plane96.png rename to web/img/cad/plane96.png diff --git a/web/img/3d/revolve32.png b/web/img/cad/revolve32.png similarity index 100% rename from web/img/3d/revolve32.png rename to web/img/cad/revolve32.png diff --git a/web/img/3d/revolve96.png b/web/img/cad/revolve96.png similarity index 100% rename from web/img/3d/revolve96.png rename to web/img/cad/revolve96.png diff --git a/web/img/3d/shell32.png b/web/img/cad/shell32.png similarity index 100% rename from web/img/3d/shell32.png rename to web/img/cad/shell32.png diff --git a/web/img/3d/shell96.png b/web/img/cad/shell96.png similarity index 100% rename from web/img/3d/shell96.png rename to web/img/cad/shell96.png diff --git a/web/img/3d/sketch32.png b/web/img/cad/sketch32.png similarity index 100% rename from web/img/3d/sketch32.png rename to web/img/cad/sketch32.png diff --git a/web/img/3d/sketch96.png b/web/img/cad/sketch96.png similarity index 100% rename from web/img/3d/sketch96.png rename to web/img/cad/sketch96.png diff --git a/web/img/3d/solid32.png b/web/img/cad/solid32.png similarity index 100% rename from web/img/3d/solid32.png rename to web/img/cad/solid32.png diff --git a/web/img/3d/sphere32.png b/web/img/cad/sphere32.png similarity index 100% rename from web/img/3d/sphere32.png rename to web/img/cad/sphere32.png diff --git a/web/img/3d/sphere96.png b/web/img/cad/sphere96.png similarity index 100% rename from web/img/3d/sphere96.png rename to web/img/cad/sphere96.png diff --git a/web/img/3d/stl32.png b/web/img/cad/stl32.png similarity index 100% rename from web/img/3d/stl32.png rename to web/img/cad/stl32.png diff --git a/web/img/3d/stl96.png b/web/img/cad/stl96.png similarity index 100% rename from web/img/3d/stl96.png rename to web/img/cad/stl96.png diff --git a/web/img/3d/union32.png b/web/img/cad/union32.png similarity index 100% rename from web/img/3d/union32.png rename to web/img/cad/union32.png diff --git a/web/img/3d/union96.png b/web/img/cad/union96.png similarity index 100% rename from web/img/3d/union96.png rename to web/img/cad/union96.png diff --git a/web/index.html b/web/index.html index f3a7a1a2..d5e605dc 100644 --- a/web/index.html +++ b/web/index.html @@ -1,13 +1,6 @@ TCAD - @@ -16,7 +9,7 @@ -
+
diff --git a/web/test/menu.js b/web/test/menu.js index f1509e5b..7c7a8952 100644 --- a/web/test/menu.js +++ b/web/test/menu.js @@ -1,4 +1,4 @@ -//import {DefaultMouseEvent} from '../app/3d/ui/utils' +//import {DefaultMouseEvent} from '../app/cad/ui/utils' export class Menu { diff --git a/web/test/test.js b/web/test/test.js index 1b2f587e..03310f98 100644 --- a/web/test/test.js +++ b/web/test/test.js @@ -147,7 +147,7 @@ export function load(url, callback) { $(function() { // fire event when iframe is ready frame.load(function() { const win = frame.get(0).contentWindow; - callback(win, win._TCAD_APP) + callback(win, win.__CAD_APP) }); }); frame.attr('src', window.location.origin + url) diff --git a/webpack.config.js b/webpack.config.js index b93baccb..364e2bf6 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -4,7 +4,9 @@ const generateCSSScopedName = require('./build/cssScoopeGenerator')(); const WEB_APP = path.join(__dirname, 'web/app'); const MODULES = path.join(__dirname, 'modules'); -const INTEGRATION_TESTS = path.join(__dirname, 'web/test'); +const INTEGRATION_TESTS = path.join(__dirname, 'web/test'); + +const GLOBAL_CSS = path.join(__dirname, 'web/css'); module.exports = { devtool: 'source-map', @@ -34,14 +36,17 @@ module.exports = { loader: 'babel-loader', include: [MODULES, WEB_APP, INTEGRATION_TESTS] }, { - test: /\.css$/, + test: /\.(less|css)$/, + include: GLOBAL_CSS, use: [ 'style-loader', - 'css-loader', - ] + 'css-loader?-url', + 'less-loader', + ] }, { - test: /\.less$/, + test: /\.(less|css)$/, + include: [MODULES, WEB_APP], use: [ 'style-loader', {