4
4
import os
5
5
import re
6
6
import copy
7
-
7
+ import gc
8
8
from .. import QtCore , QtWidgets , QtGui
9
9
from .commands import (NodeAddedCmd ,
10
10
NodeRemovedCmd ,
@@ -142,6 +142,7 @@ def __init__(self, parent=None):
142
142
self ._node_factory = NodeFactory ()
143
143
self ._undo_stack = QtWidgets .QUndoStack (self )
144
144
self ._current_node_space = None
145
+ self ._editable = True
145
146
146
147
tab = QtWidgets .QShortcut (QtGui .QKeySequence (QtCore .Qt .Key_Tab ), self ._viewer )
147
148
tab .activated .connect (self ._toggle_tab_search )
@@ -176,6 +177,8 @@ def _insert_node(self, pipe, node_id, prev_node_pos):
176
177
node_id (str): selected node id to insert.
177
178
prev_node_pos (dict): previous node position. {NodeItem: [prev_x, prev_y]}
178
179
"""
180
+ if not self ._editable :
181
+ return
179
182
node = self .get_node_by_id (node_id )
180
183
181
184
# exclude the BackdropNode
@@ -203,6 +206,8 @@ def _toggle_tab_search(self):
203
206
"""
204
207
toggle the tab search widget.
205
208
"""
209
+ if not self ._editable :
210
+ return
206
211
if self ._viewer .underMouse ():
207
212
self ._viewer .tab_search_set_nodes (self ._node_factory .names )
208
213
self ._viewer .tab_search_toggle ()
@@ -217,6 +222,8 @@ def _on_property_bin_changed(self, node_id, prop_name, prop_value):
217
222
prop_name (str): node property name.
218
223
prop_value (object): python object.
219
224
"""
225
+ if not self ._editable :
226
+ return
220
227
node = self .get_node_by_id (node_id )
221
228
222
229
# prevent signals from causing a infinite loop.
@@ -307,6 +314,8 @@ def _on_connection_changed(self, disconnected, connected):
307
314
connected (list[list[widgets.port.PortItem]]):
308
315
pair list of port view items.
309
316
"""
317
+ if not self ._editable :
318
+ return
310
319
if not (disconnected or connected ):
311
320
return
312
321
@@ -336,7 +345,7 @@ def _on_connection_sliced(self, ports):
336
345
ports (list[list[widgets.port.PortItem]]):
337
346
pair list of port connections (in port, out port)
338
347
"""
339
- if not ports :
348
+ if not ports or not self . _editable :
340
349
return
341
350
ptypes = {IN_PORT : 'inputs' , OUT_PORT : 'outputs' }
342
351
self ._undo_stack .beginMacro ('slice connections' )
@@ -385,6 +394,25 @@ def auto_update(self):
385
394
"""
386
395
return self ._auto_update
387
396
397
+ @property
398
+ def editable (self ):
399
+ """
400
+ Returns whether the graph is editable.
401
+ """
402
+ return self ._editable
403
+
404
+ @editable .setter
405
+ def editable (self , state ):
406
+ """
407
+ Set whether the graph is editable.
408
+
409
+ Args:
410
+ state(bool).
411
+ """
412
+ self ._editable = state
413
+ self ._viewer .editable = state
414
+ self ._viewer .scene ().editable = state
415
+
388
416
def show (self ):
389
417
"""
390
418
Show node graph widget this is just a convenience
@@ -513,6 +541,7 @@ def clear_undo_stack(self):
513
541
:meth:`NodeGraph.undo_stack()`
514
542
"""
515
543
self ._undo_stack .clear ()
544
+ gc .collect ()
516
545
517
546
def begin_undo (self , name ):
518
547
"""
@@ -747,6 +776,8 @@ def create_node(self, node_type, name=None, selected=True, color=None,
747
776
Returns:
748
777
NodeGraphQt.BaseNode: the created instance of the node.
749
778
"""
779
+ if not self ._editable :
780
+ return
750
781
NodeCls = self ._node_factory .create_node_instance (node_type )
751
782
if NodeCls :
752
783
node = NodeCls ()
@@ -813,6 +844,8 @@ def add_node(self, node, pos=None, unique_name=True):
813
844
pos (list[float]): node x,y position. (optional)
814
845
unique_name (bool): make node name unique
815
846
"""
847
+ if not self ._editable :
848
+ return
816
849
assert isinstance (node , NodeObject ), 'node must be a Node instance.'
817
850
818
851
wid_types = node .model .__dict__ .pop ('_TEMP_property_widget_types' )
@@ -850,6 +883,10 @@ def set_node_space(self, node):
850
883
if node is not None :
851
884
node .enter ()
852
885
self ._node_space_bar .set_node (node )
886
+ self .editable = node .is_editable ()
887
+ [n .set_editable (self .editable ) for n in node .children () if isinstance (n , BaseNode )]
888
+ else :
889
+ self .editable = True
853
890
854
891
def get_node_space (self ):
855
892
"""
@@ -867,6 +904,8 @@ def delete_node(self, node):
867
904
Args:
868
905
node (NodeGraphQt.BaseNode): node object.
869
906
"""
907
+ if not self ._editable :
908
+ return
870
909
assert isinstance (node , NodeObject ), \
871
910
'node must be a instance of a NodeObject.'
872
911
if node is self .root_node ():
@@ -887,6 +926,8 @@ def delete_nodes(self, nodes):
887
926
Args:
888
927
nodes (list[NodeGraphQt.BaseNode]): list of node instances.
889
928
"""
929
+ if not self ._editable :
930
+ return
890
931
root_node = self .root_node ()
891
932
self .nodes_deleted .emit ([n .id for n in nodes ])
892
933
self ._undo_stack .beginMacro ('delete nodes' )
@@ -1056,7 +1097,7 @@ def clear_session(self):
1056
1097
continue
1057
1098
self ._undo_stack .push (NodeRemovedCmd (self , n ))
1058
1099
self .set_node_space (root_node )
1059
- self ._undo_stack . clear ()
1100
+ self .clear_undo_stack ()
1060
1101
self ._model .session = None
1061
1102
self .session_changed .emit ("" )
1062
1103
@@ -1082,9 +1123,7 @@ def _serialize(self, nodes):
1082
1123
node_dict = n .model .to_dict
1083
1124
1084
1125
if isinstance (n , SubGraph ):
1085
- published = n .has_property ('published' )
1086
- if published :
1087
- published = n .get_property ('published' )
1126
+ published = n .get_property ('published' )
1088
1127
if not published :
1089
1128
children = n .children ()
1090
1129
if children :
@@ -1132,6 +1171,8 @@ def _deserialize(self, data, relative_pos=False, pos=None, set_parent=True):
1132
1171
Returns:
1133
1172
list[NodeGraphQt.Nodes]: list of node instances.
1134
1173
"""
1174
+ if not self ._editable :
1175
+ return
1135
1176
nodes = {}
1136
1177
# build the nodes.
1137
1178
for n_id , n_data in data .get ('nodes' , {}).items ():
@@ -1148,18 +1189,18 @@ def _deserialize(self, data, relative_pos=False, pos=None, set_parent=True):
1148
1189
for prop , val in n_data .get ('custom' , {}).items ():
1149
1190
node .model .set_property (prop , val )
1150
1191
nodes [n_id ] = node
1151
- self .add_node (node , n_data .get ('pos' ), unique_name = set_parent )
1152
- node .set_disabled (n_data .get ('disabled' , False ))
1192
+
1153
1193
if isinstance (node , SubGraph ):
1154
- if n_data .get ('custom' , None ):
1155
- published = n_data ['custom' ].get ('published' , False )
1156
- else :
1157
- published = False
1194
+ node .create_by_deserialize = True
1195
+ self .add_node (node , n_data .get ('pos' ), unique_name = set_parent )
1196
+ published = n_data ['custom' ].get ('published' , False )
1158
1197
if not published :
1159
1198
sub_graph = n_data .get ('sub_graph' , None )
1160
1199
if sub_graph :
1161
1200
children = self ._deserialize (sub_graph , relative_pos , pos , False )
1162
1201
[child .set_parent (node ) for child in children ]
1202
+ else :
1203
+ self .add_node (node , n_data .get ('pos' ), unique_name = set_parent )
1163
1204
1164
1205
if n_data .get ('dynamic_port' , None ):
1165
1206
node .set_ports ({'input_ports' : n_data ['input_ports' ], 'output_ports' : n_data ['output_ports' ]})
@@ -1212,7 +1253,7 @@ def deserialize_session(self, layout_data):
1212
1253
"""
1213
1254
self .clear_session ()
1214
1255
self ._deserialize (layout_data )
1215
- self ._undo_stack . clear ()
1256
+ self .clear_undo_stack ()
1216
1257
1217
1258
def save_session (self , file_path ):
1218
1259
"""
@@ -1287,7 +1328,7 @@ def import_session(self, file_path):
1287
1328
self .set_grid_mode (layout_data ['graph' ].get ('grid_mode' , VIEWER_GRID_LINES ))
1288
1329
1289
1330
self .set_node_space (self .root_node ())
1290
- self ._undo_stack . clear ()
1331
+ self .clear_undo_stack ()
1291
1332
self ._model .session = file_path
1292
1333
self .session_changed .emit (file_path )
1293
1334
self ._auto_update = _temp_auto_update
@@ -1325,6 +1366,8 @@ def paste_nodes(self):
1325
1366
"""
1326
1367
Pastes nodes copied from the clipboard.
1327
1368
"""
1369
+ if not self ._editable :
1370
+ return
1328
1371
clipboard = QtWidgets .QApplication .clipboard ()
1329
1372
cb_text = clipboard .text ()
1330
1373
if not cb_text :
@@ -1346,7 +1389,7 @@ def duplicate_nodes(self, nodes):
1346
1389
Returns:
1347
1390
list[NodeGraphQt.BaseNode]: list of duplicated node instances.
1348
1391
"""
1349
- if not nodes :
1392
+ if not nodes or not self . _editable :
1350
1393
return
1351
1394
1352
1395
self ._undo_stack .beginMacro ('duplicate nodes' )
@@ -1374,7 +1417,7 @@ def disable_nodes(self, nodes, mode=None):
1374
1417
nodes (list[NodeGraphQt.BaseNode]): list of node instances.
1375
1418
mode (bool): (optional) disable state of the nodes.
1376
1419
"""
1377
- if not nodes :
1420
+ if not nodes or not self . _editable :
1378
1421
return
1379
1422
if mode is None :
1380
1423
mode = not nodes [0 ].disabled ()
0 commit comments