Esempio n. 1
0
def wavy_path(width, height, y_origin):
    half_height = height / 2
    path = QPainterPath()
    pi2 = math.pi * 2
    num = 100
    num_waves = 4
    wav_limit = num // num_waves
    sin = math.sin
    path.reserve(num)
    for i in range(num):
        x = width * i / num
        rads = pi2 * (i % wav_limit) / wav_limit
        factor = sin(rads)
        y = y_origin + factor * half_height
        path.lineTo(x, y) if i else path.moveTo(x, y)
    return path
Esempio n. 2
0
class Pointer(QWidget):
    def __init__(self, gui):
        QWidget.__init__(self, gui)
        self.setObjectName('jobs_pointer')
        self.setVisible(False)
        self.resize(100, 80)
        self.animation = QPropertyAnimation(self, b"geometry", self)
        self.animation.setDuration(750)
        self.animation.setLoopCount(2)
        self.animation.setEasingCurve(QEasingCurve.Type.Linear)
        self.animation.finished.connect(self.hide)

        taily, heady = 0, 55
        self.arrow_path = QPainterPath(QPointF(40, taily))
        self.arrow_path.lineTo(40, heady)
        self.arrow_path.lineTo(20, heady)
        self.arrow_path.lineTo(50, self.height())
        self.arrow_path.lineTo(80, heady)
        self.arrow_path.lineTo(60, heady)
        self.arrow_path.lineTo(60, taily)
        self.arrow_path.closeSubpath()

        c = self.palette().color(QPalette.ColorGroup.Active,
                                 QPalette.ColorRole.WindowText)
        self.color = QColor(c)
        self.color.setAlpha(100)
        self.brush = QBrush(self.color, Qt.BrushStyle.SolidPattern)

        # from qt.core import QTimer
        # QTimer.singleShot(1000, self.start)

    @property
    def gui(self):
        return self.parent()

    def point_at(self, frac):
        return (self.path.pointAtPercent(frac).toPoint() -
                QPoint(self.rect().center().x(), self.height()))

    def rect_at(self, frac):
        return QRect(self.point_at(frac), self.size())

    def abspos(self, widget):
        pos = widget.pos()
        parent = widget.parent()
        while parent is not self.gui:
            pos += parent.pos()
            parent = parent.parent()
        return pos

    def start(self):
        if config['disable_animations']:
            return
        self.setVisible(True)
        self.raise_()
        end = self.abspos(self.gui.jobs_button)
        end = QPointF(end.x() + self.gui.jobs_button.width() / 3.0,
                      end.y() + 20)
        start = QPointF(end.x(), end.y() - 0.5 * self.height())
        self.path = QPainterPath(QPointF(start))
        self.path.lineTo(end)
        self.path.closeSubpath()
        self.animation.setStartValue(self.rect_at(0.0))
        self.animation.setEndValue(self.rect_at(1.0))
        self.animation.setDirection(QAbstractAnimation.Direction.Backward)
        num_keys = 100
        for i in range(1, num_keys):
            i /= num_keys
            self.animation.setKeyValueAt(i, self.rect_at(i))
        self.animation.start()

    def paintEvent(self, ev):
        p = QPainter(self)
        p.setRenderHints(QPainter.RenderHint.Antialiasing)
        p.setBrush(self.brush)
        p.setPen(Qt.PenStyle.NoPen)
        p.drawPath(self.arrow_path)
        p.end()
