@@ -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 """
0 commit comments