Beispiel #1
0
def is_intersection(ed1, ed2, norm):
    vis1 = is_visiable(ed1[0], ed2[0], ed2[1], norm)
    vis2 = is_visiable(ed1[1], ed2[0], ed2[1], norm)
    if (vis1 and not vis2) or (not vis1 and vis2):
        # ищем пересечение

        p1 = ed1[0]
        p2 = ed1[1]

        q1 = ed2[0]
        q2 = ed2[1]

        delta = (p2.x() - p1.x()) * (q1.y() - q2.y()) - (q1.x() - q2.x()) * (p2.y() - p1.y())
        delta_t = (q1.x() - p1.x()) * (q1.y() - q2.y()) - (q1.x() - q2.x()) * (q1.y() - p1.y())

        if abs(delta) <= 1e-6:
            return p2

        t = delta_t / delta

        I = QPointF()
        I.setX(ed1[0].x() + (ed1[1].x() - ed1[0].x()) * t)
        I.setY(ed1[0].y() + (ed1[1].y() - ed1[0].y()) * t)
        return I
    else:
        return False
Beispiel #2
0
Datei: lab9.py Projekt: ppupha/KG
def Intersection(line1, line2, n):
    print("check in Inter")
    vis1 = isVisiable(line1[0], line2, n)
    vis2 = isVisiable(line1[1], line2, n)
    if (vis1 and not vis2) or (not vis1 and vis2):
        # ищем пересечение

        p1 = line1[0]
        p2 = line1[1]

        q1 = line2[0]
        q2 = line2[1]

        delta = (p2.x() - p1.x()) * (q1.y() - q2.y()) - (q1.x() - q2.x()) * (
            p2.y() - p1.y())
        delta_t = (q1.x() - p1.x()) * (q1.y() - q2.y()) - (q1.x() - q2.x()) * (
            q1.y() - p1.y())
        if abs(delta) <= 1e-6:
            return p2

        t = delta_t / delta

        I = QPointF()
        I.setX(line1[0].x() + (line1[1].x() - line1[0].x()) * t)
        I.setY(line1[0].y() + (line1[1].y() - line1[0].y()) * t)
        return I
    else:
        return False
Beispiel #3
0
 def itemChange(self, change, value):
     # if position of label changes
     if change == QGraphicsItem.ItemPositionChange and self.scene():
         newPos = QPointF(value)  # new position
         newPos += QPointF(self.boundingRect().width() / 2, self.boundingRect().height() / 2)  # pos of center
         points = self.parentItem().points
         firstPoint = points[self.index]
         endPoint = points[self.index + 1]
         if firstPoint.x() == endPoint.x():
             if min(firstPoint.y(), endPoint.y()) > newPos.y():
                 newPos.setY(min(firstPoint.y(), endPoint.y()))
             elif newPos.y() > max(firstPoint.y(), endPoint.y()):
                 newPos.setY(max(firstPoint.y(), endPoint.y()))
         elif firstPoint.y() == endPoint.y():
             if min(firstPoint.x(), endPoint.x()) > newPos.x():
                 newPos.setX(min(firstPoint.x(), endPoint.x()))
             elif newPos.x() > max(firstPoint.x(), endPoint.x()):
                 newPos.setX(max(firstPoint.x(), endPoint.x()))
         newPos -= QPointF(self.boundingRect().width() / 2,
                           self.boundingRect().height() / 2)  # change center pos to top-left
         return newPos
     if change == QGraphicsItem.ItemPositionHasChanged and self.scene():
         self.updateGap()
         self.updateLine()
         return
     return super(LineLabel, self).itemChange(change, value)
Beispiel #4
0
def paint_pipe(self, c_e, is_pipe, l_i_nodes, cond_pipe, union_pipe, items,
               l_nodes):
    if is_pipe:
        if not cond_pipe:
            l_p = l_nodes + self.l_reservoir
            l_p_2 = l_i_nodes + self.l_i_reservoir
            node = l_p[l_p_2.index(items[0])]
            c_e.setX(node.x)
            c_e.setY(node.y)
            e_f = QPointF(c_e.x() + 1, c_e.y() + 1)
            item = self.scene_v.addLine(c_e.x(), c_e.y(), e_f.x(), e_f.y(),
                                        QPen(QColor('black')))
            union_pipe[0] = node
            return True, c_e, item, union_pipe
        else:
            self.scene_v.removeItem(self.current_item)
            l_p = l_nodes + self.l_reservoir
            l_p_2 = l_i_nodes + self.l_i_reservoir
            node = l_p[l_p_2.index(items[0])]
            e_f = QPointF()
            e_f.setX(node.x)
            e_f.setY(node.y)
            n_i = union_pipe[0]
            union_pipe[1] = node
            item = self.paint_pipe(self.start_e, e_f, n_i, node)
            return False, None, item, union_pipe

    else:
        return False, None, self.current_item, [None, None]
Beispiel #5
0
def add_point_by_btn(win):
    x = win.x.value()
    y = win.y.value()
    p = QPointF()
    p.setX(x)
    p.setY(y)
    add_point(p)
Beispiel #6
0
    def applyLayerValue(self, id, val):
        layer = self.mObject
        layerIndex = self.mMapDocument.map().layers().indexOf(layer)
        command = None
        x = id
        if x == PropertyId.NameProperty:
            command = RenameLayer(self.mMapDocument, layerIndex, val)
        elif x == PropertyId.VisibleProperty:
            command = SetLayerVisible(self.mMapDocument, layerIndex, val)
        elif x == PropertyId.OpacityProperty:
            command = SetLayerOpacity(self.mMapDocument, layerIndex, val)
        elif x == PropertyId.OffsetXProperty or x == PropertyId.OffsetYProperty:
            offset = QPointF(layer.offset())

            if id == PropertyId.OffsetXProperty:
                offset.setX(val)
            else:
                offset.setY(val)

            command = SetLayerOffset(self.mMapDocument, layerIndex, offset)
        else:
            x = layer.layerType()
            if x == Layer.TileLayerType:
                self.applyTileLayerValue(id, val)
            elif x == Layer.ObjectGroupType:
                self.applyObjectGroupValue(id, val)
            elif x == Layer.ImageLayerType:
                self.applyImageLayerValue(id, val)
        if (command):
            self.mMapDocument.undoStack().push(command)
Beispiel #7
0
    def applyLayerValue(self, id, val):
        layer = self.mObject
        layerIndex = self.mMapDocument.map().layers().indexOf(layer)
        command = None
        x = id
        if x==PropertyId.NameProperty:
            command = RenameLayer(self.mMapDocument, layerIndex, val)
        elif x==PropertyId.VisibleProperty:
            command = SetLayerVisible(self.mMapDocument, layerIndex, val)
        elif x==PropertyId.OpacityProperty:
            command = SetLayerOpacity(self.mMapDocument, layerIndex, val)
        elif x==PropertyId.OffsetXProperty or x==PropertyId.OffsetYProperty:
            offset = QPointF(layer.offset())

            if id == PropertyId.OffsetXProperty:
                offset.setX(val)
            else:
                offset.setY(val)

            command = SetLayerOffset(self.mMapDocument, layerIndex, offset)
        else:
            x = layer.layerType()
            if x==Layer.TileLayerType:
                self.applyTileLayerValue(id, val)
            elif x==Layer.ObjectGroupType:
                self.applyObjectGroupValue(id, val)
            elif x==Layer.ImageLayerType:
                self.applyImageLayerValue(id, val)
        if (command):
            self.mMapDocument.undoStack().push(command)
Beispiel #8
0
 def rotatePointClockWise(self, p: QPointF, angle):
     '''
     Standard 2x2 rotation matrix, counter-clockwise
       |  cos(phi)   sin(phi) |
       | -sin(phi)   cos(phi) |
     '''
     p.setX(cos(angle) * p.x() + sin(angle)* p.y())
     p.setY((-1.0 * sin(angle) * p.x()) + cos(angle) * p.y())
Beispiel #9
0
 def resizeEvent(self, ev=None):
     # Set correct position of label
     br = self.label.boundingRect()
     p = QPointF(0, 0)
     p.setX(int(self.size().width() / 2 - br.width() / 2))
     p.setY(10)
     self.label.setPos(p)
     self.picture = None
Beispiel #10
0
 def resizeEvent(self, ev=None):
     # Set correct position of label
     br = self.label.boundingRect()
     p = QPointF(0, 0)
     p.setX(self.textWidth + 5)
     p.setY(int(self.size().height() / 2 + br.width() / 2))
     self.label.setPos(p)
     self.picture = None
Beispiel #11
0
 def drawPolygon(self, refPolygon, painter):
     # Scale coordinates
     draw = QPolygonF(refPolygon.size())
     for i in range(refPolygon.size()):
         curr = QPointF()
         curr.setX(self.refToScreenX(refPolygon.at(i).x()))
         curr.setY(self.refToScreenY(refPolygon.at(i).y()))
         draw.replace(i, curr)
     painter.drawPolygon(draw)
Beispiel #12
0
 def enforce_bounds(self, pos):
     pos = QPointF(pos)
     if pos.x() < self.piano_width:
         pos.setX(self.piano_width)
     elif pos.x() >= self.grid_width + self.piano_width:
         pos.setX(self.grid_width + self.piano_width - 1)
     if pos.y() < self.header_height + self.padding:
         pos.setY(self.header_height + self.padding)
     return pos
Beispiel #13
0
Datei: lab9.py Projekt: ppupha/KG
def addpoint_btn(win):
    x = win.xInput.value()
    y = win.yInput.value()

    p = QPointF()
    p.setX(x)

    p.setY(y)
    add_point(p)
Beispiel #14
0
    def paint(self, painter, option, widget=None):
        path = QPainterPath()
        path.addRoundedRect(self.m_rect, 5, 5)

        anchor = self.mapFromParent(self.m_chart.mapToPosition(self.m_anchor))
        if not self.m_rect.contains(anchor):
            point1 = QPointF()
            point2 = QPointF()

            # establish the position of the anchor point in relation to m_rect
            above = anchor.y() <= self.m_rect.top()
            aboveCenter = (anchor.y() > self.m_rect.top()
                           and anchor.y() <= self.m_rect.center().y())
            belowCenter = (anchor.y() > self.m_rect.center().y()
                           and anchor.y() <= self.m_rect.bottom())
            below = anchor.y() > self.m_rect.bottom()

            onLeft = anchor.x() <= self.m_rect.left()
            leftOfCenter = (anchor.x() > self.m_rect.left()
                            and anchor.x() <= self.m_rect.center().x())
            rightOfCenter = (anchor.x() > self.m_rect.center().x()
                             and anchor.x() <= self.m_rect.right())
            onRight = anchor.x() > self.m_rect.right()

            # get the nearest m_rect corner.
            x = (onRight + rightOfCenter) * self.m_rect.width()
            y = (below + belowCenter) * self.m_rect.height()
            cornerCase = ((above and onLeft) or (above and onRight)
                          or (below and onLeft) or (below and onRight))
            vertical = abs(anchor.x() - x) > abs(anchor.y() - y)

            x1 = (x + leftOfCenter * 10 - rightOfCenter * 20 +
                  cornerCase * int(not vertical) *
                  (onLeft * 10 - onRight * 20))
            y1 = (y + aboveCenter * 10 - belowCenter * 20 +
                  cornerCase * int(vertical) * (above * 10 - below * 20))
            point1.setX(x1)
            point1.setY(y1)

            x2 = (x + leftOfCenter * 20 - rightOfCenter * 10 +
                  cornerCase * int(not vertical) *
                  (onLeft * 20 - onRight * 10))
            y2 = (y + aboveCenter * 20 - belowCenter * 10 +
                  cornerCase * int(vertical) * (above * 20 - below * 10))
            point2.setX(x2)
            point2.setY(y2)

            path.moveTo(point1)
            path.lineTo(anchor)
            path.lineTo(point2)
            path = path.simplified()

        painter.setBrush(QColor(255, 255, 255))
        painter.drawPath(path)
        painter.drawText(self.m_textRect, self.m_text)
Beispiel #15
0
Datei: lab8.py Projekt: ppupha/KG
def P_t(line, t):
    print(line, t)
    p = QPointF()
    P1 = QPointF(line[0][0], line[0][1])
    P2 = QPointF(line[1][0], line[1][1])
    print(P1.x(), P1.y())
    print(P2.x(), P2.y())
    print("chekc 9")
    p.setX(P1.x() + (P2.x() - P1.x()) * t)
    p.setY(P1.y() + (P2.y() - P1.y()) * t)
    print(p.x(), p.y())

    return p
Beispiel #16
0
    def get_line_start(self, index: int) -> QPointF:
        pt = QPointF()
        pt1 = self.clickedPoints[index]
        pt2 = self.clickedPoints[(index + 1) % len(self.clickedPoints)]
        if self.get_distance(pt1, pt2) == 0:
            f_rat = 0.5
        else:
            f_rat = float(self.__i_radius) / self.get_distance(pt1, pt2)
            if f_rat > 0.5:
                f_rat = 0.5

        pt.setX((1.0 - f_rat) * pt1.x() + f_rat * pt2.x())
        pt.setY((1.0 - f_rat) * pt1.y() + f_rat * pt2.y())
        return pt
Beispiel #17
0
    def initUi(self):

        pos = QPointF(0, 0)

        for i in range(0, self.length):  #每一秒有1個刻度,總共 length 秒
            t1 = QGraphicsTextItem('|', self)
            t1.setDefaultTextColor(QColor(Qt.blue))
            t1.setPos(pos)

            t2 = QGraphicsTextItem('{}'.format(i + int(self.start)), self)
            t2.setDefaultTextColor(QColor(Qt.blue))
            t2.setPos(t1.boundingRect().bottomLeft() + pos)

            pos.setX(pos.x() + int(self.w / self.length))
        self.setRect(0, 0, self.w, self.h)
Beispiel #18
0
def normal(a: QPointF, b: QPointF, pos: QPointF):
    fvec = QPointF(b.x() - a.x(), b.y() - a.y())
    posvec = QPointF(pos.x() - b.x(), pos.y() - b.y())

    if fvec.y():
        fpoint = -fvec.x() / fvec.y()
        normvec = QPointF(1, fpoint)
    else:
        normvec = QPointF(0, 1)

    if scalar_mult(posvec, normvec) < 0:
        normvec.setX(-normvec.x())
        normvec.setY(-normvec.y())

    return normvec
    def mouseMovedWhileCreatingObject(self, pos, modifiers):
        renderer = self.mapDocument().renderer()
        pixelCoords = renderer.screenToPixelCoords_(pos)
        # Update the size of the new map object
        objectPos = self.mNewMapObjectItem.mapObject().position()
        newSize = QPointF(max(0.0, pixelCoords.x() - objectPos.x()),
                        max(0.0, pixelCoords.y() - objectPos.y()))
        # Holding shift creates circle or square
        if (modifiers & Qt.ShiftModifier):
            m = max(newSize.x(), newSize.y())
            newSize.setX(m)
            newSize.setY(m)

        SnapHelper(renderer, modifiers).snap(newSize)
        self.mNewMapObjectItem.resizeObject(QSizeF(newSize.x(), newSize.y()))
