Skip to content

Commit 8ae2c5f

Browse files
committed
disable pipe collision #206
1 parent fafbd80 commit 8ae2c5f

File tree

4 files changed

+111
-25
lines changed

4 files changed

+111
-25
lines changed

NodeGraphQt/base/graph.py

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,8 @@ def _on_insert_node(self, pipe, node_id, prev_node_pos):
171171
return
172172
node = self.get_node_by_id(node_id)
173173

174-
# exclude the BackdropNode
175-
if isinstance(node, BackdropNode):
174+
# exclude if not a BaseNode
175+
if not isinstance(node, BaseNode):
176176
return
177177

178178
disconnected = [(pipe.input_port, pipe.output_port)]
@@ -735,6 +735,35 @@ def set_acyclic(self, mode=False):
735735
self._model.acyclic = mode
736736
self._viewer.acyclic = mode
737737

738+
def pipe_collision(self):
739+
"""
740+
Returns if pipe collision is enabled.
741+
742+
See Also:
743+
To enable/disable pipe collision
744+
:meth:`NodeGraph.set_pipe_collision_enabled`
745+
746+
Returns:
747+
bool: True if pipe collision is enabled.
748+
"""
749+
return self._model.pipe_collision
750+
751+
def set_pipe_collision(self, mode=True):
752+
"""
753+
Enable/Disable pipe collision.
754+
755+
When enabled dragging a node over a pipe will allow the node to be
756+
inserted as a new connection between the pipe.
757+
758+
See Also:
759+
:meth:`NodeGraph.pipe_collision`
760+
761+
Args:
762+
mode (bool): False to disable pipe collision.
763+
"""
764+
self._model.pipe_collision = mode
765+
self._viewer.pipe_collision = mode
766+
738767
def set_pipe_style(self, style=PIPE_LAYOUT_CURVED):
739768
"""
740769
Set node graph pipes to be drawn as straight, curved or angled.
@@ -930,6 +959,8 @@ def format_color(clr):
930959
def add_node(self, node, pos=None, unique_name=True):
931960
"""
932961
Add a node into the node graph.
962+
unlike the :meth:`NodeGraph.create_node` function this will not
963+
trigger the :attr:`NodeGraph.node_created` signal.
933964
934965
Args:
935966
node (NodeGraphQt.BaseNode): node object.
@@ -956,7 +987,11 @@ def add_node(self, node, pos=None, unique_name=True):
956987
node.model._graph_model = self.model
957988
node.model.name = node.NODE_NAME
958989
node.update()
990+
991+
self._undo_stack.beginMacro('add node: "{}"'.format(node.name()))
959992
self._undo_stack.push(NodeAddedCmd(self, node, pos))
993+
node.set_selected(True)
994+
self._undo_stack.endMacro()
960995

961996
def set_node_space(self, node):
962997
"""
@@ -1214,11 +1249,20 @@ def clear_session(self):
12141249
for n in self.all_nodes():
12151250
if n is root_node:
12161251
continue
1252+
if isinstance(n, BaseNode):
1253+
for p in n.input_ports():
1254+
if p.locked():
1255+
p.set_locked(False, connected_ports=False)
1256+
p.clear_connections()
1257+
for p in n.output_ports():
1258+
if p.locked():
1259+
p.set_locked(False, connected_ports=False)
1260+
p.clear_connections()
12171261
self._undo_stack.push(NodeRemovedCmd(self, n))
12181262
self.set_node_space(root_node)
12191263
self.clear_undo_stack()
1220-
self._model.session = None
1221-
self.session_changed.emit("")
1264+
self._model.session = ''
1265+
self.session_changed.emit('')
12221266

12231267
def _serialize(self, nodes):
12241268
"""
@@ -1231,14 +1275,21 @@ def _serialize(self, nodes):
12311275
Returns:
12321276
dict: serialized data.
12331277
"""
1234-
serial_data = {'nodes': {}, 'connections': []}
1278+
serial_data = {'graph': {}, 'nodes': {}, 'connections': []}
12351279
nodes_data = {}
1280+
1281+
# serialize graph session.
1282+
serial_data['graph']['acyclic'] = self.acyclic()
1283+
serial_data['graph']['pipe_collision'] = self.pipe_collision()
1284+
1285+
# serialize nodes.
12361286
root_node = self.root_node()
12371287
for n in nodes:
12381288
if n is root_node:
12391289
continue
12401290
# update the node model.
12411291
n.update_model()
1292+
12421293
node_dict = n.model.to_dict
12431294

12441295
if isinstance(n, SubGraph):
@@ -1253,6 +1304,7 @@ def _serialize(self, nodes):
12531304
for n_id, n_data in nodes_data.items():
12541305
serial_data['nodes'][n_id] = n_data
12551306

1307+
# serialize connections
12561308
inputs = n_data.pop('inputs') if n_data.get('inputs') else {}
12571309
outputs = n_data.pop('outputs') if n_data.get('outputs') else {}
12581310

@@ -1294,6 +1346,13 @@ def _deserialize(self, data, relative_pos=False, pos=None, set_parent=True):
12941346
if not self._editable:
12951347
return
12961348

1349+
# update node graph properties.
1350+
for attr_name, attr_value in data.get('graph', {}).items():
1351+
if attr_name == 'acyclic':
1352+
self.set_acyclic(attr_value)
1353+
elif attr_name == 'pipe_collision':
1354+
self.set_pipe_collision(attr_value)
1355+
12971356
_temp_auto_update = self._auto_update
12981357
self._auto_update = False
12991358

@@ -1452,7 +1511,6 @@ def import_session(self, file_path):
14521511
Args:
14531512
file_path (str): path to the serialized layout file.
14541513
"""
1455-
14561514
file_path = file_path.strip()
14571515
if not os.path.isfile(file_path):
14581516
raise IOError('file does not exist: {}'.format(file_path))
@@ -1746,7 +1804,7 @@ def question_dialog(self, text, title='Node Graph'):
17461804
Returns:
17471805
bool: true if user clicked yes.
17481806
"""
1749-
self._viewer.question_dialog(text, title)
1807+
return self._viewer.question_dialog(text, title)
17501808

17511809
def message_dialog(self, text, title='Node Graph'):
17521810
"""

