Example #1
0
def path_link_disabled(basepath):
    """
    Return a QPainterPath 'styled' to indicate a 'disabled' link.

    A disabled link is displayed with a single disconnection symbol in the
    middle (--||--)

    Parameters
    ----------
    basepath : QPainterPath
        The base path (a simple curve spine).

    Returns
    -------
    path : QPainterPath
        A 'styled' link path
    """
    segmentlen = basepath.length()
    px = 5

    if segmentlen < 10:
        return QPainterPath(basepath)

    t = (px / 2) / segmentlen
    p1, _ = qpainterpath_simple_split(basepath, 0.50 - t)
    _, p2 = qpainterpath_simple_split(basepath, 0.50 + t)

    angle = -basepath.angleAtPercent(0.5) + 90
    angler = math.radians(angle)
    normal = QPointF(math.cos(angler), math.sin(angler))

    end1 = p1.currentPosition()
    start2 = QPointF(p2.elementAt(0).x, p2.elementAt(0).y)
    p1.moveTo(start2.x(), start2.y())
    p1.addPath(p2)

    def QPainterPath_addLine(path, line):
        path.moveTo(line.p1())
        path.lineTo(line.p2())

    QPainterPath_addLine(p1, QLineF(end1 - normal * 3, end1 + normal * 3))
    QPainterPath_addLine(p1, QLineF(start2 - normal * 3, start2 + normal * 3))
    return p1
    def paint(self, painter, option, widget=None):
        color, _ = Edge.Color.SELECTED if self.selected else Edge.Color.DEFAULT
        pen = self.pen()
        pen.setColor(color)
        pen.setBrush(QBrush(color))
        pen.setWidth(np.clip(2 * self.weight(), .5, 4))
        painter.setPen(pen)
        self.setPen(pen)

        if self.source == self.dest:
            return self.paintArc(painter, option, widget)
        if self.source.collidesWithItem(self.dest):
            return

        have_two_edges = len([
            edge for edge in self.source.edges
            if self.source in edge and self.dest in edge and edge is not self
        ])

        source_pos = self.source.pos()
        dest_pos = self.dest.pos()

        color = self.pen().color()
        painter.setBrush(color)

        point = shape_line_intersection(self.dest.shape(), dest_pos,
                                        QLineF(source_pos, dest_pos))
        line = QLineF(source_pos, point)
        if have_two_edges:
            normal = line.normalVector()
            normal.setLength(15)
            line = QLineF(normal.p2(), point)
            self.label.setPos(line.pointAt(.5))
            self.squares.placeBelow(self.label)

        self.setLine(line)
        painter.drawLine(line)

        # Draw arrow head
        self.arrowHead.clear()
        for point in self._arrowhead_points(line):
            self.arrowHead.append(point)
        painter.drawPolygon(self.arrowHead)
Example #3
0
 def update_anchors(self):
     points, labels = self.master.get_anchors()
     if points is None:
         return
     r = self.scaled_radius * np.max(np.linalg.norm(points, axis=1))
     if self.anchor_items is None:
         self.anchor_items = []
         for point, label in zip(points, labels):
             anchor = AnchorItem(line=QLineF(0, 0, *point), text=label)
             visible = self.always_show_axes or np.linalg.norm(point) > r
             anchor.setVisible(visible)
             anchor.setPen(pg.mkPen((100, 100, 100)))
             self.plot_widget.addItem(anchor)
             self.anchor_items.append(anchor)
     else:
         for anchor, point, label in zip(self.anchor_items, points, labels):
             anchor.setLine(QLineF(0, 0, *point))
             visible = self.always_show_axes or np.linalg.norm(point) > r
             anchor.setVisible(visible)
Example #4
0
 def update_anchors(self):
     points, labels = self.master.get_anchors()
     if points is None:
         return
     r = self.scaled_radius
     if self.anchor_items is None:
         self.anchor_items = []
         for point, label in zip(points, labels):
             anchor = AnchorItem(line=QLineF(0, 0, *point), text=label)
             anchor.setVisible(np.linalg.norm(point) > r)
             anchor.setPen(pg.mkPen((100, 100, 100)))
             anchor.setFont(self.parameter_setter.anchor_font)
             self.plot_widget.addItem(anchor)
             self.anchor_items.append(anchor)
     else:
         for anchor, point, label in zip(self.anchor_items, points, labels):
             anchor.setLine(QLineF(0, 0, *point))
             anchor.setText(label)
             anchor.setVisible(np.linalg.norm(point) > r)
             anchor.setFont(self.parameter_setter.anchor_font)
