Skip to content

Code execution #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Apr 5, 2023
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
13 changes: 13 additions & 0 deletions Example_Project/Add_node.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from node_editor.gui.node import Node


class Add_Node(Node):
def __init__(self):
super().__init__()

self.title = "Add"
self.type_text = "Logic Nodes"
self.add_port(name="input A", is_output=False)
self.add_port(name="input B", is_output=False)
self.add_port(name="output", is_output=True)
self.build()
84 changes: 84 additions & 0 deletions Example_Project/test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
{
"nodes": [
{
"type": "Add_Node",
"x": 5374,
"y": 4897,
"uuid": "6e09cc9a-8b79-4129-bf61-637c6b8eb39b"
},
{
"type": "Add_Node",
"x": 5165,
"y": 5007,
"uuid": "0fe0381a-29bc-4987-ba94-ba4a14e33a13"
},
{
"type": "Add_Node",
"x": 4949,
"y": 4926,
"uuid": "0a3b1313-e73c-4f3a-b878-7a7a8a76518b"
},
{
"type": "Add_Node",
"x": 4943,
"y": 5114,
"uuid": "e06066a5-6375-4a40-8d14-c7e5e9c28f02"
},
{
"type": "Add_Node",
"x": 4617,
"y": 5014,
"uuid": "a06586f8-3c66-48ca-8be7-fd99b9ee82c3"
},
{
"type": "Add_Node",
"x": 4666,
"y": 4864,
"uuid": "24ac8fd5-b91a-4c35-bfdc-bf96961da280"
},
{
"type": "Add_Node",
"x": 4794,
"y": 5130,
"uuid": "f20b2350-0bc9-40be-9ddd-510d16ae8cc8"
}
],
"connections": [
{
"start_id": "24ac8fd5-b91a-4c35-bfdc-bf96961da280",
"end_id": "0a3b1313-e73c-4f3a-b878-7a7a8a76518b",
"start_port": "output",
"end_port": "input A"
},
{
"start_id": "a06586f8-3c66-48ca-8be7-fd99b9ee82c3",
"end_id": "0a3b1313-e73c-4f3a-b878-7a7a8a76518b",
"start_port": "output",
"end_port": "input B"
},
{
"start_id": "e06066a5-6375-4a40-8d14-c7e5e9c28f02",
"end_id": "0fe0381a-29bc-4987-ba94-ba4a14e33a13",
"start_port": "output",
"end_port": "input B"
},
{
"start_id": "0a3b1313-e73c-4f3a-b878-7a7a8a76518b",
"end_id": "0fe0381a-29bc-4987-ba94-ba4a14e33a13",
"start_port": "output",
"end_port": "input A"
},
{
"start_id": "0fe0381a-29bc-4987-ba94-ba4a14e33a13",
"end_id": "6e09cc9a-8b79-4129-bf61-637c6b8eb39b",
"start_port": "output",
"end_port": "input B"
},
{
"start_id": "f20b2350-0bc9-40be-9ddd-510d16ae8cc8",
"end_id": "e06066a5-6375-4a40-8d14-c7e5e9c28f02",
"start_port": "output",
"end_port": "input B"
}
]
}
83 changes: 65 additions & 18 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,45 @@
"""

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_type_editor import NodeTypeEditor
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.load_project)
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)
Expand All @@ -41,23 +59,20 @@ def __init__(self, parent=None):
left_layout.setContentsMargins(0, 0, 0, 0)

# Widgets
self.node_list = NodeList()
self.node_list = NodeList(self)
left_widget = QtWidgets.QWidget()
self.splitter = QtWidgets.QSplitter()
self.node_widget = NodeWidget(self)
new_node_type_btn = QtWidgets.QPushButton("New Node Type")
new_node_type_btn.setFixedHeight(50)

# 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)
left_layout.addWidget(new_node_type_btn)
main_layout.addWidget(self.splitter)

# Logic
new_node_type_btn.clicked.connect(self.new_node_cmd)
# Signals
self.load_project("C:/Users/Howard/simple-node-editor/Example_project")

# Restore GUI from last state
if settings.contains("geometry"):
Expand All @@ -66,19 +81,47 @@ def __init__(self, parent=None):
s = settings.value("splitterSize")
self.splitter.restoreState(s)

def new_node_cmd(self):
"""
Handles the New Node Type button click event by showing the NodeTypeEditor dialog.
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)

Returns:
None.
"""
node_editor = NodeTypeEditor()
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

if node_editor.exec() == QtWidgets.QDialog.Accepted:
print("Dialog accepted")
else:
print("Dialog canceled")
self.imports = {}

for file in project_path.glob("*.py"):
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 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):
"""
Expand All @@ -90,6 +133,10 @@ def closeEvent(self, 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())
Expand Down
2 changes: 1 addition & 1 deletion node_editor/gui/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def nodes(self):
Returns:
tuple: A tuple of the two Node objects connected by this Connection.
"""
return (self._start_port().node(), self._end_port().node())
return (self._start_port.node(), self._end_port.node())

def update_start_and_end_pos(self):
"""
Expand Down
6 changes: 6 additions & 0 deletions node_editor/gui/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def __init__(self):
self._width = 30 # The Width of the node
self._height = 30 # the height of the node
self._ports = [] # A list of ports
self.uuid = None # An identifier to used when saving and loading the scene

self.node_color = QtGui.QColor(20, 20, 20, 200)

Expand Down Expand Up @@ -96,6 +97,11 @@ def paint(self, painter, option=None, widget=None):
painter.drawPath(self.type_path)
painter.drawPath(self.misc_path)

def get_port(self, name):
for port in self._ports:
if port.name() == name:
return port

def add_port(self, name, is_output=False, flags=0, ptr=None):
"""
Adds a new port to the node.
Expand Down
16 changes: 12 additions & 4 deletions node_editor/gui/node_list.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
from PySide6 import QtCore, QtGui, QtWidgets
import sys
import importlib
import inspect


class NodeList(QtWidgets.QListWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setDragEnabled(True) # enable dragging

for node in ["Input", "Output", "And", "Not", "Nor", "Empty"]:
item = QtWidgets.QListWidgetItem(node)
self.addItem(item)
def update_project(self, imports):
# make an item for each custom class

self.setDragEnabled(True) # enable dragging
for name, data in imports.items():
item = QtWidgets.QListWidgetItem(name)
item.module = data["module"]
item.class_name = data["class"]
self.addItem(item)

def mousePressEvent(self, event):
item = self.itemAt(event.pos())
Expand All @@ -19,6 +26,7 @@ def mousePressEvent(self, event):
drag = QtGui.QDrag(self)
mime_data = QtCore.QMimeData()
mime_data.setText(name)
mime_data.item = item
drag.setMimeData(mime_data)

# Drag needs a pixmap or else it'll error due to a null pixmap
Expand Down
39 changes: 0 additions & 39 deletions node_editor/gui/node_type_editor.py

This file was deleted.

Loading