NodeGraphQt/base/model.py

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -320,25 +320,46 @@ def serial(self):
320320

321321

322322
class NodeGraphModel(object):
323+
"""
324+
Data dump for a node graph.
325+
"""
323326

324327
def __init__(self):
328+
self.__common_node_props = {}
329+
325330
self.nodes = {}
326331
self.session = ''
327332
self.acyclic = True
328-
self.__common_node_props = {}
333+
self.pipe_collision = False
329334

330335
def common_properties(self):
336+
"""
337+
Return all common node properties.
338+
339+
Returns:
340+
dict: common node properties.
341+
eg.
342+
{'nodeGraphQt.nodes.FooNode': {
343+
'my_property': {
344+
'widget_type': 0,
345+
'tab': 'Properties',
346+
'items': ['foo', 'bar', 'test'],
347+
'range': (0, 100)
348+
}
349+
}
350+
}
351+
"""
331352
return self.__common_node_props
332353

333354
def set_node_common_properties(self, attrs):
334355
"""
335-
store common node properties.
356+
Store common node properties.
336357
337358
Args:
338359
attrs (dict): common node properties.
339360
eg.
340-
{'nodeGraphQt.nodes.FooNode': {
341-
'my_property':{
361+
{'nodeGraphQt.nodes.FooNode': {
362+
'my_property': {
342363
'widget_type': 0,
343364
'tab': 'Properties',
344365
'items': ['foo', 'bar', 'test'],
@@ -363,6 +384,8 @@ def set_node_common_properties(self, attrs):
363384

364385
def get_node_common_properties(self, node_type):
365386
"""
387+
Return all the common properties for a registered node.
388+
366389
Args:
367390
node_type (str): node type.
368391

NodeGraphQt/constants.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@
106106
VIEWER_GRID_COLOR = (45, 45, 45)
107107
VIEWER_GRID_SIZE = 50
108108

109-
URI_SCHEME = 'ngqt://'
110-
URN_SCHEME = 'ngqt::'
109+
URI_SCHEME = 'NodeGraphQt://'
110+
URN_SCHEME = 'NodeGraphQt::'
111111

112112
# === PATHS ===
113113

NodeGraphQt/widgets/viewer.py

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ def __init__(self, parent=None):
116116
self._ctx_node_menu.setDisabled(True)
117117

118118
self.acyclic = True
119+
self.pipe_collision = False
120+
119121
self.LMB_state = False
120122
self.RMB_state = False
121123
self.MMB_state = False
@@ -385,9 +387,8 @@ def mouseReleaseEvent(self, event):
385387
# emit signal if selected node collides with pipe.
386388
# Note: if collide state is true then only 1 node is selected.
387389
nodes, pipes = self.selected_items()
388-
if self.COLLIDING_state:
389-
if nodes and pipes:
390-
self.insert_node.emit(pipes[0], nodes[0].id, moved_nodes)
390+
if self.COLLIDING_state and nodes and pipes:
391+
self.insert_node.emit(pipes[0], nodes[0].id, moved_nodes)
391392

392393
# emit node selection changed signal.
393394
prev_ids = [n.id for n in self._prev_selection_nodes if not n.selected]
@@ -447,21 +448,25 @@ def mouseMoveEvent(self, event):
447448

448449
elif self.LMB_state:
449450
self.COLLIDING_state = False
450-
nodes = self.selected_nodes()
451+
nodes, pipes = self.selected_items()
451452
if len(nodes) == 1:
452453
node = nodes[0]
453-
for pipe in self.selected_pipes():
454-
pipe.setSelected(False)
455-
for item in node.collidingItems():
456-
if isinstance(item, Pipe) and item.isVisible():
457-
if not item.input_port:
454+
[p.setSelected(False) for p in pipes]
455+
456+
if self.pipe_collision:
457+
colliding_pipes = [
458+
i for i in node.collidingItems()
459+
if isinstance(i, Pipe) and i.isVisible()
460+
]
461+
for pipe in colliding_pipes:
462+
if not pipe.input_port:
458463
continue
459464
port_node_check = all([
460-
not item.input_port.node is node,
461-
not item.output_port.node is node
465+
not pipe.input_port.node is node,
466+
not pipe.output_port.node is node
462467
])
463468
if port_node_check:
464-
item.setSelected(True)
469+
pipe.setSelected(True)
465470
self.COLLIDING_state = True
466471
break
467472

0 commit comments

Comments
 (0)