Example #5
0
 def __on_scheme_annot_geometry_change(self):
     annot = self.sender()
     item = self.__item_for_annotation[annot]
     if isinstance(annot, scheme.SchemeTextAnnotation):
         item.setGeometry(QRectF(*annot.rect))
     elif isinstance(annot, scheme.SchemeArrowAnnotation):
         p1 = item.mapFromScene(QPointF(*annot.start_pos))
         p2 = item.mapFromScene(QPointF(*annot.end_pos))
         item.setLine(QLineF(p1, p2))
     else:
         pass
Example #6
0
 def paint(self, painter, option, widget=None):
     brect = self.boundingRect()
     c = brect.center()
     line = QLineF(brect.left(), c.y(), brect.right(), c.y())
     t = painter.transform()
     line = t.map(line)
     painter.save()
     painter.resetTransform()
     painter.setPen(self.currentPen)
     painter.drawLine(line)
     painter.restore()
    def test_controlpointline(self):
        control = ControlPointLine()
        line = QGraphicsLineItem(10, 10, 200, 200)

        self.scene.addItem(line)
        self.scene.addItem(control)

        control.setLine(line.line())
        control.setFocus()
        control.lineChanged.connect(line.setLine)

        control.setLine(QLineF(30, 30, 180, 180))
        self.assertEqual(control.line(), line.line())
        self.assertEqual(line.line(), QLineF(30, 30, 180, 180))

        control.lineEdited.connect(line.setLine)

        self.view.show()
        self.app.exec_()

        self.assertEqual(control.line(), line.line())
 def paint(self, p, *args):
     # From orange3-bioinformatics:OWFeatureSelection.py, thanks to @ales-erjavec
     brect = self.boundingRect()
     c = brect.center()
     line = QLineF(brect.left(), c.y(), brect.right(), c.y())
     t = p.transform()
     line = t.map(line)
     p.save()
     p.resetTransform()
     p.setPen(self.currentPen)
     p.drawLine(line)
     p.restore()
Example #9
0
    def __activeControlMoved(self, pos):
        line = QLineF(self.__line)
        control = self.__activeControl
        if control.anchor() == ControlPoint.TopLeft:
            line.setP1(pos)
        elif control.anchor() == ControlPoint.BottomRight:
            line.setP2(pos)

        if self.__line != line:
            self.blockSignals(True)
            self.setLine(line)
            self.blockSignals(False)
            self.lineEdited.emit(line)
Example #10
0
    def __init__(self, parent=None, line=None, **kwargs):
        # type: (Optional[QGraphicsItem], Optional[QLineF], Any) -> None
        super().__init__(parent, **kwargs)
        self.setFlag(QGraphicsItem.ItemIsMovable)
        self.setFlag(QGraphicsItem.ItemIsSelectable)

        self.setFocusPolicy(Qt.ClickFocus)

        if line is None:
            line = QLineF(0, 0, 20, 0)

        self.__line = QLineF(line)
        self.__color = QColor(Qt.red)
        # An item with the same shape as this arrow, stacked behind this
        # item as a source for QGraphicsDropShadowEffect. Cannot attach
        # the effect to this item directly as QGraphicsEffect makes the item
        # non devicePixelRatio aware.
        self.__arrowShadowBase = ArrowItem(self, line=line)
        self.__arrowShadowBase.setPen(Qt.NoPen)  # no pen -> slightly thinner
        self.__arrowShadowBase.setBrush(QBrush(self.__color))
        self.__arrowShadowBase.setArrowStyle(ArrowItem.Concave)
        self.__arrowShadowBase.setLineWidth(5)

        self.__shadow = QGraphicsDropShadowEffect(
            blurRadius=5,
            offset=QPointF(1.0, 2.0),
        )

        self.__arrowShadowBase.setGraphicsEffect(self.__shadow)
        self.__shadow.setEnabled(True)

        # The 'real' shape item
        self.__arrowItem = ArrowItem(self, line=line)
        self.__arrowItem.setBrush(self.__color)
        self.__arrowItem.setPen(QPen(self.__color))
        self.__arrowItem.setArrowStyle(ArrowItem.Concave)
        self.__arrowItem.setLineWidth(5)

        self.__autoAdjustGeometry = True
