1#!/usr/local/bin/python3.8
2# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
3
4
5__license__   = 'GPL v3'
6__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
7__docformat__ = 'restructuredtext en'
8
9
10from qt.core import (
11    QToolButton, QSize, QPropertyAnimation, Qt, QMetaObject, pyqtProperty, QSizePolicy,
12    QWidget, QIcon, QPainter, QStyleOptionToolButton, QStyle, QAbstractAnimation)
13
14from calibre.gui2 import config
15
16
17class ThrobbingButton(QToolButton):
18
19    @pyqtProperty(int)
20    def icon_size(self):
21        return self._icon_size
22
23    @icon_size.setter
24    def icon_size(self, value):
25        self._icon_size = value
26
27    def __init__(self, *args):
28        QToolButton.__init__(self, *args)
29        # vertically size policy must be expanding for it to align inside a
30        # toolbar
31        self.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Expanding)
32        self._icon_size = -1
33        QToolButton.setIcon(self, QIcon(I('donate.png')))
34        self.setText('\xa0')
35        self.animation = QPropertyAnimation(self, b'icon_size', self)
36        self.animation.setDuration(int(60/72.*1000))
37        self.animation.setLoopCount(4)
38        self.animation.valueChanged.connect(self.value_changed)
39        self.setCursor(Qt.CursorShape.PointingHandCursor)
40        self.animation.finished.connect(self.animation_finished)
41
42    def animation_finished(self):
43        self.icon_size = self.iconSize().width()
44
45    def enterEvent(self, ev):
46        self.start_animation()
47
48    def leaveEvent(self, ev):
49        self.stop_animation()
50
51    def value_changed(self, val):
52        self.update()
53
54    def start_animation(self):
55        if config['disable_animations']:
56            return
57        if self.animation.state() != QAbstractAnimation.State.Stopped or not self.isVisible():
58            return
59        size = self.iconSize().width()
60        smaller = int(0.7 * size)
61        self.animation.setStartValue(smaller)
62        self.animation.setEndValue(size)
63        QMetaObject.invokeMethod(self.animation, 'start', Qt.ConnectionType.QueuedConnection)
64
65    def stop_animation(self):
66        self.animation.stop()
67        self.animation_finished()
68
69    def paintEvent(self, ev):
70        size = self._icon_size if self._icon_size > 10 else self.iconSize().width()
71        p = QPainter(self)
72        opt = QStyleOptionToolButton()
73        self.initStyleOption(opt)
74        s = self.style()
75        opt.iconSize = QSize(size, size)
76        s.drawComplexControl(QStyle.ComplexControl.CC_ToolButton, opt, p, self)
77
78
79if __name__ == '__main__':
80    from qt.core import QApplication, QHBoxLayout
81    app = QApplication([])
82    w = QWidget()
83    w.setLayout(QHBoxLayout())
84    b = ThrobbingButton()
85    b.setIcon(QIcon(I('donate.png')))
86    w.layout().addWidget(b)
87    w.show()
88    b.set_normal_icon_size(64, 64)
89    b.start_animation()
90
91    app.exec()
92