예제 #1
0
    def paintEvent(self, event):
        """
        Qt override.

        Draw lower left border of the main Stacked Widget.
        """
        super(MainWindow, self).paintEvent(event)
        tab = self.stack.tabbar
        tab_pos = self.mapTo(self, tab.pos())
        pane_pos = self.mapTo(self, self.stack.pos())

        stack_height = self.stack.height()
        menu_height = self.menuBar().height()
        header_height = 49  # From css
        padding = 20  # From css
        left = 1  # From css
        extra = 8  # Still wondering where this extra Y delta is
        deltay = menu_height + header_height + tab.height() + padding + extra
        x0 = tab_pos.x() + tab.width() + padding - left
        y0 = tab_pos.y() + deltay
        y1 = pane_pos.y() + stack_height + deltay - tab.height() - padding

        painter = QPainter(self)
        painter.setPen(QPen(QColor('#006f43'), 1, Qt.SolidLine, Qt.RoundCap))
        painter.drawLine(x0, y0, x0, y1)
예제 #2
0
    def paintEvent(self, e):
        if self.points is None:
            return
        painter = QPainter(self)
        pen = QPen()  # creates a default pen

        pen.setWidth(2)
        pen.setCapStyle(Qt.RoundCap)
        pen.setJoinStyle(Qt.RoundJoin)
        painter.setPen(pen)
        painter.setRenderHint(QPainter.Antialiasing)

        # to avoid zero division
        m = max(max(self.points), 10)
        for i, v in enumerate(self.points):
            pen.setBrush(self.colors[min(v * len(self.colors) // m,
                                         len(self.colors) - 1)])
            painter.setPen(pen)
            painter.drawLine(
                40 + 5 * i,
                self.height() // 2 - min(v, self.height()) // 2,
                40 + 5 * i,
                self.height() // 2 + min(v, self.height()) // 2,
            )

        painter.end()
예제 #3
0
    def paintEvent(self, a0: QPaintEvent) -> None:
        super().paintEvent(a0)
        painter = QPainter(self)
        painter.save()
        painter.setRenderHint(QPainter.Antialiasing)
        rect = QRectF(self.margin, self.margin,
                      self.width() - self.margin * 2,
                      self.height() - 2 * self.margin)
        painter.setBrush(Qt.white)
        painter.setPen(Qt.white)
        painter.drawEllipse(rect)

        painter.restore()
        painter.save()
        painter.setRenderHint(QPainter.Antialiasing)
        pen = QPen()
        pen.setWidth(2)
        painter.setPen(pen)
        mid_point = QPointF(a0.rect().width() / 2, a0.rect().height() / 2)
        radius = min(a0.rect().height(), a0.rect().width()) / 3
        rays_num = 10
        for i in range(rays_num):
            point = QPointF(
                math.sin(math.pi / (rays_num / 2) * i) * radius,
                math.cos(math.pi / (rays_num / 2) * i) * radius)
            painter.drawLine(mid_point + (point * 0.4), mid_point + point)
        painter.restore()
예제 #4
0
    def paintEvent(self, event: QtGui.QPaintEvent):
        border_distance = 5
        rect = self.rect()
        mid = rect.y() + rect.height() / 2
        line_begin = QPointF(rect.height() + 10 + self.text_size.width(), mid)
        line_end = QPointF(rect.width() + rect.x() - 5, mid)
        triangle = QPolygonF()
        side_length = rect.height() - 2 * border_distance
        triangle_height = side_length * sqrt(3) / 2
        start_point = QPointF(rect.x() + border_distance, rect.y() + border_distance)

        if self.isChecked():
            triangle.append(start_point)
            triangle.append(start_point + QPointF(0, side_length))
            triangle.append(start_point + QPointF(triangle_height, side_length / 2))
        else:
            triangle.append(start_point)
            triangle.append(start_point + QPointF(side_length, 0))
            triangle.append(start_point + QPointF(side_length / 2, triangle_height))
        painter = QPainter(self)

        painter.setBrush(Qt.black)
        top = rect.height() - (self.text_size.height() / 2)
        painter.drawText(rect.height() + 5, top, self.info_text)
        painter.drawPolygon(triangle, Qt.WindingFill)
        painter.drawLine(QLineF(line_begin, line_end))
예제 #5
0
 def legendIcon(self, index, size):
     """
     :param int index: Index of the legend entry (ignored as there is only one)
     :param QSizeF size: Icon size
     :return: Icon representing the marker on the legend
     
     .. seealso::
     
         :py:meth:`qwt.plot.QwtPlotItem.setLegendIconSize()`,
         :py:meth:`qwt.plot.QwtPlotItem.legendData()`
     """
     if size.isEmpty():
         return QwtGraphic()
     icon = QwtGraphic()
     icon.setDefaultSize(size)
     icon.setRenderHint(QwtGraphic.RenderPensUnscaled, True)
     painter = QPainter(icon)
     painter.setRenderHint(
         QPainter.Antialiasing,
         self.testRenderHint(QwtPlotItem.RenderAntialiased))
     if self.__data.style != QwtPlotMarker.NoLine:
         painter.setPen(self.__data.pen)
         if self.__data.style in (QwtPlotMarker.HLine, QwtPlotMarker.Cross):
             y = 0.5 * size.height()
             painter.drawLine(0.0, y, size.width(), y)
         if self.__data.style in (QwtPlotMarker.VLine, QwtPlotMarker.Cross):
             x = 0.5 * size.width()
             painter.drawLine(x, 0.0, x, size.height())
     if self.__data.symbol:
         r = QRect(0, 0, size.width(), size.height())
         self.__data.symbol.drawSymbol(painter, r)
     return icon
