예제 #1
0
    def wheelEvent(self, ev, axis=None):
        ev.accept()
        # s is actual scaling factor
        s = 1.02**(ev.delta() * self.state['wheelScaleFactor'])
        current_view = self.viewRect()

        #if only one node visible and wants to zoom in - not allowed
        if not (self.is_1_or_less(current_view) and s < 1):

            #if all visible and wants to zoom out - not allowed
            if self.is_all_visible(current_range=self.viewRange()) and s > 1:
                pass
            else:
                center = pg.QtCore.QPointF(
                    fn.invertQTransform(self.childGroup.transform()).map(
                        ev.pos()))

                if self.canopy_pespective:  #changing center to ensure fixed canopy
                    # max y-value of graph aka canopy
                    max_y_coord = max(self.y_coords)
                    center = pg.QtCore.QPointF(center.x(), max_y_coord)

                self._resetTarget()
                if (ev.modifiers() & QtCore.Qt.ShiftModifier):
                    self.scaleBy(x=s, center=center)
                elif (ev.modifiers() & QtCore.Qt.ControlModifier):
                    self.scaleBy(y=s, center=center)
                else:
                    self.scaleBy(s=s, center=center)
예제 #2
0
def wheelEvent(self, ev, axis=None):
    if axis in (0, 1):
        mask = [False, False]
        mask[axis] = self.state['mouseEnabled'][axis]
    else:
        mask = self.state['mouseEnabled'][:]
    s = 1.02**(ev.delta() * self.state['wheelScaleFactor']
               )  # actual scaling factor
    s = [(None if m is False else s) for m in mask]
    center = Point(
        fn.invertQTransform(self.childGroup.transform()).map(ev.pos()))
    # JC added
    if ev.modifiers(
    ) == QtCore.Qt.ShiftModifier and s[0] is not None and s[1] is not None:
        for child in self.childGroup.childItems()[:]:
            if hasattr(child, 'accept_mousewheel_transformations'):
                m_old = child.transform()
                m = QtGui.QTransform()
                print(1, m_old.m22(), s[1])
                m.scale(1, m_old.m22() * s[1])
                child.setTransform(m)
        ev.accept()
        child_group_transformation = self.childGroup.transform()
        # self.childGroup.update()
        # self.autoRange()
        # self.updateAutoRange()
        # self.sigTransformChanged.emit(self)  ## segfaults here: 1
        print(self.viewRange())
        print(self.targetRange())
        return
    self._resetTarget()
    self.scaleBy(s, center)
    ev.accept()
    self.sigRangeChangedManually.emit(mask)
예제 #3
0
    def wheelEvent(self, ev, axis=None):
        mask = np.array(self.state['mouseEnabled'], dtype=np.float)
        if axis is not None and axis >= 0 and axis < len(mask):
            mv = mask[axis]
            mask[:] = 0
            mask[axis] = mv
        angleDelta = ev.angleDelta().y(
        ) if ev.angleDelta().y() != 0 else ev.angleDelta().x()
        if isinstance(ev, QWheelEvent):
            s = ((mask * 0.02) +
                 1)**(angleDelta * self.state['wheelScaleFactor']
                      )  # actual scaling factor
        else:
            s = ((mask * 0.02) +
                 1)**(ev.delta() * self.state['wheelScaleFactor']
                      )  # actual scaling factor

        center = Point(
            fn.invertQTransform(self.childGroup.transform()).map(ev.pos()))
        # center = ev.pos()

        self._resetTarget()
        self.scaleBy(s, center)
        self.sigRangeChangedManually.emit(self.state['mouseEnabled'])
        ev.accept()
예제 #4
0
 def pixelHeight(self):
     ## deprecated
     vt = self.deviceTransform()
     if vt is None:
         return 0
     vt = fn.invertQTransform(vt)
     return vt.map(QtCore.QLineF(0, 0, 0, 1)).length()
예제 #5
0
 def pixelHeight(self):
     ## deprecated
     vt = self.deviceTransform()
     if vt is None:
         return 0
     vt = fn.invertQTransform(vt)
     return vt.map(QtCore.QLineF(0, 0, 0, 1)).length()
예제 #6
0
    def wheelEvent(self, ev, axis=None):
        """Override wheel event so we manually track changes of zoom and
        update map accordingly."""
        delta = 0.5 * np.sign(ev.delta())
        self.__zoom_level = self.__clipped_zoom(self.__zoom_level + delta)

        center = Point(fn.invertQTransform(self.childGroup.transform()).map(ev.pos()))
        self.match_zoom(center, offset=True)
        ev.accept()
예제 #7
0
 def mapRectFromDevice(self, rect):
     """
     Return *rect* mapped from device coordinates (pixels) to local coordinates.
     If there is no device mapping available, return None.
     """
     vt = self.deviceTransform()
     if vt is None:
         return None
     vt = fn.invertQTransform(vt)
     return vt.mapRect(rect)
예제 #8
0
 def mapRectFromDevice(self, rect):
     """
     Return *rect* mapped from device coordinates (pixels) to local coordinates.
     If there is no device mapping available, return None.
     """
     vt = self.deviceTransform()
     if vt is None:
         return None
     vt = fn.invertQTransform(vt)
     return vt.mapRect(rect)
예제 #9
0
    def mouseDragEvent(self, ev, axis=None):
        ## Scale or translate based on mouse button
        ##leftdrag = pan || rightdrag = zoom

        if ev.button() & (QtCore.Qt.LeftButton | QtCore.Qt.MidButton):
            ev.accept()
            pos = ev.pos(
            )  #comes in terms of viewport position (topleft is 0, 0)
            lastPos = ev.lastPos()
            dif = self.mapToView(pos) - self.mapToView(
                lastPos)  #converts to graph's coord

            #print(self.mapFromDevice((pos-lastPos)))
            self._resetTarget()
            if self.canopy_pespective:
                self.translateBy(x=-dif.x())
            else:
                self.translateBy(x=-dif.x(), y=-dif.y())

        elif ev.button() & QtCore.Qt.RightButton:
            ev.accept()
            dif = ev.screenPos() - ev.lastScreenPos()
            dif = np.array([dif.x(), dif.y()])
            dif[0] *= -1
            s = 1.02**dif
            current_view = self.viewRect()

            #if only one node visible and wants to zoom in - not allowed
            if not (self.is_1_or_less(current_view) and s[1] < 1):

                #if all visible and wants to zoom out - not allowed
                if self.is_all_visible(
                        current_range=self.viewRange()) and s > 1:
                    pass
                else:
                    # center is calculated in graph coords
                    tr = self.childGroup.transform()
                    tr = fn.invertQTransform(tr)
                    center = pg.QtCore.QPointF(
                        tr.map(ev.buttonDownPos(QtCore.Qt.RightButton)))

                    if self.canopy_pespective:  #changing center to ensure fixed canopy
                        # max y-value of graph aka canopy
                        max_y_coord = max(self.y_coords)
                        center = (center.x(), max_y_coord)

                    self._resetTarget()
                    if (ev.modifiers() & QtCore.Qt.ShiftModifier):
                        self.scaleBy(x=s[1], center=center)
                    elif (ev.modifiers() & QtCore.Qt.ControlModifier):
                        self.scaleBy(y=s[1], center=center)
                    else:
                        #using y displacment for calculate both scales
                        self.scaleBy(x=s[1], y=s[1], center=center)
