class PushSinkAdapter(QtCore.QObject): dataReady = QtCore.Signal(['PyQt_PyObject'], name='dataReady') def __init__(self, sink): super(PushSinkAdapter, self).__init__() self.sink = sink self._time = None self._value = None def cb_handler(self, m): try: self._time = m.time() self._value = m self.dataReady.emit(self._time) except Exception, e: log.exception(e)
class OutPort(Port): dataReady = QtCore.Signal(['PyQt_PyObject'], name='dataReady') def __init__(self, parent, name): super(Port, self).__init__(parent, name) def send(self, value): self.dataReady.emit(value) def subscribe(self, inport): info = inport.get_info() if info.queued: return self.dataReady.connect(inport.handle_receive, QtCore.Qt.QueuedConnection) else: return self.dataReady.connect(inport.handle_receive) def unsubscribe(self, inport): raise NotImplemented
class CompleterLineEdit(QtGui.QLineEdit): """ """ completionNeeded = QtCore.Signal(str) def __init__(self, parent, delimiters, entries, entries_updater): self.delimiters = delimiters super(CompleterLineEdit, self).__init__(parent) self.textChanged[str].connect(self.text_changed) self.completer = QtGui.QCompleter(self) self.completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive) self.completer.setModel(QtGui.QStringListModel(entries, self.completer)) self.completionNeeded.connect(self.completer.complete) self.completer.activated[str].connect(self.complete_text) self.completer.setWidget(self) self._upddate_entries = True self.editingFinished.connect(self.on_editing_finished) self.entries_updater = entries_updater def text_changed(self, text): """ """ if self._upddate_entries and self.entries_updater: entries = self.entries_updater() self.completer.setModel( QtGui.QStringListModel(entries, self.completer)) self._upddate_entries = False all_text = unicode(text) text = all_text[:self.cursorPosition()] split = text.split(self.delimiters[0]) prefix = split[-1].strip() if len(split) > 1: self.completer.setCompletionPrefix(prefix) self.completionNeeded.emit(prefix) self.string = text def complete_text(self, text): """ """ cursor_pos = self.cursorPosition() before_text = unicode(self.text())[:cursor_pos] after_text = unicode(self.text())[cursor_pos:] prefix_len = len(before_text.split(self.delimiters[0])[-1].strip()) if after_text.startswith(self.delimiters[1]): self.setText(before_text[:cursor_pos - prefix_len] + text + after_text) else: self.setText(before_text[:cursor_pos - prefix_len] + text + self.delimiters[1] + after_text) self.string = before_text[:cursor_pos - prefix_len] + text +\ self.delimiters[1] + after_text self.setCursorPosition(cursor_pos - prefix_len + len(text) + 2) self.textEdited.emit(self.string) def on_editing_finished(self): self._upddate_entries = True def _update_entries(self, entries): self.completer.setModel(QtGui.QStringListModel(entries, self.completer))
class QDelimitedCompleter(QtWidgets.QCompleter): """A custom completer to use with QtLineCompleter, QtTextEdit. This completer only propose completion between specified characters. Parameters ---------- parent : QLineEdit or QTextEdit Widget for which to provide a completion. delimiters : tuple Tuple of length 2 specifying the characters marking the begining end of completion. entries : iterable Iterable of values used to propose completion. entries_updaters : callable Callable used to refresh the list of entries called once for the first completion after the widget gained focus. """ # Signal emmitted to notify the completer it should propose a completion. completionNeeded = QtCore.Signal() def __init__(self, parent, delimiters, entries, entries_updater): super(QDelimitedCompleter, self).__init__(parent) self.delimiters = delimiters if isinstance(parent, QtWidgets.QLineEdit): self.text_getter = parent.text self.cursor_pos = parent.cursorPosition self.insert_text = parent.insert parent.textChanged[str].connect(self.text_changed) self.completionNeeded.connect(self.complete) elif isinstance(parent, QtWidgets.QTextEdit): parent.textChanged.connect(self.text_changed) self.cursor_pos = lambda: parent.textCursor().position() self.insert_text =\ lambda text: parent.textCursor().insertText(text) self.text_getter = parent.toPlainText self.completionNeeded.connect(self._text_edit_complete) else: msg = 'Parent of QtCompleter must QLineEdit or QTextEdit, not {}' raise ValueError(msg.format(parent)) self.setCaseSensitivity(QtCore.Qt.CaseSensitive) self.setModel(QtCore.QStringListModel(entries, self)) self.activated[str].connect(self.complete_text) self.setWidget(parent) self._upddate_entries = True self._popup_active = False self.entries_updater = entries_updater def text_changed(self, text=None): """Callback handling the text being edited on the parent. """ if not text: text = self.text_getter() if self._upddate_entries and self.entries_updater: entries = self.entries_updater() self.setModel(QtCore.QStringListModel(entries, self)) self._upddate_entries = False all_text = uni(text) text = all_text[:self.cursor_pos()] split = text.split(self.delimiters[0]) prefix = split[-1].strip() if len(split) > 1: self.setCompletionPrefix(prefix) self.completionNeeded.emit() elif self.popup().isVisible(): self.popup().hide() def complete_text(self, completion): """When the user validate a completion add it to the text. """ cursor_pos = self.cursor_pos() text = uni(self.text_getter()) before_text = text[:cursor_pos] after_text = text[cursor_pos:] prefix_len = len(before_text.split(self.delimiters[0])[-1].strip()) completion = completion[prefix_len:] if not after_text.startswith(self.delimiters[1]): completion += self.delimiters[1] self.insert_text(completion) def on_focus_gained(self): """Mark the entries for refreshing when the widget loses focus. """ self._upddate_entries = True def _update_entries(self, entries): """Update the completer completion model. """ self.setModel(QtCore.QStringListModel(entries)) def _text_edit_complete(self): """Propose completion for QTextEdit. """ cr = self.widget().cursorRect() popup = self.popup() cr.setWidth( popup.sizeHintForColumn(0) + popup.verticalScrollBar().sizeHint().width()) self.complete(cr)
class Widget(QtCore.QObject): destroyed = QtCore.Signal(bool)
class QtVirtualCameraWidget(QtOpenGL.QGLWidget): ShareWidget = None #: Fired in update() method to synchronize listeners. sigUpdate = QtCore.Signal() def __init__(self, key_event_handler=None, mouse_event_handler=None, cam_width=1024, cam_height=768, cam_near=0.01, cam_far=10.0, camera_intrinsics=None, parent=None): if QtVirtualCameraWidget.ShareWidget is None: ## create a dummy widget to allow sharing objects (textures, shaders, etc) between views QtVirtualCameraWidget.ShareWidget = QtOpenGL.QGLWidget() QtOpenGL.QGLWidget.__init__(self, parent, QtVirtualCameraWidget.ShareWidget) self.setFocusPolicy(QtCore.Qt.ClickFocus) self.bgtexture = visualization.BackgroundImage() self.camera_intrinsics = camera_intrinsics self.camera_pose = None self.camera_width = float(cam_width) self.camera_height = float(cam_height) self.camera_near = float(cam_near) self.camera_far = float(cam_far) self.screen_width = cam_width self.screen_height = cam_height self.items = [] self.key_event_handler = key_event_handler self.mouse_event_handler = mouse_event_handler self.noRepeatKeys = [ QtCore.Qt.Key_Right, QtCore.Qt.Key_Left, QtCore.Qt.Key_Up, QtCore.Qt.Key_Down, QtCore.Qt.Key_PageUp, QtCore.Qt.Key_PageDown ] self.keysPressed = {} self.keyTimer = QtCore.QTimer() self.keyTimer.timeout.connect(self.evalKeyState) self.makeCurrent() def setBackgroundTexture(self, m): self.bgtexture.imageIn(m) def setCameraIntrinsics(self, mat): self.camera_intrinsics = mat def setCameraPose(self, mat): self.camera_pose = mat def addItem(self, item): self.items.append(item) if hasattr(item, 'initializeGL'): self.makeCurrent() try: item.initializeGL() except: self.checkOpenGLVersion( 'Error while adding item %s to GLViewWidget.' % str(item)) item._setView(self) self.update() def removeItem(self, item): self.items.remove(item) item._setView(None) self.update() def setItems(self, items): for item in self.items: self.removeItem(item) for item in items: self.addItem(item) def initializeGL(self): glClearColor(0.0, 0.0, 0.0, 0.0) self.resizeGL(self.width(), self.height()) def resizeGL(self, w, h): glViewport(0, 0, w, h) self.screen_width = w self.screen_height = h #self.update() def setProjection(self): ## Create the projection matrix glMatrixMode(GL_PROJECTION) glLoadIdentity() if self.camera_intrinsics is not None: proj = calibration.projectionMatrix3x3ToOpenGL( 0., self.camera_width, 0., self.camera_height, self.camera_near, self.camera_far, self.camera_intrinsics) glMultMatrixd(proj.T) def setModelview(self): glMatrixMode(GL_MODELVIEW) glLoadIdentity() # XXX Needs more thoughts .. a transpose could be required here to be consistent with the global matrix handling # if self.camera_pose is not None: # pose = self.camera_pose.toMatrix() # glMultMatrixd(pose) def paintGL(self): self.setProjection() self.setModelview() glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT) if self.bgtexture is not None: self.bgtexture.draw(self.screen_width, self.screen_height) self.drawItemTree() def drawItemTree(self, item=None): if item is None: items = [x for x in self.items if x.parentItem() is None] else: items = item.childItems() items.append(item) items.sort(lambda a, b: cmp(a.depthValue(), b.depthValue())) for i in items: if not i.visible(): continue if i is item: try: glPushAttrib(GL_ALL_ATTRIB_BITS) i.paint() except: import pyqtgraph.debug pyqtgraph.debug.printExc() msg = "Error while drawing item %s." % str(item) ver = glGetString(GL_VERSION) if ver is not None: ver = ver.split()[0] if int(ver.split('.')[0]) < 2: print( msg + " The original exception is printed above; however, pyqtgraph requires OpenGL version 2.0 or greater for many of its 3D features and your OpenGL version is %s. Installing updated display drivers may resolve this issue." % ver) else: print(msg) finally: glPopAttrib() else: glMatrixMode(GL_MODELVIEW) glPushMatrix() try: tr = i.transform() a = np.array(tr.copyDataTo()).reshape((4, 4)) glMultMatrixf(a.transpose()) self.drawItemTree(i) finally: glMatrixMode(GL_MODELVIEW) glPopMatrix() def mousePressEvent(self, ev): self.mousePos = ev.pos() if self.mouse_event_handler: self.mouse_event_handler(("press", ev)) def mouseMoveEvent(self, ev): if self.mouse_event_handler: self.mouse_event_handler(("move", ev)) def mouseReleaseEvent(self, ev): if self.mouse_event_handler: self.mouse_event_handler(("release", ev)) def wheelEvent(self, ev): if self.mouse_event_handler: self.mouse_event_handler(("wheel", ev)) def keyPressEvent(self, ev): if ev.key() in self.noRepeatKeys: ev.accept() if ev.isAutoRepeat(): return self.keysPressed[ev.key()] = 1 self.evalKeyState() if self.key_event_handler: self.key_event_handler(("press", ev, self.keysPressed)) def keyReleaseEvent(self, ev): if ev.key() in self.noRepeatKeys: ev.accept() if ev.isAutoRepeat(): return try: del self.keysPressed[ev.key()] except: self.keysPressed = {} self.evalKeyState() if self.key_event_handler: self.key_event_handler(("release", ev, self.keysPressed)) def checkOpenGLVersion(self, msg): ## Only to be called from within exception handler. ver = glGetString(GL_VERSION).split()[0] if int(ver.split('.')[0]) < 2: import pyqtgraph.debug pyqtgraph.debug.printExc() raise Exception( msg + " The original exception is printed above; however, utInteractiveConsole requires OpenGL version 2.0 or greater for many of its 3D features and your OpenGL version is %s. Installing updated display drivers may resolve this issue." % ver) else: raise def evalKeyState(self): speed = 2.0 if len(self.keysPressed) > 0: for key in self.keysPressed: if key == QtCore.Qt.Key_Right: pass elif key == QtCore.Qt.Key_Left: pass elif key == QtCore.Qt.Key_Up: pass elif key == QtCore.Qt.Key_Down: pass elif key == QtCore.Qt.Key_PageUp: pass elif key == QtCore.Qt.Key_PageDown: pass self.keyTimer.start(16) else: self.keyTimer.stop() def readQImage(self): """ Read the current buffer pixels out as a QImage. """ w = self.width() h = self.height() self.repaint() pixels = np.empty((h, w, 4), dtype=np.ubyte) pixels[:] = 128 pixels[..., 0] = 50 pixels[..., 3] = 255 glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels) # swap B,R channels for Qt tmp = pixels[..., 0].copy() pixels[..., 0] = pixels[..., 2] pixels[..., 2] = tmp pixels = pixels[::-1] # flip vertical img = fn.makeQImage(pixels, transpose=False) return img def renderToArray(self, size, format=GL_BGRA, type=GL_UNSIGNED_BYTE, textureSize=1024, padding=256): w, h = map(int, size) self.makeCurrent() tex = None fb = None try: output = np.empty((w, h, 4), dtype=np.ubyte) fb = glfbo.glGenFramebuffers(1) glfbo.glBindFramebuffer(glfbo.GL_FRAMEBUFFER, fb) glEnable(GL_TEXTURE_2D) tex = glGenTextures(1) glBindTexture(GL_TEXTURE_2D, tex) texwidth = textureSize data = np.zeros((texwidth, texwidth, 4), dtype=np.ubyte) ## Test texture dimensions first glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGBA, texwidth, texwidth, 0, GL_RGBA, GL_UNSIGNED_BYTE, None) if glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH) == 0: raise Exception( "OpenGL failed to create 2D texture (%dx%d); too large for this hardware." % shape[:2]) ## create teture glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texwidth, texwidth, 0, GL_RGBA, GL_UNSIGNED_BYTE, data.transpose((1, 0, 2))) self.opts['viewport'] = ( 0, 0, w, h ) # viewport is the complete image; this ensures that paintGL(region=...) # is interpreted correctly. p2 = 2 * padding for x in range(-padding, w - padding, texwidth - p2): for y in range(-padding, h - padding, texwidth - p2): x2 = min(x + texwidth, w + padding) y2 = min(y + texwidth, h + padding) w2 = x2 - x h2 = y2 - y ## render to texture glfbo.glFramebufferTexture2D(glfbo.GL_FRAMEBUFFER, glfbo.GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0) self.paintGL(region=(x, h - y - h2, w2, h2), viewport=(0, 0, w2, h2)) # only render sub-region ## read texture back to array data = glGetTexImage(GL_TEXTURE_2D, 0, format, type) data = np.fromstring(data, dtype=np.ubyte).reshape( texwidth, texwidth, 4).transpose(1, 0, 2)[:, ::-1] output[x + padding:x2 - padding, y + padding:y2 - padding] = data[padding:w2 - padding, -(h2 - padding):-padding] finally: self.opts['viewport'] = None glfbo.glBindFramebuffer(glfbo.GL_FRAMEBUFFER, 0) glBindTexture(GL_TEXTURE_2D, 0) if tex is not None: glDeleteTextures([tex]) if fb is not None: glfbo.glDeleteFramebuffers([fb]) return output