# -*- coding: utf-8 -*- #!/usr/bin/env python3 from Qt import QtWidgets, QtCore, QtGui import sys import pkgutil import importlib import inspect # --- BEGIN MONKEY PATCH FOR PIPE COLOR (Optional) --- # If you want custom pipe colors, uncomment this patch: """ try: from OdenGraphQt.qgraphics.pipe import PipeItem _orig_pipeitem_init = PipeItem.__init__ def _new_pipeitem_init(self, *args, **kwargs): _orig_pipeitem_init(self, *args, **kwargs) new_color = QtGui.QColor(29, 202, 151) self._pen = QtGui.QPen(new_color, 2.0) self._pen_dragging = QtGui.QPen(new_color, 2.0) PipeItem.__init__ = _new_pipeitem_init except ImportError: print("WARNING: Could not patch PipeItem color - OdenGraphQt.qgraphics.pipe not found.") """ # --- END MONKEY PATCH FOR PIPE COLOR --- # --- BEGIN ROBUST PATCH FOR QGraphicsScene.setSelectionArea --- _original_setSelectionArea = QtWidgets.QGraphicsScene.setSelectionArea def _patched_setSelectionArea(self, *args, **kwargs): """ A robust patch that handles various call signatures for QGraphicsScene.setSelectionArea(). We try calling the original method with whatever arguments are provided. If a TypeError occurs, we assume it was missing some arguments and re-call with defaults. """ try: # First, try the original call with the given arguments. return _original_setSelectionArea(self, *args, **kwargs) except TypeError: # If a TypeError occurs, the caller likely used a minimal signature. # We'll fallback to a known signature with default arguments. if not args: raise # If no args at all, we cannot fix it. painterPath = args[0] # QPainterPath selection_op = QtCore.Qt.ReplaceSelection selection_mode = QtCore.Qt.IntersectsItemShape transform = QtGui.QTransform() return _original_setSelectionArea(self, painterPath, selection_op, selection_mode, transform) QtWidgets.QGraphicsScene.setSelectionArea = _patched_setSelectionArea # --- END ROBUST PATCH FOR QGraphicsScene.setSelectionArea --- from OdenGraphQt import NodeGraph, BaseNode def import_nodes_from_folder(package_name): """ Dynamically import all modules from the given package and return a list of classes that subclass BaseNode. """ imported_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__: imported_nodes.append(obj) return imported_nodes def make_node_command(graph, node_type_str): """ Return a function that creates a node of the given type at the current cursor position. """ def command(): try: pos = graph.cursor_pos() graph.create_node(node_type_str, pos=pos) except Exception as e: print(f"Error creating node of type {node_type_str}: {e}") return command if __name__ == "__main__": app = QtWidgets.QApplication([]) # Create the NodeGraph controller. graph = NodeGraph() graph.widget.setWindowTitle("Project Borealis - Flyff Information Overlay") # Dynamically import custom node classes from the 'Nodes' package. custom_nodes = import_nodes_from_folder("Nodes") for node_class in custom_nodes: graph.register_node(node_class) # Add context menu commands for dynamic node creation. graph_context_menu = graph.get_context_menu("graph") for node_class in custom_nodes: node_type = f"{node_class.__identifier__}.{node_class.__name__}" node_name = node_class.NODE_NAME graph_context_menu.add_command( f"Add {node_name}", make_node_command(graph, node_type) ) # Add a "Remove Selected Node" command to the graph context menu. graph_context_menu.add_command( "Remove Selected Node", lambda: [graph.remove_node(node) for node in graph.selected_nodes()] if graph.selected_nodes() else None ) # Grid styling changes # 1) Dark background color graph.set_background_color(20, 20, 20) # Dark gray # 2) Subdued grid color graph.set_grid_color(60, 60, 60) # Gray grid lines # Optionally, create a subtle gradient in the scene: scene = graph.scene() gradient = QtGui.QLinearGradient(0, 0, 0, 1) gradient.setCoordinateMode(QtGui.QGradient.ObjectBoundingMode) gradient.setColorAt(0.0, QtGui.QColor(9, 44, 68)) # Very Top Gradient gradient.setColorAt(0.3, QtGui.QColor(30, 30, 30)) # Middle Gradient gradient.setColorAt(0.7, QtGui.QColor(30, 30, 30)) # Middle Gradient gradient.setColorAt(1.0, QtGui.QColor(9, 44, 68)) # Very Bottom Gradient scene.setBackgroundBrush(QtGui.QBrush(gradient)) # Resize and show the graph widget. graph.widget.resize(1600, 900) graph.widget.show() def global_update(): for node in graph.all_nodes(): if hasattr(node, "process_input"): try: node.process_input() except Exception as e: print("Error updating node", node, e) timer = QtCore.QTimer() timer.timeout.connect(global_update) timer.start(500) sys.exit(app.exec_())