예제 #6
0
    def paintEvent(self, event):
        """Override Qt method."""
        painter = QPainter(self)

        color = QColor(self.color)
        color.setAlphaF(.5)
        painter.setPen(color)
        offset = self.editor.document().documentMargin() + \
            self.editor.contentOffset().x()
        folding_panel = self.editor.panels.get('FoldingPanel')
        folding_regions = folding_panel.folding_regions
        folding_status = folding_panel.folding_status
        leading_whitespaces = self.editor.leading_whitespaces
        for line_number in folding_regions:
            post_update = False
            end_line = folding_regions[line_number]
            start_block = self.editor.document().findBlockByNumber(line_number)
            end_block = self.editor.document().findBlockByNumber(end_line - 1)
            top = int(
                self.editor.blockBoundingGeometry(start_block).translated(
                    self.editor.contentOffset()).top())
            bottom = int(
                self.editor.blockBoundingGeometry(end_block).translated(
                    self.editor.contentOffset()).bottom())
            total_whitespace = leading_whitespaces.get(max(line_number - 1, 0))
            end_whitespace = leading_whitespaces.get(end_line - 1)
            if end_whitespace and end_whitespace != total_whitespace:
                x = (self.editor.fontMetrics().width(total_whitespace * '9') +
                     self.bar_offset + offset)
                painter.drawLine(x, top, x, bottom)
예제 #7
0
    def mouseReleaseEvent(self, event):
        if self.m_lastPos != QPoint(-1, -1):
            p = QPainter(self.m_image)
            p.setRenderHint(QPainter.Antialiasing)
            p.drawLine(self.m_lastPos, event.pos())
            self.m_lastPos = QPoint(-1, -1)

            self.scheduleRender()
예제 #8
0
파일: edgeline.py 프로젝트: wkx228/spyder
    def paintEvent(self, event):
        """Override Qt method"""
        painter = QPainter(self)
        size = self.size()

        color = QColor(self.color)
        color.setAlphaF(.5)
        painter.setPen(color)

        for column in self.columns:
            x = self.editor.fontMetrics().width(column * '9')
            painter.drawLine(x, 0, x, size.height())
예제 #9
0
    def paint(self, painter: QPainter, _option, _widget: QWidget):
        # set color depending on wether the value belongs to the scenario
        if self.id in self.map.appdata.project.scen_values.keys():
            painter.setPen(Qt.magenta)
            painter.setBrush(Qt.magenta)
        else:
            painter.setPen(Qt.darkGray)

        painter.drawRect(-15, -15, 20, 20)
        painter.setPen(Qt.darkGray)
        painter.drawLine(-5, 0, -5, -10)
        painter.drawLine(0, -5, -10, -5)
예제 #10
0
    def paintEvent(self, event):
        """
        Overriden Qt method.

        Paint indent guides.
        """
        # Set painter
        painter = QPainter(self)
        color = QColor(self.color)
        color.setAlphaF(.5)
        painter.setPen(color)

        # Compute offset
        offset = (self.editor.document().documentMargin() +
                  self.editor.contentOffset().x())

        # Folding info
        folding_panel = self.editor.panels.get('FoldingPanel')
        folding_regions = folding_panel.folding_regions
        leading_whitespaces = self.editor.leading_whitespaces

        # Visible block numbers
        visible_blocks = self.editor.get_visible_block_numbers()

        # Paint lines
        for start_line in folding_regions:
            end_line = folding_regions[start_line]
            line_numbers = (start_line, end_line)

            if self.do_paint(visible_blocks, line_numbers):
                start_block = self.editor.document().findBlockByNumber(
                    start_line)
                end_block = self.editor.document().findBlockByNumber(end_line -
                                                                     1)

                content_offset = self.editor.contentOffset()
                top = int(
                    self.editor.blockBoundingGeometry(start_block).translated(
                        content_offset).top())
                bottom = int(
                    self.editor.blockBoundingGeometry(end_block).translated(
                        content_offset).bottom())

                total_whitespace = leading_whitespaces.get(
                    max(start_line - 1, 0))
                end_whitespace = leading_whitespaces.get(end_line - 1)

                if end_whitespace and end_whitespace != total_whitespace:
                    font_metrics = self.editor.fontMetrics()
                    x = int(
                        font_metrics.width(total_whitespace * '9') +
                        self.bar_offset + offset)
                    painter.drawLine(x, top, x, bottom)
예제 #11
0
    def paintEvent(self, event):
        """Override Qt method"""
        painter = QPainter(self)
        size = self.size()

        offsets = [col - min(self.columns) for col in self.columns]
        for offset in offsets:
            color = QColor(self.color)
            color.setAlphaF(.5)
            painter.setPen(color)

            x = self.editor.fontMetrics().width(offset * '9')
            painter.drawLine(x, 0, x, size.height())
예제 #12
0
    def paintEvent(self, event):
        """Override Qt method"""
        painter = QPainter(self)
        size = self.size()

        color = QColor(self.color)
        color.setAlphaF(.5)
        painter.setPen(color)

        for column in self.columns:
            # draw edge line at column n + 3 to account for line number margin
            x = self.editor.fontMetrics().width(column * '9') + 3
            painter.drawLine(x, 0, x, size.height())
예제 #13
0
    def paintEvent(self, event):
        """Override Qt method."""
        painter = QPainter(self)

        color = QColor(self.color)
        color.setAlphaF(.5)
        painter.setPen(color)
        offset = self.editor.document().documentMargin() + \
            self.editor.contentOffset().x()

        for _, line_number, block in self.editor.visible_blocks:

            indentation = TextBlockHelper.get_fold_lvl(block)
            ref_lvl = indentation
            block = block.next()
            last_line = block.blockNumber()
            lvl = TextBlockHelper.get_fold_lvl(block)
            if ref_lvl == lvl:  # for zone set programmatically such as imports
                # in pyqode.python
                ref_lvl -= 1

            while (block.isValid() and
                   TextBlockHelper.get_fold_lvl(block) > ref_lvl):
                last_line = block.blockNumber()
                block = block.next()

            end_of_sub_fold = block
            if last_line:
                block = block.document().findBlockByNumber(last_line)
                while ((block.blockNumber()) and (block.text().strip() == ''
                       or block.text().strip().startswith('#'))):
                    block = block.previous()
                    last_line = block.blockNumber()

            block = self.editor.document().findBlockByNumber(line_number)
            top = int(self.editor.blockBoundingGeometry(block).translated(
                self.editor.contentOffset()).top())
            bottom = top + int(self.editor.blockBoundingRect(block).height())

            indentation = TextBlockHelper.get_fold_lvl(block)

            for i in range(1, indentation):
                if (line_number > last_line and
                        TextBlockHelper.get_fold_lvl(end_of_sub_fold) <= i):
                    continue
                else:
                    x = self.editor.fontMetrics().width(i * self.i_width *
                                                        '9') + offset
                    painter.drawLine(x, top, x, bottom)
