Ejemplo n.º 1
0
    def adjust_regular_roi_bounds(rect: QRectF, point: Anchor,
                                  mouse: QPointF) -> QRectF:
        """ Get the new bounding rectangle of a "regular" ROI (rectangle or ellipse) after dragging of anchor.

        @param rect: original bounding rectangle.
        @param point: anchor that has been dragged.
        @param mouse: point that mouse has been dragged to.
        @return: new bounding rectangle.
        """
        if point.position == AnchorPosition.LEFT:
            rect.setLeft(rect.left() + mouse.x())
        elif point.position == AnchorPosition.RIGHT:
            rect.setRight(rect.right() + mouse.x())
        elif point.position == AnchorPosition.TOP:
            rect.setTop(rect.top() + mouse.y())
        elif point.position == AnchorPosition.TOP_LEFT:
            rect.setLeft(rect.left() + mouse.x())
            rect.setTop(rect.top() + mouse.y())
        elif point.position == AnchorPosition.TOP_RIGHT:
            rect.setRight(rect.right() + mouse.x())
            rect.setTop(rect.top() + mouse.y())
        elif point.position == AnchorPosition.BOTTOM:
            rect.setBottom(rect.bottom() + mouse.y())
        elif point.position == AnchorPosition.BOTTOM_LEFT:
            rect.setLeft(rect.left() + mouse.x())
            rect.setBottom(rect.bottom() + mouse.y())
        elif point.position == AnchorPosition.BOTTOM_RIGHT:
            rect.setRight(rect.right() + mouse.x())
            rect.setBottom(rect.bottom() + mouse.y())

        return rect.normalized(
        )  # normalised() causes width/height to go to zero when dragging to negative
Ejemplo n.º 2
0
 def drawBackground(self, painter: QPainter, rect: QRectF):
     rect = self.sceneRect()
     super().drawBackground(painter, rect)
     # 绘制纯色背景
     # 绘制网格
     xLines_thin = []
     yLines_thin = []
     xLines_blod = []
     yLines_blod = []
     for i in range(0, self.rectSize, self.gridSize):
         if (i % 100) != 0:
             xLines_thin.append(
                 QLineF(rect.left(),
                        rect.top() + i, rect.right(),
                        rect.top() + i))
             yLines_thin.append(
                 QLineF(rect.left() + i, rect.top(),
                        rect.left() + i, rect.bottom()))
         else:
             xLines_blod.append(
                 QLineF(rect.left(),
                        rect.top() + i, rect.right(),
                        rect.top() + i))
             yLines_blod.append(
                 QLineF(rect.left() + i, rect.top(),
                        rect.left() + i, rect.bottom()))
     painter.setPen(QPen(self.grid_line_color, self.tinny_grid_line_width))
     painter.drawLines(xLines_thin)
     painter.drawLines(yLines_thin)
     painter.setPen(QPen(self.grid_line_color, self.bold_grid_line_width))
     painter.drawLines(xLines_blod)
     painter.drawLines(yLines_blod)
Ejemplo n.º 3
0
    def adjust_regular_roi_anchors(bounds: QRectF, anchors: list):
        """ Adjust the anchors of a "regular" ROI (rectangle or ellipse)

        @param bounds: bounding rectangle of ROI
        @param anchors: list of anchors
        """
        for point in anchors:
            off = point.boundingRect().width() / 2
            if point.position == AnchorPosition.LEFT:
                point.setPos(bounds.left() - off,
                             bounds.top() - off + bounds.height() / 2)
            elif point.position == AnchorPosition.RIGHT:
                point.setPos(bounds.right() - off,
                             bounds.top() - off + bounds.height() / 2)
            elif point.position == AnchorPosition.TOP:
                point.setPos(bounds.left() - off + bounds.width() / 2,
                             bounds.top() - off)
            elif point.position == AnchorPosition.TOP_LEFT:
                point.setPos(bounds.left() - off, bounds.top() - off)
            elif point.position == AnchorPosition.TOP_RIGHT:
                point.setPos(bounds.right() - off, bounds.top() - off)
            elif point.position == AnchorPosition.BOTTOM:
                point.setPos(bounds.left() - off + bounds.width() / 2,
                             bounds.bottom() - off)
            elif point.position == AnchorPosition.BOTTOM_LEFT:
                point.setPos(bounds.left() - off, bounds.bottom() - off)
            elif point.position == AnchorPosition.BOTTOM_RIGHT:
                point.setPos(bounds.right() - off, bounds.bottom() - off)
Ejemplo n.º 4
0
    def draw_background(self, painter: QtGui.QPainter, rect: QtCore.QRectF) -> None:
        if not self._show_grid:
            return

        painter.setPen(
            QtGui.QPen(
                QtGui.QColor(0, 0, 0)
            )
        )

        lines = []

        for x in list(self.stacker_map.row_termination_points())[:-1]:
            if rect.left() <= x <= rect.right():
                lines.append(
                    QLineF(
                        x, rect.top(), x, rect.bottom(),
                    )
                )

        for y in list(self.stacker_map.column_termination_points())[:-1]:
            if rect.top() <= y <= rect.bottom():
                lines.append(
                    QLineF(
                        rect.left(), y, rect.right(), y,
                    )
                )

        painter.drawLines(lines)
Ejemplo n.º 5
0
    def drawBackground(self, painter: QPainter, rect: QRectF):

        # freqs = np.fft.fftfreq(len(w), 1 / self.sample_rate)
        if self.draw_grid and len(self.frequencies) > 0:
            painter.setPen(QPen(painter.pen().color(), 0))
            parent_width = self.parent().width() if hasattr(
                self.parent(), "width") else 750
            view_rect = self.parent().view_rect() if hasattr(
                self.parent(), "view_rect") else rect

            font_width = self.font_metrics.width(
                Formatter.big_value_with_suffix(self.center_freq) + "   ")
            x_grid_size = int(view_rect.width() / parent_width * font_width)
            # x_grid_size = int(0.1 * view_rect.width()) if 0.1 * view_rect.width() > 1 else 1
            y_grid_size = 1
            x_mid = np.where(self.frequencies == 0)[0]
            x_mid = int(x_mid[0]) if len(x_mid) > 0 else 0

            left = int(rect.left()) - (int(rect.left()) % x_grid_size)
            left = left if left > 0 else 0

            top = rect.top() - (rect.top() % y_grid_size)
            bottom = rect.bottom() - (rect.bottom() % y_grid_size)
            right_border = int(
                rect.right()) if rect.right() < len(self.frequencies) else len(
                    self.frequencies)

            x_range = list(range(x_mid, left, -x_grid_size)) + list(
                range(x_mid, right_border, x_grid_size))
            lines = [QLineF(x, rect.top(), x, bottom) for x in x_range] \
                    + [QLineF(rect.left(), y, rect.right(), y) for y in np.arange(top, bottom, y_grid_size)]

            painter.drawLines(lines)
            scale_x, scale_y = util.calc_x_y_scale(rect, self.parent())

            painter.scale(scale_x, scale_y)
            counter = -1  # Counter for Label for every second line

            for x in x_range:
                freq = self.frequencies[x]
                counter += 1

                if freq != 0 and (counter % 2 !=
                                  0):  # Label for every second line
                    continue

                if freq != 0:
                    prefix = "+" if freq > 0 else ""
                    value = prefix + Formatter.big_value_with_suffix(freq, 2)
                else:
                    counter = 0
                    value = Formatter.big_value_with_suffix(6800e6 -
                                                            self.center_freq +
                                                            self.status_k)
                font_width = self.font_metrics.width(value)
                painter.drawText(x / scale_x - font_width / 2,
                                 bottom / scale_y, value)
Ejemplo n.º 6
0
    def drawPopupPointer(self, p):
        r = QRectF(self.rect())

        if self.pointerPos == self.LeftSide:
            PPIX_X = self.LR_MARGIN
            PPIX_Y = PPIX_X * 2.0
            points = [
                QPointF(r.x() + PPIX_X,
                        r.height() / 2.0 - PPIX_Y / 2.0),
                QPointF(r.x() + PPIX_X,
                        r.height() / 2.0 + PPIX_Y / 2.0),
                QPointF(r.x(),
                        r.height() / 2.0),
            ]

            p.drawPolygon(*points)

        if self.pointerPos == self.RightSide:
            PPIX_X = self.LR_MARGIN
            PPIX_Y = PPIX_X * 2.0
            points = [
                QPointF(r.right() - PPIX_X,
                        r.height() / 2.0 - PPIX_Y / 2.0),
                QPointF(r.right() - PPIX_X,
                        r.height() / 2.0 + PPIX_Y / 2.0),
                QPointF(r.right(),
                        r.height() / 2.0),
            ]

            p.drawPolygon(*points)

        if self.pointerPos == self.TopSide:
            PPIX_Y = self.TB_MARGIN
            PPIX_X = PPIX_Y * 2.0
            points = [
                QPointF(r.x() + r.width() / 2.0 - PPIX_X / 2.0,
                        r.top() + PPIX_Y),
                QPointF(r.x() + r.width() / 2.0 + PPIX_X / 2.0,
                        r.top() + PPIX_Y),
                QPointF(r.x() + r.width() / 2.0, r.top()),
            ]

            p.drawPolygon(*points)

        if self.pointerPos == self.BottomSide:
            PPIX_Y = self.TB_MARGIN
            PPIX_X = PPIX_Y * 2.0
            points = [
                QPointF(r.x() + r.width() / 2.0 - PPIX_X / 2.0,
                        r.bottom() - PPIX_Y),
                QPointF(r.x() + r.width() / 2.0 + PPIX_X / 2.0,
                        r.bottom() - PPIX_Y),
                QPointF(r.x() + r.width() / 2.0, r.bottom()),
            ]

            p.drawPolygon(*points)
Ejemplo n.º 7
0
    def drawBackground(self, painter: QPainter, rect: QRectF):
        # freqs = np.fft.fftfreq(len(w), 1 / self.sample_rate)
        if self.draw_grid and len(self.frequencies) > 0:
            painter.setPen(QPen(painter.pen().color(), Qt.FlatCap))
            parent_width = self.parent().width() if hasattr(self.parent(), "width") else 750
            view_rect = self.parent().view_rect() if hasattr(self.parent(), "view_rect") else rect

            font_width = self.font_metrics.width(Formatter.big_value_with_suffix(self.center_freq) + "   ")
            x_grid_size = int(view_rect.width() / parent_width * font_width)
            # x_grid_size = int(0.1 * view_rect.width()) if 0.1 * view_rect.width() > 1 else 1
            y_grid_size = view_rect.height() / parent_width * font_width
            x_mid = np.where(self.frequencies == 0)[0]
            x_mid = int(x_mid[0]) if len(x_mid) > 0 else 0

            left = int(rect.left()) - (int(rect.left()) % x_grid_size)
            left = left if left > 0 else 0

            top = rect.top() - (rect.top() % y_grid_size)
            bottom = rect.bottom() - (rect.bottom() % y_grid_size)
            right_border = int(rect.right()) if rect.right() < len(self.frequencies) else len(self.frequencies)

            x_range = list(range(x_mid, left, -x_grid_size)) + list(range(x_mid, right_border, x_grid_size))
            lines = [QLineF(x, rect.top(), x, bottom) for x in x_range] \
                    + [QLineF(rect.left(), y, rect.right(), y) for y in np.arange(top, bottom, y_grid_size)]

            painter.drawLines(lines)
            scale_x = view_rect.width() / parent_width
            scale_y = view_rect.height() / parent_width
            painter.scale(scale_x, scale_y)

            font_height = self.font_metrics.height()
            counter = -1  # Counter for Label for every second line

            for x in x_range:
                freq =  self.frequencies[x]
                counter += 1

                if freq != 0 and (counter % 2 != 0): # Label for every second line
                    continue

                if freq != 0:
                    prefix = "+" if freq > 0 else ""
                    value = prefix+Formatter.big_value_with_suffix(freq, 2)
                else:
                    counter = 0
                    value = Formatter.big_value_with_suffix(self.center_freq)
                font_width = self.font_metrics.width(value)
                painter.drawText(x / scale_x - font_width / 2,
                                 bottom / scale_y + font_height, value)
Ejemplo n.º 8
0
    def __iniGraphicsSystem(self):  ##初始化 graphics View系统
        rect = QRectF(-200, -100, 400, 200)
        self.scene = QGraphicsScene(rect)  #scene逻辑坐标系定义
        self.view.setScene(self.scene)

        ## 画一个矩形框,大小等于scene
        item = QGraphicsRectItem(rect)  #矩形框正好等于scene的大小
        item.setFlag(QGraphicsItem.ItemIsSelectable)  #可选,
        item.setFlag(QGraphicsItem.ItemIsFocusable)  #可以有焦点
        pen = QPen()
        pen.setWidth(2)
        item.setPen(pen)
        self.scene.addItem(item)

        ##一个位于scene中心的椭圆,测试局部坐标
        #矩形框内创建椭圆,绘图项的局部坐标,左上角(-100,-50),宽200,高100
        item2 = QGraphicsEllipseItem(-100, -50, 200, 100)
        item2.setPos(0, 0)
        item2.setBrush(QBrush(Qt.blue))
        item2.setFlag(QGraphicsItem.ItemIsSelectable)  #可选,
        item2.setFlag(QGraphicsItem.ItemIsFocusable)  #可以有焦点
        item2.setFlag(QGraphicsItem.ItemIsMovable)  #可移动

        self.scene.addItem(item2)

        ##一个圆,中心位于scene的边缘
        item3 = QGraphicsEllipseItem(-50, -50, 100, 100)  #矩形框内创建椭圆,绘图项的局部坐标
        item3.setPos(rect.right(), rect.bottom())
        item3.setBrush(QBrush(Qt.red))
        item3.setFlag(QGraphicsItem.ItemIsSelectable)  #可选,
        item3.setFlag(QGraphicsItem.ItemIsFocusable)  #可以有焦点
        item3.setFlag(QGraphicsItem.ItemIsMovable)  #可移动
        self.scene.addItem(item3)

        self.scene.clearSelection()
