Skip to content

Commit a26285c

Browse files
committed
add new node widget and improve graph performance
1 parent a0c7432 commit a26285c

File tree

16 files changed

+333
-93
lines changed

16 files changed

+333
-93
lines changed

NodeGraphQt/base/graph.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,13 @@ class NodeGraph(QtCore.QObject):
8888
:parameters: :class:`PySide2.QtCore.QMimeData`, :class:`PySide2.QtCore.QPoint`
8989
:emits: mime data, node graph position
9090
"""
91+
session_changed = QtCore.Signal(str)
92+
"""
93+
Signal is triggered when session has been changed.
9194
95+
:parameters: :str
96+
:emits: new session path
97+
"""
9298
def __init__(self, parent=None):
9399
super(NodeGraph, self).__init__(parent)
94100
self.setObjectName('NodeGraphQt')
@@ -890,6 +896,7 @@ def clear_session(self):
890896
self._undo_stack.push(NodeRemovedCmd(self, n))
891897
self._undo_stack.clear()
892898
self._model.session = None
899+
self.session_changed.emit("")
893900

894901
def _serialize(self, nodes):
895902
"""
@@ -1028,6 +1035,9 @@ def save_session(self, file_path):
10281035
with open(file_path, 'w') as file_out:
10291036
json.dump(serliazed_data, file_out, indent=2, separators=(',', ':'))
10301037

1038+
self._model.session = file_path
1039+
self.session_changed.emit(file_path)
1040+
10311041
def load_session(self, file_path):
10321042
"""
10331043
Load node graph session layout file.
@@ -1054,6 +1064,7 @@ def load_session(self, file_path):
10541064
self._deserialize(layout_data)
10551065
self._undo_stack.clear()
10561066
self._model.session = file_path
1067+
self.session_changed.emit(file_path)
10571068

10581069
def copy_nodes(self, nodes=None):
10591070
"""
@@ -1204,3 +1215,9 @@ def save_dialog(self, current_dir=None, ext=None):
12041215
str: selected file path.
12051216
"""
12061217
return self._viewer.save_dialog(current_dir, ext)
1218+
1219+
def use_opengl(self):
1220+
"""
1221+
use opengl to draw the graph
1222+
"""
1223+
self._viewer.use_opengl()

NodeGraphQt/base/node.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
from NodeGraphQt.widgets.node_widgets import (NodeComboBox,
1515
NodeLineEdit,
1616
NodeFloatEdit,
17-
NodeCheckBox)
17+
NodeCheckBox,
18+
NodeFilePath)
1819

1920

2021
class classproperty(object):
@@ -532,6 +533,30 @@ def add_text_input(self, name, label='', text='', tab=None):
532533
widget.value_changed.connect(lambda k, v: self.set_property(k, v))
533534
self.view.add_widget(widget)
534535

536+
def add_file_input(self, name, label='', text='', tab=None, ext="*"):
537+
"""
538+
Creates a custom property with the :meth:`NodeObject.create_property`
539+
function and embeds a :class:`PySide2.QtWidgets.QLineEdit` widget
540+
into the node.
541+
542+
Note:
543+
The embedded widget is wired up to the :meth:`NodeObject.set_property`
544+
function use this function to to update the widget.
545+
546+
Args:
547+
name (str): name for the custom property.
548+
label (str): label to be displayed.
549+
text (str): pre filled text.
550+
tab (str): name of the widget tab to display in.
551+
ext (str): file ext
552+
"""
553+
self.create_property(
554+
name, text, widget_type=NODE_PROP_QLINEEDIT, tab=tab)
555+
widget = NodeFilePath(self.view, name, label, text,ext)
556+
widget.value_changed.connect(lambda k, v: self.set_property(k, v))
557+
widget._node = self
558+
self.view.add_widget(widget)
559+
535560
def add_float_input(self, name, label='', value=0.0, tab=None):
536561
"""
537562
Creates a custom property with the :meth:`NodeObject.create_property`

