pymol_gl_widget.py (pymol-v2.1.0.tar.bz2) | : | pymol_gl_widget.py (pymol-open-source-2.2.0) | ||
---|---|---|---|---|
from __future__ import absolute_import | from __future__ import absolute_import | |||
import sys | import sys | |||
from pymol2 import SingletonPyMOL as PyMOL | from pymol2 import SingletonPyMOL as PyMOL | |||
from pymol.Qt import QtCore, QtOpenGL | import pymol | |||
from pymol.Qt import QtCore | ||||
from pymol.Qt import QtGui | ||||
from pymol.Qt import QtWidgets | from pymol.Qt import QtWidgets | |||
Gesture = QtCore.QEvent.Gesture | Gesture = QtCore.QEvent.Gesture | |||
Qt = QtCore.Qt | Qt = QtCore.Qt | |||
from .keymapping import get_modifiers | from .keymapping import get_modifiers | |||
# don't import the heavy OpenGL (PyOpenGL) module | # don't import the heavy OpenGL (PyOpenGL) module | |||
from pymol._cmd import glViewport | from pymol._cmd import glViewport | |||
class PyMOLGLWidget(QtOpenGL.QGLWidget): | # QOpenGLWidget is supposed to supersede QGLWidget, but has issues (e.g. | |||
# no stereo support) | ||||
USE_QOPENGLWIDGET = pymol.IS_MACOS | ||||
if USE_QOPENGLWIDGET: | ||||
BaseGLWidget = QtWidgets.QOpenGLWidget | ||||
AUTO_DETECT_STEREO = False | ||||
else: | ||||
from pymol.Qt import QtOpenGL | ||||
BaseGLWidget = QtOpenGL.QGLWidget | ||||
# only attempt stereo detection in Qt <= 5.6 (with 5.9+ on Linux I | ||||
# get GL_DOUBLEBUFFER=0 with flickering when requesting stereo) | ||||
AUTO_DETECT_STEREO = pymol.IS_WINDOWS or QtCore.QT_VERSION < 0x50700 | ||||
class PyMOLGLWidget(BaseGLWidget): | ||||
''' | ''' | |||
PyMOL OpenGL Widget | PyMOL OpenGL Widget | |||
''' | ''' | |||
# mouse button map | # mouse button map | |||
_buttonMap = { | _buttonMap = { | |||
Qt.LeftButton: 0, | Qt.LeftButton: 0, | |||
Qt.MidButton: 1, | Qt.MidButton: 1, | |||
Qt.RightButton: 2, | Qt.RightButton: 2, | |||
} | } | |||
def __init__(self, parent): | def __init__(self, parent): | |||
self.gui = parent | self.gui = parent | |||
# OpenGL context setup | # OpenGL context setup | |||
f = QtOpenGL.QGLFormat() | if USE_QOPENGLWIDGET: | |||
f.setRgba(True) | f = QtGui.QSurfaceFormat() | |||
f.setDepth(True) | else: | |||
f.setDoubleBuffer(True) | f = QtOpenGL.QGLFormat() | |||
from pymol.invocation import options | from pymol.invocation import options | |||
# logic equivalent to layer5/main.cpp:launch | # logic equivalent to layer5/main.cpp:launch | |||
if options.multisample: | if options.multisample: | |||
f.setSampleBuffers(True) | f.setSamples(4) | |||
if options.force_stereo != -1: | if options.force_stereo != -1: | |||
# See layer1/Setting.h for stereo modes | # See layer1/Setting.h for stereo modes | |||
if options.stereo_mode in (0, 1, 12): | if options.stereo_mode in (1, 12) or ( | |||
# this effectively disables stereo detection | options.stereo_mode == 0 and AUTO_DETECT_STEREO): | |||
# on Linux that is faulty in QGLWidget / PyQt5 | f.setStereo(True) | |||
if not (options.stereo_mode == 0 and | ||||
sys.platform.startswith("linux")): | ||||
f.setStereo(True) | ||||
if options.stereo_mode in (11, 12): | if options.stereo_mode in (11, 12) and not USE_QOPENGLWIDGET: | |||
f.setAccum(True) | f.setAccum(True) | |||
if options.stereo_mode in (0, 6, 7, 8, 9): | if USE_QOPENGLWIDGET: | |||
f.setStencil(True) | super(PyMOLGLWidget, self).__init__(parent=parent) | |||
self.setFormat(f) | ||||
QtOpenGL.QGLWidget.__init__(self, f, parent=parent) | else: | |||
super(PyMOLGLWidget, self).__init__(f, parent=parent) | ||||
if not self.isValid(): | ||||
raise RuntimeError('OpenGL initialization failed') | ||||
f_actual = self.format() | ||||
# report if quad buffer available | ||||
options.stereo_capable = int(f_actual.stereo() or | ||||
(options.force_stereo == 1)) | ||||
# feedback if stereo request failed | ||||
if options.stereo_mode and ( | ||||
# QTBUG-59636 f.stereo() and not f_actual.stereo() or | ||||
f.accum() and not f_actual.accum() or | ||||
f.stencil() and not f_actual.stencil()): | ||||
# cPyMOLGlobals_LaunchStatus_StereoFailed | ||||
options.launch_status |= 0x1 | ||||
# feedback if multisample request failed | ||||
if options.multisample and not f_actual.sampleBuffers(): | ||||
# cPyMOLGlobals_LaunchStatus_MultisampleFailed | ||||
options.launch_status |= 0x2 | ||||
# pymol instance | # pymol instance | |||
self.pymol = PyMOL() | self.pymol = PyMOL() | |||
self.pymol.start() | self.pymol.start() | |||
self.cmd = self.pymol.cmd | self.cmd = self.pymol.cmd | |||
# capture python output for feedback | # capture python output for feedback | |||
import pcatch | import pcatch | |||
pcatch._install() | pcatch._install() | |||
skipping to change at line 199 | skipping to change at line 192 | |||
int(self.fb_scale * (self.height() - ev.y())), | int(self.fb_scale * (self.height() - ev.y())), | |||
pymolmod) | pymolmod) | |||
self.pymol.button(button, 0, *args) | self.pymol.button(button, 0, *args) | |||
self.pymol.button(button, 1, *args) | self.pymol.button(button, 1, *args) | |||
########################## | ########################## | |||
# OpenGL | # OpenGL | |||
########################## | ########################## | |||
def paintGL(self): | def paintGL(self): | |||
glViewport(0, 0, int(self.fb_scale * self.width()), | if not USE_QOPENGLWIDGET: | |||
glViewport(0, 0, int(self.fb_scale * self.width()), | ||||
int(self.fb_scale * self.height())) | int(self.fb_scale * self.height())) | |||
self.pymol.draw() | self.pymol.draw() | |||
self._timer.start(0) | self._timer.start(0) | |||
def resizeGL(self, w, h): | def resizeGL(self, w, h): | |||
if USE_QOPENGLWIDGET: | ||||
w = int(w * self.fb_scale) | ||||
h = int(h * self.fb_scale) | ||||
self.pymol.reshape(w, h, True) | self.pymol.reshape(w, h, True) | |||
def updateFbScale(self, context): | def updateFbScale(self, context): | |||
'''Update PyMOL's display scale factor from the window or screen context | '''Update PyMOL's display scale factor from the window or screen context | |||
@type context: QWindow or QScreen | @type context: QWindow or QScreen | |||
''' | ''' | |||
self.fb_scale = context.devicePixelRatio() | self.fb_scale = context.devicePixelRatio() | |||
try: | try: | |||
self.cmd.set('display_scale_factor', int(self.fb_scale)) | self.cmd.set('display_scale_factor', int(self.fb_scale)) | |||
except BaseException as e: | except BaseException as e: | |||
# fails with modal draw (mpng ..., modal=1) | # fails with modal draw (mpng ..., modal=1) | |||
print(e) | print(e) | |||
def initializeGL(self): | def initializeGL(self): | |||
# Scale framebuffer for Retina displays | # Scale framebuffer for Retina displays | |||
try: | try: | |||
window = self.windowHandle() | window = self.windowHandle() | |||
# QOpenGLWidget workaround | ||||
if window is None: | ||||
window = self.parent().windowHandle() | ||||
self.updateFbScale(window) | self.updateFbScale(window) | |||
window.screenChanged.connect(self.updateFbScale) | window.screenChanged.connect(self.updateFbScale) | |||
except AttributeError: | except AttributeError: | |||
# Fallback for Qt4 | # Fallback for Qt4 | |||
self.fb_scale = 1.0 | self.fb_scale = 1.0 | |||
def _pymolProcess(self): | def _pymolProcess(self): | |||
idle = self.pymol.idle() | idle = self.pymol.idle() | |||
if idle or self.pymol.getRedisplay(): | if idle or self.pymol.getRedisplay(): | |||
self.update() | self.update() | |||
End of changes. 10 change blocks. | ||||
41 lines changed or deleted | 44 lines changed or added |