Пример #1
0
    def findAscent(self, font):
        dummy = "E"
        white = QColor(Qt.white)

        fm = self.fontmetrics(font)
        pm = QPixmap(fm.width(dummy), fm.height())
        pm.fill(white)

        p = QPainter(pm)
        p.setFont(font)
        p.drawText(0, 0, pm.width(), pm.height(), 0, dummy)
        p.end()

        img = pm.toImage()

        w = pm.width()
        linebytes = w * 4
        for row in range(img.height()):
            if PYSIDE2:
                line = bytes(img.scanLine(row))
            else:
                line = img.scanLine(row).asstring(linebytes)
            for col in range(w):
                color = struct.unpack("I", line[col * 4:(col + 1) * 4])[0]
                if color != white.rgb():
                    return fm.ascent() - row + 1
        return fm.ascent()
Пример #2
0
    def paintEvent(self, event):
        tic = time.perf_counter()
        painter = QPainter(self)
        rect = event.rect()
        painter.drawImage(rect, self.image, rect)
        painter.setPen(QColor.fromRgb(255, 0, 0))
        #painter.drawPoints(self.clicks)
        if self.drawBoxes:
            self.drawBoxes(painter)
        # Draw the center mark
        painter.setPen(QColor.fromRgb(255, 0, 0))
        painter.drawLine(self.center.x() - 20, self.center.y(),
                         self.center.x() + 20, self.center.y())
        painter.drawLine(self.center.x(),
                         self.center.y() - 20, self.center.x(),
                         self.center.y() + 20)

        # Draw the scale bar
        if self.scaleBar:
            painter.setPen(QColor.fromRgb(40, 40, 40))
            painter.setFont(QFont("Arial", 30))
            scaleRect = QRect(10, 420, 200, 30)
            painter.drawText(scaleRect, Qt.AlignCenter, "10 nm")
            pen = painter.pen()
            pen.setWidth(5)
            painter.setPen(pen)
            painter.drawLine(10, 460, 210, 460)

        toc = time.perf_counter()
Пример #3
0
    def paintEvent(self, event):  # this puts the line numbers in the margin
        painter = QPainter(self)
        painter.fillRect(event.rect(), self.background)
        block = self.parent.firstVisibleBlock()

        font = self.parent.font()

        while block.isValid():
            block_num = block.blockNumber()
            block_top = self.parent.blockBoundingGeometry(block).translated(
                self.parent.contentOffset()).top()

            # if the block is not visible stop wasting time
            if not block.isVisible() or block_top >= event.rect().bottom():
                break

            if block_num == self.parent.textCursor().blockNumber():
                font.setBold(True)
                painter.setFont(font)
                painter.setPen(self.highlight_color)
                background = self.highlight_background
            else:
                font.setBold(False)
                painter.setFont(font)
                painter.setPen(self.color)
                background = self.background

            text_rec = QRect(0, block_top, self.width(),
                             self.parent.fontMetrics().height())
            painter.fillRect(text_rec, background)
            painter.drawText(text_rec, Qt.AlignRight, str(block_num + 1))
            block = block.next()

        painter.end()
        QWidget.paintEvent(self, event)
Пример #4
0
    def draw_model_name(painter: QPainter, geom: NodeGeometry,
                        state: NodeState, model: NodeDataModel,
                        node_style: NodeStyle):
        """
        Draw model name

        Parameters
        ----------
        painter : QPainter
        geom : NodeGeometry
        state : NodeState
        model : NodeDataModel
        """
        if not model.caption_visible:
            return
        name = model.caption
        f = painter.font()
        f.setBold(True)
        metrics = QFontMetrics(f)
        rect = metrics.boundingRect(name)
        position = QPointF((geom.width - rect.width()) / 2.0,
                           (geom.spacing + geom.entry_height) / 3.0)
        painter.setFont(f)
        painter.setPen(node_style.font_color)
        painter.drawText(position, name)
        f.setBold(False)
        painter.setFont(f)
Пример #5
0
    def paintEvent(self, event):
        """Override Qt method.

        Painting line number area
        """
        painter = QPainter(self)
        painter.fillRect(event.rect(), self.editor.sideareas_color)
        # This is needed to make that the font size of line numbers
        # be the same as the text one when zooming
        # See Issue 2296 and 4811
        font = self.editor.font()
        font_height = self.editor.fontMetrics().height()

        active_block = self.editor.textCursor().block()
        active_line_number = active_block.blockNumber() + 1

        def draw_pixmap(ytop, pixmap):
            if not QT55_VERSION:
                pixmap_height = pixmap.height()
            else:
                # scale pixmap height to device independent pixels
                pixmap_height = pixmap.height() / pixmap.devicePixelRatio()
            painter.drawPixmap(0, ytop + (font_height-pixmap_height) / 2,
                               pixmap)

        for top, line_number, block in self.editor.visible_blocks:
            if self._margin:
                if line_number == active_line_number:
                    font.setWeight(font.Bold)
                    painter.setFont(font)
                    painter.setPen(self.editor.normal_color)
                else:
                    font.setWeight(font.Normal)
                    painter.setFont(font)
                    painter.setPen(self.linenumbers_color)

                painter.drawText(0, top, self.width(),
                                 font_height,
                                 Qt.AlignRight | Qt.AlignBottom,
                                 to_text_string(line_number))

            data = block.userData()
            if self._markers_margin and data:
                if data.code_analysis:
                    for source, code, severity, message in data.code_analysis:
                        error = severity == DiagnosticSeverity.ERROR
                        if error:
                            break
                    if error:
                        draw_pixmap(top, self.error_pixmap)
                    else:
                        draw_pixmap(top, self.warning_pixmap)
                if data.todo:
                    draw_pixmap(top, self.todo_pixmap)
                if data.breakpoint:
                    if data.breakpoint_condition is None:
                        draw_pixmap(top, self.bp_pixmap)
                    else:
                        draw_pixmap(top, self.bpc_pixmap)
