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
16 changes: 16 additions & 0 deletions NodeGraphQt/base/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ def __init__(self, parent=None):
super(NodeGraph, self).__init__(parent)
self.setObjectName('NodeGraphQt')
self._widget = None
self._undo_view = None
self._model = NodeGraphModel()
self._viewer = NodeViewer()
self._node_factory = NodeFactory()
Expand Down Expand Up @@ -387,6 +388,19 @@ def widget(self):
layout.addWidget(self._viewer)
return self._widget

@property
def undo_view(self):
"""
Returns node graph undo view.

Returns:
PySide2.QtWidgets.QUndoView: node graph undo view.
"""
if self._undo_view is None:
self._undo_view = QtWidgets.QUndoView(self._undo_stack)
self._undo_view.setWindowTitle("Undo View")
return self._undo_view

@property
def auto_update(self):
"""
Expand Down Expand Up @@ -1358,9 +1372,11 @@ def cut_nodes(self, nodes=None):
Args:
nodes (list[NodeGraphQt.BaseNode]): list of nodes (default: selected nodes).
"""
self._undo_stack.beginMacro('cut nodes')
nodes = nodes or self.selected_nodes()
self.copy_nodes(nodes)
self.delete_nodes(nodes)
self._undo_stack.endMacro()

def paste_nodes(self):
"""
Expand Down
16 changes: 10 additions & 6 deletions NodeGraphQt/base/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -1088,12 +1088,6 @@ def run(self):
"""
return

def when_disabled(self):
"""
Node evaluation logic when node has been disabled.
"""
return

def set_editable(self, state):
"""
Returns whether the node view widgets is editable.
Expand All @@ -1104,6 +1098,16 @@ def set_editable(self, state):
[wid.setEnabled(state) for wid in self.view._widgets.values()]
self.view.text_item.setEnabled(state)

def set_dynamic_port(self, state):
"""
Set whether the node will delete/add port after node has been created.

Args:
state(bool): If True, all port data will be serialized with the node,
when the node is been deserialized, all ports will restore.
"""
self.model.dynamic_port = state


class BackdropNode(NodeObject):
"""
Expand Down
1 change: 0 additions & 1 deletion NodeGraphQt/base/port.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,6 @@ def data_type(self):
def data_type(self, data_type):
self.__model.data_type = data_type


@property
def border_color(self):
return self.__view.border_color
Expand Down
12 changes: 8 additions & 4 deletions NodeGraphQt/base/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ def setup_context_menu(graph):

edit_menu.add_separator()
edit_menu.add_command('Clear Undo History', _clear_undo)
edit_menu.add_command('Show Undo View', _show_undo_view)
edit_menu.add_separator()

edit_menu.add_command('Copy', _copy_nodes, QtGui.QKeySequence.Copy)
Expand Down Expand Up @@ -270,6 +271,10 @@ def _jump_out(graph):
graph.set_node_space(node.parent())


def _show_undo_view(graph):
graph.undo_view.show()


def _curved_pipe(graph):
graph.set_pipe_style(PIPE_LAYOUT_CURVED)

