Skip to content

Commit 3743938

Browse files
committed
node_selection_changed signal
1 parent b7ba289 commit 3743938

File tree

8 files changed

+68
-10
lines changed

8 files changed

+68
-10
lines changed

NodeGraphQt/base/graph.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,14 @@ class NodeGraph(QtCore.QObject):
9090
:parameters: :class:`NodeGraphQt.NodeObject`
9191
:emits: selected node
9292
"""
93+
node_selection_changed = QtCore.Signal(list, list)
94+
"""
95+
Signal triggered when the node selection has changed.
96+
97+
:parameters: list[:class:`NodeGraphQt.NodeObject`],
98+
list[:class:`NodeGraphQt.NodeObject`]
99+
:emits: previous node selection, new selection.
100+
"""
93101
node_double_clicked = QtCore.Signal(NodeObject)
94102
"""
95103
Signal triggered when a node is double clicked and emits the node.
@@ -167,6 +175,8 @@ def _wire_signals(self):
167175

168176
# pass through signals.
169177
self._viewer.node_selected.connect(self._on_node_selected)
178+
self._viewer.node_selection_changed.connect(
179+
self._on_node_selection_changed)
170180
self._viewer.data_dropped.connect(self._on_node_data_dropped)
171181

172182
def _insert_node(self, pipe, node_id, prev_node_pos):
@@ -260,6 +270,19 @@ def _on_node_selected(self, node_id):
260270
node = self.get_node_by_id(node_id)
261271
self.node_selected.emit(node)
262272