Ejemplo n.º 9
0
    def _hitTest(self, rc: QRectF, mousePos: QPointF) -> Hit:
        maxdist = 4
        if not rc.adjusted(-maxdist, -maxdist, maxdist,
                           maxdist).contains(mousePos):
            return Hit.NoHit

        def dist(p1, p2):
            return (p1 - p2).manhattanLength()

        if dist(rc.topLeft(), mousePos) < maxdist:
            return Hit.TopLeft
        elif dist(rc.topRight(), mousePos) < maxdist:
            return Hit.TopRight
        elif dist(rc.bottomRight(), mousePos) < maxdist:
            return Hit.BottomRight
        elif dist(rc.bottomLeft(), mousePos) < maxdist:
            return Hit.BottomLeft
        elif abs(rc.left() - mousePos.x()) < maxdist:
            return Hit.Left
        elif abs(rc.right() - mousePos.x()) < maxdist:
            return Hit.Right
        elif abs(rc.top() - mousePos.y()) < maxdist:
            return Hit.Top
        elif abs(rc.bottom() - mousePos.y()) < maxdist:
            return Hit.Bottom
        elif rc.contains(mousePos):
            return Hit.Center
        else:
            return Hit.NoHit
Ejemplo n.º 10
0
    def _GridLines(self, painter: QtGui.QPainter, rect: QtCore.QRectF):
        # * grid bounds
        left = int(math.floor(rect.left()))
        right = int(math.ceil(rect.right()))
        top = int(math.floor(rect.top()))
        bottom = int(math.ceil(rect.bottom()))

        fLeft = left - (left % self._gridSize)
        fTop = top - (top % self._gridSize)

        # * compute lines
        majorLine = [
            QtCore.QLine(x, top, x, bottom)
            for x in range(fLeft, right, self._gridSize * self._lineSpacing)
        ]

        for y in range(fTop, bottom, self._gridSize * self._lineSpacing):
            majorLine.append(QtCore.QLine(left, y, right, y))

        minorLines = [
            QtCore.QLine(x, top, x, bottom)
            for x in range(fLeft, right, self._gridSize)
        ]

        for y in range(fTop, bottom, self._gridSize):
            minorLines.append(QtCore.QLine(left, y, right, y))

        # * draw lines
        painter.setPen(self._penMajorLine)
        for line in majorLine:
            painter.drawLine(line)

        painter.setPen(self._penMinorLine)
        for line in minorLines:
            painter.drawLine(line)
Ejemplo n.º 11
0
    def drawBackground(self, painter: QtGui.QPainter, rect: QtCore.QRectF):
        grid_size = 25

        left = int(rect.left()) - (int(rect.left()) % grid_size)
        top = int(rect.top()) - (int(rect.top()) % grid_size)

        lines = []

        for x in range(left, int(rect.right()), grid_size):
            lines.append(QLineF(x, rect.top(), x, rect.bottom()))

        for y in range(top, int(rect.bottom()), grid_size):
            lines.append(QLineF(rect.left(), y, rect.right(), y))

        # print(len(lines))

        painter.drawLines(lines)
Ejemplo n.º 12
0
    def drawBackground(self, painter: QPainter, rect: QRectF):
        # freqs = np.fft.fftfreq(len(w), 1 / self.sample_rate)
        if self.draw_grid and len(self.frequencies) > 0:
            painter.setPen(QPen(painter.pen().color(), Qt.FlatCap))
            parent_width = self.parent().width() if hasattr(
                self.parent(), "width") else 750
            view_rect = self.parent().view_rect() if hasattr(
                self.parent(), "view_rect") else rect

            font_width = self.font_metrics.width(
                self.value_with_suffix(self.center_freq) + "   ")
            x_grid_size = int(view_rect.width() / parent_width * font_width)
            # x_grid_size = int(0.1 * view_rect.width()) if 0.1 * view_rect.width() > 1 else 1
            y_grid_size = view_rect.height() / parent_width * font_width
            x_mid = np.where(self.frequencies == 0)[0]
            x_mid = int(x_mid[0]) if len(x_mid) > 0 else 0

            left = int(rect.left()) - (int(rect.left()) % x_grid_size)
            left = left if left > 0 else 0

            top = rect.top() - (rect.top() % y_grid_size)
            bottom = rect.bottom() - (rect.bottom() % y_grid_size)
            right_border = int(
                rect.right()) if rect.right() < len(self.frequencies) else len(
                    self.frequencies)

            x_range = list(range(x_mid, left, -x_grid_size)) + list(
                range(x_mid, right_border, x_grid_size))

            lines = [QLineF(x, rect.top(), x, bottom) for x in x_range] \
                    + [QLineF(rect.left(), y, rect.right(), y) for y in np.arange(top, bottom, y_grid_size)]

            painter.drawLines(lines)
            scale_x = view_rect.width() / parent_width
            scale_y = view_rect.height() / parent_width
            painter.scale(scale_x, scale_y)

            font_height = self.font_metrics.height()

            for x in x_range:
                value = self.value_with_suffix(self.center_freq +
                                               self.frequencies[x])
                font_width = self.font_metrics.width(value)
                painter.drawText(x / scale_x - font_width / 2,
                                 bottom / scale_y + font_height, value)
Ejemplo n.º 13
0
def qrectf_to_inscribed_rect(rect: QRectF) -> QRect:
    """
    Return the largest integer QRect such that it is completely contained in
    `rect`.
    """
    xmin = int(math.ceil(rect.x()))
    xmax = int(math.floor(rect.right()))
    ymin = int(math.ceil(rect.top()))
    ymax = int(math.floor(rect.bottom()))
    return QRect(xmin, ymin, max(xmax - xmin, 0), max(ymax - ymin, 0))
Ejemplo n.º 14
0
    def itemChange(self, change, value):
        """ Check, whether the item is out of the scenes bounds """
        if change == QGraphicsItem.ItemPositionChange:
            # get the new position
            newPos = value
            oldRect = self.sceneBoundingRect()
            newRect = QRectF(newPos.x(), newPos.y(), oldRect.width(),
                             oldRect.height())
            sceneRect = QRectF(self.scene().sceneRect())

            # check if the left or right side of the new rect is outside the scenes bounds -> move it back inside
            if newRect.left() < sceneRect.left():
                newPos.setX(sceneRect.left())
            elif newRect.left() + newRect.width() > sceneRect.right():
                newPos.setX(sceneRect.right() - newRect.width())

            # check if the top or bottom side of the new rect is outside the scenes bounds -> move it back inside
            if newRect.bottom() > sceneRect.bottom():
                newPos.setY(sceneRect.bottom() - newRect.height())
            elif newRect.top() < sceneRect.top():
                newPos.setY(sceneRect.top())
            return newPos
        return super(NodeItem, self).itemChange(change, value)
    def _from_local_coordinates(self, image_index: QModelIndex,
                                rectangle: QRectF) -> Selection:
        """
        Scales a floating point rectangle from local coordinates to an integer based rectangle in the source image
        coordinates.
        """
        image = image_index.sibling(image_index.row(), 0).data(Qt.UserRole)
        image_width: int = image.width
        scaling_factor = image_width / self.scene().width()

        return Selection(
            Point(round(rectangle.left() * scaling_factor),
                  round(rectangle.top() * scaling_factor)),
            Point(round(rectangle.right() * scaling_factor),
                  round(rectangle.bottom() * scaling_factor)), image)
    def on_rect_selected(self, rect):
        if not self.spectrogram:
            return

        scene_rect = QRectF(
            self.mapToScene(rect.topLeft()),
            self.mapToScene(rect.bottomRight())
        )

        self.scene.set_selection(scene_rect)

        fragment = self.spectrogram.get_sound_fragment(
            (scene_rect.left(), scene_rect.right()),
            (scene_rect.bottom(), scene_rect.top()),
        )

        self.fragment_selected.emit(fragment)
Ejemplo n.º 17
0
    def paintEvent(self, event):
        unused(event)
        compassAIIntrusion = 0
        compassHalfSpan = 180
        painter = QPainter()
        painter.begin(self)
        painter.setRenderHint(QPainter.Antialiasing, True)
        painter.setRenderHint(QPainter.HighQualityAntialiasing, True)

        tapeGaugeWidth = self.tapesGaugeWidthFor(self.width(), self.width())
        aiheight = self.height()
        aiwidth = self.width() - tapeGaugeWidth * 2
        if (aiheight > aiwidth):
            aiheight = aiwidth
        AIMainArea = QRectF(tapeGaugeWidth, 0, aiwidth, aiheight)
        AIPaintArea = QRectF(0, 0, self.width(), self.height())

        velocityMeterArea = QRectF(0, 0, tapeGaugeWidth, aiheight)
        altimeterArea = QRectF(AIMainArea.right(), 0, tapeGaugeWidth, aiheight)

        # calc starts
        compassRelativeWidth = 0.75
        compassBottomMargin = 0.78
        compassSize = compassRelativeWidth * AIMainArea.width(
        )  # Diameter is this times the width.
        compassCenterY = AIMainArea.bottom() + compassSize / 4

        if self.height(
        ) - compassCenterY > AIMainArea.width() / 2 * compassBottomMargin:
            compassCenterY = self.height(
            ) - AIMainArea.width() / 2 * compassBottomMargin
        compassCenterY = (compassCenterY * 2 + AIMainArea.bottom() +
                          compassSize / 4) / 3

        compassArea = QRectF(
            AIMainArea.x() +
            (1 - compassRelativeWidth) / 2 * AIMainArea.width(),
            compassCenterY - compassSize / 2, compassSize, compassSize)

        if self.height() - compassCenterY < compassSize / 2:
            compassHalfSpan = math.acos(
                (compassCenterY - self.height()) * 2 /
                compassSize) * 180 / math.pi + self.COMPASS_DISK_RESOLUTION
            if compassHalfSpan > 180:
                compassHalfSpan = 180

        compassAIIntrusion = compassSize / 2 + AIMainArea.bottom(
        ) - compassCenterY
        if compassAIIntrusion < 0:
            compassAIIntrusion = 0
        #calc ends

        hadClip = painter.hasClipping()

        painter.setClipping(True)
        painter.setClipRect(AIPaintArea)

        self.drawAIGlobalFeatures(painter, AIMainArea, AIPaintArea)
        self.drawAIAttitudeScales(painter, AIMainArea, compassAIIntrusion)
        self.drawAIAirframeFixedFeatures(painter, AIMainArea)
        self.drawAICompassDisk(painter, compassArea, compassHalfSpan)

        painter.setClipping(hadClip)
        if self.isGPSAltitudePrimary:
            self.drawAltimeter(painter, altimeterArea, self.GPSAltitude,
                               self.primaryAltitude, self.verticalVelocity)
        else:
            self.drawAltimeter(painter, altimeterArea, self.primaryAltitude,
                               self.GPSAltitude, self.verticalVelocity)
        if self.isGPSSpeedPrimary:
            self.drawVelocityMeter(painter, velocityMeterArea,
                                   self.groundspeed, self.primarySpeed)
        else:
            self.drawVelocityMeter(painter, velocityMeterArea,
                                   self.primarySpeed, self.groundspeed)
        painter.end()
Ejemplo n.º 18
0
class OverlayView(QGraphicsItem):
    """
    This is a "global" view which manages all of the line things:
        * edge views.
        * interlinks (domain-domain)
        * components
    
    It is actually a single graphics item drawn over the top of everything else.
    Therefore, it is passive and doesn't react with the user in any way.
    """
    def __init__(self, view_model: "ModelView") -> None:
        super().__init__()
        self.setZValue(DRAWING.Z_EDGES)
        self.view_model = view_model
        self.component_views: Dict[gr.Component, ComponentView] = {}
        self.interlink_views: Dict[gr.Domain, InterlinkView] = {}
        self.edge_views: Dict[gr.Edge, EdgeView] = {}

        # Create the edge views
        for edge in view_model.model.edges:
            self.edge_views[edge] = EdgeView(self, edge)

        # Create the component views
        for component in view_model.model.components:
            self.component_views[component] = ComponentView(self, component)

        # Create our interlink views
        for gene_view in view_model.gene_views.values():
            for left, right in array_helper.lagged_iterate(
                    gene_view.domain_views.values()):
                self.interlink_views[left] = InterlinkView(self, left, right)

        # Our bounds encompass the totality of the model
        # - find this!
        self.rect = QRectF(0, 0, 0, 0)

        for gene_view in view_model.gene_views.values():
            for domain_view in gene_view.domain_views.values():
                r = domain_view.window_rect()

                if r.left() < self.rect.left():
                    self.rect.setLeft(r.left())

                if r.right() > self.rect.right():
                    self.rect.setRight(r.right())

                if r.top() < self.rect.top():
                    self.rect.setTop(r.top())

                if r.bottom() > self.rect.bottom():
                    self.rect.setBottom(r.bottom())

        MARGIN = 256
        self.rect.setTop(self.rect.top() - MARGIN * 2)
        self.rect.setLeft(self.rect.left() - MARGIN * 2)
        self.rect.setBottom(self.rect.bottom() + MARGIN)
        self.rect.setRight(self.rect.right() + MARGIN)

    def boundingRect(self):
        return self.rect

    def paint(self,
              painter: QPainter,
              option: QStyleOptionGraphicsItem,
              widget: Optional[QWidget] = None) -> None:
        """
        Paint all edges
        """
        # Draw all the edges
        for edge_view in self.edge_views.values():
            edge_view.paint_edge(painter)

        # Draw all the components
        for component in self.component_views.values():
            component.paint_component(painter)

        # Draw all the interlinks
        for interlink in self.interlink_views.values():
            interlink.paint_interlink(painter)

        # Draw all the names
        for gene_view in self.view_model.gene_views.values():
            gene_view.paint_name(painter)
