Пример #1
0
 def draw_icon(self, painter):
     painter.drawEllipse(QPointF(0.5, 0.5), 0.5, 0.5)
     painter.drawChord(QRectF(0.0, 0.0, 1.0, 1.0), 45 * 16, -120 * 16)
     painter.drawChord(QRectF(0.0, 0.0, 1.0, 1.0), 135 * 16, 120 * 16)
     bottom_arrow_point = QPointF(0.5, 0.8)
     painter.drawLine(bottom_arrow_point, QPointF(0.5, 0.7))
     curve_start = QPointF(0.5, 0.7)
     bend_angle = 25
     curve_end_l = QPointF(
         0.4 * math.cos(math.radians(90 + bend_angle)) + 0.5,
         -0.4 * math.sin(math.radians(90 + bend_angle)) + 0.5)
     c1 = QPointF(0.5, 0.4)
     path = QPainterPath(curve_start)
     path.quadTo(c1, curve_end_l)
     painter.drawPath(path)
     curve_end_r = QPointF(
         0.4 * math.cos(math.radians(90 - bend_angle)) + 0.5,
         -0.4 * math.sin(math.radians(90 - bend_angle)) + 0.5)
     path = QPainterPath(curve_start)
     path.quadTo(c1, curve_end_r)
     painter.drawPath(path)
     # Draw the arrow end-caps
     painter.setBrush(QBrush(QColor(0, 0, 0)))
     arrow = QPolygonF(
         [QPointF(-0.025, 0.0),
          QPointF(0.025, 0.0),
          QPointF(0.0, 0.025)])
     painter.drawPolygon(arrow.translated(bottom_arrow_point))
     t = QTransform()
     t.rotate(180.0 - 25.0)
     arrow_l = t.map(arrow)
     arrow_l = arrow_l.translated(curve_end_l)
     painter.drawPolygon(arrow_l)
     t = QTransform()
     t.rotate(180.0 + 25.0)
     arrow_r = t.map(arrow)
     arrow_r = arrow_r.translated(curve_end_r)
     painter.drawPolygon(arrow_r)