Beispiel #20
0
    def paint(self, painter, option, widget):
        path = QPainterPath()
        x, y, w, d = self.m_rect.getRect()
        self.m_rect = QRectF(x, y, w, d)
        path.addRoundedRect(self.m_rect, 5, 5)

        anchor = self.mapFromParent(self.chart.mapToPosition(self.m_anchor))
        if not self.m_rect.contains(QPoint(int(anchor.x()), int(anchor.y()))):
            point1 = QPointF()
            point2 = QPointF()
            above = anchor.y() <= self.m_rect.top()
            aboveCenter = anchor.y() > self.m_rect.top() and anchor.y(
            ) <= self.m_rect.center().y()
            belowCenter = anchor.y() > self.m_rect.center().y() and anchor.y(
            ) <= self.m_rect.bottom()
            below = anchor.y() > self.m_rect.bottom()
            onLeft = anchor.x() <= self.m_rect.left()
            leftOfCenter = anchor.x() > self.m_rect.left() and anchor.x(
            ) <= self.m_rect.center().x()
            rightOfCenter = anchor.x() > self.m_rect.center().x() and anchor.x(
            ) <= self.m_rect.right()
            onRight = anchor.x() > self.m_rect.right()
            #get the nearest m_rect corner
            x = (onRight + rightOfCenter) * self.m_rect.width()
            y = (below + belowCenter) * self.m_rect.height()
            cornerCase = (above and onLeft) or (above and onRight) or (
                below and onLeft) or (below and onRight)
            vertical = abs(anchor.x() - x) > abs(anchor.y() - y)
            x1 = x + leftOfCenter * 10 - rightOfCenter * 20 + cornerCase * (
                not vertical) * (onLeft * 10 - onRight * 20)
            y1 = y + aboveCenter * 10 - belowCenter * 20 + cornerCase * vertical * (
                above * 10 - below * 20)
            point1.setX(x1)
            point1.setY(y1)
            x2 = x + leftOfCenter * 20 - rightOfCenter * 10 + cornerCase * (
                not vertical) * (onLeft * 20 - onRight * 10)
            y2 = y + aboveCenter * 20 - belowCenter * 10 + cornerCase * vertical * (
                above * 20 - below * 10)
            point2.setX(x2)
            point2.setY(y2)
            path.moveTo(point1)
            path.lineTo(anchor)
            path.lineTo(point2)
            path = path.simplified()
        painter.setBrush(QColor(255, 255, 255))
        painter.drawPath(path)
        painter.drawText(self.m_textRect, Qt.AlignLeft, self.m_text)
    def keyPressed(self, event):
        if (self.mAction != Action.NoAction):
            event.ignore()
            return

        moveBy = QPointF()
        x = event.key()
        if x == Qt.Key_Up:
            moveBy = QPointF(0, -1)
        elif x == Qt.Key_Down:
            moveBy = QPointF(0, 1)
        elif x == Qt.Key_Left:
            moveBy = QPointF(-1, 0)
        elif x == Qt.Key_Right:
            moveBy = QPointF(1, 0)
        else:
            super().keyPressed(event)
            return

        items = self.mapScene().selectedObjectItems()
        modifiers = event.modifiers()
        if (moveBy.isNull() or items.isEmpty()
                or (modifiers & Qt.ControlModifier)):
            event.ignore()
            return

        moveFast = modifiers & Qt.ShiftModifier
        snapToFineGrid = preferences.Preferences.instance().snapToFineGrid()
        if (moveFast):
            # TODO: This only makes sense for orthogonal maps
            moveBy.setX(moveBy.x() * self.mapDocument().map().tileWidth())
            moveBy.setX(moveBy.y() * self.mapDocument().map().tileHeight())
            if (snapToFineGrid):
                moveBy /= preferences.Preferences.instance().gridFine()

        undoStack = self.mapDocument().undoStack()
        undoStack.beginMacro(self.tr("Move %n Object(s)", "", items.size()))
        i = 0
        for objectItem in items:
            object = objectItem.mapObject()
            oldPos = object.position()
            newPos = oldPos + moveBy
            undoStack.push(
                MoveMapObject(self.mapDocument(), object, newPos, oldPos))
            i += 1

        undoStack.endMacro()
    def keyPressed(self, event):
        if (self.mAction != Action.NoAction):
            event.ignore()
            return

        moveBy = QPointF()
        x = event.key()
        if x==Qt.Key_Up:
            moveBy = QPointF(0, -1)
        elif x==Qt.Key_Down:
            moveBy = QPointF(0, 1)
        elif x==Qt.Key_Left:
            moveBy = QPointF(-1, 0)
        elif x==Qt.Key_Right:
            moveBy = QPointF(1, 0)
        else:
            super().keyPressed(event)
            return

        items = self.mapScene().selectedObjectItems()
        modifiers = event.modifiers()
        if (moveBy.isNull() or items.isEmpty() or (modifiers & Qt.ControlModifier)):
            event.ignore()
            return

        moveFast = modifiers & Qt.ShiftModifier
        snapToFineGrid = preferences.Preferences.instance().snapToFineGrid()
        if (moveFast):
            # TODO: This only makes sense for orthogonal maps
            moveBy.setX(moveBy.x() * self.mapDocument().map().tileWidth())
            moveBy.setX(moveBy.y() * self.mapDocument().map().tileHeight())
            if (snapToFineGrid):
                moveBy /= preferences.Preferences.instance().gridFine()

        undoStack = self.mapDocument().undoStack()
        undoStack.beginMacro(self.tr("Move %n Object(s)", "", items.size()))
        i = 0
        for objectItem in items:
            object = objectItem.mapObject()
            oldPos = object.position()
            newPos = oldPos + moveBy
            undoStack.push(MoveMapObject(self.mapDocument(), object, newPos, oldPos))
            i += 1

        undoStack.endMacro()
Beispiel #23
0
 def selectWindow(self, p, w, h):
     if w > 0 and h > 0:
         pEnd = QPointF()
         self.imageWindow.setX(p.x() - w / 2)
         if self.imageWindow.x() < 0:
             self.imageWindow.setX(0)
         self.imageWindow.setY(p.y() - h / 2)
         if self.imageWindow.y() < 0:
             self.imageWindow.setY(0)
         pEnd.setX(p.x() + w / 2)
         if pEnd.x() >= 320:
             pEnd.setX(319)
         pEnd.setY(p.y() + h / 2)
         if pEnd.y() >= 240:
             pEnd.setY(239)
         self.imageWindow.setWidth(pEnd.x() - self.imageWindow.x())
         self.imageWindow.setHeight(pEnd.y() - self.imageWindow.y())
         self.winSelected = True
Beispiel #24
0
def AddDrawPolygonOnMap(poly_coordinates):
    ''' Add Polygon Layer '''
    polyLyr = qgsu.selectLayerByName(Polygon_lyr)
    if polyLyr is None:
        return
    polyLyr.startEditing()
    feature = QgsFeature()
    point = QPointF()
    # create  float polygon --> construcet out of 'point'

    list_polygon = QPolygonF()
    for x in range(0, len(poly_coordinates)):
        if x % 2 == 0:
            point.setX(poly_coordinates[x])
            point.setY(poly_coordinates[x + 1])
            list_polygon.append(point)
    point.setX(poly_coordinates[0])
    point.setY(poly_coordinates[1])
    list_polygon.append(point)

    geomP = QgsGeometry.fromQPolygonF(list_polygon)
    feature.setGeometry(geomP)

    # Calculate Area WSG84 (Meters)
    area_wsg84 = QgsDistanceArea()
    area_wsg84.setSourceCrs(
        QgsCoordinateReferenceSystem.fromOgcWmsCrs('EPSG:4326'),
        QgsProject.instance().transformContext())
    if (area_wsg84.sourceCrs().isGeographic()):
        area_wsg84.setEllipsoid(area_wsg84.sourceCrs().ellipsoidAcronym())

    # Calculate Centroid
    centroid = feature.geometry().centroid().asPoint()

    feature.setAttributes([
        centroid.x(),
        centroid.y(), 0.0,
        area_wsg84.measurePolygon(geomP.asPolygon()[0])
    ])

    polyLyr.addFeatures([feature])

    CommonLayer(polyLyr)
    return
Beispiel #25
0
    def interactiveResize(self, mousePos):
        """Выполните форму интерактивного изменения размера."""
        offset = self.handleSize + self.handleSpace
        boundingRect = self.boundingRect()
        rect = self.rect()
        diff = QPointF(0, 0)

        self.prepareGeometryChange()

        if self.handleSelected == self.handleTopMiddle_c:
            fromY = self.mousePressRect.top()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            diff.setY(toY - fromY)
            boundingRect.setTop(toY)
            rect.setTop(boundingRect.top() + offset)
            self.setRect(rect)

        elif self.handleSelected == self.handleMiddleLeft_c:
            fromX = self.mousePressRect.left()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            diff.setX(toX - fromX)
            boundingRect.setLeft(toX)
            rect.setLeft(boundingRect.left() + offset)
            self.setRect(rect)

        elif self.handleSelected == self.handleMiddleRight_c:
            print("MR")
            fromX = self.mousePressRect.right()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            diff.setX(toX - fromX)
            boundingRect.setRight(toX)
            rect.setRight(boundingRect.right() - offset)
            self.setRect(rect)

        elif self.handleSelected == self.handleBottomMiddle_c:

            fromY = self.mousePressRect.bottom()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            diff.setY(toY - fromY)
            boundingRect.setBottom(toY)
            rect.setBottom(boundingRect.bottom() - offset)
            self.setRect(rect)

        self.updateHandlesPos()
Beispiel #26
0
    def interactiveResize(self, mousePos, sync=True):
        """
        Perform shape interactive resize.
        """
        diff = QPointF(0, 0)
        center = self.center()
        self.prepareGeometryChange()

        if self.handleSelected:
            fromX = self.points[self.handleSelected].x()
            fromY = self.points[self.handleSelected].y()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
        else:
            toX = mousePos.x()
            toY = mousePos.y()
            fromX = self.mousePressPos.x()
            fromY = self.mousePressPos.y()
        diff.setX(-fromX + toX)
        diff.setY(-fromY + toY)

        if not self.right:  # left click
            if self.handleSelected == self.handleTopLeft:
                self.moveTopLeft(diff)
            elif self.handleSelected == self.handleTopRight:
                self.moveTopRight(diff)
            elif self.handleSelected == self.handleBottomLeft:
                self.moveBottomLeft(diff)
            elif self.handleSelected == self.handleBottomRight:
                self.moveBottomRight(diff)
            elif self.handleSelected is None and sync:  # drag
                self.move(diff)
            self.setPolygon(list(self.points.values()))  #update points
            self.mousePressPos = mousePos
        else:  # right click
            self.rotate(-self._angle)  # rotate
            mpx, mpy = self.mousePressPos.x() - center.x(
            ), self.mousePressPos.y() - center.y()
            mx, my = mousePos.x() - center.x(), mousePos.y() - center.y()
            self._angle = angle_vec(np.array([mpx, mpy]), np.array([mx, my]))
            self.rotate(self._angle)  # rotate
        self.updateHandlesPos()
        if sync and self.canvas and self.component_name:  # only update others when we now the component name
            self.canvas.sync_measures(self)
Beispiel #27
0
 def itemChange(self, change, value):
     """
     Moves position of grip item on resize
     """
     if change == QGraphicsItem.ItemPositionChange and self.isEnabled():
         p = QPointF(self.pos())
         if self.direction == Qt.Horizontal:
             p.setX(value.x())
         elif self.direction == Qt.Vertical:
             p.setY(value.y())
         # Find change in positions
         movement = p - self.pos()
         # Set transform to oppose change in transformation due to parent
         transform = QTransform()
         transform.translate(-movement.x() / 2, -movement.y() / 2)
         self.setTransform(transform, True)
         self.parentItem().resize(self.m_index, movement)
         return p
     return super(SizeGripItem, self).itemChange(change, value)
 def mouseMoveEvent(self, event):
     mouse_pos = event.pos()
     if not self.is_mouse_pressed:
         self.cursor_position = CursorPosition(self.cropping_rect, mouse_pos)
         self.update_cursor_icon(mouse_pos)
     elif self.cursor_position != CursorPosition.cursor_position_undefined:
         mouse_delta = QPointF()
         mouse_delta.setX(mouse_pos.x() - self.start_mouse_pos.x())
         mouse_delta.setY(mouse_pos.y() - self.start_mouse_pos.y())
         if self.cursor_position != CursorPosition.cursor_position_middle:
             new_geometry = self._calculate_geometry(
                 self.last_static_cropping_rect,
                 self.cursor_position,
                 mouse_delta
             )
             if not new_geometry.isNull():
                 self.cropping_rect = new_geometry
         else:
             self.cropping_rect.moveTo(self.last_static_cropping_rect.topLeft() + mouse_delta)
	def render_snapshot(self, snapshot: Snapshot):
		self.nodz.clearGraph()
		nodes = snapshot.data
		center_position = self.nodz.mapToScene(self.nodz.viewport().rect().center())
		highlights = snapshot.highlights

		for index, node in enumerate(nodes):
			#TODO calculate pos
			node_pos = QPointF(center_position)
			#node_pos.setX(((center_position.x() * 2) / len(nodes)) * (index + 1) - 200)
			node_pos.setX(center_position.x() + (index + 1) * 185 - 1000)
			node_pos.setY(center_position.y() + (50+ (index + 1) * 10) * (-1)**(index+1))

			if highlights[index] == Snapshot.color_idle:
				attr_preset = 'attr_color_idle'
				node_preset = 'node_color_idle'
			elif highlights[index] == Snapshot.color_selected:
				attr_preset = 'attr_color_selected'
				node_preset = 'node_color_selected'
			elif highlights[index] == Snapshot.color_current:
				attr_preset = 'attr_color_current'
				node_preset = 'node_color_current'
			elif highlights[index] == Snapshot.color_current_final:
				attr_preset = 'attr_color_current_final'
				node_preset = 'node_color_current_final'

			nodz_node = self.create_node(node.name, preset=node_preset, position=node_pos)
			for attr in node.attributes:
				nodz_attr = self.create_attribute(nodz_node, attr.name, attr_preset)
			self.nodz_nodes.append(nodz_node)

		for node in nodes:
			for attr in node.attributes:
				if (not attr.connection is None) and (attr.node_name != attr.connection.node_name):
					self.nodz.createConnection(
						attr.node_name, attr.name,
						attr.connection.node_name, attr.connection.name
					)

		self.nodz.evaluateGraph()
		pass
		
Beispiel #30
0
    def itemChange(self, change, value):
        """ move position of grabber after resize"""
        if change == QGraphicsItem.ItemPositionChange and self.isEnabled():
            p = QPointF(self.pos())
            if self.direction == Qt.Horizontal:
                p.setX(value.x())
                if self.parentItem().refLine and self.m_index == len(self.parentItem().points) - 2:
                    points = self.parentItem().refLine.points
                    point1 = points[self.parentItem().refIndex]
                    point2 = points[self.parentItem().refIndex + 1]
                    point1 = self.parentItem().mapFromItem(self.parentItem().refLine, point1)
                    point2 = self.parentItem().mapFromItem(self.parentItem().refLine, point2)
                    if p.x() < min(point1.x(), point2.x()):
                        p.setX(min(point1.x(), point2.x()))
                    elif p.x() > max(point1.x(), point2.x()):
                        p.setX(max(point1.x(), point2.x()))
            elif self.direction == Qt.Vertical:
                p.setY(value.y())
                if self.parentItem().refLine and self.m_index == len(self.parentItem().points) - 2:
                    points = self.parentItem().refLine.points
                    point1 = points[self.parentItem().refIndex]
                    point2 = points[self.parentItem().refIndex + 1]
                    point1 = self.parentItem().mapFromItem(self.parentItem().refLine, point1)
                    point2 = self.parentItem().mapFromItem(self.parentItem().refLine, point2)
                    if p.y() < min(point1.y(), point2.y()):
                        p.setY(min(point1.y(), point2.y()))
                    elif p.y() > max(point1.y(), point2.y()):
                        p.setY(max(point1.y(), point2.y()))

            movement = p - self.pos()
            self.m_annotation_item.movePoints(self.m_index, movement)
            return p
        return super(Grabber, self).itemChange(change, value)
Beispiel #31
0
    def poly_handler(self, event):
        if event.type() == QEvent.GraphicsSceneMousePress:
            if type(self.active_com.gfx) is not PangoPolyGraphic:
                self.active_com = CreateShape(PangoPolyGraphic,
                                              event.scenePos(),
                                              self.active_label)
                self.stack.push(self.active_com)

            gfx = self.active_com.gfx
            pos = event.scenePos()
            if gfx.poly.count() <= 1 or not gfx.poly.isClosed():
                if QLineF(event.scenePos(),
                          gfx.poly.first()).length() < gfx.dw() * 2:
                    pos = QPointF()
                    pos.setX(gfx.poly.first().x())
                    pos.setY(gfx.poly.first().y())

                self.active_com = ExtendShape(pos, self.active_com.gfx)
                self.stack.push(self.active_com)

                if gfx.poly.count() > 1 and gfx.poly.isClosed():
                    self.reset_com()
Beispiel #32
0
    def intersection(self, point1, point2, edge_point1, edge_point2):

        p1 = point1
        p2 = point2

        q1 = edge_point1
        q2 = edge_point2

        delta = (p2.x() - p1.x()) * (q1.y() - q2.y()) - (q1.x() - q2.x()) * (
            p2.y() - p1.y())
        delta_t = (q1.x() - p1.x()) * (q1.y() - q2.y()) - (q1.x() - q2.x()) * (
            q1.y() - p1.y())

        if abs(delta) <= 1e-6:
            return p2

        t = delta_t / delta

        I = QPointF()
        I.setX(point1.x() + (point2.x() - point1.x()) * t)
        I.setY(point1.y() + (point2.y() - point1.y()) * t)
        return I
    def interactiveMove(self, mousePos):
        diff = QPointF(0, 0)
        rect = self.rect()
        boundingRect = self.boundingRect()

        from_x = self.mousePressPos.x()
        from_y = self.mousePressPos.y()

        to_x = mousePos.x()
        to_y = mousePos.y()

        diff.setX(to_x - from_x)
        diff.setY(to_y - from_y)

        self.moveBy(diff.x(), diff.y())

        # Emit bounding rect here!

        if self.scene() is not None:
            self.scene().rect_changed.emit(self.rect(), self.pos())
        self.update()

        self.updateHandlesPos()
Beispiel #34
0
    def offsetObjects(self, offset, bounds, wrapX, wrapY):
        for object in self.mObjects:
            objectCenter = object.bounds().center()
            if (not bounds.contains(objectCenter)):
                continue
            newCenter = QPointF(objectCenter + offset)
            if (wrapX and bounds.width() > 0):
                nx = math.fmod(newCenter.x() - bounds.left(), bounds.width())
                if nx < 0:
                    x = bounds.width() + nx
                else:
                    x = nx
                newCenter.setX(bounds.left() + x)

            if (wrapY and bounds.height() > 0):
                ny = math.fmod(newCenter.y() - bounds.top(), bounds.height())
                if ny < 0:
                    x = bounds.height() + ny
                else:
                    x = ny
                newCenter.setY(bounds.top() + x)

            object.setPosition(object.position() + (newCenter - objectCenter))