NodeGraphQt/base/utils.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def setup_context_menu(graph):
3535
file_menu.add_command('Open...', _open_session, QtGui.QKeySequence.Open)
3636
file_menu.add_command('Save...', _save_session, QtGui.QKeySequence.Save)
3737
file_menu.add_command('Save As...', _save_session_as, 'Ctrl+Shift+s')
38-
file_menu.add_command('Clear', _clear_session)
38+
file_menu.add_command('New', _new_session)
3939

4040
file_menu.add_separator()
4141

@@ -150,9 +150,9 @@ def _save_session_as(graph):
150150
graph.save_session(file_path)
151151

152152

153-
def _clear_session(graph):
153+
def _new_session(graph):
154154
"""
155-
Prompts a warning dialog to clear the node graph session.
155+
Prompts a warning dialog to new a node graph session.
156156
157157
Args:
158158
graph (NodeGraphQt.NodeGraph): node graph.

NodeGraphQt/constants.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# -*- coding: utf-8 -*-
33
import os
44
from .pkg_info import __version__
5+
from NodeGraphQt import QtWidgets
56

67
#: Current version of the NodeGraphQt framework.
78
VERSION = __version__
@@ -91,3 +92,12 @@
9192
Z_VAL_NODE = 1
9293
Z_VAL_PORT = 2
9394
Z_VAL_NODE_WIDGET = 3
95+
96+
97+
# === ITEM CACHE MODE ===
98+
99+
# QGraphicsItem.NoCache
100+
# QGraphicsItem.ItemCoordinateCache
101+
# QGraphicsItem.DeviceCoordinateCache
102+
103+
ITEM_CACHE_MODE = QtWidgets.QGraphicsItem.DeviceCoordinateCache

NodeGraphQt/qgraphics/node_abstract.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/python
22
from NodeGraphQt import QtCore, QtWidgets
33

4-
from NodeGraphQt.constants import Z_VAL_NODE, NODE_WIDTH, NODE_HEIGHT
4+
from NodeGraphQt.constants import Z_VAL_NODE, NODE_WIDTH, NODE_HEIGHT, ITEM_CACHE_MODE
55

66

77
class AbstractNodeItem(QtWidgets.QGraphicsItem):
@@ -26,6 +26,8 @@ def __init__(self, name='node', parent=None):
2626
self._width = NODE_WIDTH
2727
self._height = NODE_HEIGHT
2828

29+
self.setCacheMode(ITEM_CACHE_MODE)
30+
2931
def __repr__(self):
3032
return '{}.{}(\'{}\')'.format(
3133
self.__module__, self.__class__.__name__, self.name)

NodeGraphQt/qgraphics/node_base.py

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
NODE_WIDTH, NODE_HEIGHT,
66
NODE_ICON_SIZE, ICON_NODE_BASE,
77
NODE_SEL_COLOR, NODE_SEL_BORDER_COLOR,
8-
PORT_FALLOFF, Z_VAL_NODE, Z_VAL_NODE_WIDGET)
8+
PORT_FALLOFF, Z_VAL_NODE, Z_VAL_NODE_WIDGET,
9+
ITEM_CACHE_MODE)
910
from NodeGraphQt.errors import NodeWidgetError
1011
from NodeGraphQt.qgraphics.node_abstract import AbstractNodeItem
1112
from NodeGraphQt.qgraphics.port import PortItem
1213

13-
1414
class XDisabledItem(QtWidgets.QGraphicsItem):
1515
"""
1616
Node disabled overlay item.
@@ -40,7 +40,9 @@ def paint(self, painter, option, widget):
4040
used to describe the parameters needed to draw.
4141
widget (QtWidgets.QWidget): not used.
4242
"""
43+
4344
painter.save()
45+
painter.setClipRect(option.exposedRect)
4446

4547
margin = 20
4648
rect = self.boundingRect()
@@ -131,6 +133,12 @@ def __init__(self, name='node', parent=None):
131133
self._input_items = {}
132134
self._output_items = {}
133135
self._widgets = {}
136+
self._proxy_mode = False
137+
self._porxy_mode_threshold = 70
138+
139+
# def paint(self, painter, option, widget,force=False):
140+
# if self.auto_switch_mode() or force:
141+
# self._paint(self, painter, option, widget)
134142

135143
def paint(self, painter, option, widget):
136144
"""
@@ -142,6 +150,8 @@ def paint(self, painter, option, widget):
142150
used to describe the parameters needed to draw.
143151
widget (QtWidgets.QWidget): not used.
144152
"""
153+
self.auto_switch_mode()
154+
145155
painter.save()
146156
bg_border = 1.0
147157
rect = QtCore.QRectF(0.5 - (bg_border / 2),
@@ -155,6 +165,7 @@ def paint(self, painter, option, widget):
155165
path.addRoundedRect(rect, radius, radius)
156166

157167
rect = self.boundingRect()
168+
158169
bg_color = QtGui.QColor(*self.color)
159170
painter.setBrush(bg_color)
160171
painter.setPen(QtCore.Qt.NoPen)
@@ -392,7 +403,7 @@ def arrange_widgets(self, v_offset=0.0):
392403
def arrange_ports(self, v_offset=0.0):
393404
"""
394405
Arrange input, output ports in the node layout.
395-
406+
396407
Args:
397408
v_offset (float): port vertical offset.
398409
"""
@@ -468,6 +479,7 @@ def draw_node(self):
468479
self.arrange_ports(v_offset=height + (height / 2))
469480
# arrange node widgets
470481
self.arrange_widgets(v_offset=height / 2)
482+
self.update()
471483

472484
def post_init(self, viewer=None, pos=None):
473485
"""
@@ -484,6 +496,42 @@ def post_init(self, viewer=None, pos=None):
484496
if pos:
485497
self.xy_pos = pos
486498

