Skip to content

Commit df55101

Browse files
committed
wip BaseNodeCircle implementation #287
1 parent 99557f1 commit df55101

File tree

5 files changed

+337
-1
lines changed

5 files changed

+337
-1
lines changed

NodeGraphQt/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ def __init__(self):
5454
from .base.port import Port
5555
from .base.node import NodeObject
5656
from .nodes.base_node import BaseNode
57+
from .nodes.base_node_circle import BaseNodeCircle
5758
from .nodes.backdrop_node import BackdropNode
5859
from .nodes.group_node import GroupNode
5960

@@ -68,6 +69,7 @@ def __init__(self):
6869
__all__ = [
6970
'BackdropNode',
7071
'BaseNode',
72+
'BaseNodeCircle',
7173
'GroupNode',
7274
'LICENSE',
7375
'NodeBaseWidget',
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/usr/bin/python
2+
from NodeGraphQt.nodes.base_node import BaseNode
3+
from NodeGraphQt.qgraphics.node_circle import CircleNodeItem
4+
5+
6+
class BaseNodeCircle(BaseNode):
7+
8+
NODE_NAME = 'Circle Node'
9+
10+
def __init__(self, qgraphics_item=None):
11+
super(BaseNodeCircle, self).__init__(qgraphics_item or CircleNodeItem)
Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
#!/usr/bin/python
2+
from Qt import QtCore, QtGui, QtWidgets
3+
4+
from NodeGraphQt.constants import NodeEnum, PortEnum
5+
from NodeGraphQt.qgraphics.node_base import NodeItem
6+
7+
8+
class CircleNodeItem(NodeItem):
9+
"""
10+
Circle Node item.
11+
12+
Args:
13+
name (str): name displayed on the node.
14+
parent (QtWidgets.QGraphicsItem): parent item.
15+
"""
16+
17+
def __init__(self, name='circle', parent=None):
18+
super(CircleNodeItem, self).__init__(name, parent)
19+
20+
def _paint_horizontal(self, painter, option, widget):
21+
painter.save()
22+
23+
text_rect = self._text_item.boundingRect()
24+
text_rect = QtCore.QRectF(
25+
self.boundingRect().center().x() - (text_rect.width() / 2),
26+
self.boundingRect().center().y() - (text_rect.height() / 2),
27+
text_rect.width(),
28+
text_rect.height()
29+
)
30+
31+
padding = 10.0
32+
rect = QtCore.QRectF(
33+
text_rect.center().x() - (text_rect.width() / 2) - (padding / 2),
34+
text_rect.center().y() - (text_rect.width() / 2) - (padding / 2),
35+
text_rect.width() + padding,
36+
text_rect.width() + padding
37+
)
38+
39+
# draw port lines.
40+
pen_color = QtGui.QColor(*self.border_color)
41+
pen_color.setAlpha(120)
42+
pen = QtGui.QPen(pen_color, 1.5)
43+
pen.setCapStyle(QtCore.Qt.RoundCap)
44+
painter.setPen(pen)
45+
painter.setBrush(QtCore.Qt.NoBrush)
46+
for p in self.inputs:
47+
if p.isVisible():
48+
p_text = self.get_input_text_item(p)
49+
if p_text.isVisible():
50+
pt_width = p_text.boundingRect().width() * 1.2
51+
else:
52+
pt_width = p.boundingRect().width() / 2
53+
pt1 = QtCore.QPointF(
54+
p.pos().x() + (p.boundingRect().width() / 2) + pt_width,
55+
p.pos().y() + (p.boundingRect().height() / 2)
56+
)
57+
path = QtGui.QPainterPath()
58+
path.moveTo(pt1)
59+
path.lineTo(QtCore.QPointF(pt1.x() + 4.0, pt1.y()))
60+
path.lineTo(rect.center())
61+
painter.drawPath(path)
62+
63+
for p in self.outputs:
64+
if p.isVisible():
65+
p_text = self.get_output_text_item(p)
66+
if p_text.isVisible():
67+
pt_width = p_text.boundingRect().width() * 1.2
68+
else:
69+
pt_width = p.boundingRect().width() / 2
70+
pt1 = QtCore.QPointF(
71+
p.pos().x() + (p.boundingRect().width() / 2) - pt_width,
72+
p.pos().y() + (p.boundingRect().height() / 2)
73+
)
74+
path = QtGui.QPainterPath()
75+
path.moveTo(pt1)
76+
path.lineTo(QtCore.QPointF(pt1.x() - 4.0, pt1.y()))
77+
path.lineTo(rect.center())
78+
painter.drawPath(path)
79+
80+
# draw the base color.
81+
painter.setBrush(QtGui.QColor(*self.color))
82+
painter.setPen(QtCore.Qt.NoPen)
83+
painter.drawEllipse(rect)
84+
85+
# draw outline.
86+
if self.selected:
87+
# light overlay on background when selected.
88+
painter.setBrush(QtGui.QColor(*NodeEnum.SELECTED_COLOR.value))
89+
painter.drawEllipse(rect)
90+
91+
border_width = 1.2
92+
border_color = QtGui.QColor(
93+
*NodeEnum.SELECTED_BORDER_COLOR.value
94+
)
95+
else:
96+
border_width = 0.8
97+
border_color = QtGui.QColor(*self.border_color)
98+
99+
# draw the outlines.
100+
painter.setBrush(QtCore.Qt.NoBrush)
101+
painter.setPen(QtGui.QPen(border_color, border_width))
102+
painter.drawEllipse(rect)
103+
104+
# node name background.
105+
text_rect = self._text_item.boundingRect()
106+
text_rect = QtCore.QRectF(
107+
rect.center().x() - (text_rect.width() / 2),
108+
rect.center().y() - (text_rect.height() / 2),
109+
text_rect.width(),
110+
text_rect.height()
111+
)
112+
if self.selected:
113+
painter.setBrush(QtGui.QColor(*NodeEnum.SELECTED_COLOR.value))
114+
else:
115+
painter.setBrush(QtGui.QColor(0, 0, 0, 80))
116+
painter.setPen(QtCore.Qt.NoPen)
117+
painter.drawRoundedRect(text_rect, 8.0, 8.0)
118+
119+
painter.restore()
120+
121+
def _paint_vertical(self, painter, option, widget):
122+
painter.save()
123+
124+
text_rect = self._text_item.boundingRect()
125+
text_rect = QtCore.QRectF(
126+
self.boundingRect().center().x() - (text_rect.width() / 2),
127+
self.boundingRect().center().y() - (text_rect.height() / 2),
128+
text_rect.width(),
129+
text_rect.height()
130+
)
131+
132+
padding = 10.0
133+
rect = QtCore.QRectF(
134+
text_rect.center().x() - (text_rect.width() / 2) - (padding / 2),
135+
text_rect.center().y() - (text_rect.width() / 2) - (padding / 2),
136+
text_rect.width() + padding,
137+
text_rect.width() + padding
138+
)
139+
140+
# draw port lines.
141+
pen_color = QtGui.QColor(*self.border_color)
142+
pen_color.setAlpha(120)
143+
pen = QtGui.QPen(pen_color, 1.5)
144+
pen.setCapStyle(QtCore.Qt.RoundCap)
145+
painter.setPen(pen)
146+
painter.setBrush(QtCore.Qt.NoBrush)
147+
for p in self.inputs:
148+
if p.isVisible():
149+
pt1 = QtCore.QPointF(
150+
p.pos().x() + (p.boundingRect().width() / 2),
151+
p.pos().y() + (p.boundingRect().height() / 2)
152+
)
153+
path = QtGui.QPainterPath()
154+
path.moveTo(pt1)
155+
path.lineTo(QtCore.QPointF(pt1.x(), pt1.y()))
156+
path.lineTo(rect.center())
157+
painter.drawPath(path)
158+
159+
for p in self.outputs:
160+
if p.isVisible():
161+
pt1 = QtCore.QPointF(
162+
p.pos().x() + (p.boundingRect().width() / 2),
163+
p.pos().y() + (p.boundingRect().height() / 2)
164+
)
165+
path = QtGui.QPainterPath()
166+
path.moveTo(pt1)
167+
path.lineTo(QtCore.QPointF(pt1.x(), pt1.y()))
168+
path.lineTo(rect.center())
169+
painter.drawPath(path)
170+
171+
# draw the base color.
172+
painter.setBrush(QtGui.QColor(*self.color))
173+
painter.setPen(QtCore.Qt.NoPen)
174+
painter.drawEllipse(rect)
175+
176+
# draw outline.
177+
if self.selected:
178+
# light overlay on background when selected.
179+
painter.setBrush(QtGui.QColor(*NodeEnum.SELECTED_COLOR.value))
180+
painter.drawEllipse(rect)
181+
182+
border_width = 1.2
183+
border_color = QtGui.QColor(
184+
*NodeEnum.SELECTED_BORDER_COLOR.value
185+
)
186+
else:
187+
border_width = 0.8
188+
border_color = QtGui.QColor(*self.border_color)
189+
190+
# draw the outlines.
191+
painter.setBrush(QtCore.Qt.NoBrush)
192+
painter.setPen(QtGui.QPen(border_color, border_width))
193+
painter.drawEllipse(rect)
194+
195+
# node name background.
196+
text_rect = self._text_item.boundingRect()
197+
text_rect = QtCore.QRectF(
198+
rect.center().x() - (text_rect.width() / 2),
199+
rect.center().y() - (text_rect.height() / 2),
200+
text_rect.width(),
201+
text_rect.height()
202+
)
203+
if self.selected:
204+
painter.setBrush(QtGui.QColor(*NodeEnum.SELECTED_COLOR.value))
205+
else:
206+
painter.setBrush(QtGui.QColor(0, 0, 0, 80))
207+
painter.setPen(QtCore.Qt.NoPen)
208+
painter.drawRoundedRect(text_rect, 8.0, 8.0)
209+
210+
painter.restore()
211+
212+
def _align_icon_horizontal(self, h_offset, v_offset):
213+
icon_rect = self._icon_item.boundingRect()
214+
x = self.boundingRect().center().x() - (icon_rect.width() / 2)
215+
y = self.boundingRect().top()
216+
self._icon_item.setPos(x + h_offset, y + v_offset)
217+
218+
def _align_icon_vertical(self, h_offset, v_offset):
219+
self._align_icon_horizontal(h_offset, v_offset)
220+
221+
def _align_label_horizontal(self, h_offset, v_offset):
222+
rect = self.boundingRect()
223+
text_rect = self._text_item.boundingRect()
224+
x = rect.center().x() - (text_rect.width() / 2)
225+
y = rect.center().y() - (text_rect.height() / 2)
226+
self._text_item.setPos(x + h_offset, y + v_offset)
227+
228+
def _align_label_vertical(self, h_offset, v_offset):
229+
self._align_label_horizontal(h_offset, v_offset)
230+
231+
def _draw_node_horizontal(self):
232+
add_width = self.text_item.boundingRect().width() * 1.5
233+
add_height = self.text_item.boundingRect().width() / 2
234+
235+
# update port text items in visibility.
236+
for port, text in self._input_items.items():
237+
text.setVisible(port.display_name)
238+
for port, text in self._output_items.items():
239+
text.setVisible(port.display_name)
240+
241+
# setup initial base size.
242+
self._set_base_size(add_w=add_width, add_h=add_height)
243+
# set text color when node is initialized.
244+
self._set_text_color(self.text_color)
245+
# set the tooltip
246+
self._tooltip_disable(self.disabled)
247+
248+
# --- set the initial node layout ---
249+
# (do all the graphic item layout offsets here)
250+
251+
# align label text
252+
self.align_label()
253+
# arrange icon
254+
self.align_icon()
255+
# arrange input and output ports.
256+
self.align_ports(v_offset=add_height / 2)
257+
# arrange node widgets
258+
self.align_widgets(v_offset=0.0)
259+
260+
self.update()
261+
262+
def _draw_node_vertical(self):
263+
add_width = self.text_item.boundingRect().width() * 1.5
264+
add_height = self.text_item.boundingRect().width() / 2
265+
266+
# hide the port text items in vertical layout.
267+
for port, text in self._input_items.items():
268+
text.setVisible(False)
269+
for port, text in self._output_items.items():
270+
text.setVisible(False)
271+
272+
# setup initial base size.
273+
self._set_base_size(add_w=add_width, add_h=add_height)
274+
# set text color when node is initialized.
275+
self._set_text_color(self.text_color)
276+
# set the tooltip
277+
self._tooltip_disable(self.disabled)
278+
279+
# --- set the initial node layout ---
280+
# (do all the graphic item layout offsets here)
281+
282+
# align label text
283+
self.align_label()
284+
# align icon
285+
self.align_icon()
286+
# arrange input and output ports.
287+
self.align_ports()
288+
# arrange node widgets
289+
self.align_widgets(v_offset=0.0)
290+
291+
self.update()

examples/basic_example.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
graph.register_nodes([
3535
basic_nodes.BasicNodeA,
3636
basic_nodes.BasicNodeB,
37+
basic_nodes.CircleNode,
3738
custom_ports_node.CustomPortsNode,
3839
group_node.MyGroupNode,
3940
widget_nodes.DropdownMenuNode,
@@ -74,6 +75,10 @@
7475
n_combo_menu = graph.create_node(
7576
'nodes.widget.DropdownMenuNode', name='combobox node')
7677

78+
# crete node with the circular design.
79+
n_circle = graph.create_node(
80+
'nodes.basic.CircleNode', name='circle node')
81+
7782
# create group node.
7883
n_group = graph.create_node('nodes.group.MyGroupNode')
7984

examples/nodes/basic_nodes.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from NodeGraphQt import BaseNode
1+
from NodeGraphQt import BaseNode, BaseNodeCircle
22

33

44
class BasicNodeA(BaseNode):
@@ -48,3 +48,30 @@ def __init__(self):
4848
self.add_output('single 1', multi_output=False)
4949
self.add_output('single 2', multi_output=False)
5050
self.add_output('multi out')
51+
52+
53+
class CircleNode(BaseNodeCircle):
54+
"""
55+
A node class with 3 inputs and 3 outputs.
56+
This node is a circular design.
57+
"""
58+
59+
# unique node identifier.
60+
__identifier__ = 'nodes.basic'
61+
62+
# initial default node name.
63+
NODE_NAME = 'Circle Node'
64+
65+
def __init__(self):
66+
super(CircleNode, self).__init__()
67+
68+
# create node inputs
69+
self.add_input('in 1')
70+
self.add_input('in 2')
71+
self.add_input('in 3', multi_input=True)
72+
self.add_input('in 4', display_name=False)
73+
74+
# create node outputs
75+
self.add_output('out 1', display_name=False)
76+
self.add_output('out 2', multi_output=False)
77+
self.add_output('out 3', multi_output=True)

0 commit comments

Comments
 (0)