예제 #10
0
    def wheelEvent(self, ev, axis=None):
        """Override wheel event so we manually track changes of zoom and
        update map accordingly."""
        if ev.delta() > 0:
            # zoom-in
            self.__zoom_level = self.__zoom_in_range(self.__zoom_level + 1)
        else:
            # zoom-out
            self.__zoom_level = self.__zoom_in_range(self.__zoom_level - 1)

        center = Point(fn.invertQTransform(self.childGroup.transform()).map(ev.pos()))
        self.match_zoom(center, offset=True)
        ev.accept()
예제 #11
0
 def wheelEvent(self, ev, axis=None):
     mask = np.array(self.state['mouseEnabled'], dtype=np.float)
     if axis is not None and axis >= 0 and axis < len(mask):
         mv = mask[axis]
         mask[:] = 0
         mask[axis] = mv
     s = ((mask * 0.02) + 1) ** (ev.delta() * self.state['wheelScaleFactor']) # actual scaling factor
     
     center = Point(fn.invertQTransform(self.childGroup.transform()).map(ev.pos()))
     #center = ev.pos()
     
     self.scaleBy(s, center)
     self.sigRangeChangedManually.emit(self.state['mouseEnabled'])
     ev.accept()
예제 #12
0
    def mouseDragEvent(self, ev, axis=None):
        ## if axis is specified, event will only affect that axis.
        ev.accept()  ## we accept all buttons
        
        pos = ev.pos()
        lastPos = ev.lastPos()
        dif = pos - lastPos
        dif = dif * -1

        ## Ignore axes if mouse is disabled
        mask = np.array(self.state['mouseEnabled'], dtype=np.float)
        if axis is not None:
            mask[1-axis] = 0.0

        ## Scale or translate based on mouse button
        if ev.button() & (QtCore.Qt.LeftButton | QtCore.Qt.MidButton):
            if self.state['mouseMode'] == ViewBox.RectMode:
                if ev.isFinish():  ## This is the final move in the drag; change the view scale now
                    #print "finish"
                    self.rbScaleBox.hide()
                    #ax = QtCore.QRectF(Point(self.pressPos), Point(self.mousePos))
                    ax = QtCore.QRectF(Point(ev.buttonDownPos(ev.button())), Point(pos))
                    ax = self.childGroup.mapRectFromParent(ax)
                    self.showAxRect(ax)
                    self.axHistoryPointer += 1
                    self.axHistory = self.axHistory[:self.axHistoryPointer] + [ax]
                else:
                    ## update shape of scale box
                    self.updateScaleBox(ev.buttonDownPos(), ev.pos())
            else:
                tr = dif*mask
                tr = self.mapToView(tr) - self.mapToView(Point(0,0))
                self.translateBy(tr)
                self.sigRangeChangedManually.emit(self.state['mouseEnabled'])
        elif ev.button() & QtCore.Qt.RightButton:
            #print "vb.rightDrag"
            if self.state['aspectLocked'] is not False:
                mask[0] = 0
            
            dif = ev.screenPos() - ev.lastScreenPos()
            dif = np.array([dif.x(), dif.y()])
            dif[0] *= -1
            s = ((mask * 0.02) + 1) ** dif
            
            tr = self.childGroup.transform()
            tr = fn.invertQTransform(tr)
            
            center = Point(tr.map(ev.buttonDownPos(QtCore.Qt.RightButton)))
            self.scaleBy(s, center)
            self.sigRangeChangedManually.emit(self.state['mouseEnabled'])
예제 #13
0
파일: libgraph.py 프로젝트: IIBM/bci
    def mouseDragEvent(self, ev, axis = None):
        """If axis is specified, event will only affect that axis."""
        ev.accept()  ## we accept all buttons
        ## Ignore axes if mouse is disabled
        mouseEnabled = np.array(self.state['mouseEnabled'], dtype=np.float)
        mask = mouseEnabled.copy()
        if axis is not None:
            mask[1-axis] = 0.0

        ## Scale or translate based on mouse button
        if ev.button() & QtCore.Qt.RightButton:
            dif = ev.screenPos() - ev.lastScreenPos()
            tr = self.childGroup.transform()
            tr = fn.invertQTransform(tr)
            self.scaleBy(x = None, y = ((mask[1] * 0.02) + 1) ** dif.y(), center=(0, 0)) #here mu change
            self.sigRangeChangedManually.emit(self.state['mouseEnabled'])
예제 #14
0
    def generateShape(self):
        ## determine rotation of transform
        #m = self.sceneTransform()  ## Qt bug: do not access sceneTransform() until we know this object has a scene.
        #mi = m.inverted()[0]
        dt = self.deviceTransform()

        if dt is None:
            self._shape = self.path
            return None

        v = dt.map(QtCore.QPointF(1, 0)) - dt.map(QtCore.QPointF(0, 0))
        va = np.arctan2(v.y(), v.x())

        dti = fn.invertQTransform(dt)
        devPos = dt.map(QtCore.QPointF(0, 0))
        tr = QtGui.QTransform()
        tr.translate(devPos.x(), devPos.y())
        tr.rotate(va * 180. / 3.1415926)

        return dti.map(tr.map(self.path))
예제 #15
0
    def generatePicture(self):
        self.picture = QtGui.QPicture()
        p = QtGui.QPainter()
        p.begin(self.picture)

        dt = fn.invertQTransform(self.viewTransform())
        vr = self.getViewWidget().rect()
        unit = self.pixelWidth(), self.pixelHeight()
        dim = [vr.width(), vr.height()]
        lvr = self.boundingRect()
        ul = np.array([lvr.left(), lvr.top()])
        br = np.array([lvr.right(), lvr.bottom()])

        texts = []

        if ul[1] > br[1]:
            x = ul[1]
            ul[1] = br[1]
            br[1] = x
        for i in [2, 1, 0]:  ## Draw three different scales of grid
            dist = br - ul
            nlTarget = 10.0 ** i
            d = 10.0 ** np.floor(np.log10(abs(dist / nlTarget)) + 0.5)
            ul1 = np.floor(ul / d) * d
            br1 = np.ceil(br / d) * d
            dist = br1 - ul1
            nl = (dist / d) + 0.5
            # print "level", i
            # print "  dim", dim
            # print "  dist", dist
            # print "  d", d
            # print "  nl", nl
            for ax in range(0, 2):  ## Draw grid for both axes
                ppl = dim[ax] / nl[ax]
                c = np.clip(3.0 * (ppl - 3), 0.0, 30.0)
                linePen = QtGui.QPen(QtGui.QColor(255, 255, 255, c))
                textPen = QtGui.QPen(QtGui.QColor(255, 255, 255, c * 2))
                # linePen.setCosmetic(True)
                # linePen.setWidth(1)
                bx = (ax + 1) % 2
                for x in range(0, int(nl[ax])):
                    linePen.setCosmetic(False)
                    if ax == 0:
                        linePen.setWidthF(self.pixelWidth())
                        # print "ax 0 height", self.pixelHeight()
                    else:
                        linePen.setWidthF(self.pixelHeight())
                        # print "ax 1 width", self.pixelWidth()
                    p.setPen(linePen)
                    p1 = np.array([0.0, 0.0])
                    p2 = np.array([0.0, 0.0])
                    p1[ax] = ul1[ax] + x * d[ax]
                    p2[ax] = p1[ax]
                    p1[bx] = ul[bx]
                    p2[bx] = br[bx]
                    ## don't draw lines that are out of bounds.
                    if p1[ax] < min(ul[ax], br[ax]) or p1[ax] > max(ul[ax], br[ax]):
                        continue
                    p.drawLine(QtCore.QPointF(p1[0], p1[1]), QtCore.QPointF(p2[0], p2[1]))
                    if i < 2:
                        p.setPen(textPen)
                        if ax == 0:
                            x = p1[0] + unit[0]
                            y = ul[1] + unit[1] * 8.0
                        else:
                            x = ul[0] + unit[0] * 3
                            y = p1[1] + unit[1]
                        texts.append((QtCore.QPointF(x, y), "%g" % p1[ax]))
        tr = self.deviceTransform()
        # tr.scale(1.5, 1.5)
        p.setWorldTransform(fn.invertQTransform(tr))
        for t in texts:
            x = tr.map(t[0]) + Point(0.5, 0.5)
            p.drawText(x, t[1])
        p.end()
