Skip to content

Commit 723e4cf

Browse files
authored
Merge pull request #300 from jchanvfx/base_node_circle_#287
Base node circle #287
2 parents 99557f1 + 37aebb4 commit 723e4cf

File tree

9 files changed

+376
-12
lines changed

9 files changed

+376
-12
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: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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+
`Implemented in` ``v0.5.2``
9+
10+
The ``NodeGraphQt.BaseNodeCircle`` is pretty much the same class as the
11+
:class:`NodeGraphQt.BaseNode` except with a different design.
12+
13+
**Inherited from:** :class:`NodeGraphQt.BaseNode`
14+
15+
.. image:: ../_images/node_circle.png
16+
:width: 250px
17+
18+
example snippet:
19+
20+
.. code-block:: python
21+
:linenos:
22+
23+
from NodeGraphQt import BaseNodeCircle
24+
25+
class ExampleNode(BaseNodeCircle):
26+
27+
# unique node identifier domain.
28+
__identifier__ = 'io.jchanvfx.github'
29+
30+
# initial default node name.
31+
NODE_NAME = 'My Node'
32+
33+
def __init__(self):
34+
super(ExampleNode, self).__init__()
35+
36+
# create an input port.
37+
self.add_input('in')
38+
39+
# create an output port.
40+
self.add_output('out')
41+
"""
42+
43+
NODE_NAME = 'Circle Node'
44+
45+
def __init__(self, qgraphics_item=None):
46+
super(BaseNodeCircle, self).__init__(qgraphics_item or CircleNodeItem)

NodeGraphQt/qgraphics/node_base.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -236,14 +236,14 @@ def mouseDoubleClickEvent(self, event):
236236
event (QtWidgets.QGraphicsSceneMouseEvent): mouse event.
237237
"""
238238
if event.button() == QtCore.Qt.LeftButton:
239-
240-
# enable text item edit mode.
241-
items = self.scene().items(event.scenePos())
242-
if self._text_item in items:
243-
self._text_item.set_editable(True)
244-
self._text_item.setFocus()
245-
event.ignore()
246-
return
239+
if not self.disabled:
240+
# enable text item edit mode.
241+
items = self.scene().items(event.scenePos())
242+
if self._text_item in items:
243+
self._text_item.set_editable(True)
244+
self._text_item.setFocus()
245+
event.ignore()
246+
return
247247

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

docs/_images/node_circle.png

44 KB
Loading

docs/_images/screenshot.png

-164 KB
Loading

docs/nodes/BaseNode.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,10 @@ BaseNode
44
.. autoclass:: NodeGraphQt.BaseNode
55
:members:
66
:exclude-members: update_model, set_layout_direction
7+
8+
BaseNode (Circle)
9+
#################
10+
11+
.. autoclass:: NodeGraphQt.BaseNodeCircle
12+
:members:
13+
:exclude-members: update_model, set_layout_direction

0 commit comments

Comments
 (0)