Skip to content

Commit 313fe61

Browse files
committed
group node functions
1 parent 3394c75 commit 313fe61

File tree

1 file changed

+159
-29
lines changed

1 file changed

+159
-29
lines changed

NodeGraphQt/base/graph.py

Lines changed: 159 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)