273+
def _on_node_selection_changed(self, prev_ids, node_ids):
274+
"""
275+
called when the node selection changes in the viewer.
276+
(emits node objects <un-selected nodes>, <selected nodes>)
277+
278+
Args:
279+
prev_ids (list[str]): previous selection.
280+
node_ids (list[str]): current selection.
281+
"""
282+
prev_nodes = [self.get_node_by_id(nid) for nid in prev_ids]
283+
new_nodes = [self.get_node_by_id(nid) for nid in node_ids]
284+
self.node_selection_changed.emit(prev_nodes, new_nodes)
285+
263286
def _on_node_data_dropped(self, data, pos):
264287
"""
265288
called when data has been dropped on the viewer.

NodeGraphQt/constants.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@
122122

123123
# === NODE LAYOUT DIRECTION ===
124124

125+
#: Mode for vertical node layout.
125126
NODE_LAYOUT_VERTICAL = 0
127+
#: Mode for horizontal node layout.
126128
NODE_LAYOUT_HORIZONTAL = 1
129+
#: Variable for setting the node layout direction.
127130
NODE_LAYOUT_DIRECTION = NODE_LAYOUT_HORIZONTAL

NodeGraphQt/qgraphics/node_abstract.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def __init__(self, name='node', parent=None):
2323
'type_': 'AbstractBaseNode',
2424
'selected': False,
2525
'disabled': False,
26-
'visible' : False,
26+
'visible': False,
2727
}
2828
self._width = NODE_WIDTH
2929
self._height = NODE_HEIGHT
@@ -135,7 +135,9 @@ def disabled(self, state=False):
135135

136136
@property
137137
def selected(self):
138-
return self.isSelected()
138+
if self._properties['selected'] != self.isSelected():
139+
self._properties['selected'] = self.isSelected()
140+
return self._properties['selected']
139141

140142
@selected.setter
141143
def selected(self, selected=False):

NodeGraphQt/widgets/viewer.py

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class NodeViewer(QtWidgets.QGraphicsView):
3636

3737
# pass through signals
3838
node_selected = QtCore.Signal(str)
39+
node_selection_changed = QtCore.Signal(list, list)
3940
node_double_clicked = QtCore.Signal(str)
4041
data_dropped = QtCore.Signal(QtCore.QMimeData, QtCore.QPoint)
4142

@@ -306,11 +307,25 @@ def mouseReleaseEvent(self, event):
306307
self._rubber_band.hide()
307308

308309
rect = QtCore.QRect(self._origin_pos, event.pos()).normalized()
309-
for item in self.scene().items(self.mapToScene(rect).boundingRect()):
310+
rect_items = self.scene().items(
311+
self.mapToScene(rect).boundingRect()
312+
)
313+
node_ids = []
314+
for item in rect_items:
310315
if isinstance(item, AbstractNodeItem):
311-
self.node_selected.emit(item.id)
312-
return
316+
node_ids.append(item.id)
317+
318+
# emit the node selection signals.
319+
if node_ids:
320+
prev_ids = [
321+
n.id for n in self._prev_selection_nodes
322+
if not n.selected
323+
]
324+
self.node_selected.emit(node_ids[0])
325+
self.node_selection_changed.emit(prev_ids, node_ids)
326+
313327
self.scene().update(map_rect)
328+
return
314329

315330
# find position changed nodes and emit signal.
316331
moved_nodes = {
@@ -326,11 +341,16 @@ def mouseReleaseEvent(self, event):
326341

327342
# emit signal if selected node collides with pipe.
328343
# Note: if collide state is true then only 1 node is selected.
344+
nodes, pipes = self.selected_items()
329345
if self.COLLIDING_state:
330-
nodes, pipes = self.selected_items()
331346
if nodes and pipes:
332347
self.insert_node.emit(pipes[0], nodes[0].id, moved_nodes)
333348

349+
# emit node selection changed signal.
350+
prev_ids = [n.id for n in self._prev_selection_nodes if not n.selected]
351+
node_ids = [n.id for n in nodes if n not in self._prev_selection_nodes]
352+
self.node_selection_changed.emit(prev_ids, node_ids)
353+
334354
super(NodeViewer, self).mouseReleaseEvent(event)
335355

336356
def mouseMoveEvent(self, event):
@@ -544,6 +564,7 @@ def sceneMousePressEvent(self, event):
544564
def sceneMouseReleaseEvent(self, event):
545565
"""
546566
triggered mouse release event for the scene.
567+
547568
Args:
548569
event (QtWidgets.QGraphicsSceneMouseEvent):
549570
The event handler from the QtWidgets.QGraphicsScene
@@ -556,7 +577,9 @@ def sceneMouseReleaseEvent(self, event):
556577
def apply_live_connection(self, event):
557578
"""
558579
triggered mouse press/release event for the scene.
559-
- verify to make a the connection Pipe.
580+
- verifies the live connection pipe.
581+
- makes a connection pipe if valid.
582+
- emits the "connection changed" signal.
560583
561584
Args:
562585
event (QtWidgets.QGraphicsSceneMouseEvent):

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ applications that supports PySide2.
3737
#### Properties Bin
3838
<img src="/docs/_images/prop_bin.png" width="600" title="Properties Bin">
3939

40+
#### Vertical Layout
41+
<img src="/docs/_images/vertical_layout.png" width="600" title="Vertical Layout">
42+
4043
#### Example
4144

4245
```python

docs/_images/example_subgraph.gif

-2.71 MB
Loading

docs/_images/vertical_layout.png

32.4 KB
Loading

docs/examples/ex_port.rst

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Port Examples
44
Creating Custom Shapes
55
**********************
66

7-
*(Implemented on NodeGraphQt* ``v0.1.1`` *or above)*
7+
(*Implemented on* ``v0.1.1``)
88

99
To have custom port shapes the :meth:`NodeGraphQt.BaseNode.add_input` and
1010
:meth:`NodeGraphQt.BaseNode.add_output` functions now have a ``painter_func``
@@ -16,7 +16,7 @@ argument where you specify you custom port painter function.
1616
Example Triangle Port
1717
*********************
1818

19-
Here's an example function for drawing a triangle shaped port.
19+
Here's an example function for drawing a triangle port.
2020

2121
.. code-block:: python
2222
:linenos:
@@ -40,12 +40,14 @@ Here's an example function for drawing a triangle shaped port.
4040
"""
4141
painter.save()
4242
43+
# create triangle polygon.
4344
size = int(rect.height() / 2)
4445
triangle = QtGui.QPolygonF()
4546
triangle.append(QtCore.QPointF(-size, size))
4647
triangle.append(QtCore.QPointF(0.0, -size))
4748
triangle.append(QtCore.QPointF(size, size))
4849
50+
# map polygon to port position.
4951
transform = QtGui.QTransform()
5052
transform.translate(rect.center().x(), rect.center().y())
5153
port_poly = transform.map(triangle)
@@ -76,19 +78,21 @@ The ``draw_triangle_port`` painter function can then be passed to the ``painter_
7678

7779
.. code-block:: python
7880
:linenos:
81+
:emphasize-lines: 8
7982
8083
from NodeGraphQt import BaseNode
8184
8285
class MyListNode(BaseNode):
8386
8487
def __init__(self):
8588
super(MyListNode, self).__init__()
89+
# create a input port with custom painter function.
8690
self.add_input('triangle', painter_func=draw_triangle_port)
8791
8892
Example Square Port
8993
*******************
9094

91-
Here's simpler example function for drawing a Square shaped port.
95+
And here's another example function for drawing a Square port.
9296

9397
.. code-block:: python
9498
:linenos:

0 commit comments

Comments
 (0)