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: 1 addition & 1 deletion NodeGraphQt/base/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,7 @@ def set_pipe_style(self, style=PIPE_LAYOUT_CURVED):
pipe_max = max([PIPE_LAYOUT_CURVED,
PIPE_LAYOUT_STRAIGHT,
PIPE_LAYOUT_ANGLE])
style = style if 0 >= style >= pipe_max else PIPE_LAYOUT_CURVED
style = style if 0 <= style <= pipe_max else PIPE_LAYOUT_CURVED
self._viewer.set_pipe_layout(style)

def fit_to_selection(self):
Expand Down
4 changes: 2 additions & 2 deletions NodeGraphQt/base/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ def has_property(self, name):
Returns:
bool: true if property name exists in the Node.
"""
return name in self.model.properties.keys()
return name in self.model.custom_properties.keys()

def set_x_pos(self, x):
"""
Expand Down Expand Up @@ -617,7 +617,7 @@ def output_ports(self):
list[NodeGraphQt.Port]: node output ports.
"""
return self._outputs

def input(self, index):
"""
Return the input port with the matching index.
Expand Down
12 changes: 6 additions & 6 deletions NodeGraphQt/base/port.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,27 +158,27 @@ def connect_to(self, port=None):

if not port:
if pre_conn_port:
undo_stack.push(NodeInputDisconnectedCmd(self, port))
undo_stack.push(PortDisconnectedCmd(self, port))
undo_stack.push(NodeInputDisconnectedCmd(self, port))
return

if graph.acyclic() and viewer.acyclic_check(self.view, port.view):
if pre_conn_port:
undo_stack.push(NodeInputDisconnectedCmd(self, pre_conn_port))
undo_stack.push(PortDisconnectedCmd(self, pre_conn_port))
undo_stack.push(NodeInputDisconnectedCmd(self, pre_conn_port))
return

trg_conn_ports = port.connected_ports()
if not port.multi_connection() and trg_conn_ports:
dettached_port = trg_conn_ports[0]
undo_stack.push(NodeInputDisconnectedCmd(port, dettached_port))
undo_stack.push(PortDisconnectedCmd(port, dettached_port))
undo_stack.push(NodeInputDisconnectedCmd(port, dettached_port))
if pre_conn_port:
undo_stack.push(NodeInputDisconnectedCmd(self, pre_conn_port))
undo_stack.push(PortDisconnectedCmd(self, pre_conn_port))
undo_stack.push(NodeInputDisconnectedCmd(self, pre_conn_port))

undo_stack.push(NodeInputConnectedCmd(self, port))
undo_stack.push(PortConnectedCmd(self, port))
undo_stack.push(NodeInputConnectedCmd(self, port))

undo_stack.endMacro()

Expand All @@ -198,8 +198,8 @@ def disconnect_from(self, port=None):
return
graph = self.node().graph
graph.undo_stack().beginMacro('disconnect port')
graph.undo_stack().push(NodeInputDisconnectedCmd(self, port))
graph.undo_stack().push(PortDisconnectedCmd(self, port))
graph.undo_stack().push(NodeInputDisconnectedCmd(self, port))
graph.undo_stack().endMacro()

# emit "port_disconnected" signal from the parent graph.
Expand Down
249 changes: 249 additions & 0 deletions example_math_nodes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
import os
import inspect
from functools import partial

from NodeGraphQt import (NodeGraph,
BaseNode,
setup_context_menu)
from NodeGraphQt import QtWidgets, QtCore, PropertiesBinWidget, NodeTreeWidget


def update_streams(node):
"""
Update all nodes joined by pipes
"""
nodes = []
trash = []

for port, nodeList in node.connected_output_nodes().items():
nodes.extend(nodeList)

while nodes:
node = nodes.pop()
if node not in trash:
trash.append(node)

for port, nodeList in node.connected_output_nodes().items():
nodes.extend(nodeList)

if not nodes:
try:
node.run()
except Exception as error:
print("Error Update Streams: %s" % str(error))


class DataInputNode(BaseNode):
"""
Input node data.
"""

__identifier__ = 'com.chantasticvfx'
NODE_NAME = 'Input Numbers'

def __init__(self):
super(DataInputNode, self).__init__()
self.output = self.add_output('out')
self.add_text_input('out', 'Data Input', text='4', tab='widgets')
self.view.widgets['out'].value_changed.connect(partial(update_streams, self))

def run(self):
return


def add(a, b):
return a + b


def sub(a, b):
return a - b


def mul(a, b):
return a * b


def div(a, b):
return a / b


# create a dict with all function
funcs = {'add': add, 'sub': sub, 'mul': mul, 'div': div}


class MathFunctionsNode(BaseNode):
"""
Math functions node.

"""

