Skip to content

Commit 1400b56

Browse files
authored
Merge pull request #156 from cesioarg/features
General Clean up and add drag and drop to graph
2 parents 90eca1e + 7c7d373 commit 1400b56

File tree

11 files changed

+1533
-47
lines changed

11 files changed

+1533
-47
lines changed

NodeGraphQt/base/graph.py

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,29 @@
2323
from NodeGraphQt.widgets.viewer import NodeViewer
2424

2525

26+
class QWidgetDrops(QtWidgets.QWidget):
27+
def dragEnterEvent(self, event):
28+
if event.mimeData().hasUrls:
29+
event.accept()
30+
else:
31+
event.ignore()
32+
33+
def dragMoveEvent(self, event):
34+
if event.mimeData().hasUrls:
35+
event.accept()
36+
else:
37+
event.ignore()
38+
39+
def dropEvent(self, event):
40+
if event.mimeData().hasUrls:
41+
event.setDropAction(QtCore.Qt.CopyAction)
42+
event.accept()
43+
for url in event.mimeData().urls():
44+
self.import_session(url.toLocalFile())
45+
else:
46+
e.ignore()
47+
48+
2649
class NodeGraph(QtCore.QObject):
2750
"""
2851
The ``NodeGraph`` class is the main controller for managing all nodes.
@@ -110,6 +133,7 @@ def __init__(self, parent=None):
110133
self._viewer.need_show_tab_search.connect(self._toggle_tab_search)
111134

112135
self._wire_signals()
136+
self.widget.setAcceptDrops(True)
113137

114138
def __repr__(self):
115139
return '<{} object at {}>'.format(self.__class__.__name__, hex(id(self)))
@@ -325,8 +349,10 @@ def widget(self):
325349
PySide2.QtWidgets.QWidget: node graph widget.
326350
"""
327351
if self._widget is None:
328-
self._widget = QtWidgets.QWidget()
329-
layout = QtWidgets.QVBoxLayout(self._widget)
352+
self._widget = QWidgetDrops()
353+
self._widget.import_session = self.import_session
354+
355+
layout = QtWidgets.QVBoxLayout(self._widget)
330356
layout.setContentsMargins(0, 0, 0, 0)
331357
layout.addWidget(self._viewer)
332358
return self._widget
@@ -1046,16 +1072,25 @@ def save_session(self, file_path):
10461072
def load_session(self, file_path):
10471073
"""
10481074
Load node graph session layout file.
1075+
1076+
Args:
1077+
file_path (str): path to the serialized layout file.
1078+
"""
1079+
self.clear_session()
1080+
self.import_session(file_path)
10491081

1082+
def import_session(self, file_path):
1083+
"""
1084+
Import node graph session layout file.
1085+
10501086
Args:
10511087
file_path (str): path to the serialized layout file.
10521088
"""
1089+
10531090
file_path = file_path.strip()
10541091
if not os.path.isfile(file_path):
10551092
raise IOError('file does not exist.')
10561093

1057-
self.clear_session()
1058-
10591094
try:
10601095
with open(file_path) as data_file:
10611096
layout_data = json.load(data_file)

NodeGraphQt/base/utils.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ def setup_context_menu(graph):
3333

3434
# create "File" menu.
3535
file_menu.add_command('Open...', _open_session, QtGui.QKeySequence.Open)
36+
file_menu.add_command('Import...', _import_session, QtGui.QKeySequence.Open)
3637
file_menu.add_command('Save...', _save_session, QtGui.QKeySequence.Save)
3738
file_menu.add_command('Save As...', _save_session_as, 'Ctrl+Shift+s')
3839
file_menu.add_command('New Session', _new_session)
@@ -119,6 +120,20 @@ def _open_session(graph):
119120
graph.load_session(file_path)
120121

121122

