Skip to content

Commit 2bba706

Browse files
authored
Merge pull request #141 from cesioarg/master
Some fix I made while implementing a basic evaluation system
2 parents 8973c9d + 2cd5eff commit 2bba706

File tree

3 files changed

+257
-8
lines changed

3 files changed

+257
-8
lines changed

NodeGraphQt/base/node.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ def has_property(self, name):
317317
Returns:
318318
bool: true if property name exists in the Node.
319319
"""
320-
return name in self.model.properties.keys()
320+
return name in self.model.custom_properties.keys()
321321

322322
def set_x_pos(self, x):
323323
"""
@@ -617,7 +617,7 @@ def output_ports(self):
617617
list[NodeGraphQt.Port]: node output ports.
618618
"""
619619
return self._outputs
620-
620+
621621
def input(self, index):
622622
"""
623623
Return the input port with the matching index.

NodeGraphQt/base/port.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -158,27 +158,27 @@ def connect_to(self, port=None):
158158

159159
if not port:
160160
if pre_conn_port:
161-
undo_stack.push(NodeInputDisconnectedCmd(self, port))
162161
undo_stack.push(PortDisconnectedCmd(self, port))
162+
undo_stack.push(NodeInputDisconnectedCmd(self, port))
163163
return
164164

165165
if graph.acyclic() and viewer.acyclic_check(self.view, port.view):
166166
if pre_conn_port:
167-
undo_stack.push(NodeInputDisconnectedCmd(self, pre_conn_port))
168167
undo_stack.push(PortDisconnectedCmd(self, pre_conn_port))
168+
undo_stack.push(NodeInputDisconnectedCmd(self, pre_conn_port))
169169
return
170170

171171
trg_conn_ports = port.connected_ports()
172172
if not port.multi_connection() and trg_conn_ports:
173173
dettached_port = trg_conn_ports[0]
174-
undo_stack.push(NodeInputDisconnectedCmd(port, dettached_port))
175174
undo_stack.push(PortDisconnectedCmd(port, dettached_port))
175+
undo_stack.push(NodeInputDisconnectedCmd(port, dettached_port))
176176
if pre_conn_port:
177-
undo_stack.push(NodeInputDisconnectedCmd(self, pre_conn_port))
178177
undo_stack.push(PortDisconnectedCmd(self, pre_conn_port))
178+
undo_stack.push(NodeInputDisconnectedCmd(self, pre_conn_port))
179179

180-
undo_stack.push(NodeInputConnectedCmd(self, port))
181180
undo_stack.push(PortConnectedCmd(self, port))
181+
undo_stack.push(NodeInputConnectedCmd(self, port))
182182

183183
undo_stack.endMacro()
184184

@@ -198,8 +198,8 @@ def disconnect_from(self, port=None):
198198
return
199199
graph = self.node().graph
200200
graph.undo_stack().beginMacro('disconnect port')
201-
graph.undo_stack().push(NodeInputDisconnectedCmd(self, port))
202201
graph.undo_stack().push(PortDisconnectedCmd(self, port))
202+
graph.undo_stack().push(NodeInputDisconnectedCmd(self, port))
203203
graph.undo_stack().endMacro()
204204

205205
# emit "port_disconnected" signal from the parent graph.