# set a unique node identifier.
__identifier__ = 'com.chantasticvfx'

# set the initial default node name.
NODE_NAME = 'Functions node'

def __init__(self):
super(MathFunctionsNode, self).__init__()
self.set_color(25, 58, 51)
self.add_combo_menu('functions', 'Functions',
items=funcs.keys(), tab='widgets')
# switch math function type
self.view.widgets['functions'].value_changed.connect(self.addFunction)
self.set_property('functions', 'add')
self.view.widgets['functions'].value_changed.connect(
partial(update_streams, self))
self.output = self.add_output('output')
self.create_property(self.output.name(), None)

def addFunction(self, prop, func):
"""
Create inputs based on math functions arguments.
"""
self.func = funcs[func] # add, sub, mul, div

dataFunc = inspect.getargspec(self.func)

for arg in dataFunc.args:
if not self.has_property(arg):
self.add_input(arg)
self.create_property(arg, None)

def run(self):
"""
Evaluate all entries, pass them as arguments of the
chosen mathematical function.
"""
for to_port in self.input_ports():
from_ports = to_port.connected_ports()
if not from_ports:
raise Exception('Port %s not connected!' % to_port.name())

for from_port in from_ports:
from_port.node().run()
data = from_port.node().get_property(from_port.name())
self.set_property(to_port.name(), int(data))

try:
# Execute math function with arguments.
output = self.func(*[self.get_property(prop)
for prop in self.properties()['inputs']])
self.set_property('output', output)
except KeyError as error:
print("An input is missing! %s" % str(error))
except TypeError as error:
print("Error evaluating function: %s" % str(error))

def on_input_connected(self, to_port, from_port):
"""Override node callback method."""
self.set_property(to_port.name(), from_port.node().run())
update_streams(self)

def on_input_disconnected(self, to_port, from_port):
"""Override node callback method."""
self.set_property('output', None)
update_streams(self)


class DataViewerNode(BaseNode):
__identifier__ = 'com.chantasticvfx'
NODE_NAME = 'Result View'

def __init__(self):
super(DataViewerNode, self).__init__()
self.input = self.add_input('in data')
self.add_text_input('data', 'Data Viewer', tab='widgets')

def run(self):
"""Evaluate input to show it."""
for source in self.input.connected_ports():
from_node = source.node()
try:
from_node.run()
except Exception as error:
print("%s no inputs connected: %s" % (from_node.name(), str(error)))
self.set_property('data', None)
return
value = from_node.get_property(source.name())
self.set_property('data', str(value))

def on_input_connected(self, to_port, from_port):
"""Override node callback method"""
self.run()

def on_input_disconnected(self, to_port, from_port):
"""Override node callback method"""
self.set_property('data', None)


if __name__ == '__main__':
app = QtWidgets.QApplication([])

# create node graph.
graph = NodeGraph()

# set up default menu and commands.
setup_context_menu(graph)

# widget used for the node graph.
graph_widget = graph.widget
graph_widget.resize(1100, 800)
graph_widget.show()

# show the properties bin when a node is "double clicked" in the graph.
properties_bin = PropertiesBinWidget(node_graph=graph)
properties_bin.setWindowFlags(QtCore.Qt.Tool)

def show_prop_bin(node):
if not properties_bin.isVisible():
properties_bin.show()
graph.node_double_clicked.connect(show_prop_bin)

# show the nodes list when a node is "double clicked" in the graph.
node_tree = NodeTreeWidget(node_graph=graph)

def show_nodes_list(node):
if not node_tree.isVisible():
node_tree.update()
node_tree.show()
graph.node_double_clicked.connect(show_nodes_list)

# registered nodes.
reg_nodes = [DataInputNode, DataViewerNode, MathFunctionsNode]

for n in reg_nodes:
graph.register_node(n)

my_node = graph.create_node('com.chantasticvfx.MathFunctionsNode',
name='Math Functions A',
color='#0a1e20',
text_color='#feab20',
pos=[-250, 70])

my_node = graph.create_node('com.chantasticvfx.MathFunctionsNode',
name='Math Functions B',
color='#0a1e20',
text_color='#feab20',
pos=[-250, -70])

my_node = graph.create_node('com.chantasticvfx.MathFunctionsNode',
name='Math Functions C',
color='#0a1e20',
text_color='#feab20',
pos=[0, 0])

inputANode = graph.create_node('com.chantasticvfx.DataInputNode',
name='Input A',
pos=[-500, -50])

inputBNode = graph.create_node('com.chantasticvfx.DataInputNode',
name='Input B',
pos=[-500, 50])

outputNode = graph.create_node('com.chantasticvfx.DataViewerNode',
name='Output',
pos=[250, 0])

app.exec_()