Skip to content

Commit 47ff7f7

Browse files
authored
Merge pull request #135 from jchanvfx/port_signals_#130
Port signals #130
2 parents 5794a1c + c1f660d commit 47ff7f7

File tree

6 files changed

+163
-28
lines changed

6 files changed

+163
-28
lines changed

NodeGraphQt/base/commands.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,60 @@ def redo(self):
163163
self.node.view.delete()
164164

165165

166+
class NodeInputConnectedCmd(QtWidgets.QUndoCommand):
167+
"""
168+
"BaseNode.on_input_connected()" command.
169+
170+
Args:
171+
src_port (NodeGraphQt.Port): source port.
172+
trg_port (NodeGraphQt.Port): target port.
173+
"""
174+
175+
def __init__(self, src_port, trg_port):
176+
QtWidgets.QUndoCommand.__init__(self)
177+
if src_port.type_() == IN_PORT:
178+
self.source = src_port
179+
self.target = trg_port
180+
else:
181+
self.source = trg_port
182+
self.target = src_port
183+
184+
def undo(self):
185+
node = self.source.node()
186+
node.on_input_disconnected(self.source, self.target)
187+
188+
def redo(self):
189+
node = self.source.node()
190+
node.on_input_connected(self.source, self.target)
191+
192+
193+
class NodeInputDisconnectedCmd(QtWidgets.QUndoCommand):
194+
"""
195+
Node "on_input_disconnected()" command.
196+
197+
Args:
198+
src_port (NodeGraphQt.Port): source port.
199+
trg_port (NodeGraphQt.Port): target port.
200+
"""
201+
202+
def __init__(self, src_port, trg_port):
203+
QtWidgets.QUndoCommand.__init__(self)
204+
if src_port.type_() == IN_PORT:
205+
self.source = src_port
206+
self.target = trg_port
207+
else:
208+
self.source = trg_port
209+
self.target = src_port
210+
211+
def undo(self):
212+
node = self.source.node()
213+
node.on_input_connected(self.source, self.target)
214+
215+
def redo(self):
216+
node = self.source.node()
217+
node.on_input_disconnected(self.source, self.target)
218+
219+
166220
class PortConnectedCmd(QtWidgets.QUndoCommand):
167221
"""
168222
Port connected command.

NodeGraphQt/base/graph.py

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
from NodeGraphQt.base.port import Port
1717
from NodeGraphQt.constants import (DRAG_DROP_ID,
1818
PIPE_LAYOUT_CURVED,
19-
PIPE_LAYOUT_STRAIGHT, PIPE_LAYOUT_ANGLE)
19+
PIPE_LAYOUT_STRAIGHT,
20+
PIPE_LAYOUT_ANGLE,
21+
IN_PORT, OUT_PORT)
2022
from NodeGraphQt.widgets.viewer import NodeViewer
2123

2224

@@ -25,21 +27,21 @@ class NodeGraph(QtCore.QObject):
2527
base node graph controller.
2628
"""
2729

28-
#: (signal) emits the node object when a node is created in the node graph.
30+
#:QtCore.Signal: emits the node object when a node is created in the node graph.
2931
node_created = QtCore.Signal(NodeObject)
30-
#: (signal) emits a list of node ids from the deleted nodes.
32+
#:QtCore.Signal: emits a ``list[str]`` of node ids from the deleted nodes.
3133
nodes_deleted = QtCore.Signal(list)
32-
#: (signal) emits the node object when selected in the node graph.
34+
#:QtCore.Signal: emits the node object when selected in the node graph.
3335
node_selected = QtCore.Signal(NodeObject)
34-
#: (signal) triggered when a node is double clicked and emits the node.
36+
#:QtCore.Signal: triggered when a node is double clicked and emits the node.
3537
node_double_clicked = QtCore.Signal(NodeObject)
36-
#: (signal) for when a node has been connected emits (source port, target port).
38+
#:QtCore.Signal: for when a node has been connected emits (``input port``, ``output port``).
3739
port_connected = QtCore.Signal(Port, Port)
38-
#: (signal) for when a node has been disconnected emits (source port, target port).
40+
#:QtCore.Signal: for when a node has been disconnected emits (``input port``, ``output port``).
3941
port_disconnected = QtCore.Signal(Port, Port)
40-
#: (signal) for when a node property has changed emits (node, property name, property value).
42+
#:QtCore.Signal: for when a node property has changed emits (``node``, ``property name``, ``property value``).
4143
property_changed = QtCore.Signal(NodeObject, str, object)
42-
#: (signal) for when drop data has been added to the graph.
44+
#:QtCore.Signal: for when drop data has been added to the graph.
4345
data_dropped = QtCore.Signal(QtCore.QMimeData, QtCore.QPoint)
4446

4547
def __init__(self, parent=None):
@@ -177,7 +179,7 @@ def _on_connection_changed(self, disconnected, connected):
177179
return
178180

179181
label = 'connect node(s)' if connected else 'disconnect node(s)'
180-
ptypes = {'in': 'inputs', 'out': 'outputs'}
182+
ptypes = {IN_PORT: 'inputs', OUT_PORT: 'outputs'}
181183

