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.
This commit is contained in:
KIU Shueng Chuan 2021-01-23 19:21:09 +08:00
parent 5186cbd80b
commit d96ec314be

View File

@ -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.drawImage(self.rect(), self._img, QtCore.QRect(0, 0, self._img.width(), self._img.height()))
p.end() p.end()
def serialize_mouse_common(self, ev): def serialize_mouse_enum(self, *args):
if QT_LIB == 'PyQt6': # PyQt6 can pickle enums and flags but cannot cast to int
# PyQt6 can pickle MouseButtons and KeyboardModifiers but cannot cast to int # PyQt5 5.12, PyQt5 5.15, PySide2 5.15, PySide6 can pickle enums but not flags
btns = ev.buttons() # PySide2 5.12 cannot pickle enums nor flags
mods = ev.modifiers() # MouseButtons and KeyboardModifiers are flags
else: if QT_LIB != 'PyQt6':
# PyQt5, PySide2, PySide6 cannot pickle MouseButtons and KeyboardModifiers args = [int(x) for x in args]
btns = int(ev.buttons()) return args
mods = int(ev.modifiers())
return (btns, mods)
def serialize_mouse_event(self, ev): def serialize_mouse_event(self, ev):
# lpos, gpos = ev.localPos(), ev.screenPos() lpos, gpos = ev.localPos(), ev.screenPos()
# RemoteGraphicsView Renderer assumes to be at (0, 0) typ, btn, btns, mods = self.serialize_mouse_enum(
gpos = lpos = ev.localPos() ev.type(), ev.button(), ev.buttons(), ev.modifiers())
btns, mods = self.serialize_mouse_common(ev) return (typ, lpos, gpos, btn, btns, mods)
return (ev.type(), lpos, gpos, ev.button(), btns, mods)
def serialize_wheel_event(self, ev): def serialize_wheel_event(self, ev):
# lpos, gpos = ev.position(), globalPosition() # {PyQt6, PySide6} have position()
# RemoteGraphicsView Renderer assumes to be at (0, 0) # {PyQt5, PySide2} 5.15 have position()
gpos = lpos = ev.position() # {PyQt5, PySide2} 5.15 have posF() (contrary to C++ docs)
btns, mods = self.serialize_mouse_common(ev) # {PyQt5, PySide2} 5.12 have posF()
return (lpos, gpos, ev.pixelDelta(), ev.angleDelta(), btns, mods, ev.phase(), ev.inverted()) 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): def mousePressEvent(self, ev):
self._view.mousePressEvent(self.serialize_mouse_event(ev), _callSync='off') self._view.mousePressEvent(self.serialize_mouse_event(ev), _callSync='off')
@ -148,7 +149,8 @@ class RemoteGraphicsView(QtGui.QWidget):
return super().enterEvent(ev) return super().enterEvent(ev)
def leaveEvent(self, 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) return super().leaveEvent(ev)
def remoteProcess(self): def remoteProcess(self):
@ -252,16 +254,19 @@ class Renderer(GraphicsView):
def deserialize_mouse_event(self, mouse_event): def deserialize_mouse_event(self, mouse_event):
typ, pos, gpos, btn, btns, mods = mouse_event typ, pos, gpos, btn, btns, mods = mouse_event
typ = QtCore.QEvent.Type(typ) # this line needed by PyQt5 only if QT_LIB != 'PyQt6':
btns = QtCore.Qt.MouseButtons(btns) typ = QtCore.QEvent.Type(typ)
mods = QtCore.Qt.KeyboardModifiers(mods) btn = QtCore.Qt.MouseButton(btn)
btns = QtCore.Qt.MouseButtons(btns)
mods = QtCore.Qt.KeyboardModifiers(mods)
return QtGui.QMouseEvent(typ, pos, gpos, btn, btns, mods) return QtGui.QMouseEvent(typ, pos, gpos, btn, btns, mods)
def deserialize_wheel_event(self, wheel_event): 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) btns = QtCore.Qt.MouseButtons(btns)
mods = QtCore.Qt.KeyboardModifiers(mods) 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): def mousePressEvent(self, mouse_event):
ev = self.deserialize_mouse_event(mouse_event) ev = self.deserialize_mouse_event(mouse_event)
@ -284,7 +289,7 @@ class Renderer(GraphicsView):
return super().enterEvent(ev) return super().enterEvent(ev)
def leaveEvent(self, typ): def leaveEvent(self, typ):
typ = QtCore.QEvent.Type(typ) # this line needed by PyQt5 only typ = QtCore.QEvent.Type(typ)
ev = QtCore.QEvent(typ) ev = QtCore.QEvent(typ)
return super().leaveEvent(ev) return super().leaveEvent(ev)