Ejemplo n.º 19
0
class GNodeSocket(QGraphicsWidget):
    edge_started = pyqtSignal(GEdge)
    edge_released = pyqtSignal(GEdge)
    connection_changed = pyqtSignal(object, object)  # Socket, Edge or None
    position_changed = pyqtSignal(QPointF)

    INPUT = SocketType.INPUT
    OUTPUT = SocketType.OUTPUT

    def __init__(self, parent_node: 'GShaderNode', socket: NodeSocket):
        super().__init__(parent=parent_node)
        self._socket = socket
        self._socket.set_container(self)
        self._parent_g_node = parent_node
        self._connected_g_edges = IndexedSet()

        # Define socket properties
        self._circle_connected_brush = QColor(
            255, 130, 0,
            255) if self._socket.type() == NodeSocket.INPUT else QColor(
                130, 255, 0, 255)
        self._circle_disconnected_brush = QColor(
            102, 50, 0,
            255) if self._socket.type() == NodeSocket.INPUT else QColor(
                50, 102, 0, 255)
        self._circle_hover_brush = QColor(
            170, 130, 0,
            255) if self._socket.type() == NodeSocket.INPUT else QColor(
                130, 170, 0, 255)
        self._border_connected_brush = QPen(QColor(255, 255, 255, 255))
        self._border_disconnected_brush = QPen(Qt.black)
        self._circle_brush = self._circle_disconnected_brush
        self._border_brush = self._border_disconnected_brush
        self._bbox = QRectF(0, 0, 10, 10)
        self._moving_edge = False
        self._current_edge = None
        self._layout = QGraphicsLinearLayout(Qt.Horizontal)

        self._init_socket()

    def _init_socket(self):
        self.setLayout(self._layout)
        self.setFlag(QGraphicsItem.ItemIsMovable, False)
        self.setFlag(QGraphicsItem.ItemSendsScenePositionChanges, True)
        self.setAcceptHoverEvents(True)

    def type(self) -> SocketType:
        return self._socket.type()

    def value(self):
        return self._socket.value()

    def set_value(self, value: typing.Any):
        self._socket.set_value(value)

    def save_value(self):
        """Saves the value of this socket internally. This value can be reassigned by calling 'restore_value()'."""

        self._socket.save_value()

    def restore_value(self):
        """Restores the value of this socket to the last saved value."""

        self._socket.restore_value()

    def parent_node(self) -> 'GShaderNode':
        return self._parent_g_node

    def get_size(self):
        """Returns a tuple with the width,height of this socket."""
        return self._bbox.right(), self._bbox.bottom()

    def get_backend_socket(self) -> NodeSocket:
        return self._socket

    def get_connected_nodes(self) -> typing.List['GShaderNode']:
        return [n.get_container() for n in self._socket.get_connected_nodes()]

    def get_connected_sockets(self) -> typing.List['GNodeSocket']:
        return [
            s.get_container() for s in self._socket.get_connected_sockets()
        ]

    def set_index(self, index: int):
        self._socket.set_index(index)

    def get_index(self) -> int:
        return self._socket.get_index()

    def is_connected(self) -> bool:
        return self._socket.is_connected()

    def boundingRect(self):
        return self._bbox

    def paint(self, painter: QPainter, option, widget=None):
        painter.setPen(self._border_brush)
        painter.setBrush(self._circle_brush)
        painter.drawEllipse(self._bbox)

    def get_scene_pos(self) -> QPointF:
        """Gets the center position of this socket in scene coordinates."""
        pos = self.scenePos()
        pos.setX(pos.x() + self._bbox.right() / 2)
        pos.setY(pos.y() + self._bbox.bottom() / 2)
        return pos

    def connect_to(self, socket: 'GNodeSocket') -> GEdge:
        """
        Connects this GNodeSocket to another GNodeSocket.
        :param other_socket: Other GNodeSocket to connect this socket to.
        :return: the GEdge that was created between the sockets, or the old GEdge if there already exists a connection.
        """
        edge = self._socket.connect_to(socket.get_backend_socket())

        # Only emit change event for input sockets, as nothing really changed for the output socket (at least not for the node as a whole)
        if self.type() == SocketType.INPUT:
            self.connection_changed.emit(self, edge)
        elif socket.type() == SocketType.INPUT:
            socket.connection_changed.emit(socket, edge)

        return GEdge.from_edge(edge)

    def get_connected_edges(self) -> IndexedSet:
        return self._connected_g_edges

    def add_connecting_edge(self, edge: GEdge):
        self._connected_g_edges.add(edge)

    def remove_connected_edge(self, gedge: GEdge):
        assert gedge in self._connected_g_edges

        self._connected_g_edges.remove(gedge)

    def label(self) -> str:
        return self._socket.label()

    def __eq__(self, other):
        if isinstance(other, GNodeSocket):
            return self._socket.__eq__(other.get_backend_socket())

        return False

    def __hash__(self):
        return self._socket.__hash__()

    def __str__(self):
        return self._socket.__str__()

    # -------- Event Handling ---------
    # ----------------------------------
    def hoverEnterEvent(self, event: QGraphicsSceneHoverEvent):
        # self._circle_brush = self._circle_hover_brush
        self._border_brush = self._border_connected_brush
        self.update()
        event.accept()

    def hoverLeaveEvent(self, event: QGraphicsSceneHoverEvent):
        # self._circle_brush = self._circle_connected_brush if self.connected else self._circle_disconnected_brush
        if not self.is_connected():
            self._border_brush = self._border_disconnected_brush
            self.update()

        event.accept()

    def mousePressEvent(self, event: QGraphicsSceneMouseEvent):
        # Needs to be reimplemented to be able to catch mouseMoveEvent, but it does not need to do anything
        event.accept()

    def mouseMoveEvent(self, event: QGraphicsSceneMouseEvent):
        if event.buttons() == Qt.LeftButton:
            if not self._moving_edge:
                if self.type() == self.INPUT:
                    edge = GEdge(destination=self)
                else:
                    edge = GEdge(source=self)
                self._current_edge = edge
                self._moving_edge = True
                self.edge_started.emit(edge)
            else:
                self._current_edge.set_tip_pos(event.scenePos())

            event.accept()
        else:
            event.ignore()

    def mouseReleaseEvent(self, event: QGraphicsSceneMouseEvent):
        if self._current_edge:  # Prevent release without dragging
            self.edge_released.emit(self._current_edge)
            self._current_edge = None
            self._moving_edge = False

    def itemChange(self, change, value):
        if change == self.ItemScenePositionHasChanged:

            for edge in self._connected_g_edges:
                edge.update_edge()

        return super().itemChange(change, value)
Ejemplo n.º 20
0
    def drawMagnifier(self):
        # First, calculate the magnifier position due to the mouse position
        watchAreaWidth = 16
        watchAreaHeight = 16
        watchAreaPixmap = QPixmap()

        cursor_pos = self.mousePoint

        watchArea = QRect(
            QPoint(cursor_pos.x() - watchAreaWidth / 2,
                   cursor_pos.y() - watchAreaHeight / 2),
            QPoint(cursor_pos.x() + watchAreaWidth / 2,
                   cursor_pos.y() + watchAreaHeight / 2))
        if watchArea.left() < 0:
            watchArea.moveLeft(0)
            watchArea.moveRight(watchAreaWidth)
        if self.mousePoint.x() + watchAreaWidth / 2 >= self.screenPixel.width(
        ):
            watchArea.moveRight(self.screenPixel.width() - 1)
            watchArea.moveLeft(watchArea.right() - watchAreaWidth)
        if self.mousePoint.y() - watchAreaHeight / 2 < 0:
            watchArea.moveTop(0)
            watchArea.moveBottom(watchAreaHeight)
        if self.mousePoint.y(
        ) + watchAreaHeight / 2 >= self.screenPixel.height():
            watchArea.moveBottom(self.screenPixel.height() - 1)
            watchArea.moveTop(watchArea.bottom() - watchAreaHeight)

        # tricks to solve the hidpi impact on QCursor.pos()
        watchArea.setTopLeft(
            QPoint(watchArea.topLeft().x() * self.scale,
                   watchArea.topLeft().y() * self.scale))
        watchArea.setBottomRight(
            QPoint(watchArea.bottomRight().x() * self.scale,
                   watchArea.bottomRight().y() * self.scale))
        watchAreaPixmap = self.screenPixel.copy(watchArea)

        # second, calculate the magnifier area
        magnifierAreaWidth = watchAreaWidth * 10
        magnifierAreaHeight = watchAreaHeight * 10
        fontAreaHeight = 40

        cursorSize = 24
        magnifierArea = QRectF(
            QPoint(QCursor.pos().x() + cursorSize,
                   QCursor.pos().y() + cursorSize),
            QPoint(QCursor.pos().x() + cursorSize + magnifierAreaWidth,
                   QCursor.pos().y() + cursorSize + magnifierAreaHeight))
        if magnifierArea.right() >= self.screenPixel.width():
            magnifierArea.moveLeft(QCursor.pos().x() - magnifierAreaWidth -
                                   cursorSize / 2)
        if magnifierArea.bottom() + fontAreaHeight >= self.screenPixel.height(
        ):
            magnifierArea.moveTop(QCursor.pos().y() - magnifierAreaHeight -
                                  cursorSize / 2 - fontAreaHeight)

        # third, draw the watch area to magnifier area
        watchAreaScaled = watchAreaPixmap.scaled(
            QSize(magnifierAreaWidth * self.scale,
                  magnifierAreaHeight * self.scale))
        magnifierPixmap = self.graphicsScene.addPixmap(watchAreaScaled)
        magnifierPixmap.setOffset(magnifierArea.topLeft())

        # then draw lines and text
        self.graphicsScene.addRect(QRectF(magnifierArea),
                                   QPen(QColor(255, 255, 255), 2))
        self.graphicsScene.addLine(
            QLineF(QPointF(magnifierArea.center().x(), magnifierArea.top()),
                   QPointF(magnifierArea.center().x(),
                           magnifierArea.bottom())),
            QPen(QColor(0, 255, 255), 2))
        self.graphicsScene.addLine(
            QLineF(QPointF(magnifierArea.left(),
                           magnifierArea.center().y()),
                   QPointF(magnifierArea.right(),
                           magnifierArea.center().y())),
            QPen(QColor(0, 255, 255), 2))

        # get the rgb of mouse point
        pointRgb = QColor(self.screenPixel.toImage().pixel(self.mousePoint))

        # draw information
        self.graphicsScene.addRect(
            QRectF(
                magnifierArea.bottomLeft(),
                magnifierArea.bottomRight() + QPoint(0, fontAreaHeight + 30)),
            Qt.black, QBrush(Qt.black))
        rgbInfo = self.graphicsScene.addSimpleText(
            ' Rgb: ({0}, {1}, {2})'.format(pointRgb.red(), pointRgb.green(),
                                           pointRgb.blue()))
        rgbInfo.setPos(magnifierArea.bottomLeft() + QPoint(0, 5))
        rgbInfo.setPen(QPen(QColor(255, 255, 255), 2))

        rect = self.selectedArea.normalized()
        sizeInfo = self.graphicsScene.addSimpleText(' Size: {0} x {1}'.format(
            rect.width() * self.scale,
            rect.height() * self.scale))
        sizeInfo.setPos(magnifierArea.bottomLeft() + QPoint(0, 15) +
                        QPoint(0, fontAreaHeight / 2))
        sizeInfo.setPen(QPen(QColor(255, 255, 255), 2))