Example #11
0
    def __init__(self, parent=None, line=None, lineWidth=4, **kwargs):
        GraphicsPathObject.__init__(self, parent, **kwargs)

        if line is None:
            line = QLineF(0, 0, 10, 0)

        self.__line = line

        self.__lineWidth = lineWidth

        self.__arrowStyle = ArrowItem.Plain

        self.__updateArrowPath()
 def __init__(
         self, parent: Optional[QObject] = None, color=QColor(), penWidth=5,
         barFillRatioRole=Qt.UserRole + 1, barColorRole=Qt.UserRole + 2,
         **kwargs
 ):
     super().__init__(parent, **kwargs)
     self.color = color
     self.penWidth = penWidth
     self.barFillRatioRole = barFillRatioRole
     self.barColorRole = barColorRole
     # Line and pen instances reused
     self.__line = QLineF()
     self.__pen = QPen(color, penWidth, Qt.SolidLine, Qt.RoundCap)
    def update_anchors(self):
        points, labels = self.master.get_anchors()
        if points is None:
            return
        r = self.scaled_radius * np.max(np.linalg.norm(points, axis=1))
        if self.anchor_items is None:
            self.anchor_items = []
            for point, label in zip(points, labels):
                anchor = AnchorItem(line=QLineF(0, 0, *point))
                anchor._label.setToolTip(f"<b>{label}</b>")
                label = label[:MAX_LABEL_LEN - 3] + "..." if len(label) > MAX_LABEL_LEN else label
                anchor.setText(label)

                visible = self.always_show_axes or np.linalg.norm(point) > r
                anchor.setVisible(visible)
                anchor.setPen(pg.mkPen((100, 100, 100)))
                self.plot_widget.addItem(anchor)
                self.anchor_items.append(anchor)
        else:
            for anchor, point, label in zip(self.anchor_items, points, labels):
                anchor.setLine(QLineF(0, 0, *point))
                visible = self.always_show_axes or np.linalg.norm(point) > r
                anchor.setVisible(visible)
 def best_angle():
     """...is the one furthest away from all other angles"""
     angles = [
         QLineF(node.pos(), other.pos()).angle() for other in chain((
             edge.source for edge in node.edges
             if edge.dest == node and edge.source != node), (
                 edge.dest for edge in node.edges
                 if edge.dest != node and edge.source == node))
     ]
     angles.sort()
     if not angles:  # If this self-constraint is the only edge
         return 225
     deltas = np.array(angles[1:] + [360 + angles[0]]) - angles
     return (angles[deltas.argmax()] + deltas.max() / 2) % 360