Пример #6
0
    def draw_validation_rect(painter: QPainter, geom: NodeGeometry,
                             model: NodeDataModel,
                             graphics_object: NodeGraphicsObject,
                             node_style: NodeStyle):
        """
        Draw validation rect

        Parameters
        ----------
        painter : QPainter
        geom : NodeGeometry
        model : NodeDataModel
        graphics_object : NodeGraphicsObject
        node_style : NodeStyle
        """
        model_validation_state = model.validation_state()
        if model_validation_state == NodeValidationState.valid:
            return

        color = (node_style.selected_boundary_color
                 if graphics_object.isSelected()
                 else node_style.normal_boundary_color)

        if geom.hovered:
            p = QPen(color, node_style.hovered_pen_width)
        else:
            p = QPen(color, node_style.pen_width)

        painter.setPen(p)

        # Drawing the validation message background
        if model_validation_state == NodeValidationState.error:
            painter.setBrush(node_style.error_color)
        else:
            painter.setBrush(node_style.warning_color)

        radius = 3.0
        diam = node_style.connection_point_diameter
        boundary = QRectF(
            -diam,
            -diam + geom.height - geom.validation_height,
            2.0 * diam + geom.width,
            2.0 * diam + geom.validation_height,
        )
        painter.drawRoundedRect(boundary, radius, radius)
        painter.setBrush(Qt.gray)

        # Drawing the validation message itself
        error_msg = model.validation_message()
        f = painter.font()
        metrics = QFontMetrics(f)
        rect = metrics.boundingRect(error_msg)
        position = QPointF(
            (geom.width - rect.width()) / 2.0,
            geom.height - (geom.validation_height - diam) / 2.0
        )
        painter.setFont(f)
        painter.setPen(node_style.font_color)
        painter.drawText(position, error_msg)
Пример #7
0
def add_char_pixmap(pixmap, char, size=14, weight=QFont.Bold):
    if len(char) > 1:
        raise ValueError("Only one char is allowed")
    painter = QPainter(pixmap)
    painter.setFont(QFont("Times", size, weight))
    painter.setPen(QColor(255, 0, 0))
    w, h = pixmap.width(), pixmap.height()
    p = QPoint(w - size, h - 2)
    painter.drawText(p, char)
Пример #8
0
    def paintEvent(self, event):
        """Override Qt method.

        Painting line number area
        """

        painter = QPainter(self)
        painter.fillRect(event.rect(), self.editor.sideareas_color)
        # This is needed to make that the font size of line numbers
        # be the same as the text one when zooming
        # See Issue 2296
        if sys.platform == 'darwin':
            font = self.editor.font()
        else:
            font = painter.font()
        font_height = self.editor.fontMetrics().height()

        active_block = self.editor.textCursor().block()
        active_line_number = active_block.blockNumber() + 1

        def draw_pixmap(ytop, pixmap):
            painter.drawPixmap(0, ytop + (font_height-pixmap.height()) / 2,
                               pixmap)

        for top, line_number, block in self.editor.visible_blocks:
            if self._margin:
                if line_number == active_line_number:
                    font.setWeight(font.Bold)
                    painter.setFont(font)
                    painter.setPen(self.editor.normal_color)
                else:
                    font.setWeight(font.Normal)
                    painter.setFont(font)
                    painter.setPen(self.linenumbers_color)

                painter.drawText(0, top, self.width(),
                                 font_height,
                                 Qt.AlignRight | Qt.AlignBottom,
                                 to_text_string(line_number))

            data = block.userData()
            if self._markers_margin and data:
                if data.code_analysis:
                    for _message, error in data.code_analysis:
                        if error:
                            break
                    if error:
                        draw_pixmap(top, self.error_pixmap)
                    else:
                        draw_pixmap(top, self.warning_pixmap)
                if data.todo:
                    draw_pixmap(top, self.todo_pixmap)
                if data.breakpoint:
                    if data.breakpoint_condition is None:
                        draw_pixmap(top, self.bp_pixmap)
                    else:
                        draw_pixmap(top, self.bpc_pixmap)