Beispiel #35
0
    def activateNeighbor(self,  active_prexoveritem: 'PreXoverItem',
                                shortcut: str = None):
        """Draws a quad line starting from the item5p to the item3p.
        To be called with whatever the active_prexoveritem is for the parts
        `active_base`.

        Args:
            active_prexoveritem: Description
            shortcut: Default is None
        """
        if self._getActiveTool().methodPrefix() != "selectTool":
            return

        if self.is3p and not active_prexoveritem.is3p:
            item5p = active_prexoveritem
            item3p = self
        elif not self.is3p and active_prexoveritem.is3p:
            item5p = self
            item3p = active_prexoveritem
        else:
            return

        same_parity = self.is_fwd == active_prexoveritem.is_fwd

        p1 = item5p._tick_marks.scenePos() + item5p.exit_pos
        p2 = item3p._tick_marks.scenePos() + item3p.exit_pos

        c1 = QPointF()

        # case 1: same parity
        if same_parity:
            dy = abs(p2.y() - p1.y())
            c1.setX(p1.x() + _X_SCALE * dy)
            c1.setY(0.5 * (p1.y() + p2.y()))
        # case 2: different parity
        else:
            if item3p.is_fwd:
                c1.setX(p1.x() - _X_SCALE * abs(p2.y() - p1.y()))
            else:
                c1.setX(p1.x() + _X_SCALE * abs(p2.y() - p1.y()))
            c1.setY(0.5 * (p1.y() + p2.y()))

        pp = QPainterPath()
        pp.moveTo(self._tick_marks.mapFromScene(p1))
        pp.quadTo(self._tick_marks.mapFromScene(c1),
                  self._tick_marks.mapFromScene(p2))
        # pp.cubicTo(c1, c2, self._tick_marks.mapFromScene(p2))
        self._bond_item.setPath(pp)
        self._bond_item.show()
Beispiel #36
0
class MapObject(Object):
    ##
    # Enumerates the different object shapes. Rectangle is the default shape.
    # When a polygon is set, the shape determines whether it should be
    # interpreted as a filled polygon or a line.
    ##
    Rectangle, Polygon, Polyline, Ellipse = range(4)

    def __init__(self, *args):
        super().__init__(Object.MapObjectType)

        self.mPolygon = QPolygonF()
        self.mName = QString()
        self.mPos = QPointF()
        self.mCell = Cell()
        self.mType = QString()
        self.mId = 0
        self.mShape = MapObject.Rectangle
        self.mObjectGroup = None
        self.mRotation = 0.0
        self.mVisible = True

        l = len(args)
        if l==0:
            self.mSize = QSizeF(0, 0)
        elif l==4:
            name, _type, pos, size = args

            self.mName = name
            self.mType = _type
            self.mPos = pos
            self.mSize = QSizeF(size)

    ##
    # Returns the id of this object. Each object gets an id assigned that is
    # unique for the map the object is on.
    ##
    def id(self):
        return self.mId

    ##
    # Sets the id of this object.
    ##
    def setId(self, id):
        self.mId = id

    ##
    # Returns the name of this object. The name is usually just used for
    # identification of the object in the editor.
    ##
    def name(self):
        return self.mName

    ##
    # Sets the name of this object.
    ##
    def setName(self, name):
        self.mName = name

    ##
    # Returns the type of this object. The type usually says something about
    # how the object is meant to be interpreted by the engine.
    ##
    def type(self):
        return self.mType

    ##
    # Sets the type of this object.
    ##
    def setType(self, type):
        self.mType = type

    ##
    # Returns the position of this object.
    ##
    def position(self):
        return QPointF(self.mPos)

    ##
    # Sets the position of this object.
    ##
    def setPosition(self, pos):
        self.mPos = pos

    ##
    # Returns the x position of this object.
    ##
    def x(self):
        return self.mPos.x()

    ##
    # Sets the x position of this object.
    ##
    def setX(self, x):
        self.mPos.setX(x)

    ##
    # Returns the y position of this object.
    ##
    def y(self):
        return self.mPos.y()

    ##
    # Sets the x position of this object.
    ##
    def setY(self, y):
        self.mPos.setY(y)

    ##
    # Returns the size of this object.
    ##
    def size(self):
        return self.mSize

    ##
    # Sets the size of this object.
    ##
    def setSize(self, *args):
        l = len(args)
        if l==1:
            size = args[0]
            self.mSize = QSizeF(size)
        elif l==2:
            width, height = args
            self.setSize(QSizeF(width, height))

    ##
    # Returns the width of this object.
    ##
    def width(self):
        return self.mSize.width()

    ##
    # Sets the width of this object.
    ##
    def setWidth(self, width):
        self.mSize.setWidth(width)

    ##
    # Returns the height of this object.
    ##
    def height(self):
        return self.mSize.height()

    ##
    # Sets the height of this object.
    ##
    def setHeight(self, height):
        self.mSize.setHeight(height)

    ##
    # Sets the polygon associated with this object. The polygon is only used
    # when the object shape is set to either Polygon or Polyline.
    #
    # \sa setShape()
    ##
    def setPolygon(self, polygon):
        self.mPolygon = polygon

    ##
    # Returns the polygon associated with this object. Returns an empty
    # polygon when no polygon is associated with this object.
    ##
    def polygon(self):
        return QPolygonF(self.mPolygon)

    ##
    # Sets the shape of the object.
    ##
    def setShape(self, shape):
        self.mShape = shape

    ##
    # Returns the shape of the object.
    ##
    def shape(self):
        return self.mShape

    ##
    # Shortcut to getting a QRectF from position() and size().
    ##
    def bounds(self):
        return QRectF(self.mPos, self.mSize)

    ##
    # Shortcut to getting a QRectF from position() and size() that uses cell tile if present.
    ##
    def boundsUseTile(self):
        if (self.mCell.isEmpty()):
            # No tile so just use regular bounds
            return self.bounds()

        # Using the tile for determing boundary
        # Note the position given is the bottom-left corner so correct for that
        return QRectF(QPointF(self.mPos.x(),
                              self.mPos.y() - self.mCell.tile.height()),
                      self.mCell.tile.size())

    ##
    # Sets the tile that is associated with this object. The object will
    # display as the tile image.
    #
    # \warning The object shape is ignored for tile objects!
    ##
    def setCell(self, cell):
        self.mCell = cell

    ##
    # Returns the tile associated with this object.
    ##
    def cell(self):
        return self.mCell

    ##
    # Returns the object group this object belongs to.
    ##
    def objectGroup(self):
        return self.mObjectGroup

    ##
    # Sets the object group this object belongs to. Should only be called
    # from the ObjectGroup class.
    ##
    def setObjectGroup(self, objectGroup):
        self.mObjectGroup = objectGroup

    ##
    # Returns the rotation of the object in degrees.
    ##
    def rotation(self):
        return self.mRotation

    ##
    # Sets the rotation of the object in degrees.
    ##
    def setRotation(self, rotation):
        self.mRotation = rotation

    ##
    # This is somewhat of a workaround for dealing with the ways different objects
    # align.
    #
    # Traditional rectangle objects have top-left alignment.
    # Tile objects have bottom-left alignment on orthogonal maps, but
    # bottom-center alignment on isometric maps.
    #
    # Eventually, the object alignment should probably be configurable. For
    # backwards compatibility, it will need to be configurable on a per-object
    # level.
    ##
    def alignment(self):
        if (self.mCell.isEmpty()):
            return Alignment.TopLeft
        elif (self.mObjectGroup):
            map = self.mObjectGroup.map()
            if map:
                if (map.orientation() == Map.Orientation.Isometric):
                    return Alignment.Bottom

        return Alignment.BottomLeft

    def isVisible(self):
        return self.mVisible
    
    def setVisible(self, visible):
        self.mVisible = visible

    ##
    # Flip this object in the given \a direction. This doesn't change the size
    # of the object.
    ##
    def flip(self, direction):
        if (not self.mCell.isEmpty()):
            if (direction == FlipDirection.FlipHorizontally):
                self.mCell.flippedHorizontally = not self.mCell.flippedHorizontally
            elif (direction == FlipDirection.FlipVertically):
                self.mCell.flippedVertically = not self.mCell.flippedVertically

        if (not self.mPolygon.isEmpty()):
            center2 = self.mPolygon.boundingRect().center() * 2
            if (direction == FlipDirection.FlipHorizontally):
                for i in range(self.mPolygon.size()):
                    # oh, QPointF mPolygon returned is a copy of internal object
                    self.mPolygon[i] = QPointF(center2.x() - self.mPolygon[i].x(), self.mPolygon[i].y())
            elif (direction == FlipDirection.FlipVertically):
                for i in range(self.mPolygon.size()):
                    self.mPolygon[i] = QPointF(self.mPolygon[i].x(), center2.y() - self.mPolygon[i].y())

    ##
    # Returns a duplicate of this object. The caller is responsible for the
    # ownership of this newly created object.
    ##
    def clone(self):
        o = MapObject(self.mName, self.mType, self.mPos, self.mSize)
        o.setProperties(self.properties())
        o.setPolygon(self.mPolygon)
        o.setShape(self.mShape)
        o.setCell(self.mCell)
        o.setRotation(self.mRotation)
        return o
class TeleopWidget(QWidget):

    stopSIG=pyqtSignal()

    def __init__(self,winParent):
        super(TeleopWidget, self).__init__()
        self.winParent=winParent
        self.line = QPointF(0, 0);
        self.qimage=QtGui.QImage()
        self.qimage.load(':images/ball.png')
        self.stopSIG.connect(self.stop)
        self.initUI()

    def initUI(self):
        layout=QGridLayout()
        self.setLayout(layout)
        self.setAutoFillBackground(True)
        p = self.palette()
        p.setColor(self.backgroundRole(), Qt.black)
        self.setPalette(p)
        self.resize(300,300)
        self.setMinimumSize(300,300)

    def stop(self):
        self.line = QPointF(0, 0);
        self.repaint();

    def mouseMoveEvent(self,e):
        if e.buttons() == Qt.LeftButton:
            x = e.x()-self.width()/2
            y = e.y()-self.height()/2
            self.line = QPointF(x, y)
            self.repaint()


    def returnToOrigin(self):
        x = 0
        y = 0
        self.line = QPointF(x, y)
        self.repaint()

    def paintEvent(self, e):
        _width = self.width()
        _height = self.height()


        width = 2

        painter=QtGui.QPainter(self)

        pen = QtGui.QPen(Qt.blue, width)
        painter.setPen(pen)

        #Centro del widget
        painter.translate(QPoint(_width/2, _height/2))

        #eje
        painter.drawLine(QPointF(-_width, 0),
                QPointF( _width, 0))

        painter.drawLine(QPointF(0, -_height),
                QPointF(0, _height))

        #con el raton
        pen = QtGui.QPen(Qt.red, width)
        painter.setPen(pen)

        #Comprobamos que el raton este dentro de los limites
        if abs(self.line.x()*2) >= self.size().width():
            if self.line.x()>=0:
                self.line.setX(self.size().width()/2)
            elif self.line.x()<0:
                self.line.setX((-self.size().width()/2)+1)

        if abs(self.line.y()*2) >= self.size().height():
            if self.line.y()>=0:
                self.line.setY(self.size().height()/2)
            elif self.line.y()<0:
                self.line.setY((-self.size().height()/2)+1)

        painter.drawLine(QPointF(self.line.x(), -_height),
                QPointF(self.line.x(), _height))

        painter.drawLine(QPointF(-_width, self.line.y()),
                QPointF( _width, self.line.y()))

        #print "x: %f y: %f" % (self.line.x(), self.line.y())

        v_normalized = (1.0/(self.size().height()/2)) * self.line.y()
        v_normalized = float("{0:.2f}".format(v_normalized))
        w_normalized = (1.0/(self.size().width()/2)) * self.line.x()
        w_normalized = float("{0:.2f}".format(w_normalized))

        #print "v: %f w: %f" % (v_normalized,w_normalized)
        self.winParent.setXYValues(w_normalized,v_normalized)
        painter.drawImage(self.line.x()-self.qimage.width()/2, self.line.y()-self.qimage.height()/2, self.qimage);