Example #15
0
    def __init__(self, parent=None, line=None, lineWidth=4., **kwargs):
        # type: (Optional[QGraphicsItem], Optional[QLineF], float, Any) -> None
        super().__init__(parent, **kwargs)

        if line is None:
            line = QLineF(0, 0, 10, 0)

        self.__line = line

        self.__lineWidth = lineWidth

        self.__arrowStyle = ArrowItem.Plain

        self.__updateArrowPath()
    def paintArc(self, painter, option, widget):
        assert self.source is self.dest
        node = self.source

        def best_angle():
            """...is the one furthest away from all other angles"""
            angles = [
                QLineF(node.pos(), other.pos()).angle() for other in chain((
                    edge.source for edge in node.edges
                    if edge.dest == node and edge.source != node), (
                        edge.dest for edge in node.edges
                        if edge.dest != node and edge.source == node))
            ]
            angles.sort()
            if not angles:  # If this self-constraint is the only edge
                return 225
            deltas = np.array(angles[1:] + [360 + angles[0]]) - angles
            return (angles[deltas.argmax()] + deltas.max() / 2) % 360

        angle = best_angle()
        inf = QPointF(-1e20, -1e20)  # Doesn't work with real -np.inf!
        line0 = QLineF(node.pos(), inf)
        line1 = QLineF(node.pos(), inf)
        line2 = QLineF(node.pos(), inf)
        line0.setAngle(angle)
        line1.setAngle(angle - 13)
        line2.setAngle(angle + 13)

        p0 = shape_line_intersection(node.shape(), node.pos(), line0)
        p1 = shape_line_intersection(node.shape(), node.pos(), line1)
        p2 = shape_line_intersection(node.shape(), node.pos(), line2)
        path = QPainterPath()
        path.moveTo(p1)
        line = QLineF(node.pos(), p0)
        line.setLength(3 * line.length())
        pt = line.p2()
        path.quadTo(pt, p2)

        line = QLineF(node.pos(), pt)
        self.setLine(line)  # This invalidates DeviceCoordinateCache
        painter.drawPath(path)

        # Draw arrow head
        line = QLineF(pt, p2)
        self.arrowHead.clear()
        for point in self._arrowhead_points(line):
            self.arrowHead.append(point)
        painter.setBrush(self.pen().color())
        painter.drawPolygon(self.arrowHead)

        # Update label position
        self.label.setPos(path.pointAtPercent(.5))
        if 90 < angle < 270:  # Right-align the label
            pos = self.label.pos()
            x, y = pos.x(), pos.y()
            self.label.setPos(x - self.label.boundingRect().width(), y)
        self.squares.placeBelow(self.label)
Example #17
0
def arrow_path_concave(line, width):
    # type: (QLineF, float) -> QPainterPath
    """
    Return a :class:`QPainterPath` of a pretty looking arrow.
    """
    path = QPainterPath()
    p1, p2 = line.p1(), line.p2()

    if p1 == p2:
        return path

    baseline = QLineF(line)
    # Require some minimum length.
    baseline.setLength(max(line.length() - width * 3, width * 3))

    start, end = baseline.p1(), baseline.p2()
    mid = (start + end) / 2.0
    normal = QLineF.fromPolar(1.0, baseline.angle() + 90).p2()

    path.moveTo(start)
    path.lineTo(start + (normal * width / 4.0))

    path.quadTo(mid + (normal * width / 4.0),
                end + (normal * width / 1.5))

    path.lineTo(end - (normal * width / 1.5))
    path.quadTo(mid - (normal * width / 4.0),
                start - (normal * width / 4.0))
    path.closeSubpath()

    arrow_head_len = width * 4
    arrow_head_angle = 50
    line_angle = line.angle() - 180

    angle_1 = line_angle - arrow_head_angle / 2.0
    angle_2 = line_angle + arrow_head_angle / 2.0

    points = [p2,
              p2 + QLineF.fromPolar(arrow_head_len, angle_1).p2(),
              baseline.p2(),
              p2 + QLineF.fromPolar(arrow_head_len, angle_2).p2(),
              p2]

    poly = QPolygonF(points)
    path_head = QPainterPath()
    path_head.addPolygon(poly)
    path = path.united(path_head)
    return path
Example #18
0
    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton:
            if self.arrow_item is not None:
                p1, p2 = self.down_pos, event.scenePos()

                # Commit the annotation to the scheme
                self.annotation.set_line(point_to_tuple(p1),
                                         point_to_tuple(p2))

                self.document.addAnnotation(self.annotation)

                p1, p2 = map(self.arrow_item.mapFromScene, (p1, p2))
                self.arrow_item.setLine(QLineF(p1, p2))

            self.end()
            return True
Example #19
0
    def __init__(self, parent=None, line=QLineF(), text="", **kwargs):
        super().__init__(None, **kwargs)
        self._text = text
        self.setFlag(pg.GraphicsObject.ItemHasNoContents)

        self._spine = QGraphicsLineItem(line, self)
        angle = line.angle()

        self._arrow = pg.ArrowItem(parent=self, angle=0)
        self._arrow.setPos(self._spine.line().p2())
        self._arrow.setRotation(angle)

        self._label = TextItem(text=text, color=(10, 10, 10))
        self._label.setParentItem(self)
        self._label.setPos(self._spine.line().p2())

        if parent is not None:
            self.setParentItem(parent)
