Add background context menu & keyboard load-module
actions
This commit is contained in:
parent
143dcce068
commit
a6caad2489
|
@ -28,6 +28,9 @@ class GraphView extends GraphViewBase {
|
|||
}
|
||||
|
||||
Object.assign(this, {
|
||||
_super_renderBackground: this.renderBackground,
|
||||
renderBackground: this.constructor.prototype.renderBackground.bind(this),
|
||||
|
||||
_super_handleNodeMove: this.handleNodeMove,
|
||||
handleNodeMove: this.constructor.prototype.handleNodeMove.bind(this),
|
||||
|
||||
|
@ -136,6 +139,18 @@ class GraphView extends GraphViewBase {
|
|||
return super.getMouseCoordinates();
|
||||
}
|
||||
|
||||
renderBackground() {
|
||||
const { gridSize, backgroundFillId, renderBackground, onBackgroundMouseDown } = this.props;
|
||||
if (renderBackground) {
|
||||
return renderBackground({
|
||||
gridSize,
|
||||
backgroundFillId,
|
||||
onMouseDown: onBackgroundMouseDown,
|
||||
});
|
||||
}
|
||||
return this._super_renderBackground();
|
||||
}
|
||||
|
||||
getNodeComponent(id, node) {
|
||||
const { nodeTypes, nodeSubtypes, nodeSize, renderNode, renderNodeText, nodeKey } = this.props;
|
||||
return r(Node, {
|
||||
|
|
|
@ -262,6 +262,19 @@ const renderDefs = () => r(React.Fragment, [
|
|||
}),
|
||||
]);
|
||||
|
||||
const renderBackground = ({
|
||||
gridSize = 40960,
|
||||
onMouseDown,
|
||||
}) => r.rect({
|
||||
className: 'background',
|
||||
x: -(gridSize || 0) / 4,
|
||||
y: -(gridSize || 0) / 4,
|
||||
width: gridSize,
|
||||
height: gridSize,
|
||||
fill: 'url(#background-pattern)',
|
||||
onMouseDown,
|
||||
});
|
||||
|
||||
const renderNode = (nodeRef, data, key, selected, hovered) => r({
|
||||
sink: Sink,
|
||||
source: Source,
|
||||
|
@ -562,7 +575,39 @@ const renderEdgeText = state => ({ data: dgo, transform, selected }) => {
|
|||
|
||||
const layoutEngine = new LayoutEngine();
|
||||
|
||||
class GraphContextMenu extends React.PureComponent {
|
||||
class BackgroundContextMenu extends React.PureComponent {
|
||||
render() {
|
||||
return r(PopupMenu, {
|
||||
onClose: this.props.onClose,
|
||||
}, [
|
||||
r(MenuItem, {
|
||||
label: 'Create',
|
||||
}, [
|
||||
r(MenuItem, {
|
||||
label: 'Loopback',
|
||||
onClick: this.props.onLoadModuleLoopback,
|
||||
}),
|
||||
|
||||
r(MenuItem, {
|
||||
label: 'Simultaneous output',
|
||||
onClick: this.props.onLoadModuleCombineSink,
|
||||
}),
|
||||
|
||||
r(MenuItem, {
|
||||
label: 'Null output',
|
||||
onClick: this.props.onLoadModuleNullSink,
|
||||
}),
|
||||
]),
|
||||
|
||||
r(MenuItem, {
|
||||
label: 'Load a module...',
|
||||
onClick: this.props.onLoadModule,
|
||||
}),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
class GraphObjectContextMenu extends React.PureComponent {
|
||||
render() {
|
||||
return r(PopupMenu, {
|
||||
onClose: this.props.onClose,
|
||||
|
@ -575,7 +620,7 @@ class GraphContextMenu extends React.PureComponent {
|
|||
r(MenuItem.Separator),
|
||||
]),
|
||||
|
||||
r(MenuItem, {
|
||||
this.props.canDelete() && r(MenuItem, {
|
||||
label: 'Delete',
|
||||
onClick: this.props.onDelete,
|
||||
}),
|
||||
|
@ -583,6 +628,8 @@ class GraphContextMenu extends React.PureComponent {
|
|||
}
|
||||
}
|
||||
|
||||
const backgroundSymbol = Symbol('graph.backgroundSymbol');
|
||||
|
||||
class Graph extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
@ -590,11 +637,14 @@ class Graph extends React.Component {
|
|||
this.state = {
|
||||
selected: null,
|
||||
moved: null,
|
||||
contexted: null,
|
||||
};
|
||||
|
||||
this._requestedIcons = new Set();
|
||||
|
||||
Object.assign(this, {
|
||||
onBackgroundMouseDown: this.onBackgroundMouseDown.bind(this),
|
||||
|
||||
onSelectNode: this.onSelectNode.bind(this),
|
||||
onCreateNode: this.onCreateNode.bind(this),
|
||||
onUpdateNode: this.onUpdateNode.bind(this),
|
||||
|
@ -613,7 +663,12 @@ class Graph extends React.Component {
|
|||
canContextMenuSetAsDefault: this.canContextMenuSetAsDefault.bind(this),
|
||||
onContextMenuSetAsDefault: this.onContextMenuSetAsDefault.bind(this),
|
||||
|
||||
canContextMenuDelete: this.canContextMenuDelete.bind(this),
|
||||
onContextMenuDelete: this.onContextMenuDelete.bind(this),
|
||||
|
||||
onLoadModuleLoopback: this.onLoadModuleLoopback.bind(this),
|
||||
onLoadModuleCombineSink: this.onLoadModuleCombineSink.bind(this),
|
||||
onLoadModuleNullSink: this.onLoadModuleNullSink.bind(this),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -695,7 +750,7 @@ class Graph extends React.Component {
|
|||
|
||||
let { selected, moved, contexted } = state;
|
||||
|
||||
if (contexted && selected !== contexted) {
|
||||
if (contexted && contexted !== backgroundSymbol && selected !== contexted) {
|
||||
contexted = null;
|
||||
}
|
||||
|
||||
|
@ -709,7 +764,7 @@ class Graph extends React.Component {
|
|||
find(x => x.id === moved.id, edges);
|
||||
}
|
||||
|
||||
if (contexted) {
|
||||
if (contexted && contexted !== backgroundSymbol) {
|
||||
contexted = find(x => x.id === contexted.id, nodes) ||
|
||||
find(x => x.id === contexted.id, edges);
|
||||
}
|
||||
|
@ -765,6 +820,12 @@ class Graph extends React.Component {
|
|||
this._requestedIcons.add(icon);
|
||||
}
|
||||
|
||||
onBackgroundMouseDown() {
|
||||
this.setState({
|
||||
contexted: backgroundSymbol,
|
||||
});
|
||||
}
|
||||
|
||||
onSelectNode(selected) {
|
||||
this.setState({ selected });
|
||||
}
|
||||
|
@ -916,8 +977,12 @@ class Graph extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
canContextMenuDelete() {
|
||||
return this.state.contexted !== backgroundSymbol;
|
||||
}
|
||||
|
||||
onContextMenuDelete() {
|
||||
this.onDelete(this.state.selected);
|
||||
this.onDelete(this.state.contexted);
|
||||
}
|
||||
|
||||
onContextMenuClose() {
|
||||
|
@ -1214,6 +1279,22 @@ class Graph extends React.Component {
|
|||
});
|
||||
}
|
||||
|
||||
hotKeyAdd() {
|
||||
this.props.openNewGraphObjectModal();
|
||||
}
|
||||
|
||||
onLoadModuleLoopback() {
|
||||
this.props.loadModule('module-loopback', '');
|
||||
}
|
||||
|
||||
onLoadModuleCombineSink() {
|
||||
this.props.loadModule('module-combine-sink', '');
|
||||
}
|
||||
|
||||
onLoadModuleNullSink() {
|
||||
this.props.loadModule('module-null-sink', '');
|
||||
}
|
||||
|
||||
render() {
|
||||
const { nodes, edges } = this.state;
|
||||
|
||||
|
@ -1236,6 +1317,8 @@ class Graph extends React.Component {
|
|||
nodeSubtypes: {},
|
||||
edgeTypes: {},
|
||||
|
||||
onBackgroundMouseDown: this.onBackgroundMouseDown,
|
||||
|
||||
onSelectNode: this.onSelectNode,
|
||||
onCreateNode: this.onCreateNode,
|
||||
onUpdateNode: this.onUpdateNode,
|
||||
|
@ -1255,7 +1338,7 @@ class Graph extends React.Component {
|
|||
|
||||
layoutEngine,
|
||||
|
||||
backgroundFillId: '#background-pattern',
|
||||
renderBackground,
|
||||
|
||||
renderDefs,
|
||||
|
||||
|
@ -1266,14 +1349,27 @@ class Graph extends React.Component {
|
|||
renderEdgeText: renderEdgeText(this.props),
|
||||
}),
|
||||
|
||||
this.state.contexted && r(GraphContextMenu, {
|
||||
onClose: this.onContextMenuClose,
|
||||
this.state.contexted && (
|
||||
this.state.contexted === backgroundSymbol ?
|
||||
r(BackgroundContextMenu, {
|
||||
onClose: this.onContextMenuClose,
|
||||
|
||||
canSetAsDefault: this.canContextMenuSetAsDefault,
|
||||
onSetAsDefault: this.onContextMenuSetAsDefault,
|
||||
onLoadModule: this.props.openLoadModuleModal,
|
||||
|
||||
onDelete: this.onContextMenuDelete,
|
||||
}),
|
||||
onLoadModuleLoopback: this.onLoadModuleLoopback,
|
||||
onLoadModuleCombineSink: this.onLoadModuleCombineSink,
|
||||
onLoadModuleNullSink: this.onLoadModuleNullSink,
|
||||
}) :
|
||||
r(GraphObjectContextMenu, {
|
||||
onClose: this.onContextMenuClose,
|
||||
|
||||
canSetAsDefault: this.canContextMenuSetAsDefault,
|
||||
onSetAsDefault: this.onContextMenuSetAsDefault,
|
||||
|
||||
canDelete: this.canContextMenuDelete,
|
||||
onDelete: this.onContextMenuDelete,
|
||||
})
|
||||
),
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,8 @@ const keyMap = {
|
|||
hotKeyShiftMute: 'shift+space',
|
||||
|
||||
hotKeySetAsDefault: 'f',
|
||||
|
||||
hotKeyAdd: 'a',
|
||||
};
|
||||
|
||||
class MyHotKeys extends React.Component {
|
||||
|
|
|
@ -28,6 +28,8 @@ const { modules } = require('../../constants/pulse');
|
|||
|
||||
const ConnectToServerModal = require('./connect-to-server');
|
||||
const ConfirmationModal = require('./confirmation');
|
||||
const NewGraphObjectModal = require('./new-graph-object');
|
||||
const LoadModuleModal = require('./load-module');
|
||||
|
||||
Modal.setAppElement('#root');
|
||||
|
||||
|
@ -46,9 +48,14 @@ class Modals extends React.PureComponent {
|
|||
continuation: null,
|
||||
|
||||
connectToServerModalOpen: false,
|
||||
newGraphObjectModalOpen: false,
|
||||
loadModuleModalOpen: false,
|
||||
|
||||
actions: {
|
||||
openConnectToServerModal: this.openConnectToServerModal.bind(this),
|
||||
|
||||
openNewGraphObjectModal: this.openNewGraphObjectModal.bind(this),
|
||||
openLoadModuleModal: this.openLoadModuleModal.bind(this),
|
||||
},
|
||||
};
|
||||
this.state = this.initialState;
|
||||
|
@ -97,6 +104,14 @@ class Modals extends React.PureComponent {
|
|||
this.setState({ connectToServerModalOpen: true });
|
||||
}
|
||||
|
||||
openNewGraphObjectModal() {
|
||||
this.setState({ newGraphObjectModalOpen: true });
|
||||
}
|
||||
|
||||
openLoadModuleModal() {
|
||||
this.setState({ loadModuleModalOpen: true });
|
||||
}
|
||||
|
||||
handleCancel() {
|
||||
this.setState(this.initialState);
|
||||
}
|
||||
|
@ -122,6 +137,18 @@ class Modals extends React.PureComponent {
|
|||
isOpen: this.state.connectToServerModalOpen,
|
||||
onRequestClose: this.handleCancel,
|
||||
}),
|
||||
|
||||
r(NewGraphObjectModal, {
|
||||
isOpen: this.state.newGraphObjectModalOpen,
|
||||
onRequestClose: this.handleCancel,
|
||||
|
||||
openLoadModuleModal: this.state.actions.openLoadModuleModal,
|
||||
}),
|
||||
|
||||
r(LoadModuleModal, {
|
||||
isOpen: this.state.loadModuleModalOpen,
|
||||
onRequestClose: this.handleCancel,
|
||||
}),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
93
components/modals/load-module.js
Normal file
93
components/modals/load-module.js
Normal file
|
@ -0,0 +1,93 @@
|
|||
|
||||
const r = require('r-dom');
|
||||
|
||||
const React = require('react');
|
||||
|
||||
const { connect } = require('react-redux');
|
||||
const { bindActionCreators } = require('redux');
|
||||
|
||||
const Modal = require('react-modal');
|
||||
|
||||
const Button = require('../button');
|
||||
const Label = require('../label');
|
||||
const Input = require('../input');
|
||||
|
||||
const {
|
||||
pulse: pulseActions,
|
||||
} = require('../../actions');
|
||||
|
||||
class LoadModuleModal extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
name: '',
|
||||
args: '',
|
||||
};
|
||||
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
}
|
||||
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const { name, args } = this.state;
|
||||
this.props.loadModule(name, args);
|
||||
this.props.onRequestClose();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { isOpen, onRequestClose } = this.props;
|
||||
|
||||
return r(Modal, {
|
||||
isOpen,
|
||||
onRequestClose,
|
||||
}, [
|
||||
r.h3('Load a module'),
|
||||
|
||||
r.form({
|
||||
onSubmit: this.handleSubmit,
|
||||
}, [
|
||||
r(Label, [
|
||||
r.div('Module name:'),
|
||||
r.p([
|
||||
r(Input, {
|
||||
style: { width: '100%' },
|
||||
autoFocus: true,
|
||||
value: this.state.name,
|
||||
onChange: e => this.setState({ name: e.target.value }),
|
||||
}),
|
||||
]),
|
||||
]),
|
||||
|
||||
r(Label, [
|
||||
r.div('Arguments:'),
|
||||
r.p([
|
||||
r(Input, {
|
||||
style: { width: '100%' },
|
||||
value: this.state.args,
|
||||
onChange: e => this.setState({ args: e.target.value }),
|
||||
}),
|
||||
]),
|
||||
]),
|
||||
|
||||
r.div({
|
||||
className: 'button-group',
|
||||
}, [
|
||||
r(Button, {
|
||||
onClick: onRequestClose,
|
||||
}, 'Cancel'),
|
||||
|
||||
r(Button, {
|
||||
type: 'submit',
|
||||
}, 'Confirm'),
|
||||
]),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = connect(
|
||||
null,
|
||||
dispatch => bindActionCreators(pulseActions, dispatch),
|
||||
)(LoadModuleModal);
|
38
components/modals/new-graph-object.js
Normal file
38
components/modals/new-graph-object.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
|
||||
const r = require('r-dom');
|
||||
|
||||
const React = require('react');
|
||||
|
||||
const Modal = require('react-modal');
|
||||
|
||||
const Button = require('../button');
|
||||
|
||||
class NewGraphObjectModal extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
name: '',
|
||||
args: '',
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const { isOpen, onRequestClose, openLoadModuleModal } = this.props;
|
||||
|
||||
return r(Modal, {
|
||||
isOpen,
|
||||
onRequestClose,
|
||||
}, [
|
||||
r.h3('Add something'),
|
||||
|
||||
r(Button, {
|
||||
style: { width: '100%' },
|
||||
onClick: openLoadModuleModal,
|
||||
autoFocus: true,
|
||||
}, 'Load a module...'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = NewGraphObjectModal;
|
Loading…
Reference in New Issue
Block a user