def paint(self, painter, option, index): QStyledItemDelegate.paint(self, painter, option, index) pal = option.palette color = pal.color(pal.HighlightedText if option.state & QStyle.State_Selected else pal.Text).name() text = '<div style="color:%s">%s</div>' % (color, index.data(RENDER_ROLE)) st = QStaticText(text) st.setTextWidth(option.rect.width()) painter.drawStaticText(option.rect.left() + self.MARGIN // 2, option.rect.top() + self.MARGIN // 2, st)
def __init__(self, parent=None): QWidget.__init__(self, parent=parent) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.results = () self.current_result = -1 self.max_result = -1 self.mouse_hover_result = -1 self.setMouseTracking(True) self.setFocusPolicy(Qt.NoFocus) self.text_option = to = QTextOption() to.setWrapMode(to.NoWrap) self.divider = QStaticText('\xa0→ \xa0') self.divider.setTextFormat(Qt.PlainText)
def set_message(self, text, color_, bold=False, is_permanent=False): from vise.view import certificate_error_domains key = (text, color_.name(), bold, is_permanent) if key == self.current_key: return self.current_key = key self.is_permanent = is_permanent prefix = text.partition(':')[0] self.is_address = self.is_permanent and prefix.lower() in { 'http', 'https', 'vise', 'file' } self.is_secure = prefix.lower() in {'https', 'vise', 'file'} color_ = color_ or self.palette().color(self.palette().WindowText) if self.is_address: qurl = QUrl(text) if self.is_secure and qurl.host() in certificate_error_domains: self.is_secure = False if qurl.scheme() in {'vise', 'file'}: host = qurl.path() rest = '' sep = ':' else: host = qurl.host() rest = qurl.toDisplayString(QUrl.PrettyDecoded | QUrl.RemoveScheme | QUrl.RemoveAuthority) sep = '://' self.static_text = QStaticText( '<span style="white-space:nowrap; color: {fg}">' '<span style="color:{emph}; font-weight:bold">{scheme}</span><span style="color:{dull}">{sep}</span>' '<span style="color:{fg}">{host}</span>' '<span style="color:{dull}">{rest}</span>'.format( fg=color_.name(), emph='green' if self.is_secure else 'red', scheme=escape(qurl.scheme()), host=escape(host), dull=color('status bar dull foreground', 'gray'), sep=sep, rest=escape(rest))) else: self.static_text = QStaticText( '<span style="color:{}; font-weight: {}; white-space:nowrap">{}</span>' .format(color_.name(), ('bold' if bold else 'normal'), escape(text))) to = QTextOption(Qt.AlignLeft | Qt.AlignTop) to.setWrapMode(to.NoWrap) self.static_text.setTextOption(to) self.static_text.prepare(font=self.font()) self.update()
def sizeHint(self, option, index): st = QStaticText(index.data(RENDER_ROLE)) st.prepare(font=self.parent().font()) width = max(option.rect.width(), self.parent().width() - 50) if width and width != st.textWidth(): st.setTextWidth(width) br = st.size() return QSize(br.width() + self.MARGIN, br.height() + self.MARGIN)
def paint(self, painter, option, index): QStyledItemDelegate.paint(self, painter, option, QModelIndex()) theme = index.data(Qt.UserRole) if not theme: return painter.save() pixmap = index.data(Qt.DecorationRole) if pixmap and not pixmap.isNull(): rect = option.rect.adjusted(0, self.SPACING, COVER_SIZE[0] - option.rect.width(), - self.SPACING) painter.drawPixmap(rect, pixmap) if option.state & QStyle.State_Selected: painter.setPen(QPen(QApplication.instance().palette().highlightedText().color())) bottom = option.rect.bottom() - 2 painter.drawLine(0, bottom, option.rect.right(), bottom) if 'static-text' not in theme: theme['static-text'] = QStaticText(_( ''' <h1>{title}</h1> <p>by <i>{author}</i> with <b>{number}</b> icons [{size}]</p> <p>{description}</p> <p>Version: {version} Number of users: {usage}</p> '''.format(title=theme.get('title', _('Unknown')), author=theme.get('author', _('Unknown')), number=theme.get('number', 0), description=theme.get('description', ''), size=human_readable(theme.get('compressed-size', 0)), version=theme.get('version', 1), usage=theme.get('usage', 0), ))) painter.drawStaticText(COVER_SIZE[0] + self.SPACING, option.rect.top() + self.SPACING, theme['static-text']) painter.restore()
def sizeHint(self, option, index): st = QStaticText(index.data(RENDER_ROLE)) st.prepare(font=self.parent().font()) width = max(option.rect.width(), self.parent().width() - 50) if width and width != st.textWidth(): st.setTextWidth(width) br = st.size() return QSize(br.width(), br.height() + self.MARGIN)
def set_message(self, text, color_, bold=False, is_permanent=False): from vise.view import certificate_error_domains key = (text, color_.name(), bold, is_permanent) if key == self.current_key: return self.current_key = key self.is_permanent = is_permanent prefix = text.partition(':')[0] self.is_address = self.is_permanent and prefix.lower() in {'http', 'https', 'vise'} self.is_secure = prefix.lower() in {'https', 'vise'} color_ = color_ or self.palette().color(self.palette().WindowText) if self.is_address: qurl = QUrl(text) if self.is_secure and qurl.host() in certificate_error_domains: self.is_secure = False if qurl.scheme() == 'vise': host = qurl.path() rest = '' sep = ':' else: host = qurl.host() rest = qurl.toDisplayString(QUrl.PrettyDecoded | QUrl.RemoveScheme | QUrl.RemoveAuthority) sep = '://' self.static_text = QStaticText( '<span style="white-space:nowrap; color: {fg}">' '<span style="color:{emph}; font-weight:bold">{scheme}</span><span style="color:{dull}">{sep}</span>' '<span style="color:{fg}">{host}</span>' '<span style="color:{dull}">{rest}</span>'.format( fg=color_.name(), emph='green' if self.is_secure else 'red', scheme=escape(qurl.scheme()), host=escape(host), dull=color('status bar dull foreground', 'gray'), sep=sep, rest=escape(rest) )) else: self.static_text = QStaticText('<span style="color:{}; font-weight: {}; white-space:nowrap">{}</span>'.format( color_.name(), ('bold' if bold else 'normal'), escape(text))) to = QTextOption(Qt.AlignLeft | Qt.AlignTop) to.setWrapMode(to.NoWrap) self.static_text.setTextOption(to) self.static_text.prepare(font=self.font()) self.update()
def get_static_text(self, otext, positions): st = self.rendered_text_cache.get(otext) if st is None: text = (otext or '').ljust(self.max_text_length + 1, ' ') text = make_highlighted_text('color: magenta', text, positions) desc = self.descriptions.get(otext) if desc: text += ' ' + desc st = self.rendered_text_cache[otext] = QStaticText(text) st.setTextOption(self.text_option) st.setTextFormat(Qt.RichText) st.prepare(font=self.parent().font()) return st
def paintEvent(self, ev): painter = QPainter(self) painter.setClipRect(ev.rect()) pal = self.palette() painter.fillRect(self.rect(), pal.color(pal.Text)) crect = self.rect().adjusted(1, 1, -1, -1) painter.fillRect(crect, pal.color(pal.Base)) painter.setClipRect(crect) painter.setFont(self.parent().font()) width = self.rect().width() for i, st, y, height in self.iter_visible_items(): painter.save() if i == self.current_index: painter.fillRect(1, y, width, height, pal.color(pal.Highlight)) color = pal.color(QPalette.HighlightedText).name() st = QStaticText(st) text = st.text().partition('>')[2] st.setText('<span style="color: %s">%s' % (color, text)) painter.drawStaticText(self.SIDE_MARGIN, y, st) painter.restore() painter.end() if self.current_size_hint is None: QTimer.singleShot(0, self.layout)
def __call__(self, results): if results: self.current_result = 0 prefixes = [QStaticText('<b>%s</b>' % os.path.basename(x)) for x in results] [(p.setTextFormat(Qt.RichText), p.setTextOption(self.text_option)) for p in prefixes] self.maxwidth = max([x.size().width() for x in prefixes]) self.results = tuple((prefix, self.make_text(text, positions), text) for prefix, (text, positions) in izip(prefixes, results.iteritems())) else: self.results = () self.current_result = -1 self.max_result = min(10, len(self.results) - 1) self.mouse_hover_result = -1 self.update()
def paintEvent(self, ev): painter = QPainter(self) painter.setClipRect(ev.rect()) pal = self.palette() painter.fillRect(self.rect(), pal.color(QPalette.ColorRole.Text)) crect = self.rect().adjusted(1, 1, -1, -1) painter.fillRect(crect, pal.color(QPalette.ColorRole.Base)) painter.setClipRect(crect) painter.setFont(self.parent().font()) width = self.rect().width() for i, st, y, height in self.iter_visible_items(): painter.save() if i == self.current_index: painter.fillRect(1, y, width, height, pal.color(pal.Highlight)) color = pal.color(QPalette.ColorRole.HighlightedText).name() st = QStaticText(st) text = st.text().partition('>')[2] st.setText('<span style="color: %s">%s' % (color, text)) painter.drawStaticText(self.SIDE_MARGIN, y, st) painter.restore() painter.end() if self.current_size_hint is None: QTimer.singleShot(0, self.layout)
def get_static_text(self, otext, positions): st = self.rendered_text_cache.get(otext) if st is None: text = (otext or '').ljust(self.max_text_length + 1, '\xa0') text = make_highlighted_text('color: magenta', text, positions) desc = self.descriptions.get(otext) if desc: text += ' - <i>%s</i>' % prepare_string_for_xml(desc) color = self.palette().color(QPalette.ColorRole.Text).name() text = '<span style="color: %s">%s</span>' % (color, text) st = self.rendered_text_cache[otext] = QStaticText(text) st.setTextOption(self.text_option) st.setTextFormat(Qt.TextFormat.RichText) st.prepare(font=self.parent().font()) return st
def static_text(self): if self._static_text is None: before_words = self.before.split() before = ' '.join(before_words[-3:]) before_extra = len(before) - 15 if before_extra > 0: before = before[before_extra:] before = '…' + before before_space = '' if self.before.rstrip() == self.before else ' ' after_words = self.after.split() after = ' '.join(after_words[:3])[:15] + '…' after_space = '' if self.after.lstrip() == self.after else ' ' self._static_text = st = QStaticText('<p>{}{}<b>{}</b>{}{}'.format(before, before_space, self.text, after_space, after)) st.setTextFormat(Qt.RichText) st.setTextWidth(10000) return self._static_text
def make_highlighted_text(text, positions, emph='color:magenta', wrapper=None): positions = sorted(set(positions) - {-1}) if positions: parts = [] pos = 0 for p in positions: ch = text[p] parts.append(escape(text[pos:p])) parts.append('<span style="%s">%s</span>' % (emph, escape(ch))) pos = p + len(ch) parts.append(escape(text[pos:])) text = ''.join(parts) if wrapper: text = '<span style="%s">%s</span>' % (wrapper, text) ans = QStaticText(text) to = ans.textOption() to.setWrapMode(to.NoWrap) ans.setTextOption(to) ans.setTextFormat(Qt.RichText) return ans
def make_text(self, text, positions): text = QStaticText(make_highlighted_text(self.EMPH, text, positions)) text.setTextOption(self.text_option) text.setTextFormat(Qt.RichText) return text
class Message(QWidget): def __init__(self, parent, sb_background): QWidget.__init__(self, parent) self.is_permanent = False self.is_address = False self.is_secure = False self.static_text = None self.current_key = None self.setFocusPolicy(Qt.NoFocus) self.sb_background = QColor(color(sb_background, self.palette().color(QPalette.Window))) def set_message(self, text, color_, bold=False, is_permanent=False): from vise.view import certificate_error_domains key = (text, color_.name(), bold, is_permanent) if key == self.current_key: return self.current_key = key self.is_permanent = is_permanent prefix = text.partition(':')[0] self.is_address = self.is_permanent and prefix.lower() in {'http', 'https', 'vise'} self.is_secure = prefix.lower() in {'https', 'vise'} color_ = color_ or self.palette().color(self.palette().WindowText) if self.is_address: qurl = QUrl(text) if self.is_secure and qurl.host() in certificate_error_domains: self.is_secure = False if qurl.scheme() == 'vise': host = qurl.path() rest = '' sep = ':' else: host = qurl.host() rest = qurl.toDisplayString(QUrl.PrettyDecoded | QUrl.RemoveScheme | QUrl.RemoveAuthority) sep = '://' self.static_text = QStaticText( '<span style="white-space:nowrap; color: {fg}">' '<span style="color:{emph}; font-weight:bold">{scheme}</span><span style="color:{dull}">{sep}</span>' '<span style="color:{fg}">{host}</span>' '<span style="color:{dull}">{rest}</span>'.format( fg=color_.name(), emph='green' if self.is_secure else 'red', scheme=escape(qurl.scheme()), host=escape(host), dull=color('status bar dull foreground', 'gray'), sep=sep, rest=escape(rest) )) else: self.static_text = QStaticText('<span style="color:{}; font-weight: {}; white-space:nowrap">{}</span>'.format( color_.name(), ('bold' if bold else 'normal'), escape(text))) to = QTextOption(Qt.AlignLeft | Qt.AlignTop) to.setWrapMode(to.NoWrap) self.static_text.setTextOption(to) self.static_text.prepare(font=self.font()) self.update() def paintEvent(self, ev): if not self.static_text or not self.static_text.text(): return p = QPainter(self) p.setRenderHint(p.TextAntialiasing) # If text is too long too fit, fade it out at the end self.static_text.setTextWidth(self.rect().width()) sz = self.static_text.size() r = self.rect() p.drawStaticText(0, (r.height() - sz.height()) // 2, self.static_text) if sz.width() > r.width(): g = QLinearGradient(self.rect().topLeft(), self.rect().topRight()) c = QColor(self.sb_background) c.setAlpha(0) g.setColorAt(0, c) g.setColorAt(0.8, c) g.setColorAt(1.0, self.sb_background) p.fillRect(self.rect(), QBrush(g)) p.end()
class Results(QWidget): EMPH = "color:magenta; font-weight:bold" MARGIN = 4 item_selected = pyqtSignal() def __init__(self, parent=None): QWidget.__init__(self, parent=parent) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.results = () self.current_result = -1 self.max_result = -1 self.mouse_hover_result = -1 self.setMouseTracking(True) self.setFocusPolicy(Qt.NoFocus) self.text_option = to = QTextOption() to.setWrapMode(to.NoWrap) self.divider = QStaticText('\xa0→ \xa0') self.divider.setTextFormat(Qt.PlainText) def item_from_y(self, y): if not self.results: return delta = self.results[0][0].size().height() + self.MARGIN maxy = self.height() pos = 0 for i, r in enumerate(self.results): bottom = pos + delta if pos <= y < bottom: return i break pos = bottom if pos > min(y, maxy): break return -1 def mouseMoveEvent(self, ev): y = ev.pos().y() prev = self.mouse_hover_result self.mouse_hover_result = self.item_from_y(y) if prev != self.mouse_hover_result: self.update() def mousePressEvent(self, ev): if ev.button() == 1: i = self.item_from_y(ev.pos().y()) if i != -1: ev.accept() self.current_result = i self.update() self.item_selected.emit() return return QWidget.mousePressEvent(self, ev) def change_current(self, delta=1): if not self.results: return nc = self.current_result + delta if 0 <= nc <= self.max_result: self.current_result = nc self.update() def __call__(self, results): if results: self.current_result = 0 prefixes = [QStaticText('<b>%s</b>' % os.path.basename(x)) for x in results] [(p.setTextFormat(Qt.RichText), p.setTextOption(self.text_option)) for p in prefixes] self.maxwidth = max([x.size().width() for x in prefixes]) self.results = tuple((prefix, self.make_text(text, positions), text) for prefix, (text, positions) in izip(prefixes, results.iteritems())) else: self.results = () self.current_result = -1 self.max_result = min(10, len(self.results) - 1) self.mouse_hover_result = -1 self.update() def make_text(self, text, positions): text = QStaticText(make_highlighted_text(self.EMPH, text, positions)) text.setTextOption(self.text_option) text.setTextFormat(Qt.RichText) return text def paintEvent(self, ev): offset = QPoint(0, 0) p = QPainter(self) p.setClipRect(ev.rect()) bottom = self.rect().bottom() if self.results: for i, (prefix, full, text) in enumerate(self.results): size = prefix.size() if offset.y() + size.height() > bottom: break self.max_result = i offset.setX(0) if i in (self.current_result, self.mouse_hover_result): p.save() if i != self.current_result: p.setPen(Qt.DotLine) p.drawLine(offset, QPoint(self.width(), offset.y())) p.restore() offset.setY(offset.y() + self.MARGIN // 2) p.drawStaticText(offset, prefix) offset.setX(self.maxwidth + 5) p.drawStaticText(offset, self.divider) offset.setX(offset.x() + self.divider.size().width()) p.drawStaticText(offset, full) offset.setY(offset.y() + size.height() + self.MARGIN // 2) if i in (self.current_result, self.mouse_hover_result): offset.setX(0) p.save() if i != self.current_result: p.setPen(Qt.DotLine) p.drawLine(offset, QPoint(self.width(), offset.y())) p.restore() else: p.drawText(self.rect(), Qt.AlignCenter, _('No results found')) p.end() @property def selected_result(self): try: return self.results[self.current_result][-1] except IndexError: pass
class Message(QWidget): def __init__(self, parent, sb_background): QWidget.__init__(self, parent) self.is_permanent = False self.is_address = False self.is_secure = False self.static_text = None self.current_key = None self.setFocusPolicy(Qt.NoFocus) self.sb_background = QColor( color(sb_background, self.palette().color(QPalette.Window))) def set_message(self, text, color_, bold=False, is_permanent=False): from vise.view import certificate_error_domains key = (text, color_.name(), bold, is_permanent) if key == self.current_key: return self.current_key = key self.is_permanent = is_permanent prefix = text.partition(':')[0] self.is_address = self.is_permanent and prefix.lower() in { 'http', 'https', 'vise', 'file' } self.is_secure = prefix.lower() in {'https', 'vise', 'file'} color_ = color_ or self.palette().color(self.palette().WindowText) if self.is_address: qurl = QUrl(text) if self.is_secure and qurl.host() in certificate_error_domains: self.is_secure = False if qurl.scheme() in {'vise', 'file'}: host = qurl.path() rest = '' sep = ':' else: host = qurl.host() rest = qurl.toDisplayString(QUrl.PrettyDecoded | QUrl.RemoveScheme | QUrl.RemoveAuthority) sep = '://' self.static_text = QStaticText( '<span style="white-space:nowrap; color: {fg}">' '<span style="color:{emph}; font-weight:bold">{scheme}</span><span style="color:{dull}">{sep}</span>' '<span style="color:{fg}">{host}</span>' '<span style="color:{dull}">{rest}</span>'.format( fg=color_.name(), emph='green' if self.is_secure else 'red', scheme=escape(qurl.scheme()), host=escape(host), dull=color('status bar dull foreground', 'gray'), sep=sep, rest=escape(rest))) else: self.static_text = QStaticText( '<span style="color:{}; font-weight: {}; white-space:nowrap">{}</span>' .format(color_.name(), ('bold' if bold else 'normal'), escape(text))) to = QTextOption(Qt.AlignLeft | Qt.AlignTop) to.setWrapMode(to.NoWrap) self.static_text.setTextOption(to) self.static_text.prepare(font=self.font()) self.update() def paintEvent(self, ev): if not self.static_text or not self.static_text.text(): return p = QPainter(self) p.setRenderHint(p.TextAntialiasing) # If text is too long too fit, fade it out at the end self.static_text.setTextWidth(self.rect().width()) sz = self.static_text.size() r = self.rect() p.drawStaticText(0, (r.height() - sz.height()) // 2, self.static_text) if sz.width() > r.width(): g = QLinearGradient(self.rect().topLeft(), self.rect().topRight()) c = QColor(self.sb_background) c.setAlpha(0) g.setColorAt(0, c) g.setColorAt(0.8, c) g.setColorAt(1.0, self.sb_background) p.fillRect(self.rect(), QBrush(g)) p.end()
def make_text(self, text, positions): text = QStaticText( make_highlighted_text(emphasis_style(), text, positions)) text.setTextOption(self.text_option) text.setTextFormat(Qt.TextFormat.RichText) return text