Skip to content

Commit 2df0c49

Browse files
committed
add node graph editable property
1 parent 359902c commit 2df0c49

File tree

7 files changed

+73
-16
lines changed

7 files changed

+73
-16
lines changed

NodeGraphQt/base/graph.py

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ def __init__(self, parent=None):
142142
self._node_factory = NodeFactory()
143143
self._undo_stack = QtWidgets.QUndoStack(self)
144144
self._current_node_space = None
145+
self._editable = True
145146

146147
tab = QtWidgets.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_Tab), self._viewer)
147148
tab.activated.connect(self._toggle_tab_search)
@@ -176,6 +177,8 @@ def _insert_node(self, pipe, node_id, prev_node_pos):
176177
node_id (str): selected node id to insert.
177178
prev_node_pos (dict): previous node position. {NodeItem: [prev_x, prev_y]}
178179
"""
180+
if not self._editable:
181+
return
179182
node = self.get_node_by_id(node_id)
180183

181184
# exclude the BackdropNode
@@ -203,6 +206,8 @@ def _toggle_tab_search(self):
203206
"""
204207
toggle the tab search widget.
205208
"""
209+
if not self._editable:
210+
return
206211
if self._viewer.underMouse():
207212
self._viewer.tab_search_set_nodes(self._node_factory.names)
208213
self._viewer.tab_search_toggle()
@@ -217,6 +222,8 @@ def _on_property_bin_changed(self, node_id, prop_name, prop_value):
217222
prop_name (str): node property name.
218223
prop_value (object): python object.
219224
"""
225+
if not self._editable:
226+
return
220227
node = self.get_node_by_id(node_id)
221228

