def draw_icon(icon, rect, painter, icon_mode, shadow=False): cache = icon.pixmap(rect.size()) dip_offset = QPoint(1, -2) cache = QPixmap() pixname = "icon {0} {1} {2}".format(icon.cacheKey(), icon_mode, rect.height()) if QPixmapCache.find(pixname) is None: pix = icon.pixmap(rect.size()) device_pixel_ratio = pix.devicePixelRatio() radius = 3 * device_pixel_ratio offset = dip_offset * device_pixel_ratio cache = QPixmap(pix.size() + QSize(radius * 2, radius * 2)) cache.fill(Qt.transparent) cache_painter = QPainter(cache) if icon_mode == QIcon.Disabled: im = pix.toImage().convertToFormat(QImage.Format_ARGB32) for y in range(0, im.height()): scanline = im.scanLine(y) for x in range(0, im.width()): pixel = scanline intensity = qGray(pixel) scanline = qRgba(intensity, intensity, intensity, qAlpha(pixel)) scanline += 1 pix = QPixmap.fromImage(im) # Draw shadow tmp = QImage(pix.size() + QSize(radius * 2, radius * 2), QImage.Format_ARGB32_Premultiplied) tmp.fill(Qt.transparent) tmp_painter = QPainter(tmp) tmp_painter.setCompositionMode(QPainter.CompositionMode_Source) tmp_painter.drawPixmap( QRect(radius, radius, pix.width(), pix.height()), pix) tmp_painter.end() # Blur the alpha channel blurred = QImage(tmp.size(), QImage.Format_ARGB32_Premultiplied) blur_painter = QPainter(blurred) blur_painter.end() # tmp = blurred tmp_painter.begin(tmp) tmp_painter.setCompositionMode(QPainter.CompositionMode_SourceIn) tmp_painter.fillRect(tmp.rect(), QColor(0, 0, 0, 150)) tmp_painter.end() tmp_painter.begin(tmp) tmp_painter.setCompositionMode(QPainter.CompositionMode_SourceIn) tmp_painter.fillRect(tmp.rect(), QColor(0, 0, 0, 150)) tmp_painter.end() # Draw the blurred drop shadow cache_painter.drawImage( QRect(0, 0, cache.rect().width(), cache.rect().height()), tmp) # Draw the actual pixmap cache_painter.drawPixmap( QRect( QPoint(radius, radius) + offset, QSize(pix.width(), pix.height())), pix) cache_painter.end() cache.setDevicePixelRatio(device_pixel_ratio) QPixmapCache.insert(pixname, cache) target_rect = cache.rect() target_rect.setSize(target_rect.size() / cache.devicePixelRatio()) target_rect.moveCenter(rect.center() - dip_offset) painter.drawPixmap(target_rect, cache)
def __init__(self, parent=None) -> None: super().__init__(parent) self.setWindowFlags(Qt.Window | Qt.FramelessWindowHint) self.setObjectName('AboutDialog') self.setStyleSheet( 'QDialog#AboutDialog {background-image: url(:/splashscreen.png);}') pixmap = QPixmap(':/splashscreen.png') try: ratio = pixmap.devicePixelRatioF() except AttributeError: ratio = pixmap.devicePixelRatio() if ratio > 1.0: size = QSize(pixmap.width() / ratio, pixmap.height() / ratio) else: size = pixmap.size() self.setFixedSize(size) # These values are derived from the splash screen image contents. # If the image changes, so should these white_box_height = 80 title_bottom = 45 left_margin = 16 transparency = "rgba(0, 0, 0, 130)" # Standard About view msg = """Copyright © 2007-2020 Damon Lynch.<br><br> <a href="http://www.damonlynch.net/rapid" %(link_style)s> www.damonlynch.net/rapid</a><br><br> This program comes with absolutely no warranty.<br> See the <a href="http://www.gnu.org/copyleft/gpl.html" %(link_style)s>GNU General Public License, version 3 or later</a> for details. """ % dict(link_style='style="color: white;"') details = QLabel(msg) details_style_sheet = """QLabel { color: white; background-color: %(transparency)s; margin-left: 0px; padding-left: %(left_margin)dpx; padding-top: 6px; padding-right: 6px; padding-bottom: 6px; }""" % dict(left_margin=left_margin, transparency=transparency) details.setStyleSheet(details_style_sheet) details.setOpenExternalLinks(True) details.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) font = self.font() # type: QFont font_size = font.pointSize() - 2 font.setPointSize(font_size) details.setFont(font) aboutLayout = QVBoxLayout() aboutLayout.setContentsMargins(0, 0, 0, 0) aboutLayout.addSpacing(150) detailsLayout = QHBoxLayout() detailsLayout.setContentsMargins(0, 0, 0, 0) detailsLayout.addWidget(details) detailsLayout.addStretch(10) aboutLayout.addLayout(detailsLayout) aboutLayout.addStretch(10) about = QWidget() about.setLayout(aboutLayout) # Credits view credits_text = """ Copyright © 2007-2020 Damon Lynch. Portions copyright © 2008-2015 Canonical Ltd. Portions copyright © 2013 Bernard Baeyens. Portions copyright © 2012-2015 Jim Easterbrook. Portions copyright © 2012 Sven Marnach. Portions copyright © 2015 Dmitry Shachnev. Photo %(photolink)s copyright © 2014-2018 Damon Lynch, all rights reserved. Camera icon courtesy %(artlink1)s. Video camera icon courtesy %(artlink2)s. Home icon courtesy %(artlink3)s. Speech bubble courtesy %(artlink4)s. Lightbulb icon courtesy %(artlink5)s. Unlink icon courtesy %(artlink6)s. Clock icon courtesy %(artlink7)s. """ credits_text = credits_text.replace('\n', '<br>\n') credits_text = credits_text % dict( photolink= """<a href="https://500px.com/photo/246096445/afghan-men-pulling-heavy-load- by-damon-lynch" style="color: white;">Afghan Men Pulling Heavy Load</a>""", artlink1= '<a href="http://www.webalys.com" style="color: white;">Vincent Le Moign</a>', artlink2= """<a href="https://www.iconfinder.com/bluewolfski" style="color: white;">The Pictographers</a>""", artlink3= '<a href="https://www.iconfinder.com/Enesdal" style="color: white;">Enes' ' Dal</a>', artlink4= '<a href="http://www.iconsolid.com/" style="color: white;">Icons Solid</a>', artlink5= '<a href="https://sellfy.com/designcoon" style="color: white;">Icon Coon</a>', artlink6= '<a href="https://www.iconfinder.com/icons/1608708/unlink_icon" style="color: ' 'white;">Dave Gandy</a>', artlink7= '<a href="https://www.flaticon.com/authors/pixel-perfect" style="color: ' 'white;">Pixel perfect</a>') label_style_sheet = """QLabel { background-color: rgba(0, 0, 0, 0); color: white; padding-left: %(left_margin)dpx; padding-top: 6px; padding-right: 6px; padding-bottom: 6px; }""" % dict(left_margin=left_margin) creditsLabel = QLabel(credits_text) creditsLabel.setFont(font) creditsLabel.setStyleSheet(label_style_sheet) creditsLabel.setOpenExternalLinks(True) credits = QScrollArea() credits.setWidget(creditsLabel) scroll_area_style_sheet = """QScrollArea { background-color: %(transparency)s; border: 0px; } """ % dict(transparency=transparency) credits.setStyleSheet(scroll_area_style_sheet) # Translators view translators_text = """ <b>Algerian</b> Algent Albrahimi <*****@*****.**> <b>Belarusian</b> Ilya Tsimokhin <*****@*****.**> <b>Brazilian Portuguese</b> Ney Walens de Mesquita <*****@*****.**> Rubens Stuginski Jr <*****@*****.**> <b>Catalan</b> Adolfo Jayme Barrientos <*****@*****.**> <b>Czech</b> Pavel Borecki <*****@*****.**> <b>Danish</b> Torben Gundtofte-Bruun <*****@*****.**> <b>Dutch</b> Alain J. Baudrez <*****@*****.**> <b>Estonian</b> Tauno Erik <*****@*****.**> <b>Finnish</b> Mikko Ruohola <*****@*****.**> <b>French</b> Jean-Marc Lartigue <*****@*****.**> <b>Greek</b> Dimitris Xenakis <*****@*****.**> <b>Hungarian</b> László <*****@*****.**> András Lőrincz <*****@*****.**> <b>Italian</b> Matteo Carotta <*****@*****.**> Milo Casagrande <*****@*****.**> <b>Japanese</b> Koji Yokota <*****@*****.**> <b>Kabyle</b> Mohammed Belkacem <*****@*****.**> <b>Norwegian Bokmal</b> Harlad H <*****@*****.**> Rudolf Maurer <*****@*****.**> <b>Norwegian Nynorsk</b> Kevin Brubeck Unhammer <*****@*****.**> Harlad H <*****@*****.**> <b>Polish</b> Michal Predotka <*****@*****.**> <b>Russian</b> Evgeny Kozlov <*****@*****.**> <b>Serbian</b> Мирослав Николић <*****@*****.**> <b>Slovak</b> Robert Valik <*****@*****.**> <b>Spanish</b> Adolfo Jayme Barrientos <*****@*****.**> Jose Luis Tirado <*****@*****.**> <b>Swedish</b> Joachim Johansson <*****@*****.**> <b>Turkish</b> Ilker Alp <*****@*****.**> <b>Previous translators</b> Anton Alyab'ev <*****@*****.**> Michel Ange <*****@*****.**> Tobias Bannert <*****@*****.**> Bert <*****@*****.**> Martin Dahl Moe Marco de Freitas <*****@*****.**> Martin Egger <*****@*****.**> Sergiy Gavrylov <*****@*****.**> Emanuele Grande <*****@*****.**> Toni Lähdekorpi <*****@*****.**> Miroslav Matejaš <*****@*****.**> Erik M Frederik Müller <*****@*****.**> Jose Luis Navarro <*****@*****.**> Tomas Novak <*****@*****.**> Abel O'Rian <*****@*****.**> Balazs Oveges <*****@*****.**> Daniel Paessler <*****@*****.**> Miloš Popović <*****@*****.**> Ye Qing <*****@*****.**> Luca Reverberi <*****@*****.**> Ahmed Shubbar <*****@*****.**> Sergei Sedov <*****@*****.**> Marco Solari <*****@*****.**> Ulf Urdén <*****@*****.**> Julien Valroff <*****@*****.**> Aron Xu <*****@*****.**> Nicolás M. Zahlut <*****@*****.**> 梁其学 <*****@*****.**> """ # Replace < and > in email addresses translators_text = re.sub(r'<(.+)@(.+)>', r'<\1@\2>', translators_text, flags=re.MULTILINE) translators_text = translators_text.replace('\n', '<br>\n') translatorsLabel = QLabel(translators_text) translatorsLabel.setFont(font) translatorsLabel.setStyleSheet(label_style_sheet) translators = QScrollArea() translators.setWidget(translatorsLabel) translators.setStyleSheet(scroll_area_style_sheet) mainLayout = QVBoxLayout() self.stack = QStackedWidget() self.stack.addWidget(about) self.stack.addWidget(credits) self.stack.addWidget(translators) self.stack.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) buttonBox = QDialogButtonBox() closeButton = buttonBox.addButton( QDialogButtonBox.Close) # type: QPushButton translateDialogBoxButtons(buttonBox) self.creditsButton = buttonBox.addButton( _('Credits'), QDialogButtonBox.HelpRole) # type: QPushButton self.creditsButton.setDefault(False) self.creditsButton.setCheckable(True) self.translatorsButton = buttonBox.addButton( _('Translators'), QDialogButtonBox.ResetRole) # type: QPushButton self.translatorsButton.setDefault(False) self.translatorsButton.setCheckable(True) closeButton.setDefault(True) buttonLayout = QVBoxLayout() buttonLayout.addWidget(buttonBox) buttonLayout.setContentsMargins(left_margin, left_margin, left_margin, left_margin) mainLayout.setContentsMargins(0, 0, 0, 0) version = QLabel(__about__.__version__) version.setFixedHeight(white_box_height - title_bottom) version_style_sheet = """QLabel { padding-left: %(left_margin)dpx; }""" % dict(left_margin=left_margin) version.setStyleSheet(version_style_sheet) mainLayout.addSpacing(title_bottom) mainLayout.addWidget(version) mainLayout.addWidget(self.stack) mainLayout.addLayout(buttonLayout) self.setLayout(mainLayout) buttonBox.rejected.connect(self.reject) self.creditsButton.clicked.connect(self.creditsButtonClicked) self.translatorsButton.clicked.connect(self.translatorsButtonClicked) closeButton.setFocus()
def drawIconWithShadow(icon: QIcon, rect: QRect, p: QPainter, iconMode: QIcon.Mode = None, dipRadius: int = None, color: QColor = None, dipOffset: QPoint = None): if iconMode is None: iconMode = QIcon.Normal if color is None: color = QColor(0, 0, 0, 130) if dipRadius is None: dipRadius = 3 if dipOffset is None: dipOffset = QPoint(1, -2) devicePixelRatio: int = p.device().devicePixelRatio() pixmapName = "icon %s %s %s %s" % (icon.cacheKey(), iconMode, rect.height(), devicePixelRatio) cache = QPixmapCache.find(pixmapName) if cache is None: # High-dpi support: The in parameters (rect, radius, offset) are in # device-independent pixels. The call to QIcon::pixmap() below might # return a high-dpi pixmap, which will in that case have a devicePixelRatio # different than 1. The shadow drawing caluculations are done in device # pixels. window = p.device().window().windowHandle() px = icon.pixmap(window, rect.size(), iconMode) radius = dipRadius * devicePixelRatio offset = dipOffset * devicePixelRatio cache = QPixmap(px.size() + QSize(radius * 2, radius * 2)) cache.fill(Qt.transparent) cachePainter = QPainter(cache) if iconMode == QIcon.Disabled: hasDisabledState = len(icon.availableSizes()) == len( icon.availableSizes(QIcon.Disabled)) if not hasDisabledState: px = disabledSideBarIcon(icon.pixmap(window, rect.size())) elif TOOLBAR_ICON_SHADOW: # Draw shadow tmp = QImage(px.size() + QSize(radius * 2, radius * 2 + 1), QImage.Format_ARGB32_Premultiplied) tmp.fill(Qt.transparent) tmpPainter = QPainter(tmp) tmpPainter.setCompositionMode(QPainter.CompositionMode_Source) tmpPainter.drawPixmap( QRect(radius, radius, px.width(), px.height()), px) tmpPainter.end() # blur the alpha channel blurred = QImage(tmp.size(), QImage.Format_ARGB32_Premultiplied) blurred.fill(Qt.transparent) blurPainter = QPainter(blurred) #qt_blurImage(blurPainter, tmp, radius, False, True) # implement qt_blurImage via QLabel with QGraphicsBlurEffect # FIXME: alignment is broken scene = QGraphicsScene() item = QGraphicsPixmapItem(QPixmap.fromImage(tmp)) effect = QGraphicsBlurEffect() effect.setBlurRadius(radius) item.setGraphicsEffect(effect) scene.addItem(item) scene.render(blurPainter) blurPainter.end() tmp = blurred # blacken the image... tmpPainter.begin(tmp) tmpPainter.setCompositionMode(QPainter.CompositionMode_SourceIn) tmpPainter.fillRect(tmp.rect(), color) tmpPainter.end() tmpPainter.begin(tmp) tmpPainter.setCompositionMode(QPainter.CompositionMode_SourceIn) tmpPainter.fillRect(tmp.rect(), color) tmpPainter.end() # draw the blurred drop shadow... cachePainter.drawImage( QRect(0, 0, cache.rect().width(), cache.rect().height()), tmp) # Draw the actual pixmap... cachePainter.drawPixmap( QRect( QPoint(radius, radius) + offset, QSize(px.width(), px.height())), px) cachePainter.end() cache.setDevicePixelRatio(devicePixelRatio) QPixmapCache.insert(pixmapName, cache) targetRect = cache.rect() targetRect.setSize(targetRect.size() / cache.devicePixelRatio()) targetRect.moveCenter(rect.center() - dipOffset) p.drawPixmap(targetRect, cache)
def draw_icon(icon, rect, painter, icon_mode, shadow=False): cache = icon.pixmap(rect.size()) dip_offset = QPoint(1, -2) cache = QPixmap() pixname = "icon {0} {1} {2}".format( icon.cacheKey(), icon_mode, rect.height() ) if QPixmapCache.find(pixname) is None: pix = icon.pixmap(rect.size()) device_pixel_ratio = pix.devicePixelRatio() radius = 3 * device_pixel_ratio offset = dip_offset * device_pixel_ratio cache = QPixmap(pix.size() + QSize(radius * 2, radius * 2)) cache.fill(Qt.transparent) cache_painter = QPainter(cache) if icon_mode == QIcon.Disabled: im = pix.toImage().convertToFormat(QImage.Format_ARGB32) for y in range(0, im.height()): scanline = im.scanLine(y) for x in range(0, im.width()): pixel = scanline intensity = qGray(pixel) scanline = qRgba( intensity, intensity, intensity, qAlpha(pixel)) scanline += 1 pix = QPixmap.fromImage(im) # Draw shadow tmp = QImage(pix.size() + QSize(radius * 2, radius * 2), QImage.Format_ARGB32_Premultiplied) tmp.fill(Qt.transparent) tmp_painter = QPainter(tmp) tmp_painter.setCompositionMode(QPainter.CompositionMode_Source) tmp_painter.drawPixmap( QRect(radius, radius, pix.width(), pix.height()), pix) tmp_painter.end() # Blur the alpha channel blurred = QImage(tmp.size(), QImage.Format_ARGB32_Premultiplied) blur_painter = QPainter(blurred) blur_painter.end() # tmp = blurred tmp_painter.begin(tmp) tmp_painter.setCompositionMode(QPainter.CompositionMode_SourceIn) tmp_painter.fillRect(tmp.rect(), QColor(0, 0, 0, 150)) tmp_painter.end() tmp_painter.begin(tmp) tmp_painter.setCompositionMode(QPainter.CompositionMode_SourceIn) tmp_painter.fillRect(tmp.rect(), QColor(0, 0, 0, 150)) tmp_painter.end() # Draw the blurred drop shadow cache_painter.drawImage( QRect(0, 0, cache.rect().width(), cache.rect().height()), tmp) # Draw the actual pixmap cache_painter.drawPixmap( QRect(QPoint(radius, radius) + offset, QSize(pix.width(), pix.height())), pix) cache_painter.end() cache.setDevicePixelRatio(device_pixel_ratio) QPixmapCache.insert(pixname, cache) target_rect = cache.rect() target_rect.setSize(target_rect.size() / cache.devicePixelRatio()) target_rect.moveCenter(rect.center() - dip_offset) painter.drawPixmap(target_rect, cache)