diff --git a/NodeGraphQt/base/graph.py b/NodeGraphQt/base/graph.py index c448fc76..bd62af80 100644 --- a/NodeGraphQt/base/graph.py +++ b/NodeGraphQt/base/graph.py @@ -774,7 +774,7 @@ def add_node(self, node, pos=None): node_attrs[node.type_][pname].update(pattrs) self.model.set_node_common_properties(node_attrs) - node._graph = self + node.set_graph(self) node.NODE_NAME = self.get_unique_name(node.NODE_NAME) node.model._graph_model = self.model node.model.name = node.NODE_NAME @@ -1006,6 +1006,7 @@ def _deserialize(self, data, relative_pos=False, pos=None): nodes[n_id] = node self.add_node(node, n_data.get('pos')) + node.set_graph(self) # build the connections. for connection in data.get('connections', []): diff --git a/NodeGraphQt/base/model.py b/NodeGraphQt/base/model.py index eb0d4f86..4da929dd 100644 --- a/NodeGraphQt/base/model.py +++ b/NodeGraphQt/base/model.py @@ -92,7 +92,8 @@ def __init__(self): } def add_property(self, name, value, items=None, range=None, - widget_type=NODE_PROP, tab='Properties', ext=None): + widget_type=NODE_PROP, tab='Properties', + ext=None, funcs=None): """ add custom property. @@ -104,6 +105,7 @@ def add_property(self, name, value, items=None, range=None, widget_type (int): widget type flag. tab (str): widget tab name. ext (str) file ext for NODE_PROP_FILE + funcs (list) functions for NODE_PROP_BUTTON """ tab = tab or 'Properties' @@ -125,6 +127,8 @@ def add_property(self, name, value, items=None, range=None, self._TEMP_property_attrs[name]['range'] = range if ext: self._TEMP_property_attrs[name]['ext'] = ext + if funcs: + self._TEMP_property_attrs[name]['funcs'] = funcs else: attrs = {self.type_: {name: { 'widget_type': widget_type, @@ -136,6 +140,8 @@ def add_property(self, name, value, items=None, range=None, attrs[self.type_][name]['range'] = range if ext: attrs[self.type_][name]['ext'] = ext + if funcs: + attrs[self.type_][name]['funcs'] = funcs self._graph_model.set_node_common_properties(attrs) def set_property(self, name, value): @@ -144,7 +150,8 @@ def set_property(self, name, value): elif name in self._custom_prop.keys(): self._custom_prop[name] = value else: - raise NodePropertyError('No property "{}"'.format(name)) + self._custom_prop[name] = value + # raise NodePropertyError('No property "{}"'.format(name)) def get_property(self, name): if name in self.properties.keys(): @@ -248,6 +255,7 @@ def to_dict(self): json.dumps(v) except: to_remove.append(k) + [custom_props.pop(k) for k in to_remove] node_dict['custom'] = custom_props diff --git a/NodeGraphQt/base/node.py b/NodeGraphQt/base/node.py index 7cedb3eb..70b2e34f 100644 --- a/NodeGraphQt/base/node.py +++ b/NodeGraphQt/base/node.py @@ -237,7 +237,8 @@ def set_selected(self, selected=True): self.set_property('selected', selected) def create_property(self, name, value, items=None, range=None, - widget_type=NODE_PROP, tab=None, ext=None): + widget_type=NODE_PROP, tab=None, ext=None, + funcs=None): """ Creates a custom property to the node. @@ -269,8 +270,9 @@ def create_property(self, name, value, items=None, range=None, widget_type (int): widget flag to display in the ``PropertiesBinWidget`` tab (str): name of the widget tab to display in the properties bin. ext (str): file ext of ``NODE_PROP_FILE`` + funcs (list) list of functions for NODE_PROP_BUTTON """ - self.model.add_property(name, value, items, range, widget_type, tab, ext) + self.model.add_property(name, value, items, range, widget_type, tab, ext, funcs) def properties(self): """ @@ -567,11 +569,8 @@ def add_file_input(self, name, label='', text='', tab=None, ext="*"): tab (str): name of the widget tab to display in. ext (str): file ext """ - self.model.add_property(name, text, None, None, NODE_PROP_FILE, tab, ext) - # use create_property will cause strange error - # self.create_property( - # name, text, widget_type=NODE_PROP_FILE, tab=tab, ext=None) - + self.create_property( + name, text, widget_type=NODE_PROP_FILE, tab=tab, ext=ext) widget = NodeFilePath(self.view, name, label, text, ext) widget.value_changed.connect(lambda k, v: self.set_property(k, v)) self.view.add_widget(widget) @@ -705,6 +704,21 @@ def add_output(self, name='output', multi_output=True, display_name=True, self.model.outputs[port.name()] = port.model return port + def update_combo_menu(self, name, items): + if not self.has_property(name): + return + old_value = self.get_property(name) + self.set_property(name, items) + _name = '_'+name+"_" + if not self.has_property(_name): + self.create_property(_name, items) + else: + self.set_property(_name, items) + if old_value in items: + self.set_property(name, old_value) + else: + self.set_property(name, items[0]) + def inputs(self): """ Returns all the input ports from the node. diff --git a/NodeGraphQt/qgraphics/node_base.py b/NodeGraphQt/qgraphics/node_base.py index a757372c..2bae0c76 100644 --- a/NodeGraphQt/qgraphics/node_base.py +++ b/NodeGraphQt/qgraphics/node_base.py @@ -691,6 +691,9 @@ def get_widget(self, name): return widget raise NodeWidgetError('node has no widget "{}"'.format(name)) + def has_widget(self, name): + return name in self._widgets.keys() + def delete(self): for port, text in self._input_items.items(): port.delete() diff --git a/NodeGraphQt/widgets/actions.py b/NodeGraphQt/widgets/actions.py index 7b33f2b8..d11785e3 100644 --- a/NodeGraphQt/widgets/actions.py +++ b/NodeGraphQt/widgets/actions.py @@ -27,7 +27,7 @@ def get_menu(self, name, node_id=None): return menu if node_id and menu.node_class: node = menu.graph.get_node_by_id(node_id) - if isinstance(node,menu.node_class): + if isinstance(node, menu.node_class): return menu def get_menus(self, node_class): @@ -35,7 +35,7 @@ def get_menus(self, node_class): for action in self.actions(): menu = action.menu() if menu.node_class: - if issubclass(menu.node_class,node_class): + if issubclass(menu.node_class, node_class): menus.append(menu) return menus diff --git a/NodeGraphQt/widgets/node_widgets.py b/NodeGraphQt/widgets/node_widgets.py index 47ab743a..2a7e5c66 100644 --- a/NodeGraphQt/widgets/node_widgets.py +++ b/NodeGraphQt/widgets/node_widgets.py @@ -192,6 +192,10 @@ def value(self): @value.setter def value(self, text=''): + if type(text) is list: + self._combo.clear() + self._combo.addItems(text) + return if text != self.value: index = self._combo.findText(text, QtCore.Qt.MatchExactly) self._combo.setCurrentIndex(index) diff --git a/NodeGraphQt/widgets/properties.py b/NodeGraphQt/widgets/properties.py index 4d5c8102..14248421 100644 --- a/NodeGraphQt/widgets/properties.py +++ b/NodeGraphQt/widgets/properties.py @@ -245,6 +245,9 @@ def get_value(self): return self.currentText() def set_value(self, value): + if type(value) is list: + self.set_items(value) + return if value != self.get_value(): idx = self.findText(value, QtCore.Qt.MatchExactly) self.setCurrentIndex(idx) @@ -676,10 +679,12 @@ class PropButton(QtWidgets.QPushButton): def __init__(self, parent=None): super(PropButton, self).__init__(parent) - def set_value(self, value): + def set_value(self, value, node=None): # value: list of functions + if type(value) is not list: + return for func in value: - self.clicked.connect(func) + self.clicked.connect(lambda: func(node)) def get_value(self): return None @@ -869,13 +874,19 @@ def _read_node(self, node): widget.setMinimumHeight(min_widget_height) if prop_name in common_props.keys(): if 'items' in common_props[prop_name].keys(): - widget.set_items(common_props[prop_name]['items']) + _prop_name = '_' + prop_name + "_" + if node.has_property(_prop_name): + widget.set_items(node.get_property(_prop_name)) + else: + widget.set_items(common_props[prop_name]['items']) if 'range' in common_props[prop_name].keys(): prop_range = common_props[prop_name]['range'] widget.set_min(prop_range[0]) widget.set_max(prop_range[1]) if 'ext' in common_props[prop_name].keys(): widget.set_ext(common_props[prop_name]['ext']) + if 'funcs' in common_props[prop_name].keys(): + widget.set_value(common_props[prop_name]['funcs'], node) prop_window.add_widget(prop_name, widget, value, prop_name.replace('_', ' ')) diff --git a/NodeGraphQt/widgets/viewer.py b/NodeGraphQt/widgets/viewer.py index 7d8a689a..6ca3c444 100644 --- a/NodeGraphQt/widgets/viewer.py +++ b/NodeGraphQt/widgets/viewer.py @@ -131,7 +131,7 @@ def _set_viewer_zoom(self, value, sensitivity=None, pos=None): self.scale(scale, scale, pos) def _set_viewer_pan(self, pos_x, pos_y): - speed = self._scene_range.width() * 0.002 + speed = self._scene_range.width() * 0.0015 x = -pos_x * speed y = -pos_y * speed self._scene_range.adjust(x, y, x, y) @@ -201,7 +201,7 @@ def contextMenuEvent(self, event): nodes = [i for i in items if isinstance(i, AbstractNodeItem)] if nodes: node = nodes[0] - ctx_menu = self._ctx_node_menu.get_menu(node.type_,node.id) + ctx_menu = self._ctx_node_menu.get_menu(node.type_, node.id) if ctx_menu: for action in ctx_menu.actions(): if not action.menu(): @@ -277,10 +277,11 @@ def mousePressEvent(self, event): self._rubber_band.show() # allow new live pipe with the shift modifier. - if self.LMB_state: - if (not self.SHIFT_state and not self.CTRL_state) or\ - (self.SHIFT_state and pipes): - super(NodeViewer, self).mousePressEvent(event) + # if self.LMB_state: + # if (not self.SHIFT_state and not self.CTRL_state) or\ + # (self.SHIFT_state and pipes): + if not self._LIVE_PIPE.isVisible(): + super(NodeViewer, self).mousePressEvent(event) def mouseReleaseEvent(self, event): if event.button() == QtCore.Qt.LeftButton: @@ -397,7 +398,7 @@ def wheelEvent(self, event): if delta == 0: delta = event.angleDelta().x() - self._set_viewer_zoom(delta, pos = event.pos()) + self._set_viewer_zoom(delta, pos=event.pos()) def dropEvent(self, event): pos = self.mapToScene(event.pos()) diff --git a/example_auto_nodes/node_base/auto_node.py b/example_auto_nodes/node_base/auto_node.py index 9a128270..c6b4dae5 100644 --- a/example_auto_nodes/node_base/auto_node.py +++ b/example_auto_nodes/node_base/auto_node.py @@ -25,7 +25,7 @@ def get(self, text, Min=50, Max=200): return self.colors[text] -class AutoNode(BaseNode,QtCore.QObject): +class AutoNode(BaseNode, QtCore.QObject): cooked = QtCore.Signal() def __init__(self, defaultInputType=None, defaultOutputType=None): @@ -75,17 +75,20 @@ def cookTime(self, time): def cookNextNode(self): for nodeList in self.connected_output_nodes().values(): for n in nodeList: - n.cook() + if n is not self: + n.cook() def getData(self, port): # for custom output data return self.get_property(port.name()) def getInputData(self, port): - # get input data by input Port,the type of "port" can be : - # int : Port index - # str : Port name - # Port : Port object + """ + get input data by input Port,the type of "port" can be : + int : Port index + str : Port name + Port : Port object + """ if type(port) is int: to_port = self.input(port) @@ -128,7 +131,7 @@ def cook(self, forceCook=False): try: self.run() except Exception as error: - self.error(error) + self.error(error) self._autoCook = _tmp @@ -202,8 +205,8 @@ def set_port_type(self, port, value_type): current_port.view.setToolTip('{}: {} ({}) '.format(current_port.name(), data_type_name, conn_type)) def create_property(self, name, value, items=None, range=None, - widget_type=NODE_PROP, tab=None): - super(AutoNode, self).create_property(name, value, items, range, widget_type, tab) + widget_type=NODE_PROP, tab=None, ext=None, funcs=None): + super(AutoNode, self).create_property(name, value, items, range, widget_type, tab, ext, funcs) if value is not None: self.set_port_type(name, type(value)) @@ -235,7 +238,6 @@ def set_disabled(self, mode=False): else: self.cook() - def _close_error(self): self._error = False self.set_property('color', self.defaultColor) @@ -250,7 +252,7 @@ def _show_error(self, message): tooltip = '
({})
'.format(message) self._update_tool_tip(tooltip) - def _update_tool_tip(self, message = None): + def _update_tool_tip(self, message=None): if message is None: tooltip = self._toolTip.format(self._cookTime) else: @@ -269,3 +271,8 @@ def error(self, message=None): return self._error self._show_error(message) + + def update_model(self): + if self.error(): + self.set_property('color', self.defaultColor) + super(AutoNode, self).update_model() \ No newline at end of file