def __init__(self, parent): self.gui = parent self.fb_scale = 1.0 # OpenGL context setup if USE_QOPENGLWIDGET: f = QtGui.QSurfaceFormat() else: f = QtOpenGL.QGLFormat() from pymol.invocation import options # logic equivalent to layer5/main.cpp:launch if options.multisample: f.setSamples(4) if options.force_stereo != -1: # See layer1/Setting.h for stereo modes if options.stereo_mode in (1, 12) or ( options.stereo_mode == 0 and AUTO_DETECT_STEREO): f.setStereo(True) if options.stereo_mode in (11, 12) and not USE_QOPENGLWIDGET: f.setAccum(True) if USE_QOPENGLWIDGET: super(PyMOLGLWidget, self).__init__(parent=parent) self.setFormat(f) self.setUpdateBehavior(QtWidgets.QOpenGLWidget.PartialUpdate) else: super(PyMOLGLWidget, self).__init__(f, parent=parent) # pymol instance self.pymol = PyMOL() self.pymol.start() self.cmd = self.pymol.cmd # capture python output for feedback import pcatch pcatch._install() # for passive move drag self.setMouseTracking(True) # for accepting keyboard input (command line, shortcuts) self.setFocusPolicy(Qt.ClickFocus) # for idle rendering self._timer = QtCore.QTimer() self._timer.setSingleShot(True) self._timer.timeout.connect(self._pymolProcess) # drag n drop self.setAcceptDrops(True) # pinch-zoom self.grabGesture(Qt.PinchGesture)
def __init__(self, parent): self.gui = parent self.fb_scale = 1.0 # OpenGL context setup if USE_QOPENGLWIDGET: f = QtGui.QSurfaceFormat() else: f = QtOpenGL.QGLFormat() from pymol.invocation import options # logic equivalent to layer5/main.cpp:launch if options.multisample: f.setSamples(4) if options.force_stereo != -1: # See layer1/Setting.h for stereo modes if options.stereo_mode in (1, 12) or ( options.stereo_mode == 0 and AUTO_DETECT_STEREO): f.setStereo(True) if options.stereo_mode in (11, 12) and not USE_QOPENGLWIDGET: f.setAccum(True) if USE_QOPENGLWIDGET: super(PyMOLGLWidget, self).__init__(parent=parent) self.setFormat(f) else: super(PyMOLGLWidget, self).__init__(f, parent=parent) # pymol instance self.pymol = PyMOL() self.pymol.start() self.cmd = self.pymol.cmd # capture python output for feedback import pcatch pcatch._install() # for passive move drag self.setMouseTracking(True) # for accepting keyboard input (command line, shortcuts) self.setFocusPolicy(Qt.ClickFocus) # for idle rendering self._timer = QtCore.QTimer() self._timer.setSingleShot(True) self._timer.timeout.connect(self._pymolProcess) # drag n drop self.setAcceptDrops(True) # pinch-zoom self.grabGesture(Qt.PinchGesture)
class PyMOLGLWidget(BaseGLWidget): ''' PyMOL OpenGL Widget ''' # mouse button map _buttonMap = { Qt.LeftButton: 0, Qt.MidButton: 1, Qt.RightButton: 2, } def __init__(self, parent): self.gui = parent # OpenGL context setup if USE_QOPENGLWIDGET: f = QtGui.QSurfaceFormat() else: f = QtOpenGL.QGLFormat() from pymol.invocation import options # logic equivalent to layer5/main.cpp:launch if options.multisample: f.setSamples(4) if options.force_stereo != -1: # See layer1/Setting.h for stereo modes if options.stereo_mode in (1, 12) or ( options.stereo_mode == 0 and AUTO_DETECT_STEREO): f.setStereo(True) if options.stereo_mode in (11, 12) and not USE_QOPENGLWIDGET: f.setAccum(True) if USE_QOPENGLWIDGET: super(PyMOLGLWidget, self).__init__(parent=parent) self.setFormat(f) else: super(PyMOLGLWidget, self).__init__(f, parent=parent) # pymol instance self.pymol = PyMOL() self.pymol.start() self.cmd = self.pymol.cmd # capture python output for feedback import pcatch pcatch._install() # for passive move drag self.setMouseTracking(True) # for accepting keyboard input (command line, shortcuts) self.setFocusPolicy(Qt.ClickFocus) # for idle rendering self._timer = QtCore.QTimer() self._timer.setSingleShot(True) self._timer.timeout.connect(self._pymolProcess) # drag n drop self.setAcceptDrops(True) # pinch-zoom self.grabGesture(Qt.PinchGesture) def sizeHint(self): # default 640 + internal_gui, 480 + internal_feedback return QtCore.QSize(860, 498) ########################## # Input Events ########################## def event(self, ev): if ev.type() == Gesture: return self.gestureEvent(ev) return super(PyMOLGLWidget, self).event(ev) def gestureEvent(self, ev): gesture = ev.gesture(Qt.PinchGesture) if gesture is None: return False if gesture.state() == Qt.GestureStarted: self.pinch_start_z = self.cmd.get_view()[11] changeFlags = gesture.changeFlags() if changeFlags & QtWidgets.QPinchGesture.RotationAngleChanged: delta = gesture.lastRotationAngle() - gesture.rotationAngle() self.cmd.turn('z', delta) if changeFlags & QtWidgets.QPinchGesture.ScaleFactorChanged: view = list(self.cmd.get_view()) # best guess for https://bugreports.qt.io/browse/QTBUG-48138 totalscalefactor = gesture.totalScaleFactor() if totalscalefactor == 1.0: totalscalefactor = gesture.scaleFactor() z = self.pinch_start_z / totalscalefactor delta = z - view[11] view[11] = z view[15] -= delta view[16] -= delta self.cmd.set_view(view) return True def mouseMoveEvent(self, ev): self.pymol.drag(int(self.fb_scale * ev.x()), int(self.fb_scale * (self.height() - ev.y())), get_modifiers(ev)) def mousePressEvent(self, ev, state=0): if ev.button() not in self._buttonMap: return self.pymol.button(self._buttonMap[ev.button()], state, int(self.fb_scale * ev.x()), int(self.fb_scale * (self.height() - ev.y())), get_modifiers(ev)) def mouseReleaseEvent(self, ev): self.mousePressEvent(ev, 1) def wheelEvent(self, ev): pymolmod = get_modifiers(ev) try: delta = ev.delta() except AttributeError: # Qt5 angledelta = ev.angleDelta() delta = angledelta.y() if abs(delta) < abs(angledelta.x()): # Shift+Wheel emulates horizontal scrolling if not (ev.modifiers() & Qt.ShiftModifier): return delta = angledelta.x() if not delta: return button = 3 if delta > 0 else 4 args = (int(self.fb_scale * ev.x()), int(self.fb_scale * (self.height() - ev.y())), pymolmod) self.pymol.button(button, 0, *args) self.pymol.button(button, 1, *args) ########################## # OpenGL ########################## def paintGL(self): if not USE_QOPENGLWIDGET: glViewport(0, 0, int(self.fb_scale * self.width()), int(self.fb_scale * self.height())) self.pymol.draw() self._timer.start(0) 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) def updateFbScale(self, context): '''Update PyMOL's display scale factor from the window or screen context @type context: QWindow or QScreen ''' self.fb_scale = context.devicePixelRatio() try: self.cmd.set('display_scale_factor', int(self.fb_scale)) except BaseException as e: # fails with modal draw (mpng ..., modal=1) print(e) def initializeGL(self): # Scale framebuffer for Retina displays try: window = self.windowHandle() # QOpenGLWidget workaround if window is None: window = self.parent().windowHandle() self.updateFbScale(window) window.screenChanged.connect(self.updateFbScale) except AttributeError: # Fallback for Qt4 self.fb_scale = 1.0 def _pymolProcess(self): idle = self.pymol.idle() if idle or self.pymol.getRedisplay(): self.update() self._timer.start(20) ########################## # drag n drop ########################## def dragEnterEvent(self, event): if event.mimeData().hasUrls: event.accept() else: event.ignore() def dropEvent(self, event): if event.mimeData().hasUrls: for url in event.mimeData().urls(): if url.isLocalFile(): url = url.toLocalFile() else: url = url.toString() self.gui.load_dialog(url) event.accept()
class PyMOLGLWidget(BaseGLWidget): ''' PyMOL OpenGL Widget ''' # mouse button map _buttonMap = { Qt.LeftButton: 0, Qt.MidButton: 1, Qt.RightButton: 2, } def __init__(self, parent): self.gui = parent self.fb_scale = 1.0 # OpenGL context setup if USE_QOPENGLWIDGET: f = QtGui.QSurfaceFormat() else: f = QtOpenGL.QGLFormat() from pymol.invocation import options # logic equivalent to layer5/main.cpp:launch if options.multisample: f.setSamples(4) if options.force_stereo != -1: # See layer1/Setting.h for stereo modes if options.stereo_mode in (1, 12) or ( options.stereo_mode == 0 and AUTO_DETECT_STEREO): f.setStereo(True) if options.stereo_mode in (11, 12) and not USE_QOPENGLWIDGET: f.setAccum(True) if USE_QOPENGLWIDGET: super(PyMOLGLWidget, self).__init__(parent=parent) self.setFormat(f) else: super(PyMOLGLWidget, self).__init__(f, parent=parent) # pymol instance self.pymol = PyMOL() self.pymol.start() self.cmd = self.pymol.cmd # capture python output for feedback import pcatch pcatch._install() # for passive move drag self.setMouseTracking(True) # for accepting keyboard input (command line, shortcuts) self.setFocusPolicy(Qt.ClickFocus) # for idle rendering self._timer = QtCore.QTimer() self._timer.setSingleShot(True) self._timer.timeout.connect(self._pymolProcess) # drag n drop self.setAcceptDrops(True) # pinch-zoom self.grabGesture(Qt.PinchGesture) def sizeHint(self): # default 640 + internal_gui, 480 + internal_feedback return QtCore.QSize(860, 498) ########################## # Input Events ########################## def event(self, ev): if ev.type() == Gesture: return self.gestureEvent(ev) return super(PyMOLGLWidget, self).event(ev) def gestureEvent(self, ev): gesture = ev.gesture(Qt.PinchGesture) if gesture is None: return False if gesture.state() == Qt.GestureStarted: self.pinch_start_z = self.cmd.get_view()[11] changeFlags = gesture.changeFlags() if changeFlags & QtWidgets.QPinchGesture.RotationAngleChanged: delta = gesture.lastRotationAngle() - gesture.rotationAngle() self.cmd.turn('z', delta) if changeFlags & QtWidgets.QPinchGesture.ScaleFactorChanged: view = list(self.cmd.get_view()) # best guess for https://bugreports.qt.io/browse/QTBUG-48138 totalscalefactor = gesture.totalScaleFactor() if totalscalefactor == 1.0: totalscalefactor = gesture.scaleFactor() z = self.pinch_start_z / totalscalefactor delta = z - view[11] view[11] = z view[15] -= delta view[16] -= delta self.cmd.set_view(view) return True def mouseMoveEvent(self, ev): self.pymol.drag(int(self.fb_scale * ev.x()), int(self.fb_scale * (self.height() - ev.y())), get_modifiers(ev)) def mousePressEvent(self, ev, state=0): if ev.button() not in self._buttonMap: return self.pymol.button(self._buttonMap[ev.button()], state, int(self.fb_scale * ev.x()), int(self.fb_scale * (self.height() - ev.y())), get_modifiers(ev)) def mouseReleaseEvent(self, ev): self.mousePressEvent(ev, 1) def wheelEvent(self, ev): pymolmod = get_modifiers(ev) try: delta = ev.delta() except AttributeError: # Qt5 angledelta = ev.angleDelta() delta = angledelta.y() if abs(delta) < abs(angledelta.x()): # Shift+Wheel emulates horizontal scrolling if not (ev.modifiers() & Qt.ShiftModifier): return delta = angledelta.x() if not delta: return button = 3 if delta > 0 else 4 args = (int(self.fb_scale * ev.x()), int(self.fb_scale * (self.height() - ev.y())), pymolmod) self.pymol.button(button, 0, *args) self.pymol.button(button, 1, *args) ########################## # OpenGL ########################## def paintGL(self): if not USE_QOPENGLWIDGET: glViewport(0, 0, int(self.fb_scale * self.width()), int(self.fb_scale * self.height())) self.pymol.draw() self._timer.start(0) 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) def updateFbScale(self, context): '''Update PyMOL's display scale factor from the window or screen context @type context: QWindow or QScreen ''' self.fb_scale = context.devicePixelRatio() try: self.cmd.set('display_scale_factor', int(self.fb_scale)) except BaseException as e: # fails with modal draw (mpng ..., modal=1) print(e) def initializeGL(self): # Scale framebuffer for Retina displays try: window = self.windowHandle() # QOpenGLWidget workaround if window is None: window = self.parent().windowHandle() self.updateFbScale(window) window.screenChanged.connect(self.updateFbScale) window.screen().physicalDotsPerInchChanged.connect( lambda dpi: self.updateFbScale(window)) except AttributeError: # Fallback for Qt4 pass def _pymolProcess(self): idle = self.pymol.idle() if idle or self.pymol.getRedisplay(): self.update() self._timer.start(20) ########################## # drag n drop ########################## def dragEnterEvent(self, event): if event.mimeData().hasUrls: event.accept() else: event.ignore() def dropEvent(self, event): if event.mimeData().hasUrls: for url in event.mimeData().urls(): if url.isLocalFile(): url = url.toLocalFile() else: url = url.toString() self.gui.load_dialog(url) event.accept()
3ALA CA 22 2.863 2.764 1.192 3ALA C 23 3.013 2.747 1.191 3ALA O 24 3.066 2.635 1.188 3ALA CB 25 2.813 2.842 1.316 3ALA H 26 2.848 2.549 1.189 3ALA HA 27 2.835 2.820 1.100 3ALA 1HB 28 2.703 2.857 1.313 3ALA 2HB 29 2.836 2.789 1.410 3ALA 3HB 30 2.858 2.942 1.322 3.41363 3.41363 2.41380 0.00000 0.00000 0.00000 0.00000 1.70681 1.70681 """ with open(GRO_PATH, "wt") as f: f.write(grodata) pymol = SingletonPyMOL() pymol.start() cmd = pymol.cmd cmd.load(CIF_PATH) # Test rendering cmd.png(PNG_PATH, ray=1) assert isfile(PNG_PATH) # Test correct integration of NumPy assert cmd.get_coordset(PDB_ID).shape == (304, 3) # Test if we can load a .gro file cmd.load(GRO_PATH, 'grodata') assert cmd.get_coordset('grodata').shape == (30, 3)
def __init__(self, parent): self.gui = parent # OpenGL context setup f = QtOpenGL.QGLFormat() f.setRgba(True) f.setDepth(True) f.setDoubleBuffer(True) from pymol.invocation import options # logic equivalent to layer5/main.cpp:launch if options.multisample: f.setSampleBuffers(True) if options.force_stereo != -1: # See layer1/Setting.h for stereo modes if options.stereo_mode in (0, 1, 12): # this effectively disables stereo detection # on Linux that is faulty in QGLWidget / PyQt5 if not (options.stereo_mode == 0 and sys.platform.startswith("linux")): f.setStereo(True) if options.stereo_mode in (11, 12): f.setAccum(True) if options.stereo_mode in (0, 6, 7, 8, 9): f.setStencil(True) QtOpenGL.QGLWidget.__init__(self, 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 self.pymol = PyMOL() self.pymol.start() self.cmd = self.pymol.cmd # capture python output for feedback import pcatch pcatch._install() # for passive move drag self.setMouseTracking(True) # for accepting keyboard input (command line, shortcuts) self.setFocusPolicy(Qt.ClickFocus) # for idle rendering self._timer = QtCore.QTimer() self._timer.setSingleShot(True) self._timer.timeout.connect(self._pymolProcess) # drag n drop self.setAcceptDrops(True) # pinch-zoom self.grabGesture(Qt.PinchGesture)