Пример #9
0
    def paint(self, painter: QtGui.QPainter, option: 'QStyleOptionViewItem',
              index: QtCore.QModelIndex) -> None:
        viewOption = QStyleOptionViewItem(option)
        self.initStyleOption(viewOption, index)
        QStyledItemDelegate.paint(self, painter, viewOption, index)

        item = index.model().data(index, Qt.UserRole)
        if isinstance(item, QVariant):
            return

        value = item['value']
        type = item['type']
        if type == 'checkbox':
            # 数据转换
            value = True if value == 1 else 0
            # 绘制单选框
            checkBoxStyle = QStyleOptionButton()
            checkBoxStyle.state = QStyle.State_On if value else QStyle.State_Off
            checkBoxStyle.state |= QStyle.State_Enabled
            # 计算位置
            size = item['size']
            rect = calculate_middle_rect(option.rect, size, size)
            checkBoxStyle.rect = rect
            checkBox = QCheckBox()
            QApplication.style().drawPrimitive(QStyle.PE_IndicatorCheckBox,
                                               checkBoxStyle, painter,
                                               checkBox)
        if type == 'tag':
            painter.setRenderHint(QPainter.Antialiasing, True)
            painter.setRenderHints(QPainter.SmoothPixmapTransform)
            path = QPainterPath()

            # 绘制文本
            self.font = ResourceLoader().qt_font_text_tag
            text_color = item['text_color']
            border_color = item['border_color']
            text = value
            padding_v = 2
            padding_h = 4
            border_radius = 2
            border_width = 1
            painter.setFont(item['font'])
            painter.setPen(text_color)
            fm = QFontMetrics(painter.font())
            w = fm.width(text)
            h = fm.height()
            # 计算位置
            rect = calculate_middle_rect(option.rect, w + padding_h * 2,
                                         h + padding_v * 2)
            rectf = QRectF(rect.x(), rect.y(), rect.width(), rect.height())
            painter.drawText(
                QRect(rectf.x() + padding_h,
                      rectf.y() + padding_v, w, h), Qt.TextWordWrap, text)
            # 绘制边框
            path.addRoundedRect(rectf, border_radius, border_radius)
            painter.strokePath(path, QPen(border_color, border_width))
Пример #10
0
 def paintEvent(self, event: QPaintEvent):
     rect = event.rect()
     painter = QPainter(self)
     painter.save()
     if self.isChecked():
         lock = lock_close
     else:
         lock = lock_open
     painter.setFont(QFont("Symbola"))
     painter.drawText(rect.bottomLeft() + QPoint(0, -2), lock)
     painter.restore()
Пример #11
0
    def paintEvent(self, event):
        QPushButton.paintEvent(self, event)

        qp = QPainter()
        qp.begin(self)

        font = qp.font()
        font.setPixelSize(self.font().pixelSize() * 0.6)
        font.setWeight(QFont.Normal)
        qp.setFont(font)

        #qp.drawText(event.rect().translated(2, 2), str(self._atomic_number))

        qp.end()
 def drawText(self, p: QPainter, innerRect: QRectF, innerRadius: float, value: float):
     if not self.m_format:
         return
     f = QFont(self.font())
     f.setPixelSize(10)
     fm = QFontMetricsF(f)
     maxWidth = fm.width(self.valueToText(self.m_max))
     delta = innerRadius / maxWidth
     fontSize = f.pixelSize() * delta * 0.75
     f.setPixelSize(int(fontSize))
     p.setFont(f)
     textRect = QRectF(innerRect)
     p.setPen(self.palette().text().color())
     p.drawText(textRect, Qt.AlignCenter, self.valueToText(value))
Пример #13
0
    def linenumberarea_paint_event(self, event):
        """
        Paint the line number area.
        """
        if self._linenumber_enabled:
            painter = QPainter(self.linenumberarea)
            painter.fillRect(
                event.rect(),
                self._highlighter.get_sideareas_color(),
            )

            block = self.firstVisibleBlock()
            block_number = block.blockNumber()
            top = round(
                self.blockBoundingGeometry(block).translated(
                    self.contentOffset()).top())
            bottom = top + round(self.blockBoundingRect(block).height())

            font = self.font()
            active_block = self.textCursor().block()
            active_line_number = active_block.blockNumber() + 1

            while block.isValid() and top <= event.rect().bottom():
                if block.isVisible() and bottom >= event.rect().top():
                    number = block_number + 1

                    if number == active_line_number:
                        font.setWeight(font.Bold)
                        painter.setFont(font)
                        painter.setPen(
                            self._highlighter.get_foreground_color())
                    else:
                        font.setWeight(font.Normal)
                        painter.setFont(font)
                        painter.setPen(QColor(Qt.darkGray))
                    right_padding = self.linenumberarea._right_padding
                    painter.drawText(
                        0,
                        top,
                        self.linenumberarea.width() - right_padding,
                        self.fontMetrics().height(),
                        Qt.AlignRight,
                        str(number),
                    )

                block = block.next()
                top = bottom
                bottom = top + round(self.blockBoundingRect(block).height())
                block_number += 1
Пример #14
0
def get_font_array(sz, chars=DEFAULT_CHARS):
    from qtpy.QtGui import QFont, QPainter, QColor

    font = QFont()
    font.setFixedPitch(True)
    font.setPixelSize(int(sz))
    font.setStyleStrategy(QFont.NoAntialias)
    dummy = QImage(10, 10, QImage.Format_ARGB32)
    pnt = QPainter(dummy)
    pnt.setFont(font)
    metric = pnt.fontMetrics()
    rct = metric.boundingRect(chars)
    pnt.end()
    h = rct.height()
    w = rct.width()
    img = QImage(w, h, QImage.Format_ARGB32)
    paint = QPainter()
    paint.begin(img)
    paint.setFont(font)
    paint.setBrush(QColor(255, 255, 255))
    paint.setPen(QColor(255, 255, 255))
    paint.drawRect(0, 0, w + 1, h + 1)
    paint.setPen(QColor(0, 0, 0))
    paint.setBrush(QColor(0, 0, 0))
    paint.drawText(0, paint.fontMetrics().ascent(), chars)
    paint.end()
    try:
        try:
            # PyQt4 (at least until Qt 4.8)
            data = img.bits().asstring(img.numBytes())
        except AttributeError:
            if PYSIDE2:
                # PySide2
                data = bytes(img.bits())
            else:
                # PyQt5
                data = img.bits().asstring(img.byteCount())
    except SystemError:
        # PyQt4 (4.11.3) and PyQt5 (5.3.2) on Python 3
        return
    npy = np.frombuffer(data, np.uint8)
    npy.shape = img.height(), int(img.bytesPerLine() / 4), 4
    return npy[:, :, 0]