Ejemplo n.º 21
0
class NodeItemRenderer:
    """ Class is used to separate the drawing from the logic.
        This class renders a given node to a graphics scene """

    __blobConnectorSizeWithPadding = Constants.nodeItemConnectorPaddding * 2 + Constants.connectorItemOuterSize

    def __init__(self, nodeItem):
        self.__nodeItem = nodeItem

        # create lists to store TextRects for the node item
        self.__headRects = list()
        self.__blobTopNameRects = list()
        self.__blobBottomNameRects = list()

        # create Qt rects for the head and body area
        self.__rectHead = QRectF(0, 0, 1, 1)
        self.__rectBlobArea = QRectF(0, 0, 1, 1)

        # create Qt rect for enclosing rects used as bounding rects
        self.__rectAll = QRectF(0, 0, 1, 1)
        self.__rectAllSelected = QRectF(0, 0, 1, 1)

        self.__hasCurrentPhase = True

        self.update()

    def boundingRect(self):
        # selected layers have a outer 'glow', so selected layers are bigger than not selected layers
        if self.__nodeItem.isSelected():
            return self.__rectAllSelected
        else:
            return self.__rectAll

    def update(self):
        """ Recalculates positions of name, type, blobs, etc. """

        # clear lists
        del self.__headRects[:]
        del self.__blobTopNameRects[:]
        del self.__blobBottomNameRects[:]

        # get size of the name
        nameWidth = Constants.nodeItemFontNameMetrics.width(
            self.__nodeItem.getName()) + Constants.nodeItemHeadPadding
        nameHeight = Constants.nodeItemFontTypeMetrics.height()
        self.__headRects.append(
            TextRect(self.__nodeItem.getName(),
                     QRectF(0, 0, nameWidth, nameHeight),
                     Constants.nodeItemFontName))

        # get size of the type
        typeWidth = Constants.nodeItemFontTypeMetrics.width(
            self.__nodeItem.getTypeString()) + Constants.nodeItemHeadPadding
        typeHeight = Constants.nodeItemFontTypeMetrics.height()
        self.__headRects.append(
            TextRect(self.__nodeItem.getTypeString(),
                     QRectF(0, 0, typeWidth, typeHeight),
                     Constants.nodeItemFontType))

        # get size of the phase (if the node has the paramter include.phase
        if len(self.__nodeItem.getPhase()) > 0:
            phaseString = "Phase: " + self.__nodeItem.getPhase()
            phaseWidth = Constants.nodeItemFontTypeMetrics.width(
                phaseString) + Constants.nodeItemHeadPadding
            phaseHeight = Constants.nodeItemFontTypeMetrics.height()
            self.__headRects.append(
                TextRect(phaseString, QRectF(0, 0, phaseWidth, phaseHeight),
                         Constants.nodeItemFontType))

        # calculate rect width and height for names of blobs
        topBlobsInfo = self.__buildBlobNameRectList(
            self.__nodeItem.getTopConnectors())
        bottomBlobsInfo = self.__buildBlobNameRectList(
            self.__nodeItem.getBottomConnectors())
        self.__blobTopNameRects = topBlobsInfo[0]
        self.__blobBottomNameRects = bottomBlobsInfo[0]

        blobAreaWidth = 2 * self.__blobConnectorSizeWithPadding + Constants.nodeItemConnectorPaddding + \
                        bottomBlobsInfo[1] + topBlobsInfo[1]
        blobAreaHeight = max(topBlobsInfo[2], bottomBlobsInfo[2],
                             Constants.nodeItemMinBlobAreaHeight)

        # calculate the total width of the node
        rectWidth = blobAreaWidth
        for textRect in self.__headRects:
            rectWidth = max(rectWidth, textRect.rect.width())

        # change the width of the head rects to be the full width of the node
        self.__updateHeadRects(rectWidth, self.__headRects)

        # calculate the total node height
        rectHeight = self.__rectHead.bottom() + blobAreaHeight

        # create Qt rects for the body and enclosing width the top left at (0, 0)
        self.__rectBlobArea = QRectF(0, self.__rectHead.bottom(), rectWidth,
                                     blobAreaHeight)
        self.__rectAll = QRectF(0, 0, rectWidth, rectHeight)

        # calculate a larger box to support selection (outer glow)
        selSize = Constants.nodeItemSelectionSize
        self.__rectAllSelected = QRectF(self.__rectAll.left() - selSize,
                                        self.__rectAll.top() - selSize,
                                        self.__rectAll.width() + 2 * selSize,
                                        self.__rectAll.height() + 2 * selSize)

        # after calculating the total width, adjust the name rects to align at the left/right
        self.__adjustBlobNameRectPositions(self.__blobTopNameRects,
                                           self.__rectAll.width(),
                                           self.__rectHead.bottom(), False)
        self.__adjustBlobNameRectPositions(self.__blobBottomNameRects,
                                           self.__rectAll.width(),
                                           self.__rectHead.bottom(), True)

    def __updateHeadRects(self, finalWidth, headRects):
        """ Resizes the size of the head text rect after the total needed width was calculated """

        totalHeadHeight = 0
        for x in range(0, len(headRects)):
            # special case for the first head text -> start at (0, 0) and has space at the top
            if x == 0:
                headRects[x].rect = QRectF(
                    0, 0, finalWidth,
                    headRects[x].rect.height() + Constants.nodeItemTextMargin)
            # special case for the last head text -> has space at the bottom
            elif x == len(headRects) - 1:
                headRects[x].rect = QRectF(
                    0, headRects[x - 1].rect.bottom(), finalWidth,
                    headRects[x].rect.height() + Constants.nodeItemTextMargin)
            else:
                headRects[x].rect = QRectF(0, headRects[x - 1].rect.bottom(),
                                           finalWidth,
                                           headRects[x].rect.height())

            # add the rects height to the total head rect height
            totalHeadHeight += headRects[x].rect.height()

        # create Qt rect for the head part
        self.__rectHead = QRectF(0, 0, finalWidth, totalHeadHeight)

    def __buildBlobNameRectList(self, connectors):
        """ Creates rects for all top/bottom connectors (bounding rect for the text only) """

        # check if the connector or the blob name text is higher
        blobNameHeightRect = max(Constants.nodeItemFontBlobMetrics.height(),
                                 self.__blobConnectorSizeWithPadding)

        blobNameRectList = list()

        maxWidth = 0
        height = 0

        # for each connector calculate the width of the name and create a Qt rect.
        # calculate the max width of all blob names and the total height
        for item in connectors:
            blobName = item.getBlobName()
            blobNameWidth = Constants.nodeItemFontBlobMetrics.width(
                blobName) + Constants.nodeItemTextMargin
            blobRect = QRectF(0, 0, blobNameWidth, blobNameHeightRect)
            blobNameRectList.append(TextRect(blobName, blobRect))
            maxWidth = max(maxWidth, blobNameWidth)
            height += blobNameHeightRect

        return blobNameRectList, maxWidth, height

    def __adjustBlobNameRectPositions(self, blobRectNames, totalWidth,
                                      aboveHeight, atLeftBorder):
        """ Recalculates the blob name rects after the total width of the node was calculated """
        i = 0

        for item in blobRectNames:
            # position at the left side of the node
            x = self.__blobConnectorSizeWithPadding

            # or position at the right side of the node
            if not atLeftBorder:
                x = totalWidth - self.__blobConnectorSizeWithPadding - item.rect.width(
                )

            # calculate starting position (head size + position in body)
            item.rect = QRectF(x, aboveHeight + i * item.rect.height(),
                               item.rect.width(), item.rect.height())

            i += 1

    def updateConnectorPositions(self, connectors, atLeftBorder):
        """ Repositions the connector items after the new size of the node was calculated """

        i = 0
        for item in connectors:
            # position the connector item at the left border of the node,left of the blob name rect
            x = Constants.nodeItemConnectorPaddding + Constants.connectorItemOuterSize / 2

            # or at the right border of the node, right of the blob name rect
            if not atLeftBorder:
                x = self.__rectAll.width() - Constants.nodeItemConnectorPaddding - Constants.connectorItemOuterSize + \
                    Constants.connectorItemOuterSize / 2

            # set the y coordinate of the connector item to be at the center of the blob name rect
            y = self.__rectHead.bottom() + Constants.nodeItemConnectorPaddding + Constants.connectorItemOuterSize / 2 + \
                i * self.__blobConnectorSizeWithPadding

            item.setPos(QPointF(x, y))
            i += 1

    def paint(self, painter):
        # use antialiasing for both text and box
        painter.setRenderHint(QPainter.Antialiasing, True)
        painter.setRenderHint(QPainter.TextAntialiasing, True)

        # get the opacity of the node item, layers with the include.phase parameter have a different opacity
        opacity = Constants.itemOpacityInPhase
        if not self.__nodeItem.getNodeEditor().isCurrentPhase(
                self.__nodeItem.getPhase()):
            opacity = Constants.itemOpacityNotInPhase

        # draw a outer 'glow' around the node item if the node is selected
        if self.__nodeItem.isSelected():
            selectedColor = Constants.selectedColor
            selectedColor.setAlpha(opacity)
            painter.setPen(QPen(selectedColor,
                                Constants.nodeItemSelectionSize))
            painter.drawRect(self.__rectAllSelected)
            painter.fillRect(self.__rectAllSelected, QBrush(selectedColor))

        # get the type color for the header (name and type)
        typeColor = LayerColorDefinitions.getTypeColor(
            self.__nodeItem.getType())
        typeColor.setRgb(typeColor.red(), typeColor.green(), typeColor.blue(),
                         opacity)

        # get background color
        backgroundColor = Constants.itemBackgroundColorLight
        backgroundColor.setAlpha(opacity)

        # set a linear gradient for the header (type color -> background color)
        gradient = QLinearGradient(0, self.__rectHead.top(), 0,
                                   self.__rectHead.bottom())
        gradient.setColorAt(0, typeColor)
        gradient.setColorAt(0.5, backgroundColor)

        # draw background and border for the header
        painter.fillRect(self.__rectHead, QBrush(gradient))

        # draw background for the blob area
        painter.fillRect(self.__rectBlobArea, QBrush(backgroundColor))
        borderColor = Constants.itemBorderColor
        if self.__nodeItem.getIsInPlace():
            borderColor = Constants.itemInPlaceColor
        borderColor.setAlpha(opacity)
        painter.setPen(QPen(borderColor, Constants.nodeItemBorderSize))

        # draw outer border around the node
        painter.drawRect(self.__rectAll)

        # draw a line to separate header and connectors
        borSize = Constants.nodeItemBorderSize
        painter.setPen(QPen(borderColor, borSize))
        painter.drawLine(self.__rectHead.left() + borSize / 2,
                         self.__rectHead.bottom() - borSize / 2,
                         self.__rectHead.right() - borSize / 2,
                         self.__rectHead.bottom() - borSize / 2)

        painter.setPen(QPen(QColor(0, 0, 0, opacity)))

        # draw text of header
        if len(self.__headRects) > 1:
            # align the first head text at the bottom to provide some space at the top
            painter.setFont(self.__headRects[0].font)
            painter.drawText(self.__headRects[0].rect,
                             Qt.AlignHCenter | Qt.AlignBottom,
                             self.__headRects[0].text)

            # align other head texts at the center
            for i in range(1, len(self.__headRects) - 1):
                painter.setFont(self.__headRects[i].font)
                painter.drawText(self.__headRects[i].rect, Qt.AlignCenter,
                                 self.__headRects[i].text)

            # align the last head text at the top to provide some space at the bottom
            painter.setFont(self.__headRects[-1].font)
            painter.drawText(self.__headRects[-1].rect,
                             Qt.AlignHCenter | Qt.AlignTop,
                             self.__headRects[-1].text)

        # there is only one head text, so align it at the center
        elif len(self.__headRects) == 1:
            painter.setFont(self.__headRects[0].font)
            painter.drawText(self.__headRects[0].rect,
                             Qt.AlignHCenter | Qt.AlignCenter,
                             self.__headRects[0].text)

        # draw blob names
        painter.setFont(Constants.nodeItemFontBlob)
        for item in self.__blobBottomNameRects:
            painter.drawText(item.rect, Qt.AlignVCenter | Qt.AlignLeft,
                             item.text)
        for item in self.__blobTopNameRects:
            painter.drawText(item.rect, Qt.AlignVCenter | Qt.AlignRight,
                             item.text)
Ejemplo n.º 22
0
    def translateItems(self, deltaX, deltaY):
        # Moving should only be enabled for node items
        if self.scene.selectedItems() and isinstance(
                self.scene.selectedItems()[0], NodeItem):

            # Prevent multiple layers from changing relative positions when the scenes border is reached
            selectedItems = self.scene.selectedItems()
            if len(selectedItems) > 0:
                selectedItemsBoundingRect = selectedItems[0].sceneBoundingRect(
                )

                for i in range(1, len(selectedItems)):
                    selectedItemsBoundingRect = selectedItemsBoundingRect.united(
                        selectedItems[i].sceneBoundingRect())

                # Fix for wrong scene bounding rects right and bottom
                selectedItemsBoundingRect.setWidth(
                    selectedItemsBoundingRect.width() + 3)
                selectedItemsBoundingRect.setHeight(
                    selectedItemsBoundingRect.height() + 3)

                newBoundingRect = QRectF(selectedItemsBoundingRect)
                newBoundingRect.moveTo(selectedItemsBoundingRect.topLeft() +
                                       QPointF(deltaX, deltaY))

                sceneRect = self.scene.sceneRect()

                moved = False
                if newBoundingRect.left() < sceneRect.left():
                    deltaX = sceneRect.left() - selectedItemsBoundingRect.left(
                    )
                    moved = True
                elif newBoundingRect.right() > sceneRect.right():
                    deltaX = sceneRect.right(
                    ) - selectedItemsBoundingRect.right()
                    moved = True

                if newBoundingRect.top() < sceneRect.top():
                    deltaY = sceneRect.top() - selectedItemsBoundingRect.top()
                    moved = True
                elif newBoundingRect.bottom() > sceneRect.bottom():
                    deltaY = sceneRect.bottom(
                    ) - selectedItemsBoundingRect.bottom()
                    moved = True

            for item in self.scene.selectedItems():
                item.setPos(item.scenePos() + QPointF(deltaX, deltaY))

            # Check if any of the objects have reached the boundary and the view should be translated
            if len(selectedItems) > 0:
                selectedItemsBoundingRect = selectedItems[0].sceneBoundingRect(
                )

                for i in range(1, len(selectedItems)):
                    selectedItemsBoundingRect = selectedItemsBoundingRect.united(
                        selectedItems[i].sceneBoundingRect())

                newRect = self.view.mapFromScene(
                    selectedItemsBoundingRect).boundingRect()

                if newRect.left() < 0 or newRect.right() > self.view.viewport(
                ).width() or newRect.top() < 0 or newRect.bottom(
                ) > self.view.viewport().height():
                    self.view.translate(-deltaX, -deltaY)
                    moved = True

            return moved