Beispiel #38
0
class EditPolygonTool(AbstractObjectTool):
    NoMode, Selecting, Moving = range(3)

    def __init__(self, parent = None):
        super().__init__(self.tr("Edit Polygons"),
              QIcon(":images/24x24/tool-edit-polygons.png"),
              QKeySequence(self.tr("E")),
              parent)

        self.mSelectedHandles = QSet()
        self.mModifiers = Qt.KeyboardModifiers()
        self.mScreenStart = QPoint()
        self.mOldHandlePositions = QVector()
        self.mAlignPosition = QPointF()
        ## The list of handles associated with each selected map object
        self.mHandles = QMapList()
        self.mOldPolygons = QMap()
        self.mStart = QPointF()

        self.mSelectionRectangle = SelectionRectangle()
        self.mMousePressed = False
        self.mClickedHandle = None
        self.mClickedObjectItem = None
        self.mMode = EditPolygonTool.NoMode

    def __del__(self):
        del self.mSelectionRectangle

    def tr(self, sourceText, disambiguation = '', n = -1):
        return QCoreApplication.translate('EditPolygonTool', sourceText, disambiguation, n)

    def activate(self, scene):
        super().activate(scene)
        self.updateHandles()
        # TODO: Could be more optimal by separating the updating of handles from
        # the creation and removal of handles depending on changes in the
        # selection, and by only updating the handles of the objects that changed.
        self.mapDocument().objectsChanged.connect(self.updateHandles)
        scene.selectedObjectItemsChanged.connect(self.updateHandles)
        self.mapDocument().objectsRemoved.connect(self.objectsRemoved)

    def deactivate(self, scene):
        try:
            self.mapDocument().objectsChanged.disconnect(self.updateHandles)
            scene.selectedObjectItemsChanged.disconnect(self.updateHandles)
        except:
            pass
        # Delete all handles
        self.mHandles.clear()
        self.mSelectedHandles.clear()
        self.mClickedHandle = None
        super().deactivate(scene)

    def mouseEntered(self):
        pass
    def mouseMoved(self, pos, modifiers):
        super().mouseMoved(pos, modifiers)
        if (self.mMode == EditPolygonTool.NoMode and self.mMousePressed):
            screenPos = QCursor.pos()
            dragDistance = (self.mScreenStart - screenPos).manhattanLength()
            if (dragDistance >= QApplication.startDragDistance()):
                if (self.mClickedHandle):
                    self.startMoving()
                else:
                    self.startSelecting()

        x = self.mMode
        if x==EditPolygonTool.Selecting:
            self.mSelectionRectangle.setRectangle(QRectF(self.mStart, pos).normalized())
        elif x==EditPolygonTool.Moving:
            self.updateMovingItems(pos, modifiers)
        elif x==EditPolygonTool.NoMode:
            pass

    def mousePressed(self, event):
        if (self.mMode != EditPolygonTool.NoMode): # Ignore additional presses during select/move
            return
        x = event.button()
        if x==Qt.LeftButton:
            self.mMousePressed = True
            self.mStart = event.scenePos()
            self.mScreenStart = event.screenPos()
            items = self.mapScene().items(self.mStart,
                                                                   Qt.IntersectsItemShape,
                                                                   Qt.DescendingOrder,
                                                                   viewTransform(event))
            self.mClickedObjectItem = first(items, MapObjectItem)
            self.mClickedHandle = first(items, PointHandle)
        elif x==Qt.RightButton:
            items = self.mapScene().items(event.scenePos(),
                                                                   Qt.IntersectsItemShape,
                                                                   Qt.DescendingOrder,
                                                                   viewTransform(event))
            clickedHandle = first(items)
            if (clickedHandle or not self.mSelectedHandles.isEmpty()):
                self.showHandleContextMenu(clickedHandle,
                                      event.screenPos())
            else:
                super().mousePressed(event)
        else:
            super().mousePressed(event)

    def mouseReleased(self, event):
        if (event.button() != Qt.LeftButton):
            return
        x = self.mMode
        if x==EditPolygonTool.NoMode:
            if (self.mClickedHandle):
                selection = self.mSelectedHandles
                modifiers = event.modifiers()
                if (modifiers & (Qt.ShiftModifier | Qt.ControlModifier)):
                    if (selection.contains(self.mClickedHandle)):
                        selection.remove(self.mClickedHandle)
                    else:
                        selection.insert(self.mClickedHandle)
                else:
                    selection.clear()
                    selection.insert(self.mClickedHandle)

                self.setSelectedHandles(selection)
            elif (self.mClickedObjectItem):
                selection = self.mapScene().selectedObjectItems()
                modifiers = event.modifiers()
                if (modifiers & (Qt.ShiftModifier | Qt.ControlModifier)):
                    if (selection.contains(self.mClickedObjectItem)):
                        selection.remove(self.mClickedObjectItem)
                    else:
                        selection.insert(self.mClickedObjectItem)
                else:
                    selection.clear()
                    selection.insert(self.mClickedObjectItem)

                self.mapScene().setSelectedObjectItems(selection)
                self.updateHandles()
            elif (not self.mSelectedHandles.isEmpty()):
                # First clear the handle selection
                self.setSelectedHandles(QSet())
            else:
                # If there is no handle selection, clear the object selection
                self.mapScene().setSelectedObjectItems(QSet())
                self.updateHandles()
        elif x==EditPolygonTool.Selecting:
            self.updateSelection(event)
            self.mapScene().removeItem(self.mSelectionRectangle)
            self.mMode = EditPolygonTool.NoMode
        elif x==EditPolygonTool.Moving:
            self.finishMoving(event.scenePos())

        self.mMousePressed = False
        self.mClickedHandle = None

    def modifiersChanged(self, modifiers):
        self.mModifiers = modifiers

    def languageChanged(self):
        self.setName(self.tr("Edit Polygons"))
        self.setShortcut(QKeySequence(self.tr("E")))

    def updateHandles(self):
        selection = self.mapScene().selectedObjectItems()
        # First destroy the handles for objects that are no longer selected

        for l in range(len(self.mHandles)):
            i = self.mHandles.itemByIndex(l)
            if (not selection.contains(i[0])):
                for handle in i[1]:
                    if (handle.isSelected()):
                        self.mSelectedHandles.remove(handle)
                    del handle

                del self.mHandles[l]

        renderer = self.mapDocument().renderer()
        for item in selection:
            object = item.mapObject()
            if (not object.cell().isEmpty()):
                continue
            polygon = object.polygon()
            polygon.translate(object.position())
            pointHandles = self.mHandles.get(item)
            # Create missing handles
            while (pointHandles.size() < polygon.size()):
                handle = PointHandle(item, pointHandles.size())
                pointHandles.append(handle)
                self.mapScene().addItem(handle)

            # Remove superfluous handles
            while (pointHandles.size() > polygon.size()):
                handle = pointHandles.takeLast()
                if (handle.isSelected()):
                    self.mSelectedHandles.remove(handle)
                del handle

            # Update the position of all handles
            for i in range(pointHandles.size()):
                point = polygon.at(i)
                handlePos = renderer.pixelToScreenCoords_(point)
                internalHandlePos = handlePos - item.pos()
                pointHandles.at(i).setPos(item.mapToScene(internalHandlePos))

            self.mHandles.insert(item, pointHandles)

    def objectsRemoved(self, objects):
        if (self.mMode == EditPolygonTool.Moving):
            # Make sure we're not going to try to still change these objects when
            # finishing the move operation.
            # TODO: In addition to avoiding crashes, it would also be good to
            # disallow other actions while moving.
            for object in objects:
                self.mOldPolygons.remove(object)

    def deleteNodes(self):
        if (self.mSelectedHandles.isEmpty()):
            return
        p = groupIndexesByObject(self.mSelectedHandles)
        undoStack = self.mapDocument().undoStack()
        delText = self.tr("Delete %n Node(s)", "", self.mSelectedHandles.size())
        undoStack.beginMacro(delText)
        for i in p:
            object = i[0]
            indexRanges = i[1]
            oldPolygon = object.polygon()
            newPolygon = oldPolygon
            # Remove points, back to front to keep the indexes valid
            it = indexRanges.end()
            begin = indexRanges.begin()
            # assert: end != begin, since there is at least one entry
            while(it != begin):
                it -= 1
                newPolygon.remove(it.first(), it.length())
            if (newPolygon.size() < 2):
                # We've removed the entire object
                undoStack.push(RemoveMapObject(self.mapDocument(), object))
            else:
                undoStack.push(ChangePolygon(self.mapDocument(), object, newPolygon, oldPolygon))

        undoStack.endMacro()

    def joinNodes(self):
        if (self.mSelectedHandles.size() < 2):
            return
        p = groupIndexesByObject(self.mSelectedHandles)
        undoStack = self.mapDocument().undoStack()
        macroStarted = False
        for i in p:
            object = i[0]
            indexRanges = i[1]
            closed = object.shape() == MapObject.Polygon
            oldPolygon = object.polygon()
            newPolygon = joinPolygonNodes(oldPolygon, indexRanges,
                                                    closed)
            if (newPolygon.size() < oldPolygon.size()):
                if (not macroStarted):
                    undoStack.beginMacro(self.tr("Join Nodes"))
                    macroStarted = True

                undoStack.push(ChangePolygon(self.mapDocument(), object, newPolygon, oldPolygon))

        if (macroStarted):
            undoStack.endMacro()

    def splitSegments(self):
        if (self.mSelectedHandles.size() < 2):
            return
        p = groupIndexesByObject(self.mSelectedHandles)
        undoStack = self.mapDocument().undoStack()
        macroStarted = False
        for i in p:
            object = i[0]
            indexRanges = i[1]
            closed = object.shape() == MapObject.Polygon
            oldPolygon = object.polygon()
            newPolygon = splitPolygonSegments(oldPolygon, indexRanges,
                                                        closed)
            if (newPolygon.size() > oldPolygon.size()):
                if (not macroStarted):
                    undoStack.beginMacro(self.tr("Split Segments"))
                    macroStarted = True

                undoStack.push(ChangePolygon(self.mapDocument(), object, newPolygon, oldPolygon))

        if (macroStarted):
            undoStack.endMacro()

    def setSelectedHandles(self, handles):
        for handle in self.mSelectedHandles:
            if (not handles.contains(handle)):
                handle.setSelected(False)
        for handle in handles:
            if (not self.mSelectedHandles.contains(handle)):
                handle.setSelected(True)
        self.mSelectedHandles = handles

    def setSelectedHandle(self, handle):
        self.setSelectedHandles(QSet([handle]))

    def updateSelection(self, event):
        rect = QRectF(self.mStart, event.scenePos()).normalized()
        # Make sure the rect has some contents, otherwise intersects returns False
        rect.setWidth(max(1.0, rect.width()))
        rect.setHeight(max(1.0, rect.height()))
        oldSelection = self.mapScene().selectedObjectItems()
        if (oldSelection.isEmpty()):
            # Allow selecting some map objects only when there aren't any selected
            selectedItems = QSet()
            for item in self.mapScene().items(rect, Qt.IntersectsItemShape, Qt.DescendingOrder, viewTransform(event)):
                if type(item) == MapObjectItem:
                    selectedItems.insert(item)

            newSelection = QSet()
            if (event.modifiers() & (Qt.ControlModifier | Qt.ShiftModifier)):
                newSelection = oldSelection | selectedItems
            else:
                newSelection = selectedItems

            self.mapScene().setSelectedObjectItems(newSelection)
            self.updateHandles()
        else:
            # Update the selected handles
            selectedHandles = QSet()
            for item in self.mapScene().items(rect, Qt.IntersectsItemShape, Qt.DescendingOrder, viewTransform(event)):
                if type(item) == PointHandle:
                    selectedHandles.insert(item)

            if (event.modifiers() & (Qt.ControlModifier | Qt.ShiftModifier)):
                self.setSelectedHandles(self.mSelectedHandles | selectedHandles)
            else:
                self.setSelectedHandles(selectedHandles)

    def startSelecting(self):
        self.mMode = EditPolygonTool.Selecting
        self.mapScene().addItem(self.mSelectionRectangle)

    def startMoving(self):
        # Move only the clicked handle, if it was not part of the selection
        if (not self.mSelectedHandles.contains(self.mClickedHandle)):
            self.setSelectedHandle(self.mClickedHandle)
        self.mMode = EditPolygonTool.Moving
        renderer = self.mapDocument().renderer()
        # Remember the current object positions
        self.mOldHandlePositions.clear()
        self.mOldPolygons.clear()
        self.mAlignPosition = renderer.screenToPixelCoords_((self.mSelectedHandles.begin()).pos())
        for handle in self.mSelectedHandles:
            pos = renderer.screenToPixelCoords_(handle.pos())
            self.mOldHandlePositions.append(handle.pos())
            if (pos.x() < self.mAlignPosition.x()):
                self.mAlignPosition.setX(pos.x())
            if (pos.y() < self.mAlignPosition.y()):
                self.mAlignPosition.setY(pos.y())
            mapObject = handle.mapObject()
            if (not self.mOldPolygons.contains(mapObject)):
                self.mOldPolygons.insert(mapObject, mapObject.polygon())

    def updateMovingItems(self, pos, modifiers):
        renderer = self.mapDocument().renderer()
        diff = pos - self.mStart
        snapHelper = SnapHelper(renderer, modifiers)
        if (snapHelper.snaps()):
            alignScreenPos = renderer.pixelToScreenCoords_(self.mAlignPosition)
            newAlignScreenPos = alignScreenPos + diff
            newAlignPixelPos = renderer.screenToPixelCoords_(newAlignScreenPos)
            snapHelper.snap(newAlignPixelPos)
            diff = renderer.pixelToScreenCoords_(newAlignPixelPos) - alignScreenPos

        i = 0
        for handle in self.mSelectedHandles:
            # update handle position
            newScreenPos = self.mOldHandlePositions.at(i) + diff
            handle.setPos(newScreenPos)

            # calculate new pixel position of polygon node
            item = handle.mapObjectItem()
            newInternalPos = item.mapFromScene(newScreenPos)
            newScenePos = item.pos() + newInternalPos
            newPixelPos = renderer.screenToPixelCoords_(newScenePos)

            # update the polygon
            mapObject = item.mapObject()
            polygon = mapObject.polygon()
            polygon[handle.pointIndex()] = newPixelPos - mapObject.position()
            self.mapDocument().mapObjectModel().setObjectPolygon(mapObject, polygon)

            i += 1

    def finishMoving(self, pos):
        self.mMode = EditPolygonTool.NoMode
        if (self.mStart == pos or self.mOldPolygons.isEmpty()): # Move is a no-op
            return
        undoStack = self.mapDocument().undoStack()
        undoStack.beginMacro(self.tr("Move %n Point(s)", "", self.mSelectedHandles.size()))
        # TODO: This isn't really optimal. Would be better to have a single undo
        # command that supports changing multiple map objects.
        for i in self.mOldPolygons:
            undoStack.push(ChangePolygon(self.mapDocument(), i[0], i[1]))

        undoStack.endMacro()
        self.mOldHandlePositions.clear()
        self.mOldPolygons.clear()

    def showHandleContextMenu(self, clickedHandle, screenPos):
        if (clickedHandle and not self.mSelectedHandles.contains(clickedHandle)):
            self.setSelectedHandle(clickedHandle)
        n = self.mSelectedHandles.size()
        delIcon = QIcon(":images/16x16/edit-delete.png")
        delText = self.tr("Delete %n Node(s)", "", n)
        menu = QMenu()
        deleteNodesAction = menu.addAction(delIcon, delText)
        joinNodesAction = menu.addAction(self.tr("Join Nodes"))
        splitSegmentsAction = menu.addAction(self.tr("Split Segments"))
        Utils.setThemeIcon(deleteNodesAction, "edit-delete")
        joinNodesAction.setEnabled(n > 1)
        splitSegmentsAction.setEnabled(n > 1)
        deleteNodesAction.triggered.connect(self.deleteNodes)
        joinNodesAction.triggered.connect(self.joinNodes)
        splitSegmentsAction.triggered.connect(self.splitSegments)
        menu.exec(screenPos)
Beispiel #39
0
    def mouseMoveEvent(self, mouseEvent):
        """
        Executed when then mouse is moved on the view.
        :type mouseEvent: QGraphicsSceneMouseEvent
        """
        scene = self.scene()
        mousePos = mouseEvent.pos()
        mouseButtons = mouseEvent.buttons()
        viewport = self.viewport()

        if mouseButtons & Qt.RightButton:

            if (mouseEvent.pos() - self.mousePressPos).manhattanLength() >= QApplication.startDragDistance():

                ########################################################################################################
                #                                                                                                      #
                #                                            SCENE DRAG                                                #
                #                                                                                                      #
                ########################################################################################################

                if scene.mode is not DiagramMode.SceneDrag:
                    scene.setMode(DiagramMode.SceneDrag)
                    viewport.setCursor(Qt.ClosedHandCursor)

                mousePos /= self.zoom
                mousePressPos = self.mousePressPos / self.zoom
                self.centerOn(self.mousePressCenterPos - mousePos + mousePressPos)

        else:

            super().mouseMoveEvent(mouseEvent)

            if mouseButtons & Qt.LeftButton:
                
                self.stopMove()

                if scene.mode is DiagramMode.RubberBandDrag:

                    ####################################################################################################
                    #                                                                                                  #
                    #                                       RUBBERBAND DRAG                                            #
                    #                                                                                                  #
                    ####################################################################################################

                    area = QRectF(self.mapFromScene(self.rubberBandOrigin), mousePos).normalized()
                    path = QPainterPath()
                    path.addRect(area)
                    scene.setSelectionArea(self.mapToScene(path))
                    self.rubberBand.setGeometry(area.toRect())

                if scene.mode in { DiagramMode.BreakPointMove,
                                   DiagramMode.InsertEdge,
                                   DiagramMode.MoveNode,
                                   DiagramMode.ResizeNode,
                                   DiagramMode.RubberBandDrag }:

                    ####################################################################################################
                    #                                                                                                  #
                    #                                      VIEW SCROLLING                                              #
                    #                                                                                                  #
                    ####################################################################################################

                    R = viewport.rect()
                    if not R.contains(mousePos):

                        move = QPointF(0, 0)

                        if mousePos.x() < R.left():
                            move.setX(mousePos.x() - R.left())
                        elif mousePos.x() > R.right():
                            move.setX(mousePos.x() - R.right())

                        if mousePos.y() < R.top():
                            move.setY(mousePos.y() - R.top())
                        elif mousePos.y() > R.bottom():
                            move.setY(mousePos.y() - R.bottom())

                        if move:
                            move.setX(clamp(move.x(), -MainView.MoveBound, +MainView.MoveBound))
                            move.setY(clamp(move.y(), -MainView.MoveBound, +MainView.MoveBound))
                            self.startMove(move, MainView.MoveRate)