Example #20
0
 def __init__(self,
              x,
              y,
              parent=None,
              line=QLineF(),
              scene_size=1,
              text="",
              **kwargs):
     super().__init__(parent, **kwargs)
     self.arrows = [
         pg.ArrowItem(
             pos=(x - scene_size * 0.07 * np.cos(np.radians(angle)),
                  y + scene_size * 0.07 * np.sin(np.radians(angle))),
             parent=self,
             angle=angle,
             headLen=13,
             tipAngle=45,
             brush=pg.mkColor(128, 128, 128)) for angle in (0, 90, 180, 270)
     ]
    def __init__(self, parent=None, orientation=Qt.Vertical, value=0.0,
                 length=10.0, **kwargs):
        self._orientation = orientation
        self._value = value
        self._length = length
        self._min = 0.0
        self._max = 1.0
        self._line = QLineF()  # type: Optional[QLineF]
        self._pen = QPen()
        super().__init__(parent, **kwargs)

        self.setAcceptedMouseButtons(Qt.LeftButton)
        self.setPen(make_pen(brush=QColor(50, 50, 50), width=1, cosmetic=False,
                             style=Qt.DashLine))

        if self._orientation == Qt.Vertical:
            self.setCursor(Qt.SizeVerCursor)
        else:
            self.setCursor(Qt.SizeHorCursor)
Example #22
0
 def __init__(self,
              parent=None,
              orientation=Qt.Vertical,
              value=0.0,
              length=10.0,
              **kwargs):
     self._orientation = orientation
     self._value = value
     self._length = length
     self._min = 0.0
     self._max = 1.0
     self._line: Optional[QLineF] = QLineF()
     self._pen: Optional[QPen] = None
     super().__init__(parent, **kwargs)
     self.setAcceptedMouseButtons(Qt.LeftButton)
     if self._orientation == Qt.Vertical:
         self.setCursor(Qt.SizeVerCursor)
     else:
         self.setCursor(Qt.SizeHorCursor)
Example #23
0
    def editItem(self, item):
        annotation = self.scene.annotation_for_item(item)
        control = controlpoints.ControlPointLine()
        self.scene.addItem(control)

        line = item.line()
        self.savedLine = line

        p1, p2 = map(item.mapToScene, (line.p1(), line.p2()))

        control.setLine(QLineF(p1, p2))
        control.setFocusProxy(item)
        control.lineEdited.connect(self.__on_lineEdited)

        item.geometryChanged.connect(self.__on_lineGeometryChanged)

        self.item = item
        self.annotation = annotation
        self.control = control
Example #24
0
    def __init__(self, parent=None, **kwargs):
        QGraphicsObject.__init__(self, parent, **kwargs)
        self.setFlag(QGraphicsItem.ItemHasNoContents)
        self.setFlag(QGraphicsItem.ItemIsFocusable)

        self.__line = QLineF()
        self.__points = [
            ControlPoint(self, ControlPoint.TopLeft),  # TopLeft is line start
            ControlPoint(self, ControlPoint.BottomRight),  # line end
        ]

        self.__activeControl = None

        if self.scene():
            self.__installFilter()

        for p in self.__points:
            p.setFlag(QGraphicsItem.ItemIsFocusable)
            p.setFocusProxy(self)
Example #25
0
    def __init__(self, parent=None, **kwargs):
        # type: (Optional[QGraphicsItem], Any) -> None
        super().__init__(parent, **kwargs)
        self.setFlag(QGraphicsItem.ItemHasNoContents)
        self.setFlag(QGraphicsItem.ItemIsFocusable)

        self.__line = QLineF()
        self.__points = \
            [ControlPoint(self, ControlPoint.TopLeft),  # TopLeft is line start
             ControlPoint(self, ControlPoint.BottomRight)  # line end
             ]

        self.__activeControl = None  # type: Optional[ControlPoint]

        if self.scene():
            self.__installFilter()

        for p in self.__points:
            p.setFlag(QGraphicsItem.ItemIsFocusable)
            p.setFocusProxy(self)
