Beispiel #1
0
class LinkCurveItem(QGraphicsPathItem):
    """
    Link curve item. The main component of a :class:`LinkItem`.
    """
    def __init__(self, parent):
        QGraphicsPathItem.__init__(self, parent)
        if not isinstance(parent, LinkItem):
            raise TypeError("'LinkItem' expected")

        self.setAcceptedMouseButtons(Qt.NoButton)
        self.__canvasLink = parent
        self.setAcceptHoverEvents(True)

        self.shadow = QGraphicsDropShadowEffect(blurRadius=5,
                                                color=QColor(SHADOW_COLOR),
                                                offset=QPointF(0, 0))

        self.normalPen = QPen(QBrush(QColor("#9CACB4")), 2.0)
        self.hoverPen = QPen(QBrush(QColor("#7D7D7D")), 2.1)
        self.setPen(self.normalPen)
        self.setGraphicsEffect(self.shadow)
        self.shadow.setEnabled(False)

        self.__hover = False
        self.__enabled = True
        self.__shape = None

    def linkItem(self):
        """
        Return the :class:`LinkItem` instance this curve belongs to.
        """
        return self.__canvasLink

    def setHoverState(self, state):
        self.prepareGeometryChange()
        self.__shape = None
        self.__hover = state
        self.__update()

    def setLinkEnabled(self, state):
        self.prepareGeometryChange()
        self.__shape = None
        self.__enabled = state
        self.__update()

    def isLinkEnabled(self):
        return self.__enabled

    def setCurvePenSet(self, pen, hoverPen):
        self.prepareGeometryChange()
        if pen is not None:
            self.normalPen = pen
        if hoverPen is not None:
            self.hoverPen = hoverPen
        self.__shape = None
        self.__update()

    def shape(self):
        if self.__shape is None:
            path = self.path()
            pen = QPen(self.pen())
            pen.setWidthF(max(pen.widthF(), 7.0))
            pen.setStyle(Qt.SolidLine)
            self.__shape = stroke_path(path, pen)
        return self.__shape

    def setPath(self, path):
        self.__shape = None
        QGraphicsPathItem.setPath(self, path)

    def __update(self):
        shadow_enabled = self.__hover
        if self.shadow.isEnabled() != shadow_enabled:
            self.shadow.setEnabled(shadow_enabled)

        link_enabled = self.__enabled
        if link_enabled:
            pen_style = Qt.SolidLine
        else:
            pen_style = Qt.DashLine

        if self.__hover:
            pen = self.hoverPen
        else:
            pen = self.normalPen

        pen.setStyle(pen_style)
        self.setPen(pen)