class ObjectSelectionTool(AbstractObjectTool):
    def __init__(self, parent = None):
        super().__init__(self.tr("Select Objects"),
              QIcon(":images/22x22/tool-select-objects.png"),
              QKeySequence(self.tr("S")),
              parent)
        self.mSelectionRectangle = SelectionRectangle()
        self.mOriginIndicator = OriginIndicator()
        self.mMousePressed = False
        self.mHoveredObjectItem = None
        self.mClickedObjectItem = None
        self.mClickedRotateHandle = None
        self.mClickedResizeHandle = None
        self.mResizingLimitHorizontal = False
        self.mResizingLimitVertical = False
        self.mMode = Mode.Resize
        self.mAction = Action.NoAction
        self.mRotateHandles = [0, 0, 0, 0]
        self.mResizeHandles = [0, 0, 0, 0, 0, 0, 0, 0]
        self.mAlignPosition = QPointF()
        self.mMovingObjects = QVector()
        self.mScreenStart = QPoint()
        self.mStart = QPointF()
        self.mModifiers = 0
        self.mOrigin = QPointF()

        for i in range(AnchorPosition.CornerAnchorCount):
            self.mRotateHandles[i] = RotateHandle(i)
        for i in range(AnchorPosition.AnchorCount):
            self.mResizeHandles[i] = ResizeHandle(i)

    def __del__(self):
        if self.mSelectionRectangle.scene():
            self.mSelectionRectangle.scene().removeItem(self.mSelectionRectangle)
        if self.mOriginIndicator.scene():
            self.mOriginIndicator.scene().removeItem(self.mOriginIndicator)
        for i in range(AnchorPosition.CornerAnchorCount):
            handle = self.mRotateHandles[i]
            scene = handle.scene()
            if scene:
                scene.removeItem(handle)
        self.mRotateHandles.clear()
        for i in range(AnchorPosition.AnchorCount):
            handle = self.mResizeHandles[i]
            scene = handle.scene()
            if scene:
                scene.removeItem(handle)
        self.mResizeHandles.clear()

    def tr(self, sourceText, disambiguation = '', n = -1):
        return QCoreApplication.translate('ObjectSelectionTool', sourceText, disambiguation, n)

    def activate(self, scene):
        super().activate(scene)
        self.updateHandles()
        self.mapDocument().objectsChanged.connect(self.updateHandles)
        self.mapDocument().mapChanged.connect(self.updateHandles)
        scene.selectedObjectItemsChanged.connect(self.updateHandles)
        self.mapDocument().objectsRemoved.connect(self.objectsRemoved)
        if self.mOriginIndicator.scene() != scene:
            scene.addItem(self.mOriginIndicator)
        for i in range(AnchorPosition.CornerAnchorCount):
            handle = self.mRotateHandles[i]
            if handle.scene() != scene:
                scene.addItem(handle)
        for i in range(AnchorPosition.AnchorCount):
            handle = self.mResizeHandles[i]
            if handle.scene() != scene:
                scene.addItem(handle)

    def deactivate(self, scene):
        if self.mOriginIndicator.scene() == scene:
            scene.removeItem(self.mOriginIndicator)
        for i in range(AnchorPosition.CornerAnchorCount):
            handle = self.mRotateHandles[i]
            if handle.scene() == scene:
                scene.removeItem(handle)
        for i in range(AnchorPosition.AnchorCount):
            handle = self.mResizeHandles[i]
            if handle.scene() == scene:
                scene.removeItem(handle)
        self.mapDocument().objectsChanged.disconnect(self.updateHandles)
        self.mapDocument().mapChanged.disconnect(self.updateHandles)
        scene.selectedObjectItemsChanged.disconnect(self.updateHandles)
        super().deactivate(scene)

    def keyPressed(self, event):
        if (self.mAction != Action.NoAction):
            event.ignore()
            return

        moveBy = QPointF()
        x = event.key()
        if x==Qt.Key_Up:
            moveBy = QPointF(0, -1)
        elif x==Qt.Key_Down:
            moveBy = QPointF(0, 1)
        elif x==Qt.Key_Left:
            moveBy = QPointF(-1, 0)
        elif x==Qt.Key_Right:
            moveBy = QPointF(1, 0)
        else:
            super().keyPressed(event)
            return

        items = self.mapScene().selectedObjectItems()
        modifiers = event.modifiers()
        if (moveBy.isNull() or items.isEmpty() or (modifiers & Qt.ControlModifier)):
            event.ignore()
            return

        moveFast = modifiers & Qt.ShiftModifier
        snapToFineGrid = preferences.Preferences.instance().snapToFineGrid()
        if (moveFast):
            # TODO: This only makes sense for orthogonal maps
            moveBy.setX(moveBy.x() * self.mapDocument().map().tileWidth())
            moveBy.setX(moveBy.y() * self.mapDocument().map().tileHeight())
            if (snapToFineGrid):
                moveBy /= preferences.Preferences.instance().gridFine()

        undoStack = self.mapDocument().undoStack()
        undoStack.beginMacro(self.tr("Move %n Object(s)", "", items.size()))
        i = 0
        for objectItem in items:
            object = objectItem.mapObject()
            oldPos = object.position()
            newPos = oldPos + moveBy
            undoStack.push(MoveMapObject(self.mapDocument(), object, newPos, oldPos))
            i += 1

        undoStack.endMacro()

    def mouseEntered(self):
        pass
        
    def mouseMoved(self, pos, modifiers):
        super().mouseMoved(pos, modifiers)
        
        # Update the hovered item (for mouse cursor)
        hoveredRotateHandle = None
        hoveredResizeHandle = None
        hoveredObjectItem = None
        
        view = self.mapScene().views()[0]
        if view:
            hoveredItem = self.mapScene().itemAt(pos,view.transform())
            hoveredRotateHandle = None
            hoveredResizeHandle = None
            tp = type(hoveredItem)
            if tp==RotateHandle:
                hoveredRotateHandle = hoveredItem
            elif tp==ResizeHandle:
                hoveredResizeHandle = hoveredItem

        if (not hoveredRotateHandle and not hoveredResizeHandle):
            hoveredObjectItem = self.topMostObjectItemAt(pos)

        self.mHoveredObjectItem = hoveredObjectItem
        
        if (self.mAction == Action.NoAction and self.mMousePressed):
            screenPos = QCursor.pos()
            dragDistance = (self.mScreenStart - screenPos).manhattanLength()
            if (dragDistance >= QApplication.startDragDistance()):
                hasSelection = not self.mapScene().selectedObjectItems().isEmpty()
                # Holding Alt forces moving current selection
                # Holding Shift forces selection rectangle
                if ((self.mClickedObjectItem or (modifiers & Qt.AltModifier) and hasSelection) and not (modifiers & Qt.ShiftModifier)):
                    self.startMoving(modifiers)
                elif (self.mClickedRotateHandle):
                    self.startRotating()
                elif (self.mClickedResizeHandle):
                    self.startResizing()
                else:
                    self.startSelecting()

        x = self.mAction
        if x==Action.Selecting:
            self.mSelectionRectangle.setRectangle(QRectF(self.mStart, pos).normalized())
        elif x==Action.Moving:
            self.updateMovingItems(pos, modifiers)
        elif x==Action.Rotating:
            self.updateRotatingItems(pos, modifiers)
        elif x==Action.Resizing:
            self.updateResizingItems(pos, modifiers)
        elif x==Action.NoAction:
            pass
        self.refreshCursor()

    def mousePressed(self, event):
        if (self.mAction != Action.NoAction): # Ignore additional presses during select/move
            return
        x = event.button()
        if x==Qt.LeftButton:
            self.mMousePressed = True
            self.mStart = event.scenePos()
            self.mScreenStart = event.screenPos()
            clickedRotateHandle = 0
            clickedResizeHandle = 0
            view = findView(event)
            if view:
                clickedItem = self.mapScene().itemAt(event.scenePos(), view.transform())
                clickedRotateHandle = None
                clickedResizeHandle = None
                tp = type(clickedItem)
                if tp==RotateHandle:
                    clickedRotateHandle = clickedItem
                elif tp==ResizeHandle:
                    clickedResizeHandle = clickedItem
            self.mClickedRotateHandle = clickedRotateHandle
            self.mClickedResizeHandle = clickedResizeHandle
            if (not clickedRotateHandle and not clickedResizeHandle):
                self.mClickedObjectItem = self.topMostObjectItemAt(self.mStart)
        else:
            super().mousePressed(event)

    def mouseReleased(self, event):
        if (event.button() != Qt.LeftButton):
            return
        x = self.mAction
        if x==Action.NoAction:
            if (not self.mClickedRotateHandle and not self.mClickedResizeHandle):
                # Don't change selection as a result of clicking on a handle
                modifiers = event.modifiers()
                if (self.mClickedObjectItem):
                    selection = self.mapScene().selectedObjectItems()
                    if (modifiers & (Qt.ShiftModifier | Qt.ControlModifier)):
                        if (selection.contains(self.mClickedObjectItem)):
                            selection.remove(self.mClickedObjectItem)
                        else:
                            selection.insert(self.mClickedObjectItem)
                    elif (selection.contains(self.mClickedObjectItem)):
                        # Clicking one of the selected items changes the edit mode
                        if self.mMode == Mode.Resize:
                            _x = Mode.Rotate
                        else:
                            _x = Mode.Resize
                        self.setMode(_x)
                    else:
                        selection.clear()
                        selection.insert(self.mClickedObjectItem)
                        self.setMode(Mode.Resize)
                    self.mapScene().setSelectedObjectItems(selection)
                elif (not (modifiers & Qt.ShiftModifier)):
                    self.mapScene().setSelectedObjectItems(QSet())
        elif x==Action.Selecting:
            self.updateSelection(event.scenePos(), event.modifiers())
            self.mapScene().removeItem(self.mSelectionRectangle)
            self.mAction = Action.NoAction
        elif x==Action.Moving:
            self.finishMoving(event.scenePos())
        elif x==Action.Rotating:
            self.finishRotating(event.scenePos())
        elif x==Action.Resizing:
            self.finishResizing(event.scenePos())

        self.mMousePressed = False
        self.mClickedObjectItem = None
        self.mClickedRotateHandle = None
        self.mClickedResizeHandle = None
        self.refreshCursor()
        
    def modifiersChanged(self, modifiers):
        self.mModifiers = modifiers
        self.refreshCursor()

    def languageChanged(self):
        self.setName(self.tr("Select Objects"))
        self.setShortcut(QKeySequence(self.tr("S")))

    def updateHandles(self):
        if (self.mAction == Action.Moving or self.mAction == Action.Rotating or self.mAction == Action.Resizing):
            return
        objects = self.mapDocument().selectedObjects()
        showHandles = objects.size() > 0
        if (showHandles):
            renderer = self.mapDocument().renderer()
            boundingRect = objectBounds(objects.first(), renderer, objectTransform(objects.first(), renderer))
            for i in range(1, objects.size()):
                object = objects.at(i)
                boundingRect |= objectBounds(object, renderer, objectTransform(object, renderer))

            topLeft = boundingRect.topLeft()
            topRight = boundingRect.topRight()
            bottomLeft = boundingRect.bottomLeft()
            bottomRight = boundingRect.bottomRight()
            center = boundingRect.center()
            handleRotation = 0
            # If there is only one object selected, align to its orientation.
            if (objects.size() == 1):
                object = objects.first()
                handleRotation = object.rotation()
                if (resizeInPixelSpace(object)):
                    bounds = pixelBounds(object)
                    transform = QTransform(objectTransform(object, renderer))
                    topLeft = transform.map(renderer.pixelToScreenCoords_(bounds.topLeft()))
                    topRight = transform.map(renderer.pixelToScreenCoords_(bounds.topRight()))
                    bottomLeft = transform.map(renderer.pixelToScreenCoords_(bounds.bottomLeft()))
                    bottomRight = transform.map(renderer.pixelToScreenCoords_(bounds.bottomRight()))
                    center = transform.map(renderer.pixelToScreenCoords_(bounds.center()))
                    # Ugly hack to make handles appear nicer in this case
                    if (self.mapDocument().map().orientation() == Map.Orientation.Isometric):
                        handleRotation += 45
                else:
                    bounds = objectBounds(object, renderer, QTransform())
                    transform = QTransform(objectTransform(object, renderer))
                    topLeft = transform.map(bounds.topLeft())
                    topRight = transform.map(bounds.topRight())
                    bottomLeft = transform.map(bounds.bottomLeft())
                    bottomRight = transform.map(bounds.bottomRight())
                    center = transform.map(bounds.center())

            self.mOriginIndicator.setPos(center)
            self.mRotateHandles[AnchorPosition.TopLeftAnchor].setPos(topLeft)
            self.mRotateHandles[AnchorPosition.TopRightAnchor].setPos(topRight)
            self.mRotateHandles[AnchorPosition.BottomLeftAnchor].setPos(bottomLeft)
            self.mRotateHandles[AnchorPosition.BottomRightAnchor].setPos(bottomRight)
            top = (topLeft + topRight) / 2
            left = (topLeft + bottomLeft) / 2
            right = (topRight + bottomRight) / 2
            bottom = (bottomLeft + bottomRight) / 2
            self.mResizeHandles[AnchorPosition.TopAnchor].setPos(top)
            self.mResizeHandles[AnchorPosition.TopAnchor].setResizingOrigin(bottom)
            self.mResizeHandles[AnchorPosition.LeftAnchor].setPos(left)
            self.mResizeHandles[AnchorPosition.LeftAnchor].setResizingOrigin(right)
            self.mResizeHandles[AnchorPosition.RightAnchor].setPos(right)
            self.mResizeHandles[AnchorPosition.RightAnchor].setResizingOrigin(left)
            self.mResizeHandles[AnchorPosition.BottomAnchor].setPos(bottom)
            self.mResizeHandles[AnchorPosition.BottomAnchor].setResizingOrigin(top)
            self.mResizeHandles[AnchorPosition.TopLeftAnchor].setPos(topLeft)
            self.mResizeHandles[AnchorPosition.TopLeftAnchor].setResizingOrigin(bottomRight)
            self.mResizeHandles[AnchorPosition.TopRightAnchor].setPos(topRight)
            self.mResizeHandles[AnchorPosition.TopRightAnchor].setResizingOrigin(bottomLeft)
            self.mResizeHandles[AnchorPosition.BottomLeftAnchor].setPos(bottomLeft)
            self.mResizeHandles[AnchorPosition.BottomLeftAnchor].setResizingOrigin(topRight)
            self.mResizeHandles[AnchorPosition.BottomRightAnchor].setPos(bottomRight)
            self.mResizeHandles[AnchorPosition.BottomRightAnchor].setResizingOrigin(topLeft)
            for i in range(AnchorPosition.CornerAnchorCount):
                self.mRotateHandles[i].setRotation(handleRotation)
            for i in range(AnchorPosition.AnchorCount):
                self.mResizeHandles[i].setRotation(handleRotation)

        self.updateHandleVisibility()

    def updateHandleVisibility(self):
        hasSelection = not self.mapDocument().selectedObjects().isEmpty()
        showHandles = hasSelection and (self.mAction == Action.NoAction or self.mAction == Action.Selecting)
        showOrigin = hasSelection and self.mAction != Action.Moving and (self.mMode == Mode.Rotate or self.mAction == Action.Resizing)
        for i in range(AnchorPosition.CornerAnchorCount):
            self.mRotateHandles[i].setVisible(showHandles and self.mMode == Mode.Rotate)
        for i in range(AnchorPosition.AnchorCount):
            self.mResizeHandles[i].setVisible(showHandles and self.mMode == Mode.Resize)
        self.mOriginIndicator.setVisible(showOrigin)

    def objectsRemoved(self, objects):
        if (self.mAction != Action.Moving and self.mAction != Action.Rotating and self.mAction != Action.Resizing):
            return
        # Abort move/rotate/resize to avoid crashing...
        # TODO: This should really not be allowed to happen in the first place.
        # since it breaks the undo history, for example.
        for i in range(self.mMovingObjects.size() - 1, -1, -1):
            object = self.mMovingObjects[i]
            mapObject = object.item.mapObject()
            if objects.contains(mapObject):
                # Avoid referencing the removed object
                self.mMovingObjects.remove(i)
            else:
                mapObject.setPosition(object.oldPosition)
                mapObject.setSize(object.oldSize)
                mapObject.setPolygon(object.oldPolygon)
                mapObject.setRotation(object.oldRotation)
        
        self.mapDocument().mapObjectModel().emitObjectsChanged(self.changingObjects)
        self.mMovingObjects.clear()

    def updateSelection(self, pos, modifiers):
        rect = QRectF(self.mStart, pos).normalized()
        # Make sure the rect has some contents, otherwise intersects returns False
        rect.setWidth(max(1.0, rect.width()))
        rect.setHeight(max(1.0, rect.height()))
        selectedItems = QSet()
        for item in self.mapScene().items(rect):
            if type(item) == MapObjectItem:
                selectedItems.insert(item)

        if (modifiers & (Qt.ControlModifier | Qt.ShiftModifier)):
            selectedItems |= self.mapScene().selectedObjectItems()
        else:
            self.setMode(Mode.Resize)
        self.mapScene().setSelectedObjectItems(selectedItems)

    def startSelecting(self):
        self.mAction = Action.Selecting
        self.mapScene().addItem(self.mSelectionRectangle)

    def startMoving(self, modifiers):
        # Move only the clicked item, if it was not part of the selection
        if (self.mClickedObjectItem and not (modifiers & Qt.AltModifier)):
            if (not self.mapScene().selectedObjectItems().contains(self.mClickedObjectItem)):
                self.mapScene().setSelectedObjectItems(QSet([self.mClickedObjectItem]))

        self.saveSelectionState()
        self.mAction = Action.Moving
        self.mAlignPosition = self.mMovingObjects[0].oldPosition
        for object in self.mMovingObjects:
            pos = object.oldPosition
            if (pos.x() < self.mAlignPosition.x()):
                self.mAlignPosition.setX(pos.x())
            if (pos.y() < self.mAlignPosition.y()):
                self.mAlignPosition.setY(pos.y())

        self.updateHandleVisibility()

    def updateMovingItems(self, pos, modifiers):
        renderer = self.mapDocument().renderer()

        diff = self.snapToGrid(pos-self.mStart, modifiers)
        for object in self.mMovingObjects:
            newPixelPos = object.oldItemPosition + diff
            newPos = renderer.screenToPixelCoords_(newPixelPos)

            mapObject = object.item.mapObject()
            mapObject.setPosition(newPos)
        self.mapDocument().mapObjectModel().emitObjectsChanged(self.changingObjects())
        
    def finishMoving(self, pos):
        self.mAction = Action.NoAction
        self.updateHandles()
        if (self.mStart == pos): # Move is a no-op
            return
        undoStack = self.mapDocument().undoStack()
        undoStack.beginMacro(self.tr("Move %n Object(s)", "", self.mMovingObjects.size()))
        for object in self.mMovingObjects:
            undoStack.push(MoveMapObject(self.mapDocument(), object.item.mapObject(), object.oldPosition))

        undoStack.endMacro()
        self.mMovingObjects.clear()

    def startRotating(self):
        self.mAction = Action.Rotating
        self.mOrigin = self.mOriginIndicator.pos()
        self.saveSelectionState()
        self.updateHandleVisibility()

    def updateRotatingItems(self, pos, modifiers):
        renderer = self.mapDocument().renderer()
        startDiff = self.mOrigin - self.mStart
        currentDiff = self.mOrigin - pos
        startAngle = math.atan2(startDiff.y(), startDiff.x())
        currentAngle = math.atan2(currentDiff.y(), currentDiff.x())
        angleDiff = currentAngle - startAngle
        snap = 15 * M_PI / 180 # 15 degrees in radians
        if (modifiers & Qt.ControlModifier):
            angleDiff = math.floor((angleDiff + snap / 2) / snap) * snap
        for object in self.mMovingObjects:
            mapObject = object.item.mapObject()
            offset = mapObject.objectGroup().offset()
        
            oldRelPos = object.oldItemPosition + offset - self.mOrigin
            sn = math.sin(angleDiff)
            cs = math.cos(angleDiff)
            newRelPos = QPointF(oldRelPos.x() * cs - oldRelPos.y() * sn, oldRelPos.x() * sn + oldRelPos.y() * cs)
            newPixelPos = self.mOrigin + newRelPos - offset
            newPos = renderer.screenToPixelCoords_(newPixelPos)
            newRotation = object.oldRotation + angleDiff * 180 / M_PI
            mapObject.setPosition(newPos)
            mapObject.setRotation(newRotation)
        
        self.mapDocument().mapObjectModel().emitObjectsChanged(self.changingObjects())
        
    def finishRotating(self, pos):
        self.mAction = Action.NoAction
        self.updateHandles()
        if (self.mStart == pos): # No rotation at all
            return
        undoStack = self.mapDocument().undoStack()
        undoStack.beginMacro(self.tr("Rotate %n Object(s)", "", self.mMovingObjects.size()))
        for object in self.mMovingObjects:
            mapObject = object.item.mapObject()
            undoStack.push(MoveMapObject(self.mapDocument(), mapObject, object.oldPosition))
            undoStack.push(RotateMapObject(self.mapDocument(), mapObject, object.oldRotation))

        undoStack.endMacro()
        self.mMovingObjects.clear()

    def startResizing(self):
        self.mAction = Action.Resizing
        self.mOrigin = self.mOriginIndicator.pos()
        self.mResizingLimitHorizontal = self.mClickedResizeHandle.resizingLimitHorizontal()
        self.mResizingLimitVertical = self.mClickedResizeHandle.resizingLimitVertical()
        self.mStart = self.mClickedResizeHandle.pos()
        self.saveSelectionState()
        self.updateHandleVisibility()

    def updateResizingItems(self, pos, modifiers):
        renderer = self.mapDocument().renderer()
        resizingOrigin = self.mClickedResizeHandle.resizingOrigin()
        if (modifiers & Qt.ShiftModifier):
            resizingOrigin = self.mOrigin
        self.mOriginIndicator.setPos(resizingOrigin)
        ## Alternative toggle snap modifier, since Control is taken by the preserve
        # aspect ratio option.
        ##
        snapHelper = SnapHelper(renderer)
        if (modifiers & Qt.AltModifier):
            snapHelper.toggleSnap()
        pixelPos = renderer.screenToPixelCoords_(pos)
        snapHelper.snap(pixelPos)
        snappedScreenPos = renderer.pixelToScreenCoords_(pixelPos)
        diff = snappedScreenPos - resizingOrigin
        startDiff = self.mStart - resizingOrigin
        if (self.mMovingObjects.size() == 1):
            ## For single items the resizing is performed in object space in order
            # to handle different scaling on X and Y axis as well as to improve
            # handling of 0-sized objects.
            ##
            self.updateResizingSingleItem(resizingOrigin, snappedScreenPos, modifiers)
            return

        ## Calculate the scaling factor. Minimum is 1% to protect against making
        # everything 0-sized and non-recoverable (it's still possibly to run into
        # problems by repeatedly scaling down to 1%, but that's asking for it)
        ##
        scale = 0.0
        if (self.mResizingLimitHorizontal):
            scale = max(0.01, diff.y() / startDiff.y())
        elif (self.mResizingLimitVertical):
            scale = max(0.01, diff.x() / startDiff.x())
        else:
            scale = min(max(0.01, diff.x() / startDiff.x()),
                         max(0.01, diff.y() / startDiff.y()))

        if not math.isfinite(scale):
            scale = 1
        
        for object in self.mMovingObjects:
            mapObject = object.item.mapObject()
            offset = mapObject.objectGroup().offset()
        
            oldRelPos = object.oldItemPosition + offset - resizingOrigin
            scaledRelPos = QPointF(oldRelPos.x() * scale, oldRelPos.y() * scale)
            newScreenPos = resizingOrigin + scaledRelPos - offset
            newPos = renderer.screenToPixelCoords_(newScreenPos)
            origSize = object.oldSize
            newSize = QSizeF(origSize.width() * scale, origSize.height() * scale)
            if (mapObject.polygon().isEmpty() == False):
                # For polygons, we have to scale in object space.
                rotation = object.item.rotation() * M_PI / -180
                sn = math.sin(rotation)
                cs = math.cos(rotation)
                oldPolygon = object.oldPolygon
                newPolygon = QPolygonF(oldPolygon.size())
                for n in range(oldPolygon.size()):
                    oldPoint = QPointF(oldPolygon[n])
                    rotPoint = QPointF(oldPoint.x() * cs + oldPoint.y() * sn, oldPoint.y() * cs - oldPoint.x() * sn)
                    scaledPoint = QPointF(rotPoint.x() * scale, rotPoint.y() * scale)
                    newPoint = QPointF(scaledPoint.x() * cs - scaledPoint.y() * sn, scaledPoint.y() * cs + scaledPoint.x() * sn)
                    newPolygon[n] = newPoint

                mapObject.setPolygon(newPolygon)

            mapObject.setSize(newSize)
            mapObject.setPosition(newPos)
        
        self.mapDocument().mapObjectModel().emitObjectsChanged(self.changingObjects())
        
    def updateResizingSingleItem(self, resizingOrigin, screenPos, modifiers):
        renderer = self.mapDocument().renderer()
        object = self.mMovingObjects.first()
        mapObject = object.item.mapObject()
        
        ## The resizingOrigin, screenPos and mStart are affected by the ObjectGroup
        # offset. We will un-apply it to these variables since the resize for
        # single items happens in local coordinate space.
        ##
        offset = mapObject.objectGroup().offset()
    
        ## These transformations undo and redo the object rotation, which is always
        # applied in screen space.
        ##
        unrotate = rotateAt(object.oldItemPosition, -object.oldRotation)
        rotate = rotateAt(object.oldItemPosition, object.oldRotation)
        origin = (resizingOrigin - offset) * unrotate
        pos = (screenPos - offset) * unrotate
        start = (self.mStart - offset) * unrotate
        oldPos = object.oldItemPosition
        ## In order for the resizing to work somewhat sanely in isometric mode,
        # the resizing is performed in pixel space except for tile objects, which
        # are not affected by isometric projection apart from their position.
        ##
        pixelSpace = resizeInPixelSpace(mapObject)
        preserveAspect = modifiers & Qt.ControlModifier
        if (pixelSpace):
            origin = renderer.screenToPixelCoords_(origin)
            pos = renderer.screenToPixelCoords_(pos)
            start = renderer.screenToPixelCoords_(start)
            oldPos = object.oldPosition

        newPos = oldPos
        newSize = object.oldSize
        ## In case one of the anchors was used as-is, the desired size can be
        # derived directly from the distance from the origin for rectangle
        # and ellipse objects. This allows scaling up a 0-sized object without
        # dealing with infinite scaling factor issues.
        #
        # For obvious reasons this can't work on polygons or polylines, nor when
        # preserving the aspect ratio.
        ##
        if (self.mClickedResizeHandle.resizingOrigin() == resizingOrigin and (mapObject.shape() == MapObject.Rectangle or
                 mapObject.shape() == MapObject.Ellipse) and not preserveAspect):
            newBounds = QRectF(newPos, newSize)
            newBounds = align(newBounds, mapObject.alignment())
            x = self.mClickedResizeHandle.anchorPosition()
            if x==AnchorPosition.LeftAnchor or x==AnchorPosition.TopLeftAnchor or x==AnchorPosition.BottomLeftAnchor:
                newBounds.setLeft(min(pos.x(), origin.x()))
            elif x==AnchorPosition.RightAnchor or x==AnchorPosition.TopRightAnchor or x==AnchorPosition.BottomRightAnchor:
                newBounds.setRight(max(pos.x(), origin.x()))
            else:
                # nothing to do on this axis
                pass

            x = self.mClickedResizeHandle.anchorPosition()
            if x==AnchorPosition.TopAnchor or x==AnchorPosition.TopLeftAnchor or x==AnchorPosition.TopRightAnchor:
                newBounds.setTop(min(pos.y(), origin.y()))
            elif x==AnchorPosition.BottomAnchor or x==AnchorPosition.BottomLeftAnchor or x==AnchorPosition.BottomRightAnchor:
                newBounds.setBottom(max(pos.y(), origin.y()))
            else:
                # nothing to do on this axis
                pass

            newBounds = unalign(newBounds, mapObject.alignment())
            newSize = newBounds.size()
            newPos = newBounds.topLeft()
        else:
            relPos = pos - origin
            startDiff = start - origin
            try:
                newx = relPos.x() / startDiff.x()
            except:
                newx = 0
            try:
                newy = relPos.y() / startDiff.y()
            except:
                newy = 0
            scalingFactor = QSizeF(max(0.01, newx), max(0.01, newy))
            if not math.isfinite(scalingFactor.width()):
                scalingFactor.setWidth(1)
            if not math.isfinite(scalingFactor.height()):
                scalingFactor.setHeight(1)
            
            if (self.mResizingLimitHorizontal):
                if preserveAspect:
                    scalingFactor.setWidth(scalingFactor.height())
                else:
                    scalingFactor.setWidth(1)
            elif (self.mResizingLimitVertical):
                if preserveAspect:
                    scalingFactor.setHeight(scalingFactor.width())
                else:
                    scalingFactor.setHeight(1)
            elif (preserveAspect):
                scale = min(scalingFactor.width(), scalingFactor.height())
                scalingFactor.setWidth(scale)
                scalingFactor.setHeight(scale)

            oldRelPos = oldPos - origin
            newPos = origin + QPointF(oldRelPos.x() * scalingFactor.width(), oldRelPos.y() * scalingFactor.height())
            newSize.setWidth(newSize.width() * scalingFactor.width())
            newSize.setHeight(newSize.height() * scalingFactor.height())
            if (not object.oldPolygon.isEmpty()):
                newPolygon = QPolygonF(object.oldPolygon.size())
                for n in range(object.oldPolygon.size()):
                    point = object.oldPolygon[n]
                    newPolygon[n] = QPointF(point.x() * scalingFactor.width(), point.y() * scalingFactor.height())

                mapObject.setPolygon(newPolygon)

        if (pixelSpace):
            newPos = renderer.pixelToScreenCoords_(newPos)
        newPos = renderer.screenToPixelCoords_(newPos * rotate)
        mapObject.setSize(newSize)
        mapObject.setPosition(newPos)
        self.mapDocument().mapObjectModel().emitObjectsChanged(self.changingObjects())
        
    def finishResizing(self, pos):
        self.mAction = Action.NoAction
        self.updateHandles()
        if (self.mStart == pos): # No scaling at all
            return
        undoStack = self.mapDocument().undoStack()
        undoStack.beginMacro(self.tr("Resize %n Object(s)", "", self.mMovingObjects.size()))
        for object in self.mMovingObjects:
            mapObject = object.item.mapObject()
            undoStack.push(MoveMapObject(self.mapDocument(), mapObject, object.oldPosition))
            undoStack.push(ResizeMapObject(self.mapDocument(), mapObject, object.oldSize))
            if (not object.oldPolygon.isEmpty()):
                undoStack.push(ChangePolygon(self.mapDocument(), mapObject, object.oldPolygon))

        undoStack.endMacro()
        self.mMovingObjects.clear()

    def setMode(self, mode):
        if (self.mMode != mode):
            self.mMode = mode
            self.updateHandles()

    def saveSelectionState(self):
        self.mMovingObjects.clear()
        # Remember the initial state before moving, resizing or rotating
        for item in self.mapScene().selectedObjectItems():
            mapObject = item.mapObject()
            object = MovingObject()
            object.item = item
            object.oldItemPosition = item.pos()
            object.oldPosition = mapObject.position()
            object.oldSize = mapObject.size()
            object.oldPolygon = mapObject.polygon()
            object.oldRotation = mapObject.rotation()

            self.mMovingObjects.append(object)

    def refreshCursor(self):
        cursorShape = Qt.ArrowCursor

        if self.mAction == Action.NoAction:
            hasSelection = not self.mapScene().selectedObjectItems().isEmpty()

            if ((self.mHoveredObjectItem or ((self.mModifiers & Qt.AltModifier) and hasSelection)) and not (self.mModifiers & Qt.ShiftModifier)):
                cursorShape = Qt.SizeAllCursor
        elif self.mAction == Action.Moving:
            cursorShape = Qt.SizeAllCursor

        if self.cursor.shape != cursorShape:
            self.setCursor(cursorShape)

    def snapToGrid(self, diff, modifiers):
        renderer = self.mapDocument().renderer()
        snapHelper = SnapHelper(renderer, modifiers)
        if (snapHelper.snaps()):
            alignScreenPos = renderer.pixelToScreenCoords_(self.mAlignPosition)
            newAlignScreenPos = alignScreenPos + diff
            newAlignPixelPos = renderer.screenToPixelCoords_(newAlignScreenPos)
            snapHelper.snap(newAlignPixelPos)
            return renderer.pixelToScreenCoords_(newAlignPixelPos) - alignScreenPos

        return diff

    def changingObjects(self):
        changingObjects = QList()
        
        for movingObject in self.mMovingObjects:
            changingObjects.append(movingObject.item.mapObject())

        return changingObjects
