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 <noreply@anthropic.com>
This commit is contained in:
parent
042be8b49b
commit
ad9a59283c
|
|
@ -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.
|
||||
|
|
@ -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)
|
||||
|
|
@ -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())
|
||||
Loading…
Reference in New Issue