Пример #2
0
class Connection_Item(QGraphicsPathItem):
    def __init__(self, connection, parent):
        super().__init__()
        self._connection = connection
        self._source_ui = self._find_ui(parent, connection.source.connector)
        self._sink_ui = self._find_ui(parent, connection.sink.connector)
        self.avoid_conn = None
        self._duplicate_is = None
        self._duplicate_of = None
        self._switch_direction_count = 1
        self.path = QPainterPath()
        self.stroker_path = QPainterPath()
        self.stroker = QPainterPathStroker()
        self.stroker.setWidth(8)
        self.update_endpoints()
        self.setZValue(-10)
        self.arrow = QGraphicsPolygonItem()
        self._set_default_appearance()
        self.setFlag(self.ItemIsFocusable)
        self._ports_item = Connection_Ports_Item()
        self._ports_item.setParentItem(self)
        self._timer = QTimer(self.scene())
        self._timer.setSingleShot(True)
        self._timer.setSingleShot(True)
        self._timer.timeout.connect(self._start_hover)
        self._hover_pos = 0, 0
        self.set_show_connection_ports_on_hover(False)

    def shape(self):
        return self.stroker_path

    def setPath(self, path):
        super().setPath(path)
        self.stroker_path = self.stroker.createStroke(path)

    def _set_default_appearance(self):
        self.setPen(QPen(Qt.black, 2))
        self.arrow.setPen(QPen(Qt.black))
        self.arrow.setBrush(QBrush(Qt.black))
        self._arrow_height = 8
        self.update_from_avoid_router()  # trigger arrow size change

    def focusInEvent(self, event):
        self.setPen(QPen(highlight_color, 4))
        self.arrow.setPen(QPen(highlight_color))
        self.arrow.setBrush(QBrush(highlight_color))
        self._arrow_height = 12
        self.update_from_avoid_router()  # trigger arrow size change
        super().focusInEvent(event)

    def focusOutEvent(self, event):
        self._set_default_appearance()
        super().focusOutEvent(event)

    def keyPressEvent(self, event):
        key = event.key()
        if (key == Qt.Key_Delete):
            self.parentItem().remove_connection(self)
            return
        elif (key == Qt.Key_D):
            self._switch_direction()
            return
        super().keyPressEvent(event)

    def _switch_direction(self):
        if self._duplicate_is:
            self.parentItem().remove_connection(self._duplicate_is)
            self._switch_direction_count = 0
        elif self._switch_direction_count < 2:
            sink = self._connection.sink
            self._connection.sink = self._connection.source
            self._connection.source = sink
            self._source_ui = self._find_ui(self.parentItem(),
                                            self._connection.source.connector)
            self._sink_ui = self._find_ui(self.parentItem(),
                                          self._connection.sink.connector)
            self._switch_direction_count += 1
        else:
            conn = diagram.Connection(
                source=self._connection.sink,
                sink=self._connection.source,
            )
            self.parentItem().add_connection(conn)
            self._switch_direction_count = 3
        self.update_endpoints()
        self.parentItem()._hide_duplicate_connections()
        if self._switch_direction_count == 0:
            self._switch_direction()

    def mouseDoubleClickEvent(self, event):
        if event.button() == Qt.LeftButton:
            self._switch_direction()
            return  # Do not call mousePressEvent, will pass on to diagram
        super().mouseDoubleClickEvent(event)

    def set_show_connection_ports_on_hover(self, show):
        if not show:
            self._ports_item.hide()
        self.setAcceptHoverEvents(show)

    def hoverEnterEvent(self, event):
        w = self._ports_item.rect().width()
        h = self._ports_item.rect().height()
        x = event.pos().x() - w / 2.0
        y = event.pos().y() - h / 2.0
        self._hover_pos = x, y
        self._timer.start(200)

    def hoverLeaveEvent(self, event):
        self._stop_hover()

    def _start_hover(self):
        if self.hasFocus():
            return
        #print("start hover", [a.name for a in self._connection.source_ports])
        x, y = self._hover_pos
        self._ports_item.setX(x)
        self._ports_item.setY(y)
        self.setZValue(10)
        self._ports_item.show()

    def _stop_hover(self):
        self._timer.stop()
        self._ports_item.hide()
        self.setZValue(-10)

    def _find_ui(self, parent, c):
        result = None
        for b_ui in parent._block_items:
            for c_ui in b_ui._connectors:
                if c_ui._connector == c:
                    return c_ui
        return result

    def _get_endpoint(self, c_ui):
        x, y = c_ui.get_connection_point()
        if x is None:
            return None, None
        p = self.mapToParent(
            self.mapFromScene(c_ui.parentItem().mapToScene(x, y)))
        return p.x(), p.y()

    def update_endpoints(self):
        self.x1, self.y1 = self._get_endpoint(self._source_ui)
        self.x2, self.y2 = self._get_endpoint(self._sink_ui)
        if self.x1 is None or self.x2 is None:
            return False
        self.path = QPainterPath()
        self.path.moveTo(self.x1, self.y1)
        self.path.lineTo(self.x2, self.y2)
        self.setPath(self.path)
        self._update_avoid()
        return True

    def _update_avoid(self):
        if self.parentItem():
            avoid_router = self.parentItem().avoid_router
            src = avoid.ConnEnd(avoid.Point(self.x1, self.y1))
            if self.isVisible():
                dest = avoid.ConnEnd(avoid.Point(self.x2, self.y2))
            else:
                dest = src  # Don't route duplicate connection
            if self.avoid_conn is None:
                self.avoid_conn = avoid.ConnRef(avoid_router, src, dest)
            else:
                self.avoid_conn.setEndpoints(src, dest)

    def update_from_avoid_router(self):
        if self.avoid_conn is not None and self.avoid_conn.needsRepaint():
            radius = self.parentItem().route_radius
            route = self.avoid_conn.displayRoute()
            self.path = QPainterPath()
            last_i = route.size() - 1
            for i in range(0, route.size()):
                point = route.at(i)
                if i > 0:
                    last_point = route.at(i - 1)
                    last_path_point = self.path.currentPosition()
                    if point.y == last_point.y:  # horizontal line
                        if point.x > last_point.x:  # right
                            sign = 1
                        else:  # left
                            sign = -1
                        self.path.quadTo(last_point.x, last_point.y,
                                         last_point.x + sign * radius, point.y)
                        if i == last_i:
                            my_x = point.x
                        else:
                            my_x = point.x - sign * radius
                        self.path.lineTo(my_x, point.y)
                    elif point.x == last_point.x:  # vertical line
                        if point.y > last_point.y:  # down
                            sign = 1
                        else:  # up
                            sign = -1
                        self.path.quadTo(last_point.x, last_point.y, point.x,
                                         last_point.y + sign * radius)
                        if i == last_i:
                            my_y = point.y
                        else:
                            my_y = point.y - sign * radius
                        self.path.lineTo(point.x, my_y)
                    else:
                        self.path.lineTo(point.x, point.y)
                else:
                    self.path.moveTo(point.x, point.y)
            self.setPath(self.path)

            sink = self._sink_ui
            entry_from = "L"
            x = 0
            if route.at(route.size() - 1).x < route.at(route.size() - 2).x:
                entry_from = "R"
                x = sink.parentItem().rect().width()
            if self._duplicate_of:
                route = self._duplicate_of.avoid_conn.displayRoute()
                if route.at(0).x < route.at(1).x:
                    entry_from = "R"
                    x = sink.parentItem().rect().width()
            y = sink.y() + sink.rect().height() / 2.0
            p = self.mapToParent(
                self.mapFromScene(sink.parentItem().mapToScene(x, y)))
            xc, yc = p.x(), p.y()
            arrow_h = self._arrow_height
            arrow_y = arrow_h / 2.0
            arrow_x = sqrt(arrow_h * arrow_h - arrow_y * arrow_y)
            poly = QPolygonF()
            if entry_from == "L":
                poly << QPointF(xc - arrow_x, yc)
                poly << QPointF(xc - arrow_x, yc + arrow_y)
                poly << QPointF(xc, yc)
                poly << QPointF(xc - arrow_x, yc - arrow_y)
                poly << QPointF(xc - arrow_x, yc)
            else:
                poly << QPointF(xc + arrow_x, yc)
                poly << QPointF(xc + arrow_x, yc + arrow_y)
                poly << QPointF(xc, yc)
                poly << QPointF(xc + arrow_x, yc - arrow_y)
                poly << QPointF(xc + arrow_x, yc)
            self.arrow.setPolygon(poly)

    def setParentItem(self, parent_item):
        super().setParentItem(parent_item)
        self._update_avoid()