Пример #15
0
    def render(self):
        rect = QRect(QPoint(), self.geometry().size())
        self.m_backingStore.resize(rect.size())

        self.m_backingStore.beginPaint(QRegion(rect))

        device = self.m_backingStore.paintDevice()

        p = QPainter(device)
        p.drawImage(0, 0, self.m_image)

        font = QFont()
        font.setPixelSize(32)

        p.setFont(font)
        p.drawText(rect, 0, self.m_text)

        self.m_backingStore.endPaint()
        self.m_backingStore.flush(QRegion(rect))
Пример #16
0
    def paintEvent(self, event):
        if self.elideMode == 0:  # if not set then behave as a normal label
            QLabel.paintEvent(self, event)
        else:
            QFrame.paintEvent(self, event)
            painter = QPainter(self)
            painter.setFont(self.font())

            # gets the spacing between lines
            lineSpacing = self.fontMetrics().lineSpacing()
            y = 0

            textLayout = QTextLayout(self.text(), self.font())
            textLayout.beginLayout()

            # loops  til the end of line
            while True:
                # create a line
                line = textLayout.createLine()
                if line.isValid() != True:
                    break
                self.lines += 1
                # set limit of line width
                line.setLineWidth(self.width())
                # calculate position of next line
                nextLineY = y + lineSpacing

                if self.height() >= nextLineY + lineSpacing:
                    line.draw(painter, QPoint(0, y))
                    y = nextLineY
                else:  # regenerate each line so that they do not overflow the width of widget
                    lastLine = self.text()[line.textStart():len(self.text())]
                    elidedLastLine = self.fontMetrics().elidedText(
                        lastLine, Qt.ElideRight, self.width())
                    painter.drawText(
                        QPoint(0, y + self.fontMetrics().ascent()),
                        elidedLastLine)
                    line = textLayout.createLine()
                    break
            textLayout.endLayout()
Пример #17
0
    def paintEvent(self, event):
        """Override Qt method."""
        painter = QPainter(self)
        painter.setOpacity(self.current_opacity)

        max_width = (
            SASS_VARIABLES.WIDGET_CONTENT_TOTAL_WIDTH - 2 *
            SASS_VARIABLES.WIDGET_CONTENT_PADDING - 2 *
            SASS_VARIABLES.WIDGET_CONTENT_MARGIN
        )

        # Hover top
        br = self.label_icon.rect().bottomRight()
        tl = self.label_icon.rect().topLeft() + QPoint(1, 1)
        y = br.y() + self.label_text.height() - 2
        #        br_new = QPoint(br.x() + 2, y) - QPoint(1, 1)
        br_new = QPoint(max_width - 1, y) - QPoint(1, 1)
        rect_hover = QRect(tl, br_new)  # 2 is the border

        pen = QPen(Qt.NoPen)
        brush = QBrush(Qt.SolidPattern)
        brush.setColor(QColor('#fff'))
        painter.setBrush(brush)
        painter.setPen(pen)
        painter.drawRect(rect_hover)

        font = self.font()
        font.setPointSize(10)
        painter.setFont(font)
        pen = QPen()
        pen.setColor(QColor('black'))
        painter.setPen(pen)
        td = self.text_document
        td.setPageSize(QSizeF(rect_hover.size()))
        td.setHtml(self.summary)
        td.drawContents(painter)

        self.raise_()
Пример #18
0
    def paintEvent(self, event: QtGui.QPaintEvent):
        bar_width = 30

        if self.image is None:
            return

        rect = self.rect()
        number_of_marks = self.number_of_marks(rect.height())
        image_rect = QRect(rect.topLeft(),
                           QSize(bar_width,
                                 rect.size().height()))
        painter = QPainter(self)
        old_font = painter.font()
        new_font = painter.font()
        new_font.setPointSizeF(new_font.pointSizeF() / 1.1)
        painter.setFont(new_font)
        painter.drawImage(image_rect, self.image)
        if self.range[1] == self.range[0]:
            painter.drawText(bar_width + 5, 20, f"{self.range[1]}")
            painter.drawText(bar_width + 5,
                             rect.size().height(), f"{self.range[1]}")
            painter.setFont(old_font)
            return
        start_prop = 1 - (self.round_range[0] -
                          self.range[0]) / (self.range[1] - self.range[0])
        end_prop = 1 - (self.round_range[1] - self.range[0]) / (self.range[1] -
                                                                self.range[0])
        for pos, val in zip(
                np.linspace(10 + end_prop * rect.size().height(),
                            start_prop * rect.size().height(),
                            number_of_marks),
                np.linspace(self.round_range[1],
                            self.round_range[0],
                            number_of_marks,
                            dtype=np.uint32),
        ):
            painter.drawText(bar_width + 5, int(pos), f"{val}")
        painter.setFont(old_font)
