class OpenGLBackend(QGLWidget, OpenGLPlotCanvas): _signalRedisplay = pyqtSignal() # PyQt binds it to instances def __init__(self, parent=None, **kw): QGLWidget.__init__(self, parent) self._signalRedisplay.connect(self.update) self.setAutoFillBackground(False) self.setMouseTracking(True) OpenGLPlotCanvas.__init__(self, parent, **kw) def postRedisplay(self): """Thread-safe call to QWidget.update.""" self._signalRedisplay.emit() # Mouse events # _MOUSE_BTNS = {1: 'left', 2: 'right', 4: 'middle'} def sizeHint(self): return QSize(8 * 80, 6 * 80) # Mimic MatplotlibBackend def mousePressEvent(self, event): xPixel, yPixel = event.x(), event.y() btn = self._MOUSE_BTNS[event.button()] self.onMousePress(xPixel, yPixel, btn) event.accept() def mouseMoveEvent(self, event): xPixel, yPixel = event.x(), event.y() self.onMouseMove(xPixel, yPixel) event.accept() def mouseReleaseEvent(self, event): xPixel, yPixel = event.x(), event.y() btn = self._MOUSE_BTNS[event.button()] self.onMouseRelease(xPixel, yPixel, btn) event.accept() def wheelEvent(self, event): xPixel, yPixel = event.x(), event.y() if hasattr(event, 'angleDelta'): # Qt 5 delta = event.angleDelta().y() else: # Qt 4 support delta = event.delta() angleInDegrees = delta / 8. self.onMouseWheel(xPixel, yPixel, angleInDegrees) event.accept() _CURSORS = { CURSOR_DEFAULT: Qt.ArrowCursor, CURSOR_POINTING: Qt.PointingHandCursor, CURSOR_SIZE_HOR: Qt.SizeHorCursor, CURSOR_SIZE_VER: Qt.SizeVerCursor, CURSOR_SIZE_ALL: Qt.SizeAllCursor, } def setCursor(self, cursor=CURSOR_DEFAULT): cursor = self._CURSORS[cursor] super(OpenGLBackend, self).setCursor(QCursor(cursor)) # Widget def getWidgetHandle(self): return self # PySide seems to need proxy methods def initializeGL(self): return OpenGLPlotCanvas.initializeGL(self) def paintGL(self): return OpenGLPlotCanvas.paintGL(self) def resizeGL(self, width, height): return OpenGLPlotCanvas.resizeGL(self, width, height)
class OSMesaGLBackend(QLabel, OpenGLPlotCanvas): _signalRedisplay = pyqtSignal() # PyQt binds it to instances _currentContext = None def __init__(self, parent=None, **kw): # Qt init QLabel.__init__(self, parent) self._signalRedisplay.connect(self.update) self.setAutoFillBackground(False) self.setMouseTracking(True) # OS Mesa init self.__dirtyPixmap = True self.__context = mesa.OSMesaCreateContext(mesa.OSMESA_BGRA, None) assert self.__context != 0 # OpenGL Plot backend init OpenGLPlotCanvas.__init__(self, parent, **kw) def __del__(self): mesa.OSMesaDestroyContext(self.__context) @classmethod def getCurrentContext(cls): """Returns the current OSMesa GL context.""" return cls._currentContext def makeCurrent(self): """Set the current OSMesa GL context to this instance. There is one context per OSMesaGLBackend instance. """ OSMesaGLBackend._currentContext = self def postRedisplay(self): self.__dirtyPixmap = True self._signalRedisplay.emit() # Paint # def paintEvent(self, event): # Only refresh content when paint comes from backend if self.__dirtyPixmap: self.__dirtyPixmap = False height, width = self.__pixmap.shape[0:2] assert width == self.size().width() assert height == self.size().height() errCode = mesa.OSMesaMakeCurrent(self.__context, self.__pixmap, gl.GL_UNSIGNED_BYTE, width, height) assert errCode == gl.GL_TRUE self.makeCurrent() self.paintGL() gl.glFinish() image = QImage(self.__pixmap.data, width, height, QImage.Format_ARGB32) self.setPixmap(QPixmap.fromImage(image)) QLabel.paintEvent(self, event) def resizeEvent(self, event): width, height = self.size().width(), self.size().height() # Update underlying pixmap self.__dirtyPixmap = True self.__pixmap = np.empty((height, width, 4), dtype=np.uint8) errCode = mesa.OSMesaMakeCurrent(self.__context, self.__pixmap, gl.GL_UNSIGNED_BYTE, width, height) assert errCode == gl.GL_TRUE mesa.OSMesaPixelStore(mesa.OSMESA_Y_UP, 0) self.makeCurrent() gl.testGL() self.initializeGL() self.resizeGL(width, height) QLabel.resizeEvent(self, event) # Mouse events # _MOUSE_BTNS = {1: 'left', 2: 'right', 4: 'middle'} def sizeHint(self): return QSize(8 * 80, 6 * 80) # Mimic MatplotlibBackend def mousePressEvent(self, event): xPixel, yPixel = event.x(), event.y() btn = self._MOUSE_BTNS[event.button()] self.onMousePress(xPixel, yPixel, btn) event.accept() def mouseMoveEvent(self, event): xPixel, yPixel = event.x(), event.y() self.onMouseMove(xPixel, yPixel) event.accept() def mouseReleaseEvent(self, event): xPixel, yPixel = event.x(), event.y() btn = self._MOUSE_BTNS[event.button()] self.onMouseRelease(xPixel, yPixel, btn) event.accept() def wheelEvent(self, event): xPixel, yPixel = event.x(), event.y() angleInDegrees = event.delta() / 8. self.onMouseWheel(xPixel, yPixel, angleInDegrees) event.accept() _CURSORS = { CURSOR_DEFAULT: Qt.ArrowCursor, CURSOR_POINTING: Qt.PointingHandCursor, CURSOR_SIZE_HOR: Qt.SizeHorCursor, CURSOR_SIZE_VER: Qt.SizeVerCursor, CURSOR_SIZE_ALL: Qt.SizeAllCursor, } def setCursor(self, cursor=CURSOR_DEFAULT): cursor = self._CURSORS[cursor] QLabel.setCursor(self, QCursor(cursor)) # Widget handle def getWidgetHandle(self): return self