1# Copyright (C) 2016-2020 Damon Lynch <damonlynch@gmail.com>
2
3# This file is part of Rapid Photo Downloader.
4#
5# Rapid Photo Downloader is free software: you can redistribute it and/or
6# modify it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Rapid Photo Downloader is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Rapid Photo Downloader.  If not,
17# see <http://www.gnu.org/licenses/>.
18
19__author__ = 'Damon Lynch'
20__copyright__ = "Copyright 2016-2020, Damon Lynch"
21
22import math
23
24from PyQt5.QtCore import QSize, Qt
25from PyQt5.QtGui import (
26    QFont, QIcon, QFontMetrics, QGuiApplication, QPainter, QPaintEvent,
27)
28from PyQt5.QtWidgets import (QPushButton, QSizePolicy)
29
30from raphodo.rotatedpushbutton import FlatButton
31
32
33class TopPushButton(QPushButton, FlatButton):
34    def __init__(self, text, parent, extra_top: int=0) -> None:
35        """
36
37        :param text: text to display in the button
38        :param extra_top: extra spacing at the top of the widget
39        :param parent: parent widget
40        """
41
42        super().__init__(text, parent)
43        self.rapidApp = parent
44        self.setCheckable(True)
45        self.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
46
47        font = self.font()  # type: QFont
48        top_row_font_size = font.pointSize() + 8
49        self.top_row_icon_size = top_row_font_size + 10
50        font.setPointSize(top_row_font_size)
51        self.setFont(font)
52
53        font_height = QFontMetrics(font).height()
54        self.padding_side = math.ceil(font_height / 3.5)
55        padding_bottom = math.ceil(font_height / 5.6)
56        padding_top = padding_bottom + extra_top
57
58        self.non_elided_text = ''
59
60        padding = 'padding-left: {padding_side}px; padding-right: {padding_side}px; padding-top: ' \
61                  '{padding_top}px; padding-bottom: {padding_bottom}px;'.format(
62                    padding_top=padding_top, padding_side=self.padding_side,
63                    padding_bottom=padding_bottom
64        )
65        self.setFlatStyle(self, darker_if_checked=False, padding=padding)
66
67    def text(self) -> str:
68        return self.non_elided_text
69
70    def setText(self, text: str) -> None:
71        self.non_elided_text = text
72        self.update()
73
74    def setIcon(self, icon: QIcon) -> None:
75        super().setIcon(icon)
76        self.setIconSize(QSize(self.top_row_icon_size, self.top_row_icon_size))
77
78    def paintEvent(self, event: QPaintEvent):
79        """
80        Override default rendering to elide button text if it is bigger than half the window
81        size
82        """
83
84        painter = QPainter(self)
85        metrics = painter.fontMetrics()
86        right_element_widths = self.rapidApp.downloadButton.width() + self.rapidApp.menuButton.width()
87        window_width = self.rapidApp.width()
88        window_half  = window_width / 2
89        if right_element_widths > window_half:
90            maximum_width = window_width - right_element_widths
91        else:
92            maximum_width = window_half
93        maximum_width -= self.padding_side - self.top_row_icon_size
94
95        # account for situations where we might have negative values, i.e., display some
96        # text at least
97        maximum_width = max(30, maximum_width)
98
99        usable_width = round(0.9 * maximum_width)
100        elided_text = metrics.elidedText(self.non_elided_text, Qt.ElideMiddle, usable_width)
101        super().setText(elided_text)
102        super().paintEvent(event)
103
104
105class DownloadButton(QPushButton):
106    """
107    Button used to initiate downloads
108    """
109
110    def __init__(self, text: str, parent) -> None:
111        super().__init__(text, parent)
112
113        self.rapidApp = parent
114        self.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
115
116        font_height = QFontMetrics(self.font()).tightBoundingRect(
117            _('Download 8 Photos and 10 Videos')).height()
118        padding = math.ceil(font_height * 1.7)
119        height = font_height // 2 * 6
120        radius = height // 2
121
122        palette = QGuiApplication.palette()
123        primaryColor = palette.highlight().color()
124        borderColor = primaryColor.darker(105)
125        hoverColor = palette.highlight().color().darker(106)
126        hoverBorderColor = hoverColor.darker(105)
127        primaryTextColor = palette.highlightedText().color()
128
129        disabledColor = palette.window().color().darker(120)
130        disabledBorderColor = disabledColor.darker(105)
131        disabledTextColor = palette.highlightedText().color()
132
133        # outline:none is used to remove the rectangle that appears on a
134        # button when the button has focus
135        # http://stackoverflow.com/questions/17280056/qt-css-decoration-on-focus
136        self.setStyleSheet("""
137            QPushButton {
138            background-color: %(color)s;
139            outline: none;
140            padding-left: %(padding)dpx;
141            padding-right: %(padding)dpx;
142            border-radius: %(radius)dpx;
143            border: 1px solid %(borderColor)s;
144            height: %(height)dpx;
145            color: %(textcolor)s;
146            }
147            QPushButton:hover {
148            background-color: %(hoverColor)s;
149            border: 1px solid %(hoverBorderColor)s;
150            }
151            QPushButton:disabled {
152            background-color: %(disabledColor)s;
153            color: %(disabledTextColor)s;
154            border: 1px solid %(disabledBorderColor)s;
155            }
156            """ % dict(
157                color=primaryColor.name(),
158                padding=padding,
159                borderColor=borderColor.name(),
160                hoverColor=hoverColor.name(),
161                hoverBorderColor=hoverBorderColor.name(),
162                height=height,
163                radius=radius,
164                textcolor=primaryTextColor.name(),
165                disabledColor=disabledColor.name(),
166                disabledTextColor=disabledTextColor.name(),
167                disabledBorderColor=disabledBorderColor.name()
168            )
169        )
170
171    def setText(self, text: str) -> None:
172        super().setText(text)
173        self.rapidApp.sourceButton.updateGeometry()
174