Ejemplo n.º 23
0
    def paintEvent(self, _):
        """
        重写绘制事件,参考 qfusionstyle.cpp 中的 CE_ProgressBarContents 绘制方法
        """
        option = QStyleOptionProgressBar()
        self.initStyleOption(option)

        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.translate(0.5, 0.5)

        vertical = option.orientation == Qt.Vertical  # 是否垂直
        inverted = option.invertedAppearance  # 是否反转
        # 是否显示动画
        indeterminate = (option.minimum == option.maximum) or (
            option.minimum < option.progress < option.maximum)
        rect = option.rect

        if vertical:
            rect = QRect(rect.left(), rect.top(), rect.height(),
                         rect.width())  # 翻转宽度和高度
            m = QTransform.fromTranslate(rect.height(), 0)
            m.rotate(90.0)
            painter.setTransform(m, True)

        maxWidth = rect.width()
        progress = max(option.progress, option.minimum)
        totalSteps = max(1, option.maximum - option.minimum)
        progressSteps = progress - option.minimum
        progressBarWidth = int(progressSteps * maxWidth / totalSteps)
        width = progressBarWidth  # 已进行的进度宽度
        radius = max(1, (min(width,
                             self.width() if vertical else self.height()) //
                         4) if self._radius is None else self._radius)

        reverse = (not vertical and
                   option.direction == Qt.RightToLeft) or vertical
        if inverted:
            reverse = not reverse

        # 绘制范围
        path = QPainterPath()
        if not reverse:
            progressBar = QRectF(rect.left(), rect.top(), width, rect.height())
        else:
            progressBar = QRectF(rect.right() - width, rect.top(), width,
                                 rect.height())

        # 切割范围
        path.addRoundedRect(progressBar, radius, radius)
        painter.setClipPath(path)

        # 绘制背景颜色
        painter.setPen(Qt.NoPen)
        painter.setBrush(self._color)
        painter.drawRoundedRect(progressBar, radius, radius)

        if not indeterminate:
            if self._animation:
                self._animation.stop()
                self._animation = None
        else:
            # 叠加颜色覆盖后出现类似线条间隔的效果
            color = self._color.lighter(320)
            color.setAlpha(80)
            painter.setPen(QPen(color, self._lineWidth))

            if self._animation:
                step = int(self._animation.animationStep() % self._lineWidth)
            else:
                step = 0
                self._animation = QProgressStyleAnimation(self._fps, self)
                self._animation.start()

            # 动画斜线绘制
            startX = int(progressBar.left() - rect.height() - self._lineWidth)
            endX = int(rect.right() + self._lineWidth)

            if (not inverted and not vertical) or (inverted and vertical):
                lines = [
                    QLineF(x + step, progressBar.bottom(),
                           x + rect.height() + step, progressBar.top())
                    for x in range(startX, endX, self._lineWidth)
                ]
            else:
                lines = [
                    QLineF(x - step, progressBar.bottom(),
                           x + rect.height() - step, progressBar.top())
                    for x in range(startX, endX, self._lineWidth)
                ]
            painter.drawLines(lines)
Ejemplo n.º 24
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.selection.setLeft(R.left())
            self.selection.setTop(R.top())

            self.background[self.indexT] = QPointF(R.left() + R.width() / 2,
                                                   R.top())
            self.background[self.indexB] = QPointF(
                R.left() + R.width() / 2, self.background[self.indexB].y())
            self.background[self.indexL] = QPointF(R.left(),
                                                   R.top() + R.height() / 2)
            self.background[self.indexE] = QPointF(R.left(),
                                                   R.top() + R.height() / 2)
            self.background[self.indexR] = QPointF(
                self.background[self.indexR].x(),
                R.top() + R.height() / 2)

            self.polygon[self.indexT] = QPointF(R.left() + R.width() / 2,
                                                R.top() + offset)
            self.polygon[self.indexB] = QPointF(R.left() + R.width() / 2,
                                                self.polygon[self.indexB].y())
            self.polygon[self.indexL] = QPointF(R.left() + offset,
                                                R.top() + R.height() / 2)
            self.polygon[self.indexE] = QPointF(R.left() + offset,
                                                R.top() + R.height() / 2)
            self.polygon[self.indexR] = QPointF(self.polygon[self.indexR].x(),
                                                R.top() + R.height() / 2)

        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.selection.setTop(R.top())

            self.background[self.indexT] = QPointF(
                self.background[self.indexT].x(), R.top())
            self.background[self.indexL] = QPointF(
                self.background[self.indexL].x(),
                R.top() + R.height() / 2)
            self.background[self.indexE] = QPointF(
                self.background[self.indexE].x(),
                R.top() + R.height() / 2)
            self.background[self.indexR] = QPointF(
                self.background[self.indexR].x(),
                R.top() + R.height() / 2)

            self.polygon[self.indexT] = QPointF(self.polygon[self.indexT].x(),
                                                R.top() + offset)
            self.polygon[self.indexL] = QPointF(self.polygon[self.indexL].x(),
                                                R.top() + R.height() / 2)
            self.polygon[self.indexE] = QPointF(self.polygon[self.indexE].x(),
                                                R.top() + R.height() / 2)
            self.polygon[self.indexR] = QPointF(self.polygon[self.indexR].x(),
                                                R.top() + R.height() / 2)

        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.selection.setRight(R.right())
            self.selection.setTop(R.top())

            self.background[self.indexT] = QPointF(R.right() - R.width() / 2,
                                                   R.top())
            self.background[self.indexB] = QPointF(
                R.right() - R.width() / 2, self.background[self.indexB].y())
            self.background[self.indexL] = QPointF(
                self.background[self.indexL].x(),
                R.top() + R.height() / 2)
            self.background[self.indexE] = QPointF(
                self.background[self.indexE].x(),
                R.top() + R.height() / 2)
            self.background[self.indexR] = QPointF(R.right(),
                                                   R.top() + R.height() / 2)

            self.polygon[self.indexT] = QPointF(R.right() - R.width() / 2,
                                                R.top() + offset)
            self.polygon[self.indexB] = QPointF(R.right() - R.width() / 2,
                                                self.polygon[self.indexB].y())
            self.polygon[self.indexL] = QPointF(self.polygon[self.indexL].x(),
                                                R.top() + R.height() / 2)
            self.polygon[self.indexE] = QPointF(self.polygon[self.indexE].x(),
                                                R.top() + R.height() / 2)
            self.polygon[self.indexR] = QPointF(R.right() - offset,
                                                R.top() + R.height() / 2)

        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.selection.setLeft(R.left())

            self.background[self.indexL] = QPointF(
                R.left(),
                self.mousePressBound.top() + self.mousePressBound.height() / 2)
            self.background[self.indexE] = QPointF(
                R.left(),
                self.mousePressBound.top() + self.mousePressBound.height() / 2)
            self.background[self.indexT] = QPointF(
                R.left() + R.width() / 2, self.background[self.indexT].y())
            self.background[self.indexB] = QPointF(
                R.left() + R.width() / 2, self.background[self.indexB].y())

            self.polygon[self.indexL] = QPointF(
                R.left() + offset,
                self.mousePressBound.top() + self.mousePressBound.height() / 2)
            self.polygon[self.indexE] = QPointF(
                R.left() + offset,
                self.mousePressBound.top() + self.mousePressBound.height() / 2)
            self.polygon[self.indexT] = QPointF(R.left() + R.width() / 2,
                                                self.polygon[self.indexT].y())
            self.polygon[self.indexB] = QPointF(R.left() + R.width() / 2,
                                                self.polygon[self.indexB].y())

        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.selection.setRight(R.right())

            self.background[self.indexR] = QPointF(
                R.right(),
                self.mousePressBound.top() + self.mousePressBound.height() / 2)
            self.background[self.indexT] = QPointF(
                R.right() - R.width() / 2, self.background[self.indexT].y())
            self.background[self.indexB] = QPointF(
                R.right() - R.width() / 2, self.background[self.indexB].y())

            self.polygon[self.indexR] = QPointF(
                R.right() - offset,
                self.mousePressBound.top() + self.mousePressBound.height() / 2)
            self.polygon[self.indexT] = QPointF(R.right() - R.width() / 2,
                                                self.polygon[self.indexT].y())
            self.polygon[self.indexB] = QPointF(R.right() - R.width() / 2,
                                                self.polygon[self.indexB].y())

        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.selection.setLeft(R.left())
            self.selection.setBottom(R.bottom())

            self.background[self.indexT] = QPointF(
                R.left() + R.width() / 2, self.background[self.indexT].y())
            self.background[self.indexB] = QPointF(R.left() + R.width() / 2,
                                                   R.bottom())
            self.background[self.indexL] = QPointF(R.left(),
                                                   R.bottom() - R.height() / 2)
            self.background[self.indexE] = QPointF(R.left(),
                                                   R.bottom() - R.height() / 2)
            self.background[self.indexR] = QPointF(
                self.background[self.indexR].x(),
                R.bottom() - R.height() / 2)

            self.polygon[self.indexT] = QPointF(R.left() + R.width() / 2,
                                                self.polygon[self.indexT].y())
            self.polygon[self.indexB] = QPointF(R.left() + R.width() / 2,
                                                R.bottom() - offset)
            self.polygon[self.indexL] = QPointF(R.left() + offset,
                                                R.bottom() - R.height() / 2)
            self.polygon[self.indexE] = QPointF(R.left() + offset,
                                                R.bottom() - R.height() / 2)
            self.polygon[self.indexR] = QPointF(self.polygon[self.indexR].x(),
                                                R.bottom() - R.height() / 2)

        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.selection.setBottom(R.bottom())

            self.background[self.indexB] = QPointF(
                self.background[self.indexB].x(), R.bottom())
            self.background[self.indexL] = QPointF(
                self.background[self.indexL].x(),
                R.top() + R.height() / 2)
            self.background[self.indexE] = QPointF(
                self.background[self.indexE].x(),
                R.top() + R.height() / 2)
            self.background[self.indexR] = QPointF(
                self.background[self.indexR].x(),
                R.top() + R.height() / 2)

            self.polygon[self.indexB] = QPointF(self.polygon[self.indexB].x(),
                                                R.bottom() - offset)
            self.polygon[self.indexL] = QPointF(self.polygon[self.indexL].x(),
                                                R.top() + R.height() / 2)
            self.polygon[self.indexE] = QPointF(self.polygon[self.indexE].x(),
                                                R.top() + R.height() / 2)
            self.polygon[self.indexR] = QPointF(self.polygon[self.indexR].x(),
                                                R.top() + R.height() / 2)

        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.selection.setRight(R.right())
            self.selection.setBottom(R.bottom())

            self.background[self.indexT] = QPointF(
                R.right() - R.width() / 2, self.background[self.indexT].y())
            self.background[self.indexB] = QPointF(R.right() - R.width() / 2,
                                                   R.bottom())
            self.background[self.indexL] = QPointF(
                self.background[self.indexL].x(),
                R.bottom() - R.height() / 2)
            self.background[self.indexE] = QPointF(
                self.background[self.indexE].x(),
                R.bottom() - R.height() / 2)
            self.background[self.indexR] = QPointF(R.right(),
                                                   R.bottom() - R.height() / 2)

            self.polygon[self.indexT] = QPointF(R.right() - R.width() / 2,
                                                self.polygon[self.indexT].y())
            self.polygon[self.indexB] = QPointF(R.right() - R.width() / 2,
                                                R.bottom() - offset)
            self.polygon[self.indexL] = QPointF(self.polygon[self.indexL].x(),
                                                R.bottom() - R.height() / 2)
            self.polygon[self.indexE] = QPointF(self.polygon[self.indexE].x(),
                                                R.bottom() - R.height() / 2)
            self.polygon[self.indexR] = QPointF(R.right() - offset,
                                                R.bottom() - R.height() / 2)

        self.updateHandles()
        self.updateTextPos(moved=moved)
        self.updateAnchors(self.mousePressData, D)
Ejemplo n.º 25
0
class TestPathFinding(TestCase):

################################################################################

    def setUp(self):
        """

        """

        #       --left     --right
        #       '          '
        #   I   |    II    |  III
        # ------+==========+------   --top
        #  VIII |  IX (in) |  IV
        # ------+==========+------   --bottom
        #  VII  |    VI    |   V

        self._offset = 10
        self._rect = QRectF(QPointF(-20, -10), QPointF(20, 10))
        self._pointI = QPointF(self._rect.left()-self._offset, self._rect.top()-self._offset)
        self._pointII = QPointF(self._rect.center().x(), self._rect.top()-self._offset)
        self._pointIII = QPointF(self._rect.right()+ self._offset, self._rect.top()- self._offset)
        self._pointIV = QPointF(self._rect.right()+self._offset, self._rect.center().y())
        self._pointV = QPointF(self._rect.right()+self._offset, self._rect.bottom()+self._offset)
        self._pointVI = QPointF(self._rect.center().x(), self._rect.bottom()+self._offset)
        self._pointVII = QPointF(self._rect.left()-self._offset, self._rect.bottom()+self._offset)
        self._pointVIII = QPointF(self._rect.left()-self._offset, self._rect.center().y())
        self._pointIX = self._rect.center()

        self._lineI_VII = QLineF(self._pointI, self._pointVII)
        self._lineI_V = QLineF(self._pointI, self._pointV)
        self._lineII = QLineF(self._pointII, QPointF(self._rect.center().x(), self._rect.top()))
        self._lineII_IV = QLineF(QPointF(self._rect.right()-self._offset, self._rect.top()-self._offset),
                                 QPointF(self._rect.right()+self._offset, self._rect.top()+self._offset))

