Beispiel #1
0
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)
Beispiel #2
0
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
Beispiel #3
0
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))
Beispiel #4
0
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