예제 #16
0
    def mouseDragEvent(
        self,
        ev,
        axis: Optional[int] = None,
    ) -> None:
        #  if axis is specified, event will only affect that axis.
        ev.accept()  # we accept all buttons
        button = ev.button()

        pos = ev.pos()
        lastPos = ev.lastPos()
        dif = pos - lastPos
        dif = dif * -1

        # Ignore axes if mouse is disabled
        mouseEnabled = np.array(self.state['mouseEnabled'], dtype=np.float)
        mask = mouseEnabled.copy()
        if axis is not None:
            mask[1 - axis] = 0.0

        # Scale or translate based on mouse button
        if button & (QtCore.Qt.LeftButton | QtCore.Qt.MidButton):

            # zoom y-axis ONLY when click-n-drag on it
            if axis == 1:
                # set a static y range special value on chart widget to
                # prevent sizing to data in view.
                self.chart._static_yrange = 'axis'

                scale_y = 1.3**(dif.y() * -1 / 20)
                self.setLimits(yMin=None, yMax=None)

                # print(scale_y)
                self.scaleBy((0, scale_y))

            if self.state['mouseMode'] == ViewBox.RectMode:

                down_pos = ev.buttonDownPos()

                # This is the final position in the drag
                if ev.isFinish():

                    self.select_box.mouse_drag_released(down_pos, pos)

                    # ax = QtCore.QRectF(down_pos, pos)
                    # ax = self.childGroup.mapRectFromParent(ax)
                    # print(ax)

                    # this is the zoom transform cmd
                    # self.showAxRect(ax)

                    # self.axHistoryPointer += 1
                    # self.axHistory = self.axHistory[
                    #     :self.axHistoryPointer] + [ax]
                else:
                    self.select_box.set_pos(down_pos, pos)

                    # update shape of scale box
                    # self.updateScaleBox(ev.buttonDownPos(), ev.pos())
            else:
                # default bevavior: click to pan view

                tr = self.childGroup.transform()
                tr = fn.invertQTransform(tr)
                tr = tr.map(dif * mask) - tr.map(Point(0, 0))

                x = tr.x() if mask[0] == 1 else None
                y = tr.y() if mask[1] == 1 else None

                self._resetTarget()

                if x is not None or y is not None:
                    self.translateBy(x=x, y=y)

                self.sigRangeChangedManually.emit(self.state['mouseEnabled'])

        elif button & QtCore.Qt.RightButton:

            # right click zoom to center behaviour

            if self.state['aspectLocked'] is not False:
                mask[0] = 0

            dif = ev.screenPos() - ev.lastScreenPos()
            dif = np.array([dif.x(), dif.y()])
            dif[0] *= -1
            s = ((mask * 0.02) + 1)**dif

            tr = self.childGroup.transform()
            tr = fn.invertQTransform(tr)

            x = s[0] if mouseEnabled[0] == 1 else None
            y = s[1] if mouseEnabled[1] == 1 else None

            center = Point(tr.map(ev.buttonDownPos(QtCore.Qt.RightButton)))
            self._resetTarget()
            self.scaleBy(x=x, y=y, center=center)
            self.sigRangeChangedManually.emit(self.state['mouseEnabled'])
예제 #17
0
 def generatePicture(self):
     self.picture = QtGui.QPicture()
     p = QtGui.QPainter()
     p.begin(self.picture)
     
     dt = fn.invertQTransform(self.viewTransform())
     vr = self.getViewWidget().rect()
     unit = self.pixelWidth(), self.pixelHeight()
     dim = [vr.width(), vr.height()]
     lvr = self.boundingRect()
     ul = np.array([lvr.left(), lvr.top()])
     br = np.array([lvr.right(), lvr.bottom()])
     
     texts = []
     
     if ul[1] > br[1]:
         x = ul[1]
         ul[1] = br[1]
         br[1] = x
     for i in [2,1,0]:   ## Draw three different scales of grid
         dist = br-ul
         nlTarget = 10.**i
         d = 10. ** np.floor(np.log10(abs(dist/nlTarget))+0.5)
         ul1 = np.floor(ul / d) * d
         br1 = np.ceil(br / d) * d
         dist = br1-ul1
         nl = (dist / d) + 0.5
         #print "level", i
         #print "  dim", dim
         #print "  dist", dist
         #print "  d", d
         #print "  nl", nl
         for ax in range(0,2):  ## Draw grid for both axes
             ppl = dim[ax] / nl[ax]
             c = np.clip(3.*(ppl-3), 0., 30.)
             linePen = QtGui.QPen(QtGui.QColor(255, 255, 255, c)) 
             textPen = QtGui.QPen(QtGui.QColor(255, 255, 255, c*2)) 
             #linePen.setCosmetic(True)
             #linePen.setWidth(1)
             bx = (ax+1) % 2
             for x in range(0, int(nl[ax])):
                 linePen.setCosmetic(False)
                 if ax == 0:
                     linePen.setWidthF(self.pixelWidth())
                     #print "ax 0 height", self.pixelHeight()
                 else:
                     linePen.setWidthF(self.pixelHeight())
                     #print "ax 1 width", self.pixelWidth()
                 p.setPen(linePen)
                 p1 = np.array([0.,0.])
                 p2 = np.array([0.,0.])
                 p1[ax] = ul1[ax] + x * d[ax]
                 p2[ax] = p1[ax]
                 p1[bx] = ul[bx]
                 p2[bx] = br[bx]
                 ## don't draw lines that are out of bounds.
                 if p1[ax] < min(ul[ax], br[ax]) or p1[ax] > max(ul[ax], br[ax]):
                     continue
                 p.drawLine(QtCore.QPointF(p1[0], p1[1]), QtCore.QPointF(p2[0], p2[1]))
                 if i < 2:
                     p.setPen(textPen)
                     if ax == 0:
                         x = p1[0] + unit[0]
                         y = ul[1] + unit[1] * 8.
                     else:
                         x = ul[0] + unit[0]*3
                         y = p1[1] + unit[1]
                     texts.append((QtCore.QPointF(x, y), "%g"%p1[ax]))
     tr = self.deviceTransform()
     #tr.scale(1.5, 1.5)
     p.setWorldTransform(fn.invertQTransform(tr))
     for t in texts:
         x = tr.map(t[0]) + Point(0.5, 0.5)
         p.drawText(x, t[1])
     p.end()