Esempio n. 3
0
    def paintEvent(self, event):
        QSplitterHandle.paintEvent(self, event)
        left, right = self.parent().left, self.parent().right
        painter = QPainter(self)
        painter.setClipRect(event.rect())
        w = self.width()
        h = self.height()
        painter.setRenderHints(QPainter.RenderHint.Antialiasing, True)

        C = 16  # Curve factor.

        def create_line(ly, ry, right_to_left=False):
            ' Create path that represents upper or lower line of change marker '
            line = QPainterPath()
            if not right_to_left:
                line.moveTo(0, ly)
                line.cubicTo(C, ly, w - C, ry, w, ry)
            else:
                line.moveTo(w, ry)
                line.cubicTo(w - C, ry, C, ly, 0, ly)
            return line

        ldoc, rdoc = left.document(), right.document()
        lorigin, rorigin = left.contentOffset(), right.contentOffset()
        lfv, rfv = left.firstVisibleBlock().blockNumber(), right.firstVisibleBlock().blockNumber()
        lines = []

        for (ltop, lbot, kind), (rtop, rbot, kind) in zip(left.changes, right.changes):
            if lbot < lfv and rbot < rfv:
                continue
            ly_top = left.blockBoundingGeometry(ldoc.findBlockByNumber(ltop)).translated(lorigin).y()
            ly_bot = left.blockBoundingGeometry(ldoc.findBlockByNumber(lbot)).translated(lorigin).y()
            ry_top = right.blockBoundingGeometry(rdoc.findBlockByNumber(rtop)).translated(rorigin).y()
            ry_bot = right.blockBoundingGeometry(rdoc.findBlockByNumber(rbot)).translated(rorigin).y()
            if max(ly_top, ly_bot, ry_top, ry_bot) < 0:
                continue
            if min(ly_top, ly_bot, ry_top, ry_bot) > h:
                break

            upper_line = create_line(ly_top, ry_top)
            lower_line = create_line(ly_bot, ry_bot, True)

            region = QPainterPath()
            region.moveTo(0, ly_top)
            region.connectPath(upper_line)
            region.lineTo(w, ry_bot)
            region.connectPath(lower_line)
            region.closeSubpath()

            painter.fillPath(region, left.diff_backgrounds[kind])
            for path, aa in zip((upper_line, lower_line), (ly_top != ry_top, ly_bot != ry_bot)):
                lines.append((kind, path, aa))

        for kind, path, aa in sorted(lines, key=lambda x:{'replace':0}.get(x[0], 1)):
            painter.setPen(left.diff_foregrounds[kind])
            painter.setRenderHints(QPainter.RenderHint.Antialiasing, aa)
            painter.drawPath(path)

        painter.setFont(left.heading_font)
        for (lnum, text), (rnum, text) in zip(left.headers, right.headers):
            ltop, lbot, rtop, rbot = lnum, lnum + 3, rnum, rnum + 3
            if lbot < lfv and rbot < rfv:
                continue
            ly_top = left.blockBoundingGeometry(ldoc.findBlockByNumber(ltop)).translated(lorigin).y()
            ly_bot = left.blockBoundingGeometry(ldoc.findBlockByNumber(lbot)).translated(lorigin).y()
            ry_top = right.blockBoundingGeometry(rdoc.findBlockByNumber(rtop)).translated(rorigin).y()
            ry_bot = right.blockBoundingGeometry(rdoc.findBlockByNumber(rbot)).translated(rorigin).y()
            if max(ly_top, ly_bot, ry_top, ry_bot) < 0:
                continue
            if min(ly_top, ly_bot, ry_top, ry_bot) > h:
                break
            ly = painter.boundingRect(3, ly_top, left.width(), ly_bot - ly_top - 5, Qt.TextFlag.TextSingleLine, text).bottom() + 3
            ry = painter.boundingRect(3, ry_top, right.width(), ry_bot - ry_top - 5, Qt.TextFlag.TextSingleLine, text).bottom() + 3
            line = create_line(ly, ry)
            painter.setPen(QPen(left.palette().text(), 2))
            painter.setRenderHints(QPainter.RenderHint.Antialiasing, ly != ry)
            painter.drawPath(line)

        painter.end()
        # Paint the splitter without the change lines if the mouse is over the
        # splitter
        if getattr(self, 'hover', False):
            QSplitterHandle.paintEvent(self, event)