Beispiel #41
0
    def updateFloatPath(self, point=None):
        """
        Draws a quad curve from the edge of the fromBase
        to the top or bottom of the toBase (q5), and
        finally to the center of the toBase (toBaseEndpoint).

        If floatPos!=None, this is a floatingXover and floatPos is the
        destination point (where the mouse is) while toHelix, toIndex
        are potentially None and represent the base at floatPos.

        Args:
            point (None, optional): Description

        """
        node3 = self._node3
        node5 = self._node5

        bw = _BASE_WIDTH

        vhi5 = self._virtual_helix_item
        nucleicacid_part_item = vhi5.partItem()
        pt5 = vhi5.mapToItem(nucleicacid_part_item, *node5.floatPoint())

        n5_is_forward = node5.is_forward

        # Enter/exit are relative to the direction that the path travels
        # overall.
        five_enter_pt = pt5 + QPointF(0 if n5_is_forward else 1, .5)*bw
        five_center_pt = pt5 + QPointF(.5, .5)*bw
        five_exit_pt = pt5 + QPointF(.5, 0 if n5_is_forward else 1)*bw

        vhi3 = node3.virtualHelixItem()

        if point:
            pt3 = point
            n3_is_forward = True
            same_strand = False
            same_parity = False
            three_enter_pt = three_center_pt = three_exit_pt = pt3
        else:
            pt3 = vhi3.mapToItem(nucleicacid_part_item, *node3.point())
            n3_is_forward = node3.is_forward
            same_strand = (n5_is_forward == n3_is_forward) and vhi3 == vhi5
            same_parity = n5_is_forward == n3_is_forward

            three_enter_pt = pt3 + QPointF(.5, 0 if n3_is_forward else 1)*bw
            three_center_pt = pt3 + QPointF(.5, .5)*bw
            three_exit_pt = pt3 + QPointF(1 if n3_is_forward else 0, .5)*bw

        c1 = QPointF()
        # case 1: same strand
        if same_strand:
            dx = abs(three_enter_pt.x() - five_exit_pt.x())
            c1.setX(0.5 * (five_exit_pt.x() + three_enter_pt.x()))
            if n5_is_forward:
                c1.setY(five_exit_pt.y() - _yScale * dx)
            else:
                c1.setY(five_exit_pt.y() + _yScale * dx)
            # case 2: same parity
        elif same_parity:
            dy = abs(three_enter_pt.y() - five_exit_pt.y())
            c1.setX(five_exit_pt.x() + _xScale * dy)
            c1.setY(0.5 * (five_exit_pt.y() + three_enter_pt.y()))
        # case 3: different parity
        else:
            if n5_is_forward:
                c1.setX(five_exit_pt.x() - _xScale *
                        abs(three_enter_pt.y() - five_exit_pt.y()))
            else:
                c1.setX(five_exit_pt.x() + _xScale *
                        abs(three_enter_pt.y() - five_exit_pt.y()))
            c1.setY(0.5 * (five_exit_pt.y() + three_enter_pt.y()))

        # Construct painter path
        painterpath = QPainterPath()
        painterpath.moveTo(five_enter_pt)
        painterpath.lineTo(five_center_pt)
        painterpath.lineTo(five_exit_pt)
        painterpath.quadTo(c1, three_enter_pt)
        painterpath.lineTo(three_center_pt)
        painterpath.lineTo(three_exit_pt)

        self.setPath(painterpath)
        self._updateFloatPen()
Beispiel #42
0
    def _updatePath(self, strand5p):
        """
        Draws a quad curve from the edge of the fromBase
        to the top or bottom of the toBase (q5), and
        finally to the center of the toBase (toBaseEndpoint).

        If floatPos!=None, this is a floatingXover and floatPos is the
        destination point (where the mouse is) while toHelix, toIndex
        are potentially None and represent the base at floatPos.

        """
        group = self.group()
        self.tempReparent()

        node3 = self._node3
        node5 = self._node5

        bw = _BASE_WIDTH

        parent = self.partItem()

        vhi5 = self._virtual_helix_item
        pt5 = vhi5.mapToItem(parent, *node5.point())

        five_is_top = node5.isOnTop()
        five_is_5to3 = node5.isDrawn5to3()

        vhi3 = node3.virtualHelixItem()
        pt3 = vhi3.mapToItem(parent, *node3.point())

        three_is_top = node3.isOnTop()
        three_is_5to3 = node3.isDrawn5to3()
        same_strand = (node5.strandType() == node3.strandType()) and vhi3 == vhi5
        same_parity = five_is_5to3 == three_is_5to3

        # Enter/exit are relative to the direction that the path travels
        # overall.
        five_enter_pt = pt5 + QPointF(0 if five_is_5to3 else 1, 0.5) * bw
        five_center_pt = pt5 + QPointF(0.5, 0.5) * bw
        five_exit_pt = pt5 + QPointF(0.5, 0 if five_is_top else 1) * bw

        three_enter_pt = pt3 + QPointF(0.5, 0 if three_is_top else 1) * bw
        three_center_pt = pt3 + QPointF(0.5, 0.5) * bw
        three_exit_pt = pt3 + QPointF(1 if three_is_5to3 else 0, 0.5) * bw

        c1 = QPointF()
        # case 1: same strand
        if same_strand:
            dx = abs(three_enter_pt.x() - five_exit_pt.x())
            c1.setX(0.5 * (five_exit_pt.x() + three_enter_pt.x()))
            if five_is_top:
                c1.setY(five_exit_pt.y() - _Y_SCALE * dx)
            else:
                c1.setY(five_exit_pt.y() + _Y_SCALE * dx)
        # case 2: same parity
        elif same_parity:
            dy = abs(three_enter_pt.y() - five_exit_pt.y())
            c1.setX(five_exit_pt.x() + _X_SCALE * dy)
            c1.setY(0.5 * (five_exit_pt.y() + three_enter_pt.y()))
        # case 3: different parity
        else:
            if five_is_top and five_is_5to3:
                c1.setX(five_exit_pt.x() - _X_SCALE * abs(three_enter_pt.y() - five_exit_pt.y()))
            else:
                c1.setX(five_exit_pt.x() + _X_SCALE * abs(three_enter_pt.y() - five_exit_pt.y()))
            c1.setY(0.5 * (five_exit_pt.y() + three_enter_pt.y()))

        # Construct painter path
        painterpath = QPainterPath()
        painterpath.moveTo(five_enter_pt)
        painterpath.lineTo(five_center_pt)
        painterpath.lineTo(five_exit_pt)

        # The xover5's non-crossing-over end (3') has a connection
        painterpath.quadTo(c1, three_enter_pt)
        painterpath.lineTo(three_center_pt)
        painterpath.lineTo(three_exit_pt)

        tempR = painterpath.boundingRect()
        tempR.adjust(-bw / 2, 0, bw, 0)
        self._click_area.setRect(tempR)
        self.setPath(painterpath)
        node3.updatePositionAndAppearance()
        node5.updatePositionAndAppearance()

        if group:
            group.addToGroup(self)

        self._updateColor(strand5p)
