forked from bhowiebkr/python-node-editor
-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.py
165 lines (123 loc) · 5.47 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
"""
A simple Node Editor application that allows the user to create, modify and connect nodes of various types.
The application consists of a main window that contains a splitter with a Node List and a Node Widget. The Node List
shows a list of available node types, while the Node Widget is where the user can create, edit and connect nodes.
This application uses PySide6 as a GUI toolkit.
Author: Bryan Howard
Repo: https://github.com/bhowiebkr/simple-node-editor
"""
import logging
from pathlib import Path
import importlib
import inspect
from PySide6 import QtCore, QtGui, QtWidgets
from node_editor.gui.node_list import NodeList
from node_editor.gui.node_widget import NodeWidget
logging.basicConfig(level=logging.DEBUG)
class NodeEditor(QtWidgets.QMainWindow):
OnProjectPathUpdate = QtCore.Signal(Path)
def __init__(self, parent=None):
super().__init__(parent)
self.settings = None
self.project_path = None
self.imports = None # we will store the project import node types here for now.
icon = QtGui.QIcon("resources\\app.ico")
self.setWindowIcon(icon)
self.setWindowTitle("Simple Node Editor")
settings = QtCore.QSettings("node-editor", "NodeEditor")
# create a "File" menu and add an "Export CSV" action to it
file_menu = QtWidgets.QMenu("File", self)
self.menuBar().addMenu(file_menu)
load_action = QtGui.QAction("Load Project", self)
load_action.triggered.connect(self.get_project_path)
file_menu.addAction(load_action)
save_action = QtGui.QAction("Save Project", self)
save_action.triggered.connect(self.save_project)
file_menu.addAction(save_action)
# Layouts
main_widget = QtWidgets.QWidget()
self.setCentralWidget(main_widget)
main_layout = QtWidgets.QHBoxLayout()
main_widget.setLayout(main_layout)
left_layout = QtWidgets.QVBoxLayout()
left_layout.setContentsMargins(0, 0, 0, 0)
# Widgets
self.node_list = NodeList(self)
left_widget = QtWidgets.QWidget()
self.splitter = QtWidgets.QSplitter()
self.node_widget = NodeWidget(self)
# Add Widgets to layouts
self.splitter.addWidget(left_widget)
self.splitter.addWidget(self.node_widget)
left_widget.setLayout(left_layout)
left_layout.addWidget(self.node_list)
main_layout.addWidget(self.splitter)
# Load the example project
example_project_path = (Path(__file__).parent.resolve() / 'Example_project')
self.load_project(example_project_path)
# Restore GUI from last state
if settings.contains("geometry"):
self.restoreGeometry(settings.value("geometry"))
s = settings.value("splitterSize")
self.splitter.restoreState(s)
def save_project(self):
file_dialog = QtWidgets.QFileDialog()
file_dialog.setAcceptMode(QtWidgets.QFileDialog.AcceptSave)
file_dialog.setDefaultSuffix("json")
file_dialog.setNameFilter("JSON files (*.json)")
file_path, _ = file_dialog.getSaveFileName()
self.node_widget.save_project(file_path)
def load_project(self, project_path=None):
if not project_path:
return
project_path = Path(project_path)
if project_path.exists() and project_path.is_dir():
self.project_path = project_path
self.imports = {}
for file in project_path.glob("*.py"):
if not file.stem.endswith('_node'):
print('file:', file.stem)
continue
spec = importlib.util.spec_from_file_location(file.stem, file)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
for name, obj in inspect.getmembers(module):
if not name.endswith('_Node'):
continue
if inspect.isclass(obj):
self.imports[obj.__name__] = {"class": obj, "module": module}
#break
self.node_list.update_project(self.imports)
# work on just the first json file. add the ablitity to work on multiple json files later
for json_path in project_path.glob("*.json"):
self.node_widget.load_scene(json_path, self.imports)
break
def get_project_path(self):
project_path = QtWidgets.QFileDialog.getExistingDirectory(None, "Select Project Folder", "")
if not project_path:
return
self.load_project(project_path)
def closeEvent(self, event):
"""
Handles the close event by saving the GUI state and closing the application.
Args:
event: Close event.
Returns:
None.
"""
# debugging lets save the scene:
# self.node_widget.save_project("C:/Users/Howard/simple-node-editor/Example_Project/test.json")
self.settings = QtCore.QSettings("node-editor", "NodeEditor")
self.settings.setValue("geometry", self.saveGeometry())
self.settings.setValue("splitterSize", self.splitter.saveState())
QtWidgets.QWidget.closeEvent(self, event)
if __name__ == "__main__":
import sys
import qdarktheme
app = QtWidgets.QApplication(sys.argv)
app.setWindowIcon(QtGui.QIcon("resources\\app.ico"))
qdarktheme.setup_theme()
launcher = NodeEditor()
launcher.show()
app.exec()
sys.exit()