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

Can add members and minor fixes

parent c281d62c
......@@ -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 = [
{
selector: 'node.gme-node[hasChildren]',
......@@ -39,13 +49,13 @@ const DEFAULT_STYLES = [
selector: 'edge.pointer',
style: {
content: 'data(label)',
color: 'rgb(0,0,255)',
'font-size': 10,
color: COLORS.EDGE_LABEL,
'font-size': 7,
width: 1,
'line-color': 'rgb(0,0,255)',
'line-color': COLORS.POINTER,
'curve-style': 'bezier',
'target-arrow-color': 'rgb(0,0,255)',
'target-arrow-color': COLORS.POINTER,
'target-arrow-shape': 'vee',
},
},
......@@ -53,13 +63,13 @@ const DEFAULT_STYLES = [
selector: 'edge.set-member',
style: {
content: 'data(label)',
color: 'rgb(255,0,255)',
'font-size': 10,
color: COLORS.EDGE_LABEL,
'font-size': 7,
width: 1,
'curve-style': 'bezier',
'line-color': 'rgb(255,0,255)',
'target-arrow-color': 'rgb(255,0,255)',
'line-color': COLORS.SET,
'target-arrow-color': COLORS.SET,
'target-arrow-shape': 'vee',
},
},
......@@ -67,10 +77,10 @@ const DEFAULT_STYLES = [
selector: 'edge.base-pointer',
style: {
width: 1,
'line-color': 'rgb(255,0,0)',
'line-color': COLORS.BASE_POINTER,
'curve-style': 'bezier',
'target-arrow-fill': 'hollow',
'target-arrow-color': 'rgb(255,0,0)',
'target-arrow-color': COLORS.BASE_POINTER,
'target-arrow-shape': 'triangle',
},
},
......@@ -80,34 +90,49 @@ const DEFAULT_STYLES = [
// 'border-width': '2px',
'border-style': 'solid',
'border-opacity': '1',
'border-color': 'rgba(82, 168, 236, 0.6)',
'border-color': COLORS.SELECTED,
},
},
{
selector: 'node[^hasChildren].in-active-selection',
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',
style: {
'background-color': 'rgba(185, 236, 185, 0.64)',
'background-color': COLORS.VALID_TARGET,
},
},
{
selector: 'node.invalid-action-target',
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: {
width: 5,
'line-color': 'rgba(82, 168, 236, 0.6)',
width: 4,
'line-color': COLORS.VALID_TARGET,
},
},
{
selector: 'edge.invalid-action-target',
style: {
width: 4,
'line-color': COLORS.INVALID_TARGET,
},
},
];
export default DEFAULT_STYLES;
......@@ -119,6 +119,7 @@ export default class GraphEditor extends Component {
state = {
showNodeMenu: null,
// newChildMenuParent: null,
activeFilters: (() => {
const {validFilters} = this.props;
const res = {};
......@@ -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) => {
this.setState({
showNodeMenu: false,
showNodeMenu: null,
creatingNew: {
type: 'connection',
nodeId,
......@@ -437,6 +451,14 @@ ${activeSelection.includes(edgeId) ? ' in-active-selection' : ''}`,
});
};
// showNewChildMenu = (nodeId) => {
// this.setState({
// showNodeMenu: null,
// newChildMenuParent: nodeId,
// creatingNew: null,
// });
// };
atLayoutStop = () => {
this.storePositions(this.cy.nodes('.gme-node')
.map(ele => ({
......@@ -446,6 +468,102 @@ ${activeSelection.includes(edgeId) ? ' in-active-selection' : ''}`,
};
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}) => {
const {setActiveSelection} = this.props;
if (typeof target.id === 'function' && target.hasClass('aux-node') === false) {
......@@ -472,93 +590,30 @@ ${activeSelection.includes(edgeId) ? ' in-active-selection' : ''}`,
}
});
this.cy.on('vclick', 'node', (e) => {
const {setActiveSelection, gmeClient} = this.props;
const {creatingNew} = this.state;
// This is async :+1:
this.setState({creatingNew: null});
this.cy.on('vclick', (e) => {
const {setActiveSelection} = this.props;
if (typeof e.target.id === 'function') {
const nodeId = e.target.id();
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) {
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,
},
},
});
if (e.target === this.cy) {
console.log('Canvas was clicked!');
setActiveSelection([]);
} else if (e.target.hasClass('gme-node') || e.target.hasClass('gme-connection')) {
onClickNodeOrConnection(e.target.id(), e.originalEvent);
} else if (e.target.hasClass('pointer') || e.target.hasClass('set-member')) {
setTimeout(() => {
setActiveSelection([e.target.id()]);
});
}
setActiveSelection([]);
} else {
setActiveSelection([]);
}
});
this.cy.on('mouseover', 'node', (e) => {
const {creatingNew} = this.state;
const {gmeClient} = this.props;
const nodeId = e.target.id();
const gmeNode = gmeClient.getNode(nodeId);
if (!gmeNode) {
return;
}
this.setState({creatingNew: null});
});
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.isValidMemberOf(creatingNew.nodeId, creatingNew.id);
} else if (creatingNew.type === 'connection') {
isValid = gmeNode.isValidTargetOf(creatingNew.id, 'dst');
}
this.cy.on('mouseover', 'node.gme-node', (e) => {
onMouseOverNodeOrConnection(e.target.id());
});
this.setState({
creatingNew: {
type: creatingNew.type,
id: creatingNew.id, // connection meta-id, ptr-name or set-name.
nodeId: creatingNew.nodeId,
target: nodeId,
isValid,
},
});
}
this.cy.on('mouseover', 'edge.gme-connection', (e) => {
onMouseOverNodeOrConnection(e.target.id());
});
}
......@@ -641,15 +696,15 @@ ${activeSelection.includes(edgeId) ? ' in-active-selection' : ''}`,
<FullscreenIcon/>
</Button>
</Tooltip>
<Tooltip id="tooltip-show-filters" title="Manage filters">
<Button
onClick={() => {
this.setState({showFilterSelector: true});
}}
>
<FilterIcon/>
</Button>
</Tooltip>
{/*<Tooltip id="tooltip-show-filters" title="Manage filters">*/}
{/*<Button*/}
{/*onClick={() => {*/}
{/*this.setState({showFilterSelector: true});*/}
{/*}}*/}
{/*>*/}
{/*<FilterIcon/>*/}
{/*</Button>*/}
{/*</Tooltip>*/}
</span>
</div>
<ReactCytoscape
......@@ -680,16 +735,18 @@ ${activeSelection.includes(edgeId) ? ' in-active-selection' : ''}`,
}}
onSetPointerTarget={this.startNewPointer}
onCreateConnection={this.startNewConnection}
onAddSetMember={this.startNewSetMember}
// onAddChild={this.showNewChildMenu}
onSetActiveNode={setActiveNode}
/>) : null}
<FilterSelector
open={showFilterSelector}
validItems={validFilters}
activeItems={activeFilters}
handleToggle={this.toggleFilter}
onClose={(() => this.setState({showFilterSelector: false}))}
/>
{/*<FilterSelector*/}
{/*open={showFilterSelector}*/}
{/*validItems={validFilters}*/}
{/*activeItems={activeFilters}*/}
{/*handleToggle={this.toggleFilter}*/}
{/*onClose={(() => this.setState({showFilterSelector: false}))}*/}
{/*/>*/}
</div>);
}
}
......@@ -29,11 +29,11 @@ export default class SimpleActionMenu extends Component {
onClose: PropTypes.func.isRequired,
allowDeletion: PropTypes.bool,
onAddChild: PropTypes.func,
onSetActiveNode: PropTypes.func,
onSetPointerTarget: PropTypes.func,
onAddSetMember: PropTypes.func,
onCreateConnection: PropTypes.func,
onCreateChild: PropTypes.func,
};
static defaultProps = {
......@@ -43,7 +43,7 @@ export default class SimpleActionMenu extends Component {
onSetPointerTarget: noop,
onAddSetMember: noop,
onCreateConnection: noop,
onCreateChild: noop,
onAddChild: noop,
}
setActiveNode = () => {
......@@ -93,7 +93,7 @@ export default class SimpleActionMenu extends Component {
onSetPointerTarget,
onAddSetMember,
onCreateConnection,
onCreateChild,
onAddChild,
onClose,
} = this.props;
......@@ -105,7 +105,7 @@ export default class SimpleActionMenu extends Component {
if (onSetActiveNode !== noop) {
menuItems.push((
<MenuItem key="open-sub-system" onClick={this.setActiveNode}>
<MenuItem key="open-node" onClick={this.setActiveNode}>
<ListItemIcon>
<OpenIcon/>
</ListItemIcon>
......@@ -124,7 +124,7 @@ export default class SimpleActionMenu extends Component {
<PointerIcon/>
</ListItemIcon>
<ListItemText>
{`Create pointer ${name} from here ...`}
{`Set pointer ${name} from here ..`}
</ListItemText>
</MenuItem>));
});
......@@ -140,7 +140,7 @@ export default class SimpleActionMenu extends Component {
<SetIcon/>
</ListItemIcon>
<ListItemText>
{`Add new member to set ${name} ...`}
{`Add new member to set ${name} ..`}
</ListItemText>
</MenuItem>));
});
......@@ -157,12 +157,36 @@ export default class SimpleActionMenu extends Component {
<ConnectionIcon/>
</ListItemIcon>
<ListItemText>
{`Create connection ${info.name} from here...`}
{`Start new connection ${info.name} from here ..`}
</ListItemText>
</MenuItem>));
});
}
if (onAddChild !== noop && isReadOnly === false) {
menuItems.push((
<MenuItem key="add-child" onClick={() => onAddChild(nodeId)}>
<ListItemIcon>
<NodeIcon/>
</ListItemIcon>
<ListItemText>
Add a new child node ..
</ListItemText>
</MenuItem>));
}
if (allowDeletion && isReadOnly === false) {
menuItems.push((
<MenuItem key="delete-node" onClick={this.deleteNode}>
<ListItemIcon>
<DeleteIcon/>
</ListItemIcon>
<ListItemText>
{`Delete ${nodeObj.getAttribute('name')}`}
</ListItemText>
</MenuItem>));
}
return (
<Menu
id="simple-menu"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment