From ad9a59283cfa0e34a9fe93ecd505d28635a6c550 Mon Sep 17 00:00:00 2001 From: rob Date: Thu, 15 Jan 2026 19:10:10 -0400 Subject: [PATCH] Add patch for NodeGraphQt PySide6 6.7+ compatibility The setSelectionArea() API changed in PySide6 6.7 - it now requires an ItemSelectionOperation parameter before ItemSelectionMode. Files added: - patches/nodegraphqt_pyside6_compat.patch: Git-style patch file - patches/UPSTREAM_ISSUE.md: Issue report for upstream project - scripts/patch_nodegraphqt.py: Script to auto-apply the patch The patch fixes rubber band selection errors when dragging in the node graph viewer. Run after pip install: python scripts/patch_nodegraphqt.py Co-Authored-By: Claude Opus 4.5 --- patches/UPSTREAM_ISSUE.md | 80 ++++++++++++++++++ patches/nodegraphqt_pyside6_compat.patch | 13 +++ scripts/patch_nodegraphqt.py | 103 +++++++++++++++++++++++ 3 files changed, 196 insertions(+) create mode 100644 patches/UPSTREAM_ISSUE.md create mode 100644 patches/nodegraphqt_pyside6_compat.patch create mode 100644 scripts/patch_nodegraphqt.py diff --git a/patches/UPSTREAM_ISSUE.md b/patches/UPSTREAM_ISSUE.md new file mode 100644 index 0000000..56725d3 --- /dev/null +++ b/patches/UPSTREAM_ISSUE.md @@ -0,0 +1,80 @@ +# PySide6 6.7+ Compatibility Issue: setSelectionArea API Change + +## Issue + +When using NodeGraphQt-QuiltiX-fork with PySide6 6.7+, dragging a rubber band selection in the node graph causes repeated TypeError exceptions: + +``` +TypeError: 'PySide6.QtWidgets.QGraphicsScene.setSelectionArea' called with wrong argument types: + PySide6.QtWidgets.QGraphicsScene.setSelectionArea(QPainterPath, ItemSelectionMode) +Supported signatures: + PySide6.QtWidgets.QGraphicsScene.setSelectionArea(PySide6.QtGui.QPainterPath, PySide6.QtGui.QTransform) + PySide6.QtWidgets.QGraphicsScene.setSelectionArea(PySide6.QtGui.QPainterPath, PySide6.QtCore.Qt.ItemSelectionOperation = Instance(Qt.ReplaceSelection), PySide6.QtCore.Qt.ItemSelectionMode = Instance(Qt.IntersectsItemShape), PySide6.QtGui.QTransform = Default(QTransform)) +``` + +## Root Cause + +The `QGraphicsScene.setSelectionArea()` method signature changed in PySide6 6.7. The old signature allowed: + +```python +setSelectionArea(path, mode) # mode = Qt.ItemSelectionMode +``` + +The new signature requires: + +```python +setSelectionArea(path, operation, mode) # operation = Qt.ItemSelectionOperation +``` + +## Affected File + +`NodeGraphQt/widgets/viewer.py` line 524-526 + +## Current Code + +```python +self.scene().setSelectionArea( + path, QtCore.Qt.IntersectsItemShape +) +``` + +## Fix + +```python +self.scene().setSelectionArea( + path, QtCore.Qt.ReplaceSelection, + QtCore.Qt.IntersectsItemShape +) +``` + +## Environment + +- Python: 3.12 +- PySide6: 6.6.3.1 (installed by NodeGraphQt-QuiltiX-fork, but issue affects 6.7+) +- NodeGraphQt-QuiltiX-fork: 0.7.0 + +## Workaround + +Apply this patch after installation: + +```python +# In viewer.py, change line 524-526 from: +self.scene().setSelectionArea( + path, QtCore.Qt.IntersectsItemShape +) + +# To: +self.scene().setSelectionArea( + path, QtCore.Qt.ReplaceSelection, + QtCore.Qt.IntersectsItemShape +) +``` + +## Related + +This issue may also exist in: +- Original NodeGraphQt +- OdenGraphQt +- Other forks + +The fix is backward compatible with older PySide6 versions that support the 3-argument signature. diff --git a/patches/nodegraphqt_pyside6_compat.patch b/patches/nodegraphqt_pyside6_compat.patch new file mode 100644 index 0000000..ef50717 --- /dev/null +++ b/patches/nodegraphqt_pyside6_compat.patch @@ -0,0 +1,13 @@ +--- a/NodeGraphQt/widgets/viewer.py ++++ b/NodeGraphQt/widgets/viewer.py +@@ -521,8 +521,10 @@ class NodeViewer(QtWidgets.QGraphicsView): + path = QtGui.QPainterPath() + path.addRect(map_rect) + self._rubber_band.setGeometry(rect) ++ # PySide6 6.7+ requires ItemSelectionOperation parameter + self.scene().setSelectionArea( +- path, QtCore.Qt.IntersectsItemShape ++ path, QtCore.Qt.ReplaceSelection, ++ QtCore.Qt.IntersectsItemShape + ) + self.scene().update(map_rect) diff --git a/scripts/patch_nodegraphqt.py b/scripts/patch_nodegraphqt.py new file mode 100644 index 0000000..dc78110 --- /dev/null +++ b/scripts/patch_nodegraphqt.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python3 +"""Patch NodeGraphQt for PySide6 6.7+ compatibility. + +The setSelectionArea() API changed in PySide6 6.7 to require an +ItemSelectionOperation parameter. This script patches the installed +NodeGraphQt package to work with newer PySide6 versions. + +Issue: setSelectionArea(path, mode) -> setSelectionArea(path, operation, mode) + +Usage: + python scripts/patch_nodegraphqt.py + +This can be run after `pip install NodeGraphQt-QuiltiX-fork[pyside6]` +""" + +import sys +import site +from pathlib import Path + + +def find_viewer_file(): + """Find the NodeGraphQt viewer.py file in site-packages.""" + # Check common locations + for site_dir in site.getsitepackages() + [site.getusersitepackages()]: + viewer_path = Path(site_dir) / "NodeGraphQt" / "widgets" / "viewer.py" + if viewer_path.exists(): + return viewer_path + + # Check virtual environment + venv_path = Path(sys.prefix) / "lib" + for python_dir in venv_path.glob("python*"): + viewer_path = python_dir / "site-packages" / "NodeGraphQt" / "widgets" / "viewer.py" + if viewer_path.exists(): + return viewer_path + + return None + + +def patch_file(viewer_path: Path) -> bool: + """Apply the PySide6 compatibility patch.""" + content = viewer_path.read_text() + + # Check if already patched + if "Qt.ReplaceSelection" in content: + print(f"Already patched: {viewer_path}") + return True + + # The old code pattern + old_code = """self.scene().setSelectionArea( + path, QtCore.Qt.IntersectsItemShape + )""" + + # The new code with ItemSelectionOperation + new_code = """self.scene().setSelectionArea( + path, QtCore.Qt.ReplaceSelection, + QtCore.Qt.IntersectsItemShape + )""" + + if old_code not in content: + print(f"Warning: Could not find code to patch in {viewer_path}") + print("The file may have a different format or already be modified.") + return False + + # Apply patch + patched_content = content.replace(old_code, new_code) + + # Backup original + backup_path = viewer_path.with_suffix(".py.bak") + if not backup_path.exists(): + viewer_path.rename(backup_path) + print(f"Backup created: {backup_path}") + + # Write patched file + viewer_path.write_text(patched_content) + print(f"Patched successfully: {viewer_path}") + return True + + +def main(): + print("NodeGraphQt PySide6 Compatibility Patch") + print("=" * 40) + + viewer_path = find_viewer_file() + + if not viewer_path: + print("Error: Could not find NodeGraphQt installation.") + print("Make sure NodeGraphQt-QuiltiX-fork is installed:") + print(" pip install 'NodeGraphQt-QuiltiX-fork[pyside6]'") + return 1 + + print(f"Found: {viewer_path}") + + if patch_file(viewer_path): + print("\nPatch applied successfully!") + print("The rubber band selection should now work in PySide6 6.7+") + return 0 + else: + print("\nPatch failed.") + return 1 + + +if __name__ == "__main__": + sys.exit(main())