Skip to content

Commit 7fb0518

Browse files
authored
Merge pull request #336 from jchanvfx/self_connected_node_pipes_#328
Self connected node pipes #328
2 parents 68db17c + 42564d7 commit 7fb0518

File tree

3 files changed

+101
-11
lines changed

3 files changed

+101
-11
lines changed

NodeGraphQt/pkg_info.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/python
22
# -*- coding: utf-8 -*-
3-
__version__ = '0.5.9'
3+
__version__ = '0.5.10'
44
__status__ = 'Work in Progress'
55
__license__ = 'MIT'
66

NodeGraphQt/qgraphics/pipe.py

Lines changed: 93 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,58 @@ def paint(self, painter, option, widget):
158158
# QPaintDevice: Cannot destroy paint device that is being painted.
159159
painter.restore()
160160

161+
def __draw_path_cycled_vertical(self, start_port, pos1, pos2, path):
162+
"""
163+
Draw pipe vertically around node if connection is cyclic.
164+
165+
Args:
166+
start_port (PortItem): port used to draw the starting point.
167+
pos1 (QPointF): start port position.
168+
pos2 (QPointF): end port position.
169+
path (QPainterPath): path to draw.
170+
"""
171+
n_rect = start_port.node.boundingRect()
172+
ptype = start_port.port_type
173+
start_pos = pos1 if ptype == PortTypeEnum.IN.value else pos2
174+
end_pos = pos2 if ptype == PortTypeEnum.IN.value else pos1
175+
176+
padding = 40
177+
top = start_pos.y() - padding
178+
bottom = end_pos.y() + padding
179+
path.moveTo(end_pos)
180+
path.lineTo(end_pos.x(), bottom)
181+
path.lineTo(end_pos.x() + n_rect.right(), bottom)
182+
path.lineTo(end_pos.x() + n_rect.right(), top)
183+
path.lineTo(start_pos.x(), top)
184+
path.lineTo(start_pos)
185+
self.setPath(path)
186+
187+
def __draw_path_cycled_horizontal(self, start_port, pos1, pos2, path):
188+
"""
189+
Draw pipe horizontally around node if connection is cyclic.
190+
191+
Args:
192+
start_port (PortItem): port used to draw the starting point.
193+
pos1 (QPointF): start port position.
194+
pos2 (QPointF): end port position.
195+
path (QPainterPath): path to draw.
196+
"""
197+
n_rect = start_port.node.boundingRect()
198+
ptype = start_port.port_type
199+
start_pos = pos1 if ptype == PortTypeEnum.IN.value else pos2
200+
end_pos = pos2 if ptype == PortTypeEnum.IN.value else pos1
201+
202+
padding = 40
203+
left = end_pos.x() + padding
204+
right = start_pos.x() - padding
205+
path.moveTo(start_pos)
206+
path.lineTo(right, start_pos.y())
207+
path.lineTo(right, end_pos.y() + n_rect.bottom())
208+
path.lineTo(left, end_pos.y() + n_rect.bottom())
209+
path.lineTo(left, end_pos.y())
210+
path.lineTo(end_pos)
211+
self.setPath(path)
212+
161213
def __draw_path_vertical(self, start_port, pos1, pos2, path):
162214
"""
163215
Draws the vertical path between ports.
@@ -272,47 +324,79 @@ def draw_path(self, start_port, end_port=None, cursor_pos=None):
272324

273325
line = QtCore.QLineF(pos1, pos2)
274326
path = QtGui.QPainterPath()
327+
328+
direction = self.viewer_layout_direction()
329+
330+
if end_port and not self.viewer().acyclic:
331+
if end_port.node == start_port.node:
332+
if direction is LayoutDirectionEnum.VERTICAL.value:
333+
self.__draw_path_cycled_vertical(
334+
start_port, pos1, pos2, path
335+
)
336+
return
337+
elif direction is LayoutDirectionEnum.HORIZONTAL.value:
338+
self.__draw_path_cycled_horizontal(
339+
start_port, pos1, pos2, path
340+
)
341+
return
342+
275343
path.moveTo(line.x1(), line.y1())
276344

277345
if self.viewer_pipe_layout() == PipeLayoutEnum.STRAIGHT.value:
278346
path.lineTo(pos2)
279347
self.setPath(path)
280348
return
281349

282-
if self.viewer_layout_direction() is LayoutDirectionEnum.VERTICAL.value:
350+
if direction is LayoutDirectionEnum.VERTICAL.value:
283351
self.__draw_path_vertical(start_port, pos1, pos2, path)
284-
elif self.viewer_layout_direction() is LayoutDirectionEnum.HORIZONTAL.value:
352+
elif direction is LayoutDirectionEnum.HORIZONTAL.value:
285353
self.__draw_path_horizontal(start_port, pos1, pos2, path)
286354

287355
def reset_path(self):
288356
path = QtGui.QPainterPath(QtCore.QPointF(0.0, 0.0))
289357
self.setPath(path)
290358

291359
@staticmethod
292-
def calc_distance(p1, p2):
360+
def _calc_distance(p1, p2):
293361
x = math.pow((p2.x() - p1.x()), 2)
294362
y = math.pow((p2.y() - p1.y()), 2)
295363
return math.sqrt(x + y)
296364

297365
def port_from_pos(self, pos, reverse=False):
298366
inport_pos = self.input_port.scenePos()
299367
outport_pos = self.output_port.scenePos()
300-
input_dist = self.calc_distance(inport_pos, pos)
301-
output_dist = self.calc_distance(outport_pos, pos)
368+
input_dist = self._calc_distance(inport_pos, pos)
369+
output_dist = self._calc_distance(outport_pos, pos)
302370
if input_dist < output_dist:
303371
port = self.output_port if reverse else self.input_port
304372
else:
305373
port = self.input_port if reverse else self.output_port
306374
return port
307375

308-
def viewer_pipe_layout(self):
376+
def viewer(self):
377+
"""
378+
Returns:
379+
NodeViewer: node graph viewer.
380+
"""
309381
if self.scene():
310-
viewer = self.scene().viewer()
382+
return self.scene().viewer()
383+
384+
def viewer_pipe_layout(self):
385+
"""
386+
Returns:
387+
int: pipe layout mode.
388+
"""
389+
viewer = self.viewer()
390+
if viewer:
311391
return viewer.get_pipe_layout()
312392

313393
def viewer_layout_direction(self):
314-
if self.scene():
315-
viewer = self.scene().viewer()
394+
"""
395+
Returns:
396+
int: graph layout mode.
397+
"""
398+
viewer = self.viewer()
399+
if viewer:
316400
return viewer.get_layout_direction()
317401

318402
def activate(self):

NodeGraphQt/widgets/viewer.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -897,14 +897,20 @@ def apply_live_connection(self, event):
897897
if self._start_port is end_port:
898898
return
899899

900+
# if connection to itself
901+
same_node_connection = end_port.node == self._start_port.node
902+
if not self.acyclic:
903+
# allow a node cycle connection.
904+
same_node_connection = False
905+
900906
# restore connection check.
901907
restore_connection = any([
902908
# if the end port is locked.
903909
end_port.locked,
904910
# if same port type.
905911
end_port.port_type == self._start_port.port_type,
906912
# if connection to itself.
907-
end_port.node == self._start_port.node,
913+
same_node_connection,
908914
# if end port is the start port.
909915
end_port == self._start_port,
910916
# if detached port is the end port.

0 commit comments

Comments
 (0)