예제 #14
0
    def paintEvent(self, event):
        """Override Qt method."""
        painter = QPainter(self)

        color = QColor(self.color)
        color.setAlphaF(.5)
        painter.setPen(color)
        offset = self.editor.document().documentMargin() + \
            self.editor.contentOffset().x()

        for _, line_number, block in self.editor.visible_blocks:

            indentation = TextBlockHelper.get_fold_lvl(block)
            ref_lvl = indentation
            block = block.next()
            last_line = block.blockNumber()
            lvl = TextBlockHelper.get_fold_lvl(block)
            if ref_lvl == lvl:  # for zone set programmatically such as imports
                # in pyqode.python
                ref_lvl -= 1

            while (block.isValid() and
                   TextBlockHelper.get_fold_lvl(block) > ref_lvl):
                last_line = block.blockNumber()
                block = block.next()

            end_of_sub_fold = block
            if last_line:
                block = block.document().findBlockByNumber(last_line)
                while ((block.blockNumber()) and (block.text().strip() == ''
                       or block.text().strip().startswith('#'))):
                    block = block.previous()
                    last_line = block.blockNumber()

            block = self.editor.document().findBlockByNumber(line_number)
            top = int(self.editor.blockBoundingGeometry(block).translated(
                self.editor.contentOffset()).top())
            bottom = top + int(self.editor.blockBoundingRect(block).height())

            indentation = TextBlockHelper.get_fold_lvl(block)

            for i in range(1, indentation):
                if (line_number > last_line and
                        TextBlockHelper.get_fold_lvl(end_of_sub_fold) <= i):
                    continue
                else:
                    x = self.editor.fontMetrics().width(i * self.i_width *
                                                        '9') + offset
                    painter.drawLine(x, top, x, bottom)
예제 #15
0
    def paintEvent(self, event):
        """Override Qt method."""
        painter = QPainter(self)

        color = QColor(self.color)
        color.setAlphaF(.5)
        painter.setPen(color)

        for top, line_number, block in self.editor.visible_blocks:
            bottom = top + int(self.editor.blockBoundingRect(block).height())

            indentation = TextBlockHelper.get_fold_lvl(block)

            for i in range(1, indentation):
                x = self.editor.fontMetrics().width(i * self.i_width * '9')
                painter.drawLine(x, top, x, bottom)
예제 #16
0
    def paintEvent(self, event):
        """Override Qt method."""
        painter = QPainter(self)

        color = QColor(self.color)
        color.setAlphaF(.5)
        painter.setPen(color)

        for top, line_number, block in self.editor.visible_blocks:
            bottom = top + int(self.editor.blockBoundingRect(block).height())

            indentation = TextBlockHelper.get_fold_lvl(block)

            for i in range(1, indentation):
                x = self.editor.fontMetrics().width(i * self.i_width * '9')
                painter.drawLine(x, top, x, bottom)
예제 #17
0
    def drawColorBar(self, painter, colorMap, interval, scaleMap, orientation,
                     rect):
        """
        Draw a color bar into a rectangle

        :param QPainter painter: Painter
        :param qwt.color_map.QwtColorMap colorMap: Color map
        :param qwt.interval.QwtInterval interval: Value range
        :param qwt.scalemap.QwtScaleMap scaleMap: Scale map
        :param Qt.Orientation orientation: Orientation
        :param QRectF rect: Target rectangle
        """
        colorTable = []
        if colorMap.format() == QwtColorMap.Indexed:
            colorTable = colorMap.colorTable(interval)
        c = QColor()
        devRect = rect.toAlignedRect()
        pixmap = QPixmap(devRect.size())
        pixmap.fill(Qt.transparent)
        pmPainter = QPainter(pixmap)
        pmPainter.translate(-devRect.x(), -devRect.y())
        if orientation == Qt.Horizontal:
            sMap = QwtScaleMap(scaleMap)
            sMap.setPaintInterval(rect.left(), rect.right())
            for x in range(devRect.left(), devRect.right() + 1):
                value = sMap.invTransform(x)
                if colorMap.format() == QwtColorMap.RGB:
                    c.setRgba(colorMap.rgb(interval, value))
                else:
                    c = colorTable[colorMap.colorIndex(interval, value)]
                pmPainter.setPen(c)
                pmPainter.drawLine(
                    QLineF(x, devRect.top(), x, devRect.bottom()))
        else:
            sMap = QwtScaleMap(scaleMap)
            sMap.setPaintInterval(rect.bottom(), rect.top())
            for y in range(devRect.top(), devRect.bottom() + 1):
                value = sMap.invTransform(y)
                if colorMap.format() == QwtColorMap.RGB:
                    c.setRgba(colorMap.rgb(interval, value))
                else:
                    c = colorTable[colorMap.colorIndex(interval, value)]
                pmPainter.setPen(c)
                pmPainter.drawLine(
                    QLineF(devRect.left(), y, devRect.right(), y))
        pmPainter.end()
        self.drawPixmap(painter, rect, pixmap)