Пример #19
0
def graph2icon(g: Graph,
               width: int,
               node_mode: bool,
               show_label: bool,
               monochrome: bool,
               *,
               except_node: Optional[int] = None,
               engine: str = "",
               pos: Optional[_Pos] = None) -> QIcon:
    """Draw a generalized chain graph."""
    if engine:
        pos = engine_picker(g, engine, node_mode)
    if pos is None:
        raise ValueError("no engine selected")
    if not pos:
        pixmap = QPixmap(width, width)
        pixmap.fill(Qt.transparent)
        return QIcon(pixmap)

    width_bound = -float('inf')
    for x, y in pos.values():
        if abs(x) > width_bound:
            width_bound = x
        if abs(y) > width_bound:
            width_bound = y
    width_bound *= 2.5
    image = QImage(QSize(int(width_bound), int(width_bound)),
                   QImage.Format_ARGB32_Premultiplied)
    image.fill(Qt.transparent)
    painter = QPainter(image)
    painter.translate(image.width() / 2, image.height() / 2)
    pen = QPen()
    r = int(width_bound / 50)
    pen.setWidth(r)
    painter.setPen(pen)
    _font.setPixelSize(r * 6)
    painter.setFont(_font)

    # Draw edges
    if node_mode:
        for l1, l2 in g.edges:
            if except_node in {l1, l2}:
                pen.setColor(Qt.gray)
            else:
                pen.setColor(Qt.black)
            painter.setPen(pen)

            painter.drawLine(QPointF(pos[l1][0], -pos[l1][1]),
                             QPointF(pos[l2][0], -pos[l2][1]))
    else:
        color = color_qt('dark-gray') if monochrome else LINK_COLOR
        color.setAlpha(150)
        painter.setBrush(QBrush(color))
        for link in g.vertices:
            if link == except_node:
                pen.setColor(Qt.gray)
            else:
                pen.setColor(Qt.black)
            painter.setPen(pen)

            painter.drawPolygon(*convex_hull([(pos[n][0], -pos[n][1])
                                              for n, edge in edges_view(g)
                                              if link in edge],
                                             as_qpoint=True))

    # Draw vertices
    for k, (x, y) in pos.items():
        if node_mode:
            color = color_num(len(list(g.neighbors(k))) - 1)
            if k == except_node:
                color.setAlpha(150)
        else:
            if monochrome:
                color = Qt.black
            elif except_node in dict(edges_view(g))[k]:
                color = color_qt('green')
            else:
                color = color_qt('blue')
        pen.setColor(color)
        painter.setPen(pen)
        painter.setBrush(QBrush(color))
        point = QPointF(x, -y)
        painter.drawEllipse(point, r, r)
        if show_label:
            pen.setColor(Qt.darkMagenta)
            painter.setPen(pen)
            painter.drawText(point, str(k))
    painter.end()
    return QIcon(QPixmap.fromImage(image).scaledToWidth(width))