Beispiel #2
0
class NodeBodyItem(GraphicsPathObject):
    """
    The central part (body) of the `NodeItem`.
    """
    def __init__(self, parent=None):
        GraphicsPathObject.__init__(self, parent)
        assert(isinstance(parent, NodeItem))

        self.__processingState = 0
        self.__progress = -1
        self.__animationEnabled = False
        self.__isSelected = False
        self.__hasFocus = False
        self.__hover = False
        self.__shapeRect = QRectF(-10, -10, 20, 20)

        self.setAcceptHoverEvents(True)

        self.setFlag(QGraphicsItem.ItemSendsScenePositionChanges, True)
        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)

        self.setPen(QPen(Qt.NoPen))

        self.setPalette(default_palette())

        self.shadow = QGraphicsDropShadowEffect(
            blurRadius=3,
            color=QColor(SHADOW_COLOR),
            offset=QPointF(0, 0),
            )

        self.setGraphicsEffect(self.shadow)
        self.shadow.setEnabled(True)

        self.__blurAnimation = QPropertyAnimation(self.shadow, b"blurRadius",
                                                  self)
        self.__blurAnimation.setDuration(100)
        self.__blurAnimation.finished.connect(self.__on_finished)

        self.__pingAnimation = QPropertyAnimation(self, b"scale", self)
        self.__pingAnimation.setDuration(250)
        self.__pingAnimation.setKeyValues([(0.0, 1.0), (0.5, 1.1), (1.0, 1.0)])

    # TODO: The body item should allow the setting of arbitrary painter
    # paths (for instance rounded rect, ...)
    def setShapeRect(self, rect):
        """
        Set the item's shape `rect`. The item should be confined within
        this rect.

        """
        path = QPainterPath()
        path.addEllipse(rect)
        self.setPath(path)
        self.__shapeRect = rect

    def setPalette(self, palette):
        """
        Set the body color palette (:class:`QPalette`).
        """
        self.palette = palette
        self.__updateBrush()

    def setAnimationEnabled(self, enabled):
        """
        Set the node animation enabled.
        """
        if self.__animationEnabled != enabled:
            self.__animationEnabled = enabled

    def setProcessingState(self, state):
        """
        Set the processing state of the node.
        """
        if self.__processingState != state:
            self.__processingState = state
            if not state and self.__animationEnabled:
                self.ping()

    def setProgress(self, progress):
        """
        Set the progress indicator state of the node. `progress` should
        be a number between 0 and 100.

        """
        self.__progress = progress
        self.update()

    def ping(self):
        """
        Trigger a 'ping' animation.
        """
        animation_restart(self.__pingAnimation)

    def hoverEnterEvent(self, event):
        self.__hover = True
        self.__updateShadowState()
        return GraphicsPathObject.hoverEnterEvent(self, event)

    def hoverLeaveEvent(self, event):
        self.__hover = False
        self.__updateShadowState()
        return GraphicsPathObject.hoverLeaveEvent(self, event)

    def paint(self, painter, option, widget):
        """
        Paint the shape and a progress meter.
        """
        # Let the default implementation draw the shape
        if option.state & QStyle.State_Selected:
            # Prevent the default bounding rect selection indicator.
            option.state = option.state ^ QStyle.State_Selected
        GraphicsPathObject.paint(self, painter, option, widget)
        if self.__progress >= 0:
            # Draw the progress meter over the shape.
            # Set the clip to shape so the meter does not overflow the shape.
            painter.setClipPath(self.shape(), Qt.ReplaceClip)
            color = self.palette.color(QPalette.ButtonText)
            pen = QPen(color, 5)
            painter.save()
            painter.setPen(pen)
            painter.setRenderHints(QPainter.Antialiasing)
            span = max(1, int(self.__progress * 57.60))
            painter.drawArc(self.__shapeRect, 90 * 16, -span)
            painter.restore()

    def __updateShadowState(self):
        if self.__hasFocus:
            color = QColor(FOCUS_OUTLINE_COLOR)
            self.setPen(QPen(color, 1.5))
        else:
            self.setPen(QPen(Qt.NoPen))

        radius = 3
        enabled = False

        if self.__isSelected:
            enabled = True
            radius = 7

        if self.__hover:
            radius = 17
            enabled = True

        if enabled and not self.shadow.isEnabled():
            self.shadow.setEnabled(enabled)

        if self.__animationEnabled:
            if self.__blurAnimation.state() == QPropertyAnimation.Running:
                self.__blurAnimation.pause()

            self.__blurAnimation.setStartValue(self.shadow.blurRadius())
            self.__blurAnimation.setEndValue(radius)
            self.__blurAnimation.start()
        else:
            self.shadow.setBlurRadius(radius)

    def __updateBrush(self):
        palette = self.palette
        if self.__isSelected:
            cg = QPalette.Active
        else:
            cg = QPalette.Inactive

        palette.setCurrentColorGroup(cg)
        c1 = palette.color(QPalette.Light)
        c2 = palette.color(QPalette.Button)
        grad = radial_gradient(c2, c1)
        self.setBrush(QBrush(grad))

    # TODO: The selected and focus states should be set using the
    # QStyle flags (State_Selected. State_HasFocus)

    def setSelected(self, selected):
        """
        Set the `selected` state.

        .. note:: The item does not have `QGraphicsItem.ItemIsSelectable` flag.
                  This property is instead controlled by the parent NodeItem.

        """
        self.__isSelected = selected
        self.__updateBrush()

    def setHasFocus(self, focus):
        """
        Set the `has focus` state.

        .. note:: The item does not have `QGraphicsItem.ItemIsFocusable` flag.
                  This property is instead controlled by the parent NodeItem.

        """
        self.__hasFocus = focus
        self.__updateShadowState()

    def __on_finished(self):
        if self.shadow.blurRadius() == 0:
            self.shadow.setEnabled(False)