예제 #18
0
    def onMouseWheeled(self, ev, axis):
        """
        Allows mouse wheel zoom on ctrl-click [currently]
        """
        self.controlDrag = False  # TODO: hack that should not be needed
        modifiers = QtGui.QApplication.keyboardModifiers()
        if modifiers == QtCore.Qt.ControlModifier or (modifiers == (
                QtCore.Qt.ControlModifier | QtCore.Qt.ShiftModifier)):
            # Emit a signal when the wheel is rotated alone and return a positive or negative value in self.progressBy
            # that we can use to incremement the image layer in the current axes
            if ev.delta() > 0:
                self.progressBy = 1
            elif ev.delta() < 0:
                self.progressBy = -1
            else:
                self.progressBy = 0

            # this may be mouse-specific!
            self.progressBy = (self.progressBy * abs(ev.delta()) / 120)

            if modifiers == (QtCore.Qt.ControlModifier
                             | QtCore.Qt.ShiftModifier):
                # Allow faster scrolling if it was a shift+wheel
                self.progressBy = self.progressBy * 5

            self.progressLayer.emit()
        else:
            # Handle zoom (mousewheel with no keyboard modifier)
            mask = np.array(self.state["mouseEnabled"], dtype=np.float)

            if axis is not None and 0 <= axis < len(mask):
                mv = mask[axis]
                mask[:] = 0
                mask[axis] = mv

            # actual scaling factor
            s = ((mask * 0.02) + 1)**(ev.delta() *
                                      self.state["wheelScaleFactor"])

            center = pg.Point(
                fn.invertQTransform(self.childGroup.transform()).map(ev.pos()))
            # center = ev.pos()

            self._resetTarget()
            self.scaleBy(s, center)
            self.sigRangeChangedManually.emit(self.state["mouseEnabled"])
            ev.accept()

            if len(self.linkedAxis) > 0:
                for thisViewBox in self.linkedAxis:

                    if self.linkedAxis[thisViewBox]["linkZoom"]:
                        # Centre with the appropriate axes to avoid the views translating in horrible ways during zooming
                        # I don't know why I also need to call my centerOn() method, but at least this works
                        if (self.linkedAxis[thisViewBox]["linkX"] == "x" and
                                self.linkedAxis[thisViewBox]["linkY"] is None):
                            thisViewBox.scaleBy(s, x=center.x())
                            self.centreOn(thisViewBox, x=center.x())

                        if (self.linkedAxis[thisViewBox]["linkY"] == "y" and
                                self.linkedAxis[thisViewBox]["linkX"] is None):
                            thisViewBox.scaleBy(s, y=center.y())
                            self.centreOn(thisViewBox, y=center.y())

                        if (self.linkedAxis[thisViewBox]["linkX"] == "y" and
                                self.linkedAxis[thisViewBox]["linkY"] is None):
                            thisViewBox.scaleBy(s, y=center.x())
                            self.centreOn(thisViewBox, y=center.x())

                        if (self.linkedAxis[thisViewBox]["linkY"] == "x" and
                                self.linkedAxis[thisViewBox]["linkX"] is None):
                            thisViewBox.scaleBy(s, x=center.y())
                            self.centreOn(thisViewBox, x=center.y())

                        # The following two cases aren't used currently by Lasagna, but may be required in the future.
                        # They haven't been tested yet. [28/07/15]
                        if (self.linkedAxis[thisViewBox]["linkY"] == "x" and
                                self.linkedAxis[thisViewBox]["linkX"] == "y"):
                            thisViewBox.scaleBy(s, x=center.y(), y=center.x())
                            self.centreOn(thisViewBox,
                                          x=center.y(),
                                          y=center.x())

                        if (self.linkedAxis[thisViewBox]["linkY"] == "y" and
                                self.linkedAxis[thisViewBox]["linkX"] == "x"):
                            thisViewBox.scaleBy(s, x=center.x(), y=center.y())
                            self.centreOn(thisViewBox,
                                          x=center.x(),
                                          y=center.y())
예제 #19
0
 def mapRectFromView(self, obj):
     vt = self.viewTransform()
     if vt is None:
         return None
     vt = fn.invertQTransform(vt)
     return vt.mapRect(obj)
예제 #20
0
 def mapToView(self, obj):
     """Maps from the local coordinates of the ViewBox to the coordinate system displayed inside the ViewBox"""
     m = fn.invertQTransform(self.childTransform())
     return m.map(obj)
예제 #21
0
 def pixelVectors(self, direction=None):
     """Return vectors in local coordinates representing the width and height of a view pixel.
     If direction is specified, then return vectors parallel and orthogonal to it.
     
     Return (None, None) if pixel size is not yet defined (usually because the item has not yet been displayed)
     or if pixel size is below floating-point precision limit.
     """
     
     ## This is an expensive function that gets called very frequently.
     ## We have two levels of cache to try speeding things up.
     
     dt = self.deviceTransform()
     if dt is None:
         return None, None
     
     ## check local cache
     if direction is None and dt == self._pixelVectorCache[0]:
         return self._pixelVectorCache[1]
     
     ## check global cache
     key = (dt.m11(), dt.m21(), dt.m31(), dt.m12(), dt.m22(), dt.m32(), dt.m31(), dt.m32())
     pv = self._pixelVectorGlobalCache.get(key, None)
     if pv is not None:
         self._pixelVectorCache = [dt, pv]
         return pv
     
     
     if direction is None:
         direction = QtCore.QPointF(1, 0)  
     if direction.manhattanLength() == 0:
         raise Exception("Cannot compute pixel length for 0-length vector.")
         
     ## attempt to re-scale direction vector to fit within the precision of the coordinate system
     if direction.x() == 0:
         r = abs(dt.m32())/(abs(dt.m12()) + abs(dt.m22()))
         #r = 1.0/(abs(dt.m12()) + abs(dt.m22()))
     elif direction.y() == 0:
         r = abs(dt.m31())/(abs(dt.m11()) + abs(dt.m21()))
         #r = 1.0/(abs(dt.m11()) + abs(dt.m21()))
     else:
         r = ((abs(dt.m32())/(abs(dt.m12()) + abs(dt.m22()))) * (abs(dt.m31())/(abs(dt.m11()) + abs(dt.m21()))))**0.5
     directionr = direction * r
     
     ## map direction vector onto device
     #viewDir = Point(dt.map(directionr) - dt.map(Point(0,0)))
     #mdirection = dt.map(directionr)
     dirLine = QtCore.QLineF(QtCore.QPointF(0,0), directionr)
     viewDir = dt.map(dirLine)
     if viewDir.length() == 0:
         return None, None   ##  pixel size cannot be represented on this scale
        
     ## get unit vector and orthogonal vector (length of pixel)
     #orthoDir = Point(viewDir[1], -viewDir[0])  ## orthogonal to line in pixel-space
     try:  
         normView = viewDir.unitVector()
         #normView = viewDir.norm()  ## direction of one pixel orthogonal to line
         normOrtho = normView.normalVector()
         #normOrtho = orthoDir.norm()
     except:
         raise Exception("Invalid direction %s" %directionr)
         
     ## map back to item 
     dti = fn.invertQTransform(dt)
     #pv = Point(dti.map(normView)-dti.map(Point(0,0))), Point(dti.map(normOrtho)-dti.map(Point(0,0)))
     pv = Point(dti.map(normView).p2()), Point(dti.map(normOrtho).p2())
     self._pixelVectorCache[1] = pv
     self._pixelVectorCache[0] = dt
     self._pixelVectorGlobalCache[key] = pv
     return self._pixelVectorCache[1]
