Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions NodeGraphQt/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 ===

Expand Down
2 changes: 1 addition & 1 deletion NodeGraphQt/widgets/node_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
69 changes: 48 additions & 21 deletions NodeGraphQt/widgets/properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -333,6 +334,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)
Expand All @@ -357,6 +359,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:
Expand Down Expand Up @@ -389,16 +393,17 @@ 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)

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)

Expand All @@ -407,25 +412,26 @@ 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)

Expand All @@ -448,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
Expand Down Expand Up @@ -506,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)

Expand All @@ -522,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:
Expand All @@ -532,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))

Expand Down Expand Up @@ -656,6 +664,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,
Expand All @@ -671,6 +694,7 @@ def __init__(self, parent=None):
NODE_PROP_VECTOR4: PropVector4,
NODE_PROP_FLOAT: PropFloat,
NODE_PROP_INT: PropInt,
NODE_PROP_BUTTON: PropButton
}


Expand Down Expand Up @@ -710,11 +734,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):
Expand Down
3 changes: 3 additions & 0 deletions NodeGraphQt/widgets/viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
80 changes: 58 additions & 22 deletions example_auto_nodes/node_base/auto_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from NodeGraphQt import QtCore
import random
import copy

import time

def rand_color(seed_type):
seed = id(seed_type)
Expand Down Expand Up @@ -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
Expand All @@ -51,11 +54,24 @@ 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:
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
Expand All @@ -77,38 +93,41 @@ 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):
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

_tmp = self._autoCook
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.cookNextNode()
return

if not self.needCook:
return

_tmp = self._autoCook
self._autoCook = False

if self.error():
self._close_error()

_start_time = time.time()

try:
self.run()
except Exception as error:
self.error(error)

self._autoCook = _tmp

if self.error():
return

self.cookTime = time.time() - _start_time

self.cooked.emit()
self.cookNextNode()

Expand All @@ -128,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
Expand Down Expand Up @@ -203,21 +217,43 @@ 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)
self._view._tooltip_disable(False)
self._update_tool_tip()

def _show_error(self, message):
if not self._error:
self.defaultColor = self.get_property("color")

self._error = True
self.set_property('color', self.errorColor)
tooltip = '<b>{}</b>'.format(self.name())
tooltip += ' <font color="red"><br>({})</br></font>'.format(message)
tooltip += '<br/>{}<br/>'.format(self._view.type_)
self._view.setToolTip(tooltip)
tooltip = '<font color="red"><br>({})</br></font>'.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 = '<b>{}</b>'.format(self.name())
tooltip += message
tooltip += '<br/>{}<br/>'.format(self._view.type_)
self.view.setToolTip(tooltip)
return tooltip

def _setup_tool_tip(self):
tooltip = '<br> last cook used: {}s</br>'
return self._update_tool_tip(tooltip)

def error(self, message=None):
if message is None:
Expand Down