Example #26
0
    def mouseMoveEvent(self, event):
        if event.buttons() & Qt.LeftButton:
            if self.arrow_item is None and \
                    (self.down_pos - event.scenePos()).manhattanLength() > \
                    QApplication.instance().startDragDistance():

                annot = scheme.SchemeArrowAnnotation(
                    point_to_tuple(self.down_pos),
                    point_to_tuple(event.scenePos()))
                annot.set_color(self.color)
                item = self.scene.add_annotation(annot)

                self.arrow_item = item
                self.annotation = annot

            if self.arrow_item is not None:
                p1, p2 = map(self.arrow_item.mapFromScene,
                             (self.down_pos, event.scenePos()))
                self.arrow_item.setLine(QLineF(p1, p2))

            event.accept()
            return True
Example #27
0
def arrow_path_plain(line, width):
    """
    Return an :class:`QPainterPath` of a plain looking arrow.
    """
    path = QPainterPath()
    p1, p2 = line.p1(), line.p2()

    if p1 == p2:
        return path

    baseline = QLineF(line)
    # Require some minimum length.
    baseline.setLength(max(line.length() - width * 3, width * 3))
    path.moveTo(baseline.p1())
    path.lineTo(baseline.p2())

    stroker = QPainterPathStroker()
    stroker.setWidth(width)
    path = stroker.createStroke(path)

    arrow_head_len = width * 4
    arrow_head_angle = 50
    line_angle = line.angle() - 180

    angle_1 = line_angle - arrow_head_angle / 2.0
    angle_2 = line_angle + arrow_head_angle / 2.0

    points = [
        p2,
        p2 + QLineF.fromPolar(arrow_head_len, angle_1).p2(),
        p2 + QLineF.fromPolar(arrow_head_len, angle_2).p2(),
        p2,
    ]

    poly = QPolygonF(points)
    path_head = QPainterPath()
    path_head.addPolygon(poly)
    path = path.united(path_head)
    return path
Example #28
0
    def add_annotation(self, scheme_annot):
        # type: (BaseSchemeAnnotation) -> Annotation
        """
        Create a new item for :class:`SchemeAnnotation` and add it
        to the scene. If the `scheme_annot` is already in the scene do
        nothing and just return its item.

        """
        if scheme_annot in self.__item_for_annotation:
            # Already added
            return self.__item_for_annotation[scheme_annot]

        if isinstance(scheme_annot, scheme.SchemeTextAnnotation):
            item = items.TextAnnotation()
            x, y, w, h = scheme_annot.rect  # type: ignore
            item.setPos(x, y)
            item.resize(w, h)
            item.setTextInteractionFlags(Qt.TextEditorInteraction)

            font = font_from_dict(scheme_annot.font,
                                  item.font())  # type: ignore
            item.setFont(font)
            item.setContent(scheme_annot.content, scheme_annot.content_type)
            scheme_annot.content_changed.connect(item.setContent)
        elif isinstance(scheme_annot, scheme.SchemeArrowAnnotation):
            item = items.ArrowAnnotation()
            start, end = scheme_annot.start_pos, scheme_annot.end_pos
            item.setLine(QLineF(QPointF(*start),
                                QPointF(*end)))  # type: ignore
            item.setColor(QColor(scheme_annot.color))

        scheme_annot.geometry_changed.connect(
            self.__on_scheme_annot_geometry_change)

        self.add_annotation_item(item)
        self.__item_for_annotation[scheme_annot] = item

        return item
Example #29
0
    def adjustGeometry(self):
        """
        Adjust the widget geometry to exactly fit the arrow inside
        while preserving the arrow path scene geometry.

        """
        # local system coordinate
        geom = self.geometry().translated(-self.pos())
        line = self.__line

        arrow_rect = self.__arrowItem.shape().boundingRect()

        if geom.isNull() and not line.isNull():
            geom = QRectF(0, 0, 1, 1)

        if not (geom.contains(arrow_rect)):
            geom = geom.united(arrow_rect)

        geom = geom.intersected(arrow_rect)
        diff = geom.topLeft()
        line = QLineF(line.p1() - diff, line.p2() - diff)
        geom.translate(self.pos())
        self.setGeometry(geom)
        self.setLine(line)
Example #30
0
 def line(self):
     # type: () -> QLineF
     """
     Return the arrow base line (`QLineF` in object coordinates).
     """
     return QLineF(self.__line)