499+
def auto_switch_mode(self):
500+
if ITEM_CACHE_MODE is QtWidgets.QGraphicsItem.ItemCoordinateCache:
501+
return
502+
rect= self.sceneBoundingRect()
503+
l = self.viewer().mapToGlobal(self.viewer().mapFromScene(rect.topLeft()))
504+
r = self.viewer().mapToGlobal(self.viewer().mapFromScene( rect.topRight()))
505+
# with is the node with in screen
506+
width = r.x()-l.x()
507+
508+
self.set_proxy_mode(width < self._porxy_mode_threshold)
509+
510+
def set_proxy_mode(self,mode):
511+
if mode is self._proxy_mode:
512+
return
513+
514+
self._proxy_mode = mode
515+
516+
visible = not mode
517+
518+
for w in self._widgets.values():
519+
w.widget.setVisible(visible)
520+
for port, text in self._input_items.items():
521+
port.setVisible(visible)
522+
text.setVisible(visible)
523+
for pipe in port.connected_pipes:
524+
pipe.setVisible(visible)
525+
526+
for port, text in self._output_items.items():
527+
port.setVisible(visible)
528+
text.setVisible(visible)
529+
for pipe in port.connected_pipes:
530+
pipe.setVisible(visible)
531+
532+
self._text_item.setVisible(visible)
533+
self._icon_item.setVisible(visible)
534+
487535
@property
488536
def icon(self):
489537
return self._properties['icon']
@@ -500,6 +548,8 @@ def icon(self, path=None):
500548
if self.scene():
501549
self.post_init()
502550

551+
self.update()
552+
503553
@AbstractNodeItem.width.setter
504554
def width(self, width=0.0):
505555
w, h = self.calc_size()
@@ -533,17 +583,20 @@ def name(self, name=''):
533583
self._text_item.setPlainText(name)
534584
if self.scene():
535585
self.draw_node()
586+
self.update()
536587

