예제 #1
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))
예제 #2
0
    def create_drop_indicator_pixmap(palette, size, drop_area):
        border_color = palette.color(QPalette.Active, QPalette.Highlight)
        background_color = palette.color(QPalette.Active, QPalette.Base)
        area_background_color = palette.color(QPalette.Active,
                                              QPalette.Highlight).lighter(150)

        pm = QPixmap(size.width(), size.height())
        pm.fill(QColor(0, 0, 0, 0))

        painter = QPainter(pm)
        pen = painter.pen()
        base_rect = QRectF(pm.rect())

        painter.fillRect(base_rect, background_color)

        painter.save()
        area_rect = QRectF()
        area_line = QLineF()
        gradient = QLinearGradient()
        if drop_area == DropArea.TopDropArea:
            area_rect = QRectF(base_rect.x(), base_rect.y(), base_rect.width(),
                               base_rect.height() * 0.5)
            area_line = QLineF(area_rect.bottomLeft(), area_rect.bottomRight())
            gradient.setStart(area_rect.topLeft())
            gradient.setFinalStop(area_rect.bottomLeft())
            gradient.setColorAt(0, area_background_color)
            gradient.setColorAt(1, area_background_color.lighter(120))
        elif drop_area == DropArea.RightDropArea:
            area_rect = QRectF(base_rect.width() * 0.5, base_rect.y(),
                               base_rect.width() * 0.5, base_rect.height())
            area_line = QLineF(area_rect.topLeft(), area_rect.bottomLeft())
            gradient.setStart(area_rect.topLeft())
            gradient.setFinalStop(area_rect.topRight())
            gradient.setColorAt(0, area_background_color.lighter(120))
            gradient.setColorAt(1, area_background_color)
        elif drop_area == DropArea.BottomDropArea:
            area_rect = QRectF(base_rect.x(),
                               base_rect.height() * 0.5, base_rect.width(),
                               base_rect.height() * 0.5)
            area_line = QLineF(area_rect.topLeft(), area_rect.topRight())
            gradient.setStart(area_rect.topLeft())
            gradient.setFinalStop(area_rect.bottomLeft())
            gradient.setColorAt(0, area_background_color.lighter(120))
            gradient.setColorAt(1, area_background_color)
        elif drop_area == DropArea.LeftDropArea:
            area_rect = QRectF(base_rect.x(), base_rect.y(),
                               base_rect.width() * 0.5, base_rect.height())
            area_line = QLineF(area_rect.topRight(), area_rect.bottomRight())
            gradient.setStart(area_rect.topLeft())
            gradient.setFinalStop(area_rect.topRight())
            gradient.setColorAt(0, area_background_color)
            gradient.setColorAt(1, area_background_color.lighter(120))

        if area_rect.isValid():
            painter.fillRect(area_rect, gradient)
            pen = painter.pen()
            pen.setColor(border_color)
            pen.setStyle(Qt.DashLine)
            painter.setPen(pen)
            painter.drawLine(area_line)

        painter.restore()

        painter.save()
        pen = painter.pen()
        pen.setColor(border_color)
        pen.setWidth(1)

        painter.setPen(pen)
        painter.drawRect(base_rect.adjusted(0, 0, -pen.width(), -pen.width()))
        painter.restore()

        return pm
