Exemple #1
0
    def _updateLabel(self, is_left):
        """
        Called by updatePositionAndAppearance during init, or later by
        updateConnectivity. Updates drawing and position of the label.
        """
        lbl = self._label
        if self._idx != None:
            bw = _BASE_WIDTH
            num = self._partner_virtual_helix.number()
            tBR = _FM.tightBoundingRect(str(num))
            half_label_h = tBR.height()/2.0
            half_label_w = tBR.width()/2.0
            # determine x and y positions
            label_x = bw/2.0 - half_label_w
            if self._is_on_top:
                label_y = -0.25*half_label_h - 0.5 - 0.5*bw
            else:
                label_y = 2*half_label_h + 0.5 + 0.5*bw
            # adjust x for left vs right
            label_x_offset = 0.25*bw if is_left else -0.25*bw
            label_x += label_x_offset
            # adjust x for numeral 1
            if num == 1: label_x -= half_label_w/2.0
            # create text item
            if lbl == None:
                lbl = QGraphicsSimpleTextItem(str(num), self)
            lbl.setPos(label_x, label_y)
            lbl.setBrush(_ENAB_BRUSH)
            lbl.setFont(_TO_HELIX_NUM_FONT)
            self._label = lbl

            lbl.setText( str(self._partner_virtual_helix.number()) )
            lbl.show()
Exemple #2
0
    def _updateLabel(self, is_left):
        """
        Called by updatePositionAndAppearance during init, or later by
        updateConnectivity. Updates drawing and position of the label.
        """
        lbl = self._label
        if self._idx != None:
            bw = _BASE_WIDTH
            num = self._partner_virtual_helix.number()
            tBR = _FM.tightBoundingRect(str(num))
            half_label_h = tBR.height() / 2.0
            half_label_w = tBR.width() / 2.0
            # determine x and y positions
            label_x = bw / 2.0 - half_label_w
            if self._is_on_top:
                label_y = -0.25 * half_label_h - 0.5 - 0.5 * bw
            else:
                label_y = 2 * half_label_h + 0.5 + 0.5 * bw
            # adjust x for left vs right
            label_x_offset = 0.25 * bw if is_left else -0.25 * bw
            label_x += label_x_offset
            # adjust x for numeral 1
            if num == 1: label_x -= half_label_w / 2.0
            # create text item
            if lbl == None:
                lbl = QGraphicsSimpleTextItem(str(num), self)
            lbl.setPos(label_x, label_y)
            lbl.setBrush(_ENAB_BRUSH)
            lbl.setFont(_TO_HELIX_NUM_FONT)
            self._label = lbl

            lbl.setText(str(self._partner_virtual_helix.number()))
            lbl.show()
Exemple #3
0
class EdgeItem(QGraphicsItem):
    LINE_WIDTH = 1
    OFFSET = 8  # 方向线偏离中心线的距离
    MIN_ARROW_WIDTH, MAX_ARROW_WIDTH = 1, 8

    double_click_callback = EMPTY_FUNC

    def __init__(self, edge_id):
        super().__init__()
        self.setZValue(1)
        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges)
        self.setAcceptHoverEvents(True)

        self.edge_id = edge_id
        self.text_item = QGraphicsSimpleTextItem('', self)
        self.text_item.setZValue(4)

        self.style = {
            'name': f'Edge{edge_id}',
            'color': Qt.black,
            'width': 0.5,  # 0~1 的中间值
            'line': Qt.SolidLine,
            'show_arrow': False,
            'text': '',
            'text_color': Qt.black,
            'show_text': False,
        }
        self.hover = False

    def type(self):
        return QGraphicsItem.UserType + abs(hash(EdgeItem))

    def boundingRect(self):
        return self.bounding_rect

    def shape(self):
        path = QPainterPath()
        path.addPolygon(self.shape_polygon)
        path.closeSubpath()
        return path

    # -------------------------------------------------------------------------
    def adjust(self, src_p: QPointF, dst_p: QPointF):
        self.angle = getAngle(src_p, dst_p)

        self.src_p = src_p
        self.arrow_p = (src_p + 2 * dst_p) / 3  # 箭头开始位置, 前端2/3处
        self.dst_p = dst_p

        W1 = 1 * self.OFFSET
        W2 = 2 * self.OFFSET
        W3 = 3 * self.OFFSET

        vec = getRightOffsetVector(self.angle)
        self.arrow_polygon = QPolygonF([
            src_p + vec * W1, dst_p + vec * W1, self.arrow_p + vec * W2,
            self.arrow_p + vec * W1
        ])

        self.shape_polygon = QPolygonF(
            [src_p, src_p + vec * W2, dst_p + vec * W2, dst_p])

        self.bounding_rect = QRectF(src_p,
                                    dst_p).normalized()  # normalized 正方向
        self.bounding_rect.adjust(-W3, -W3, W3, W3)

        self.text_p = ((src_p + dst_p) / 2) + vec * W1
        self.text_item.setPos(self.text_p)
        self.prepareGeometryChange()

    # -------------------------------------------------------------------------
    def paint(self, painter, option, widget=None):
        if self.style['show_arrow'] or self.hover:
            width = threshold(0.0, self.style['width'], 1.0)
            width = width * (self.MAX_ARROW_WIDTH -
                             self.MIN_ARROW_WIDTH) + self.MIN_ARROW_WIDTH
            painter.setPen(QPen(self.style['color'], width,
                                self.style['line']))
            painter.setBrush(self.style['color'])
            painter.drawPolygon(self.arrow_polygon)
        else:
            # TODO 定制线类型 虚线或实线
            painter.setPen(QPen(Qt.black, self.LINE_WIDTH))
            painter.drawLine(self.src_p, self.dst_p)

        if (self.style['show_arrow']
                and self.style['show_text']) or self.hover:
            self.text_item.setPen(self.style['text_color'])
            self.text_item.setText(
                f"{self.style['name']}\n{self.style['text']}")
            self.text_item.show()
        else:
            self.text_item.hide()

    # -------------------------------------------------------------------------
    def mouseDoubleClickEvent(self, event):
        self.double_click_callback(self.edge_id)
        super().mouseDoubleClickEvent(event)

    def hoverEnterEvent(self, event):
        self.hover = True
        self.update()
        super().hoverEnterEvent(event)

    def hoverLeaveEvent(self, event):
        self.hover = False
        self.update()
        super().hoverLeaveEvent(event)

    # -------------------------------------------------------------------------
    def setStyle(self, style) -> None:
        for key in self.style:
            try:
                self.style[key] = style[key]
            except KeyError:
                pass
        self.update()