################################################################################

    def testPointRectDist(self):
        """

        """

        lineI = PathFinding.pointRectDist(self._pointI, self._rect)
        self.assertEqual(lineI.p2(), self._rect.topLeft())
        self.assertEqual(lineI.length(), pow(pow(self._offset, 2)+pow(self._offset, 2), 0.5))
        lineII = PathFinding.pointRectDist(self._pointII, self._rect)
        self.assertEqual(lineII.p2(), QPointF(self._rect.center().x(), self._rect.top()))
        self.assertEqual(lineII.length(), self._offset)
        lineIII = PathFinding.pointRectDist(self._pointIII, self._rect)
        self.assertEqual(lineIII.p2(), self._rect.topRight())
        self.assertEqual(lineIII.length(), pow(pow(self._offset, 2)+pow(self._offset, 2), 0.5))
        lineIV = PathFinding.pointRectDist(self._pointIV, self._rect)
        self.assertEqual(lineIV.p2(), QPointF(self._rect.right(), self._rect.center().y()))
        self.assertEqual(lineIV.length(), self._offset)
        lineV = PathFinding.pointRectDist(self._pointV, self._rect)
        self.assertEqual(lineV.p2(), self._rect.bottomRight())
        self.assertEqual(lineV.length(), pow(pow(self._offset, 2)+pow(self._offset, 2), 0.5))
        lineVI = PathFinding.pointRectDist(self._pointVI, self._rect)
        self.assertEqual(lineVI.p2(), QPointF(self._rect.center().x(), self._rect.bottom()))
        self.assertEqual(lineVI.length(), self._offset)
        lineVII = PathFinding.pointRectDist(self._pointVII, self._rect)
        self.assertEqual(lineVII.p2(), self._rect.bottomLeft())
        self.assertEqual(lineVII.length(), pow(pow(self._offset, 2)+pow(self._offset, 2), 0.5))
        lineVIII = PathFinding.pointRectDist(self._pointVIII, self._rect)
        self.assertEqual(lineVIII.p2(), QPointF(self._rect.left(), self._rect.center().y()))
        self.assertEqual(lineVIII.length(), self._offset)
        lineIX = PathFinding.pointRectDist(self._pointIX, self._rect)
        self.assertEqual(lineIX.p2(), self._pointIX)
        self.assertEqual(lineIX.length(), 0)

################################################################################

    def testIntersects(self):
        """

        """

        rect = QRectF(QPointF(-50, -10), QPointF(50, 10))
        # line completely outside of the rectangle
        self.assertFalse(PathFinding.intersects(rect, QLineF(QPointF(-100, -50), QPointF(-100, 50))))
        # the line is a top side of the rectangle
        self.assertFalse(PathFinding.intersects(rect, QLineF(rect.topLeft(), rect.topRight())))
        # the line starts at the left corner of the rectangle and is not perpendicular to any of the rectangle sides;
        # the line ends outside of the rectangle, not going through it
        self.assertFalse(PathFinding.intersects(rect, QLineF(rect.topLeft(), QPointF(-100, -100))))
        # the line starts at the left corner of the rectangle and is perpendicular to the top side of the rectangle;
        # the line ends outside of the rectangle, not going through it
        self.assertFalse(PathFinding.intersects(rect, QLineF(rect.topLeft(), QPointF(rect.left(), rect.top() - 100))))
        # the line is horizontal and goes straight through the center of the rectangle
        self.assertTrue(PathFinding.intersects(rect, QLineF(QPointF(-100, 0), QPointF(100, 0))))
        # the line is vertical and goes straight through the center of the rectangle
        self.assertTrue(PathFinding.intersects(rect, QLineF(QPointF(0, -100), QPointF(0, 100))))
        # the line is vertical and goes up from the bottom right corner of the rectangle
        self.assertFalse(PathFinding.intersects(rect, QLineF(rect.bottomRight(), QPointF(rect.right(), rect.top()-100))))
        # the line is diagonal of the rectangle
        self.assertTrue(PathFinding.intersects(rect, QLineF(rect.topLeft(), rect.bottomRight())))
Ejemplo n.º 26
0
class DomainView(QGraphicsItem):
    """
    The basic and only interactive unit of the view.
    Paints a domain.
    
    We have an `is_selected` variable.
    This is independent and used in lieu of either Qt's selection or the selection on the groot form.   
    """
    def __init__(self, domain: gr.UserDomain, gene_view: "GeneView",
                 positional_index: int,
                 precursor: Optional["DomainView"]) -> None:
        """
        CONSTRUCTOR
        
        :param domain:             Domain to view 
        :param gene_view:              Owning view 
        :param positional_index:        Index of domain within gene 
        :param precursor:               Previous domain, or None 
        """
        assert isinstance(domain, gr.UserDomain)

        #
        # SUPER
        #
        super().__init__()
        self.setZValue(DRAWING.Z_GENE)

        #
        # FIELDS
        #
        self.gene_view = gene_view
        self.model_view = gene_view.model_view
        self.sibling_next: DomainView = None
        self.sibling_previous: DomainView = precursor
        self.domain: gr.UserDomain = domain
        self.mousedown_original_pos: QPointF = None
        self.mousemove_label: str = None
        self.mousemove_snapline: Tuple[int, int] = None
        self.mousedown_move_all = False
        self.index = positional_index
        self.is_selected = False
        self.colour = DRAWING.DEFAULT_COLOUR

        #
        # POSITION
        #
        table = gene_view.model_view.lookup_table
        self.rect = QRectF(0, 0, domain.length * table.letter_size,
                           table.gene_height)

        self.load_state()

        #
        # PRECURSOR
        #
        if precursor:
            precursor.sibling_next = self

        #
        # COMPONENTS
        #
        self.components: List[
            gr.
            Component] = self.model_view.model.components.find_components_for_minor_domain(
                self.domain)

    def get_x_for_site(self, site):
        offset = site - self.domain.start
        offset *= self.model_view.lookup_table.letter_size
        return self.x() + offset

    @property
    def options(self) -> groot.data.config.GlobalOptions:
        return groot.data.config.options()

    @property
    def model(self) -> gr.Model:
        return self.model_view.model

    def load_state(self):
        """
        Loads the state (position and colour) of this domain view from the options.
        If there is no saved state, the default is applied.
        """
        ac = (self.domain.gene.index, self.domain.start)
        position = self.model.lego_domain_positions.get(ac)

        if not isinstance(position, dict):
            self.reset_state()
            return

        x = position.get("x", 0)
        y = position.get("y", 0)
        c = position.get("c", DRAWING.DEFAULT_COLOUR.colour.name())

        self.setPos(x, y)
        self.colour = ColourBlock(QColor(c))

    def save_state(self):
        """
        Saves the state (position) of this domain view to the options.
        """
        ac = (self.domain.gene.index, self.domain.start)
        self.model.lego_domain_positions[ac] = {
            "x": self.pos().x(),
            "y": self.pos().y(),
            "c": self.colour.colour.name()
        }

    def reset_state(self):
        """
        Resets the state (position and colour) of this domain view to the default.
        The reset state is automatically saved to the options.
        """
        table = self.gene_view.model_view.lookup_table
        precursor = self.sibling_previous
        domain = self.domain

        if precursor:
            x = precursor.window_rect().right()
            y = precursor.window_rect().top()
        else:
            x = domain.start * table.letter_size
            y = domain.gene.index * (table.gene_ysep + table.gene_height)

        self.setPos(x, y)
        self.colour = DRAWING.DEFAULT_COLOUR
        self.save_state()

    @override
    def boundingRect(self) -> QRectF:
        return self.rect

    @override
    def paint(self, painter: QPainter, *args, **kwargs):
        """
        Paint the domains
        """
        r = self.rect
        painter.setBrush(self.colour.brush)
        painter.setPen(self.colour.pen)
        painter.drawRect(r)

        is_selected = self.is_selected

        # Movement is allowed if we have enabled it
        move_enabled = misc_helper.coalesce(
            self.options.lego_move_enabled,
            self.gene_view.model_view.user_move_enabled)

        # Draw the piano roll unless we're moving
        if self.options.lego_view_piano_roll is False or move_enabled:
            draw_piano_roll = False
        elif self.options.lego_view_piano_roll is None:
            draw_piano_roll = is_selected
        else:
            draw_piano_roll = not is_selected

        # Draw the selection bars, unless the piano roll is indicative of this already
        draw_sel_bars = is_selected and not draw_piano_roll

        # Selection bars
        # (A blue box inside the gene box)
        if draw_sel_bars:
            self.__paint_selection_rect(painter)

        # Movement bars
        # (The same as the selection bars but dotted in red and cyan)
        if move_enabled and is_selected:
            self.__paint_movement_rect(painter)

        # Piano roll
        # (A piano roll for genes)
        if draw_piano_roll:
            lookup_table = self.model_view.lookup_table
            letter_size = lookup_table.letter_size
            painter.setPen(Qt.NoPen)
            painter.setBrush(
                DRAWING.PIANO_ROLL_SELECTED_BACKGROUND
                if is_selected else DRAWING.PIANO_ROLL_UNSELECTED_BACKGROUND)
            OFFSET_X = letter_size
            rect_width = self.rect.width()
            rect_height = lookup_table.count * letter_size
            painter.drawRect(0, OFFSET_X, rect_width, rect_height)

            array = self.domain.site_array

            if not array:
                painter.setPen(Pens.RED)
                painter.drawLine(0, 0, rect_width, rect_height)
                painter.drawLine(0, rect_height, rect_width, 0)
            else:
                for i, c in enumerate(array):
                    pos = lookup_table.letter_order_table.get(c)

                    if pos is not None:
                        painter.setPen(
                            lookup_table.letter_colour_table.get(
                                c, DRAWING.GENE_DEFAULT_FG))
                        painter.drawEllipse(i * letter_size,
                                            pos * letter_size + OFFSET_X,
                                            letter_size, letter_size)

        # Snap-lines, when moving
        if self.mousemove_snapline:
            x = self.mousemove_snapline[0] - self.pos().x()
            y = self.mousemove_snapline[1] - self.pos().y()
            painter.setPen(DRAWING.SNAP_LINE_2)
            painter.drawLine(x, self.boundingRect().height() / 2, x, y)
            painter.setPen(DRAWING.SNAP_LINE)
            painter.drawLine(x, self.boundingRect().height() / 2, x, y)
            if not self.mousemove_label.startswith("<"):
                x -= QFontMetrics(painter.font()).width(self.mousemove_label)

            if y < 0:
                y = self.rect.top() - DRAWING.TEXT_MARGIN
            else:
                y = self.rect.bottom() + DRAWING.TEXT_MARGIN + QFontMetrics(
                    painter.font()).xHeight()
            painter.setPen(DRAWING.TEXT_LINE)
            painter.drawText(QPointF(x, y),
                             self.mousemove_label)  # Mouse snapline position
        elif self.mousemove_label:
            painter.setPen(DRAWING.TEXT_LINE)
            painter.drawText(
                QPointF(self.rect.left() + DRAWING.TEXT_MARGIN,
                        self.rect.top() - DRAWING.TEXT_MARGIN),
                self.mousemove_label)  # Mouse position

        if not move_enabled:
            # Positions (when not in move mode)
            if misc_helper.coalesce(self.options.lego_view_positions,
                                    is_selected):
                # Draw position
                if self.sibling_previous is None or self.sibling_next is None or self.sibling_previous.rect.width(
                ) > 32:
                    self.__draw_position(painter)

            # Domains (when not in move mode)
            if misc_helper.coalesce(self.options.lego_view_components,
                                    is_selected):
                self.__draw_component_name(painter)

    def __draw_component_name(self, painter: QPainter):
        text = ", ".join(str(x) for x in self.components)
        x = (self.rect.left() + self.rect.right()) / 2 - QFontMetrics(
            painter.font()).width(text) / 2
        y = self.rect.top() - DRAWING.TEXT_MARGIN

        painter.setPen(DRAWING.COMPONENT_PEN)
        painter.setBrush(0)
        painter.drawText(QPointF(x, y), text)

    def __draw_position(self, painter: QPainter):
        text = str(self.domain.start)
        lx = self.rect.left() - QFontMetrics(painter.font()).width(text) / 2

        painter.setPen(DRAWING.POSITION_TEXT)
        painter.drawText(QPointF(lx,
                                 self.rect.top() - DRAWING.TEXT_MARGIN), text)

    def __paint_movement_rect(self, painter: QPainter):
        r = self.rect
        MARGIN = 4
        painter.setBrush(0)
        painter.setPen(DRAWING.MOVE_LINE)
        painter.drawRect(r.left() + MARGIN,
                         r.top() + MARGIN,
                         r.width() - MARGIN * 2,
                         r.height() - MARGIN * 2)
        painter.setPen(DRAWING.MOVE_LINE_SEL)
        painter.drawRect(r.left() + MARGIN,
                         r.top() + MARGIN,
                         r.width() - MARGIN * 2,
                         r.height() - MARGIN * 2)
        # Black start/end when in movement mode if domain isn't adjacent to its siblings
        if self.sibling_next and self.sibling_next.window_rect().left(
        ) != self.window_rect().right():
            MARGIN = 8
            painter.setPen(DRAWING.DISJOINT_LINE)
            painter.drawLine(r.right(),
                             r.top() - MARGIN, r.right(),
                             r.bottom() + MARGIN)
        if self.sibling_previous and self.sibling_previous.window_rect().right(
        ) != self.window_rect().left():
            MARGIN = 8
            painter.setPen(DRAWING.DISJOINT_LINE)
            painter.drawLine(r.left(),
                             r.top() - MARGIN, r.left(),
                             r.bottom() + MARGIN)

    def __paint_selection_rect(self, painter: QPainter):
        r = self.rect
        MARGIN = 4
        painter.setBrush(0)
        painter.setPen(DRAWING.SELECTION_LINE)
        painter.drawRect(r.left() + MARGIN,
                         r.top() + MARGIN,
                         r.width() - MARGIN * 2,
                         r.height() - MARGIN * 2)

    def __is_draw_position(self, is_selected):
        return misc_helper.coalesce(self.options.lego_view_positions,
                                    is_selected)

    def __draw_next_sibling_position(self, is_selected):
        ns = self.sibling_next

        if ns is None:
            return False

        if not ns.__is_draw_position(is_selected):
            return False

        return ns.pos().x() == self.window_rect().right()

    def window_rect(self) -> QRectF:
        result = self.boundingRect().translated(self.scenePos())
        assert result.left() == self.pos().x(), "{} {}".format(
            self.window_rect().left(),
            self.pos().x())  # todo: remove
        assert result.top() == self.pos().y()
        return result

    def mousePressEvent(self, m: QGraphicsSceneMouseEvent):
        """
        OVERRIDE
        Mouse press on domain view
        i.e. Use clicks a domain
        """
        if m.buttons() & Qt.LeftButton:
            # Remember the initial position items in case we drag stuff
            # - do this for all items because it's still possible for the selection to change post-mouse-down
            for item in self.gene_view.domain_views.values():
                item.mousedown_original_pos = item.pos()

            # If ctrl or meta is down, add to the selection
            if (m.modifiers() & Qt.ControlModifier) or (m.modifiers()
                                                        & Qt.MetaModifier):
                toggle = True
            else:
                toggle = False

            if self.is_selected:
                # If we are selected stop, this confuses with dragging from a design perspective
                return

            self.model_view.handle_domain_clicked(self.domain, toggle)

    def mouseDoubleClickEvent(self, m: QGraphicsSceneMouseEvent):
        """
        OVERRIDE
        Double click
        Just toggles "move enabled" 
        """
        self.model_view.user_move_enabled = not self.model_view.user_move_enabled
        self.model_view.scene.setBackgroundBrush(QBrush(QColor(255, 255, 0)))
        self.model_view.scene.update()

    def focusInEvent(self, QFocusEvent):
        self.setZValue(DRAWING.Z_FOCUS)

    def focusOutEvent(self, QFocusEvent):
        self.setZValue(DRAWING.Z_GENE)

    def snaps(self):
        for gene_view in self.gene_view.model_view.gene_views.values():
            for domain_view in gene_view.domain_views.values():
                if domain_view is not self:
                    left_snap = domain_view.scenePos().x()
                    right_snap = domain_view.scenePos().x(
                    ) + domain_view.boundingRect().width()
                    yield left_snap, "Start of {}[{}]".format(
                        domain_view.domain.gene,
                        domain_view.domain.start), domain_view.scenePos().y()
                    yield right_snap, "End of {}[{}]".format(
                        domain_view.domain.gene,
                        domain_view.domain.end), domain_view.scenePos().y()

    def mouseMoveEvent(self, m: QGraphicsSceneMouseEvent) -> None:
        if m.buttons() & Qt.LeftButton:
            if not misc_helper.coalesce(
                    self.options.lego_move_enabled, self.model_view.
                    user_move_enabled) or self.mousedown_original_pos is None:
                return

            new_pos: QPointF = self.mousedown_original_pos + (
                m.scenePos() - m.buttonDownScenePos(Qt.LeftButton))
            new_x = new_pos.x()
            new_y = new_pos.y()
            new_x2 = new_x + self.boundingRect().width()

            self.mousemove_label = "({0} {1})".format(new_pos.x(), new_pos.y())
            self.mousemove_snapline = None

            x_snap_enabled = misc_helper.coalesce(
                self.options.lego_x_snap,
                not bool(m.modifiers() & Qt.ControlModifier))
            y_snap_enabled = misc_helper.coalesce(
                self.options.lego_y_snap,
                not bool(m.modifiers() & Qt.AltModifier))

            if x_snap_enabled:
                for snap_x, snap_label, snap_y in self.snaps():
                    if (snap_x - 8) <= new_x <= (snap_x + 8):
                        new_x = snap_x
                        self.mousemove_label = "<-- " + snap_label
                        self.mousemove_snapline = snap_x, snap_y
                        break
                    elif (snap_x - 8) <= new_x2 <= (snap_x + 8):
                        new_x = snap_x - self.boundingRect().width()
                        self.mousemove_label = snap_label + " -->"
                        self.mousemove_snapline = snap_x, snap_y
                        break

            if y_snap_enabled:
                ysep = self.rect.height()
                yy = (self.rect.height() + ysep)
                new_y += yy / 2
                new_y = new_y - new_y % yy

            new_pos.setX(new_x)
            new_pos.setY(new_y)

            self.setPos(new_pos)
            self.save_state()

            delta_x = new_x - self.mousedown_original_pos.x()
            delta_y = new_y - self.mousedown_original_pos.y()

            selected_items = self.model_view.get_selected_userdomain_views()

            for selected_item in selected_items:
                if selected_item is not self and selected_item.mousedown_original_pos is not None:
                    selected_item.setPos(
                        selected_item.mousedown_original_pos.x() + delta_x,
                        selected_item.mousedown_original_pos.y() + delta_y)
                    selected_item.save_state()

            self.model_view.overlay_view.update()

    def mouseReleaseEvent(self, m: QGraphicsSceneMouseEvent):
        self.mousemove_label = None
        self.mousemove_snapline = None
        self.update()
        pass  # suppress default mouse handling implementation

    def __repr__(self):
        return "<<View of '{}' at ({},{})>>".format(self.domain,
                                                    self.window_rect().left(),
                                                    self.window_rect().top())
 def coerceInside(point: QPointF, rect: QRectF):
     return QPointF(
         min(max(point.x(), rect.left()), rect.right()),
         min(max(point.y(), rect.top()), rect.bottom()),
     )
