def _updateButtons(self): """ Update button icons. """ sz = QSize(32, 32) if self.orientation() == Qt.Vertical: sz.setHeight(sz.height() / 2) pix = QPixmap(sz) pix.fill(Qt.transparent) pnt = QPainter(pix) pnt.setPen(Qt.black) path = QPainterPath() arrowwidth = pix.width() - 2 * 2 arrowheight = min(arrowwidth / 2, pix.height() - 2 * 2) path.moveTo((pix.width() - arrowwidth) / 2, (pix.height() - arrowheight) / 2) path.lineTo((pix.width() + arrowwidth) / 2, (pix.height() - arrowheight) / 2) path.lineTo(pix.width() / 2, (pix.height() + arrowheight) / 2) path.lineTo((pix.width() - arrowwidth) / 2, (pix.height() - arrowheight) / 2) pnt.fillPath(path, Qt.black) pnt.end() self._inc.setIcon(QIcon(pix)) self._dec.setIcon(QIcon(QPixmap.fromImage(pix.toImage().mirrored())))
def __init__(self, gui): QWidget.__init__(self, gui) self.setObjectName('jobs_pointer') self.setVisible(False) self.resize(100, 80) self.animation = QPropertyAnimation(self, "geometry", self) self.animation.setDuration(750) self.animation.setLoopCount(2) self.animation.setEasingCurve(QEasingCurve.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.Active, QPalette.WindowText) self.color = QColor(c) self.color.setAlpha(100) self.brush = QBrush(self.color, Qt.SolidPattern)
def _create_crop_elements(self): cw, ch, _ = self._crop_size path = QPainterPath() path.moveTo(0, ch) path.lineTo(cw / 2, 0) path.lineTo(cw, ch) path.lineTo(0, ch) self._crop_path = path self._crop_brush = QBrush(self.palette().light().color())
def paint_background(self, painter): br = 12 # border_radius bw = 1 # border_width c = QColor('#fdfd96') p = QPainterPath() p.addRoundedRect(QRectF(self.rect()), br, br) painter.fillPath(p, c) p.addRoundedRect(QRectF(self.rect()).adjusted(bw, bw, -bw, -bw), br, br) painter.fillPath(p, QColor('black'))
def paint(self, painter, option, index): QStyledItemDelegate.paint(self, painter, option, index) hovering = index.data(HOVER_ROLE) is True painter.save() rect = option.rect is_current = index.data(Qt.FontRole) is not None if not hovering and is_current: qpp = QPainterPath() qpp.addRoundedRect(QRectF(rect), 6, 6) painter.fillPath(qpp, self.current_background) icon_rect = QRect(rect.left() + self.MARGIN, rect.top() + self.MARGIN, ICON_SIZE, ICON_SIZE) left = icon_rect.right() + 2 * self.MARGIN text_rect = QRect(left, icon_rect.top(), rect.width() - left + rect.left(), icon_rect.height()) mark = index.data(MARK_ROLE) if hovering or mark: text_rect.adjust(0, 0, -text_rect.height(), 0) text = index.data(DISPLAY_ROLE) or '' font = index.data(Qt.FontRole) if font: painter.setFont(font) text_flags = Qt.AlignVCenter | Qt.AlignLeft | Qt.TextSingleLine text = elided_text(text, font, text_rect.width(), 'right') if option.state & QStyle.State_Selected: painter.setPen(QPen(self.highlighted_text)) painter.drawText(text_rect, text_flags, text) if mark: hrect = QRect(text_rect.right(), text_rect.top(), text_rect.height(), text_rect.height()) painter.fillRect(hrect, QColor('#ffffaa')) painter.drawText(hrect, Qt.AlignCenter, mark) elif hovering: hrect = QRect(text_rect.right(), text_rect.top(), text_rect.height(), text_rect.height()) close_hover = index.data(CLOSE_HOVER_ROLE) is True if close_hover: pen = painter.pen() pen.setColor(QColor('red')) painter.setPen(pen) painter.drawText(hrect, Qt.AlignCenter, '✖ ') if index.data(LOADING_ROLE): if not self.errored_out: angle = index.data(ANGLE_ROLE) try: draw_snake_spinner(painter, icon_rect, angle, self.light, self.dark) except Exception: import traceback traceback.print_exc() self.errored_out = True else: icurl = index.data(URL_ROLE) if icurl == WELCOME_URL: icon = welcome_icon() elif icurl == DOWNLOADS_URL: icon = downloads_icon() else: icon = index.data(DECORATION_ROLE) icon.paint(painter, icon_rect) painter.restore()
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
def paint_background(self, painter): br = 12 # border_radius bw = 1 # border_width pal = self.palette() c = pal.color(pal.Window) c.setAlphaF(0.9) p = QPainterPath() p.addRoundedRect(QRectF(self.rect()), br, br) painter.fillPath(p, c) p.addRoundedRect(QRectF(self.rect()).adjusted(bw, bw, -bw, -bw), br, br) painter.fillPath(p, pal.color(pal.WindowText))
def draw_fold(x, m=1, corner=left_corner): ans = p = QPainterPath(QPointF(x, rtop)) draw_curved_line(p, rwidth*m, 0, 0.1, 0.1*m, 0.5, -0.2*m) fold_upper = p.currentPosition() p.lineTo(p.currentPosition() + QPointF(-deltax*m, height)) fold_corner = p.currentPosition() draw_curved_line(p, -rwidth*m, 0, 0.2, -0.1*m, 0.8, -0.1*m) draw_curved_line(p, deltax*m, -height, 0.2, 0.1*m, 0.8, 0.1*m) p = inner_fold = QPainterPath(corner) dp = fold_corner - p.currentPosition() draw_curved_line(p, dp.x(), dp.y(), 0.5, 0.3*m, 1, 0*m) p.lineTo(fold_upper), p.closeSubpath() return ans, inner_fold
def full(p, xmax, ymax): p.drawRect(0, 0, xmax, ymax) p.drawPolyline(QPoint(0, 0), QPoint(xmax, 0), QPoint(xmax, ymax), QPoint(0, ymax), QPoint(0, 0)) pp = QPainterPath() pp.addRect(0, 0, xmax, ymax) p.drawPath(pp) p.save() for i in range(3): col = [0, 0, 0, 200] col[i] = 255 p.setOpacity(0.3) p.fillRect(0, 0, xmax/10, xmax/10, QBrush(QColor(*col))) p.setOpacity(1) p.drawRect(0, 0, xmax/10, xmax/10) p.translate(xmax/10, xmax/10) p.scale(1, 1.5) p.restore() # p.scale(2, 2) # p.rotate(45) p.drawPixmap(0, 0, xmax/4, xmax/4, QPixmap(I('library.png'))) p.drawRect(0, 0, xmax/4, xmax/4) f = p.font() f.setPointSize(20) # f.setLetterSpacing(f.PercentageSpacing, 200) f.setUnderline(True) # f.setOverline(True) # f.setStrikeOut(True) f.setFamily('Calibri') p.setFont(f) # p.setPen(QColor(0, 0, 255)) # p.scale(2, 2) # p.rotate(45) p.drawText(QPoint(xmax/3.9, 30), 'Some—text not By’s ū --- Д AV ff ff') b = QBrush(Qt.HorPattern) b.setColor(QColor(Qt.blue)) pix = QPixmap(I('lt.png')) w = xmax/4 p.fillRect(0, ymax/3, w, w, b) p.fillRect(xmax/3, ymax/3, w, w, QBrush(pix)) x, y = 2*xmax/3, ymax/3 p.drawTiledPixmap(QRectF(x, y, w, w), pix, QPointF(10, 10)) x, y = 1, ymax/1.9 g = QLinearGradient(QPointF(x, y), QPointF(x+w, y+w)) g.setColorAt(0, QColor('#00f')) g.setColorAt(1, QColor('#fff')) p.fillRect(x, y, w, w, QBrush(g))
def __call__(self, painter, rect, color_theme, title_block, subtitle_block, footer_block): painter.fillRect(rect, self.color1) r = QRect(0, int(title_block.position.y), rect.width(), title_block.height + subtitle_block.height + subtitle_block.line_spacing // 2 + title_block.leading) painter.save() p = QPainterPath() p.addRoundedRect(QRectF(r), 10, 10 * r.width()/r.height(), Qt.RelativeSize) painter.setClipPath(p) painter.setRenderHint(QPainter.Antialiasing) painter.fillRect(r, self.color2) painter.restore() r = QRect(0, 0, int(title_block.position.x), rect.height()) painter.fillRect(r, self.color2) return self.ccolor2, self.ccolor2, self.ccolor1
def createPixmapForSite(self, icon, title, url): ''' @param: icon QIcon @param: title QString @param: url QString @return: QPixmap ''' fontMetrics = QApplication.fontMetrics() padding = 4 text = len(title) > len(url) and title or url maxWidth = fontMetrics.width(text) + 3 * padding + 16 width = min(maxWidth, 150) height = fontMetrics.height() * 2 + fontMetrics.leading() + 2 * padding pixelRatio = gVar.app.devicePixelRatio() pixmap = QPixmap(width * pixelRatio, height * pixelRatio) pixmap.setDevicePixelRatio(pixelRatio) painter = QPainter(pixmap) painter.setRenderHint(QPainter.Antialiasing) # Draw background pen = QPen(Qt.black) pen.setWidth(1) painter.setPen(pen) path = QPainterPath() path.addRect(QRectF(0, 0, width, height)) painter.fillPath(path, Qt.white) painter.drawPath(path) # Draw icon iconRect = QRect(padding, 0, 16, height) icon.paint(painter, iconRect) # Draw title titleRect = QRectF(iconRect.right() + padding, padding, width - padding - iconRect.right(), fontMetrics.height()) painter.drawText(titleRect, fontMetrics.elidedText(title, Qt.ElideRight, titleRect.width())) # Draw url urlRect = QRectF(titleRect.x(), titleRect.bottom() + fontMetrics.leading(), titleRect.width(), titleRect.height()) painter.setPen(QApplication.palette().color(QPalette.Link)) painter.drawText(urlRect, fontMetrics.elidedText(url, Qt.ElideRight, urlRect.width())) return pixmap
def __call__(self, painter, rect, color_theme, title_block, subtitle_block, footer_block): painter.fillRect(rect, self.color1) top = title_block.position.y + 2 extra_spacing = subtitle_block.line_spacing // 2 if subtitle_block.line_spacing else title_block.line_spacing // 3 height = title_block.height + subtitle_block.height + extra_spacing + title_block.leading right = rect.right() - self.hmargin width = right - self.hmargin # Draw main banner p = main = QPainterPath(QPointF(self.hmargin, top)) draw_curved_line(p, rect.width() - 2 * self.hmargin, 0, 0.1, -0.1, 0.9, -0.1) deltax = self.GRADE * height p.lineTo(right + deltax, top + height) right_corner = p.currentPosition() draw_curved_line(p, - width - 2 * deltax, 0, 0.1, 0.05, 0.9, 0.05) left_corner = p.currentPosition() p.closeSubpath() # Draw fold rectangles rwidth = self.fold_width yfrac = 0.1 width23 = int(0.67 * rwidth) rtop = top + height * yfrac def draw_fold(x, m=1, corner=left_corner): ans = p = QPainterPath(QPointF(x, rtop)) draw_curved_line(p, rwidth*m, 0, 0.1, 0.1*m, 0.5, -0.2*m) fold_upper = p.currentPosition() p.lineTo(p.currentPosition() + QPointF(-deltax*m, height)) fold_corner = p.currentPosition() draw_curved_line(p, -rwidth*m, 0, 0.2, -0.1*m, 0.8, -0.1*m) draw_curved_line(p, deltax*m, -height, 0.2, 0.1*m, 0.8, 0.1*m) p = inner_fold = QPainterPath(corner) dp = fold_corner - p.currentPosition() draw_curved_line(p, dp.x(), dp.y(), 0.5, 0.3*m, 1, 0*m) p.lineTo(fold_upper), p.closeSubpath() return ans, inner_fold left_fold, left_inner = draw_fold(self.hmargin - width23) right_fold, right_inner = draw_fold(right + width23, m=-1, corner=right_corner) painter.save() painter.setRenderHint(QPainter.Antialiasing) pen = QPen(self.ccolor2) pen.setWidth(3) pen.setJoinStyle(Qt.RoundJoin) painter.setPen(pen) for r in (left_fold, right_fold): painter.fillPath(r, QBrush(self.color2)) painter.drawPath(r) for r in (left_inner, right_inner): painter.fillPath(r, QBrush(self.color2.darker())) painter.drawPath(r) painter.fillPath(main, QBrush(self.color2)) painter.drawPath(main) painter.restore() return self.ccolor2, self.ccolor2, self.ccolor1
def _draw_column_data(self, painter, color, xcol, ycol, xmin, xmax, ymin, ymax): painter.setPen( QPen(QColor(color), 2, Qt.SolidLine, Qt.RoundCap)) path = QPainterPath() row = self.data.rows[0] x, y = self._xy_from_data(row[xcol], row[ycol], xmin, xmax, ymin, ymax) path.moveTo(x, y) for row in self.data.rows[1:]: x, y = self._xy_from_data(row[xcol], row[ycol], xmin, xmax, ymin, ymax) path.lineTo(x, y) painter.drawPath(path)
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(self.animation.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 __call__(self, painter, rect, color_theme, title_block, subtitle_block, footer_block): if not self.PATH_CACHE: from calibre.utils.speedups import svg_path_to_painter_path try: self.__class__.PATH_CACHE['corner'] = svg_path_to_painter_path( self.CORNER_VECTOR) except Exception: import traceback traceback.print_exc() p = painter painter.setRenderHint(QPainter.RenderHint.Antialiasing) g = QRadialGradient(QPointF(rect.center()), rect.width()) g.setColorAt(0, self.color1), g.setColorAt(1, self.color2) painter.fillRect(rect, QBrush(g)) painter.save() painter.setWindow(0, 0, *self.VIEWPORT) try: path = self.PATH_CACHE['corner'] except KeyError: path = QPainterPath() pen = p.pen() pen.setColor(self.ccolor1) p.setPen(pen) def corner(): b = QBrush(self.ccolor1) p.fillPath(path, b) p.rotate(90), p.translate(100, -100), p.scale(1, -1), p.translate( -103, -97) p.fillPath(path, b) p.setWorldTransform(QTransform()) # Top-left corner corner() # Top right corner p.scale(-1, 1), p.translate(-400, 0), corner() # Bottom left corner p.scale(1, -1), p.translate(0, -500), corner() # Bottom right corner p.scale(-1, -1), p.translate(-400, -500), corner() for y in (28.4, 471.7): p.drawLine(QPointF(160, y), QPointF(240, y)) for x in (31.3, 368.7): p.drawLine(QPointF(x, 155), QPointF(x, 345)) pen.setWidthF(1.8) p.setPen(pen) for y in (23.8, 476.7): p.drawLine(QPointF(160, y), QPointF(240, y)) for x in (26.3, 373.7): p.drawLine(QPointF(x, 155), QPointF(x, 345)) painter.restore() return self.ccolor2, self.ccolor2, self.ccolor1
def drawContents(self, painter): self.drawn_once = True painter.save() painter.setPen(Qt.black) painter.setRenderHint(painter.TextAntialiasing, True) painter.setRenderHint(painter.Antialiasing, True) f = painter.font() f.setPixelSize(18) painter.setFont(f) t = QTransform() t.translate(330, 450) painter.setTransform(t) painter.rotate(-98) if iswindows: # On windows Qt cannot anti-alias rotated text p = QPainterPath() p.addText(0, 0, f, self.message()) painter.fillPath(p, QBrush(Qt.black)) else: painter.drawText(0, 0, self.message()) painter.restore()
def paintEvent(self, event): painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) painter.drawPixmap(0, 0, self._pixmap) painter.fillRect(self.rect(), self.palette().midlight().color()) round_path = QPainterPath() round_path.addRoundedRect(0, 0, self.width(), self.height(), 5, 5) sq_path = QPainterPath() sq_path.addRect(0, 0, 10, self.height()) draw_path = sq_path - round_path painter.setPen(Qt.NoPen) painter.setBrush(self.palette().dark().color()) painter.drawPath(draw_path)
def drawContents(self, painter): self.drawn_once = True painter.save() painter.setPen(Qt.black) painter.setRenderHint(painter.TextAntialiasing, True) painter.setRenderHint(painter.Antialiasing, True) f = painter.font() f.setPixelSize(18) painter.setFont(f) t = QTransform() t.translate(330, 450) painter.setTransform(t) painter.rotate(-98) left_margin = 25 if iswindows: # On windows Qt cannot anti-alias rotated text p = QPainterPath() p.addText(left_margin, 0, f, self.message()) painter.fillPath(p, QBrush(Qt.black)) else: painter.drawText(left_margin, 0, self.message()) painter.restore()
def paint_background(self, painter): br = 12 # border_radius bw = 1 # border_width c = QColor('#fdfd96') p = QPainterPath() p.addRoundedRect(QRectF(self.rect()), br, br) painter.fillPath(p, c) p.addRoundedRect( QRectF(self.rect()).adjusted(bw, bw, -bw, -bw), br, br) painter.fillPath(p, QColor('black'))
def paint_background(self, painter): br = 12 # border_radius bw = 1 # border_width pal = self.palette() c = pal.color(QPalette.ColorRole.Window) c.setAlphaF(0.9) p = QPainterPath() p.addRoundedRect(QRectF(self.rect()), br, br) painter.fillPath(p, c) p.addRoundedRect(QRectF(self.rect()).adjusted(bw, bw, -bw, -bw), br, br) painter.fillPath(p, pal.color(QPalette.ColorRole.WindowText))
def shape(self): '''Defines the selection shape of the item.''' stroker = QPainterPathStroker() # Tolerance on click to update if needed stroker.setWidth(12) path = QPainterPath() path.moveTo(self.line().p1()) path.lineTo(self.line().p2()) return stroker.createStroke(path)
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
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(self.animation.Backward) num_keys = 100 for i in xrange(1, num_keys): i /= num_keys self.animation.setKeyValueAt(i, self.rect_at(i)) self.animation.start()
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, "geometry", self) self.animation.setDuration(750) self.animation.setLoopCount(2) self.animation.setEasingCurve(QEasingCurve.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.Active, QPalette.WindowText) self.color = QColor(c) self.color.setAlpha(100) self.brush = QBrush(self.color, Qt.SolidPattern) # from PyQt5.Qt 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(self.animation.Backward) num_keys = 100 for i in xrange(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(p.Antialiasing) p.setBrush(self.brush) p.setPen(Qt.NoPen) p.drawPath(self.arrow_path) p.end()
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, "geometry", self) self.animation.setDuration(750) self.animation.setLoopCount(2) self.animation.setEasingCurve(QEasingCurve.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.Active, QPalette.WindowText) self.color = QColor(c) self.color.setAlpha(100) self.brush = QBrush(self.color, Qt.SolidPattern) # from PyQt5.Qt 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(self.animation.Backward) num_keys = 100 for i in xrange(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(p.Antialiasing) p.setBrush(self.brush) p.setPen(Qt.NoPen) p.drawPath(self.arrow_path) p.end()
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 PyQt5.Qt 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
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.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.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.TextSingleLine, text).bottom() + 3 ry = painter.boundingRect(3, ry_top, right.width(), ry_bot - ry_top - 5, Qt.TextSingleLine, text).bottom() + 3 line = create_line(ly, ry) painter.setPen(QPen(left.palette().text(), 2)) painter.setRenderHints(QPainter.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)
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 PyQt5.Qt import QPainterPath cmd = last_cmd = b'' path = QPainterPath() moveto_abs, moveto_rel = b'Mm' closepath1, closepath2 = b'Zz' lineto_abs, lineto_rel = b'Ll' hline_abs, hline_rel = b'Hh' vline_abs, vline_rel = b'Vv' curveto_abs, curveto_rel = b'Cc' smoothcurveto_abs, smoothcurveto_rel = b'Ss' quadcurveto_abs, quadcurveto_rel = b'Qq' smoothquadcurveto_abs, smoothquadcurveto_rel = b'Tt' # Store the last parsed values # x/y = end position # x1/y1 and x2/y2 = bezier control points x = y = x1 = y1 = x2 = y2 = 0 data = d.replace(b',', b' ').replace(b'\n', b' ') if isinstance(data, type('')): data = data.encode('ascii') end = len(data) data = ReadOnlyFileBuffer(data) def parse_float(): chars = [] while data.tell() < end: c = data.read(1) if c == b' ' and not chars: continue if c == b'-' or b'0' <= c[0] <= b'9' or c == b'.': chars.append(c[0]) 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 xrange(num): val = parse_float() yield val + (x_offset if i % 2 == 0 else y_offset) repeated_command = None while data.tell() < end: last_cmd = cmd cmd = data.read(1) if repeated_command is None else repeated_command repeated_command = None if cmd == b' ': continue elif 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[0] in b'-.' or b'0' <= cmd[0] <= b'9': # A new number begins # In this case, multiple parameters tuples are specified for the last command # We rewind to reparse data correctly data.seek(-1, os.SEEK_CUR) # 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
def _contour(self): """Returns contour path.""" ppath = QPainterPath() rect = self.contentsRect() margin = 5 ppath.addRoundedRect(rect.left() - margin, rect.top() - margin, rect.width() + 2 * margin, rect.height() + 2 * margin, 15, 15) arrowpath = QPainterPath() arrowpath.moveTo(rect.center().x(), self.height()) arrowpath.lineTo(rect.center().x() - 10, rect.bottom()) arrowpath.lineTo(rect.center().x() + 10, rect.bottom()) arrowpath.lineTo(rect.center().x(), self.height()) ppath = ppath.united(arrowpath) return ppath
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 PyQt5.Qt import QPainterPath cmd = last_cmd = b'' path = QPainterPath() moveto_abs, moveto_rel = b'Mm' closepath1, closepath2 = b'Zz' lineto_abs, lineto_rel = b'Ll' hline_abs, hline_rel = b'Hh' vline_abs, vline_rel = b'Vv' curveto_abs, curveto_rel = b'Cc' smoothcurveto_abs, smoothcurveto_rel = b'Ss' quadcurveto_abs, quadcurveto_rel = b'Qq' smoothquadcurveto_abs, smoothquadcurveto_rel = b'Tt' # Store the last parsed values # x/y = end position # x1/y1 and x2/y2 = bezier control points x = y = x1 = y1 = x2 = y2 = 0 data = d.replace(b',', b' ').replace(b'\n', b' ') if isinstance(data, type('')): data = data.encode('ascii') end = len(data) data = ReadOnlyFileBuffer(data) def parse_float(): chars = [] while data.tell() < end: c = data.read(1) if c == b' ' and not chars: continue if c == b'-' or b'0' <= c[0] <= b'9' or c == b'.': chars.append(c[0]) 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 data.tell() < end: last_cmd = cmd cmd = data.read(1) if repeated_command is None else repeated_command repeated_command = None if cmd == b' ': continue elif 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[0] in b'-.' or b'0' <= cmd[0] <= b'9': # A new number begins # In this case, multiple parameters tuples are specified for the last command # We rewind to reparse data correctly data.seek(-1, os.SEEK_CUR) # 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