예제 #22
0
    def mouseDragEvent(
        self,
        ev,
        axis: Optional[int] = None,
        relayed_from: ChartView = None,

    ) -> None:

        pos = ev.pos()
        lastPos = ev.lastPos()
        dif = pos - lastPos
        dif = dif * -1

        # NOTE: if axis is specified, event will only affect that axis.
        button = ev.button()

        # Ignore axes if mouse is disabled
        mouseEnabled = np.array(self.state['mouseEnabled'], dtype=np.float)
        mask = mouseEnabled.copy()
        if axis is not None:
            mask[1-axis] = 0.0

        # Scale or translate based on mouse button
        if button & (
            QtCore.Qt.LeftButton | QtCore.Qt.MidButton
        ):
            # zoom y-axis ONLY when click-n-drag on it
            # if axis == 1:
            #     # set a static y range special value on chart widget to
            #     # prevent sizing to data in view.
            #     self.chart._static_yrange = 'axis'

            #     scale_y = 1.3 ** (dif.y() * -1 / 20)
            #     self.setLimits(yMin=None, yMax=None)

            #     # print(scale_y)
            #     self.scaleBy((0, scale_y))

            # SELECTION MODE
            if (
                self.state['mouseMode'] == ViewBox.RectMode
                and axis is None
            ):
                # XXX: WHY
                ev.accept()

                down_pos = ev.buttonDownPos()

                # This is the final position in the drag
                if ev.isFinish():

                    self.select_box.mouse_drag_released(down_pos, pos)

                    ax = QtCore.QRectF(down_pos, pos)
                    ax = self.childGroup.mapRectFromParent(ax)

                    # this is the zoom transform cmd
                    self.showAxRect(ax)

                    # axis history tracking
                    self.axHistoryPointer += 1
                    self.axHistory = self.axHistory[
                        :self.axHistoryPointer] + [ax]

                else:
                    print('drag finish?')
                    self.select_box.set_pos(down_pos, pos)

                    # update shape of scale box
                    # self.updateScaleBox(ev.buttonDownPos(), ev.pos())
                    self.updateScaleBox(
                        down_pos,
                        ev.pos(),
                    )

            # PANNING MODE
            else:
                # XXX: WHY
                ev.accept()

                self.start_ic()
                # if self._ic is None:
                #     self.chart.pause_all_feeds()
                #     self._ic = trio.Event()

                if axis == 1:
                    self.chart._static_yrange = 'axis'

                tr = self.childGroup.transform()
                tr = fn.invertQTransform(tr)
                tr = tr.map(dif*mask) - tr.map(Point(0, 0))

                x = tr.x() if mask[0] == 1 else None
                y = tr.y() if mask[1] == 1 else None

                self._resetTarget()

                if x is not None or y is not None:
                    self.translateBy(x=x, y=y)

                self.sigRangeChangedManually.emit(self.state['mouseEnabled'])

                if ev.isFinish():
                    self.signal_ic()
                    # self._ic.set()
                    # self._ic = None
                    # self.chart.resume_all_feeds()

        # WEIRD "RIGHT-CLICK CENTER ZOOM" MODE
        elif button & QtCore.Qt.RightButton:

            if self.state['aspectLocked'] is not False:
                mask[0] = 0

            dif = ev.screenPos() - ev.lastScreenPos()
            dif = np.array([dif.x(), dif.y()])
            dif[0] *= -1
            s = ((mask * 0.02) + 1) ** dif

            tr = self.childGroup.transform()
            tr = fn.invertQTransform(tr)

            x = s[0] if mouseEnabled[0] == 1 else None
            y = s[1] if mouseEnabled[1] == 1 else None

            center = Point(tr.map(ev.buttonDownPos(QtCore.Qt.RightButton)))
            self._resetTarget()
            self.scaleBy(x=x, y=y, center=center)
            self.sigRangeChangedManually.emit(self.state['mouseEnabled'])

            # XXX: WHY
            ev.accept()