123+
def _import_session(graph):
124+
"""
125+
Prompts a file open dialog to load a session.
126+
127+
Args:
128+
graph (NodeGraphQt.NodeGraph): node graph.
129+
"""
130+
current = graph.current_session()
131+
viewer = graph.viewer()
132+
file_path = viewer.load_dialog(current)
133+
if file_path:
134+
graph.import_session(file_path)
135+
136+
122137
def _save_session(graph):
123138
"""
124139
Prompts a file save dialog to serialize a session if required.

example_math_nodes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,6 @@ def show_nodes_list(node):
4141

4242
# registered nodes.
4343
[graph.register_node(n) for n in Nodes]
44-
graph.load_session('example.nodes')
44+
graph.load_session(r'example_nodes\networks\example.nodes')
4545

4646
app.exec_()

example_nodes/__init__.py

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,58 @@
11
#!/usr/bin/python
22
import os
33
import sys
4-
import inspect
5-
import importlib
4+
import ast
5+
6+
7+
VALID_NODE_TYPE = ['BaseNode', 'AutoNode']
8+
9+
10+
def detectNodesFromText(filepath):
11+
"""returns Node names from a python script"""
12+
froms = []
13+
14+
with open(filepath, "r") as source:
15+
tree = ast.parse(source.read())
16+
17+
for node in tree.body:
18+
if isinstance(node, ast.ClassDef):
19+
for base in node.bases:
20+
if base.id in VALID_NODE_TYPE:
21+
for indef in node.body:
22+
if isinstance(indef, ast.Assign):
23+
for target in indef.targets:
24+
if target.id == '__identifier__':
25+
froms.append(node.name)
26+
return froms
627

728

829
def getNodesRecursively(path=__file__):
30+
""" Returns imported nodes. """
931
Nodes = []
1032
basedir, filename = os.path.split(path)
33+
rootModule = os.path.basename(basedir)
34+
1135
for root, dirs, files in os.walk(basedir, topdown=False):
1236
if root not in sys.path:
1337
sys.path.append(root)
1438

1539
for name in files:
1640
if name.endswith('.py') and not name.startswith('_'):
17-
module_name = name[:-3]
18-
module = importlib.import_module(module_name)
19-
for name, obj in inspect.getmembers(module):
20-
if inspect.isclass(obj) and not obj.__name__ == 'BaseNode':
21-
for clsObj in inspect.getmro(obj):
22-
if clsObj.__name__ == 'BaseNode':
23-
Nodes.append(obj)
24-
break
41+
module_name = root.split(rootModule)[1].replace('\\', '.') + name[:-3]
42+
modulePath = os.path.join(root, name)
43+
froms = detectNodesFromText(modulePath)
44+
if not froms:
45+
continue
46+
47+
try:
48+
mod = __import__(module_name, globals(), locals(), froms, 0)
49+
for node in froms:
50+
Nodes.append(getattr(mod, node))
51+
52+
except ImportError as e:
53+
print ('Error in importing class: %s' % (e))
54+
continue
55+
2556
return Nodes
2657

2758

example_nodes/input_nodes.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import os
12
from NodeGraphQt import BaseNode, QtCore
23

34

@@ -64,7 +65,7 @@ def run(self):
6465
data = fread.read()
6566
self.set_property('output', data)
6667
else:
67-
print('No existe %s' % path)
68+
print("%s doesn't exist!" % path)
6869
self.set_property('output', '')
6970

7071

example.nodes renamed to example_nodes/networks/example.nodes

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"nodes":{
3-
"0x15095e08":{
3+
"0x150eccc8":{
44
"type_":"Viewers.DataViewerNode",
55
"icon":null,
66
"name":"Output",
@@ -27,14 +27,14 @@
2727
"width":170,
2828
"height":91.0,
2929
"pos":[
30-
149.0,
31-
-146.0
30+
602.4100268187593,
31+
341.7567828173967
3232
],
3333
"custom":{
3434
"data":""
3535
}
3636
},
37-
"0x15126848":{
37+
"0x150f5588":{
3838
"type_":"Inputs.BoolInputNode",
3939
"icon":null,
4040
"name":"Bool",
@@ -61,15 +61,15 @@
6161
"width":170,
6262
"height":103.0,
6363
"pos":[
64-
-413.0,
65-
-212.0
64+
40.41002681875926,
65+
275.7567828173967
6666
],
6767
"custom":{
6868
"out":true,
6969
"combo":"True"
7070
}
7171
},
72-
"0x15140308":{
72+
"0x150f5d88":{
7373
"type_":"Logics.BooleanNode",
7474
"icon":null,
7575
"name":"Boolean",
@@ -96,15 +96,15 @@
9696
"width":170,
9797
"height":103.0,
9898
"pos":[
99-
-143.0,
100-
-149.0
99+
310.41002681875943,
100+
338.7567828173967
101101
],
102102
"custom":{
103103
"out":null,
104104
"funcs":"and"
105105
}
106106
},
107-
"0x1514a4c8":{
107+
"0x1510e948":{
108108
"type_":"Inputs.BoolInputNode",
109109
"icon":null,
110110
"name":"Bool 1",
@@ -131,8 +131,8 @@
131131
"width":170,
132132
"height":103.0,
133133
"pos":[
134-
-411.25,
135-
-61.5
134+
42.16002681875926,
135+
426.2567828173967
136136
],
137137
"custom":{
138138
"out":true,
@@ -143,31 +143,31 @@
143143
"connections":[
144144
{
145145
"in":[
146-
"0x15095e08",
146+
"0x150eccc8",
147147
"data"
148148
],
149149
"out":[
150-
"0x15140308",
150+
"0x150f5d88",
151151
"out"
152152
]
153153
},
154154
{
155155
"out":[
156-
"0x15126848",
156+
"0x150f5588",
157157
"out"
158158
],
159159
"in":[
160-
"0x15140308",
160+
"0x150f5d88",
161161
"a"
162162
]
163163
},
164164
{
165165
"in":[
166-
"0x15140308",
166+
"0x150f5d88",
167167
"b"
168168
],
169169
"out":[
170-
"0x1514a4c8",
170+
"0x1510e948",
171171
"out"
172172
]
173173
}

0 commit comments

Comments
 (0)