Borealis-Legacy/borealis_transparent.py

105 lines
3.8 KiB
Python

import os
import sys
import pkgutil
import importlib
import inspect
from PyQt5.QtWidgets import QApplication, QMainWindow, QAction, QMenu, QUndoStack
from PyQt5.QtCore import Qt, QTimer, QRect
from PyQt5.QtGui import QColor, QPainter, QPen, QBrush
from OdenGraphQt import NodeGraph, BaseNode
# Force qtpy to use PyQt5 explicitly
os.environ["QT_API"] = "pyqt5"
# --- PATCH OdenGraphQt to use QtWidgets.QUndoStack instead of QtGui.QUndoStack ---
import qtpy.QtGui
import qtpy.QtWidgets
if not hasattr(qtpy.QtGui, "QUndoStack"): # Ensure patching only if necessary
qtpy.QtGui.QUndoStack = qtpy.QtWidgets.QUndoStack
# --- END PATCH ---
class TransparentGraphWindow(QMainWindow):
def __init__(self):
super().__init__()
# Enable transparency & always-on-top behavior
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.Tool)
self.setAttribute(Qt.WA_TranslucentBackground, True)
# Get full-screen size for overlay
screen_geometry = QApplication.primaryScreen().geometry()
self.setGeometry(screen_geometry)
# Create Node Graph
self.graph = NodeGraph()
self.graph.widget.setParent(self)
self.graph.widget.setGeometry(self.rect())
# Make bottom-left corner interactive for context menu
self.context_menu_area = QRect(10, self.height() - 40, 50, 30)
# Load nodes dynamically
self.import_nodes()
# Global update timer for processing nodes
self.timer = QTimer()
self.timer.timeout.connect(self.update_nodes)
self.timer.start(500)
def import_nodes(self):
"""Dynamically import all custom node classes from the 'Nodes' package."""
try:
package_name = 'Nodes'
package = importlib.import_module(package_name)
for loader, module_name, is_pkg in pkgutil.walk_packages(package.__path__, package.__name__ + "."):
module = importlib.import_module(module_name)
for name, obj in inspect.getmembers(module, inspect.isclass):
if issubclass(obj, BaseNode) and obj.__module__ == module.__name__:
self.graph.register_node(obj)
except Exception as e:
print(f"Error loading nodes: {e}")
def update_nodes(self):
"""Calls process_input() on all nodes, if applicable."""
for node in self.graph.all_nodes():
if hasattr(node, "process_input"):
try:
node.process_input()
except Exception as e:
print(f"Error processing node {node}: {e}")
def mousePressEvent(self, event):
"""Override mouse press to handle context menu in bottom-left area."""
if event.button() == Qt.RightButton and self.context_menu_area.contains(event.pos()):
self.show_context_menu(event.globalPos())
def show_context_menu(self, position):
"""Displays a right-click context menu."""
menu = QMenu(self)
quit_action = QAction("Quit", self)
quit_action.triggered.connect(self.close)
menu.addAction(quit_action)
menu.exec_(position)
def paintEvent(self, event):
"""Render transparent overlay and the small clickable menu area."""
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
# Draw semi-transparent context menu area
painter.setBrush(QBrush(QColor(50, 50, 50, 150))) # Dark semi-transparent box
painter.setPen(QPen(QColor(200, 200, 200, 200)))
painter.drawRect(self.context_menu_area)
painter.setFont(self.font())
painter.setPen(QColor(255, 255, 255))
painter.drawText(self.context_menu_area, Qt.AlignCenter, "Menu")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = TransparentGraphWindow()
window.show()
sys.exit(app.exec_())