예제 #3
0
class JoyPad(QWidget, object):

    xChanged = Signal(float)
    yChanged = Signal(float)

    def __init__(self, parent=None):
        super(JoyPad, self).__init__(parent=parent)

        self._x = 0
        self._y = 0
        self._bounds = QRectF()
        self._knop_bounds = QRectF()
        self._last_pos = QPoint()
        self._knop_pressed = False

        self._return_animation = QParallelAnimationGroup(self)
        self._x_anim = QPropertyAnimation(self, 'x')
        self._y_anim = QPropertyAnimation(self, 'y')
        self._alignment = Qt.AlignTop | Qt.AlignLeft

        self._x_anim.setEndValue(0.0)
        self._x_anim.setDuration(400)
        self._x_anim.setEasingCurve(QEasingCurve.OutSine)

        self._y_anim.setEndValue(0.0)
        self._y_anim.setDuration(400)
        self._y_anim.setEasingCurve(QEasingCurve.OutSine)

        self._return_animation.addAnimation(self._x_anim)
        self._return_animation.addAnimation(self._y_anim)

    # region Static Functions
    @staticmethod
    def constraint(value, min_value, max_value):
        return min_value if value < min_value else max_value if value > max_value else value

    # endregion

    # region Properties
    def get_x(self):
        return self._x

    def set_x(self, x):
        self._x = self.constraint(x, -1.0, 1.0)
        radius = (self._bounds.width() - self._knop_bounds.width()) * 0.5
        self._knop_bounds.moveCenter(
            QPointF(self._bounds.center().x() + self._x * radius,
                    self._knop_bounds.center().y()))
        self.update()
        self.xChanged.emit(self._x)

    def get_y(self):
        return self._y

    def set_y(self, y):
        self._y = self.constraint(y, -1.0, 1.0)
        radius = (self._bounds.width() - self._knop_bounds.width()) * 0.5
        self._knop_bounds.moveCenter(
            QPointF(self._knop_bounds.center().x(),
                    self._bounds.center().y() - self._y * radius))
        self.update()
        self.yChanged.emit(self._x)

    def get_alignment(self):
        return self._alignment

    def set_alignment(self, alignment):
        self._alignment = alignment

    x = property(get_x, set_x)
    y = property(get_y, set_y)
    alignment = property(get_alignment, set_alignment)

    # endregion

    # region Override Functions
    def resizeEvent(self, event):
        a = min(self.width(), self.height())
        top_left = QPointF()
        if self._alignment & Qt.AlignTop:
            top_left.setY(0)
        elif self._alignment & Qt.AlignVCenter:
            top_left.setY((self.height() - a) * 0.5)
        elif self._alignment & Qt.AlignBottom:
            top_left.setY(self.height() - a)

        if self._alignment & Qt.AlignLeft:
            top_left.setX(0)
        elif self._alignment & Qt.AlignHCenter:
            top_left.setX((self.width() - a) * 0.5)
        elif self._alignment & Qt.AlignRight:
            top_left.setX(self.width() - a)

        self._bounds = QRectF(top_left, QSize(a, a))
        self._knop_bounds.setWidth(a * 0.3)
        self._knop_bounds.setHeight(a * 0.3)

        radius = (self._bounds.width() - self._knop_bounds.height()) * 0.5
        self._knop_bounds.moveCenter(
            QPointF(self._bounds.center().x() + self._x * radius,
                    self._bounds.center().y() - self._y * radius))

    def mousePressEvent(self, event):
        if self._knop_bounds.contains(event.pos()):
            # self._return_animation.stop()
            self._last_pos = event.pos()
            self._knop_pressed = True

    def mouseReleaseEvent(self, event):
        self._knop_pressed = False
        self.x = 0.0
        self.y = 0.0
        # self._return_animation.start()

    def mouseMoveEvent(self, event):
        if not self._knop_pressed:
            return

        delta_pos = QPointF(event.pos() - self._last_pos)
        delta_pos += 0.5 * (QPointF(event.pos()) - self._knop_bounds.center())

        from_center_to_knop = self._knop_bounds.center(
        ) + delta_pos - self._bounds.center()
        radius = (self._bounds.width() - self._knop_bounds.width()) * 0.5
        from_center_to_knop.setX(
            self.constraint(from_center_to_knop.x(), -radius, radius))
        from_center_to_knop.setY(
            self.constraint(from_center_to_knop.y(), -radius, radius))
        self._knop_bounds.moveCenter(from_center_to_knop +
                                     self._bounds.center())
        self._last_pos = event.pos()

        self.update()

        if radius == 0:
            return
        x = (self._knop_bounds.center().x() -
             self._bounds.center().x()) / radius
        y = (-self._knop_bounds.center().y() +
             self._bounds.center().y()) / radius

        if self._x != x:
            self._x = x
            self.xChanged.emit(self._x)

        if self._y != y:
            self._y = y
            self.yChanged.emit(self._y)

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.setRenderHint(QPainter.HighQualityAntialiasing)

        gradient = QRadialGradient(self._bounds.center(),
                                   self._bounds.width() * 0.5,
                                   self._bounds.center())
        gradient.setFocalRadius(self._bounds.width() * 0.3)
        gradient.setCenterRadius(self._bounds.width() * 0.7)
        gradient.setColorAt(0, Qt.white)
        gradient.setColorAt(1, Qt.lightGray)

        painter.setPen(QPen(QBrush(Qt.gray), self._bounds.width() * 0.005))
        painter.setBrush(QBrush(gradient))
        painter.drawEllipse(self._bounds)

        painter.setPen(QPen(QBrush(Qt.gray), self._bounds.width() * 0.005))
        painter.drawLine(
            QPointF(self._bounds.left(),
                    self._bounds.center().y()),
            QPointF(self._bounds.center().x() - self._bounds.width() * 0.35,
                    self._bounds.center().y()))
        painter.drawLine(
            QPointF(self._bounds.center().x() + self._bounds.width() * 0.35,
                    self._bounds.center().y()),
            QPointF(self._bounds.right(),
                    self._bounds.center().y()))
        painter.drawLine(
            QPointF(self._bounds.center().x(), self._bounds.top()),
            QPointF(self._bounds.center().x(),
                    self._bounds.center().y() - self._bounds.width() * 0.35))
        painter.drawLine(
            QPointF(self._bounds.center().x(),
                    self._bounds.center().y() + self._bounds.width() * 0.35),
            QPointF(self._bounds.center().x(), self._bounds.bottom()))

        if not self.isEnabled():
            return

        gradient = QRadialGradient(self._knop_bounds.center(),
                                   self._knop_bounds.width() * 0.5,
                                   self._knop_bounds.center())
        gradient.setFocalRadius(self._knop_bounds.width() * 0.2)
        gradient.setCenterRadius(self._knop_bounds.width() * 0.5)
        gradient.setColorAt(0, Qt.gray)
        gradient.setColorAt(1, Qt.darkGray)

        painter.setPen(QPen(QBrush(Qt.darkGray), self._bounds.width() * 0.005))
        painter.setBrush(QBrush(gradient))
        painter.drawEllipse(self._knop_bounds)

        # endregion

    # region Public Functions
    def add_x_animation(self):
        # Abort if the animation is already added
        if self._x_anim.parent() == self._return_animation:
            return

        self._return_animation.addAnimation(self._x_anim)

    def remove_x_animation(self):
        # Abort if the animation is already removed
        if self._x_anim.parent() != self._return_animation:
            return

        self._return_animation.removeAnimation(self._x_anim)

        # Take ownership of the animation (parent is 0 after removeAnimation())
        self._x_anim.setParent(self)

    def add_y_animation(self):
        # Abort if the animation is already added
        if self._y_anim.parent() == self._return_animation:
            return

        self._return_animation.addAnimation(self._y_anim)

    def remove_y_animation(self):
        # Abort if the animation is already removed
        if self._y_anim.parent() != self._return_animation:
            return

        self._return_animation.removeAnimation(self._y_anim)

        # Take ownership of the animation (parent is 0 after removeAnimation())
        self._y_anim.setParent(self)