182184
self._undo_stack.beginMacro(label)
183185
for p1_view, p2_view in disconnected:
@@ -204,7 +206,7 @@ def _on_connection_sliced(self, ports):
204206
"""
205207
if not ports:
206208
return
207-
ptypes = {'in': 'inputs', 'out': 'outputs'}
209+
ptypes = {IN_PORT: 'inputs', OUT_PORT: 'outputs'}
208210
self._undo_stack.beginMacro('slice connections')
209211
for p1_view, p2_view in ports:
210212
node1 = self._model.nodes[p1_view.node.id]
@@ -242,14 +244,14 @@ def widget(self):
242244
def show(self):
243245
"""
244246
Show node graph widget this is just a convenience
245-
function to :meth:`NodeGraphQt.NodeGraph.widget.show()`.
247+
function to :meth:`NodeGraph.widget().show()`.
246248
"""
247249
self._widget.show()
248250

249251
def close(self):
250252
"""
251253
Close node graph NodeViewer widget this is just a convenience
252-
function to :meth:`NodeGraphQt.NodeGraph.widget.close()`.
254+
function to :meth:`NodeGraph.widget().close()`.
253255
"""
254256
self._widget.close()
255257

@@ -356,7 +358,7 @@ def clear_undo_stack(self):
356358
357359
Note:
358360
Convenience function to
359-
:meth:`NodeGraphQt.NodeGraph.undo_stack().clear`
361+
:meth:`NodeGraph.undo_stack().clear()`
360362
361363
See Also:
362364
:meth:`NodeGraph.begin_undo()`,
@@ -772,14 +774,16 @@ def _serialize(self, nodes):
772774
for pname, conn_data in inputs.items():
773775
for conn_id, prt_names in conn_data.items():
774776
for conn_prt in prt_names:
775-
pipe = {'in': [n_id, pname], 'out': [conn_id, conn_prt]}
777+
pipe = {IN_PORT: [n_id, pname],
778+
OUT_PORT: [conn_id, conn_prt]}
776779
if pipe not in serial_data['connections']:
777780
serial_data['connections'].append(pipe)
778781

779782
for pname, conn_data in outputs.items():
780783
for conn_id, prt_names in conn_data.items():
781784
for conn_prt in prt_names:
782-
pipe = {'out': [n_id, pname], 'in': [conn_id, conn_prt]}
785+
pipe = {OUT_PORT: [n_id, pname],
786+
IN_PORT: [conn_id, conn_prt]}
783787
if pipe not in serial_data['connections']:
784788
serial_data['connections'].append(pipe)
785789

NodeGraphQt/base/node.py

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,14 @@ class NodeObject(object):
3333
qgraphics_item (AbstractNodeItem): graphic item used for drawing.
3434
"""
3535

36-
#: (str) unique node identifier domain.
36+
#:str: unique node identifier domain.
3737
__identifier__ = 'nodeGraphQt.nodes'
3838

39-
#: (str) base node name.
39+
#:str: base node name.
4040
NODE_NAME = None
4141

4242
def __init__(self, qgraphics_item=None):
43-
assert qgraphics_item, 'qgraphics item cannot be None.'
43+
assert qgraphics_item, 'qgraphics_item item cannot be None.'
4444
self._graph = None
4545
self._model = NodeModel()
4646
self._model.type_ = self.type_
@@ -261,7 +261,7 @@ def get_property(self, name):
261261
object: property data.
262262
"""
263263
if self.graph and name == 'selected':
264-
self.model.set_property(self.view.selected)
264+
self.model.set_property(name, self.view.selected)
265265

266266
return self.model.get_property(name)
267267

@@ -602,6 +602,65 @@ def set_output(self, index, port):
602602
src_port = self.output(index)
603603
src_port.connect_to(port)
604604

605+
def connected_input_nodes(self):
606+
"""
607+
Returns all nodes connected from the input ports.
608+
609+
Returns:
610+
dict: {<input_port>: <node_list>}
611+
"""
612+
nodes = {}
613+
for p in self.input_ports():
614+
nodes[p] = [cp.node() for cp in p.connected_ports()]
615+
return nodes
616+
617+
def connected_output_nodes(self):
618+
"""
619+
Returns all nodes connected from the output ports.
620+
621+
Returns:
622+
dict: {<output_port>: <node_list>}
623+
"""
624+
nodes = {}
625+
for p in self.output_ports():
626+
nodes[p] = [cp.node() for cp in p.connected_ports()]
627+
return nodes
628+
629+
def on_input_connected(self, in_port, out_port):
630+
"""
631+
Callback triggered when a new pipe connection is made.
632+
633+
*The default of this function does nothing re-implement if you require
634+
logic to run for this event.*
635+
636+
Note:
637+
to work with undo & redo for this method re-implement
638+
:meth:`BaseNode.on_input_disconnected` with the reverse logic.
639+
640+
Args:
641+
in_port (NodeGraphQt.Port): source input port from this node.
642+
out_port (NodeGraphQt.Port): output port that connected to this node.
643+
"""
644+
return
645+
646+
def on_input_disconnected(self, in_port, out_port):
647+
"""
648+
Callback triggered when a pipe connection has been disconnected
649+
from a INPUT port.
650+
651+
*The default of this function does nothing re-implement if you require
652+
logic to run for this event.*
653+
654+
Note:
655+
to work with undo & redo for this method re-implement
656+
:meth:`BaseNode.on_input_connected` with the reverse logic.
657+
658+
Args:
659+
in_port (NodeGraphQt.Port): source input port from this node.
660+
out_port (NodeGraphQt.Port): output port that was disconnected.
661+
"""
662+
return
663+
605664

606665
class BackdropNode(NodeObject):
607666
"""

