diff --git a/NodeGraphQt/base/graph.py b/NodeGraphQt/base/graph.py index e24eb9a2..1436ed6e 100644 --- a/NodeGraphQt/base/graph.py +++ b/NodeGraphQt/base/graph.py @@ -1210,6 +1210,10 @@ def _deserialize(self, data, relative_pos=False, pos=None, set_parent=True): """ if not self._editable: return + + _temp_auto_update = self._auto_update + self._auto_update = False + nodes = {} # build the nodes. for n_id, n_data in data.get('nodes', {}).items(): @@ -1269,6 +1273,7 @@ def _deserialize(self, data, relative_pos=False, pos=None, set_parent=True): if set_parent: [node.set_parent(self._current_node_space) for node in node_objs] + self._auto_update = _temp_auto_update return node_objs @@ -1340,8 +1345,7 @@ def import_session(self, file_path): Args: file_path (str): path to the serialized layout file. """ - _temp_auto_update = self._auto_update - self._auto_update = False + file_path = file_path.strip() if not os.path.isfile(file_path): raise IOError('file does not exist.') @@ -1368,7 +1372,6 @@ def import_session(self, file_path): self.clear_undo_stack() self._model.session = file_path self.session_changed.emit(file_path) - self._auto_update = _temp_auto_update def copy_nodes(self, nodes=None): """ diff --git a/NodeGraphQt/base/model.py b/NodeGraphQt/base/model.py index 89203bff..8260da03 100644 --- a/NodeGraphQt/base/model.py +++ b/NodeGraphQt/base/model.py @@ -20,7 +20,7 @@ def __init__(self, node): self.multi_connection = False self.visible = True self.connected_ports = defaultdict(list) - self.data_type = 'None' + self.data_type = 'NoneType' def __repr__(self): return '<{}(\'{}\') @ {}>'.format( diff --git a/NodeGraphQt/base/node.py b/NodeGraphQt/base/node.py index 6c45703f..9d94f3c2 100644 --- a/NodeGraphQt/base/node.py +++ b/NodeGraphQt/base/node.py @@ -763,7 +763,7 @@ def add_checkbox(self, name, label='', text='', state=False, tab=None): self.view.add_widget(widget) def add_input(self, name='input', multi_input=False, display_name=True, - color=None, data_type='None', painter_func=None): + color=None, data_type='NoneType', painter_func=None): """ Add input :class:`Port` to node. @@ -803,7 +803,7 @@ def add_input(self, name='input', multi_input=False, display_name=True, return port def add_output(self, name='output', multi_output=True, display_name=True, - color=None, data_type='None', painter_func=None): + color=None, data_type='NoneType', painter_func=None): """ Add output :class:`Port` to node. diff --git a/NodeGraphQt/base/utils.py b/NodeGraphQt/base/utils.py index 822a8083..58b25d98 100644 --- a/NodeGraphQt/base/utils.py +++ b/NodeGraphQt/base/utils.py @@ -85,8 +85,8 @@ def setup_context_menu(graph): edit_menu.add_separator() - edit_menu.add_command('Layout Graph Down Stream', _layout_graph_down, 'L') - edit_menu.add_command('Layout Graph Up Stream', _layout_graph_up, 'Ctrl+L') + edit_menu.add_command('Layout Graph Up Stream', _layout_graph_up, 'L') + edit_menu.add_command('Layout Graph Down Stream', _layout_graph_down, 'Ctrl+L') edit_menu.add_separator() @@ -826,10 +826,14 @@ def minimize_node_ref_count(node): if hasattr(node, 'deleted'): del node return - from .node import BaseNode, SubGraph + from .node import BaseNode + from .graph import SubGraph node._parent = None if isinstance(node, BaseNode): - [wid.deleteLater() for wid in node.view._widgets.values()] + try: + [wid.deleteLater() for wid in node.view._widgets.values()] + except: + pass node.view._widgets.clear() for port in node._inputs: port.model.node = None diff --git a/NodeGraphQt/qgraphics/pipe.py b/NodeGraphQt/qgraphics/pipe.py index 24c1823d..5c1b2b0e 100644 --- a/NodeGraphQt/qgraphics/pipe.py +++ b/NodeGraphQt/qgraphics/pipe.py @@ -384,8 +384,6 @@ def delete(self): self.output_port.remove_pipe(self) if self.scene(): self.scene().removeItem(self) - # TODO: not sure if we need this...? - del self class LivePipe(Pipe): diff --git a/NodeGraphQt/widgets/viewer.py b/NodeGraphQt/widgets/viewer.py index ef7169ea..5d41784b 100644 --- a/NodeGraphQt/widgets/viewer.py +++ b/NodeGraphQt/widgets/viewer.py @@ -251,7 +251,6 @@ def mousePressEvent(self, event): items = self._items_near(map_pos, None, 20, 20) nodes = [i for i in items if isinstance(i, AbstractNodeItem)] - pipes = [i for i in items if isinstance(i, Pipe)] if nodes: self.MMB_state = False @@ -735,7 +734,7 @@ def tab_search_set_nodes(self, nodes): self._search_widget.set_nodes(nodes) def tab_search_toggle(self): - if type(self._search_widget) is TabSearchMenuWidget: + if isinstance(self._search_widget, TabSearchMenuWidget): return pos = self._previous_pos @@ -753,7 +752,7 @@ def tab_search_toggle(self): self.clearFocus() def rebuild_tab_search(self): - if type(self._search_widget) is TabSearchMenuWidget: + if isinstance(self._search_widget, TabSearchMenuWidget): self._search_widget.rebuild = True def context_menus(self): diff --git a/example.py b/example.py index cfba8b8c..9965ca9d 100644 --- a/example.py +++ b/example.py @@ -135,6 +135,7 @@ def __init__(self): if __name__ == '__main__': + QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling) app = QtWidgets.QApplication([]) # create node graph. diff --git a/example_auto_nodes.py b/example_auto_nodes.py index 0c96f03b..103abd6e 100644 --- a/example_auto_nodes.py +++ b/example_auto_nodes.py @@ -47,6 +47,7 @@ def get_published_nodes_from_folder(folder_path): if __name__ == '__main__': + QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling) app = QtWidgets.QApplication() # create node graph. diff --git a/example_auto_nodes/data_node.py b/example_auto_nodes/data_node.py index c5bf7f8f..3c56d158 100644 --- a/example_auto_nodes/data_node.py +++ b/example_auto_nodes/data_node.py @@ -5,7 +5,7 @@ class VectorSplit(AutoNode): """ - Splict a vector to x,y,z + Split a vector to x,y,z """ __identifier__ = 'Data' @@ -49,7 +49,7 @@ def __init__(self): super(VectorMaker, self).__init__() self.add_output('out', list) - self.create_property("out",None) + self.create_property("out", None) self.add_input("x", float) self.add_input("y", float) diff --git a/example_auto_nodes/networks/example_SubGraph.json b/example_auto_nodes/networks/example_SubGraph.json index 1e381167..345d2b44 100644 --- a/example_auto_nodes/networks/example_SubGraph.json +++ b/example_auto_nodes/networks/example_SubGraph.json @@ -1,6 +1,6 @@ { "nodes":{ - "0x1c874156488":{ + "0x17f3e2d7b08":{ "type_":"Inputs.Vector3InputNode", "icon":null, "name":"Vector 6", @@ -33,13 +33,7 @@ 1229.2270073169514 ], "custom":{ - "autoCook":true, - "default_color":[ - 13, - 18, - 23, - 255 - ], + "auto_cook":true, "out":[ 2.0, 0.0, @@ -47,10 +41,51 @@ ] } }, - "0x1c872d61a48":{ - "type_":"Custom.Distance", + "0x17f3e2db648":{ + "type_":"Inputs.Vector3InputNode", "icon":null, - "name":"Distance", + "name":"Vector 1", + "color":[ + 13, + 18, + 23, + 255 + ], + "border_color":[ + 74, + 84, + 85, + 255 + ], + "text_color":[ + 255, + 255, + 255, + 180 + ], + "disabled":false, + "selected":true, + "visible":true, + "dynamic_port":false, + "width":170, + "height":80, + "pos":[ + 453.25455062884396, + 286.4559843936471 + ], + "custom":{ + "auto_cook":true, + "out":[ + 5.0, + 2.0, + 2.0 + ] + } + }, + "0x17f3e308d08":{ + "type_":"Custom.Cross_Product", + "icon":null, + "name":"Cross Product", "color":[ 36, 97, @@ -74,10 +109,10 @@ "visible":true, "dynamic_port":true, "width":170, - "height":86.0, + "height":94.0, "pos":[ - 807.1827263231012, - 388.68161853520036 + 807.1827263231013, + 780.44801182068 ], "input_ports":[ { @@ -102,18 +137,12 @@ } ], "custom":{ - "autoCook":true, - "default_color":[ - 13, - 18, - 23, - 255 - ], + "auto_cook":true, "graph_rect":[ - 124.44323723701683, - -60.24013089798626, - 1542.340175197216, - 1451.6142825385552 + -435.67905012250253, + -49.5251261608848, + 1741.228265197031, + 375.77709769823343 ], "published":true, "input count":2, @@ -121,10 +150,10 @@ "create_from_select":false } }, - "0x1c8753116c8":{ - "type_":"Inputs.Vector3InputNode", + "0x17f3f49fc48":{ + "type_":"Viewers.DataViewerNode", "icon":null, - "name":"Vector 2", + "name":"Result View 1", "color":[ 13, 18, @@ -147,35 +176,30 @@ "selected":true, "visible":true, "dynamic_port":false, - "width":170, - "height":80, + "width":243.0, + "height":97.0, "pos":[ - 454.0167492061021, - 470.38062384195075 + 1168.9255987050249, + 775.0158843263519 ], "custom":{ - "autoCook":true, - "default_color":[ - 13, - 18, - 23, - 255 - ], + "auto_cook":true, + "data":"[3.0, -2.0, 0.0]", "out":[ - 10.0, - 2.0, - 2.0 + 3.0, + -2.0, + 0.0 ] } }, - "0x1c8741705c8":{ - "type_":"Inputs.Vector3InputNode", + "0x17f3e30cc88":{ + "type_":"Custom.Dot_Product", "icon":null, - "name":"Vector 1", + "name":"Dot Product", "color":[ - 13, - 18, - 23, + 36, + 97, + 100, 255 ], "border_color":[ @@ -193,32 +217,53 @@ "disabled":false, "selected":true, "visible":true, - "dynamic_port":false, + "dynamic_port":true, "width":170, - "height":80, + "height":94.0, "pos":[ - 453.25455062884396, - 286.4559843936471 + 814.7746429589047, + 1120.8014926015035 + ], + "input_ports":[ + { + "name":"input0", + "multi_connection":false, + "display_name":true, + "data_type":"None" + }, + { + "name":"input1", + "multi_connection":false, + "display_name":true, + "data_type":"None" + } + ], + "output_ports":[ + { + "name":"output0", + "multi_connection":true, + "display_name":true, + "data_type":"None" + } ], "custom":{ - "autoCook":true, - "default_color":[ - 13, - 18, - 23, - 255 + "auto_cook":true, + "graph_rect":[ + 267.85670937024156, + -207.36298023006623, + 1066.9861577818897, + 1004.2222661476602 ], - "out":[ - 5.0, - 2.0, - 2.0 - ] + "published":true, + "input count":2, + "output count":1, + "create_from_select":false } }, - "0x1c87416dd88":{ - "type_":"Inputs.Vector3InputNode", + "0x17f3e303f48":{ + "type_":"Viewers.DataViewerNode", "icon":null, - "name":"Vector 4", + "name":"Result View", "color":[ 13, 18, @@ -241,31 +286,22 @@ "selected":true, "visible":true, "dynamic_port":false, - "width":170, - "height":80, + "width":243.0, + "height":97.0, "pos":[ - 455.8742304029088, - 881.4349497471972 + 1163.3987364418397, + 391.1813579826517 ], "custom":{ - "autoCook":true, - "default_color":[ - 13, - 18, - 23, - 255 - ], - "out":[ - 0.0, - 0.0, - 1.0 - ] + "auto_cook":true, + "data":"5.0000000000", + "out":5.0 } }, - "0x1c874168c08":{ - "type_":"Viewers.DataViewerNode", + "0x17f3e3070c8":{ + "type_":"Inputs.Vector3InputNode", "icon":null, - "name":"Result View", + "name":"Vector 5", "color":[ 13, 18, @@ -288,28 +324,25 @@ "selected":true, "visible":true, "dynamic_port":false, - "width":222.33333333333331, - "height":91.0, + "width":170, + "height":80, "pos":[ - 1163.3987364418397, - 391.1813579826517 + 452.9037437055922, + 1054.8695311801075 ], "custom":{ - "autoCook":true, - "default_color":[ - 13, - 18, - 23, - 255 - ], - "data":"5.0000000000", - "out":5.0 + "auto_cook":true, + "out":[ + 20.0, + 0.0, + 0.0 + ] } }, - "0x1c87416b048":{ - "type_":"Viewers.DataViewerNode", + "0x17f2fe3e9c8":{ + "type_":"Inputs.Vector3InputNode", "icon":null, - "name":"Result View 2", + "name":"Vector 3", "color":[ 13, 18, @@ -332,28 +365,25 @@ "selected":true, "visible":true, "dynamic_port":false, - "width":222.33333333333331, - "height":91.0, + "width":170, + "height":80, "pos":[ - 1177.2962257618165, - 1119.6816415773787 + 456.3976677920282, + 712.8463768277693 ], "custom":{ - "autoCook":true, - "default_color":[ - 13, - 18, - 23, - 255 - ], - "data":"40.0000000000", - "out":40.0 + "auto_cook":true, + "out":[ + 2.0, + 3.0, + 0.0 + ] } }, - "0x1c874170b08":{ - "type_":"Custom.Dot_Product", + "0x17f3e2f5b88":{ + "type_":"Custom.Distance", "icon":null, - "name":"Dot Product", + "name":"Distance", "color":[ 36, 97, @@ -377,10 +407,10 @@ "visible":true, "dynamic_port":true, "width":170, - "height":86.0, + "height":94.0, "pos":[ - 814.7746429589047, - 1120.8014926015035 + 807.1827263231012, + 388.68161853520036 ], "input_ports":[ { @@ -405,18 +435,12 @@ } ], "custom":{ - "autoCook":true, - "default_color":[ - 13, - 18, - 23, - 255 - ], + "auto_cook":true, "graph_rect":[ - 267.85670937024156, - -207.36298023006623, - 1066.9861577818897, - 1004.2222661476602 + 124.44323723701683, + -60.24013089798626, + 1542.340175197216, + 1451.6142825385552 ], "published":true, "input count":2, @@ -424,10 +448,10 @@ "create_from_select":false } }, - "0x1c859465088":{ + "0x17f3e30f408":{ "type_":"Inputs.Vector3InputNode", "icon":null, - "name":"Vector 5", + "name":"Vector 4", "color":[ 13, 18, @@ -453,28 +477,22 @@ "width":170, "height":80, "pos":[ - 452.9037437055922, - 1054.8695311801075 + 455.8742304029088, + 881.4349497471972 ], "custom":{ - "autoCook":true, - "default_color":[ - 13, - 18, - 23, - 255 - ], + "auto_cook":true, "out":[ - 20.0, 0.0, - 0.0 + 0.0, + 1.0 ] } }, - "0x1c875311c08":{ + "0x17f3f49f5c8":{ "type_":"Viewers.DataViewerNode", "icon":null, - "name":"Result View 1", + "name":"Result View 2", "color":[ 13, 18, @@ -497,32 +515,22 @@ "selected":true, "visible":true, "dynamic_port":false, - "width":222.33333333333331, - "height":91.0, + "width":243.0, + "height":97.0, "pos":[ - 1168.9255987050249, - 775.0158843263519 + 1177.2962257618165, + 1119.6816415773787 ], "custom":{ - "autoCook":true, - "default_color":[ - 13, - 18, - 23, - 255 - ], - "data":"[3.0, -2.0, 0.0]", - "out":[ - 3.0, - -2.0, - 0.0 - ] + "auto_cook":true, + "data":"40.0000000000", + "out":40.0 } }, - "0x1c874170908":{ + "0x17f3e2f5448":{ "type_":"Inputs.Vector3InputNode", "icon":null, - "name":"Vector 3", + "name":"Vector 2", "color":[ 13, 18, @@ -548,188 +556,108 @@ "width":170, "height":80, "pos":[ - 456.3976677920282, - 712.8463768277693 + 454.0167492061021, + 470.38062384195075 ], "custom":{ - "autoCook":true, - "default_color":[ - 13, - 18, - 23, - 255 - ], + "auto_cook":true, "out":[ + 10.0, 2.0, - 3.0, - 0.0 + 2.0 ] } - }, - "0x1c874156e48":{ - "type_":"Custom.Cross_Product", - "icon":null, - "name":"Cross Product", - "color":[ - 36, - 97, - 100, - 255 - ], - "border_color":[ - 74, - 84, - 85, - 255 - ], - "text_color":[ - 255, - 255, - 255, - 180 - ], - "disabled":false, - "selected":true, - "visible":true, - "dynamic_port":true, - "width":170, - "height":86.0, - "pos":[ - 807.1827263231013, - 780.44801182068 - ], - "input_ports":[ - { - "name":"input0", - "multi_connection":false, - "display_name":true, - "data_type":"None" - }, - { - "name":"input1", - "multi_connection":false, - "display_name":true, - "data_type":"None" - } - ], - "output_ports":[ - { - "name":"output0", - "multi_connection":true, - "display_name":true, - "data_type":"None" - } - ], - "custom":{ - "autoCook":true, - "default_color":[ - 13, - 18, - 23, - 255 - ], - "graph_rect":[ - -435.67905012250253, - -49.5251261608848, - 1741.228265197031, - 375.77709769823343 - ], - "published":true, - "input count":2, - "output count":1, - "create_from_select":false - } } }, "connections":[ { "out":[ - "0x1c874156488", + "0x17f3e2d7b08", "out" ], "in":[ - "0x1c874170b08", + "0x17f3e30cc88", "input1" ] }, + { + "out":[ + "0x17f3e2db648", + "out" + ], + "in":[ + "0x17f3e2f5b88", + "input0" + ] + }, { "in":[ - "0x1c872d61a48", + "0x17f3e308d08", "input0" ], "out":[ - "0x1c8741705c8", + "0x17f2fe3e9c8", "out" ] }, { "in":[ - "0x1c872d61a48", + "0x17f3e308d08", "input1" ], "out":[ - "0x1c8753116c8", + "0x17f3e30f408", "out" ] }, { "out":[ - "0x1c872d61a48", + "0x17f3e308d08", "output0" ], "in":[ - "0x1c874168c08", + "0x17f3f49fc48", "in data" ] }, { + "in":[ + "0x17f3e30cc88", + "input0" + ], "out":[ - "0x1c87416dd88", + "0x17f3e3070c8", "out" - ], - "in":[ - "0x1c874156e48", - "input1" ] }, { - "in":[ - "0x1c87416b048", - "in data" - ], "out":[ - "0x1c874170b08", + "0x17f3e30cc88", "output0" - ] - }, - { - "in":[ - "0x1c874170b08", - "input0" ], - "out":[ - "0x1c859465088", - "out" + "in":[ + "0x17f3f49f5c8", + "in data" ] }, { "in":[ - "0x1c875311c08", + "0x17f3e303f48", "in data" ], "out":[ - "0x1c874156e48", + "0x17f3e2f5b88", "output0" ] }, { + "in":[ + "0x17f3e2f5b88", + "input1" + ], "out":[ - "0x1c874170908", + "0x17f3e2f5448", "out" - ], - "in":[ - "0x1c874156e48", - "input0" ] } ], @@ -737,10 +665,10 @@ "node_space":"0000000000000", "pipe_layout":0, "graph_rect":[ - 488.82494495974424, - 362.3012370553538, - 949.6771572075074, - 893.8137950188301 + 450.82667111036204, + 294.0331487339252, + 1067.9275607970987, + 1005.1082925149151 ], "grid_mode":1 } diff --git a/example_auto_nodes/node_base/auto_node.py b/example_auto_nodes/node_base/auto_node.py index c9c96d89..fe81a924 100644 --- a/example_auto_nodes/node_base/auto_node.py +++ b/example_auto_nodes/node_base/auto_node.py @@ -1,32 +1,10 @@ -from NodeGraphQt import BaseNode, Port, QtCore -from . utils import update_node_down_stream +from NodeGraphQt import BaseNode, Port, QtCore, QtWidgets, QtGui +from . utils import update_node_down_stream, get_data_type, CryptoColors import traceback -import hashlib import copy import time -class CryptoColors(object): - """ - Generate random color based on strings - """ - - def __init__(self): - self.colors = {} - - def get(self, text, Min=50, Max=200): - if text in self.colors: - return self.colors[text] - h = hashlib.sha256(text.encode('utf-8')).hexdigest() - d = int('0xFFFFFFFFFFFFFFFF', 0) - r = int(Min + (int("0x" + h[:16], 0) / d) * (Max - Min)) - g = int(Min + (int("0x" + h[16:32], 0) / d) * (Max - Min)) - b = int(Min + (int("0x" + h[32:48], 0) / d) * (Max - Min)) - # a = int(Min + (int("0x" + h[48:], 0) / d) * (Max - Min)) - self.colors[text] = (r, g, b, 255) - return self.colors[text] - - class AutoNode(BaseNode, QtCore.QObject): cooked = QtCore.Signal() @@ -38,10 +16,8 @@ def __init__(self, defaultInputType=None, defaultOutputType=None): self.matchTypes = [['float', 'int']] self.errorColor = (200, 50, 50) self.stopCookColor = (200, 200, 200) - self._cryptoColors = CryptoColors() self.create_property('auto_cook', True) - self.create_property('default_color', self.get_property('color')) self.defaultValue = None self.defaultInputType = defaultInputType self.defaultOutputType = defaultOutputType @@ -49,6 +25,12 @@ def __init__(self, defaultInputType=None, defaultOutputType=None): self._cook_time = 0.0 self._toolTip = self._setup_tool_tip() + # effect + self.color_effect = QtWidgets.QGraphicsColorizeEffect() + self.color_effect.setStrength(0.7) + self.color_effect.setEnabled(False) + self.view.setGraphicsEffect(self.color_effect) + @property def auto_cook(self): """ @@ -70,12 +52,9 @@ def auto_cook(self, mode): return self.model.set_property('auto_cook', mode) - if mode: - self.set_property('color', self.get_property('default_color')) - else: - if not self._error: - self.model.set_property('default_color', self.get_property('color')) - self.set_property('color', self.stopCookColor) + self.color_effect.setEnabled(not mode) + if not mode: + self.color_effect.setColor(QtGui.QColor(*self.stopCookColor)) @property def cook_time(self): @@ -114,7 +93,7 @@ def update_stream(self, forceCook=False): """ if not forceCook: - if not self.auto_cook or not self.get_input_data: + if not self.auto_cook or not self._need_cook: return if self.graph is not None and not self.graph.auto_update: return @@ -200,12 +179,12 @@ def on_input_connected(self, to_port, from_port): if self.check_port_type(to_port, from_port): self.update_stream() else: - self.get_input_data = False + self._need_cook = False to_port.disconnect_from(from_port) def on_input_disconnected(self, to_port, from_port): - if not self.get_input_data: - self.get_input_data = True + if not self._need_cook: + self._need_cook = True return self.update_stream() @@ -222,7 +201,7 @@ def check_port_type(self, to_port, from_port): """ if to_port.data_type != from_port.data_type: - if to_port.data_type == 'None' or from_port.data_type == 'None': + if to_port.data_type == 'NoneType' or from_port.data_type == 'NoneType': return True for types in self.matchTypes: if to_port.data_type in types and from_port.data_type in types: @@ -264,30 +243,26 @@ def set_port_type(self, port, data_type: str): else: current_port.data_type = data_type - current_port.border_color = current_port.color = self._cryptoColors.get(data_type) + current_port.border_color = current_port.color = CryptoColors.get(data_type) conn_type = 'multi' if current_port.multi_connection() else 'single' current_port.view.setToolTip('{}: {} ({}) '.format(current_port.name(), data_type, conn_type)) - def add_input(self, name='input', data_type='None', multi_input=False, display_name=True, - color=None): - new_port = super(AutoNode, self).add_input(name, multi_input, display_name, color) - if data_type == 'None' and self.defaultInputType is not None: + def add_input(self, name='input', data_type='', multi_input=False, display_name=True, + color=None, painter_func=None): + new_port = super(AutoNode, self).add_input(name, multi_input, display_name, + color, data_type, painter_func) + if data_type == '': data_type = self.defaultInputType - if type(data_type) is not str: - data_type = data_type.__name__ - self.set_port_type(new_port, data_type) - + self.set_port_type(new_port, get_data_type(data_type)) return new_port - def add_output(self, name='output', data_type='None', multi_output=True, display_name=True, - color=None): - new_port = super(AutoNode, self).add_output(name, multi_output, display_name, color) - if data_type == 'None' and self.defaultOutputType is not None: + def add_output(self, name='output', data_type='', multi_output=True, display_name=True, + color=None, painter_func=None): + new_port = super(AutoNode, self).add_output(name, multi_output, display_name, + color, data_type, painter_func) + if data_type == '': data_type = self.defaultOutputType - if type(data_type) is not str: - data_type = data_type.__name__ - self.set_port_type(new_port, data_type) - + self.set_port_type(new_port, get_data_type(data_type)) return new_port def set_disabled(self, mode=False): @@ -300,7 +275,7 @@ def _close_error(self): """ self._error = False - self.set_property('color', self.get_property('default_color')) + self.color_effect.setEnabled(False) self._update_tool_tip() def _update_tool_tip(self, message=None): @@ -338,11 +313,9 @@ def error(self, message): message(str): the describe of the error. """ - if not self._error: - self.model.set_property('default_color', self.get_property('color')) - self._error = True - self.set_property('color', self.errorColor) + self.color_effect.setEnabled(True) + self.color_effect.setColor(QtGui.QColor(*self.errorColor)) tooltip = '
({})
'.format(message) self._update_tool_tip(tooltip) diff --git a/example_auto_nodes/node_base/utils.py b/example_auto_nodes/node_base/utils.py index 81496a15..7a068fd2 100644 --- a/example_auto_nodes/node_base/utils.py +++ b/example_auto_nodes/node_base/utils.py @@ -1,4 +1,5 @@ from NodeGraphQt import topological_sort_by_down, NodePublishWidget +import hashlib # node stream update @@ -22,8 +23,41 @@ def update_nodes(nodes): _update_nodes(topological_sort_by_down(all_nodes=nodes)) +# auto node + +def get_data_type(data_type): + if not isinstance(data_type, str): + if hasattr(data_type, '__name__'): + data_type = data_type.__name__ + else: + data_type = type(data_type).__name__ + return data_type + + +class CryptoColors(object): + """ + Generate random color based on strings + """ + + colors = {} + + @staticmethod + def get(text, Min=50, Max=200): + if text in CryptoColors.colors: + return CryptoColors.colors[text] + h = hashlib.sha256(text.encode('utf-8')).hexdigest() + d = int('0xFFFFFFFFFFFFFFFF', 0) + r = int(Min + (int("0x" + h[:16], 0) / d) * (Max - Min)) + g = int(Min + (int("0x" + h[16:32], 0) / d) * (Max - Min)) + b = int(Min + (int("0x" + h[32:48], 0) / d) * (Max - Min)) + # a = int(Min + (int("0x" + h[48:], 0) / d) * (Max - Min)) + CryptoColors.colors[text] = (r, g, b, 255) + return CryptoColors.colors[text] + + # node menu + def setup_node_menu(graph, published_node_class): from .auto_node import AutoNode from .subgraph_node import SubGraphNode diff --git a/example_auto_nodes/subgraph_nodes.py b/example_auto_nodes/subgraph_nodes.py index 24659fc1..56763c60 100644 --- a/example_auto_nodes/subgraph_nodes.py +++ b/example_auto_nodes/subgraph_nodes.py @@ -145,11 +145,11 @@ def create_node_class(file_path): if not data: return None try: - class_name =data['node']['class_name'] + class_name = data['node']['class_name'] new_node_class = type(class_name, (Publish,), {'NODE_FILE': file_path}) new_node_class.__identifier__ = data['node']['__identifier__'] new_node_class.NODE_NAME = data['node']['name'] return new_node_class except: print('file {} is not a correct published node.'.format(file_path)) - return None \ No newline at end of file + return None diff --git a/example_auto_nodes/viewer_nodes.py b/example_auto_nodes/viewer_nodes.py index 74c71a82..5ce3d26f 100644 --- a/example_auto_nodes/viewer_nodes.py +++ b/example_auto_nodes/viewer_nodes.py @@ -8,9 +8,9 @@ class DataViewerNode(AutoNode): def __init__(self): super(DataViewerNode, self).__init__() self.add_input('in data') - self.add_text_input('data', 'Data Viewer',multi_line=True) + self.add_text_input('data', 'Data Viewer', multi_line=True) self.add_output("out") - self.create_property("out",None) + self.create_property("out", None) def run(self): """Evaluate input to show it.""" diff --git a/example_math_nodes.py b/example_math_nodes.py index 2469837c..2c5e1bd1 100644 --- a/example_math_nodes.py +++ b/example_math_nodes.py @@ -8,6 +8,7 @@ if __name__ == '__main__': + QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling) app = QtWidgets.QApplication([]) # create node graph.