예제 #18
0
 def legendIcon(self, index, size):
     """
     :param int index: Index of the legend entry (ignored as there is only one)
     :param QSizeF size: Icon size
     :return: Icon representing the curve on the legend
     
     .. seealso::
     
         :py:meth:`qwt.plot.QwtPlotItem.setLegendIconSize()`,
         :py:meth:`qwt.plot.QwtPlotItem.legendData()`
     """
     if size.isEmpty():
         return QwtGraphic()
     graphic = QwtGraphic()
     graphic.setDefaultSize(size)
     graphic.setRenderHint(QwtGraphic.RenderPensUnscaled, True)
     painter = QPainter(graphic)
     painter.setRenderHint(
         QPainter.Antialiasing,
         self.testRenderHint(QwtPlotItem.RenderAntialiased))
     if self.__data.legendAttributes == 0 or (
             self.__data.legendAttributes & QwtPlotCurve.LegendShowBrush):
         brush = self.__data.brush
         if brush.style(
         ) == Qt.NoBrush and self.__data.legendAttributes == 0:
             if self.style() != QwtPlotCurve.NoCurve:
                 brush = QBrush(self.pen().color())
             elif (self.__data.symbol
                   and self.__data.symbol.style() != QwtSymbol.NoSymbol):
                 brush = QBrush(self.__data.symbol.pen().color())
         if brush.style() != Qt.NoBrush:
             r = QRectF(0, 0, size.width(), size.height())
             painter.fillRect(r, brush)
     if self.__data.legendAttributes & QwtPlotCurve.LegendShowLine:
         if self.pen() != Qt.NoPen:
             pn = self.pen()
             #                pn.setCapStyle(Qt.FlatCap)
             painter.setPen(pn)
             y = 0.5 * size.height()
             painter.drawLine(0.0, y, size.width(), y)
     if self.__data.legendAttributes & QwtPlotCurve.LegendShowSymbol:
         if self.__data.symbol:
             r = QRectF(0, 0, size.width(), size.height())
             self.__data.symbol.drawSymbol(painter, r)
     return graphic
예제 #19
0
 def drawline(self, p1, p2, angle, tip=False):
     painter = QPainter()
     painter.begin(self)
     painter.setRenderHint(QPainter.Antialiasing)
     painter.setPen(Qt.blue)
     pen = painter.pen()
     pen.setWidth(2)
     painter.setPen(pen)
     painter.setBrush(Qt.blue)
     painter.translate(p1)
     painter.rotate(angle)
     pt = (p2 - p1)
     if tip:
         pt /= (pt.x()**2 + pt.y()**2)**0.5 / 10
     # painter.scale(scale, scale)
     # painter.drawLine(QPoint(0, 0), (p2-p1)*scale)
     painter.drawLine(QPoint(0, 0), pt)
     return painter
예제 #20
0
    def paintEvent(self, event):
        painter = QPainter()
        painter.begin(self.pixmap)
        painter.drawPixmap(0, 0, self.pixmap)

        pen1 = QPen(QColor(self.c1), 1)
        pen2 = QPen(QColor(self.c2), 2)

        painter.setPen(pen1)
        y = self.size - 1
        for x in range(self.size):
            painter.drawLine(0, x, y, x)
            y = y - 1

        painter.setPen(pen2)
        y = 1
        for x in range(self.size, 0, -1):
            painter.drawLine(y, x, self.size, x)
            y = y + 1

        painter.end()