Beispiel #43
0
    def interactiveResize(self, mousePos):
        """
        Handle the interactive resize of the shape.
        :type mousePos: QPointF
        """
        scene = self.scene()
        snap = scene.mainwindow.snapToGrid
        size = scene.GridSize
        offset = self.handleSize + self.handleMove
        moved = self.label.moved

        R = QRectF(self.boundingRect())
        D = QPointF(0, 0)

        minBoundW = self.minwidth + offset * 2
        minBoundH = self.minheight + offset * 2

        self.prepareGeometryChange()

        if self.mousePressHandle == self.handleTL:

            fromX = self.mousePressBound.left()
            fromY = self.mousePressBound.top()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            toX = snapF(toX, size, -offset, snap)
            toY = snapF(toY, size, -offset, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setLeft(toX)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.width() < minBoundW:
                D.setX(D.x() - minBoundW + R.width())
                R.setLeft(R.left() - minBoundW + R.width())
            if R.height() < minBoundH:
                D.setY(D.y() - minBoundH + R.height())
                R.setTop(R.top() - minBoundH + R.height())

            self.background.setLeft(R.left())
            self.background.setTop(R.top())
            self.selection.setLeft(R.left())
            self.selection.setTop(R.top())
            self.polygon.setLeft(R.left() + offset)
            self.polygon.setTop(R.top() + offset)

        elif self.mousePressHandle == self.handleTM:

            fromY = self.mousePressBound.top()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            toY = snapF(toY, size, -offset, snap)
            D.setY(toY - fromY)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.height() < minBoundH:
                D.setY(D.y() - minBoundH + R.height())
                R.setTop(R.top() - minBoundH + R.height())

            self.background.setTop(R.top())
            self.selection.setTop(R.top())
            self.polygon.setTop(R.top() + offset)

        elif self.mousePressHandle == self.handleTR:

            fromX = self.mousePressBound.right()
            fromY = self.mousePressBound.top()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            toX = snapF(toX, size, +offset, snap)
            toY = snapF(toY, size, -offset, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setRight(toX)
            R.setTop(toY)

             ## CLAMP SIZE
            if R.width() < minBoundW:
                D.setX(D.x() + minBoundW - R.width())
                R.setRight(R.right() + minBoundW - R.width())
            if R.height() < minBoundH:
                D.setY(D.y() - minBoundH + R.height())
                R.setTop(R.top() - minBoundH + R.height())

            self.background.setRight(R.right())
            self.background.setTop(R.top())
            self.selection.setRight(R.right())
            self.selection.setTop(R.top())
            self.polygon.setRight(R.right() - offset)
            self.polygon.setTop(R.top() + offset)

        elif self.mousePressHandle == self.handleML:

            fromX = self.mousePressBound.left()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toX = snapF(toX, size, -offset, snap)
            D.setX(toX - fromX)
            R.setLeft(toX)

             ## CLAMP SIZE
            if R.width() < minBoundW:
                D.setX(D.x() - minBoundW + R.width())
                R.setLeft(R.left() - minBoundW + R.width())

            self.background.setLeft(R.left())
            self.selection.setLeft(R.left())
            self.polygon.setLeft(R.left() + offset)

        elif self.mousePressHandle == self.handleMR:

            fromX = self.mousePressBound.right()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toX = snapF(toX, size, +offset, snap)
            D.setX(toX - fromX)
            R.setRight(toX)

            ## CLAMP SIZE
            if R.width() < minBoundW:
                D.setX(D.x() + minBoundW - R.width())
                R.setRight(R.right() + minBoundW - R.width())

            self.background.setRight(R.right())
            self.selection.setRight(R.right())
            self.polygon.setRight(R.right() - offset)

        elif self.mousePressHandle == self.handleBL:

            fromX = self.mousePressBound.left()
            fromY = self.mousePressBound.bottom()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            toX = snapF(toX, size, -offset, snap)
            toY = snapF(toY, size, +offset, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setLeft(toX)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.width() < minBoundW:
                D.setX(D.x() - minBoundW + R.width())
                R.setLeft(R.left() - minBoundW + R.width())
            if R.height() < minBoundH:
                D.setY(D.y() + minBoundH - R.height())
                R.setBottom(R.bottom() + minBoundH - R.height())

            self.background.setLeft(R.left())
            self.background.setBottom(R.bottom())
            self.selection.setLeft(R.left())
            self.selection.setBottom(R.bottom())
            self.polygon.setLeft(R.left() + offset)
            self.polygon.setBottom(R.bottom() - offset)

        elif self.mousePressHandle == self.handleBM:

            fromY = self.mousePressBound.bottom()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            toY = snapF(toY, size, +offset, snap)
            D.setY(toY - fromY)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.height() < minBoundH:
                D.setY(D.y() + minBoundH - R.height())
                R.setBottom(R.bottom() + minBoundH - R.height())

            self.background.setBottom(R.bottom())
            self.selection.setBottom(R.bottom())
            self.polygon.setBottom(R.bottom() - offset)

        elif self.mousePressHandle == self.handleBR:

            fromX = self.mousePressBound.right()
            fromY = self.mousePressBound.bottom()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            toX = snapF(toX, size, +offset, snap)
            toY = snapF(toY, size, +offset, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setRight(toX)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.width() < minBoundW:
                D.setX(D.x() + minBoundW - R.width())
                R.setRight(R.right() + minBoundW - R.width())
            if R.height() < minBoundH:
                D.setY(D.y() + minBoundH - R.height())
                R.setBottom(R.bottom() + minBoundH - R.height())

            self.background.setRight(R.right())
            self.background.setBottom(R.bottom())
            self.selection.setRight(R.right())
            self.selection.setBottom(R.bottom())
            self.polygon.setRight(R.right() - offset)
            self.polygon.setBottom(R.bottom() - offset)

        self.updateHandles()
        self.updateTextPos(moved=moved)
        self.updateAnchors(self.mousePressData, D)
Beispiel #44
0
class PixmapDial(QDial):
    # enum CustomPaintMode
    CUSTOM_PAINT_MODE_NULL        = 0 # default (NOTE: only this mode has label gradient)
    CUSTOM_PAINT_MODE_CARLA_WET   = 1 # color blue-green gradient (reserved #3)
    CUSTOM_PAINT_MODE_CARLA_VOL   = 2 # color blue (reserved #3)
    CUSTOM_PAINT_MODE_CARLA_L     = 3 # color yellow (reserved #4)
    CUSTOM_PAINT_MODE_CARLA_R     = 4 # color yellow (reserved #4)
    CUSTOM_PAINT_MODE_CARLA_PAN   = 5 # color yellow (reserved #3)
    CUSTOM_PAINT_MODE_COLOR       = 6 # color, selectable (reserved #3)
    CUSTOM_PAINT_MODE_ZITA        = 7 # custom zita knob (reserved #6)
    CUSTOM_PAINT_MODE_NO_GRADIENT = 8 # skip label gradient

    # enum Orientation
    HORIZONTAL = 0
    VERTICAL   = 1

    HOVER_MIN = 0
    HOVER_MAX = 9

    MODE_DEFAULT = 0
    MODE_LINEAR = 1

    # signals
    realValueChanged = pyqtSignal(float)

    def __init__(self, parent, index=0):
        QDial.__init__(self, parent)

        self.fDialMode = self.MODE_LINEAR

        self.fMinimum   = 0.0
        self.fMaximum   = 1.0
        self.fRealValue = 0.0
        self.fPrecision = 10000
        self.fIsInteger = False

        self.fIsHovered = False
        self.fIsPressed = False
        self.fHoverStep = self.HOVER_MIN

        self.fLastDragPos = None
        self.fLastDragValue = 0.0

        self.fIndex     = index
        self.fPixmap    = QPixmap(":/bitmaps/dial_01d.png")
        self.fPixmapNum = "01"

        if self.fPixmap.width() > self.fPixmap.height():
            self.fPixmapOrientation = self.HORIZONTAL
        else:
            self.fPixmapOrientation = self.VERTICAL

        self.fLabel     = ""
        self.fLabelPos  = QPointF(0.0, 0.0)
        self.fLabelFont = QFont(self.font())
        self.fLabelFont.setPixelSize(8)
        self.fLabelWidth  = 0
        self.fLabelHeight = 0

        if self.palette().window().color().lightness() > 100:
            # Light background
            c = self.palette().dark().color()
            self.fLabelGradientColor1 = c
            self.fLabelGradientColor2 = QColor(c.red(), c.green(), c.blue(), 0)
            self.fLabelGradientColorT = [self.palette().buttonText().color(), self.palette().mid().color()]
        else:
            # Dark background
            self.fLabelGradientColor1 = QColor(0, 0, 0, 255)
            self.fLabelGradientColor2 = QColor(0, 0, 0, 0)
            self.fLabelGradientColorT = [Qt.white, Qt.darkGray]

        self.fLabelGradient = QLinearGradient(0, 0, 0, 1)
        self.fLabelGradient.setColorAt(0.0, self.fLabelGradientColor1)
        self.fLabelGradient.setColorAt(0.6, self.fLabelGradientColor1)
        self.fLabelGradient.setColorAt(1.0, self.fLabelGradientColor2)

        self.fLabelGradientRect = QRectF(0.0, 0.0, 0.0, 0.0)

        self.fCustomPaintMode  = self.CUSTOM_PAINT_MODE_NULL
        self.fCustomPaintColor = QColor(0xff, 0xff, 0xff)

        self.updateSizes()

        # Fake internal value, custom precision
        QDial.setMinimum(self, 0)
        QDial.setMaximum(self, self.fPrecision)
        QDial.setValue(self, 0)

        self.valueChanged.connect(self.slot_valueChanged)

    def getIndex(self):
        return self.fIndex

    def getBaseSize(self):
        return self.fPixmapBaseSize

    def forceWhiteLabelGradientText(self):
        self.fLabelGradientColor1 = QColor(0, 0, 0, 255)
        self.fLabelGradientColor2 = QColor(0, 0, 0, 0)
        self.fLabelGradientColorT = [Qt.white, Qt.darkGray]

    def setLabelColor(self, enabled, disabled):
        self.fLabelGradientColor1 = QColor(0, 0, 0, 255)
        self.fLabelGradientColor2 = QColor(0, 0, 0, 0)
        self.fLabelGradientColorT = [enabled, disabled]

    def updateSizes(self):
        self.fPixmapWidth  = self.fPixmap.width()
        self.fPixmapHeight = self.fPixmap.height()

        if self.fPixmapWidth < 1:
            self.fPixmapWidth = 1

        if self.fPixmapHeight < 1:
            self.fPixmapHeight = 1

        if self.fPixmapOrientation == self.HORIZONTAL:
            self.fPixmapBaseSize    = self.fPixmapHeight
            self.fPixmapLayersCount = self.fPixmapWidth / self.fPixmapHeight
        else:
            self.fPixmapBaseSize    = self.fPixmapWidth
            self.fPixmapLayersCount = self.fPixmapHeight / self.fPixmapWidth

        self.setMinimumSize(self.fPixmapBaseSize, self.fPixmapBaseSize + self.fLabelHeight + 5)
        self.setMaximumSize(self.fPixmapBaseSize, self.fPixmapBaseSize + self.fLabelHeight + 5)

        if not self.fLabel:
            self.fLabelHeight = 0
            self.fLabelWidth  = 0
            return

        self.fLabelWidth  = QFontMetrics(self.fLabelFont).width(self.fLabel)
        self.fLabelHeight = QFontMetrics(self.fLabelFont).height()

        self.fLabelPos.setX(float(self.fPixmapBaseSize)/2.0 - float(self.fLabelWidth)/2.0)

        if self.fPixmapNum in ("01", "02", "07", "08", "09", "10"):
            self.fLabelPos.setY(self.fPixmapBaseSize + self.fLabelHeight)
        elif self.fPixmapNum in ("11",):
            self.fLabelPos.setY(self.fPixmapBaseSize + self.fLabelHeight*2/3)
        else:
            self.fLabelPos.setY(self.fPixmapBaseSize + self.fLabelHeight/2)

        self.fLabelGradient.setStart(0, float(self.fPixmapBaseSize)/2.0)
        self.fLabelGradient.setFinalStop(0, self.fPixmapBaseSize + self.fLabelHeight + 5)

        self.fLabelGradientRect = QRectF(float(self.fPixmapBaseSize)/8.0, float(self.fPixmapBaseSize)/2.0, float(self.fPixmapBaseSize*3)/4.0, self.fPixmapBaseSize+self.fLabelHeight+5)

    def setCustomPaintMode(self, paintMode):
        if self.fCustomPaintMode == paintMode:
            return

        self.fCustomPaintMode = paintMode
        self.update()

    def setCustomPaintColor(self, color):
        if self.fCustomPaintColor == color:
            return

        self.fCustomPaintColor = color
        self.update()

    def setLabel(self, label):
        if self.fLabel == label:
            return

        self.fLabel = label
        self.updateSizes()
        self.update()

    def setIndex(self, index):
        self.fIndex = index

    def setPixmap(self, pixmapId):
        self.fPixmapNum = "%02i" % pixmapId
        self.fPixmap.load(":/bitmaps/dial_%s%s.png" % (self.fPixmapNum, "" if self.isEnabled() else "d"))

        if self.fPixmap.width() > self.fPixmap.height():
            self.fPixmapOrientation = self.HORIZONTAL
        else:
            self.fPixmapOrientation = self.VERTICAL

        # special pixmaps
        if self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_NULL:
            # reserved for carla-wet, carla-vol, carla-pan and color
            if self.fPixmapNum == "03":
                self.fCustomPaintMode = self.CUSTOM_PAINT_MODE_COLOR

            # reserved for carla-L and carla-R
            elif self.fPixmapNum == "04":
                self.fCustomPaintMode = self.CUSTOM_PAINT_MODE_CARLA_L

            # reserved for zita
            elif self.fPixmapNum == "06":
                self.fCustomPaintMode = self.CUSTOM_PAINT_MODE_ZITA

        self.updateSizes()
        self.update()

    def setPrecision(self, value, isInteger):
        self.fPrecision = value
        self.fIsInteger = isInteger
        QDial.setMaximum(self, value)

    def setMinimum(self, value):
        self.fMinimum = value

    def setMaximum(self, value):
        self.fMaximum = value

    def setValue(self, value, emitSignal=False):
        if self.fRealValue == value:
            return

        if value <= self.fMinimum:
            qtValue = 0
            self.fRealValue = self.fMinimum

        elif value >= self.fMaximum:
            qtValue = self.fPrecision
            self.fRealValue = self.fMaximum

        else:
            qtValue = round(float(value - self.fMinimum) / float(self.fMaximum - self.fMinimum) * self.fPrecision)
            self.fRealValue = value

        # Block change signal, we'll handle it ourselves
        self.blockSignals(True)
        QDial.setValue(self, qtValue)
        self.blockSignals(False)

        if emitSignal:
            self.realValueChanged.emit(self.fRealValue)

    @pyqtSlot(int)
    def slot_valueChanged(self, value):
        self.fRealValue = float(value)/self.fPrecision * (self.fMaximum - self.fMinimum) + self.fMinimum
        self.realValueChanged.emit(self.fRealValue)

    @pyqtSlot()
    def slot_updatePixmap(self):
        self.setPixmap(int(self.fPixmapNum))

    def minimumSizeHint(self):
        return QSize(self.fPixmapBaseSize, self.fPixmapBaseSize)

    def sizeHint(self):
        return QSize(self.fPixmapBaseSize, self.fPixmapBaseSize)

    def changeEvent(self, event):
        QDial.changeEvent(self, event)

        # Force pixmap update if enabled state changes
        if event.type() == QEvent.EnabledChange:
            self.setPixmap(int(self.fPixmapNum))

    def enterEvent(self, event):
        self.fIsHovered = True
        if self.fHoverStep == self.HOVER_MIN:
            self.fHoverStep = self.HOVER_MIN + 1
        QDial.enterEvent(self, event)

    def leaveEvent(self, event):
        self.fIsHovered = False
        if self.fHoverStep == self.HOVER_MAX:
            self.fHoverStep = self.HOVER_MAX - 1
        QDial.leaveEvent(self, event)

    def mousePressEvent(self, event):
        if self.fDialMode == self.MODE_DEFAULT:
            return QDial.mousePressEvent(self, event)

        if event.button() == Qt.LeftButton:
            self.fIsPressed = True
            self.fLastDragPos = event.pos()
            self.fLastDragValue = self.fRealValue

    def mouseMoveEvent(self, event):
        if self.fDialMode == self.MODE_DEFAULT:
            return QDial.mouseMoveEvent(self, event)

        if not self.fIsPressed:
            return

        range = (self.fMaximum - self.fMinimum) / 4.0
        pos   = event.pos()
        dx    = range * float(pos.x() - self.fLastDragPos.x()) / self.width()
        dy    = range * float(pos.y() - self.fLastDragPos.y()) / self.height()
        value = self.fLastDragValue + dx - dy

        if value < self.fMinimum:
            value = self.fMinimum
        elif value > self.fMaximum:
            value = self.fMaximum
        elif self.fIsInteger:
            value = float(round(value))

        self.setValue(value, True)

    def mouseReleaseEvent(self, event):
        if self.fDialMode == self.MODE_DEFAULT:
            return QDial.mouseReleaseEvent(self, event)

        if self.fIsPressed:
            self.fIsPressed = False

    def paintEvent(self, event):
        painter = QPainter(self)
        event.accept()

        painter.save()
        painter.setRenderHint(QPainter.Antialiasing, True)

        if self.fLabel:
            if self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_NULL:
                painter.setPen(self.fLabelGradientColor2)
                painter.setBrush(self.fLabelGradient)
                painter.drawRect(self.fLabelGradientRect)

            painter.setFont(self.fLabelFont)
            painter.setPen(self.fLabelGradientColorT[0 if self.isEnabled() else 1])
            painter.drawText(self.fLabelPos, self.fLabel)

        if self.isEnabled():
            normValue = float(self.fRealValue - self.fMinimum) / float(self.fMaximum - self.fMinimum)
            target    = QRectF(0.0, 0.0, self.fPixmapBaseSize, self.fPixmapBaseSize)

            curLayer = int((self.fPixmapLayersCount - 1) * normValue)

            if self.fPixmapOrientation == self.HORIZONTAL:
                xpos = self.fPixmapBaseSize * curLayer
                ypos = 0.0
            else:
                xpos = 0.0
                ypos = self.fPixmapBaseSize * curLayer

            source = QRectF(xpos, ypos, self.fPixmapBaseSize, self.fPixmapBaseSize)
            painter.drawPixmap(target, self.fPixmap, source)

            # Custom knobs (Dry/Wet and Volume)
            if self.fCustomPaintMode in (self.CUSTOM_PAINT_MODE_CARLA_WET, self.CUSTOM_PAINT_MODE_CARLA_VOL):
                # knob color
                colorGreen = QColor(0x5D, 0xE7, 0x3D).lighter(100 + self.fHoverStep*6)
                colorBlue  = QColor(0x3E, 0xB8, 0xBE).lighter(100 + self.fHoverStep*6)

                # draw small circle
                ballRect = QRectF(8.0, 8.0, 15.0, 15.0)
                ballPath = QPainterPath()
                ballPath.addEllipse(ballRect)
                #painter.drawRect(ballRect)
                tmpValue  = (0.375 + 0.75*normValue)
                ballValue = tmpValue - floor(tmpValue)
                ballPoint = ballPath.pointAtPercent(ballValue)

                # draw arc
                startAngle = 216*16
                spanAngle  = -252*16*normValue

                if self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_CARLA_WET:
                    painter.setBrush(colorBlue)
                    painter.setPen(QPen(colorBlue, 0))
                    painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2))

                    gradient = QConicalGradient(15.5, 15.5, -45)
                    gradient.setColorAt(0.0,   colorBlue)
                    gradient.setColorAt(0.125, colorBlue)
                    gradient.setColorAt(0.625, colorGreen)
                    gradient.setColorAt(0.75,  colorGreen)
                    gradient.setColorAt(0.76,  colorGreen)
                    gradient.setColorAt(1.0,   colorGreen)
                    painter.setBrush(gradient)
                    painter.setPen(QPen(gradient, 3))

                else:
                    painter.setBrush(colorBlue)
                    painter.setPen(QPen(colorBlue, 0))
                    painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2))

                    painter.setBrush(colorBlue)
                    painter.setPen(QPen(colorBlue, 3))

                painter.drawArc(4.0, 4.0, 26.0, 26.0, startAngle, spanAngle)

            # Custom knobs (L and R)
            elif self.fCustomPaintMode in (self.CUSTOM_PAINT_MODE_CARLA_L, self.CUSTOM_PAINT_MODE_CARLA_R):
                # knob color
                color = QColor(0xAD, 0xD5, 0x48).lighter(100 + self.fHoverStep*6)

                # draw small circle
                ballRect = QRectF(7.0, 8.0, 11.0, 12.0)
                ballPath = QPainterPath()
                ballPath.addEllipse(ballRect)
                #painter.drawRect(ballRect)
                tmpValue  = (0.375 + 0.75*normValue)
                ballValue = tmpValue - floor(tmpValue)
                ballPoint = ballPath.pointAtPercent(ballValue)

                painter.setBrush(color)
                painter.setPen(QPen(color, 0))
                painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.0, 2.0))

                # draw arc
                if self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_CARLA_L:
                    startAngle = 216*16
                    spanAngle  = -252.0*16*normValue
                else:
                    startAngle = 324.0*16
                    spanAngle  = 252.0*16*(1.0-normValue)

                painter.setPen(QPen(color, 2))
                painter.drawArc(3.5, 4.5, 22.0, 22.0, startAngle, spanAngle)

            # Custom knobs (Color)
            elif self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_COLOR:
                # knob color
                color = self.fCustomPaintColor.lighter(100 + self.fHoverStep*6)

                # draw small circle
                ballRect = QRectF(8.0, 8.0, 15.0, 15.0)
                ballPath = QPainterPath()
                ballPath.addEllipse(ballRect)
                tmpValue  = (0.375 + 0.75*normValue)
                ballValue = tmpValue - floor(tmpValue)
                ballPoint = ballPath.pointAtPercent(ballValue)

                # draw arc
                startAngle = 216*16
                spanAngle  = -252*16*normValue

                painter.setBrush(color)
                painter.setPen(QPen(color, 0))
                painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2))

                painter.setBrush(color)
                painter.setPen(QPen(color, 3))
                painter.drawArc(4.0, 4.0, 26.0, 26.0, startAngle, spanAngle)

            # Custom knobs (Zita)
            elif self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_ZITA:
                a = normValue * pi * 1.5 - 2.35
                r = 10.0
                x = 10.5
                y = 10.5
                x += r * sin(a)
                y -= r * cos(a)
                painter.setBrush(Qt.black)
                painter.setPen(QPen(Qt.black, 2))
                painter.drawLine(QPointF(11.0, 11.0), QPointF(x, y))

            # Custom knobs
            else:
                painter.restore()
                return

            if self.HOVER_MIN < self.fHoverStep < self.HOVER_MAX:
                self.fHoverStep += 1 if self.fIsHovered else -1
                QTimer.singleShot(20, self.update)

        else: # isEnabled()
            target = QRectF(0.0, 0.0, self.fPixmapBaseSize, self.fPixmapBaseSize)
            painter.drawPixmap(target, self.fPixmap, target)

        painter.restore()

    def resizeEvent(self, event):
        QDial.resizeEvent(self, event)
        self.updateSizes()
