diff --git a/Experimental/accept_reject_example.py b/Experimental/accept_reject_example.py new file mode 100644 index 0000000..fd6f028 --- /dev/null +++ b/Experimental/accept_reject_example.py @@ -0,0 +1,192 @@ +import signal + +from qtpy import QtWidgets + +from OdenGraphQt import BaseNode, NodeGraph +from OdenGraphQt.constants import PortTypeEnum +from OdenGraphQt.qgraphics.node_base import NodeItem + + +class PublishWriteNodeItem(NodeItem): + def _align_widgets_horizontal(self, v_offset: int): + if not self._widgets: + return + + rect = self.boundingRect() + y = rect.y() + v_offset + for widget in self._widgets.values(): + if not widget.isVisible(): + continue + + widget_rect = widget.boundingRect() + x = rect.center().x() - (widget_rect.width() / 2) + widget.widget().setTitleAlign('center') + widget.setPos(x, y) + y += widget_rect.height() + + +class PrevNextNode(BaseNode): + __identifier__ = "action" + NODE_NAME = "Action Node" + + def __init__(self): + super().__init__() + + # create an input port. + input_port = self.add_input("_prev", color=(180, 80, 0), multi_input=False) + # create an output port. + output_port = self.add_output("_next", multi_output=False) + + input_port.port_item.set_allow_partial_match_constraint(True) + input_port.port_item.set_accept_constraint( + port_name=output_port.name(), + port_type=PortTypeEnum.OUT.value, + node_identifier=self.__identifier__, + ) + + output_port.port_item.set_allow_partial_match_constraint(True) + output_port.port_item.set_accept_constraint( + port_name=input_port.name(), + port_type=PortTypeEnum.IN.value, + node_identifier=self.__identifier__, + ) + + +class IngredientNode(BaseNode): + __identifier__ = "ingredient" + + +class SpamNode(IngredientNode): + __identifier__ = "spam" + NODE_NAME = "Spam" + + def __init__(self): + super().__init__() + spam_port = self.add_output( + "spam", + color=(50, 150, 222), + ) + + +class EggNode(IngredientNode): + __identifier__ = "egg" + NODE_NAME = "Egg" + + def __init__(self): + super().__init__() + egg_port = self.add_output( + "egg", + color=(50, 150, 222), + ) + + +class MealNode(BaseNode): + NODE_NAME = "Meal" + + def __init__(self): + super().__init__() + spam_port = self.add_input("spam", color=(222, 15, 0), multi_input=False) + spam_port.port_item.set_reject_constraint( + port_name="egg", + port_type=PortTypeEnum.OUT.value, + node_identifier="egg", + ) + egg_port = self.add_input("egg", color=(222, 15, 0), multi_input=False) + egg_port.port_item.set_reject_constraint( + port_name="spam", + port_type=PortTypeEnum.OUT.value, + node_identifier="spam", + ) + + +class BasePublishNode(PrevNextNode): + __identifier__ = "publish" + allow_multiple_write = False + + def __init__(self): + super().__init__() + port = self.add_output( + "write", + color=(184, 150, 0), + multi_output=self.allow_multiple_write, + ) + port.port_item.set_accept_constraint( + port_name="src", + port_type=PortTypeEnum.IN.value, + node_identifier="publish", + ) + + +class PubNode(PrevNextNode): + __identifier__ = "pub" + NODE_NAME = "Not Tavern" + + +class PublishFileActionNode(BasePublishNode): + NODE_NAME = "Publish File" + allow_multiple_write = False + + +class PublishFileToManyActionNode(BasePublishNode): + NODE_NAME = "Publish File to Many" + allow_multiple_write = True + + +class PublishWriteNode(BaseNode): + __identifier__ = "publish" + NODE_NAME = "Publish Write" + + def __init__(self): + super().__init__(qgraphics_item=PublishWriteNodeItem) + self.set_color(164, 130, 0) + self.add_text_input("write", "Path:") + + port = self.add_input("src", multi_input=False) + port.port_item.set_accept_constraint( + port_name="write", + port_type=PortTypeEnum.OUT.value, + node_identifier="publish", + ) + + +if __name__ == '__main__': + + # handle SIGINT to make the app terminate on CTRL+C + signal.signal(signal.SIGINT, signal.SIG_DFL) + + app = QtWidgets.QApplication([]) + + # create graph controller. + graph = NodeGraph() + + # set up context menu for the node graph. + graph.set_context_menu_from_file('../examples/hotkeys/hotkeys.json') + + # registered example nodes. + graph.register_nodes([ + SpamNode, + EggNode, + MealNode, + PubNode, + PublishFileActionNode, + PublishFileToManyActionNode, + PublishWriteNode, + ]) + + # add nodes + graph.add_node(SpamNode()) + graph.add_node(EggNode()) + graph.add_node(MealNode()) + graph.add_node(PubNode()) + graph.add_node(PublishFileToManyActionNode()) + graph.add_node(PublishFileActionNode()) + graph.add_node(PublishWriteNode()) + graph.auto_layout_nodes() + graph.clear_selection() + + # show the node graph widget. + graph_widget = graph.widget + graph_widget.resize(1100, 800) + graph_widget.show() + + app.exec_() \ No newline at end of file diff --git a/Legacy_Code/Orphaned Code/data_collector.py b/Legacy/Orphaned Code/data_collector.py similarity index 100% rename from Legacy_Code/Orphaned Code/data_collector.py rename to Legacy/Orphaned Code/data_collector.py diff --git a/Legacy_Code/borealis_overlay.py b/Legacy/borealis_overlay.py similarity index 100% rename from Legacy_Code/borealis_overlay.py rename to Legacy/borealis_overlay.py diff --git a/Nodes/__pycache__/backdrop_node.cpython-312.pyc b/Nodes/__pycache__/backdrop_node.cpython-312.pyc new file mode 100644 index 0000000..9f205ca Binary files /dev/null and b/Nodes/__pycache__/backdrop_node.cpython-312.pyc differ diff --git a/Nodes/__pycache__/basic_nodes.cpython-312.pyc b/Nodes/__pycache__/basic_nodes.cpython-312.pyc new file mode 100644 index 0000000..8b10dfa Binary files /dev/null and b/Nodes/__pycache__/basic_nodes.cpython-312.pyc differ diff --git a/Nodes/__pycache__/custom_ports_node.cpython-312.pyc b/Nodes/__pycache__/custom_ports_node.cpython-312.pyc new file mode 100644 index 0000000..5ea85b2 Binary files /dev/null and b/Nodes/__pycache__/custom_ports_node.cpython-312.pyc differ diff --git a/Nodes/__pycache__/flyff_character_status_node.cpython-312.pyc b/Nodes/__pycache__/flyff_character_status_node.cpython-312.pyc new file mode 100644 index 0000000..0a1961f Binary files /dev/null and b/Nodes/__pycache__/flyff_character_status_node.cpython-312.pyc differ diff --git a/Nodes/__pycache__/group_node.cpython-312.pyc b/Nodes/__pycache__/group_node.cpython-312.pyc new file mode 100644 index 0000000..236137e Binary files /dev/null and b/Nodes/__pycache__/group_node.cpython-312.pyc differ diff --git a/Nodes/__pycache__/widget_node.cpython-312.pyc b/Nodes/__pycache__/widget_node.cpython-312.pyc new file mode 100644 index 0000000..0476609 Binary files /dev/null and b/Nodes/__pycache__/widget_node.cpython-312.pyc differ diff --git a/Nodes/backdrop_node.py b/Nodes/backdrop_node.py new file mode 100644 index 0000000..5eaca22 --- /dev/null +++ b/Nodes/backdrop_node.py @@ -0,0 +1,184 @@ +#!/usr/bin/env python3 +""" +Enhanced Backdrop Node (Inherited from BaseNode) + +Features: + - Inherits from `BaseNode` so it can be discovered in your node scanning. + - Custom context menu to rename (set title) or pick a new color. + - Forces geometry updates to reduce "ghosting" or partial redraws. +""" + +from Qt import QtWidgets, QtGui +from OdenGraphQt import BaseNode +from OdenGraphQt.constants import NodePropWidgetEnum +from OdenGraphQt.qgraphics.node_backdrop import BackdropNodeItem + + +class BackdropNode(BaseNode): + """ + Backdrop Node: + - Allows grouping or annotating other nodes by resizing a large rectangle. + - Provides a custom context menu for renaming and recoloring (via on_context_menu). + """ + + __identifier__ = 'bunny-lab.io.backdrop' + NODE_NAME = 'Backdrop' + + def __init__(self): + # Use BackdropNodeItem for the specialized QGraphicsItem. + super(BackdropNode, self).__init__(qgraphics_item=BackdropNodeItem) + + # Default color (teal). + self.model.color = (5, 129, 138, 255) + + # Multi-line text property for storing the backdrop text. + self.create_property( + 'backdrop_text', + '', + widget_type=NodePropWidgetEnum.QTEXT_EDIT.value, + tab='Backdrop' + ) + + # -------------------------------------------------------------------------- + # Resizing / Geometry + # -------------------------------------------------------------------------- + def on_backdrop_updated(self, update_prop, value=None): + """ + Triggered when the user resizes or double-clicks the backdrop sizer handle. + """ + if not self.graph: + return + + if update_prop == 'sizer_mouse_release': + # User finished dragging the resize handle + self.view.prepareGeometryChange() + self.graph.begin_undo(f'resized "{self.name()}"') + self.set_property('width', value['width']) + self.set_property('height', value['height']) + self.set_pos(*value['pos']) + self.graph.end_undo() + self.view.update() + + elif update_prop == 'sizer_double_clicked': + # User double-clicked the resize handle (auto-resize) + self.view.prepareGeometryChange() + self.graph.begin_undo(f'"{self.name()}" auto resize') + self.set_property('width', value['width']) + self.set_property('height', value['height']) + self.set_pos(*value['pos']) + self.graph.end_undo() + self.view.update() + + def auto_size(self): + """ + Auto-resize the backdrop to fit around intersecting nodes. + """ + if not self.graph: + return + self.view.prepareGeometryChange() + self.graph.begin_undo(f'"{self.name()}" auto resize') + size = self.view.calc_backdrop_size() + self.set_property('width', size['width']) + self.set_property('height', size['height']) + self.set_pos(*size['pos']) + self.graph.end_undo() + self.view.update() + + def wrap_nodes(self, nodes): + """ + Fit the backdrop around the specified nodes. + """ + if not self.graph or not nodes: + return + self.view.prepareGeometryChange() + self.graph.begin_undo(f'"{self.name()}" wrap nodes') + size = self.view.calc_backdrop_size([n.view for n in nodes]) + self.set_property('width', size['width']) + self.set_property('height', size['height']) + self.set_pos(*size['pos']) + self.graph.end_undo() + self.view.update() + + def nodes(self): + """ + Return a list of nodes wrapped by this backdrop. + """ + node_ids = [n.id for n in self.view.get_nodes()] + return [self.graph.get_node_by_id(nid) for nid in node_ids] + + def set_text(self, text=''): + """ + Set the multi-line text in the backdrop. + """ + self.set_property('backdrop_text', text) + + def text(self): + """ + Return the text content in the backdrop. + """ + return self.get_property('backdrop_text') + + def set_size(self, width, height): + """ + Manually set the backdrop size. + """ + if self.graph: + self.view.prepareGeometryChange() + self.graph.begin_undo('backdrop size') + self.set_property('width', width) + self.set_property('height', height) + self.graph.end_undo() + self.view.update() + else: + self.view.width, self.view.height = width, height + self.model.width, self.model.height = width, height + + def size(self): + """ + Return (width, height) of the backdrop. + """ + self.model.width = self.view.width + self.model.height = self.view.height + return self.model.width, self.model.height + + # No ports for a backdrop: + def inputs(self): + return + + def outputs(self): + return + + # -------------------------------------------------------------------------- + # Custom Context Menu + # -------------------------------------------------------------------------- + def on_context_menu(self, menu): + """ + Called manually by the node context menu callback in older NodeGraphQt versions. + """ + rename_action = menu.addAction("Set Title...") + rename_action.triggered.connect(self._change_title) + + color_action = menu.addAction("Set Color...") + color_action.triggered.connect(self._change_color) + + def _change_title(self): + """ + Prompt for a new backdrop title (header). + """ + new_title, ok = QtWidgets.QInputDialog.getText( + None, "Backdrop Title", "Enter new backdrop title:" + ) + if ok and new_title: + self.set_name(new_title) + + def _change_color(self): + """ + Prompt for a new backdrop color via QColorDialog. + """ + current_color = QtGui.QColor(*self.model.color) + color = QtWidgets.QColorDialog.getColor( + current_color, None, "Select Backdrop Color" + ) + if color.isValid(): + self.model.color = (color.red(), color.green(), color.blue(), color.alpha()) + self.view.update() diff --git a/Nodes/basic_nodes.py b/Nodes/basic_nodes.py new file mode 100644 index 0000000..4d36de1 --- /dev/null +++ b/Nodes/basic_nodes.py @@ -0,0 +1,86 @@ +from OdenGraphQt import BaseNode, BaseNodeCircle + + +class BasicNodeA(BaseNode): + """ + A node class with 2 inputs and 2 outputs. + """ + + # unique node identifier. + __identifier__ = 'nodes.basic' + + # initial default node name. + NODE_NAME = 'node A' + + def __init__(self): + super(BasicNodeA, self).__init__() + + # create node inputs. + self.add_input('in A') + self.add_input('in B') + + # create node outputs. + self.add_output('out A') + self.add_output('out B') + + +class BasicNodeB(BaseNode): + """ + A node class with 3 inputs and 3 outputs. + The last input and last output can take in multiple pipes. + """ + + # unique node identifier. + __identifier__ = 'nodes.basic' + + # initial default node name. + NODE_NAME = 'node B' + + def __init__(self): + super(BasicNodeB, self).__init__() + + # create node inputs + self.add_input('single 1') + self.add_input('single 2') + self.add_input('multi in', multi_input=True) + + # create node outputs + self.add_output('single 1', multi_output=False) + self.add_output('single 2', multi_output=False) + self.add_output('multi out') + + +class CircleNode(BaseNodeCircle): + """ + A node class with 3 inputs and 3 outputs. + This node is a circular design. + """ + + # unique node identifier. + __identifier__ = 'nodes.basic' + + # initial default node name. + NODE_NAME = 'Circle Node' + + def __init__(self): + super(CircleNode, self).__init__() + self.set_color(10, 24, 38) + + # create node inputs + p = self.add_input('in 1') + p.add_accept_port_type( + port_name='single 1', + port_type='out', + node_type='nodes.basic.BasicNodeB' + ) + + self.add_input('in 2') + self.add_input('in 3', multi_input=True) + self.add_input('in 4', display_name=False) + self.add_input('in 5', display_name=False) + + # create node outputs + self.add_output('out 1') + self.add_output('out 2', multi_output=False) + self.add_output('out 3', multi_output=True, display_name=False) + self.add_output('out 4', multi_output=True, display_name=False) \ No newline at end of file diff --git a/Nodes/custom_ports_node.py b/Nodes/custom_ports_node.py new file mode 100644 index 0000000..ac3eb43 --- /dev/null +++ b/Nodes/custom_ports_node.py @@ -0,0 +1,121 @@ +#!/usr/bin/python +from qtpy import QtCore, QtGui + +from OdenGraphQt import BaseNode + + +def draw_triangle_port(painter, rect, info): + """ + Custom paint function for drawing a Triangle shaped port. + + Args: + painter (QtGui.QPainter): painter object. + rect (QtCore.QRectF): port rect used to describe parameters + needed to draw. + info (dict): information describing the ports current state. + { + 'port_type': 'in', + 'color': (0, 0, 0), + 'border_color': (255, 255, 255), + 'multi_connection': False, + 'connected': False, + 'hovered': False, + } + """ + painter.save() + + size = int(rect.height() / 2) + triangle = QtGui.QPolygonF() + triangle.append(QtCore.QPointF(-size, size)) + triangle.append(QtCore.QPointF(0.0, -size)) + triangle.append(QtCore.QPointF(size, size)) + + transform = QtGui.QTransform() + transform.translate(rect.center().x(), rect.center().y()) + port_poly = transform.map(triangle) + + # mouse over port color. + if info['hovered']: + color = QtGui.QColor(14, 45, 59) + border_color = QtGui.QColor(136, 255, 35) + # port connected color. + elif info['connected']: + color = QtGui.QColor(195, 60, 60) + border_color = QtGui.QColor(200, 130, 70) + # default port color + else: + color = QtGui.QColor(*info['color']) + border_color = QtGui.QColor(*info['border_color']) + + pen = QtGui.QPen(border_color, 1.8) + pen.setJoinStyle(QtCore.Qt.PenJoinStyle.MiterJoin) + + painter.setPen(pen) + painter.setBrush(color) + painter.drawPolygon(port_poly) + + painter.restore() + + +def draw_square_port(painter, rect, info): + """ + Custom paint function for drawing a Square shaped port. + + Args: + painter (QtGui.QPainter): painter object. + rect (QtCore.QRectF): port rect used to describe parameters + needed to draw. + info (dict): information describing the ports current state. + { + 'port_type': 'in', + 'color': (0, 0, 0), + 'border_color': (255, 255, 255), + 'multi_connection': False, + 'connected': False, + 'hovered': False, + } + """ + painter.save() + + # mouse over port color. + if info['hovered']: + color = QtGui.QColor(14, 45, 59) + border_color = QtGui.QColor(136, 255, 35, 255) + # port connected color. + elif info['connected']: + color = QtGui.QColor(195, 60, 60) + border_color = QtGui.QColor(200, 130, 70) + # default port color + else: + color = QtGui.QColor(*info['color']) + border_color = QtGui.QColor(*info['border_color']) + + pen = QtGui.QPen(border_color, 1.8) + pen.setJoinStyle(QtCore.Qt.PenJoinStyle.MiterJoin) + + painter.setPen(pen) + painter.setBrush(color) + painter.drawRect(rect) + + painter.restore() + + +class CustomPortsNode(BaseNode): + """ + example test node with custom shaped ports. + """ + + # set a unique node identifier. + __identifier__ = 'nodes.custom.ports' + + # set the initial default node name. + NODE_NAME = 'node' + + def __init__(self): + super(CustomPortsNode, self).__init__() + + # create input and output port. + self.add_input('in', color=(200, 10, 0)) + self.add_output('default') + self.add_output('square', painter_func=draw_square_port) + self.add_output('triangle', painter_func=draw_triangle_port) \ No newline at end of file diff --git a/Nodes/character_status_node.py b/Nodes/flyff_character_status_node.py similarity index 92% rename from Nodes/character_status_node.py rename to Nodes/flyff_character_status_node.py index ab5e0fd..b9d57f4 100644 --- a/Nodes/character_status_node.py +++ b/Nodes/flyff_character_status_node.py @@ -1,13 +1,4 @@ #!/usr/bin/env python3 -""" -Character Status Node - -This node represents the character's status. It has seven output ports: - - HP: Current, HP: Total, MP: Current, MP: Total, FP: Current, FP: Total, EXP. -It polls an API endpoint (http://127.0.0.1:5000/data) every 500 ms to update its values. -If the API call is successful, the node's title is set to "Character Status (API Connected)". -If the API is down or returns an error, the title is set to "Character Status (API Disconnected)". -""" from OdenGraphQt import BaseNode from Qt import QtCore, QtGui @@ -44,7 +35,7 @@ def get_draw_stat_port(color, border_color=None, alpha=127): return painter_func class CharacterStatusNode(BaseNode): - __identifier__ = 'bunny-lab.io.status_node' + __identifier__ = 'bunny-lab.io.flyff_character_status_node' NODE_NAME = 'Character Status' def __init__(self): diff --git a/Nodes/group_node.py b/Nodes/group_node.py new file mode 100644 index 0000000..9b937b5 --- /dev/null +++ b/Nodes/group_node.py @@ -0,0 +1,21 @@ +from OdenGraphQt import GroupNode + + +class MyGroupNode(GroupNode): + """ + example test group node with a in port and out port. + """ + + # set a unique node identifier. + __identifier__ = 'nodes.group' + + # set the initial default node name. + NODE_NAME = 'group node' + + def __init__(self): + super(MyGroupNode, self).__init__() + self.set_color(50, 8, 25) + + # create input and output port. + self.add_input('in') + self.add_output('out') \ No newline at end of file diff --git a/Nodes/widget_node.py b/Nodes/widget_node.py new file mode 100644 index 0000000..eff1ac2 --- /dev/null +++ b/Nodes/widget_node.py @@ -0,0 +1,155 @@ +from OdenGraphQt import BaseNode +from OdenGraphQt.constants import NodePropWidgetEnum +from OdenGraphQt.widgets.node_widgets import NodeLineEditValidatorCheckBox + + +class DropdownMenuNode(BaseNode): + """ + An example node with a embedded added QCombobox menu. + """ + + # unique node identifier. + __identifier__ = 'nodes.widget' + + # initial default node name. + NODE_NAME = 'menu' + + def __init__(self): + super(DropdownMenuNode, self).__init__() + + # create input & output ports + self.add_input('in 1') + self.add_output('out 1') + self.add_output('out 2') + + # create the QComboBox menu. + items = ["item 1", "item 2", "item 3"] + self.add_combo_menu( + "my_menu", + "Menu Test", + items=items, + tooltip="example custom tooltip", + ) + + +class TextInputNode(BaseNode): + """ + An example of a node with a embedded QLineEdit. + """ + + # unique node identifier. + __identifier__ = 'nodes.widget' + + # initial default node name. + NODE_NAME = 'text' + + def __init__(self): + super().__init__() + pattern = r"^[A-Za-z0-9]*$" + placeholder = "" + tooltip = "Valid characters: A-Z a-z 0-9" + is_case_sensitive = True + checkbox_label = "Use Parser?" + + # create input & output ports + self.add_input('in') + self.add_output('out') + + # create QLineEdit text input widget. + self.add_text_input('my_input', 'Text Input', tab='widgets') + + tool_btn_kwargs = { + "func": self._callback, + "tooltip": "Awesome" + } + kwargs = { + "validator": { + "pattern": pattern, + "placeholder": placeholder, + "tooltip": tooltip, + "is_case_insensitive": is_case_sensitive, + "checkbox_visible": True, + "tool_btn_visible": True, + }, + "checkbox_label": checkbox_label, + "tool_btn": tool_btn_kwargs, + } + node_widget = NodeLineEditValidatorCheckBox( + "src_path", + pattern, + placeholder, + tooltip, + is_case_sensitive, + checkbox_label, + checkbox_visible=True, + tool_btn_visible=True, + widget_label="src_path", + parent=self.view, + ) + node_widget.get_custom_widget().set_tool_btn(**tool_btn_kwargs) + self.add_custom_widget( + node_widget, + NodePropWidgetEnum.LINEEDIT_VALIDATOR_CHECKBOX.value, + "widgets", + **kwargs, + ) + + kwargs2 = { + "validator": { + "pattern": pattern, + "placeholder": placeholder, + "tooltip": tooltip, + "is_case_insensitive": is_case_sensitive, + "checkbox_visible": False, + "tool_btn_visible": False, + }, + "checkbox_label": "Check In Luggage?", + "tool_btn": tool_btn_kwargs, + } + node_widget2 = NodeLineEditValidatorCheckBox( + "dst_path", + pattern, + placeholder, + tooltip, + is_case_sensitive, + "Check In Luggage?", + checkbox_visible=False, + tool_btn_visible=False, + widget_label="dst_path", + parent=self.view, + ) + node_widget2.get_custom_widget().set_tool_btn(**tool_btn_kwargs) + node_widget2.set_checkbox_visible(False) + node_widget2.set_tool_btn_visible(False) + self.add_custom_widget( + node_widget2, + NodePropWidgetEnum.LINEEDIT_VALIDATOR_CHECKBOX.value, + "widgets", + **kwargs2, + ) + + def _callback(self): + print(f"YOU HAVE CLICKED ON '{self.NODE_NAME}'") + + +class CheckboxNode(BaseNode): + """ + An example of a node with 2 embedded QCheckBox widgets. + """ + + # set a unique node identifier. + __identifier__ = 'nodes.widget' + + # set the initial default node name. + NODE_NAME = 'checkbox' + + def __init__(self): + super(CheckboxNode, self).__init__() + + # create the checkboxes. + self.add_checkbox('cb_1', '', 'Checkbox 1', True) + self.add_checkbox('cb_2', '', 'Checkbox 2', False) + + # create input and output port. + self.add_input('in', color=(200, 100, 0)) + self.add_output('out', color=(0, 100, 200)) \ No newline at end of file diff --git a/borealis.py b/borealis.py index 0b5c030..dad0a31 100644 --- a/borealis.py +++ b/borealis.py @@ -1,27 +1,27 @@ #!/usr/bin/env python3 -# --- Patch QGraphicsScene.setSelectionArea to handle selection arguments --- -from Qt import QtWidgets, QtCore, QtGui - -_original_setSelectionArea = QtWidgets.QGraphicsScene.setSelectionArea - -def _patched_setSelectionArea(self, painterPath, second_arg, *args, **kwargs): - try: - # Try calling the original method with the provided arguments. - return _original_setSelectionArea(self, painterPath, second_arg, *args, **kwargs) - except TypeError as e: - # If a TypeError is raised, assume the call was made with only a QPainterPath - # and an ItemSelectionMode, and patch it by supplying defaults. - # Default operation: ReplaceSelection, default transform: QTransform() - return _original_setSelectionArea(self, painterPath, - QtCore.Qt.ReplaceSelection, - second_arg, - QtGui.QTransform()) - -# Monkey-patch the setSelectionArea method. -QtWidgets.QGraphicsScene.setSelectionArea = _patched_setSelectionArea - -# --- End of patch section --- +## --- Patch QGraphicsScene.setSelectionArea to handle selection arguments --- +#from Qt import QtWidgets, QtCore, QtGui +# +#_original_setSelectionArea = QtWidgets.QGraphicsScene.setSelectionArea +# +#def _patched_setSelectionArea(self, painterPath, second_arg, *args, **kwargs): +# try: +# # Try calling the original method with the provided arguments. +# return _original_setSelectionArea(self, painterPath, second_arg, *args, **kwargs) +# except TypeError as e: +# # If a TypeError is raised, assume the call was made with only a QPainterPath +# # and an ItemSelectionMode, and patch it by supplying defaults. +# # Default operation: ReplaceSelection, default transform: QTransform() +# return _original_setSelectionArea(self, painterPath, +# QtCore.Qt.ReplaceSelection, +# second_arg, +# QtGui.QTransform()) +# +## Monkey-patch the setSelectionArea method. +#QtWidgets.QGraphicsScene.setSelectionArea = _patched_setSelectionArea +# +## --- End of patch section --- import sys import pkgutil diff --git a/data_collector_v2.py b/data_collector_v2.py index abeb253..da9a44e 100644 --- a/data_collector_v2.py +++ b/data_collector_v2.py @@ -188,7 +188,6 @@ def collect_ocr_data(): # Run OCR text = pytesseract.image_to_string(processed, config='--psm 4 --oem 1') - print("OCR Output:", text) # Debugging stats = parse_all_stats(text.strip()) hp_cur, hp_max = stats["hp"] @@ -207,7 +206,8 @@ def collect_ocr_data(): "exp": exp_val } - print(f"OCR Updated: HP: {hp_cur}/{hp_max}, MP: {mp_cur}/{mp_max}, FP: {fp_cur}/{fp_max}, EXP: {exp_val}") # Debug + # DEBUG OUTPUT + print(f"Flyff - Character Status: HP: {hp_cur}/{hp_max}, MP: {mp_cur}/{mp_max}, FP: {fp_cur}/{fp_max}, EXP: {exp_val}%") time.sleep(0.5) @@ -286,7 +286,6 @@ class OverlayCanvas(QWidget): self.region["y"] = event.y() - self.drag_offset.y() region_lock.unlock() - print(f"Region Moved: x={self.region['x']}, y={self.region['y']}, w={self.region['w']}, h={self.region['h']}") # Debugging self.update() def mouseReleaseEvent(self, event): diff --git a/debug_processed.png b/debug_processed.png index b905d3f..4d17f78 100644 Binary files a/debug_processed.png and b/debug_processed.png differ diff --git a/debug_screenshot.png b/debug_screenshot.png index ad9b0a0..199633c 100644 Binary files a/debug_screenshot.png and b/debug_screenshot.png differ