# Copyright (C) 2015-2017 Damon Lynch # This file is part of Rapid Photo Downloader. # # Rapid Photo Downloader is free software: you can redistribute it and/or # modify it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Rapid Photo Downloader is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Rapid Photo Downloader. If not, # see . __author__ = 'Damon Lynch' __copyright__ = "Copyright 2015-2017, Damon Lynch" from enum import IntEnum from PyQt5.QtGui import (QColor, QPalette) from PyQt5.QtWidgets import (QPushButton, QStylePainter, QStyle, QStyleOptionButton, QHBoxLayout) class VerticalRotation(IntEnum): left_side = 270 right_side = 90 class FlatButton: _padding = 'padding-left: {padding_side}px; padding-right: {padding_side}px; padding-top: ' \ '{padding_top}px; padding-bottom: {padding_bottom}px;'.format( padding_top=6, padding_side=7, padding_bottom=6 ) def setFlatStyle(self, button: QPushButton, darker_if_checked: bool=True, padding: str='', color: QColor=None, text_color: QColor=None) -> None: if color is None: color = QPalette().color(QPalette.Background) default_color = color.name(QColor.HexRgb) if darker_if_checked: checked_color = color.darker(125).name(QColor.HexRgb) else: checked_color = default_color hover_color = color.darker(110).name(QColor.HexRgb) if not padding: padding = self._padding if text_color is not None: text = 'color: {};'.format(text_color.name(QColor.HexRgb)) else: text = '' # outline:none is used to remove the rectangle that appears on a # button when the button has focus # http://stackoverflow.com/questions/17280056/qt-css-decoration-on-focus stylesheet = """ QPushButton { background-color: %s; border: 0px; outline: none; %s %s} QPushButton:checked { background-color: %s; border: none; } QPushButton:hover{ background-color: %s; border-style: inset; } """ % (default_color, padding, text, checked_color, hover_color) # button.setStyleSheet(stylesheet) def setHighlightedFlatStyle(self, button: QPushButton) -> None: palette = QPalette() color = palette.color(palette.Highlight) text_color = palette.color(palette.HighlightedText) self.setFlatStyle(button, color=color, text_color=text_color, darker_if_checked=False) class RotatedButton(QPushButton, FlatButton): leftSide = 270.0 rightSide = 90.0 def __init__(self, text: str, rotation: float, flat: bool=True, use_highlight_color=False, checkable: bool=True, parent=None) -> None: """ A push button to show in the left or right side of a window :param text: text to display :param rotation: whether on the left or right side of the window :param flat: if True, set style to flat style :param use_highlight_color: if True, the button's color should be the palette's color for highlighting selected items. Takes effect only when using a flat is also True. :param checkable: if the button is checkable or not :param parent: optional parent widget """ super().__init__(text, parent) self.buttonRotation = rotation if flat: # Use only the stylesheet to give the appearance of being flat. # Don't mix and match stylesheet and non-stylesheet options for widgets. # http://stackoverflow.com/questions/34654545/qt-flat-qpushbutton-background-color-doesnt-work if use_highlight_color: self.setHighlightedFlatStyle(self) else: self.setFlatStyle(self) self.setCheckable(checkable) def paintEvent(self, event): painter = QStylePainter(self) painter.rotate(self.buttonRotation) if self.buttonRotation == VerticalRotation.left_side: painter.translate(-1 * self.height(), 0) elif self.buttonRotation == VerticalRotation.right_side: painter.translate(0, -1 * self.width()) painter.drawControl(QStyle.CE_PushButton, self.getSyleOptions()) def setRotation(self, rotation: float): self.buttonRotation = rotation def sizeHint(self): size = super().sizeHint() size.transpose() return size def getSyleOptions(self) -> QStyleOptionButton: options = QStyleOptionButton() options.initFrom(self) size = options.rect.size() size.transpose() options.rect.setSize(size) try: options.features = QStyleOptionButton.None_ except AttributeError: # Allow for bug in PyQt 5.4 options.features = getattr(QStyleOptionButton, 'None') if self.isFlat(): options.features |= QStyleOptionButton.Flat if self.menu(): options.features |= QStyleOptionButton.HasMenu if self.autoDefault() or self.isDefault(): options.features |= QStyleOptionButton.AutoDefaultButton if self.isDefault(): options.features |= QStyleOptionButton.DefaultButton if self.isDown() or (self.menu() and self.menu().isVisible()): options.state |= QStyle.State_Sunken if self.isChecked(): options.state |= QStyle.State_On if not self.isFlat() and not self.isDown(): options.state |= QStyle.State_Raised options.text = self.text() options.icon = self.icon() options.iconSize = self.iconSize() return options def setHighlighted(self, highlighted: bool) -> None: if highlighted: self.setHighlightedFlatStyle(self) else: self.setFlatStyle(self) self.update()