Ejemplo n.º 28
0
 def point_is_outside(self, point: QPointF, bounds: QRectF):
     return point.x() < bounds.left() or point.x() > bounds.right() or point.y() < bounds.top() or point.y() > bounds.bottom()
Ejemplo n.º 29
0
        xoffset = -h if is_fwd else h
        w = end_poly.boundingRect().width()
        yoffset = w if is_fwd else -w
        angle = -90 if is_fwd else 90
        T = QTransform()
        T.translate(next_pt.x()+xoffset, next_pt.y()+yoffset)
        T.rotate(angle)
        path.addPolygon(T.map(end_poly))
    return path
# end def


# create hash marks QPainterPaths only once
LO_X = BASE_RECT.left()
HI_X = BASE_RECT.right()
BOT_Y = BASE_RECT.bottom()+BASE_WIDTH/5
TOP_Y = BASE_RECT.top()-BASE_WIDTH/5
WIDTH_X = BASE_WIDTH/3
HEIGHT_Y = BASE_WIDTH/3

FWD_L1 = QPointF(LO_X, BOT_Y)
FWD_L2 = QPointF(LO_X+WIDTH_X, BOT_Y)
FWD_L3 = QPointF(LO_X+WIDTH_X, BOT_Y-HEIGHT_Y)
FWD_H1 = QPointF(HI_X, BOT_Y)
FWD_H2 = QPointF(HI_X-WIDTH_X, BOT_Y)
FWD_H3 = QPointF(HI_X-WIDTH_X, BOT_Y-HEIGHT_Y)
REV_L1 = QPointF(LO_X, TOP_Y)
REV_L2 = QPointF(LO_X+WIDTH_X, TOP_Y)
REV_L3 = QPointF(LO_X+WIDTH_X, TOP_Y+HEIGHT_Y)
REV_H1 = QPointF(HI_X, TOP_Y)
REV_H2 = QPointF(HI_X-WIDTH_X, TOP_Y)
Ejemplo n.º 30
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)
Ejemplo n.º 31
0
 def nextTick(self):
     self.time += 1
     if (self.time >= 180 and self.time <= 300 and self.time % 20 == 0):
         Enemy1()
         Enemy2()
     elif self.time == 360:
         Enemy3()
     elif (self.time >= 400 and self.time < 700 and self.time % 20 == 0):
         Enemy4()
     elif (self.time >= 800 and self.time < 1100 and self.time % 20 == 0):
         Enemy5()
         if self.time == 840:
             Enemy6()
     elif (self.time >= 1200 and self.time < 1500 and self.time % 20 == 0):
         Enemy4(20)
     elif (self.time >= 1600 and self.time < 1900 and self.time % 20 == 0):
         Enemy5()
         if self.time % 30 == 0:
             Enemy6()
     elif self.time >= 2000 and self.time < 2810 and self.time % 30 == 0:
         Enemy7()
         Enemy8()
     elif self.time == 2870:
         Enemy9()
     elif self.time == 3050:
         Enemy10(100)
     elif self.time == 3220:
         Enemy10(-100)
     elif self.time == 3400:
         Enemy10(100)
         Enemy10(-100)
     elif self.time == 3700:
         for i in range(10):
             Enemy12(i)
     elif self.time == 3900:
         for i in range(10):
             Enemy13(i)
     elif self.time == 4100:
         for i in range(10):
             Enemy12(i)
     elif self.time == 4300:
         for i in range(10):
             Enemy13(i)
     elif self.time == 4500:
         Enemy15()
     else:
         pass
     ################################################
     enemyComs = Component.components.get('enemy')
     danComs = Component.components.get('dan')
     dans = None
     if danComs is not None:
         dans = [Entity.entities.get(danCom.id) for danCom in danComs]
     if enemyComs is None:
         return
     removes = []
     for enemyCom in enemyComs:
         enemy = enemyCom.enemy
         position = enemy.positionCom
         size = enemy.sizeCom
         if self.isOut(position, size):
             removes.append(enemy)
             continue
         # 检测Dan碰撞
         if dans is None:
             continue
         for dan in dans:
             danSize = dan.sizeCom
             # 左上角坐标
             danPosition = dan.positionCom
             enemySize = enemy.sizeCom
             enemyPosition = enemy.positionCom
             danRect = QRectF(danPosition.x + 14, danPosition.y,
                              danSize.width, danSize.height)
             enemyRect = QRectF(enemyPosition.x, enemyPosition.y,
                                enemySize.width, enemySize.height)
             xCo = (danRect.right() > enemyRect.left()
                    and danRect.right() < enemyRect.right()) or (
                        danRect.left() > enemyRect.left()
                        and danRect.left() < enemyRect.right())
             yCo = (danRect.top() > enemyRect.top()
                    and danRect.top() < enemyRect.bottom()) or (
                        danRect.bottom() > enemyRect.top()
                        and danRect.bottom() < enemyRect.bottom())
             co = xCo and yCo
             if co:
                 # scorexxx
                 self.score.value += 10
                 dan.destory()
                 enemy.healthCom.decrease()
                 if enemy.healthCom.dead():
                     self.score.value += 300
                     removes.append(enemy)
     enemy_remove = set(removes)
     for enemy in enemy_remove:
         enemy.destroy()
Ejemplo n.º 32
0
class Callout(QGraphicsItem):
    def __init__(self, chart):
        super().__init__(chart)

        self.m_chart = chart
        self.m_text = ""
        self.m_textRect = QRectF()
        self.m_rect = QRectF()
        self.m_anchor = QPointF()
        self.m_font = QFont()

    def boundingRect(self):
        anchor = self.mapFromParent(self.m_chart.mapToPosition(self.m_anchor))
        rect = QRectF()
        rect.setLeft(min(self.m_rect.left(), anchor.x()))
        rect.setRight(max(self.m_rect.right(), anchor.x()))
        rect.setTop(min(self.m_rect.top(), anchor.y()))
        rect.setBottom(max(self.m_rect.bottom(), anchor.y()))
        return rect

    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)

    def mousePressEvent(self, event):
        event.setAccepted(True)

    def mouseMoveEvent(self, event):
        if event.buttons() & Qt.LeftButton:
            self.setPos(
                self.mapToParent(event.pos() -
                                 event.buttonDownPos(Qt.LeftButton)))
            event.setAccepted(True)
        else:
            event.setAccepted(False)

    def setText(self, text):
        self.m_text = text
        metrics = QFontMetrics(self.m_font)
        self.m_textRect = QRectF(
            metrics.boundingRect(QRect(0, 0, 150, 150), Qt.AlignLeft,
                                 self.m_text))
        self.m_textRect.translate(5, 5)
        self.prepareGeometryChange()
        self.m_rect = self.m_textRect.adjusted(-5, -5, 5, 5)

    def setAnchor(self, point):
        self.m_anchor = point

    def updateGeometry(self):
        self.prepareGeometryChange()
        self.setPos(
            self.m_chart.mapToPosition(self.m_anchor) + QPoint(10, -50))