예제 #23
0
 def pixelVectors(self, direction=None):
     """Return vectors in local coordinates representing the width and height of a view pixel.
     If direction is specified, then return vectors parallel and orthogonal to it.
     
     Return (None, None) if pixel size is not yet defined (usually because the item has not yet been displayed)
     or if pixel size is below floating-point precision limit.
     """
     
     ## This is an expensive function that gets called very frequently.
     ## We have two levels of cache to try speeding things up.
     
     dt = self.deviceTransform()
     if dt is None:
         return None, None
         
     ## Ignore translation. If the translation is much larger than the scale
     ## (such as when looking at unix timestamps), we can get floating-point errors.
     dt.setMatrix(dt.m11(), dt.m12(), 0, dt.m21(), dt.m22(), 0, 0, 0, 1)
     
     ## check local cache
     if direction is None and dt == self._pixelVectorCache[0]:
         return tuple(map(Point, self._pixelVectorCache[1]))  ## return a *copy*
     
     ## check global cache
     #key = (dt.m11(), dt.m21(), dt.m31(), dt.m12(), dt.m22(), dt.m32(), dt.m31(), dt.m32())
     key = (dt.m11(), dt.m21(), dt.m12(), dt.m22())
     pv = self._pixelVectorGlobalCache.get(key, None)
     if direction is None and pv is not None:
         self._pixelVectorCache = [dt, pv]
         return tuple(map(Point,pv))  ## return a *copy*
     
     
     if direction is None:
         direction = QtCore.QPointF(1, 0)  
     if direction.manhattanLength() == 0:
         raise Exception("Cannot compute pixel length for 0-length vector.")
         
     ## attempt to re-scale direction vector to fit within the precision of the coordinate system
     ## Here's the problem: we need to map the vector 'direction' from the item to the device, via transform 'dt'.
     ## In some extreme cases, this mapping can fail unless the length of 'direction' is cleverly chosen.
     ## Example:
     ##   dt = [ 1, 0,    2 
     ##          0, 2, 1e20
     ##          0, 0,    1 ]
     ## Then we map the origin (0,0) and direction (0,1) and get:
     ##    o' = 2,1e20
     ##    d' = 2,1e20  <-- should be 1e20+2, but this can't be represented with a 32-bit float
     ##    
     ##    |o' - d'|  == 0    <-- this is the problem.
     
     ## Perhaps the easiest solution is to exclude the transformation column from dt. Does this cause any other problems?
     
     #if direction.x() == 0:
         #r = abs(dt.m32())/(abs(dt.m12()) + abs(dt.m22()))
         ##r = 1.0/(abs(dt.m12()) + abs(dt.m22()))
     #elif direction.y() == 0:
         #r = abs(dt.m31())/(abs(dt.m11()) + abs(dt.m21()))
         ##r = 1.0/(abs(dt.m11()) + abs(dt.m21()))
     #else:
         #r = ((abs(dt.m32())/(abs(dt.m12()) + abs(dt.m22()))) * (abs(dt.m31())/(abs(dt.m11()) + abs(dt.m21()))))**0.5
     #if r == 0:
         #r = 1.  ## shouldn't need to do this; probably means the math above is wrong?
     #directionr = direction * r
     directionr = direction
     
     ## map direction vector onto device
     #viewDir = Point(dt.map(directionr) - dt.map(Point(0,0)))
     #mdirection = dt.map(directionr)
     dirLine = QtCore.QLineF(QtCore.QPointF(0,0), directionr)
     viewDir = dt.map(dirLine)
     if viewDir.length() == 0:
         return None, None   ##  pixel size cannot be represented on this scale
        
     ## get unit vector and orthogonal vector (length of pixel)
     #orthoDir = Point(viewDir[1], -viewDir[0])  ## orthogonal to line in pixel-space
     try:  
         normView = viewDir.unitVector()
         #normView = viewDir.norm()  ## direction of one pixel orthogonal to line
         normOrtho = normView.normalVector()
         #normOrtho = orthoDir.norm()
     except:
         raise Exception("Invalid direction %s" %directionr)
         
     ## map back to item 
     dti = fn.invertQTransform(dt)
     #pv = Point(dti.map(normView)-dti.map(Point(0,0))), Point(dti.map(normOrtho)-dti.map(Point(0,0)))
     pv = Point(dti.map(normView).p2()), Point(dti.map(normOrtho).p2())
     self._pixelVectorCache[1] = pv
     self._pixelVectorCache[0] = dt
     self._pixelVectorGlobalCache[key] = pv
     return self._pixelVectorCache[1]
예제 #24
0
 def mapRectFromView(self, obj):
     vt = self.viewTransform()
     if vt is None:
         return None
     vt = fn.invertQTransform(vt)
     return vt.mapRect(obj)
예제 #25
0
    def pixelVectors(self, direction=None):
        """Return vectors in local coordinates representing the width and height of a view pixel.
        If direction is specified, then return vectors parallel and orthogonal to it.
        
        Return (None, None) if pixel size is not yet defined (usually because the item has not yet been displayed)
        or if pixel size is below floating-point precision limit.
        """

        ## This is an expensive function that gets called very frequently.
        ## We have two levels of cache to try speeding things up.

        dt = self.deviceTransform()
        if dt is None:
            return None, None

        ## Ignore translation. If the translation is much larger than the scale
        ## (such as when looking at unix timestamps), we can get floating-point errors.
        dt.setMatrix(dt.m11(), dt.m12(), 0, dt.m21(), dt.m22(), 0, 0, 0, 1)

        ## check local cache
        if direction is None and dt == self._pixelVectorCache[0]:
            return tuple(map(Point,
                             self._pixelVectorCache[1]))  ## return a *copy*

        ## check global cache
        #key = (dt.m11(), dt.m21(), dt.m31(), dt.m12(), dt.m22(), dt.m32(), dt.m31(), dt.m32())
        key = (dt.m11(), dt.m21(), dt.m12(), dt.m22())
        pv = self._pixelVectorGlobalCache.get(key, None)
        if direction is None and pv is not None:
            self._pixelVectorCache = [dt, pv]
            return tuple(map(Point, pv))  ## return a *copy*

        if direction is None:
            direction = QtCore.QPointF(1, 0)
        if direction.manhattanLength() == 0:
            raise Exception("Cannot compute pixel length for 0-length vector.")

        ## attempt to re-scale direction vector to fit within the precision of the coordinate system
        ## Here's the problem: we need to map the vector 'direction' from the item to the device, via transform 'dt'.
        ## In some extreme cases, this mapping can fail unless the length of 'direction' is cleverly chosen.
        ## Example:
        ##   dt = [ 1, 0,    2
        ##          0, 2, 1e20
        ##          0, 0,    1 ]
        ## Then we map the origin (0,0) and direction (0,1) and get:
        ##    o' = 2,1e20
        ##    d' = 2,1e20  <-- should be 1e20+2, but this can't be represented with a 32-bit float
        ##
        ##    |o' - d'|  == 0    <-- this is the problem.

        ## Perhaps the easiest solution is to exclude the transformation column from dt. Does this cause any other problems?

        #if direction.x() == 0:
        #r = abs(dt.m32())/(abs(dt.m12()) + abs(dt.m22()))
        ##r = 1.0/(abs(dt.m12()) + abs(dt.m22()))
        #elif direction.y() == 0:
        #r = abs(dt.m31())/(abs(dt.m11()) + abs(dt.m21()))
        ##r = 1.0/(abs(dt.m11()) + abs(dt.m21()))
        #else:
        #r = ((abs(dt.m32())/(abs(dt.m12()) + abs(dt.m22()))) * (abs(dt.m31())/(abs(dt.m11()) + abs(dt.m21()))))**0.5
        #if r == 0:
        #r = 1.  ## shouldn't need to do this; probably means the math above is wrong?
        #directionr = direction * r
        directionr = direction

        ## map direction vector onto device
        #viewDir = Point(dt.map(directionr) - dt.map(Point(0,0)))
        #mdirection = dt.map(directionr)
        dirLine = QtCore.QLineF(QtCore.QPointF(0, 0), directionr)
        viewDir = dt.map(dirLine)
        if viewDir.length() == 0:
            return None, None  ##  pixel size cannot be represented on this scale

        ## get unit vector and orthogonal vector (length of pixel)
        #orthoDir = Point(viewDir[1], -viewDir[0])  ## orthogonal to line in pixel-space
        try:
            normView = viewDir.unitVector()
            #normView = viewDir.norm()  ## direction of one pixel orthogonal to line
            normOrtho = normView.normalVector()
            #normOrtho = orthoDir.norm()
        except:
            raise Exception("Invalid direction %s" % directionr)

        ## map back to item
        dti = fn.invertQTransform(dt)
        #pv = Point(dti.map(normView)-dti.map(Point(0,0))), Point(dti.map(normOrtho)-dti.map(Point(0,0)))
        pv = Point(dti.map(normView).p2()), Point(dti.map(normOrtho).p2())
        self._pixelVectorCache[1] = pv
        self._pixelVectorCache[0] = dt
        self._pixelVectorGlobalCache[key] = pv
        return self._pixelVectorCache[1]