537588
@AbstractNodeItem.color.setter
538589
def color(self, color=(100, 100, 100, 255)):
539590
AbstractNodeItem.color.fset(self, color)
540591
if self.scene():
541592
self.scene().update()
593+
self.update()
542594

543595
@AbstractNodeItem.text_color.setter
544596
def text_color(self, color=(100, 100, 100, 255)):
545597
AbstractNodeItem.text_color.fset(self, color)
546598
self._set_text_color(color)
599+
self.update()
547600

548601
@property
549602
def inputs(self):
@@ -566,7 +619,7 @@ def add_input(self, name='input', multi_port=False, display_name=True):
566619
Args:
567620
name (str): name for the port.
568621
multi_port (bool): allow multiple connections.
569-
display_name (bool): display the port name.
622+
display_name (bool): display the port name.
570623
571624
Returns:
572625
PortItem: input item widget
@@ -580,6 +633,7 @@ def add_input(self, name='input', multi_port=False, display_name=True):
580633
text.font().setPointSize(8)
581634
text.setFont(text.font())
582635
text.setVisible(display_name)
636+
text.setCacheMode(ITEM_CACHE_MODE)
583637
self._input_items[port] = text
584638
if self.scene():
585639
self.post_init()
@@ -604,6 +658,7 @@ def add_output(self, name='output', multi_port=False, display_name=True):
604658
text.font().setPointSize(8)
605659
text.setFont(text.font())
606660
text.setVisible(display_name)
661+
text.setCacheMode(ITEM_CACHE_MODE)
607662
self._output_items[port] = text
608663
if self.scene():
609664
self.post_init()

NodeGraphQt/qgraphics/pipe.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
PIPE_HIGHLIGHT_COLOR, PIPE_DISABLED_COLOR,
88
PIPE_STYLE_DASHED, PIPE_STYLE_DEFAULT, PIPE_STYLE_DOTTED,
99
PIPE_LAYOUT_STRAIGHT, PIPE_WIDTH, IN_PORT, OUT_PORT, Z_VAL_PIPE,
10-
Z_VAL_NODE_WIDGET,
11-
PIPE_LAYOUT_ANGLE, PIPE_LAYOUT_CURVED)
10+
Z_VAL_NODE_WIDGET,PIPE_LAYOUT_ANGLE,
11+
PIPE_LAYOUT_CURVED,ITEM_CACHE_MODE)
1212
from NodeGraphQt.qgraphics.port import PortItem
1313

1414
PIPE_STYLES = {
@@ -39,6 +39,7 @@ def __init__(self, input_port=None, output_port=None):
3939
self._arrow.append(QtCore.QPointF(-size, size))
4040
self._arrow.append(QtCore.QPointF(0.0, -size * 1.5))
4141
self._arrow.append(QtCore.QPointF(size, size))
42+
self.setCacheMode(ITEM_CACHE_MODE)
4243

4344
def __repr__(self):
4445
in_name = self._input_port.name if self._input_port else ''

NodeGraphQt/qgraphics/port.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
PORT_HOVER_BORDER_COLOR,
1212
PORT_ACTIVE_COLOR,
1313
PORT_ACTIVE_BORDER_COLOR,
14-
Z_VAL_PORT)
14+
Z_VAL_PORT,
15+
ITEM_CACHE_MODE)
1516

1617

1718
class PortItem(QtWidgets.QGraphicsItem):
@@ -37,6 +38,8 @@ def __init__(self, parent=None):
3738
self._port_type = None
3839
self._multi_connection = False
3940

41+
self.setCacheMode(ITEM_CACHE_MODE)
42+
4043
def __str__(self):
4144
return '{}.PortItem("{}")'.format(self.__module__, self.name)
4245

@@ -201,6 +204,7 @@ def color(self):
201204
@color.setter
202205
def color(self, color=(0, 0, 0, 255)):
203206
self._color = color
207+
self.update()
204208

205209
@property
206210
def border_color(self):

0 commit comments

Comments
 (0)