From d96ec314beaad7a51f93d54eb670211ec551e5f2 Mon Sep 17 00:00:00 2001 From: KIU Shueng Chuan Date: Sat, 23 Jan 2021 19:21:09 +0800 Subject: [PATCH] RemoteGraphicsView.py : fix mouse interactions for Qt 5.12 mouse interactions had previously only been tested on Qt 5.15 and Qt 6.0, and found to be not working on Qt 5.12. differences in Qt 5.12 and Qt 5.15 are documented in the comments. an addition bug found (and fixed) was that right-click was drawing the pop-up menu away from the mouse position. --- pyqtgraph/widgets/RemoteGraphicsView.py | 59 ++++++++++++++----------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/pyqtgraph/widgets/RemoteGraphicsView.py b/pyqtgraph/widgets/RemoteGraphicsView.py index 620f4085..a289f9e5 100644 --- a/pyqtgraph/widgets/RemoteGraphicsView.py +++ b/pyqtgraph/widgets/RemoteGraphicsView.py @@ -97,30 +97,31 @@ class RemoteGraphicsView(QtGui.QWidget): p.drawImage(self.rect(), self._img, QtCore.QRect(0, 0, self._img.width(), self._img.height())) p.end() - def serialize_mouse_common(self, ev): - if QT_LIB == 'PyQt6': - # PyQt6 can pickle MouseButtons and KeyboardModifiers but cannot cast to int - btns = ev.buttons() - mods = ev.modifiers() - else: - # PyQt5, PySide2, PySide6 cannot pickle MouseButtons and KeyboardModifiers - btns = int(ev.buttons()) - mods = int(ev.modifiers()) - return (btns, mods) + def serialize_mouse_enum(self, *args): + # PyQt6 can pickle enums and flags but cannot cast to int + # PyQt5 5.12, PyQt5 5.15, PySide2 5.15, PySide6 can pickle enums but not flags + # PySide2 5.12 cannot pickle enums nor flags + # MouseButtons and KeyboardModifiers are flags + if QT_LIB != 'PyQt6': + args = [int(x) for x in args] + return args def serialize_mouse_event(self, ev): - # lpos, gpos = ev.localPos(), ev.screenPos() - # RemoteGraphicsView Renderer assumes to be at (0, 0) - gpos = lpos = ev.localPos() - btns, mods = self.serialize_mouse_common(ev) - return (ev.type(), lpos, gpos, ev.button(), btns, mods) + lpos, gpos = ev.localPos(), ev.screenPos() + typ, btn, btns, mods = self.serialize_mouse_enum( + ev.type(), ev.button(), ev.buttons(), ev.modifiers()) + return (typ, lpos, gpos, btn, btns, mods) def serialize_wheel_event(self, ev): - # lpos, gpos = ev.position(), globalPosition() - # RemoteGraphicsView Renderer assumes to be at (0, 0) - gpos = lpos = ev.position() - btns, mods = self.serialize_mouse_common(ev) - return (lpos, gpos, ev.pixelDelta(), ev.angleDelta(), btns, mods, ev.phase(), ev.inverted()) + # {PyQt6, PySide6} have position() + # {PyQt5, PySide2} 5.15 have position() + # {PyQt5, PySide2} 5.15 have posF() (contrary to C++ docs) + # {PyQt5, PySide2} 5.12 have posF() + lpos = ev.position() if hasattr(ev, 'position') else ev.posF() + # gpos = ev.globalPosition() if hasattr(ev, 'globalPosition') else ev.globalPosF() + gpos = lpos # RemoteGraphicsView Renderer assumes to be at (0, 0) + btns, mods, phase = self.serialize_mouse_enum(ev.buttons(), ev.modifiers(), ev.phase()) + return (lpos, gpos, ev.pixelDelta(), ev.angleDelta(), btns, mods, phase, ev.inverted()) def mousePressEvent(self, ev): self._view.mousePressEvent(self.serialize_mouse_event(ev), _callSync='off') @@ -148,7 +149,8 @@ class RemoteGraphicsView(QtGui.QWidget): return super().enterEvent(ev) def leaveEvent(self, ev): - self._view.leaveEvent(ev.type(), _callSync='off') + typ, = self.serialize_mouse_enum(ev.type()) + self._view.leaveEvent(typ, _callSync='off') return super().leaveEvent(ev) def remoteProcess(self): @@ -252,16 +254,19 @@ class Renderer(GraphicsView): def deserialize_mouse_event(self, mouse_event): typ, pos, gpos, btn, btns, mods = mouse_event - typ = QtCore.QEvent.Type(typ) # this line needed by PyQt5 only - btns = QtCore.Qt.MouseButtons(btns) - mods = QtCore.Qt.KeyboardModifiers(mods) + if QT_LIB != 'PyQt6': + typ = QtCore.QEvent.Type(typ) + btn = QtCore.Qt.MouseButton(btn) + btns = QtCore.Qt.MouseButtons(btns) + mods = QtCore.Qt.KeyboardModifiers(mods) return QtGui.QMouseEvent(typ, pos, gpos, btn, btns, mods) def deserialize_wheel_event(self, wheel_event): - pos, gpos, pixelDelta, angleDelta, btns, mods, scrollPhase, inverted = wheel_event + pos, gpos, pixelDelta, angleDelta, btns, mods, phase, inverted = wheel_event btns = QtCore.Qt.MouseButtons(btns) mods = QtCore.Qt.KeyboardModifiers(mods) - return QtGui.QWheelEvent(pos, gpos, pixelDelta, angleDelta, btns, mods, scrollPhase, inverted) + phase = QtCore.Qt.ScrollPhase(phase) + return QtGui.QWheelEvent(pos, gpos, pixelDelta, angleDelta, btns, mods, phase, inverted) def mousePressEvent(self, mouse_event): ev = self.deserialize_mouse_event(mouse_event) @@ -284,7 +289,7 @@ class Renderer(GraphicsView): return super().enterEvent(ev) def leaveEvent(self, typ): - typ = QtCore.QEvent.Type(typ) # this line needed by PyQt5 only + typ = QtCore.QEvent.Type(typ) ev = QtCore.QEvent(typ) return super().leaveEvent(ev)