예제 #26
0
    def wheelEvent(
        self,
        ev,
        axis=None,
        relayed_from: ChartView = None,
    ):
        '''
        Override "center-point" location for scrolling.

        This is an override of the ``ViewBox`` method simply changing
        the center of the zoom to be the y-axis.

        TODO: PR a method into ``pyqtgraph`` to make this configurable

        '''
        if axis in (0, 1):
            mask = [False, False]
            mask[axis] = self.state['mouseEnabled'][axis]
        else:
            mask = self.state['mouseEnabled'][:]

        chart = self.linkedsplits.chart

        # don't zoom more then the min points setting
        l, lbar, rbar, r = chart.bars_range()
        vl = r - l

        if ev.delta() > 0 and vl <= _min_points_to_show:
            log.debug("Max zoom bruh...")
            return

        if ev.delta() < 0 and vl >= len(chart._arrays[chart.name]) + 666:
            log.debug("Min zoom bruh...")
            return

        # actual scaling factor
        s = 1.015 ** (ev.delta() * -1 / 20)  # self.state['wheelScaleFactor'])
        s = [(None if m is False else s) for m in mask]

        if (
            # zoom happened on axis
            axis == 1

            # if already in axis zoom mode then keep it
            or self.chart._static_yrange == 'axis'
        ):
            self.chart._static_yrange = 'axis'
            self.setLimits(yMin=None, yMax=None)

            # print(scale_y)
            # pos = ev.pos()
            # lastPos = ev.lastPos()
            # dif = pos - lastPos
            # dif = dif * -1
            center = Point(
                fn.invertQTransform(
                    self.childGroup.transform()
                ).map(ev.pos())
            )
            # scale_y = 1.3 ** (center.y() * -1 / 20)
            self.scaleBy(s, center)

        else:

            # center = pg.Point(
            #     fn.invertQTransform(self.childGroup.transform()).map(ev.pos())
            # )

            # XXX: scroll "around" the right most element in the view
            # which stays "pinned" in place.

            # furthest_right_coord = self.boundingRect().topRight()

            # yaxis = pg.Point(
            #     fn.invertQTransform(
            #         self.childGroup.transform()
            #     ).map(furthest_right_coord)
            # )

            # This seems like the most "intuitive option, a hybrid of
            # tws and tv styles
            last_bar = pg.Point(int(rbar)) + 1

            ryaxis = chart.getAxis('right')
            r_axis_x = ryaxis.pos().x()

            end_of_l1 = pg.Point(
                round(
                    chart.cv.mapToView(
                        pg.Point(r_axis_x - chart._max_l1_line_len)
                        # QPointF(chart._max_l1_line_len, 0)
                    ).x()
                )
            )  # .x()

            # self.state['viewRange'][0][1] = end_of_l1
            # focal = pg.Point((last_bar.x() + end_of_l1)/2)

            focal = min(
                last_bar,
                end_of_l1,
                key=lambda p: p.x()
            )
            # focal = pg.Point(last_bar.x() + end_of_l1)

            self._resetTarget()
            self.scaleBy(s, focal)
            self.sigRangeChangedManually.emit(mask)

            # self._ic.set()
            # self._ic = None
            # self.chart.resume_all_feeds()

            ev.accept()
예제 #27
0
    def mouseDragEvent(self, ev, axis=None):
        #  if axis is specified, event will only affect that axis.
        ev.accept()  # we accept all buttons

        pos = ev.pos()
        lastPos = ev.lastPos()
        dif = pos - lastPos
        dif = dif * -1

        # Ignore axes if mouse is disabled
        mouseEnabled = np.array(self.state['mouseEnabled'], dtype=np.float)
        mask = mouseEnabled.copy()
        if axis is not None:
            mask[1 - axis] = 0.0

        # Scale or translate based on mouse button
        if ev.button() & (QtCore.Qt.LeftButton | QtCore.Qt.MidButton):

            if self.state['mouseMode'] == ViewBox.RectMode:

                down_pos = ev.buttonDownPos()

                # This is the final position in the drag
                if ev.isFinish():

                    self.select_box.mouse_drag_released(down_pos, pos)

                    # ax = QtCore.QRectF(down_pos, pos)
                    # ax = self.childGroup.mapRectFromParent(ax)
                    # print(ax)

                    # this is the zoom transform cmd
                    # self.showAxRect(ax)

                    # self.axHistoryPointer += 1
                    # self.axHistory = self.axHistory[
                    #     :self.axHistoryPointer] + [ax]
                else:
                    self.select_box.set_pos(down_pos, pos)

                    # update shape of scale box
                    # self.updateScaleBox(ev.buttonDownPos(), ev.pos())
            else:
                tr = self.childGroup.transform()
                tr = fn.invertQTransform(tr)
                tr = tr.map(dif * mask) - tr.map(Point(0, 0))

                x = tr.x() if mask[0] == 1 else None
                y = tr.y() if mask[1] == 1 else None

                self._resetTarget()
                if x is not None or y is not None:
                    self.translateBy(x=x, y=y)
                self.sigRangeChangedManually.emit(self.state['mouseEnabled'])

        elif ev.button() & QtCore.Qt.RightButton:
            # print "vb.rightDrag"
            if self.state['aspectLocked'] is not False:
                mask[0] = 0

            dif = ev.screenPos() - ev.lastScreenPos()
            dif = np.array([dif.x(), dif.y()])
            dif[0] *= -1
            s = ((mask * 0.02) + 1)**dif

            tr = self.childGroup.transform()
            tr = fn.invertQTransform(tr)

            x = s[0] if mouseEnabled[0] == 1 else None
            y = s[1] if mouseEnabled[1] == 1 else None

            center = Point(tr.map(ev.buttonDownPos(QtCore.Qt.RightButton)))
            self._resetTarget()
            self.scaleBy(x=x, y=y, center=center)
            self.sigRangeChangedManually.emit(self.state['mouseEnabled'])