222229
# prevent signals from causing a infinite loop.
@@ -307,6 +314,8 @@ def _on_connection_changed(self, disconnected, connected):
307314
connected (list[list[widgets.port.PortItem]]):
308315
pair list of port view items.
309316
"""
317+
if not self._editable:
318+
return
310319
if not (disconnected or connected):
311320
return
312321

@@ -336,7 +345,7 @@ def _on_connection_sliced(self, ports):
336345
ports (list[list[widgets.port.PortItem]]):
337346
pair list of port connections (in port, out port)
338347
"""
339-
if not ports:
348+
if not ports or not self._editable:
340349
return
341350
ptypes = {IN_PORT: 'inputs', OUT_PORT: 'outputs'}
342351
self._undo_stack.beginMacro('slice connections')
@@ -747,6 +756,8 @@ def create_node(self, node_type, name=None, selected=True, color=None,
747756
Returns:
748757
NodeGraphQt.BaseNode: the created instance of the node.
749758
"""
759+
if not self._editable:
760+
return
750761
NodeCls = self._node_factory.create_node_instance(node_type)
751762
if NodeCls:
752763
node = NodeCls()
@@ -813,6 +824,8 @@ def add_node(self, node, pos=None, unique_name=True):
813824
pos (list[float]): node x,y position. (optional)
814825
unique_name (bool): make node name unique
815826
"""
827+
if not self._editable:
828+
return
816829
assert isinstance(node, NodeObject), 'node must be a Node instance.'
817830

818831
wid_types = node.model.__dict__.pop('_TEMP_property_widget_types')
@@ -850,6 +863,10 @@ def set_node_space(self, node):
850863
if node is not None:
851864
node.enter()
852865
self._node_space_bar.set_node(node)
866+
self._editable = node.is_editable()
867+
else:
868+
self._editable = True
869+
self._viewer.scene().set_editable(self._editable)
853870

854871
def get_node_space(self):
855872
"""
@@ -867,6 +884,8 @@ def delete_node(self, node):
867884
Args:
868885
node (NodeGraphQt.BaseNode): node object.
869886
"""
887+
if not self._editable:
888+
return
870889
assert isinstance(node, NodeObject), \
871890
'node must be a instance of a NodeObject.'
872891
if node is self.root_node():
@@ -887,6 +906,8 @@ def delete_nodes(self, nodes):
887906
Args:
888907
nodes (list[NodeGraphQt.BaseNode]): list of node instances.
889908
"""
909+
if not self._editable:
910+
return
890911
root_node = self.root_node()
891912
self.nodes_deleted.emit([n.id for n in nodes])
892913
self._undo_stack.beginMacro('delete nodes')
@@ -1082,9 +1103,7 @@ def _serialize(self, nodes):
10821103
node_dict = n.model.to_dict
10831104

10841105
if isinstance(n, SubGraph):
1085-
published = n.has_property('published')
1086-
if published:
1087-
published = n.get_property('published')
1106+
published = n.get_property('published')
10881107
if not published:
10891108
children = n.children()
10901109
if children:
@@ -1132,6 +1151,8 @@ def _deserialize(self, data, relative_pos=False, pos=None, set_parent=True):
11321151
Returns:
11331152
list[NodeGraphQt.Nodes]: list of node instances.
11341153
"""
1154+
if not self._editable:
1155+
return
11351156
nodes = {}
11361157
# build the nodes.
11371158
for n_id, n_data in data.get('nodes', {}).items():
@@ -1325,6 +1346,8 @@ def paste_nodes(self):
13251346
"""
13261347
Pastes nodes copied from the clipboard.
13271348
"""
1349+
if not self._editable:
1350+
return
13281351
clipboard = QtWidgets.QApplication.clipboard()
13291352
cb_text = clipboard.text()
13301353
if not cb_text:
@@ -1346,7 +1369,7 @@ def duplicate_nodes(self, nodes):
13461369
Returns:
13471370
list[NodeGraphQt.BaseNode]: list of duplicated node instances.
13481371
"""
1349-
if not nodes:
1372+
if not nodes or not self._editable:
13501373
return
13511374

13521375
self._undo_stack.beginMacro('duplicate nodes')
@@ -1374,7 +1397,7 @@ def disable_nodes(self, nodes, mode=None):
13741397
nodes (list[NodeGraphQt.BaseNode]): list of node instances.
13751398
mode (bool): (optional) disable state of the nodes.
13761399
"""
1377-
if not nodes:
1400+
if not nodes or not self._editable:
13781401
return
13791402
if mode is None:
13801403
mode = not nodes[0].disabled()

NodeGraphQt/qgraphics/node_base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ def calc_size(self, add_w=0.0, add_h=0.0):
301301
add_h (float): additional height.
302302
"""
303303
width = 0
304-
height = 0
304+
height = self.text_item.boundingRect().height()
305305

306306
if self._widgets:
307307
wid_width = max([

NodeGraphQt/qgraphics/text_item.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from PySide2 import QtWidgets, QtGui, QtCore
1+
from .. import QtWidgets, QtGui, QtCore
22

33

44
class text_item(QtWidgets.QGraphicsTextItem):
@@ -7,7 +7,7 @@ class text_item(QtWidgets.QGraphicsTextItem):
77
def __init__(self, text, parent=None):
88
super(text_item, self).__init__(text, parent)
99
self.setFlags(QtWidgets.QGraphicsItem.ItemIsFocusable)
10-
self.setTextInteractionFlags(QtGui.Qt.NoTextInteraction)
10+
self.setTextInteractionFlags(QtCore.Qt.NoTextInteraction)
1111
self.isEditing = False
1212

1313
def _editingFinished(self):
@@ -17,7 +17,7 @@ def _editingFinished(self):
1717
self.editingFinished.emit(self.toPlainText())
1818

1919
def mousePressEvent(self, event):
20-
self.setTextInteractionFlags(QtGui.Qt.TextEditable)
20+
self.setTextInteractionFlags(QtCore.Qt.TextEditable)
2121
self.isEditing = True
2222
super(text_item, self).mousePressEvent(event)
2323

NodeGraphQt/widgets/scene.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,25 @@ def __init__(self, parent=None):
1616
self.background_color = VIEWER_BG_COLOR
1717
self.grid_color = VIEWER_GRID_COLOR
1818
self._grid_mode = VIEWER_GRID_LINES
19+
self._editable = True
1920
self.setBackgroundBrush(self._bg_qcolor)
2021

2122
def __repr__(self):
2223
return '{}.{}(\'{}\')'.format(self.__module__,
2324
self.__class__.__name__,
2425
self.viewer())
2526

27+
def set_editable(self, state):
28+
self._editable = state
29+
30+
def _draw_text(self, painter):
31+
font = QtGui.QFont()
32+
font.setPixelSize(48)
33+
painter.setFont(font)
34+
parent = self.viewer()
35+
pos = QtCore.QPoint(20, parent.height()-20)
36+
painter.drawText(parent.mapToScene(pos), 'Not Editable')
37+
2638
def _draw_grid(self, painter, rect, pen, grid_size):
2739
left = int(rect.left())
2840
right = int(rect.right())
@@ -54,9 +66,7 @@ def _draw_dots(self, painter, rect, pen, grid_size):
5466
pen.setWidth(grid_size / 10)
5567
painter.setPen(pen)
5668

57-
for x in range(first_left, right, grid_size):
58-
for y in range(first_top, bottom, grid_size):
59-
painter.drawPoint(int(x), int(y))
69+
[painter.drawPoint(int(x), int(y)) for x in range(first_left, right, grid_size) for y in range(first_top, bottom, grid_size)]
6070

6171
def drawBackground(self, painter, rect):
6272
super(NodeScene, self).drawBackground(painter, rect)
@@ -81,6 +91,8 @@ def drawBackground(self, painter, rect):
8191
pen = QtGui.QPen(color, 0.65)
8292
self._draw_grid(painter, rect, pen, VIEWER_GRID_SIZE * 8)
8393

94+
if not self._editable:
95+
self._draw_text(painter)
8496
painter.restore()
8597

8698
def mousePressEvent(self, event):

example_auto_nodes.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ def enter_node(graph, node):
6666
graph.set_node_space(node)
6767

6868

69+
def allow_edit(graph, node):
70+
node.set_property('published', False)
71+
72+
6973
def print_path(graph, node):
7074
print(node.path())
7175

@@ -125,6 +129,7 @@ def show_nodes_list(node):
125129

126130
# setup node menu
127131
node_menu = graph.context_nodes_menu()
132+
node_menu.add_command('Allow Edit', allow_edit, node_class=Publish)
128133
node_menu.add_command('Enter Node', enter_node, node_class=SubGraphNode)
129134
node_menu.add_command('Publish Node', publish_node, node_class=SubGraphNode)
130135
node_menu.add_command('Print Children', print_children, node_class=SubGraphNode)

example_auto_nodes/node_base/subgraph_node.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ def __init__(self, defaultInputType=None, defaultOutputType=None, dynamic_port=T
1616
self.sub_graph_input_nodes = []
1717
self.sub_graph_output_nodes = []
1818
self.create_property('graph_rect', None)
19+
self.create_property('published', False)
1920
if dynamic_port:
2021
self.model.dynamic_port = True
2122
self.add_int_input('input count', 'input count', 0)
@@ -37,6 +38,19 @@ def mark_node_to_be_cooked(self, port):
3738
if port not in self._marked_ports and port in self.input_ports():
3839
self._marked_ports.append(port)
3940

41+
def is_editable(self):
42+
"""
43+
Returns whether the node is allowed edit.
44+
"""
45+
46+
parent = self.parent()
47+
if parent is None:
48+
return not self.get_property('published')
49+
50+
if not self.get_property('published') and self.parent().is_editable():
51+
return True
52+
return False
53+
4054
def enter(self):
4155
"""
4256
Action when enter the sub graph.
@@ -330,6 +344,7 @@ def publish(self, file_path, node_name, node_identifier, node_class_name):
330344
data['node']['name'] = node_name
331345
data['node']['class_name'] = node_class_name.replace(" ", "_")
332346
data['node'].pop('type_')
347+
data['node']['custom']['published'] = True
333348
file_path = file_path.strip()
334349
with open(file_path, 'w') as file_out:
335350
json.dump(data, file_out, indent=2, separators=(',', ':'))

example_auto_nodes/subgraph_nodes.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ class Publish(SubGraph):
8686
def __init__(self, defaultInputType=None, defaultOutputType=None):
8787
super(Publish, self).__init__(defaultInputType, defaultOutputType, dynamic_port=False)
8888
self.set_property('color', (36, 97, 100, 255))
89-
self.create_property('published', True)
89+
self.set_property('published', True)
9090
self.created = False
9191

9292
def set_graph(self, graph):
@@ -100,7 +100,7 @@ def create_from_file(self):
100100
Update node properties and create sub graph nodes by published node file.
101101
"""
102102

103-
if self.NODE_FILE is None:
103+
if self.NODE_FILE is None or not self.get_property('published'):
104104
return
105105
data = read_json(self.NODE_FILE)
106106
if not data:
@@ -125,7 +125,9 @@ def create_from_file(self):
125125
[node.set_parent(self) for node in children]
126126

127127
def publish(self, file_path, node_name, node_identifier, node_class_name):
128-
return
128+
if self.get_property('published'):
129+
return
130+
super(Publish, self).publish(file_path, node_name, node_identifier, node_class_name)
129131

130132
@staticmethod
131133
def create_node_class(file_path):

0 commit comments

Comments
 (0)