Exemple #4
0
class NodeItem(QGraphicsItem):  # 面向图形界面, 负责控制显示效果
    MIN_SIZE, MAX_SIZE = 10, 100

    press_callback = EMPTY_FUNC
    release_callback = EMPTY_FUNC
    double_click_callback = EMPTY_FUNC
    move_callback = EMPTY_FUNC

    def __init__(self, node_id):
        super().__init__()

        self.setZValue(2)
        self.setAcceptHoverEvents(True)
        self.setFlag(QGraphicsItem.ItemIsMovable)  # 可以移动
        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges)
        self.setCacheMode(QGraphicsItem.DeviceCoordinateCache)

        # 面向UINet 负责增添逻辑操作
        self.node_id = node_id
        self.hover = False
        self.cached_size = None
        self.bounding_rect = QRectF()  # XXX 在重绘时会被更新,重绘前可能会节点可能会被覆盖显示

        # self.call_backs = CallTable()
        self.text_item = QGraphicsSimpleTextItem(self)
        self.text_item.setZValue(3)

        # 面向图形界面, 负责控制显示效果
        self.style = {
            'name': f' {node_id}',
            'color': Qt.white,
            'shape': 'Pie',  # ('Pie', 'Rect', QPixmap)
            'size': 0.5,  # 0~1 的中间值
            'text': '',
            'text_color': Qt.black,
            'show_text': False,
        }

    def type(self) -> int:
        return QGraphicsItem.UserType + abs(hash(NodeItem))

    def boundingRect(self):
        return self.bounding_rect

    def shape(self):
        path = QPainterPath()
        path.addRect(self.bounding_rect)
        return path

    def paint(self, painter, option, widget=None) -> None:
        # 绘制尺寸
        size = threshold(0.0, self.style['size'], 1.0)
        size = size * (self.MAX_SIZE - self.MIN_SIZE) + self.MIN_SIZE
        if size != self.cached_size:
            self.bounding_rect = QRectF(-size / 2, -size / 2, size, size)
            self.cached_size = size
        # 绘制图标或颜色和形状
        if isinstance(self.style['shape'], QPixmap):
            pixmap = self.style['shape']
            painter.drawPixmap(self.bounding_rect, pixmap,
                               QRectF(pixmap.rect()))
        elif self.style['shape'] == 'Pie':
            painter.setBrush(self.style['color'])
            painter.drawEllipse(self.bounding_rect)  # or drawRect
        elif self.style['shape'] == 'Rect':
            painter.setBrush(self.style['color'])
            painter.drawRect(self.bounding_rect)  # or drawRect
        else:
            raise ValueError('未知shape类型', self.style['shape'])
        # 绘制说明
        text = f"{self.style['name']}\n"
        if self.style['show_text'] or self.hover:
            text += str(self.style['text'])

        self.text_item.setPen(self.style['text_color'])
        self.text_item.setText(text)
        self.text_item.show()

    # ------------------------------------------------------------------------------------------------------------------
    def itemChange(self, change, value):
        if change == QGraphicsItem.ItemPositionHasChanged:
            self.style['pos'] = self.pos()  # 更新位置变化
            self.move_callback(self.node_id)
        return super().itemChange(change, value)

    def mousePressEvent(self, event):
        self.press_callback(self.node_id)
        return super().mousePressEvent(event)

    def mouseReleaseEvent(self, event):
        self.release_callback(self.node_id)
        return super().mouseReleaseEvent(event)

    def mouseDoubleClickEvent(self, event):
        self.double_click_callback(self.node_id)
        return super().mouseDoubleClickEvent(event)

    def hoverEnterEvent(self, event):
        self.hover = True
        return super().hoverEnterEvent(event)

    def hoverLeaveEvent(self, event):
        self.hover = False
        return super().hoverLeaveEvent(event)

    # ------------------------------------------------------------------------------------------------------------------
    def setStyle(self, style) -> None:
        for key in self.style:
            if key in style:
                self.style[key] = style[key]
        self.update()

    def checkPos(self, x, y):
        pos = QPointF(x, y)
        if self.pos() != pos:
            self.setPos(pos)