@@ -868,7 +868,7 @@ def register_nodes(self, nodes):
868868 self ._viewer .rebuild_tab_search ()
869869
870870 def create_node (self , node_type , name = None , selected = True , color = None ,
871- text_color = None , pos = None ):
871+ text_color = None , pos = None , push_undo = True ):
872872 """
873873 Create a new node in the node graph.
874874
@@ -882,9 +882,10 @@ def create_node(self, node_type, name=None, selected=True, color=None,
882882 color (tuple or str): node color ``(255, 255, 255)`` or ``"#FFFFFF"``.
883883 text_color (tuple or str): text color ``(255, 255, 255)`` or ``"#FFFFFF"``.
884884 pos (list[int, int]): initial x, y position for the node (default: ``(0, 0)``).
885+ push_undo (bool): register the command to the undo stack. (default: True)
885886
886887 Returns:
887- _NodeObject : the created instance of the node.
888+ NodeObject : the created instance of the node.
888889 """
889890 _NodeCls = self ._node_factory .create_node_instance (node_type )
890891 if _NodeCls :
@@ -923,14 +924,18 @@ def format_color(clr):
923924
924925 node .update ()
925926
926- undo_cmd = NodeAddedCmd (self , node , node .model .pos )
927- undo_cmd .setText ('create node: "{}"' .format (node .NODE_NAME ))
928- self ._undo_stack .push (undo_cmd )
927+ if push_undo :
928+ undo_cmd = NodeAddedCmd (self , node , node .model .pos )
929+ undo_cmd .setText ('create node: "{}"' .format (node .NODE_NAME ))
930+ self ._undo_stack .push (undo_cmd )
931+ else :
932+ NodeAddedCmd (self , node , node .model .pos ).redo ()
933+
929934 self .node_created .emit (node )
930935 return node
931936 raise TypeError ('\n \n >> Cannot find node:\t "{}"\n ' .format (node_type ))
932937
933- def add_node (self , node , pos = None ):
938+ def add_node (self , node , pos = None , selected = True , push_undo = True ):
934939 """
935940 Add a node into the node graph.
936941 unlike the :meth:`NodeGraph.create_node` function this will not
@@ -939,6 +944,8 @@ def add_node(self, node, pos=None):
939944 Args:
940945 node (NodeGraphQt.BaseNode): node object.
941946 pos (list[float]): node x,y position. (optional)
947+ selected (bool): node selected state. (optional)
948+ push_undo (bool): register the command to the undo stack. (default: True)
942949 """
943950 assert isinstance (node , NodeObject ), 'node must be a Node instance.'
944951
@@ -959,61 +966,124 @@ def add_node(self, node, pos=None):
959966 node .model .name = node .NODE_NAME
960967 node .update ()
961968
962- self ._undo_stack .beginMacro ('add node: "{}"' .format (node .name ()))
963- self ._undo_stack .push (NodeAddedCmd (self , node , pos ))
964- node .set_selected (True )
965- self ._undo_stack .endMacro ()
969+ if push_undo :
970+ self ._undo_stack .beginMacro ('add node: "{}"' .format (node .name ()))
971+ self ._undo_stack .push (NodeAddedCmd (self , node , pos ))
972+ if selected :
973+ node .set_selected (True )
974+ self ._undo_stack .endMacro ()
975+ else :
976+ NodeAddedCmd (self , node , pos ).redo ()
966977
967- def delete_node (self , node ):
978+ def delete_node (self , node , push_undo = True ):
968979 """
969980 Remove the node from the node graph.
970981
971982 Args:
972983 node (NodeGraphQt.BaseNode): node object.
984+ push_undo (bool): register the command to the undo stack. (default: True)
973985 """
974986 assert isinstance (node , NodeObject ), \
975987 'node must be a instance of a NodeObject.'
976988 node_id = node .id
977- self ._undo_stack .beginMacro ('delete node: "{}"' .format (node .name ()))
989+ if push_undo :
990+ self ._undo_stack .beginMacro ('delete node: "{}"' .format (node .name ()))
991+
978992 if isinstance (node , BaseNode ):
979993 for p in node .input_ports ():
980994 if p .locked ():
981- p .set_locked (False , connected_ports = False )
995+ p .set_locked (False ,
996+ connected_ports = False ,
997+ push_undo = push_undo )
982998 p .clear_connections ()
983999 for p in node .output_ports ():
9841000 if p .locked ():
985- p .set_locked (False , connected_ports = False )
1001+ p .set_locked (False ,
1002+ connected_ports = False ,
1003+ push_undo = push_undo )
9861004 p .clear_connections ()
987- self ._undo_stack .push (NodeRemovedCmd (self , node ))
988- self ._undo_stack .endMacro ()
1005+
1006+ if push_undo :
1007+ self ._undo_stack .push (NodeRemovedCmd (self , node ))
1008+ self ._undo_stack .endMacro ()
1009+ else :
1010+ NodeRemovedCmd (self , node ).redo ()
1011+
9891012 self .nodes_deleted .emit ([node_id ])
9901013
991- def delete_nodes (self , nodes ):
1014+ def remove_node (self , node , push_undo = True ):
1015+ """
1016+ Remove the node from the node graph.
1017+
1018+ unlike the :meth:`NodeGraph.delete_node` function this will not
1019+ trigger the :attr:`NodeGraph.nodes_deleted` signal.
1020+
1021+ Args:
1022+ node (NodeGraphQt.BaseNode): node object.
1023+ push_undo (bool): register the command to the undo stack. (default: True)
1024+
1025+ """
1026+ assert isinstance (node , NodeObject ), 'node must be a Node instance.'
1027+
1028+ if push_undo :
1029+ self ._undo_stack .beginMacro ('delete node: "{}"' .format (node .name ()))
1030+
1031+ if isinstance (node , BaseNode ):
1032+ for p in node .input_ports ():
1033+ if p .locked ():
1034+ p .set_locked (False ,
1035+ connected_ports = False ,
1036+ push_undo = push_undo )
1037+ p .clear_connections ()
1038+ for p in node .output_ports ():
1039+ if p .locked ():
1040+ p .set_locked (False ,
1041+ connected_ports = False ,
1042+ push_undo = push_undo )
1043+ p .clear_connections ()
1044+
1045+ if push_undo :
1046+ self ._undo_stack .push (NodeRemovedCmd (self , node ))
1047+ self ._undo_stack .endMacro ()
1048+ else :
1049+ NodeRemovedCmd (self , node ).redo ()
1050+
1051+ def delete_nodes (self , nodes , push_undo = True ):
9921052 """
9931053 Remove a list of specified nodes from the node graph.
9941054
9951055 Args:
9961056 nodes (list[NodeGraphQt.BaseNode]): list of node instances.
1057+ push_undo (bool): register the command to the undo stack. (default: True)
9971058 """
9981059 if not nodes :
9991060 return
10001061 if len (nodes ) == 1 :
1001- self .delete_node (nodes [0 ])
1062+ self .delete_node (nodes [0 ], push_undo = push_undo )
10021063 return
10031064 node_ids = [n .id for n in nodes ]
1004- self ._undo_stack .beginMacro ('deleted "{}" nodes' .format (len (nodes )))
1065+ if push_undo :
1066+ self ._undo_stack .beginMacro ('deleted "{}" nodes' .format (len (nodes )))
10051067 for node in nodes :
10061068 if isinstance (node , BaseNode ):
10071069 for p in node .input_ports ():
10081070 if p .locked ():
1009- p .set_locked (False , connected_ports = False )
1010- p .clear_connections ()
1071+ p .set_locked (False ,
1072+ connected_ports = False ,
1073+ push_undo = push_undo )
1074+ p .clear_connections (push_undo = push_undo )
10111075 for p in node .output_ports ():
10121076 if p .locked ():
1013- p .set_locked (False , connected_ports = False )
1014- p .clear_connections ()
1015- self ._undo_stack .push (NodeRemovedCmd (self , node ))
1016- self ._undo_stack .endMacro ()
1077+ p .set_locked (False ,
1078+ connected_ports = False ,
1079+ push_undo = push_undo )
1080+ p .clear_connections (push_undo = push_undo )
1081+ if push_undo :
1082+ self ._undo_stack .push (NodeRemovedCmd (self , node ))
1083+ else :
1084+ NodeRemovedCmd (self , node ).redo ()
1085+ if push_undo :
1086+ self ._undo_stack .endMacro ()
10171087 self .nodes_deleted .emit (node_ids )
10181088
10191089 def all_nodes (self ):
@@ -1860,7 +1930,8 @@ def _register_builtin_nodes(self):
18601930
18611931 def _build_port_nodes (self ):
18621932 """
1863- Build the corresponding input & output nodes from the parent node ports.
1933+ Build the corresponding input & output nodes from the parent node ports
1934+ and remove any port nodes that are outdated..
18641935
18651936 Returns:
18661937 tuple(dict, dict): input nodes, output nodes.
@@ -1874,8 +1945,8 @@ def _build_port_nodes(self):
18741945 input_node .NODE_NAME = port .name ()
18751946 input_node .model .set_property ('name' , port .name ())
18761947 input_node .add_output (port .name ())
1877- self .add_node (input_node )
18781948 input_nodes [port .name ()] = input_node
1949+ self .add_node (input_node , selected = False , push_undo = False )
18791950
18801951 # build the parent output port nodes.
18811952 output_nodes = {n .name (): n for n in
@@ -1886,8 +1957,8 @@ def _build_port_nodes(self):
18861957 output_port .NODE_NAME = port .name ()
18871958 output_port .model .set_property ('name' , port .name ())
18881959 output_port .add_input (port .name ())
1889- self .add_node (output_port )
18901960 output_nodes [port .name ()] = output_port
1961+ self .add_node (output_port , selected = False , push_undo = False )
18911962
18921963 return input_nodes , output_nodes
18931964
@@ -2025,7 +2096,7 @@ def initialized_graphs(self):
20252096 Returns a list of the sub graphs in the order they were initialized.
20262097
20272098 Returns:
2028- list[SubGraph]: list of sub graph objects.
2099+ list[NodeGraphQt. SubGraph]: list of sub graph objects.
20292100 """
20302101 if self ._parent_graph .is_root :
20312102 return self ._initialized_graphs
@@ -2101,6 +2172,17 @@ def node(self):
21012172 """
21022173 return self ._node
21032174
2175+ def delete_node (self , node , push_undo = True ):
2176+ port_nodes = self .get_input_port_nodes () + self .get_output_port_nodes ()
2177+ if node in port_nodes and node .parent_port is not None :
2178+ # note: port nodes can only be deleted by deleting the parent
2179+ # port object.
2180+ raise RuntimeError (
2181+ 'Can\' t delete node "{}" it is attached to port "{}"'
2182+ .format (node , node .parent_port )
2183+ )
2184+ super (SubGraph , self ).delete_node (node , push_undo = push_undo )
2185+
21042186 def collapse_graph (self , clear_session = True ):
21052187 """
21062188 Collapse the current sub graph and hide its widget.
@@ -2203,3 +2285,51 @@ def collapse_group_node(self, node):
22032285
22042286 sub_graph .collapse_graph (clear_session = True )
22052287 self .widget .remove_viewer (sub_graph .subviewer_widget )
2288+
2289+ def get_input_port_nodes (self ):
2290+ """
2291+ Return all the port nodes related to the group node input ports.
2292+
2293+ .. image:: _images/port_in_node.png
2294+ :width: 150px
2295+
2296+ See Also:
2297+ :meth:`NodeGraph.get_nodes_by_type`,
2298+ :meth:`SubGraph.get_output_port_nodes`
2299+
2300+ Returns:
2301+ list[NodeGraphQt.PortInputNode]: input nodes.
2302+ """
2303+ return self .get_nodes_by_type (PortInputNode .type_ )
2304+
2305+ def get_output_port_nodes (self ):
2306+ """
2307+ Return all the port nodes related to the group node output ports.
2308+
2309+ .. image:: _images/port_out_node.png
2310+ :width: 150px
2311+
2312+ See Also:
2313+ :meth:`NodeGraph.get_nodes_by_type`,
2314+ :meth:`SubGraph.get_input_port_nodes`
2315+
2316+ Returns:
2317+ list[NodeGraphQt.PortOutputNode]: output nodes.
2318+ """
2319+ return self .get_nodes_by_type (PortOutputNode .type_ )
2320+
2321+ def get_node_by_port (self , port ):
2322+ """
2323+ Returns the node related to the parent group node port object.
2324+
2325+ Args:
2326+ port (NodeGraphQt.Port): parent node port object.
2327+
2328+ Returns:
2329+ PortInputNode or PortOutputNode: port node object.
2330+ """
2331+ func_type = {IN_PORT : self .get_input_port_nodes ,
2332+ OUT_PORT : self .get_output_port_nodes }
2333+ for n in func_type .get (port .type_ (), []):
2334+ if port == n .parent_port :
2335+ return n
0 commit comments