example_math_nodes.py

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
#!/usr/bin/python
2+
# -*- coding: utf-8 -*-
3+
import os
4+
import inspect
5+
from functools import partial
6+
7+
from NodeGraphQt import (NodeGraph,
8+
BaseNode,
9+
setup_context_menu)
10+
from NodeGraphQt import QtWidgets, QtCore, PropertiesBinWidget, NodeTreeWidget
11+
12+
13+
def update_streams(node):
14+
"""
15+
Update all nodes joined by pipes
16+
"""
17+
nodes = []
18+
trash = []
19+
20+
for port, nodeList in node.connected_output_nodes().items():
21+
nodes.extend(nodeList)
22+
23+
while nodes:
24+
node = nodes.pop()
25+
if node not in trash:
26+
trash.append(node)
27+
28+
for port, nodeList in node.connected_output_nodes().items():
29+
nodes.extend(nodeList)
30+
31+
if not nodes:
32+
try:
33+
node.run()
34+
except Exception as error:
35+
print("Error Update Streams: %s" % str(error))
36+
37+
38+
class DataInputNode(BaseNode):
39+
"""
40+
Input node data.
41+
"""
42+
43+
__identifier__ = 'com.chantasticvfx'
44+
NODE_NAME = 'Input Numbers'
45+
46+
def __init__(self):
47+
super(DataInputNode, self).__init__()
48+
self.output = self.add_output('out')
49+
self.add_text_input('out', 'Data Input', text='4', tab='widgets')
50+
self.view.widgets['out'].value_changed.connect(partial(update_streams, self))
51+
52+
def run(self):
53+
return
54+
55+
56+
def add(a, b):
57+
return a + b
58+
59+
60+
def sub(a, b):
61+
return a - b
62+
63+
64+
def mul(a, b):
65+
return a * b
66+
67+
68+
def div(a, b):
69+
return a / b
70+
71+
72+
# create a dict with all function
73+
funcs = {'add': add, 'sub': sub, 'mul': mul, 'div': div}
74+
75+
76+
class MathFunctionsNode(BaseNode):
77+
"""
78+
Math functions node.
79+
80+
"""
81+
82+
# set a unique node identifier.
83+
__identifier__ = 'com.chantasticvfx'
84+
85+
# set the initial default node name.
86+
NODE_NAME = 'Functions node'
87+
88+
def __init__(self):
89+
super(MathFunctionsNode, self).__init__()
90+
self.set_color(25, 58, 51)
91+
self.add_combo_menu('functions', 'Functions',
92+
items=funcs.keys(), tab='widgets')
93+
# switch math function type
94+
self.view.widgets['functions'].value_changed.connect(self.addFunction)
95+
self.set_property('functions', 'add')
96+
self.view.widgets['functions'].value_changed.connect(
97+
partial(update_streams, self))
98+
self.output = self.add_output('output')
99+
self.create_property(self.output.name(), None)
100+
101+
def addFunction(self, prop, func):
102+
"""
103+
Create inputs based on math functions arguments.
104+
"""
105+
self.func = funcs[func] # add, sub, mul, div
106+
107+
dataFunc = inspect.getargspec(self.func)
108+
109+
for arg in dataFunc.args:
110+
if not self.has_property(arg):
111+
self.add_input(arg)
112+
self.create_property(arg, None)
113+
114+
def run(self):
115+
"""
116+
Evaluate all entries, pass them as arguments of the
117+
chosen mathematical function.
118+
"""
119+
for to_port in self.input_ports():
120+
from_ports = to_port.connected_ports()
121+
if not from_ports:
122+
raise Exception('Port %s not connected!' % to_port.name())
123+
124+
for from_port in from_ports:
125+
from_port.node().run()
126+
data = from_port.node().get_property(from_port.name())
127+
self.set_property(to_port.name(), int(data))
128+
129+
try:
130+
# Execute math function with arguments.
131+
output = self.func(*[self.get_property(prop)
132+
for prop in self.properties()['inputs']])
133+
self.set_property('output', output)
134+
except KeyError as error:
135+
print("An input is missing! %s" % str(error))
136+
except TypeError as error:
137+
print("Error evaluating function: %s" % str(error))
138+
139+
def on_input_connected(self, to_port, from_port):
140+
"""Override node callback method."""
141+
self.set_property(to_port.name(), from_port.node().run())
142+
update_streams(self)
143+
144+
def on_input_disconnected(self, to_port, from_port):
145+
"""Override node callback method."""
146+
self.set_property('output', None)
147+
update_streams(self)
148+
149+
150+
class DataViewerNode(BaseNode):
151+
__identifier__ = 'com.chantasticvfx'
152+
NODE_NAME = 'Result View'
153+
154+
def __init__(self):
155+
super(DataViewerNode, self).__init__()
156+
self.input = self.add_input('in data')
157+
self.add_text_input('data', 'Data Viewer', tab='widgets')
158+
159+
def run(self):
160+
"""Evaluate input to show it."""
161+
for source in self.input.connected_ports():
162+
from_node = source.node()
163+
try:
164+
from_node.run()
165+
except Exception as error:
166+
print("%s no inputs connected: %s" % (from_node.name(), str(error)))
167+
self.set_property('data', None)
168+
return
169+
value = from_node.get_property(source.name())
170+
self.set_property('data', str(value))
171+
172+
def on_input_connected(self, to_port, from_port):
173+
"""Override node callback method"""
174+
self.run()
175+
176+
def on_input_disconnected(self, to_port, from_port):
177+
"""Override node callback method"""
178+
self.set_property('data', None)
179+
180+
181+
if __name__ == '__main__':
182+
app = QtWidgets.QApplication([])
183+
184+
# create node graph.
185+
graph = NodeGraph()
186+
187+
# set up default menu and commands.
188+
setup_context_menu(graph)
189+
190+
# widget used for the node graph.
191+
graph_widget = graph.widget
192+
graph_widget.resize(1100, 800)
193+
graph_widget.show()
194+
195+
# show the properties bin when a node is "double clicked" in the graph.
196+
properties_bin = PropertiesBinWidget(node_graph=graph)
197+
properties_bin.setWindowFlags(QtCore.Qt.Tool)
198+
199+
def show_prop_bin(node):
200+
if not properties_bin.isVisible():
201+
properties_bin.show()
202+
graph.node_double_clicked.connect(show_prop_bin)
203+
204+
# show the nodes list when a node is "double clicked" in the graph.
205+
node_tree = NodeTreeWidget(node_graph=graph)
206+
207+
def show_nodes_list(node):
208+
if not node_tree.isVisible():
209+
node_tree.update()
210+
node_tree.show()
211+
graph.node_double_clicked.connect(show_nodes_list)
212+
213+
# registered nodes.
214+
reg_nodes = [DataInputNode, DataViewerNode, MathFunctionsNode]
215+
216+
for n in reg_nodes:
217+
graph.register_node(n)
218+
219+
my_node = graph.create_node('com.chantasticvfx.MathFunctionsNode',
220+
name='Math Functions A',
221+
color='#0a1e20',
222+
text_color='#feab20',
223+
pos=[-250, 70])
224+
225+
my_node = graph.create_node('com.chantasticvfx.MathFunctionsNode',
226+
name='Math Functions B',
227+
color='#0a1e20',
228+
text_color='#feab20',
229+
pos=[-250, -70])
230+
231+
my_node = graph.create_node('com.chantasticvfx.MathFunctionsNode',
232+
name='Math Functions C',
233+
color='#0a1e20',
234+
text_color='#feab20',
235+
pos=[0, 0])
236+
237+
inputANode = graph.create_node('com.chantasticvfx.DataInputNode',
238+
name='Input A',
239+
pos=[-500, -50])
240+
241+
inputBNode = graph.create_node('com.chantasticvfx.DataInputNode',
242+
name='Input B',
243+
pos=[-500, 50])
244+
245+
outputNode = graph.create_node('com.chantasticvfx.DataViewerNode',
246+
name='Output',
247+
pos=[250, 0])
248+
249+
app.exec_()

0 commit comments

Comments
 (0)