Expand Down Expand Up @@ -560,11 +565,10 @@ def _update_nodes(nodes):
nodes (list[NodeGraphQt.BaseNode]): nodes to be run.
"""
for node in nodes:
if node.disabled():
continue
try:
if node.disabled():
node.when_disabled()
else:
node.run()
node.run()
except Exception as error:
print("Error Update Node : {}\n{}" .format(node, str(error)))
break
Expand Down
85 changes: 10 additions & 75 deletions example_auto_nodes.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
import example_auto_nodes
from NodeGraphQt import NodeGraph, setup_context_menu
from NodeGraphQt import QtWidgets, QtCore, PropertiesBinWidget, \
NodeTreeWidget, BackdropNode, NodePublishWidget
import os
import sys
import inspect
from NodeGraphQt import NodeGraph, setup_context_menu, \
QtWidgets, QtCore, PropertiesBinWidget, BackdropNode
from example_auto_nodes import Publish, RootNode, update_nodes, setup_node_menu
import importlib
from example_auto_nodes import AutoNode, ModuleNode, \
SubGraphNode, Publish, RootNode, update_nodes
import inspect
import sys
import os


def get_nodes_from_folder(folder_path):
Expand Down Expand Up @@ -49,58 +46,16 @@ def get_published_nodes_from_folder(folder_path):
return nodes


def cook_node(graph, node):
node.update_stream(forceCook=True)


def print_functions(graph, node):
for func in node.module_functions:
print(func)


def toggle_auto_cook(graph, node):
node.auto_cook = not node.auto_cook


def enter_node(graph, node):
graph.set_node_space(node)


def allow_edit(graph, node):
node.set_property('published', False)


def print_path(graph, node):
print(node.path())


def find_node_by_path(graph, node):
print(graph.get_node_by_path(node.path()))


def print_children(graph, node):
children = node.children()
print(len(children), children)


def publish_node(graph, node):
wid = NodePublishWidget(node=node)
wid.show()


def cook_nodes(nodes):
update_nodes(nodes)


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

# create node graph.
graph = NodeGraph()
graph.use_OpenGL()

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

# show the properties bin when a node is "double clicked" in the graph.
properties_bin = PropertiesBinWidget(node_graph=graph)
Expand All @@ -111,40 +66,20 @@ def show_prop_bin(node):
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)

# register nodes
reg_nodes = get_nodes_from_folder(os.getcwd() + "/example_auto_nodes")
BackdropNode.__identifier__ = 'Utility::Backdrop'
reg_nodes.append(BackdropNode)
reg_nodes.extend(get_published_nodes_from_folder(os.getcwd() + "/example_auto_nodes/published_nodes"))
[graph.register_node(n) for n in reg_nodes]

# setup node menu
node_menu = graph.context_nodes_menu()
node_menu.add_command('Allow Edit', allow_edit, node_class=Publish)
node_menu.add_command('Enter Node', enter_node, node_class=SubGraphNode)
node_menu.add_command('Publish Node', publish_node, node_class=SubGraphNode)
node_menu.add_command('Print Children', print_children, node_class=SubGraphNode)
node_menu.add_command('Print Functions', print_functions, node_class=ModuleNode)
node_menu.add_command('Cook Node', cook_node, node_class=AutoNode)
node_menu.add_command('Toggle Auto Cook', toggle_auto_cook, node_class=AutoNode)
node_menu.add_command('Print Path', print_path, node_class=AutoNode)
node_menu.add_command('Find Node By Path', find_node_by_path, node_class=AutoNode)

# create root node
# if we want to use sub graph system, root node is must.
graph.add_node(RootNode())

# create test nodes
graph.load_session(r'example_auto_nodes/networks/example_SubGraph.json')
cook_nodes(graph.root_node().children())
update_nodes(graph.root_node().children())

# widget used for the node graph.
graph_widget = graph.widget
Expand Down
6 changes: 2 additions & 4 deletions example_auto_nodes/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from .node_base.auto_node import AutoNode
from .node_base.module_node import ModuleNode
from .node_base.subgraph_node import SubGraphNode, RootNode
from .node_base import AutoNode, ModuleNode, SubGraphNode, RootNode
from .subgraph_nodes import Publish
from .node_base.utils import update_node_down_stream, update_nodes
from .node_base.utils import update_node_down_stream, update_nodes, setup_node_menu
2 changes: 1 addition & 1 deletion example_auto_nodes/basic_nodes.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .node_base.auto_node import AutoNode
from .node_base import AutoNode


class FooNode(AutoNode):
Expand Down
2 changes: 1 addition & 1 deletion example_auto_nodes/data_node.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
from .node_base.auto_node import AutoNode
from .node_base import AutoNode


class VectorSplit(AutoNode):
Expand Down
2 changes: 1 addition & 1 deletion example_auto_nodes/input_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
NODE_PROP_VECTOR3,
NODE_PROP_VECTOR4)

from .node_base.auto_node import AutoNode
from .node_base import AutoNode
import os


Expand Down
2 changes: 1 addition & 1 deletion example_auto_nodes/logic_nodes.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .basic_nodes import AutoNode
from .node_base import AutoNode


class IfNode(AutoNode):
Expand Down
12 changes: 6 additions & 6 deletions example_auto_nodes/module_nodes.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from .node_base.module_node import (ModuleNode,
get_functions_from_module,
get_functions_from_type)
from .node_base import (ModuleNode,
get_functions_from_module,
get_functions_from_type)

import os
import sys
Expand Down Expand Up @@ -113,7 +113,8 @@ def is_function(self, obj):
return True
return False

def get_numpy_args(self, func):
@staticmethod
def get_numpy_args(func):
args = []
info = numpydoc.docscrape.FunctionDoc(func)
for i in info["Parameters"]:
Expand All @@ -122,7 +123,7 @@ def get_numpy_args(self, func):
args.append(param.split("'")[1])
return args

def addFunction(self, prop, func):
def add_function(self, prop, func):
"""
Create inputs based on functions arguments.
"""
Expand Down Expand Up @@ -156,7 +157,6 @@ class StringFunctionsNode(ModuleNode):

module_functions = get_functions_from_type(_str)


def __init__(self):
super(StringFunctionsNode, self).__init__()

Expand Down
3 changes: 3 additions & 0 deletions example_auto_nodes/node_base/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .auto_node import AutoNode
from .module_node import ModuleNode, get_functions_from_module, get_functions_from_type
from .subgraph_node import SubGraphNode, SubGraphInputNode, SubGraphOutputNode, RootNode
15 changes: 6 additions & 9 deletions example_auto_nodes/node_base/auto_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,12 @@ def get_data(self, port):
Returns:
node data.
"""
if self.disabled() and self.input_ports():
out_ports = self.output_ports()
if port in out_ports:
idx = out_ports.index(port)
max_idx = max(0, len(self.input_ports()) - 1)
return self.get_input_data(min(idx, max_idx))

return self.get_property(port.name())

Expand All @@ -156,15 +162,6 @@ def get_input_data(self, port):
data = from_port.node().get_data(from_port)
return copy.deepcopy(data)

def when_disabled(self):
"""
Node evaluation logic when node has been disabled.
"""

num = max(0, len(self.input_ports())-1)
for index, out_port in enumerate(self.output_ports()):
self.model.set_property(out_port.name(), self.get_input_data(min(index, num)))

def cook(self):
"""
The entry of the node evaluation.
Expand Down
Loading