Ejemplo n.º 33
0
    def paintEvent(self,event):
        global monster_data
        global dmg
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.drawPixmap(event.rect(),self.pixmap)

        if self.card is not None and self.card.ID is not 0:
            card = self.card
            # Draw card level at the bottom centered
            pen = QPen()
            if np.floor(card.lv) == monster_data[card.ID]['max_level']:
                lvstr = 'Lv.Max'
                brush = QBrush(QColor(252,232,131))
            else:
                lvstr = 'Lv.%d' % np.floor(card.lv)
                brush = QBrush(Qt.white)

            path = QPainterPath()
            pen.setWidth(0);
            pen.setBrush(Qt.black)

            font = QFont()
            font.setPointSize(11)
            font.setWeight(QFont.Black)
            
            path.addText(event.rect().x(),event.rect().y()+48,font,lvstr)

            rect = path.boundingRect()
            target = (event.rect().x()+event.rect().width())/2

            # center the rect in event.rect()
            path.translate(target-rect.center().x(), 0)

            painter.setPen(pen)
            painter.setBrush(QBrush(Qt.black))
            painter.drawPath(path.translated(.5,.5))

            painter.setPen(pen)
            painter.setBrush(brush)

            painter.drawPath(path)

            # Draw +eggs at the top right
            eggs = card.plus_atk+card.plus_hp+card.plus_rcv
            if eggs > 0:
                eggstr = '+%d' % eggs
                pen.setBrush(Qt.yellow)
                brush = QBrush(Qt.yellow)

                path = QPainterPath()
                pen.setWidth(0)
                pen.setBrush(Qt.black)
                font = QFont()
                font.setPointSize(11)
                font.setWeight(QFont.Black)
                path.addText(event.rect().x(),event.rect().y()+12,font,eggstr)

                path.translate(50-path.boundingRect().right()-3,0)
                #painter.setFont(font)
                painter.setPen(pen)
                painter.setBrush(QBrush(Qt.black))
                painter.drawPath(path.translated(.5,.5))

                painter.setPen(pen)
                painter.setBrush(brush)
                painter.drawPath(path)
                #painter.drawText(event.rect().adjusted(0,0,0,0),Qt.AlignRight, eggstr)

            # Draw awakenings at the top left in a green circle
            if card.current_awakening > 0:
                path = QPainterPath()
                rect = QRectF(event.rect()).adjusted(4,4,-36,-36)
                path.addEllipse(rect)
                painter.setBrush(QBrush(QColor(34,139,34)))
                pen.setBrush(Qt.white)
                pen.setWidth(1)
                painter.setPen(pen)
                painter.drawPath(path)

                path = QPainterPath()
                font.setPointSize(9)
                awkstr = ('%d' % card.current_awakening if
                        card.current_awakening < card.max_awakening else
                        '★')
                path.addText(rect.x(),rect.bottom(),font,awkstr)
                
                br = path.boundingRect()
                path.translate(rect.center().x()-br.center().x(),
                        rect.center().y()-br.center().y())

                pen.setBrush(QColor(0,0,0,0))
                pen.setWidth(0)
                painter.setPen(pen)
                painter.setBrush(QBrush(Qt.yellow))
                painter.drawPath(path)

            # Draw main attack damage
            #print(self.main_attack)
            if self.main_attack > 0:
                matkstr = '%d' % self.main_attack
                painter.setBrush(QBrush(COLORS[self.card.element[0]]))
                path = QPainterPath()
                font = QFont()
                font.setFamily('Helvetica')
                font.setWeight(QFont.Black)
                #font.setStretch(25)
                font.setPointSize(13)
                path.addText(rect.x(),rect.bottom(),font,matkstr)

                rect = QRectF(event.rect())
                br = path.boundingRect()
                path.translate(rect.center().x()-br.center().x(),
                        rect.center().y()-br.bottom()-1)

                # 
                pen.setBrush(Qt.black)
                pen.setWidthF(.75)
                painter.setPen(pen)
                painter.drawPath(path)

            # Draw sub attack damage
            #print(self.main_attack)
            if self.sub_attack > 0:
                satkstr = '%d' % self.sub_attack
                painter.setBrush(QBrush(COLORS[self.card.element[1]]))
                path = QPainterPath()
                font = QFont()
                font.setFamily('Helvetica')
                font.setWeight(QFont.Black)
                #font.setStretch(25)
                font.setPointSize(12)
                path.addText(rect.x(),rect.bottom(),font,satkstr)

                rect = QRectF(event.rect())
                br = path.boundingRect()
                path.translate(rect.center().x()-br.center().x(),
                        rect.center().y()-br.top()+1)

                # 
                pen.setBrush(Qt.black)
                pen.setWidthF(.75)
                painter.setPen(pen)
                painter.drawPath(path)
Ejemplo n.º 34
0
class Game(QObject):

    # 클래스 변수
    update_signal = pyqtSignal()
    gameover_signal = pyqtSignal(int)

    def __init__(self, w):
        super().__init__()
        self.parent = w
        self.rect = w.rect()

        # 바둑판 사각형
        self.outrect = QRectF(self.rect)
        gap = 10
        self.outrect.adjust(gap, gap, -gap, -gap)

        # 바둑돌 놓는 사각형
        self.inrect = QRectF(self.outrect)
        gap = 20
        self.inrect.adjust(gap, gap, -gap, -gap)

        self.line = 19
        self.size = self.inrect.width() / (self.line - 1)

        # 바둑돌
        self.wdol = []
        self.bdol = []
        self.bTrun = True

        # 바둑돌 중간 교차점
        x = self.inrect.left()
        y = self.inrect.top()
        self.cpt = [[
            QPointF(x + (self.size * c), y + (self.size * r))
            for c in range(self.line)
        ] for r in range(self.line)]
        #print(self.cpt)

        # 바둑판 상태 저장 0:돌없음, 1:흑돌, 2:백돌
        self.state = [[0 for c in range(self.line)] for r in range(self.line)]
        #print(self.state)

        # 시그널, 슬롯
        self.update_signal.connect(self.parent.update)
        self.gameover_signal.connect(self.parent.gameOver)

    def draw(self, qp):
        b = QBrush(QColor(175, 150, 75))
        qp.setBrush(b)
        qp.drawRect(self.outrect)

        x = self.inrect.left()
        y = self.inrect.top()

        x1 = self.inrect.right()
        y1 = self.inrect.top()

        x2 = self.inrect.left()
        y2 = self.inrect.bottom()

        # 바둑판 줄 그리기
        for i in range(self.line):
            qp.drawLine(x, y + (self.size * i), x1, y1 + (self.size * i))
            qp.drawLine(x + (self.size * i), y, x2 + (self.size * i), y2)

        # 흑돌 그리기
        b = QBrush(Qt.black)
        qp.setBrush(b)
        for dol in self.bdol:
            x = dol.x() - self.size / 2
            y = dol.y() - self.size / 2
            rect = QRectF(x, y, self.size, self.size)
            qp.drawEllipse(rect)

        # 백돌 그리기
        b = QBrush(Qt.white)
        qp.setBrush(b)
        for dol in self.wdol:
            x = dol.x() - self.size / 2
            y = dol.y() - self.size / 2
            rect = QRectF(x, y, self.size, self.size)
            qp.drawEllipse(rect)

    def mouseDown(self, x, y):
        # 바둑판 안에 두었는지?
        #T = self.inrect.top()
        #B = self.inrect.bottom()
        #L = self.inrect.left()
        #R = self.inrect.right()
        #if (x>L and x<R) and (y>T and y<B):
        if self.inrect.contains(QPointF(x, y)):
            row, col = self.getCP(x, y)
            print('row:', row, 'col:', col)

            # 돌이 없으면
            if self.state[row][col] == 0:
                if self.bTrun:
                    self.state[row][col] = 1
                    self.bdol.append(self.cpt[row][col])
                else:
                    self.state[row][col] = 2
                    self.wdol.append(self.cpt[row][col])

                self.bTrun = not self.bTrun
                self.update_signal.emit()

                # 판정 0:진행중, 1:흑돌승, 2:백돌승, 3:무승부
                result = self.panjung()
                if result != 0:
                    self.gameover_signal.emit(result)

            else:
                QMessageBox.warning(self.parent, '오류', '이미 돌이 있습니다',
                                    QMessageBox.Ok)
        else:
            QMessageBox.warning(self.parent, '오류', '바둑판 안에 돌을 놓으세요',
                                QMessageBox.Ok)

    def getCP(self, x, y):
        s = self.size
        for r in range(self.line):
            for c in range(self.line):
                pt = self.cpt[r][c]
                _x = pt.x()
                _y = pt.y()
                rect = QRectF(_x - s / 2, _y - s / 2, s, s)
                if rect.contains(QPointF(x, y)):
                    return r, c

    def panjung(self):
        # 판정 0:진행중, 1:흑돌승, 2:백돌승, 3:무승부

        cnt = 0
        for r in range(self.line):
            for c in range(self.line):
                # 무승부
                if self.state[r][c] != 0:
                    cnt += 1

                # 흑돌 가로 판정
                if c <= 14:
                    if (self.state[r][c] == 1 and self.state[r][c + 1] == 1
                            and self.state[r][c + 2] == 1
                            and self.state[r][c + 3] == 1
                            and self.state[r][c + 4] == 1):
                        return 1
                # 흑돌 세로 판정
                if r <= 14:
                    if (self.state[r][c] == 1 and self.state[r + 1][c] == 1
                            and self.state[r + 2][c] == 1
                            and self.state[r + 3][c] == 1
                            and self.state[r + 4][c] == 1):
                        return 1
                # 흑돌 대각(좌우) 판정
                if r <= 14 and c <= 14:
                    if (self.state[r][c] == 1 and self.state[r + 1][c + 1] == 1
                            and self.state[r + 2][c + 2] == 1
                            and self.state[r + 3][c + 3] == 1
                            and self.state[r + 4][c + 4] == 1):
                        return 1
                # 흑돌 대각(우좌) 판정
                if r <= 14 and c >= 4:
                    if (self.state[r][c] == 1 and self.state[r + 1][c - 1] == 1
                            and self.state[r + 2][c - 2] == 1
                            and self.state[r + 3][c - 3] == 1
                            and self.state[r + 4][c - 4] == 1):
                        return 1
                # 백돌 가로 판정
                if c <= 14:
                    if (self.state[r][c] == 2 and self.state[r][c + 1] == 2
                            and self.state[r][c + 2] == 2
                            and self.state[r][c + 3] == 2
                            and self.state[r][c + 4] == 2):
                        return 2
                # 백돌 세로 판정
                if r <= 14:
                    if (self.state[r][c] == 2 and self.state[r + 1][c] == 2
                            and self.state[r + 2][c] == 2
                            and self.state[r + 3][c] == 2
                            and self.state[r + 4][c] == 2):
                        return 2
                # 백돌 대각(좌우) 판정
                if r <= 14 and c <= 14:
                    if (self.state[r][c] == 2 and self.state[r + 1][c + 1] == 2
                            and self.state[r + 2][c + 2] == 2
                            and self.state[r + 3][c + 3] == 2
                            and self.state[r + 4][c + 4] == 2):
                        return 2
                # 백돌 대각(우좌) 판정
                if r <= 14 and c >= 4:
                    if (self.state[r][c] == 2 and self.state[r + 1][c - 1] == 2
                            and self.state[r + 2][c - 2] == 2
                            and self.state[r + 3][c - 3] == 2
                            and self.state[r + 4][c - 4] == 2):
                        return 2

        if cnt == self.line * self.line:
            return 3

        return 0
Ejemplo n.º 35
0
        w = end_poly.boundingRect().width()
        yoffset = w if is_fwd else -w
        angle = -90 if is_fwd else 90
        T = QTransform()
        T.translate(next_pt.x() + xoffset, next_pt.y() + yoffset)
        T.rotate(angle)
        path.addPolygon(T.map(end_poly))
    return path


# end def

# create hash marks QPainterPaths only once
LO_X = BASE_RECT.left()
HI_X = BASE_RECT.right()
BOT_Y = BASE_RECT.bottom() + BASE_WIDTH / 5
TOP_Y = BASE_RECT.top() - BASE_WIDTH / 5
WIDTH_X = BASE_WIDTH / 3
HEIGHT_Y = BASE_WIDTH / 3

FWD_L1 = QPointF(LO_X, BOT_Y)
FWD_L2 = QPointF(LO_X + WIDTH_X, BOT_Y)
FWD_L3 = QPointF(LO_X + WIDTH_X, BOT_Y - HEIGHT_Y)
FWD_H1 = QPointF(HI_X, BOT_Y)
FWD_H2 = QPointF(HI_X - WIDTH_X, BOT_Y)
FWD_H3 = QPointF(HI_X - WIDTH_X, BOT_Y - HEIGHT_Y)
REV_L1 = QPointF(LO_X, TOP_Y)
REV_L2 = QPointF(LO_X + WIDTH_X, TOP_Y)
REV_L3 = QPointF(LO_X + WIDTH_X, TOP_Y + HEIGHT_Y)
REV_H1 = QPointF(HI_X, TOP_Y)
REV_H2 = QPointF(HI_X - WIDTH_X, TOP_Y)