예제 #21
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()
예제 #22
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))
예제 #23
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()
예제 #24
0
파일: utils.py 프로젝트: tlambert03/napari
def crosshair_pixmap():
    """Create a cross cursor with white/black hollow square pixmap in the middle.
    For use as points cursor."""

    size = 25

    pixmap = QPixmap(QSize(size, size))
    pixmap.fill(Qt.transparent)
    painter = QPainter(pixmap)

    # Base measures
    width = 1
    center = 3  # Must be odd!
    rect_size = center + 2 * width
    square = rect_size + width * 4

    pen = QPen(Qt.white, 1)
    pen.setJoinStyle(Qt.PenJoinStyle.MiterJoin)
    painter.setPen(pen)

    # # Horizontal rectangle
    painter.drawRect(0, (size - rect_size) // 2, size - 1, rect_size - 1)

    # Vertical rectangle
    painter.drawRect((size - rect_size) // 2, 0, rect_size - 1, size - 1)

    # Square
    painter.drawRect(
        (size - square) // 2, (size - square) // 2, square - 1, square - 1
    )

    pen = QPen(Qt.black, 2)
    pen.setJoinStyle(Qt.PenJoinStyle.MiterJoin)
    painter.setPen(pen)

    # # Square
    painter.drawRect(
        (size - square) // 2 + 2,
        (size - square) // 2 + 2,
        square - 4,
        square - 4,
    )

    pen = QPen(Qt.black, 3)
    pen.setJoinStyle(Qt.PenJoinStyle.MiterJoin)
    painter.setPen(pen)

    # # # Horizontal lines
    mid_vpoint = QPoint(2, size // 2)
    painter.drawLine(
        mid_vpoint, QPoint(((size - center) // 2) - center + 1, size // 2)
    )
    mid_vpoint = QPoint(size - 3, size // 2)
    painter.drawLine(
        mid_vpoint, QPoint(((size - center) // 2) + center + 1, size // 2)
    )

    # # # Vertical lines
    mid_hpoint = QPoint(size // 2, 2)
    painter.drawLine(
        QPoint(size // 2, ((size - center) // 2) - center + 1), mid_hpoint
    )
    mid_hpoint = QPoint(size // 2, size - 3)
    painter.drawLine(
        QPoint(size // 2, ((size - center) // 2) + center + 1), mid_hpoint
    )

    painter.end()
    return pixmap
예제 #25
0
파일: scale.py 프로젝트: slaclab/pydm
class QScale(QFrame):
    """
    A bar-shaped indicator for scalar value.
    Configurable features include indicator type (bar/pointer), scale tick
    marks and orientation (horizontal/vertical).

    Parameters
    ----------
    parent : QWidget
        The parent widget for the Scale
    """
    def __init__(self, parent=None):
        super(QScale, self).__init__(parent)
        self._value = 1
        self._lower_limit = -5
        self._upper_limit = 5
        self.position = None  # unit: pixel

        self._bg_color = QColor('darkgray')
        self._bg_size_rate = 0.8    # from 0 to 1

        self._indicator_color = QColor('black')
        self._pointer_width_rate = 0.05
        self._barIndicator = False

        self._num_divisions = 10
        self._show_ticks = True
        self._tick_pen = QPen()
        self._tick_color = QColor('black')
        self._tick_width = 0
        self._tick_size_rate = 0.1  # from 0 to 1
        self._painter = QPainter()

        self._painter_rotation = None
        self._painter_translation_y = None
        self._painter_translation_x = None
        self._painter_scale_x = None
        self._flip_traslation_y = None
        self._flip_scale_y = None

        self._widget_width = self.width()
        self._widget_height = self.height()

        self._orientation = Qt.Horizontal
        self._inverted_appearance = False
        self._flip_scale = False
        self._scale_height = 35
        self._origin_at_zero = False
        self._origin_position = 0

        self.set_position()

    def adjust_transformation(self):
        """
        This method sets parameters for the widget transformations (needed to for
        orientation, flipping and appearance inversion).
        """
        self.setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)  # Unset fixed size
        if self._orientation == Qt.Horizontal:
            self._widget_width = self.width()
            self._widget_height = self.height()
            self._painter_translation_y = 0
            self._painter_rotation = 0
            self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
            self.setFixedHeight(self._scale_height)
        elif self._orientation == Qt.Vertical:
            # Invert dimensions for paintEvent()
            self._widget_width = self.height()
            self._widget_height = self.width()
            self._painter_translation_y = self._widget_width
            self._painter_rotation = -90
            self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)
            self.setFixedWidth(self._scale_height)

        if self._inverted_appearance:
            self._painter_translation_x = self._widget_width
            self._painter_scale_x = -1
        else:
            self._painter_translation_x = 0
            self._painter_scale_x = 1

        if self._flip_scale:
            self._flip_traslation_y = self._widget_height
            self._flip_scale_y = -1
        else:
            self._flip_traslation_y = 0
            self._flip_scale_y = 1

    def set_tick_pen(self):
        """
        Define pen style for drawing scale tick marks.
        """
        self._tick_pen.setColor(self._tick_color)
        self._tick_pen.setWidth(self._tick_width)

    def draw_ticks(self):
        """
        Draw tick marks on the scale.
        """
        if not self._show_ticks:
            return
        self.set_tick_pen()
        self._painter.setPen(self._tick_pen)
        division_size = self._widget_width / self._num_divisions
        tick_y0 = self._widget_height
        tick_yf = (1 - self._tick_size_rate)*self._widget_height
        for i in range(self._num_divisions+1):
            x = i*division_size
            self._painter.drawLine(x, tick_y0, x, tick_yf) # x1, y1, x2, y2

    def draw_bar(self):
        """
        Draw a bar as indicator of current value.
        """
        self.set_origin()
        self.set_position()

        if self.position < 0 or self.position > self._widget_width:
            return
        self._painter.setPen(Qt.transparent)
        self._painter.setBrush(self._indicator_color)
        bar_width = self.position - self._origin_position
        bar_height = self._bg_size_rate * self._widget_height
        self._painter.drawRect(self._origin_position, 0, bar_width, bar_height)

    def draw_pointer(self):
        """
        Draw a pointer as indicator of current value.
        """
        self.set_position()
        if self.position < 0 or self.position > self._widget_width:
            return
        self._painter.setPen(Qt.transparent)
        self._painter.setBrush(self._indicator_color)
        pointer_width = self._pointer_width_rate * self._widget_width
        pointer_height = self._bg_size_rate * self._widget_height
        points = [
            QPoint(self.position, 0),
            QPoint(self.position + 0.5*pointer_width, 0.5*pointer_height),
            QPoint(self.position, pointer_height),
            QPoint(self.position - 0.5*pointer_width, 0.5*pointer_height)
        ]
        self._painter.drawPolygon(QPolygon(points))

    def draw_indicator(self):
        """
        Draw the selected indicator for current value.
        """
        if self._barIndicator:
            self.draw_bar()
        else:
            self.draw_pointer()

    def draw_background(self):
        """
        Draw the background of the scale.
        """
        self._painter.setPen(Qt.transparent)
        self._painter.setBrush(self._bg_color)
        bg_width = self._widget_width
        bg_height = self._bg_size_rate * self._widget_height
        self._painter.drawRect(0, 0, bg_width, bg_height)

    def paintEvent(self, event):
        """
        Paint events are sent to widgets that need to update themselves,
        for instance when part of a widget is exposed because a covering
        widget was moved.

        Parameters
        ----------
        event : QPaintEvent
        """
        self.adjust_transformation()
        self._painter.begin(self)
        self._painter.translate(0, self._painter_translation_y) # Draw vertically if needed
        self._painter.rotate(self._painter_rotation)
        self._painter.translate(self._painter_translation_x, 0) # Invert appearance if needed
        self._painter.scale(self._painter_scale_x, 1)

        self._painter.translate(0, self._flip_traslation_y)     # Invert scale if needed
        self._painter.scale(1, self._flip_scale_y)

        self._painter.setRenderHint(QPainter.Antialiasing)

        self.draw_background()
        self.draw_ticks()
        self.draw_indicator()

        self._painter.end()

    def calculate_position_for_value(self, value):
        """
        Calculate the position (pixel) in which the pointer should be drawn for a given value.
        """
        if value < self._lower_limit or value > self._upper_limit or \
           self._upper_limit - self._lower_limit == 0:
            proportion = -1 # Invalid
        else:
            proportion = (value - self._lower_limit) / (self._upper_limit - self._lower_limit)

        position = int(proportion * self._widget_width)
        return position

    def set_origin(self):
        """
        Set the position (pixel) in which the origin should be drawn.
        """
        if self._origin_at_zero:
            self._origin_position = self.calculate_position_for_value(0)
        else:
            self._origin_position = 0

    def set_position(self):
        """
        Set the position (pixel) in which the pointer should be drawn.
        """
        self.position = self.calculate_position_for_value(self._value)

    def update_indicator(self):
        """
        Update the position and the drawing of indicator.
        """
        self.set_position()
        self.repaint()

    def set_value(self, value):
        """
        Set a new current value for the indicator.
        """
        self._value = value
        self.update_indicator()

    def set_upper_limit(self, new_limit):
        """
        Set the scale upper limit.

        Parameters
        ----------
        new_limit : float
            The upper limit of the scale.
        """
        self._upper_limit = new_limit

    def set_lower_limit(self, new_limit):
        """
        Set the scale lower limit.

        Parameters
        ----------
        new_limit : float
            The lower limit of the scale.
        """
        self._lower_limit = new_limit

    def get_show_ticks(self):
        return self._show_ticks

    def set_show_ticks(self, checked):
        if self._show_ticks != bool(checked):
            self._show_ticks = checked
            self.repaint()

    def get_orientation(self):
        return self._orientation

    def set_orientation(self, orientation):
        self._orientation = orientation
        self.adjust_transformation()
        self.repaint()

    def get_flip_scale(self):
        return self._flip_scale

    def set_flip_scale(self, checked):
        self._flip_scale = bool(checked)
        self.adjust_transformation()
        self.repaint()

    def get_inverted_appearance(self):
        return self._inverted_appearance

    def set_inverted_appearance(self, inverted):
        self._inverted_appearance = inverted
        self.adjust_transformation()
        self.repaint()

    def get_bar_indicator(self):
        return self._barIndicator

    def set_bar_indicator(self, checked):
        if self._barIndicator != bool(checked):
            self._barIndicator = checked
            self.repaint()

    def get_background_color(self):
        return self._bg_color

    def set_background_color(self, color):
        self._bg_color = color
        self.repaint()

    def get_indicator_color(self):
        return self._indicator_color

    def set_indicator_color(self, color):
        self._indicator_color = color
        self.repaint()

    def get_tick_color(self):
        return self._tick_color

    def set_tick_color(self, color):
        self._tick_color = color
        self.repaint()

    def get_background_size_rate(self):
        return self._bg_size_rate

    def set_background_size_rate(self, rate):
        if rate >= 0 and rate <=1 and self._bg_size_rate != rate:
            self._bg_size_rate = rate
            self.repaint()

    def get_tick_size_rate(self):
        return self._tick_size_rate

    def set_tick_size_rate(self, rate):
        if rate >= 0 and rate <=1 and self._tick_size_rate != rate:
            self._tick_size_rate = rate
            self.repaint()

    def get_num_divisions(self):
        return self._num_divisions

    def set_num_divisions(self, divisions):
        if isinstance(divisions, int) and divisions > 0 and self._num_divisions != divisions:
            self._num_divisions = divisions
            self.repaint()

    def get_scale_height(self):
        return self._scale_height

    def set_scale_height(self, value):
        self._scale_height = int(value)
        self.adjust_transformation()
        self.repaint()

    def get_origin_at_zero(self):
        return self._origin_at_zero

    def set_origin_at_zero(self, checked):
        if self._origin_at_zero != bool(checked):
            self._origin_at_zero = checked
            self.repaint()
예제 #26
0
파일: scale.py 프로젝트: vbaggiol/pydm
class QScale(QFrame):
    """
    A bar-shaped indicator for scalar value.
    Configurable features include indicator type (bar/pointer), scale tick
    marks and orientation (horizontal/vertical).

    Parameters
    ----------
    parent : QWidget
        The parent widget for the Scale
    """
    def __init__(self, parent=None):
        super(QScale, self).__init__(parent)
        self._value = 1
        self._lower_limit = -5
        self._upper_limit = 5
        self.position = None  # unit: pixel

        self._bg_color = QColor('darkgray')
        self._bg_size_rate = 0.8  # from 0 to 1

        self._indicator_color = QColor('black')
        self._pointer_width_rate = 0.05
        self._barIndicator = False

        self._num_divisions = 10
        self._show_ticks = True
        self._tick_pen = QPen()
        self._tick_color = QColor('black')
        self._tick_width = 0
        self._tick_size_rate = 0.1  # from 0 to 1
        self._painter = QPainter()

        self._painter_rotation = None
        self._painter_translation_y = None
        self._painter_translation_x = None
        self._painter_scale_x = None
        self._flip_traslation_y = None
        self._flip_scale_y = None

        self._widget_width = self.width()
        self._widget_height = self.height()

        self._orientation = Qt.Horizontal
        self._inverted_appearance = False
        self._flip_scale = False
        self._scale_height = 35
        self._origin_at_zero = False
        self._origin_position = 0

        self.set_position()

    def adjust_transformation(self):
        """
        This method sets parameters for the widget transformations (needed to for
        orientation, flipping and appearance inversion).
        """
        self.setMaximumSize(QWIDGETSIZE_MAX,
                            QWIDGETSIZE_MAX)  # Unset fixed size
        if self._orientation == Qt.Horizontal:
            self._widget_width = self.width()
            self._widget_height = self.height()
            self._painter_translation_y = 0
            self._painter_rotation = 0
            self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
            self.setFixedHeight(self._scale_height)
        elif self._orientation == Qt.Vertical:
            # Invert dimensions for paintEvent()
            self._widget_width = self.height()
            self._widget_height = self.width()
            self._painter_translation_y = self._widget_width
            self._painter_rotation = -90
            self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)
            self.setFixedWidth(self._scale_height)

        if self._inverted_appearance:
            self._painter_translation_x = self._widget_width
            self._painter_scale_x = -1
        else:
            self._painter_translation_x = 0
            self._painter_scale_x = 1

        if self._flip_scale:
            self._flip_traslation_y = self._widget_height
            self._flip_scale_y = -1
        else:
            self._flip_traslation_y = 0
            self._flip_scale_y = 1

    def set_tick_pen(self):
        """
        Define pen style for drawing scale tick marks.
        """
        self._tick_pen.setColor(self._tick_color)
        self._tick_pen.setWidth(self._tick_width)

    def draw_ticks(self):
        """
        Draw tick marks on the scale.
        """
        if not self._show_ticks:
            return
        self.set_tick_pen()
        self._painter.setPen(self._tick_pen)
        division_size = self._widget_width / self._num_divisions
        tick_y0 = self._widget_height
        tick_yf = (1 - self._tick_size_rate) * self._widget_height
        for i in range(self._num_divisions + 1):
            x = i * division_size
            self._painter.drawLine(x, tick_y0, x, tick_yf)  # x1, y1, x2, y2

    def draw_bar(self):
        """
        Draw a bar as indicator of current value.
        """
        self.set_origin()
        self.set_position()

        if self.position < 0 or self.position > self._widget_width:
            return
        self._painter.setPen(Qt.transparent)
        self._painter.setBrush(self._indicator_color)
        bar_width = self.position - self._origin_position
        bar_height = self._bg_size_rate * self._widget_height
        self._painter.drawRect(self._origin_position, 0, bar_width, bar_height)

    def draw_pointer(self):
        """
        Draw a pointer as indicator of current value.
        """
        self.set_position()
        if self.position < 0 or self.position > self._widget_width:
            return
        self._painter.setPen(Qt.transparent)
        self._painter.setBrush(self._indicator_color)
        pointer_width = self._pointer_width_rate * self._widget_width
        pointer_height = self._bg_size_rate * self._widget_height
        points = [
            QPoint(self.position, 0),
            QPoint(self.position + 0.5 * pointer_width, 0.5 * pointer_height),
            QPoint(self.position, pointer_height),
            QPoint(self.position - 0.5 * pointer_width, 0.5 * pointer_height)
        ]
        self._painter.drawPolygon(QPolygon(points))

    def draw_indicator(self):
        """
        Draw the selected indicator for current value.
        """
        if self._barIndicator:
            self.draw_bar()
        else:
            self.draw_pointer()

    def draw_background(self):
        """
        Draw the background of the scale.
        """
        self._painter.setPen(Qt.transparent)
        self._painter.setBrush(self._bg_color)
        bg_width = self._widget_width
        bg_height = self._bg_size_rate * self._widget_height
        self._painter.drawRect(0, 0, bg_width, bg_height)

    def paintEvent(self, event):
        """
        Paint events are sent to widgets that need to update themselves,
        for instance when part of a widget is exposed because a covering
        widget was moved.

        Parameters
        ----------
        event : QPaintEvent
        """
        self.adjust_transformation()
        self._painter.begin(self)
        self._painter.translate(
            0, self._painter_translation_y)  # Draw vertically if needed
        self._painter.rotate(self._painter_rotation)
        self._painter.translate(self._painter_translation_x,
                                0)  # Invert appearance if needed
        self._painter.scale(self._painter_scale_x, 1)

        self._painter.translate(
            0, self._flip_traslation_y)  # Invert scale if needed
        self._painter.scale(1, self._flip_scale_y)

        self._painter.setRenderHint(QPainter.Antialiasing)

        self.draw_background()
        self.draw_ticks()
        self.draw_indicator()

        self._painter.end()

    def calculate_position_for_value(self, value):
        """
        Calculate the position (pixel) in which the pointer should be drawn for a given value.
        """
        if value is None or value < self._lower_limit or value > self._upper_limit or \
           self._upper_limit - self._lower_limit == 0:
            proportion = -1  # Invalid
        else:
            proportion = (value - self._lower_limit) / (self._upper_limit -
                                                        self._lower_limit)

        position = int(proportion * self._widget_width)
        return position

    def set_origin(self):
        """
        Set the position (pixel) in which the origin should be drawn.
        """
        if self._origin_at_zero:
            self._origin_position = self.calculate_position_for_value(0)
        else:
            self._origin_position = 0

    def set_position(self):
        """
        Set the position (pixel) in which the pointer should be drawn.
        """
        self.position = self.calculate_position_for_value(self._value)

    def update_indicator(self):
        """
        Update the position and the drawing of indicator.
        """
        self.set_position()
        self.repaint()

    def set_value(self, value):
        """
        Set a new current value for the indicator.
        """
        self._value = value
        self.update_indicator()

    def set_upper_limit(self, new_limit):
        """
        Set the scale upper limit.

        Parameters
        ----------
        new_limit : float
            The upper limit of the scale.
        """
        self._upper_limit = new_limit

    def set_lower_limit(self, new_limit):
        """
        Set the scale lower limit.

        Parameters
        ----------
        new_limit : float
            The lower limit of the scale.
        """
        self._lower_limit = new_limit

    def get_show_ticks(self):
        return self._show_ticks

    def set_show_ticks(self, checked):
        if self._show_ticks != bool(checked):
            self._show_ticks = checked
            self.repaint()

    def get_orientation(self):
        return self._orientation

    def set_orientation(self, orientation):
        self._orientation = orientation
        self.adjust_transformation()
        self.repaint()

    def get_flip_scale(self):
        return self._flip_scale

    def set_flip_scale(self, checked):
        self._flip_scale = bool(checked)
        self.adjust_transformation()
        self.repaint()

    def get_inverted_appearance(self):
        return self._inverted_appearance

    def set_inverted_appearance(self, inverted):
        self._inverted_appearance = inverted
        self.adjust_transformation()
        self.repaint()

    def get_bar_indicator(self):
        return self._barIndicator

    def set_bar_indicator(self, checked):
        if self._barIndicator != bool(checked):
            self._barIndicator = checked
            self.repaint()

    def get_background_color(self):
        return self._bg_color

    def set_background_color(self, color):
        self._bg_color = color
        self.repaint()

    def get_indicator_color(self):
        return self._indicator_color

    def set_indicator_color(self, color):
        self._indicator_color = color
        self.repaint()

    def get_tick_color(self):
        return self._tick_color

    def set_tick_color(self, color):
        self._tick_color = color
        self.repaint()

    def get_background_size_rate(self):
        return self._bg_size_rate

    def set_background_size_rate(self, rate):
        if rate >= 0 and rate <= 1 and self._bg_size_rate != rate:
            self._bg_size_rate = rate
            self.repaint()

    def get_tick_size_rate(self):
        return self._tick_size_rate

    def set_tick_size_rate(self, rate):
        if rate >= 0 and rate <= 1 and self._tick_size_rate != rate:
            self._tick_size_rate = rate
            self.repaint()

    def get_num_divisions(self):
        return self._num_divisions

    def set_num_divisions(self, divisions):
        if isinstance(
                divisions,
                int) and divisions > 0 and self._num_divisions != divisions:
            self._num_divisions = divisions
            self.repaint()

    def get_scale_height(self):
        return self._scale_height

    def set_scale_height(self, value):
        self._scale_height = int(value)
        self.adjust_transformation()
        self.repaint()

    def get_origin_at_zero(self):
        return self._origin_at_zero

    def set_origin_at_zero(self, checked):
        if self._origin_at_zero != bool(checked):
            self._origin_at_zero = checked
            self.repaint()
예제 #27
0
    def create_high_dpi_drop_indicator_pixmap(
            self, size: QSizeF, area: DockWidgetArea,
            mode: OverlayMode) -> QPixmap:
        '''
        Create high dpi drop indicator pixmap

        Parameters
        ----------
        size : QSizeF
        area : DockWidgetArea
        mode : OverlayMode

        Returns
        -------
        value : QPixmap
        '''
        border_color = self.icon_color(IconColor.frame_color)
        background_color = self.icon_color(IconColor.window_background_color)

        window = self.public.window()

        # QT version compatibility (TODO necessary for qtpy?)
        device_pixel_ratio = (window.devicePixelRatioF()
                              if hasattr(window, 'devicePixelRatioF')
                              else window.devicePixelRatio())

        pixmap_size = QSizeF(size * device_pixel_ratio)
        pm = QPixmap(pixmap_size.toSize())
        pm.fill(QColor(0, 0, 0, 0))
        p = QPainter(pm)
        pen = p.pen()
        shadow_rect = QRectF(pm.rect())

        base_rect = QRectF()
        base_rect.setSize(shadow_rect.size() * 0.7)
        base_rect.moveCenter(shadow_rect.center())

        # Fill
        shadow_color = self.icon_color(IconColor.shadow_color)
        if shadow_color.alpha() == 255:
            shadow_color.setAlpha(64)

        p.fillRect(shadow_rect, shadow_color)

        # Drop area rect.
        p.save()
        area_rect = QRectF()
        area_line = QLineF()
        non_area_rect = QRectF()

        if area == DockWidgetArea.top:
            area_rect = QRectF(base_rect.x(), base_rect.y(), base_rect.width(),
                               base_rect.height()*.5)
            non_area_rect = QRectF(base_rect.x(), shadow_rect.height()*.5,
                                   base_rect.width(), base_rect.height()*.5)
            area_line = QLineF(area_rect.bottomLeft(), area_rect.bottomRight())
        elif area == DockWidgetArea.right:
            area_rect = QRectF(shadow_rect.width()*.5, base_rect.y(),
                               base_rect.width()*.5, base_rect.height())
            non_area_rect = QRectF(base_rect.x(), base_rect.y(),
                                   base_rect.width()*.5, base_rect.height())
            area_line = QLineF(area_rect.topLeft(), area_rect.bottomLeft())
        elif area == DockWidgetArea.bottom:
            area_rect = QRectF(base_rect.x(), shadow_rect.height()*.5,
                               base_rect.width(), base_rect.height()*.5)
            non_area_rect = QRectF(base_rect.x(), base_rect.y(),
                                   base_rect.width(), base_rect.height()*.5)
            area_line = QLineF(area_rect.topLeft(), area_rect.topRight())
        elif area == DockWidgetArea.left:
            area_rect = QRectF(base_rect.x(), base_rect.y(),
                               base_rect.width()*.5, base_rect.height())
            non_area_rect = QRectF(shadow_rect.width()*.5, base_rect.y(),
                                   base_rect.width()*.5, base_rect.height())
            area_line = QLineF(area_rect.topRight(), area_rect.bottomRight())

        baseSize = base_rect.size()
        if (OverlayMode.container == mode
                and area != DockWidgetArea.center):
            base_rect = area_rect

        p.fillRect(base_rect, background_color)
        if area_rect.isValid():
            pen = p.pen()
            pen.setColor(border_color)
            Color = self.icon_color(IconColor.overlay_color)
            if Color.alpha() == 255:
                Color.setAlpha(64)

            p.setBrush(Color)
            p.setPen(Qt.NoPen)
            p.drawRect(area_rect)
            pen = p.pen()
            pen.setWidth(1)
            pen.setColor(border_color)
            pen.setStyle(Qt.DashLine)
            p.setPen(pen)
            p.drawLine(area_line)

        p.restore()
        p.save()

        # Draw outer border
        pen = p.pen()
        pen.setColor(border_color)
        pen.setWidth(1)
        p.setBrush(Qt.NoBrush)
        p.setPen(pen)
        p.drawRect(base_rect)

        # draw window title bar
        p.setBrush(border_color)
        frame_rect = QRectF(base_rect.topLeft(),
                            QSizeF(base_rect.width(), baseSize.height()/10))
        p.drawRect(frame_rect)
        p.restore()

        # Draw arrow for outer container drop indicators
        if (OverlayMode.container == mode and
                area != DockWidgetArea.center):
            arrow_rect = QRectF()
            arrow_rect.setSize(baseSize)
            arrow_rect.setWidth(arrow_rect.width()/4.6)
            arrow_rect.setHeight(arrow_rect.height()/2)
            arrow_rect.moveCenter(QPointF(0, 0))

            arrow = QPolygonF()
            arrow.append(arrow_rect.topLeft())
            arrow.append(QPointF(arrow_rect.right(), arrow_rect.center().y()))
            arrow.append(arrow_rect.bottomLeft())

            p.setPen(Qt.NoPen)
            p.setBrush(self.icon_color(IconColor.arrow_color))
            p.setRenderHint(QPainter.Antialiasing, True)
            p.translate(non_area_rect.center().x(), non_area_rect.center().y())
            if area == DockWidgetArea.top:
                p.rotate(-90)
            elif area == DockWidgetArea.right:
                ...
            elif area == DockWidgetArea.bottom:
                p.rotate(90)
            elif area == DockWidgetArea.left:
                p.rotate(180)

            p.drawPolygon(arrow)

        pm.setDevicePixelRatio(device_pixel_ratio)
        return pm