NodeGraphQt/base/port.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
#!/usr/bin/python
22
from NodeGraphQt.base.commands import (PortConnectedCmd,
33
PortDisconnectedCmd,
4-
PortVisibleCmd)
4+
PortVisibleCmd,
5+
NodeInputConnectedCmd,
6+
NodeInputDisconnectedCmd)
57
from NodeGraphQt.base.model import PortModel
68
from NodeGraphQt.constants import IN_PORT, OUT_PORT
79

@@ -66,7 +68,7 @@ def node(self):
6668
Return the parent node.
6769
6870
Returns:
69-
NodeGraphQt.NodeObject: parent node object.
71+
NodeGraphQt.BaseNode: parent node object.
7072
"""
7173
return self.model.node
7274

@@ -138,8 +140,8 @@ def connect_to(self, port=None):
138140

139141
graph = self.node().graph
140142
viewer = graph.viewer()
141-
undo_stack = graph.undo_stack()
142143

144+
undo_stack = graph.undo_stack()
143145
undo_stack.beginMacro('connect port')
144146

145147
pre_conn_port = None
@@ -149,26 +151,33 @@ def connect_to(self, port=None):
149151

150152
if not port:
151153
if pre_conn_port:
154+
undo_stack.push(NodeInputDisconnectedCmd(self, port))
152155
undo_stack.push(PortDisconnectedCmd(self, port))
153156
return
154157

155158
if graph.acyclic() and viewer.acyclic_check(self.view, port.view):
156159
if pre_conn_port:
160+
undo_stack.push(NodeInputDisconnectedCmd(self, pre_conn_port))
157161
undo_stack.push(PortDisconnectedCmd(self, pre_conn_port))
158162
return
159163

160164
trg_conn_ports = port.connected_ports()
161165
if not port.multi_connection() and trg_conn_ports:
162166
dettached_port = trg_conn_ports[0]
167+
undo_stack.push(NodeInputDisconnectedCmd(port, dettached_port))
163168
undo_stack.push(PortDisconnectedCmd(port, dettached_port))
164169
if pre_conn_port:
170+
undo_stack.push(NodeInputDisconnectedCmd(self, pre_conn_port))
165171
undo_stack.push(PortDisconnectedCmd(self, pre_conn_port))
166172

173+
undo_stack.push(NodeInputConnectedCmd(self, port))
167174
undo_stack.push(PortConnectedCmd(self, port))
175+
168176
undo_stack.endMacro()
169177

170178
# emit "port_connected" signal from the parent graph.
171-
graph.port_connected.emit(self, port)
179+
ports = {p.type_(): p for p in [self, port]}
180+
graph.port_connected.emit(ports[IN_PORT], ports[OUT_PORT])
172181

173182
def disconnect_from(self, port=None):
174183
"""
@@ -181,7 +190,11 @@ def disconnect_from(self, port=None):
181190
if not port:
182191
return
183192
graph = self.node().graph
193+
graph.undo_stack().beginMacro('disconnect port')
194+
graph.undo_stack().push(NodeInputDisconnectedCmd(self, port))
184195
graph.undo_stack().push(PortDisconnectedCmd(self, port))
196+
graph.undo_stack().endMacro()
185197

186198
# emit "port_disconnected" signal from the parent graph.
187-
graph.port_disconnected.emit(self, port)
199+
ports = {p.type_(): p for p in [self, port]}
200+
graph.port_disconnected.emit(ports[IN_PORT], ports[OUT_PORT])

NodeGraphQt/constants.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
# === PIPE ===
1010

1111
PIPE_WIDTH = 1.2
12-
PIPE_STYLE_DEFAULT = 'line'
13-
PIPE_STYLE_DASHED = 'dashed'
14-
PIPE_STYLE_DOTTED = 'dotted'
12+
PIPE_STYLE_DEFAULT = 0
13+
PIPE_STYLE_DASHED = 1
14+
PIPE_STYLE_DOTTED = 2
1515
PIPE_DEFAULT_COLOR = (175, 95, 30, 255)
1616
PIPE_DISABLED_COLOR = (190, 20, 20, 255)
1717
PIPE_ACTIVE_COLOR = (70, 255, 220, 255)

docs/_static/ngqt.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ code span.pre {
4242
color: #5cafb9;
4343
}
4444

45+
/* properties */
46+
em.property {
47+
color: #5d86c3;
48+
}
49+
4550
/* tables */
4651
table.docutils td,
4752
table.docutils th {

0 commit comments

Comments
 (0)