2017-11-15 00:46:02 +01:00
|
|
|
import React from 'react';
|
|
|
|
import PropTypes from 'prop-types';
|
2017-11-15 00:53:19 +01:00
|
|
|
import * as actions from '../actions/index.js';
|
2017-11-15 00:46:02 +01:00
|
|
|
import { connect } from 'react-redux';
|
2017-11-15 15:13:49 +01:00
|
|
|
import Menu from '../components/Menu.js';
|
|
|
|
import SubMenu from '../components/SubMenu.js';
|
|
|
|
import MenuItem from '../components/MenuItem.js';
|
|
|
|
import * as contextTools from '../constants/contextTools.js';
|
|
|
|
import * as d2Tools from '../constants/d2Tools.js';
|
2017-11-15 00:46:02 +01:00
|
|
|
import { createSelector } from 'reselect';
|
2017-11-17 20:46:54 +01:00
|
|
|
import injectSheet from 'react-jss';
|
2017-11-23 10:51:52 +01:00
|
|
|
// TODO move this to jss instead of css
|
|
|
|
import '../../styles/styles.css';
|
2017-11-15 00:46:02 +01:00
|
|
|
// import createDebug from 'debug';
|
|
|
|
// const debug = createDebug('d3d:sketchertoolbars');
|
|
|
|
|
|
|
|
const TOOLBAR2D = 'toolbar2d';
|
|
|
|
const TOOLBAR3D = 'toolbar3d';
|
|
|
|
const CONTEXT = 'context';
|
|
|
|
|
2017-11-17 20:46:54 +01:00
|
|
|
const styles = {
|
|
|
|
contextMenuContainer: {
|
|
|
|
position: 'absolute',
|
|
|
|
left: 0,
|
|
|
|
bottom: 0,
|
|
|
|
right: 0,
|
|
|
|
top: 0,
|
|
|
|
display: 'flex',
|
|
|
|
justifyContent: 'center',
|
|
|
|
alignItems: 'center',
|
|
|
|
pointerEvents: 'none', /* enable clicking through object */
|
|
|
|
'& *': {
|
|
|
|
pointerEvents: 'visible' /* enable clicking in children */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-15 00:46:02 +01:00
|
|
|
class SketcherToolbars extends React.Component {
|
|
|
|
|
|
|
|
static propTypes = {
|
|
|
|
dispatch: PropTypes.func.isRequired,
|
|
|
|
toolbar2d: PropTypes.object, // TODO: specify further
|
|
|
|
toolbar3d: PropTypes.object, // TODO: specify further
|
|
|
|
context: PropTypes.object // TODO: specify further
|
|
|
|
};
|
|
|
|
onSelect2D = ({ value }) => {
|
|
|
|
const { dispatch } = this.props;
|
|
|
|
dispatch(actions.d2ChangeTool(value));
|
|
|
|
};
|
|
|
|
onSelect3D = ({ value }) => {
|
|
|
|
this.props.dispatch(actions.d3ChangeTool(value));
|
|
|
|
};
|
|
|
|
onSelectContext = ({ value }) => {
|
|
|
|
switch (value) {
|
|
|
|
case contextTools.DUPLICATE:
|
|
|
|
this.props.dispatch(actions.duplicateSelection(value));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case contextTools.DELETE:
|
|
|
|
this.props.dispatch(actions.deleteSelection(value));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case contextTools.UNION:
|
|
|
|
this.props.dispatch(actions.union(value));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case contextTools.INTERSECT:
|
|
|
|
this.props.dispatch(actions.intersect(value));
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
const { dispatch } = this.props;
|
|
|
|
dispatch(actions.contextChangeTool(value));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
onOpen = ({ menuValue }) => {
|
|
|
|
this.props.dispatch(actions.menuOpen(menuValue));
|
|
|
|
};
|
|
|
|
onClose = ({ menuValue }) => {
|
|
|
|
this.props.dispatch(actions.menuClose(menuValue));
|
|
|
|
};
|
|
|
|
renderToolbar = (value, onSelect, data) => {
|
|
|
|
return (
|
|
|
|
<div id={`${value}-container`}>
|
|
|
|
<Menu
|
|
|
|
id={value}
|
|
|
|
value={value}
|
|
|
|
className="toolbar"
|
|
|
|
onSelect={onSelect}
|
|
|
|
onOpen={this.onOpen}
|
|
|
|
onClose={this.onClose}
|
|
|
|
selectedValue={data.selected}
|
|
|
|
>
|
|
|
|
{renderChildren(data.children)}
|
|
|
|
</Menu>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
render() {
|
2017-11-17 20:46:54 +01:00
|
|
|
const { toolbar2d, toolbar3d, context, classes } = this.props;
|
2017-11-15 00:46:02 +01:00
|
|
|
|
|
|
|
return (
|
|
|
|
<div>
|
|
|
|
<div id="sketcher-toolbars">
|
|
|
|
{this.renderToolbar(TOOLBAR2D, this.onSelect2D, toolbar2d)}
|
|
|
|
{this.renderToolbar(TOOLBAR3D, this.onSelect3D, toolbar3d)}
|
|
|
|
</div>
|
2017-11-17 20:46:54 +01:00
|
|
|
{context.children.length > 0 && <div className={classes.contextMenuContainer}>
|
2017-11-15 00:46:02 +01:00
|
|
|
{this.renderToolbar(CONTEXT, this.onSelectContext, context)}
|
|
|
|
</div>}
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function renderChildren(children) {
|
|
|
|
const components = [];
|
|
|
|
|
|
|
|
for (const child of children) {
|
|
|
|
let component;
|
|
|
|
if (child.children.length > 0) {
|
|
|
|
component = (
|
|
|
|
<SubMenu
|
|
|
|
id={child.value}
|
|
|
|
value={child.value}
|
|
|
|
key={child.value}
|
|
|
|
selectedValue={child.selected}
|
|
|
|
open={child.open}
|
|
|
|
svg={child.svg}
|
|
|
|
selectOnOpen={child.selectOnOpen}
|
|
|
|
toggleBehavior={child.toggleBehavior}
|
|
|
|
>
|
|
|
|
{renderChildren(child.children)}
|
|
|
|
</SubMenu>
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
component = (
|
|
|
|
<MenuItem
|
|
|
|
id={child.value}
|
|
|
|
value={child.value}
|
|
|
|
key={child.value}
|
|
|
|
svg={child.svg}
|
|
|
|
disabled={child.disabled}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
components.push(component);
|
|
|
|
}
|
|
|
|
return components;
|
|
|
|
}
|
|
|
|
|
2017-11-22 14:01:08 +01:00
|
|
|
function filterMenus(activeTool, numSelectedObjects, numFilledObjects, numSolidObjects, menus) {
|
|
|
|
const showUnion = activeTool === d2Tools.TRANSFORM && numFilledObjects && numSelectedObjects >= 2;
|
2017-11-15 00:46:02 +01:00
|
|
|
const showIntersect = activeTool === d2Tools.TRANSFORM && numSelectedObjects >= 1;
|
|
|
|
return {
|
|
|
|
...menus,
|
|
|
|
children: menus.children.filter(({ value }) => {
|
|
|
|
switch (value) {
|
|
|
|
case contextTools.ADVANCED:
|
|
|
|
return showUnion || showIntersect;
|
|
|
|
|
|
|
|
case contextTools.UNION:
|
|
|
|
return showUnion;
|
|
|
|
|
|
|
|
case contextTools.INTERSECT:
|
|
|
|
return showIntersect;
|
|
|
|
|
|
|
|
case contextTools.DUPLICATE:
|
|
|
|
case contextTools.DELETE:
|
|
|
|
return numSelectedObjects > 0;
|
|
|
|
|
2017-11-22 14:01:08 +01:00
|
|
|
case contextTools.FILL_TOGGLE:
|
|
|
|
return numSelectedObjects > 0 && numSolidObjects === numSelectedObjects;
|
|
|
|
|
2017-11-15 00:46:02 +01:00
|
|
|
case contextTools.ALIGN:
|
|
|
|
return numSelectedObjects > 1;
|
|
|
|
|
|
|
|
case contextTools.COLOR_PICKER:
|
|
|
|
if (activeTool === d2Tools.ERASER) return false;
|
|
|
|
if (activeTool === d2Tools.TRANSFORM && numSelectedObjects === 0) return false;
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case contextTools.ERASER_SIZE:
|
|
|
|
return activeTool === d2Tools.ERASER;
|
|
|
|
|
|
|
|
case contextTools.BRUSH_SIZE:
|
|
|
|
return activeTool === d2Tools.BRUSH;
|
|
|
|
|
2017-11-22 14:01:08 +01:00
|
|
|
case contextTools.HOLE_TOGGLE:
|
|
|
|
return numSelectedObjects > 0 && numFilledObjects === numSelectedObjects;
|
|
|
|
|
2017-11-15 00:46:02 +01:00
|
|
|
default:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}).map(child => {
|
2017-11-22 14:01:08 +01:00
|
|
|
return filterMenus(activeTool, numSelectedObjects, numFilledObjects, numSolidObjects, child);
|
2017-11-15 00:46:02 +01:00
|
|
|
})
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function nestChildren(menus, target) {
|
|
|
|
// const targetStr = JSON.stringify(target);
|
|
|
|
const children = target.children.map(value => nestChildren(menus, menus[value]));
|
|
|
|
const { selected } = target;
|
|
|
|
return {
|
|
|
|
svg: selected && children.find(({ value }) => value === selected).svg,
|
|
|
|
...target,
|
|
|
|
selected,
|
|
|
|
children: children.filter(({ hide }) => !hide)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
const getMenus = createSelector([
|
|
|
|
state => state.sketcher.present.menus,
|
2017-11-22 14:01:08 +01:00
|
|
|
state => state.sketcher.present.d2.tool,
|
2017-11-15 00:46:02 +01:00
|
|
|
state => state.sketcher.present.selection.objects.length,
|
2017-11-22 14:01:08 +01:00
|
|
|
state => state.sketcher.present.selection.objects.filter(({ id }) => state.sketcher.present.objectsById[id].fill).length,
|
|
|
|
state => state.sketcher.present.selection.objects.filter(({ id }) => state.sketcher.present.objectsById[id].solid).length
|
|
|
|
], (menus, activeTool, numSelectedObjects, numFilledObjects, numSolidObjects) => ({
|
|
|
|
toolbar2d: filterMenus(activeTool, numSelectedObjects, numFilledObjects, numSolidObjects, nestChildren(menus, menus[TOOLBAR2D])),
|
|
|
|
toolbar3d: filterMenus(activeTool, numSelectedObjects, numFilledObjects, numSolidObjects, nestChildren(menus, menus[TOOLBAR3D])),
|
|
|
|
context: filterMenus(activeTool, numSelectedObjects, numFilledObjects, numSolidObjects, nestChildren(menus, menus[CONTEXT]))
|
2017-11-15 00:46:02 +01:00
|
|
|
}));
|
|
|
|
|
2017-11-17 20:46:54 +01:00
|
|
|
export default injectSheet(styles)(connect(getMenus)(SketcherToolbars));
|