Commit 994cc699 authored by Patrik Meijer's avatar Patrik Meijer
Browse files

Can add members and minor fixes

parent c281d62c
...@@ -8,6 +8,16 @@ ...@@ -8,6 +8,16 @@
* *
*/ */
const COLORS = {
EDGE_LABEL: 'rgb(86, 86, 86)',
POINTER: 'rgb(0,0,255)',
SET: 'rgb(255,0,255)',
BASE_POINTER: 'rgb(255,0,0)',
SELECTED: 'rgba(82, 168, 236, 0.6)',
VALID_TARGET: 'rgb(139, 255, 135)',
INVALID_TARGET: 'rgb(255, 135, 135)',
};
const DEFAULT_STYLES = [ const DEFAULT_STYLES = [
{ {
selector: 'node.gme-node[hasChildren]', selector: 'node.gme-node[hasChildren]',
...@@ -39,13 +49,13 @@ const DEFAULT_STYLES = [ ...@@ -39,13 +49,13 @@ const DEFAULT_STYLES = [
selector: 'edge.pointer', selector: 'edge.pointer',
style: { style: {
content: 'data(label)', content: 'data(label)',
color: 'rgb(0,0,255)', color: COLORS.EDGE_LABEL,
'font-size': 10, 'font-size': 7,
width: 1, width: 1,
'line-color': 'rgb(0,0,255)', 'line-color': COLORS.POINTER,
'curve-style': 'bezier', 'curve-style': 'bezier',
'target-arrow-color': 'rgb(0,0,255)', 'target-arrow-color': COLORS.POINTER,
'target-arrow-shape': 'vee', 'target-arrow-shape': 'vee',
}, },
}, },
...@@ -53,13 +63,13 @@ const DEFAULT_STYLES = [ ...@@ -53,13 +63,13 @@ const DEFAULT_STYLES = [
selector: 'edge.set-member', selector: 'edge.set-member',
style: { style: {
content: 'data(label)', content: 'data(label)',
color: 'rgb(255,0,255)', color: COLORS.EDGE_LABEL,
'font-size': 10, 'font-size': 7,
width: 1, width: 1,
'curve-style': 'bezier', 'curve-style': 'bezier',
'line-color': 'rgb(255,0,255)', 'line-color': COLORS.SET,
'target-arrow-color': 'rgb(255,0,255)', 'target-arrow-color': COLORS.SET,
'target-arrow-shape': 'vee', 'target-arrow-shape': 'vee',
}, },
}, },
...@@ -67,10 +77,10 @@ const DEFAULT_STYLES = [ ...@@ -67,10 +77,10 @@ const DEFAULT_STYLES = [
selector: 'edge.base-pointer', selector: 'edge.base-pointer',
style: { style: {
width: 1, width: 1,
'line-color': 'rgb(255,0,0)', 'line-color': COLORS.BASE_POINTER,
'curve-style': 'bezier', 'curve-style': 'bezier',
'target-arrow-fill': 'hollow', 'target-arrow-fill': 'hollow',
'target-arrow-color': 'rgb(255,0,0)', 'target-arrow-color': COLORS.BASE_POINTER,
'target-arrow-shape': 'triangle', 'target-arrow-shape': 'triangle',
}, },
}, },
...@@ -80,34 +90,49 @@ const DEFAULT_STYLES = [ ...@@ -80,34 +90,49 @@ const DEFAULT_STYLES = [
// 'border-width': '2px', // 'border-width': '2px',
'border-style': 'solid', 'border-style': 'solid',
'border-opacity': '1', 'border-opacity': '1',
'border-color': 'rgba(82, 168, 236, 0.6)', 'border-color': COLORS.SELECTED,
}, },
}, },
{ {
selector: 'node[^hasChildren].in-active-selection', selector: 'node[^hasChildren].in-active-selection',
style: { style: {
'background-color': 'rgba(82, 168, 236, 0.6)', 'background-color': COLORS.SELECTED,
},
},
{
selector: 'edge.in-active-selection',
style: {
width: 5,
'line-color': COLORS.SELECTED,
}, },
}, },
{ {
selector: 'node.valid-action-target', selector: 'node.valid-action-target',
style: { style: {
'background-color': 'rgba(185, 236, 185, 0.64)', 'background-color': COLORS.VALID_TARGET,
}, },
}, },
{ {
selector: 'node.invalid-action-target', selector: 'node.invalid-action-target',
style: { style: {
'background-color': 'rgba(236, 150, 185, 0.64)', 'background-color': COLORS.INVALID_TARGET,
}, },
}, },
{ {
selector: 'edge.in-active-selection', selector: 'edge.valid-action-target',
style: { style: {
width: 5, width: 4,
'line-color': 'rgba(82, 168, 236, 0.6)', 'line-color': COLORS.VALID_TARGET,
}, },
}, },
{
selector: 'edge.invalid-action-target',
style: {
width: 4,
'line-color': COLORS.INVALID_TARGET,
},
},
]; ];
export default DEFAULT_STYLES; export default DEFAULT_STYLES;
...@@ -119,6 +119,7 @@ export default class GraphEditor extends Component { ...@@ -119,6 +119,7 @@ export default class GraphEditor extends Component {
state = { state = {
showNodeMenu: null, showNodeMenu: null,
// newChildMenuParent: null,
activeFilters: (() => { activeFilters: (() => {
const {validFilters} = this.props; const {validFilters} = this.props;
const res = {}; const res = {};
...@@ -424,9 +425,22 @@ ${activeSelection.includes(edgeId) ? ' in-active-selection' : ''}`, ...@@ -424,9 +425,22 @@ ${activeSelection.includes(edgeId) ? ' in-active-selection' : ''}`,
}); });
}; };
startNewSetMember = (nodeId, setName) => {
this.setState({
showNodeMenu: null,
creatingNew: {
type: 'set',
nodeId,
id: setName,
target: null,
isValid: null,
},
});
};
startNewConnection = (nodeId, connTypeId) => { startNewConnection = (nodeId, connTypeId) => {
this.setState({ this.setState({
showNodeMenu: false, showNodeMenu: null,
creatingNew: { creatingNew: {
type: 'connection', type: 'connection',
nodeId, nodeId,
...@@ -437,6 +451,14 @@ ${activeSelection.includes(edgeId) ? ' in-active-selection' : ''}`, ...@@ -437,6 +451,14 @@ ${activeSelection.includes(edgeId) ? ' in-active-selection' : ''}`,
}); });
}; };
// showNewChildMenu = (nodeId) => {
// this.setState({
// showNodeMenu: null,
// newChildMenuParent: nodeId,
// creatingNew: null,
// });
// };
atLayoutStop = () => { atLayoutStop = () => {
this.storePositions(this.cy.nodes('.gme-node') this.storePositions(this.cy.nodes('.gme-node')
.map(ele => ({ .map(ele => ({
...@@ -446,6 +468,102 @@ ${activeSelection.includes(edgeId) ? ' in-active-selection' : ''}`, ...@@ -446,6 +468,102 @@ ${activeSelection.includes(edgeId) ? ' in-active-selection' : ''}`,
}; };
attachCytoscapeHandlers() { attachCytoscapeHandlers() {
const onMouseOverNodeOrConnection = (nodeId) => {
const {creatingNew} = this.state;
const {gmeClient} = this.props;
const gmeNode = gmeClient.getNode(nodeId);
if (!gmeNode) {
return;
}
if (creatingNew && creatingNew.target !== nodeId) {
let isValid = false;
if (creatingNew.type === 'pointer') {
isValid = gmeNode.isValidTargetOf(creatingNew.nodeId, creatingNew.id);
} else if (creatingNew.type === 'set') {
isValid = gmeNode.isValidTargetOf(creatingNew.nodeId, creatingNew.id);
} else if (creatingNew.type === 'connection') {
isValid = gmeNode.isValidTargetOf(creatingNew.id, 'dst');
if (isValid) {
// Check if the new connection can be placed inside common parent.
let parentId = gmeNode.getCommonParentId(creatingNew.nodeId);
if (parentId === creatingNew.nodeId || parentId === nodeId) {
parentId = gmeClient.getNode(parentId)
.getParentId();
}
isValid = gmeNode.isValidChildOf(parentId);
}
}
this.setState({
creatingNew: {
type: creatingNew.type,
id: creatingNew.id, // connection meta-id, ptr-name or set-name.
nodeId: creatingNew.nodeId,
target: nodeId,
isValid,
},
});
}
};
const onClickNodeOrConnection = (nodeId, orgEvent) => {
const {creatingNew} = this.state;
const {gmeClient, setActiveSelection} = this.props;
if (creatingNew && creatingNew.target === nodeId && creatingNew.isValid) {
if (creatingNew.type === 'pointer') {
gmeClient.setPointer(creatingNew.nodeId, creatingNew.id, creatingNew.target);
} else if (creatingNew.type === 'set') {
// FIXME: This uses the shuffled client arguments for addMember!
gmeClient.addMember(creatingNew.nodeId, creatingNew.target, creatingNew.id);
} else if (creatingNew.type === 'connection') {
const gmeNode = gmeClient.getNode(nodeId);
if (gmeNode) {
let parentId = gmeNode.getCommonParentId(creatingNew.nodeId);
if (parentId === creatingNew.nodeId || parentId === nodeId) {
parentId = gmeClient.getNode(parentId)
.getParentId();
}
gmeClient.startTransaction();
const connId = gmeClient.createNode({
baseId: creatingNew.id,
parentId,
});
gmeClient.setPointer(connId, 'src', creatingNew.nodeId);
gmeClient.setPointer(connId, 'dst', creatingNew.target);
gmeClient.completeTransaction();
setTimeout(() => {
setActiveSelection([connId]);
});
}
} else {
console.error('Unexpected createNew type', JSON.stringy(creatingNew));
}
} else {
this.setState({
showNodeMenu: {
id: nodeId,
position: {
x: orgEvent.clientX,
y: orgEvent.clientY,
},
},
});
setTimeout(() => {
setActiveSelection([nodeId]);
});
}
};
this.cy.on('dragfree', ({target}) => { this.cy.on('dragfree', ({target}) => {
const {setActiveSelection} = this.props; const {setActiveSelection} = this.props;
if (typeof target.id === 'function' && target.hasClass('aux-node') === false) { if (typeof target.id === 'function' && target.hasClass('aux-node') === false) {
...@@ -472,93 +590,30 @@ ${activeSelection.includes(edgeId) ? ' in-active-selection' : ''}`, ...@@ -472,93 +590,30 @@ ${activeSelection.includes(edgeId) ? ' in-active-selection' : ''}`,
} }
}); });
this.cy.on('vclick', 'node', (e) => { this.cy.on('vclick', (e) => {
const {setActiveSelection, gmeClient} = this.props; const {setActiveSelection} = this.props;
const {creatingNew} = this.state;
// This is async :+1:
this.setState({creatingNew: null});
if (typeof e.target.id === 'function') { if (e.target === this.cy) {
const nodeId = e.target.id(); console.log('Canvas was clicked!');
if (creatingNew && creatingNew.target === nodeId && creatingNew.isValid) { setActiveSelection([]);
if (creatingNew.type === 'pointer') { } else if (e.target.hasClass('gme-node') || e.target.hasClass('gme-connection')) {
gmeClient.setPointer(creatingNew.nodeId, creatingNew.id, creatingNew.target); onClickNodeOrConnection(e.target.id(), e.originalEvent);
} else if (creatingNew.type === 'set') { } else if (e.target.hasClass('pointer') || e.target.hasClass('set-member')) {
// FIXME: This uses the shuffled client arguments for addMember!
gmeClient.addMember(creatingNew.nodeId, creatingNew.target, creatingNew.id);
} else if (creatingNew.type === 'connection') {
const gmeNode = gmeClient.getNode(nodeId);
if (gmeNode) {
const commonParentId = gmeNode.getCommonParentId(creatingNew.nodeId);
gmeClient.startTransaction();
const connId = gmeClient.createNode({
baseId: creatingNew.id,
parentId: commonParentId,
});
gmeClient.setPointer(connId, 'src', creatingNew.nodeId);
gmeClient.setPointer(connId, 'dst', creatingNew.target);
gmeClient.completeTransaction();
setTimeout(() => {
setActiveSelection([connId]);
});
}
} else {
console.error('Unexpected createNew type', JSON.stringy(creatingNew));
}
} else if (e.target.hasClass('aux-node') === false) {
this.setState({
showNodeMenu: {
id: e.target.id(),
position: {
x: e.originalEvent.clientX,
y: e.originalEvent.clientY,
},
},
});
setTimeout(() => { setActiveSelection([]);
setActiveSelection([e.target.id()]);
});
}
} else { } else {
setActiveSelection([]); setActiveSelection([]);
} }
});
this.cy.on('mouseover', 'node', (e) => { this.setState({creatingNew: null});
const {creatingNew} = this.state; });
const {gmeClient} = this.props;
const nodeId = e.target.id();
const gmeNode = gmeClient.getNode(nodeId);
if (!gmeNode) {
return;
}
if (creatingNew && creatingNew.target !== nodeId) { this.cy.on('mouseover', 'node.gme-node', (e) => {
let isValid = false; onMouseOverNodeOrConnection(e.target.id());
if (creatingNew.type === 'pointer') { });
isValid = gmeNode.isValidTargetOf(creatingNew.nodeId, creatingNew.id);
} else if (creatingNew.type === 'set') {
isValid = gmeNode.isValidMemberOf(creatingNew.nodeId, creatingNew.id);
} else if (creatingNew.type === 'connection') {
isValid = gmeNode.isValidTargetOf(creatingNew.id, 'dst');
}
this.setState({ this.cy.on('mouseover', 'edge.gme-connection', (e) => {
creatingNew: { onMouseOverNodeOrConnection(e.target.id());
type: creatingNew.type,
id: creatingNew.id, // connection meta-id, ptr-name or set-name.
nodeId: creatingNew.nodeId,
target: nodeId,
isValid,
},
});
}
}); });
} }
...@@ -641,15 +696,15 @@ ${activeSelection.includes(edgeId) ? ' in-active-selection' : ''}`, ...@@ -641,15 +696,15 @@ ${activeSelection.includes(edgeId) ? ' in-active-selection' : ''}`,
<FullscreenIcon/> <FullscreenIcon/>
</Button> </Button>
</Tooltip> </Tooltip>
<Tooltip id="tooltip-show-filters" title="Manage filters"> {/*<Tooltip id="tooltip-show-filters" title="Manage filters">*/}
<Button {/*<Button*/}
onClick={() => { {/*onClick={() => {*/}
this.setState({showFilterSelector: true}); {/*this.setState({showFilterSelector: true});*/}
}} {/*}}*/}
> {/*>*/}
<FilterIcon/> {/*<FilterIcon/>*/}
</Button> {/*</Button>*/}
</Tooltip> {/*</Tooltip>*/}
</span> </span>
</div> </div>
<ReactCytoscape <ReactCytoscape
...@@ -680,16 +735,18 @@ ${activeSelection.includes(edgeId) ? ' in-active-selection' : ''}`, ...@@ -680,16 +735,18 @@ ${activeSelection.includes(edgeId) ? ' in-active-selection' : ''}`,
}} }}
onSetPointerTarget={this.startNewPointer} onSetPointerTarget={this.startNewPointer}
onCreateConnection={this.startNewConnection} onCreateConnection={this.startNewConnection}
onAddSetMember={this.startNewSetMember}
// onAddChild={this.showNewChildMenu}
onSetActiveNode={setActiveNode} onSetActiveNode={setActiveNode}
/>) : null} />) : null}
<FilterSelector {/*<FilterSelector*/}
open={showFilterSelector} {/*open={showFilterSelector}*/}
validItems={validFilters} {/*validItems={validFilters}*/}
activeItems={activeFilters} {/*activeItems={activeFilters}*/}
handleToggle={this.toggleFilter} {/*handleToggle={this.toggleFilter}*/}
onClose={(() => this.setState({showFilterSelector: false}))} {/*onClose={(() => this.setState({showFilterSelector: false}))}*/}
/> {/*/>*/}
</div>); </div>);
} }
} }
...@@ -29,11 +29,11 @@ export default class SimpleActionMenu extends Component { ...@@ -29,11 +29,11 @@ export default class SimpleActionMenu extends Component {
onClose: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired,
allowDeletion: PropTypes.bool, allowDeletion: PropTypes.bool,
onAddChild: PropTypes.func,
onSetActiveNode: PropTypes.func, onSetActiveNode: PropTypes.func,
onSetPointerTarget: PropTypes.func, onSetPointerTarget: PropTypes.func,
onAddSetMember: PropTypes.func, onAddSetMember: PropTypes.func,
onCreateConnection: PropTypes.func, onCreateConnection: PropTypes.func,
onCreateChild: PropTypes.func,
}; };
static defaultProps = { static defaultProps = {
...@@ -43,7 +43,7 @@ export default class SimpleActionMenu extends Component { ...@@ -43,7 +43,7 @@ export default class SimpleActionMenu extends Component {
onSetPointerTarget: noop, onSetPointerTarget: noop,
onAddSetMember: noop, onAddSetMember: noop,
onCreateConnection: noop, onCreateConnection: noop,
onCreateChild: noop, onAddChild: noop,
} }
setActiveNode = () => { setActiveNode = () => {
...@@ -93,7 +93,7 @@ export default class SimpleActionMenu extends Component { ...@@ -93,7 +93,7 @@ export default class SimpleActionMenu extends Component {
onSetPointerTarget, onSetPointerTarget,
onAddSetMember, onAddSetMember,
onCreateConnection, onCreateConnection,
onCreateChild, onAddChild,
onClose, onClose,
} = this.props; } = this.props;
...@@ -105,7 +105,7 @@ export default class SimpleActionMenu extends Component { ...@@ -105,7 +105,7 @@ export default class SimpleActionMenu extends Component {
if (onSetActiveNode !== noop) { if (onSetActiveNode !== noop) {
menuItems.push(( menuItems.push((
<MenuItem key="open-sub-system" onClick={this.setActiveNode}> <MenuItem key="open-node" onClick={this.setActiveNode}>
<ListItemIcon> <ListItemIcon>
<OpenIcon/> <OpenIcon/>
</ListItemIcon> </ListItemIcon>
...@@ -124,7 +124,7 @@ export default class SimpleActionMenu extends Component { ...@@ -124,7 +124,7 @@ export default class SimpleActionMenu extends Component {
<PointerIcon/> <PointerIcon/>
</ListItemIcon> </ListItemIcon>
<ListItemText> <ListItemText>
{`Create pointer ${name} from here ...`} {`Set pointer ${name} from here ..`}
</ListItemText> </ListItemText>
</MenuItem>)); </MenuItem>));
}); });
...@@ -140,7 +140,7 @@ export default class SimpleActionMenu extends Component { ...@@ -140,7 +140,7 @@ export default class SimpleActionMenu extends Component {
<SetIcon/> <SetIcon/>
</ListItemIcon> </ListItemIcon>
<ListItemText> <ListItemText>
{`Add new member to set ${name} ...`} {`Add new member to set ${name} ..`}
</ListItemText> </ListItemText>
</MenuItem>)); </MenuItem>));
}); });
...@@ -157,12 +157,36 @@ export default class SimpleActionMenu extends Component { ...@@ -157,12 +157,36 @@ export default class SimpleActionMenu extends Component {
<ConnectionIcon/>