Пример #20
0
class BaseCanvas(QWidget, metaclass=QABCMeta):
    """The subclass can draw a blank canvas more easier."""
    @abstractmethod
    def __init__(self, parent: QWidget):
        """Set the parameters for drawing."""
        super(BaseCanvas, self).__init__(parent)
        self.setSizePolicy(
            QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
        self.setFocusPolicy(Qt.StrongFocus)
        self.setMouseTracking(True)
        self.painter = QPainter()
        # Origin coordinate
        self.ox = self.width() / 2
        self.oy = self.height() / 2
        # Canvas zoom rate
        self.zoom = 1.
        # Joint size
        self.joint_size = 5
        # Canvas line width
        self.link_width = 3
        self.path_width = 3
        # Font size
        self.font_size = 15
        # Show point mark or dimension
        self.show_ticks = _TickMark.SHOW
        self.show_point_mark = True
        self.show_dimension = True
        # Path track
        self.path = _PathOption()
        # Path solving
        self.ranges: Dict[str, QRectF] = {}
        self.target_path: Dict[int, Sequence[_Coord]] = {}
        self.show_target_path = False
        # Background
        self.background = QImage()
        self.background_opacity = 1.
        self.background_scale = 1.
        self.background_offset = QPointF(0, 0)
        # Monochrome mode
        self.monochrome = False
        # Grab mode
        self.__grab_mode = False

    def switch_grab(self) -> None:
        """Start grab mode."""
        self.__grab_mode = not self.__grab_mode

    @staticmethod
    def zoom_factor(width: int, height: int, x_right: float, x_left: float,
                    y_top: float, y_bottom: float) -> float:
        """Calculate the zoom factor."""
        x_diff = x_left - x_right
        y_diff = y_top - y_bottom
        x_diff = x_diff if x_diff else 1.
        y_diff = y_diff if y_diff else 1.
        if width / x_diff < height / y_diff:
            return width / x_diff
        else:
            return height / y_diff

    @abstractmethod
    def paintEvent(self, event: QPaintEvent) -> None:
        """Using a QPainter under 'self',
        so just change QPen or QBrush before painting.
        """
        if not self.__grab_mode:
            self.painter.begin(self)
            self.painter.fillRect(event.rect(), QBrush(Qt.white))
        # Translation
        self.painter.translate(self.ox, self.oy)
        # Background
        if not self.background.isNull():
            rect = self.background.rect()
            self.painter.setOpacity(self.background_opacity)
            self.painter.drawImage(
                QRectF(
                    self.background_offset * self.zoom,
                    QSizeF(rect.width(), rect.height()) *
                    self.background_scale * self.zoom), self.background,
                QRectF(rect))
            self.painter.setOpacity(1)
        # Show frame
        pen = QPen(Qt.blue)
        pen.setWidth(1)
        self.painter.setPen(pen)
        self.painter.setFont(QFont("Arial", self.font_size))
        # Draw origin lines
        if self.show_ticks not in {_TickMark.SHOW, _TickMark.SHOW_NUM}:
            return
        pen.setColor(Qt.gray)
        self.painter.setPen(pen)
        x_l = -self.ox
        x_r = self.width() - self.ox
        self.painter.drawLine(QPointF(x_l, 0), QPointF(x_r, 0))
        y_t = self.height() - self.oy
        y_b = -self.oy
        self.painter.drawLine(QPointF(0, y_b), QPointF(0, y_t))

        def indexing(v: float) -> int:
            """Draw tick."""
            return int(v / self.zoom - v / self.zoom % 5)

        # Draw tick
        for x in range(indexing(x_l), indexing(x_r) + 1, 5):
            if x == 0:
                continue
            is_ten = x % 10 == 0
            end = QPointF(x * self.zoom, -10 if is_ten else -5)
            self.painter.drawLine(QPointF(x, 0) * self.zoom, end)
            if self.show_ticks == _TickMark.SHOW_NUM and is_ten:
                self.painter.drawText(end + QPointF(0, 3), f"{x}")
        for y in range(indexing(y_b), indexing(y_t) + 1, 5):
            if y == 0:
                continue
            is_ten = y % 10 == 0
            end = QPointF(10 if is_ten else 5, y * self.zoom)
            self.painter.drawLine(QPointF(0, y) * self.zoom, end)
            if self.show_ticks == _TickMark.SHOW_NUM and is_ten:
                self.painter.drawText(end + QPointF(3, 0), f"{-y}")
        # Please to call the "end" method when ending paint event.

    def draw_circle(self, p: QPointF, r: float) -> None:
        """Draw circle."""
        self.painter.drawEllipse(p, r, r)

    def draw_point(self,
                   i: int,
                   cx: float,
                   cy: float,
                   fixed: bool,
                   color: Optional[Tuple[int, int, int]],
                   mul: int = 1) -> None:
        """Draw a joint."""
        if self.monochrome or color is None:
            color = Qt.black
        else:
            color = QColor(*color)
        pen = QPen(color)
        pen.setWidth(2)
        self.painter.setPen(pen)
        x = cx * self.zoom
        y = cy * -self.zoom
        if fixed:
            # Draw a triangle below
            self.painter.drawPolygon(
                QPointF(x, y),
                QPointF(x - self.joint_size, y + 2 * self.joint_size),
                QPointF(x + self.joint_size, y + 2 * self.joint_size))
        r = self.joint_size
        for _ in range(1 if mul < 1 else mul):
            self.draw_circle(QPointF(x, y), r)
            r += 5
        if not self.show_point_mark:
            return
        pen.setColor(Qt.darkGray)
        pen.setWidth(2)
        self.painter.setPen(pen)
        text = f"[Point{i}]"
        if self.show_dimension:
            text += f":({cx:.02f}, {cy:.02f})"
        self.painter.drawText(QPointF(x, y) + QPointF(6, -6), text)

    def draw_ranges(self) -> None:
        """Draw rectangle ranges."""
        pen = QPen()
        pen.setWidth(5)
        for i, (tag, rect) in enumerate(self.ranges.items()):
            range_color = QColor(color_num(i + 1))
            range_color.setAlpha(30)
            self.painter.setBrush(range_color)
            range_color.setAlpha(255)
            pen.setColor(range_color)
            self.painter.setPen(pen)
            cx = rect.x() * self.zoom
            cy = rect.y() * -self.zoom
            if rect.width():
                self.painter.drawRect(
                    QRectF(QPointF(cx, cy),
                           QSizeF(rect.width(), rect.height()) * self.zoom))
            else:
                self.draw_circle(QPointF(cx, cy), 3)
            range_color.setAlpha(255)
            pen.setColor(range_color)
            self.painter.setPen(pen)
            self.painter.drawText(QPointF(cx, cy) + QPointF(6, -6), tag)
            self.painter.setBrush(Qt.NoBrush)

    def draw_target_path(self) -> None:
        """Draw solving path."""
        pen = QPen()
        pen.setWidth(self.path_width)
        for i, n in enumerate(sorted(self.target_path)):
            path = self.target_path[n]
            if self.monochrome:
                line, dot = target_path_style(0)
            else:
                line, dot = target_path_style(i + 1)
            pen.setColor(line)
            self.painter.setPen(pen)
            if len(path) == 1:
                x, y = path[0]
                p = QPointF(x, -y) * self.zoom
                self.painter.drawText(p + QPointF(6, -6), f"P{n}")
                pen.setColor(dot)
                self.painter.setPen(pen)
                self.draw_circle(p, self.joint_size)
            else:
                painter_path = QPainterPath()
                for j, (x, y) in enumerate(path):
                    p = QPointF(x, -y) * self.zoom
                    self.draw_circle(p, self.joint_size)
                    if j == 0:
                        self.painter.drawText(p + QPointF(6, -6), f"P{n}")
                        painter_path.moveTo(p)
                    else:
                        x2, y2 = path[j - 1]
                        self.__draw_arrow(x, -y, x2, -y2, zoom=True)
                        painter_path.lineTo(p)
                pen.setColor(line)
                self.painter.setPen(pen)
                self.painter.drawPath(painter_path)
                for x, y in path:
                    pen.setColor(dot)
                    self.painter.setPen(pen)
                    self.draw_circle(
                        QPointF(x, -y) * self.zoom, self.joint_size)
        self.painter.setBrush(Qt.NoBrush)

    def __draw_arrow(self,
                     x1: float,
                     y1: float,
                     x2: float,
                     y2: float,
                     *,
                     zoom: bool = False,
                     text: str = '') -> None:
        """Front point -> Back point"""
        if zoom:
            x1 *= self.zoom
            y1 *= self.zoom
            x2 *= self.zoom
            y2 *= self.zoom
        a = atan2(y2 - y1, x2 - x1)
        x1 = (x1 + x2) / 2 - 7.5 * cos(a)
        y1 = (y1 + y2) / 2 - 7.5 * sin(a)
        first_point = QPointF(x1, y1)
        self.painter.drawLine(
            first_point,
            QPointF(x1 + 15 * cos(a + radians(20)),
                    y1 + 15 * sin(a + radians(20))))
        self.painter.drawLine(
            first_point,
            QPointF(x1 + 15 * cos(a - radians(20)),
                    y1 + 15 * sin(a - radians(20))))
        if not text:
            return
        # Font
        font = self.painter.font()
        font_copy = QFont(font)
        font.setBold(True)
        font.setPointSize(font.pointSize() + 8)
        self.painter.setFont(font)
        # Color
        pen = self.painter.pen()
        color = pen.color()
        pen.setColor(color.darker())
        self.painter.setPen(pen)
        self.painter.drawText(first_point, text)
        pen.setColor(color)
        self.painter.setPen(pen)
        self.painter.setFont(font_copy)

    def draw_curve(self, path: Sequence[_Coord]) -> None:
        """Draw path as curve."""
        if len(set(path)) < 2:
            return
        painter_path = QPainterPath()
        error = False
        for i, (x, y) in enumerate(path):
            if isnan(x):
                error = True
                self.painter.drawPath(painter_path)
                painter_path = QPainterPath()
            else:
                p = QPointF(x, -y) * self.zoom
                if i == 0:
                    painter_path.moveTo(p)
                    self.draw_circle(p, 2)
                    continue
                if error:
                    painter_path.moveTo(p)
                    error = False
                else:
                    painter_path.lineTo(p)
        self.painter.drawPath(painter_path)

    def draw_dot(self, path: Sequence[_Coord]) -> None:
        """Draw path as dots."""
        if len(set(path)) < 2:
            return
        for i, (x, y) in enumerate(path):
            if isnan(x):
                continue
            p = QPointF(x, -y) * self.zoom
            if i == 0:
                self.draw_circle(p, 2)
            else:
                self.painter.drawPoint(p)

    def solution_polygon(
            self, func: str, args: Sequence[str], target: str,
            pos: Sequence[VPoint]) -> Tuple[List[QPointF], QColor]:
        """Get solution polygon."""
        if func == 'PLLP':
            color = QColor(121, 171, 252)
            params = [args[0], args[-1]]
        elif func == 'PLAP':
            color = QColor(249, 84, 216)
            params = [args[0]]
        else:
            if func == 'PLPP':
                color = QColor(94, 255, 185)
            else:
                # PXY
                color = QColor(249, 175, 27)
            params = [args[0]]
        params.append(target)
        tmp_list = []
        for name in params:
            try:
                index = int(name.replace('P', ''))
            except ValueError:
                continue
            else:
                vpoint = pos[index]
                tmp_list.append(QPointF(vpoint.cx, -vpoint.cy) * self.zoom)
        return tmp_list, color

    def draw_solution(self, func: str, args: Sequence[str], target: str,
                      pos: Sequence[VPoint]) -> None:
        """Draw the solution triangle."""
        points, color = self.solution_polygon(func, args, target, pos)
        color.setAlpha(150)
        pen = QPen(color)
        pen.setWidth(self.joint_size)
        self.painter.setPen(pen)

        def draw_arrow(index: int, text: str) -> None:
            """Draw arrow."""
            self.__draw_arrow(points[-1].x(),
                              points[-1].y(),
                              points[index].x(),
                              points[index].y(),
                              text=text)

        draw_arrow(0, args[1])
        if func == 'PLLP':
            draw_arrow(1, args[2])
        color.setAlpha(30)
        self.painter.setBrush(QBrush(color))
        self.painter.drawPolygon(QPolygonF(points))
        self.painter.setBrush(Qt.NoBrush)

    @Slot(int)
    def set_show_ticks(self, show: int):
        """Set the appearance of tick mark."""
        self.show_ticks = _TickMark(show + 1)
        self.update()

    @Slot(bool)
    def set_monochrome_mode(self, monochrome: bool) -> None:
        """Set monochrome mode."""
        self.monochrome = monochrome
        self.update()
Пример #21
0
    def paintEvent(self, event):
        """Override Qt method.

        Painting line number area
        """
        painter = QPainter(self)
        painter.fillRect(event.rect(), self.editor.sideareas_color)
        # This is needed to make that the font size of line numbers
        # be the same as the text one when zooming
        # See Issue 2296 and 4811
        font = self.editor.font()
        font_height = self.editor.fontMetrics().height()

        active_block = self.editor.textCursor().block()
        active_line_number = active_block.blockNumber() + 1

        def draw_pixmap(xleft, ytop, pixmap):
            if not QT55_VERSION:
                pixmap_height = pixmap.height()
            else:
                # scale pixmap height to device independent pixels
                pixmap_height = pixmap.height() / pixmap.devicePixelRatio()
            painter.drawPixmap(xleft, ytop + (font_height - pixmap_height) / 2,
                               pixmap)

        for top, line_number, block in self.editor.visible_blocks:
            if self._margin:
                if line_number == active_line_number:
                    font.setWeight(font.Bold)
                    painter.setFont(font)
                    painter.setPen(self.editor.normal_color)
                else:
                    font.setWeight(font.Normal)
                    painter.setFont(font)
                    painter.setPen(self.linenumbers_color)

                painter.drawText(0, top, self.width(), font_height,
                                 Qt.AlignRight | Qt.AlignBottom,
                                 to_text_string(line_number))

            size = self.get_markers_margin() - 2
            icon_size = QSize(size, size)

            data = block.userData()
            if self._markers_margin and data:
                if data.code_analysis:
                    errors = 0
                    warnings = 0
                    infos = 0
                    hints = 0
                    for _, _, sev, _ in data.code_analysis:
                        errors += sev == DiagnosticSeverity.ERROR
                        warnings += sev == DiagnosticSeverity.WARNING
                        infos += sev == DiagnosticSeverity.INFORMATION
                        hints += sev == DiagnosticSeverity.HINT

                    if errors:
                        draw_pixmap(1, top, self.error_icon.pixmap(icon_size))
                    elif warnings:
                        draw_pixmap(1, top,
                                    self.warning_icon.pixmap(icon_size))
                    elif infos:
                        draw_pixmap(1, top, self.info_icon.pixmap(icon_size))
                    elif hints:
                        draw_pixmap(1, top, self.hint_icon.pixmap(icon_size))

                if data.todo:
                    draw_pixmap(1, top, self.todo_icon.pixmap(icon_size))
Пример #22
0
    def paint(self, painter: QtGui.QPainter, option: 'QStyleOptionViewItem',
              index: QtCore.QModelIndex) -> None:
        if not index.isValid():
            return
        if option.state & QStyle.State_Selected:
            pass
        if option.state & QStyle.State_MouseOver:
            pass

        item = index.model().data(index, Qt.UserRole)
        if isinstance(item, QVariant):
            return

        painter.setRenderHint(QPainter.Antialiasing, True)
        painter.setRenderHints(QPainter.SmoothPixmapTransform)

        value = item['value']
        type = item['type']
        x = option.rect.x()
        y = option.rect.y()
        w = option.rect.width()
        h = option.rect.height()
        if type == 'device_activity':
            painter.save()
            # 图标
            icon = QImage(ResourceLoader().icon_path(value['icon']))
            rect_icon = QRectF(x + 20, y + 13, 44, 44)
            painter.drawImage(rect_icon, icon)
            # 设备标签
            painter.setFont(ResourceLoader().qt_font_text_xs)
            rect = calculate_text_rect('设备',
                                       painter=painter,
                                       x=x + 70,
                                       y=y + 15)
            painter.drawText(rect, Qt.TextSingleLine, '设备')
            # 设备编号
            painter.setPen(ResourceLoader().qt_color_label_link)
            painter.setFont(ResourceLoader().qt_font_text_xs)
            rect = calculate_text_rect(value['device'],
                                       painter=painter,
                                       x=x + 110,
                                       y=y + 15)
            painter.drawText(rect, Qt.TextSingleLine, value['device'])
            # 活动内容
            painter.setPen(ResourceLoader().qt_color_sub_text)
            painter.setFont(ResourceLoader().qt_font_text_xss)
            content = value['content'] + ',' + toDateStr()
            rect = calculate_text_rect(content,
                                       painter=painter,
                                       x=x + 70,
                                       y=y + 40)
            painter.drawText(rect, Qt.TextSingleLine, content)
            # 绘制边框
            path = QPainterPath()
            path.addRoundedRect(QRectF(x + 4, y + 4, w - 8, h - 8), 4, 4)
            painter.strokePath(path,
                               QPen(ResourceLoader().qt_color_background, 1))

            painter.restore()
        elif type == 'load_more':
            # 绘制加载图标
            # painter.save()
            # painter.translate(x+16, y+16)
            # self.loading_rotate += 5
            # painter.rotate(self.loading_rotate%360)
            # icon = qtawesome.icon('mdi.loading', color=ResourceLoader().qt_color_sub_text)
            # icon_pixmap = icon.pixmap(QSize(32, 32))
            # painter.drawPixmap(QRect(-16, -16, 32, 32), icon_pixmap)
            # painter.restore()
            # 绘制加载信息
            painter.save()
            painter.setFont(ResourceLoader().qt_font_text_xs)
            painter.setPen(ResourceLoader().qt_color_sub_text)
            _rect = calculate_text_rect('~~~ 正在努力加载 ~~~', painter=painter)
            rect = calculate_middle_rect(option.rect,
                                         width=_rect.width(),
                                         height=_rect.height())
            painter.drawText(rect, Qt.TextSingleLine, '~~~ 正在努力加载 ~~~')
            painter.restore()
        elif type == 'no_more':
            painter.save()
            painter.setFont(ResourceLoader().qt_font_text_xs)
            painter.setPen(ResourceLoader().qt_color_sub_text)
            _rect = calculate_text_rect('--- 我是有底线的 ---', painter=painter)
            rect = calculate_middle_rect(option.rect,
                                         width=_rect.width(),
                                         height=_rect.height())
            painter.drawText(rect, Qt.TextSingleLine, '--- 我是有底线的 ---')
            painter.restore()
        else:
            self.initStyleOption(option, index)
            QStyledItemDelegate.paint(self, painter, option, index)