From 17ab198ee51de7bcb32633992c6566b223d4d420 Mon Sep 17 00:00:00 2001 From: ArnoChenFx Date: Thu, 6 Feb 2020 18:23:01 +0800 Subject: [PATCH 1/4] upgrade value edit --- NodeGraphQt/widgets/node_widgets.py | 2 +- NodeGraphQt/widgets/properties.py | 28 +++++++++++++++++----------- NodeGraphQt/widgets/viewer.py | 3 +++ 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/NodeGraphQt/widgets/node_widgets.py b/NodeGraphQt/widgets/node_widgets.py index 33c8ec8e..47ab743a 100644 --- a/NodeGraphQt/widgets/node_widgets.py +++ b/NodeGraphQt/widgets/node_widgets.py @@ -417,7 +417,7 @@ def __init__(self, parent=None, name='', label='', text='', ext="*"): self._ext = ext def _on_select_file(self): - file_path = file_dialog.getOpenFileName() + file_path = file_dialog.getOpenFileName(ext_filter=self._ext) file = file_path[0] or None if file: self.value = file diff --git a/NodeGraphQt/widgets/properties.py b/NodeGraphQt/widgets/properties.py index 819914f2..427c2fa6 100644 --- a/NodeGraphQt/widgets/properties.py +++ b/NodeGraphQt/widgets/properties.py @@ -333,6 +333,7 @@ class _valueMenu(QtWidgets.QMenu): mouseMove = QtCore.Signal(object) mouseRelease = QtCore.Signal(object) + stepChange = QtCore.Signal() def __init__(self, parent=None): super(_valueMenu, self).__init__(parent) @@ -357,6 +358,8 @@ def mouseMoveEvent(self, event): action = self.actionAt(event.pos()) if action: + if action is not self.last_action: + self.stepChange.emit() self.last_action = action self.step = action.step elif self.last_action: @@ -389,9 +392,9 @@ def __init__(self, parent=None): self._data_type = float self.setText("0") - self.pre_x = 0 + self.pre_x = None + self.pre_val = None self._step = 1 - self._tmp_value = 0 self._speed = 0.1 self.textChanged.connect(self._on_text_changed) @@ -399,6 +402,7 @@ def __init__(self, parent=None): self.menu = _valueMenu() self.menu.mouseMove.connect(self.mouseMoveEvent) self.menu.mouseRelease.connect(self.mouseReleaseEvent) + self.menu.stepChange.connect(self._reset) steps = [0.001, 0.01, 0.1, 1, 10, 100, 1000] self.menu.set_steps(steps) @@ -407,25 +411,27 @@ def __init__(self, parent=None): def _on_text_changed(self, value): self.valueChanged.emit(self.value()) + def _reset(self): + self.pre_x = None + def mouseMoveEvent(self, event): if self.mid_state: if self.pre_x is None: self.pre_x = event.x() - self.set_step(self.menu.step) - delta = (event.x() - self.pre_x) - self._tmp_value += delta * self._speed * self._step - if abs(self._tmp_value) > self._step: - value = self.value() + delta * self._step + self.pre_val = self.value() + else: + self.set_step(self.menu.step) + delta = event.x() - self.pre_x + value = self.pre_val + int(delta*self._speed) * self._step self.setValue(value) - self._tmp_value = 0 - self.pre_x = event.x() + + super(_valueEdit,self).mouseMoveEvent(event) def mousePressEvent(self, event): if event.button() == QtCore.Qt.MiddleButton: self.mid_state = True - self.pre_x = None - self._tmp_value = 0 + self._reset() self.menu.exec_(QtGui.QCursor.pos()) super(_valueEdit,self).mousePressEvent(event) diff --git a/NodeGraphQt/widgets/viewer.py b/NodeGraphQt/widgets/viewer.py index 2482bae1..0725f222 100644 --- a/NodeGraphQt/widgets/viewer.py +++ b/NodeGraphQt/widgets/viewer.py @@ -246,6 +246,9 @@ def mousePressEvent(self, event): 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 + # toggle extend node selection. if self.LMB_state: if self.SHIFT_state: From a8dd16eb11b51942d137dc99a37cac647392d858 Mon Sep 17 00:00:00 2001 From: ArnoChenFx Date: Thu, 6 Feb 2020 22:02:47 +0800 Subject: [PATCH 2/4] add button node_prop && fix autoCook bug --- NodeGraphQt/constants.py | 2 + NodeGraphQt/widgets/properties.py | 27 ++++++++++-- example_auto_nodes/node_base/auto_node.py | 51 +++++++++++++++++++---- 3 files changed, 67 insertions(+), 13 deletions(-) diff --git a/NodeGraphQt/constants.py b/NodeGraphQt/constants.py index 59ef50e4..7e5c7ae2 100644 --- a/NodeGraphQt/constants.py +++ b/NodeGraphQt/constants.py @@ -81,6 +81,8 @@ NODE_PROP_FLOAT = 14 #: Property type represented with int widget in the properties bin. NODE_PROP_INT = 15 +#: Property type represented with button widget in the properties bin. +NODE_PROP_BUTTON = 16 # === NODE VIEWER === diff --git a/NodeGraphQt/widgets/properties.py b/NodeGraphQt/widgets/properties.py index 427c2fa6..e0762e7b 100644 --- a/NodeGraphQt/widgets/properties.py +++ b/NodeGraphQt/widgets/properties.py @@ -15,7 +15,8 @@ NODE_PROP_VECTOR3, NODE_PROP_VECTOR4, NODE_PROP_FLOAT, - NODE_PROP_INT) + NODE_PROP_INT, + NODE_PROP_BUTTON) from NodeGraphQt.widgets.file_dialog import file_dialog @@ -425,7 +426,6 @@ def mouseMoveEvent(self, event): value = self.pre_val + int(delta*self._speed) * self._step self.setValue(value) - super(_valueEdit,self).mouseMoveEvent(event) def mousePressEvent(self, event): @@ -662,6 +662,21 @@ def __init__(self, parent=None): self.set_data_type(int) +class PropButton(QtWidgets.QPushButton): + value_changed = QtCore.Signal(str, object) + + def __init__(self, parent=None): + super(PropButton, self).__init__(parent) + + def set_value(self, value): + # value: list of functions + for func in value: + self.clicked.connect(func) + + def get_value(self): + return None + + WIDGET_MAP = { NODE_PROP_QLABEL: PropLabel, NODE_PROP_QLINEEDIT: PropLineEdit, @@ -677,6 +692,7 @@ def __init__(self, parent=None): NODE_PROP_VECTOR4: PropVector4, NODE_PROP_FLOAT: PropFloat, NODE_PROP_INT: PropInt, + NODE_PROP_BUTTON: PropButton } @@ -716,11 +732,14 @@ def add_widget(self, name, widget, value, label=None): if row > 0: row += 1 + label = QtWidgets.QLabel(label) label_flags = QtCore.Qt.AlignCenter | QtCore.Qt.AlignRight if widget.__class__.__name__ == 'PropTextEdit': label_flags = label_flags | QtCore.Qt.AlignTop - - self.__layout.addWidget(QtWidgets.QLabel(label), row, 0, label_flags) + elif widget.__class__.__name__ == 'PropButton': + label.setVisible(False) + widget.setText(name) + self.__layout.addWidget(label, row, 0, label_flags) self.__layout.addWidget(widget, row, 1) def get_widget(self, name): diff --git a/example_auto_nodes/node_base/auto_node.py b/example_auto_nodes/node_base/auto_node.py index fd0aeffc..56c9807e 100644 --- a/example_auto_nodes/node_base/auto_node.py +++ b/example_auto_nodes/node_base/auto_node.py @@ -4,7 +4,7 @@ from NodeGraphQt import QtCore import random import copy - +import time def rand_color(seed_type): seed = id(seed_type) @@ -35,6 +35,9 @@ def __init__(self, defaultInputType=None, defaultOutputType=None): self.defaultInputType = defaultInputType self.defaultOutputType = defaultOutputType + self._cookTime = 0.0 + self._toolTip = self._setup_tool_tip() + @property def autoCook(self): return self._autoCook @@ -51,6 +54,15 @@ def autoCook(self, mode): self.defaultColor = self.get_property("color") self.set_property('color', self.stopCookColor) + @property + def cookTime(self): + return self._cookTime + + @autoCook.setter + def cookTime(self, time): + self._cookTime = time + self._update_tool_tip() + def cookNextNode(self): for nodeList in self.connected_output_nodes().values(): for n in nodeList: @@ -80,6 +92,11 @@ def getInputData(self, port): data = from_port.node().get_property(from_port.name()) return copy.deepcopy(data) + def when_disabled(self): + num = len(self.input_ports()) + for index, out_port in enumerate(self.output_ports()): + self.set_property(out_port.name(), self.getInputData(index % num)) + def cook(self, forceCook=False): if not self._autoCook and forceCook is not True: return @@ -88,18 +105,20 @@ def cook(self, forceCook=False): self._autoCook = False if self.disabled(): - num = len(self.input_ports()) - for index, out_port in enumerate(self.output_ports()): - self.set_property(out_port.name(), self.getInputData(index % num)) + self._autoCook = _tmp + self.when_disabled() self.cookNextNode() return if not self.needCook: + self._autoCook = _tmp return if self.error(): self._close_error() + _start_time = time.time() + try: self.run() except Exception as error: @@ -109,6 +128,8 @@ def cook(self, forceCook=False): if self.error(): return + self.cookTime = time.time() - _start_time + self.cooked.emit() self.cookNextNode() @@ -206,7 +227,7 @@ def add_output(self, name='output', data_type=None, multi_output=True, display_n def _close_error(self): self._error = False self.set_property('color', self.defaultColor) - self._view._tooltip_disable(False) + self._update_tool_tip() def _show_error(self, message): if not self._error: @@ -214,10 +235,22 @@ def _show_error(self, message): self._error = True self.set_property('color', self.errorColor) - tooltip = '{}'.format(self.name()) - tooltip += '
({})
'.format(message) - tooltip += '
{}
'.format(self._view.type_) - self._view.setToolTip(tooltip) + tooltip = '
({})
'.format(message) + self._update_tool_tip(tooltip) + + def _update_tool_tip(self, message = None): + if message is None: + tooltip = self._toolTip.format(self._cookTime) + else: + tooltip = '{}'.format(self.name()) + tooltip += message + tooltip += '
{}
'.format(self._view.type_) + self.view.setToolTip(tooltip) + return tooltip + + def _setup_tool_tip(self): + tooltip = '
last cook used: {}s
' + return self._update_tool_tip(tooltip) def error(self, message=None): if message is None: From ca4f9c3a2967be0fcfac67128f1a7ed2e83fd3dc Mon Sep 17 00:00:00 2001 From: ArnoChenFx Date: Fri, 7 Feb 2020 14:50:45 +0800 Subject: [PATCH 3/4] fix value slider edit update bug --- NodeGraphQt/widgets/properties.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/NodeGraphQt/widgets/properties.py b/NodeGraphQt/widgets/properties.py index e0762e7b..588c10e1 100644 --- a/NodeGraphQt/widgets/properties.py +++ b/NodeGraphQt/widgets/properties.py @@ -454,8 +454,10 @@ def set_data_type(self, dt): def _convert_text(self,text): # int("1.0") will return error # so we use int(float("1.0")) - - value = float(text) + try: + value = float(text) + except: + value = 0.0 if self._data_type is int: value = int(value) return value @@ -512,14 +514,13 @@ def __init__(self, parent=None): self._lock = False def _on_edit_changed(self,value): - if self._lock: - return - self._lock = True self._set_slider_value(value) self.valueChanged.emit(self._edit.value()) - self._lock = False def _on_slider_changed(self,value): + if self._lock: + self._lock = False + return value = value / float(self._mul) self._edit.setValue(value) @@ -528,7 +529,7 @@ def _set_slider_value(self,value): if value == self._slider.value(): return - + self._lock = True _min = self._slider.minimum() _max = self._slider.maximum() if _min<=value<=_max: @@ -538,6 +539,7 @@ def _set_slider_value(self,value): elif value > _max and self._slider.value() != _max: self._slider.setValue(_max) + def set_min(self, value=0): self._slider.setMinimum(int(value*self._mul)) From ffae9351ab907375b6f62c9911539acee68a8bc9 Mon Sep 17 00:00:00 2001 From: ArnoChenFx Date: Fri, 7 Feb 2020 15:55:11 +0800 Subject: [PATCH 4/4] update AutoNode --- example_auto_nodes/node_base/auto_node.py | 35 ++++++++++++----------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/example_auto_nodes/node_base/auto_node.py b/example_auto_nodes/node_base/auto_node.py index 56c9807e..fc6b5159 100644 --- a/example_auto_nodes/node_base/auto_node.py +++ b/example_auto_nodes/node_base/auto_node.py @@ -68,6 +68,10 @@ def cookNextNode(self): for n in nodeList: 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 @@ -89,7 +93,7 @@ def getInputData(self, port): return copy.deepcopy(self.defaultValue) for from_port in from_ports: - data = from_port.node().get_property(from_port.name()) + data = from_port.node().getData(from_port) return copy.deepcopy(data) def when_disabled(self): @@ -101,19 +105,12 @@ def cook(self, forceCook=False): if not self._autoCook and forceCook is not True: return - _tmp = self._autoCook - self._autoCook = False - - if self.disabled(): - self._autoCook = _tmp - self.when_disabled() - self.cookNextNode() - return - if not self.needCook: - self._autoCook = _tmp return + _tmp = self._autoCook + self._autoCook = False + if self.error(): self._close_error() @@ -123,6 +120,7 @@ def cook(self, forceCook=False): self.run() except Exception as error: self.error(error) + self._autoCook = _tmp if self.error(): @@ -149,11 +147,6 @@ def on_input_disconnected(self, to_port, from_port): return self.cook() - def set_disabled(self, mode=False): - super(AutoNode, self).set_disabled(mode) - if self.input_ports(): - self.cook() - def checkPortType(self, to_port, from_port): # None type port can connect with any other type port # types in self.matchTypes can connect with each other @@ -224,6 +217,16 @@ def add_output(self, name='output', data_type=None, multi_output=True, display_n self.set_port_type(new_port, self.defaultOutputType) return new_port + def set_disabled(self, mode=False): + super(AutoNode, self).set_disabled(mode) + self._autoCook = not mode + if mode is True: + self.when_disabled() + self.cookNextNode() + else: + self.cook() + + def _close_error(self): self._error = False self.set_property('color', self.defaultColor)