Beispiel #45
0
class Node(QGraphicsItem):
    Type = QGraphicsItem.UserType + 1

    def __init__(self, graphWidget):
        super(Node, self).__init__()

        self.graph = graphWidget
        self.edgeList = []
        self.newPos = QPointF()

        self.setFlag(QGraphicsItem.ItemIsMovable)
        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges)
        self.setCacheMode(QGraphicsItem.DeviceCoordinateCache)
        self.setZValue(1)

    def type(self):
        return Node.Type

    def addEdge(self, edge):
        self.edgeList.append(edge)
        edge.adjust()

    def edges(self):
        return self.edgeList

    def calculateForces(self):
        if not self.scene() or self.scene().mouseGrabberItem() is self:
            self.newPos = self.pos()
            return
    
        # Sum up all forces pushing this item away.
        xvel = 0.0
        yvel = 0.0
        for item in self.scene().items():
            if not isinstance(item, Node):
                continue

            line = QLineF(self.mapFromItem(item, 0, 0), QPointF(0, 0))
            dx = line.dx()
            dy = line.dy()
            l = 2.0 * (dx * dx + dy * dy)
            if l > 0:
                xvel += (dx * 150.0) / l
                yvel += (dy * 150.0) / l

        # Now subtract all forces pulling items together.
        weight = (len(self.edgeList) + 1) * 10.0
        for edge in self.edgeList:
            if edge.sourceNode() is self:
                pos = self.mapFromItem(edge.destNode(), 0, 0)
            else:
                pos = self.mapFromItem(edge.sourceNode(), 0, 0)
            xvel += pos.x() / weight
            yvel += pos.y() / weight
    
        if qAbs(xvel) < 0.1 and qAbs(yvel) < 0.1:
            xvel = yvel = 0.0

        sceneRect = self.scene().sceneRect()
        self.newPos = self.pos() + QPointF(xvel, yvel)
        self.newPos.setX(min(max(self.newPos.x(), sceneRect.left() + 10), sceneRect.right() - 10))
        self.newPos.setY(min(max(self.newPos.y(), sceneRect.top() + 10), sceneRect.bottom() - 10))

    def advance(self):
        if self.newPos == self.pos():
            return False

        self.setPos(self.newPos)
        return True

    def boundingRect(self):
        adjust = 2.0
        return QRectF(-10 - adjust, -10 - adjust, 23 + adjust, 23 + adjust)

    def shape(self):
        path = QPainterPath()
        path.addEllipse(-10, -10, 20, 20)
        return path

    def paint(self, painter, option, widget):
        painter.setPen(Qt.NoPen)
        painter.setBrush(Qt.darkGray)
        painter.drawEllipse(-7, -7, 20, 20)

        gradient = QRadialGradient(-3, -3, 10)
        if option.state & QStyle.State_Sunken:
            gradient.setCenter(3, 3)
            gradient.setFocalPoint(3, 3)
            gradient.setColorAt(1, QColor(Qt.yellow).lighter(120))
            gradient.setColorAt(0, QColor(Qt.darkYellow).lighter(120))
        else:
            gradient.setColorAt(0, Qt.yellow)
            gradient.setColorAt(1, Qt.darkYellow)

        painter.setBrush(QBrush(gradient))
        painter.setPen(QPen(Qt.black, 0))
        painter.drawEllipse(-10, -10, 20, 20)

    def itemChange(self, change, value):
        if change == QGraphicsItem.ItemPositionHasChanged:
            for edge in self.edgeList:
                edge.adjust()
            self.graph.itemMoved()

        return super(Node, self).itemChange(change, value)

    def mousePressEvent(self, event):
        self.update()
        super(Node, self).mousePressEvent(event)

    def mouseReleaseEvent(self, event):
        self.update()
        super(Node, self).mouseReleaseEvent(event)
Beispiel #46
0
 def __findIntersection(self, p1, p2, p3, p4):
     """
     Private method to calculate the intersection point of two lines.
     
     The first line is determined by the points p1 and p2, the second
     line by p3 and p4. If the intersection point is not contained in
     the segment p1p2, then it returns (-1.0, -1.0).
     
     For the function's internal calculations remember:<br />
     QT coordinates start with the point (0,0) as the topleft corner
     and x-values increase from left to right and y-values increase
     from top to bottom; it means the visible area is quadrant I in
     the regular XY coordinate system
     
     <pre>
         Quadrant II     |   Quadrant I
        -----------------|-----------------
         Quadrant III    |   Quadrant IV
     </pre>
     
     In order for the linear function calculations to work in this method
     we must switch x and y values (x values become y values and viceversa)
     
     @param p1 first point of first line (QPointF)
     @param p2 second point of first line (QPointF)
     @param p3 first point of second line (QPointF)
     @param p4 second point of second line (QPointF)
     @return the intersection point (QPointF)
     """
     x1 = p1.y()
     y1 = p1.x()
     x2 = p2.y()
     y2 = p2.x()
     x3 = p3.y()
     y3 = p3.x()
     x4 = p4.y()
     y4 = p4.x()
     
     # line 1 is the line between (x1, y1) and (x2, y2)
     # line 2 is the line between (x3, y3) and (x4, y4)
     no_line1 = True    # it is false, if line 1 is a linear function
     no_line2 = True    # it is false, if line 2 is a linear function
     slope1 = 0.0
     slope2 = 0.0
     b1 = 0.0
     b2 = 0.0
     
     if x2 != x1:
         slope1 = (y2 - y1) / (x2 - x1)
         b1 = y1 - slope1 * x1
         no_line1 = False
     if x4 != x3:
         slope2 = (y4 - y3) / (x4 - x3)
         b2 = y3 - slope2 * x3
         no_line2 = False
     
     pt = QPointF()
     # if either line is not a function
     if no_line1 and no_line2:
         # if the lines are not the same one
         if x1 != x3:
             return QPointF(-1.0, -1.0)
         # if the lines are the same ones
         if y3 <= y4:
             if y3 <= y1 and y1 <= y4:
                 return QPointF(y1, x1)
             else:
                 return QPointF(y2, x2)
         else:
             if y4 <= y1 and y1 <= y3:
                 return QPointF(y1, x1)
             else:
                 return QPointF(y2, x2)
     elif no_line1:
         pt.setX(slope2 * x1 + b2)
         pt.setY(x1)
         if y1 >= y2:
             if not (y2 <= pt.x() and pt.x() <= y1):
                 pt.setX(-1.0)
                 pt.setY(-1.0)
         else:
             if not (y1 <= pt.x() and pt.x() <= y2):
                 pt.setX(-1.0)
                 pt.setY(-1.0)
         return pt
     elif no_line2:
         pt.setX(slope1 * x3 + b1)
         pt.setY(x3)
         if y3 >= y4:
             if not (y4 <= pt.x() and pt.x() <= y3):
                 pt.setX(-1.0)
                 pt.setY(-1.0)
         else:
             if not (y3 <= pt.x() and pt.x() <= y4):
                 pt.setX(-1.0)
                 pt.setY(-1.0)
         return pt
     
     if slope1 == slope2:
         pt.setX(-1.0)
         pt.setY(-1.0)
         return pt
     
     pt.setY((b2 - b1) / (slope1 - slope2))
     pt.setX(slope1 * pt.y() + b1)
     # the intersection point must be inside the segment (x1, y1) (x2, y2)
     if x2 >= x1 and y2 >= y1:
         if not ((x1 <= pt.y() and pt.y() <= x2) and
                 (y1 <= pt.x() and pt.x() <= y2)):
             pt.setX(-1.0)
             pt.setY(-1.0)
     elif x2 < x1 and y2 >= y1:
         if not ((x2 <= pt.y() and pt.y() <= x1) and
                 (y1 <= pt.x() and pt.x() <= y2)):
             pt.setX(-1.0)
             pt.setY(-1.0)
     elif x2 >= x1 and y2 < y1:
         if not ((x1 <= pt.y() and pt.y() <= x2) and
                 (y2 <= pt.x() and pt.x() <= y1)):
             pt.setX(-1.0)
             pt.setY(-1.0)
     else:
         if not ((x2 <= pt.y() and pt.y() <= x1) and
                 (y2 <= pt.x() and pt.x() <= y1)):
             pt.setX(-1.0)
             pt.setY(-1.0)
     
     return pt
Beispiel #47
0
    def interactiveResize(self, mousePos):
        """
        Perform shape interactive resize.
        """
        offset = self.handleSize + self.handleSpace
        boundingRect = self.boundingRect()
        rect = self.rect()
        diff = QPointF(0, 0)

        self.prepareGeometryChange()

        if self.handleSelected == self.handleTopLeft:
            fromX = self.mousePressRect.left()
            fromY = self.mousePressRect.top()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            diff.setX(toX - fromX)
            diff.setY(toY - fromY)
            boundingRect.setLeft(toX)
            boundingRect.setTop(toY)
            rect.setLeft(boundingRect.left() + offset)
            rect.setTop(boundingRect.top() + offset)
            self.setRect(rect)

        elif self.handleSelected == self.handleTopMiddle:
            fromY = self.mousePressRect.top()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            diff.setY(toY - fromY)
            boundingRect.setTop(toY)
            rect.setTop(boundingRect.top() + offset)
            self.setRect(rect)

        elif self.handleSelected == self.handleTopRight:
            fromX = self.mousePressRect.right()
            fromY = self.mousePressRect.top()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            diff.setX(toX - fromX)
            diff.setY(toY - fromY)
            boundingRect.setRight(toX)
            boundingRect.setTop(toY)
            rect.setRight(boundingRect.right() - offset)
            rect.setTop(boundingRect.top() + offset)
            self.setRect(rect)

        elif self.handleSelected == self.handleMiddleLeft:
            fromX = self.mousePressRect.left()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            diff.setX(toX - fromX)
            boundingRect.setLeft(toX)
            rect.setLeft(boundingRect.left() + offset)
            self.setRect(rect)

        elif self.handleSelected == self.handleMiddleRight:
            fromX = self.mousePressRect.right()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            diff.setX(toX - fromX)
            boundingRect.setRight(toX)
            rect.setRight(boundingRect.right() - offset)
            self.setRect(rect)

        elif self.handleSelected == self.handleBottomLeft:
            fromX = self.mousePressRect.left()
            fromY = self.mousePressRect.bottom()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            diff.setX(toX - fromX)
            diff.setY(toY - fromY)
            boundingRect.setLeft(toX)
            boundingRect.setBottom(toY)
            rect.setLeft(boundingRect.left() + offset)
            rect.setBottom(boundingRect.bottom() - offset)
            self.setRect(rect)

        elif self.handleSelected == self.handleBottomMiddle:
            fromY = self.mousePressRect.bottom()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            diff.setY(toY - fromY)
            boundingRect.setBottom(toY)
            rect.setBottom(boundingRect.bottom() - offset)
            self.setRect(rect)

        elif self.handleSelected == self.handleBottomRight:
            fromX = self.mousePressRect.right()
            fromY = self.mousePressRect.bottom()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            diff.setX(toX - fromX)
            diff.setY(toY - fromY)
            boundingRect.setRight(toX)
            boundingRect.setBottom(toY)
            rect.setRight(boundingRect.right() - offset)
            rect.setBottom(boundingRect.bottom() - offset)
            self.setRect(rect)

        self.updateHandlesPos()