예제 #28
0
    def mouseDragEvent(self, ev, axis=None):
        """Mouse drag tracker

        This function keep track of the mouse position and overwrites it to take the draw mode into account.

        Args:
            ev: signal emitted when user releases a mouse button.
        """
        # Overwritting mouseDragEvent to take drawmode into account.
        ev.accept()

        pos = ev.pos()
        lastPos = ev.lastPos()
        dif = pos - lastPos
        dif = dif * -1

        # Ignore axes if mouse is disabled
        mouseEnabled = np.array(self.state['mouseEnabled'], dtype=np.float)
        mask = mouseEnabled.copy()
        if axis is not None:
            mask[1 - axis] = 0.0

        # If in drawing mode (editted part):
        if self.drawing:
            self.state['mouseMode'] = self.RectMode
            # If right button is selected draw zoom in boxes:
            if ev.button() & QtCore.Qt.RightButton:
                if ev.isFinish():
                    self.rbScaleBox.hide()
                    ax = QtCore.QRectF(
                        Point(ev.buttonDownPos(ev.button())), Point(pos))
                    ax = self.childGroup.mapRectFromParent(ax)
                    self.showAxRect(ax)
                    self.axHistoryPointer += 1
                    self.axHistory = self.axHistory[:self.axHistoryPointer] + [ax]
                else:
                    self.updateScaleBox(ev.buttonDownPos(), ev.pos())
            # If Left Button is selected drag image (This will be overwritten in the image by the drawing kernel)
            elif ev.button() & QtCore.Qt.LeftButton:
                tr = dif * mask
                tr = self.mapToView(tr) - self.mapToView(Point(0, 0))
                x = tr.x() if mask[0] == 1 else None
                y = tr.y() if mask[1] == 1 else None

                self._resetTarget()
                if x is not None or y is not None:
                    self.translateBy(x=x, y=y)
                self.sigRangeChangedManually.emit(self.state['mouseEnabled'])
            # If Middle Button (wheel) zoom in or out.
            elif ev.button() & QtCore.Qt.MidButton:
                if self.state['aspectLocked'] is not False:
                    mask[0] = 0

                dif = ev.screenPos() - ev.lastScreenPos()
                dif = np.array([dif.x(), dif.y()])
                dif[0] *= -1
                s = ((mask * 0.02) + 1) ** dif

                tr = self.childGroup.transform()
                tr = fn.invertQTransform(tr)

                x = s[0] if mouseEnabled[0] == 1 else None
                y = s[1] if mouseEnabled[1] == 1 else None

                center = Point(tr.map(ev.buttonDownPos(QtCore.Qt.LeftButton)))
                self._resetTarget()
                self.scaleBy(x=x, y=y, center=center)
                self.sigRangeChangedManually.emit(self.state['mouseEnabled'])
        # If not in drawing mode: (original functionality)
        else:
            # Scale or translate based on mouse button
            if ev.button() & (QtCore.Qt.LeftButton | QtCore.Qt.MidButton):
                if self.state['mouseMode'] == ViewBox.RectMode:
                    if ev.isFinish():  # This is the final move in the drag; change the view scale now
                        # print "finish"
                        self.rbScaleBox.hide()
                        ax = QtCore.QRectF(
                            Point(ev.buttonDownPos(ev.button())), Point(pos))
                        ax = self.childGroup.mapRectFromParent(ax)
                        self.showAxRect(ax)
                        self.axHistoryPointer += 1
                        self.axHistory = self.axHistory[:self.axHistoryPointer] + [
                            ax]
                    else:
                        # update shape of scale box
                        self.updateScaleBox(ev.buttonDownPos(), ev.pos())
                else:
                    tr = dif * mask
                    tr = self.mapToView(tr) - self.mapToView(Point(0, 0))
                    x = tr.x() if mask[0] == 1 else None
                    y = tr.y() if mask[1] == 1 else None

                    self._resetTarget()
                    if x is not None or y is not None:
                        self.translateBy(x=x, y=y)
                    self.sigRangeChangedManually.emit(
                        self.state['mouseEnabled'])
            elif ev.button() & QtCore.Qt.RightButton:
                # print "vb.rightDrag"
                if self.state['aspectLocked'] is not False:
                    mask[0] = 0

                dif = ev.screenPos() - ev.lastScreenPos()
                dif = np.array([dif.x(), dif.y()])
                dif[0] *= -1
                s = ((mask * 0.02) + 1) ** dif

                tr = self.childGroup.transform()
                tr = fn.invertQTransform(tr)

                x = s[0] if mouseEnabled[0] == 1 else None
                y = s[1] if mouseEnabled[1] == 1 else None

                center = Point(tr.map(ev.buttonDownPos(QtCore.Qt.RightButton)))
                self._resetTarget()
                self.scaleBy(x=x, y=y, center=center)
                self.sigRangeChangedManually.emit(self.state['mouseEnabled'])
예제 #29
0
    def onMouseWheeled(self, ev, axis):
        """
        Allows mouse wheel zoom on ctrl-click [currently]
        """
        self.controlDrag=False #TODO: hack that should not be needed
        modifiers = QtGui.QApplication.keyboardModifiers()
        if  modifiers == QtCore.Qt.ControlModifier  or (modifiers == (QtCore.Qt.ControlModifier |  QtCore.Qt.ShiftModifier)):
            # Emit a signal when the wheel is rotated alone and return a positive or negative value in self.progressBy
            # that we can use to incremement the image layer in the current axes
            if ev.delta()>0:
                self.progressBy=1
            elif ev.delta()<0:
                self.progressBy=-1
            else:
                self.progressBy=0
            self.progressBy = self.progressBy * abs(ev.delta())/120 #this may be mouse-specific!

            if modifiers == (QtCore.Qt.ControlModifier |  QtCore.Qt.ShiftModifier):
                # Allow faster scrolling if it was a shift+wheel
                self.progressBy = self.progressBy*5

            self.progressLayer.emit()
    
        else:
            #Handle zoom (mousewheel with no keyboard modifier) 
            mask = np.array(self.state['mouseEnabled'], dtype=np.float)
 
            if axis is not None and axis >= 0 and axis < len(mask):
                mv = mask[axis]
                mask[:] = 0
                mask[axis] = mv

            s = ((mask * 0.02) + 1) ** (ev.delta() * self.state['wheelScaleFactor']) # actual scaling factor
            center = pg.Point(fn.invertQTransform(self.childGroup.transform()).map(ev.pos()))
            #center = ev.pos()
        
            self._resetTarget()
            self.scaleBy(s, center)
            self.sigRangeChangedManually.emit(self.state['mouseEnabled'])
            ev.accept()

            if len(self.linkedAxis)>0:
                for thisViewBox in self.linkedAxis:

                    if self.linkedAxis[thisViewBox]['linkZoom']==True: 
                        #Centre with the appropriate axes to avoid the views translating in horrible ways during zooming
                        #I don't know why I also need to call my centerOn() method, but at least this works
                        if self.linkedAxis[thisViewBox]['linkX']=='x' and self.linkedAxis[thisViewBox]['linkY'] is None :
                            thisViewBox.scaleBy(s,x=center.x())
                            self.centreOn(thisViewBox,x=center.x())

                        if self.linkedAxis[thisViewBox]['linkY']=='y' and self.linkedAxis[thisViewBox]['linkX'] is None :
                            thisViewBox.scaleBy(s,y=center.y())
                            self.centreOn(thisViewBox,y=center.y())

                        if self.linkedAxis[thisViewBox]['linkX']=='y' and self.linkedAxis[thisViewBox]['linkY'] is None : 
                            thisViewBox.scaleBy(s,y=center.x())
                            self.centreOn(thisViewBox,y=center.x())

                        if self.linkedAxis[thisViewBox]['linkY']=='x' and self.linkedAxis[thisViewBox]['linkX'] is None : 
                            thisViewBox.scaleBy(s,x=center.y())
                            self.centreOn(thisViewBox,x=center.y())

                        #The following two cases aren't used currently by Lasagna, but may be required in the future. 
                        #They haven't been tested yet. [28/07/15]
                        if self.linkedAxis[thisViewBox]['linkY']=='x' and self.linkedAxis[thisViewBox]['linkX']=='y' : 
                            thisViewBox.scaleBy(s,x=center.y(),y=center.x())
                            self.centreOn(thisViewBox,x=center.y(),y=center.x())

                        if self.linkedAxis[thisViewBox]['linkY']=='y' and self.linkedAxis[thisViewBox]['linkX']=='x' : 
                            thisViewBox.scaleBy(s,x=center.x(),y=center.y())
                            self.centreOn(thisViewBox,x=center.x(),y=center.y())