Esempio n. 4
0
def svg_path_to_painter_path(d):
    '''
    Convert a tiny SVG 1.2 path into a QPainterPath.

    :param d: The value of the d attribute of an SVG <path> tag
    '''
    from qt.core import QPainterPath
    cmd = last_cmd = b''
    path = QPainterPath()
    moveto_abs, moveto_rel = b'M', b'm'
    closepath1, closepath2 = b'Z', b'z'
    lineto_abs, lineto_rel = b'L', b'l'
    hline_abs, hline_rel = b'H', b'h'
    vline_abs, vline_rel = b'V', b'v'
    curveto_abs, curveto_rel = b'C', b'c'
    smoothcurveto_abs, smoothcurveto_rel = b'S', b's'
    quadcurveto_abs, quadcurveto_rel = b'Q', b'q'
    smoothquadcurveto_abs, smoothquadcurveto_rel = b'T', b't'

    # Store the last parsed values
    # x/y = end position
    # x1/y1 and x2/y2 = bezier control points
    x = y = x1 = y1 = x2 = y2 = 0

    if isinstance(d, unicode_type):
        d = d.encode('ascii')
    d = d.replace(b',', b' ').replace(b'\n', b' ')
    end = len(d)
    pos = [0]

    def read_byte():
        p = pos[0]
        pos[0] += 1
        return d[p:p+1]

    def parse_float():
        chars = []
        while pos[0] < end:
            c = read_byte()
            if c == b' ' and not chars:
                continue
            if c in b'-.0123456789':
                chars.append(c)
            else:
                break
        if not chars:
            raise ValueError('Premature end of input while expecting a number')
        return float(b''.join(chars))

    def parse_floats(num, x_offset=0, y_offset=0):
        for i in range(num):
            val = parse_float()
            yield val + (x_offset if i % 2 == 0 else y_offset)

    repeated_command = None

    while pos[0] < end:
        last_cmd = cmd
        cmd = read_byte() if repeated_command is None else repeated_command
        repeated_command = None

        if cmd == b' ':
            continue
        if cmd == moveto_abs:
            x, y = parse_float(), parse_float()
            path.moveTo(x, y)
        elif cmd == moveto_rel:
            x += parse_float()
            y += parse_float()
            path.moveTo(x, y)
        elif cmd == closepath1 or cmd == closepath2:
            path.closeSubpath()
        elif cmd == lineto_abs:
            x, y = parse_floats(2)
            path.lineTo(x, y)
        elif cmd == lineto_rel:
            x += parse_float()
            y += parse_float()
            path.lineTo(x, y)
        elif cmd == hline_abs:
            x = parse_float()
            path.lineTo(x, y)
        elif cmd == hline_rel:
            x += parse_float()
            path.lineTo(x, y)
        elif cmd == vline_abs:
            y = parse_float()
            path.lineTo(x, y)
        elif cmd == vline_rel:
            y += parse_float()
            path.lineTo(x, y)
        elif cmd == curveto_abs:
            x1, y1, x2, y2, x, y = parse_floats(6)
            path.cubicTo(x1, y1, x2, y2, x, y)
        elif cmd == curveto_rel:
            x1, y1, x2, y2, x, y = parse_floats(6, x, y)
            path.cubicTo(x1, y1, x2, y2, x, y)
        elif cmd == smoothcurveto_abs:
            if last_cmd == curveto_abs or last_cmd == curveto_rel or last_cmd == smoothcurveto_abs or last_cmd == smoothcurveto_rel:
                x1 = 2 * x - x2
                y1 = 2 * y - y2
            else:
                x1, y1 = x, y
            x2, y2, x, y = parse_floats(4)
            path.cubicTo(x1, y1, x2, y2, x, y)
        elif cmd == smoothcurveto_rel:
            if last_cmd == curveto_abs or last_cmd == curveto_rel or last_cmd == smoothcurveto_abs or last_cmd == smoothcurveto_rel:
                x1 = 2 * x - x2
                y1 = 2 * y - y2
            else:
                x1, y1 = x, y
            x2, y2, x, y = parse_floats(4, x, y)
            path.cubicTo(x1, y1, x2, y2, x, y)
        elif cmd == quadcurveto_abs:
            x1, y1, x, y = parse_floats(4)
            path.quadTo(x1, y1, x, y)
        elif cmd == quadcurveto_rel:
            x1, y1, x, y = parse_floats(4, x, y)
            path.quadTo(x1, y1, x, y)
        elif cmd == smoothquadcurveto_abs:
            if last_cmd in (quadcurveto_abs, quadcurveto_rel, smoothquadcurveto_abs, smoothquadcurveto_rel):
                x1 = 2 * x - x1
                y1 = 2 * y - y1
            else:
                x1, y1 = x, y
            x, y = parse_floats(2)
            path.quadTo(x1, y1, x, y)
        elif cmd == smoothquadcurveto_rel:
            if last_cmd in (quadcurveto_abs, quadcurveto_rel, smoothquadcurveto_abs, smoothquadcurveto_rel):
                x1 = 2 * x - x1
                y1 = 2 * y - y1
            else:
                x1, y1 = x, y
            x, y = parse_floats(2, x, y)
            path.quadTo(x1, y1, x, y)
        elif cmd in b'-.0123456789':
            # A new number begins
            # In this case, multiple parameters tuples are specified for the last command
            # We rewind to reparse data correctly
            pos[0] -= 1

            # Handle extra parameters
            if last_cmd == moveto_abs:
                repeated_command = cmd = lineto_abs
            elif last_cmd == moveto_rel:
                repeated_command = cmd = lineto_rel
            elif last_cmd in (closepath1, closepath2):
                raise ValueError('Extra parameters after close path command')
            elif last_cmd in (
                lineto_abs, lineto_rel, hline_abs, hline_rel, vline_abs,
                vline_rel, curveto_abs, curveto_rel,smoothcurveto_abs,
                smoothcurveto_rel, quadcurveto_abs, quadcurveto_rel,
                smoothquadcurveto_abs, smoothquadcurveto_rel
            ):
                repeated_command = cmd = last_cmd
        else:
            raise ValueError('Unknown path command: %s' % cmd)
    return path