1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtWidgets module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qstyleanimation_p.h"
41 
42 #include <qcoreapplication.h>
43 #include <qwidget.h>
44 #include <qevent.h>
45 
46 QT_BEGIN_NAMESPACE
47 
48 static const qreal ScrollBarFadeOutDuration = 200.0;
49 static const qreal ScrollBarFadeOutDelay = 450.0;
50 
QStyleAnimation(QObject * target)51 QStyleAnimation::QStyleAnimation(QObject *target) : QAbstractAnimation(target),
52     _delay(0), _duration(-1), _startTime(QTime::currentTime()), _fps(ThirtyFps), _skip(0)
53 {
54 }
55 
~QStyleAnimation()56 QStyleAnimation::~QStyleAnimation()
57 {
58 }
59 
target() const60 QObject *QStyleAnimation::target() const
61 {
62     return parent();
63 }
64 
duration() const65 int QStyleAnimation::duration() const
66 {
67     return _duration;
68 }
69 
setDuration(int duration)70 void QStyleAnimation::setDuration(int duration)
71 {
72     _duration = duration;
73 }
74 
delay() const75 int QStyleAnimation::delay() const
76 {
77     return _delay;
78 }
79 
setDelay(int delay)80 void QStyleAnimation::setDelay(int delay)
81 {
82     _delay = delay;
83 }
84 
startTime() const85 QTime QStyleAnimation::startTime() const
86 {
87     return _startTime;
88 }
89 
setStartTime(const QTime & time)90 void QStyleAnimation::setStartTime(const QTime &time)
91 {
92     _startTime = time;
93 }
94 
frameRate() const95 QStyleAnimation::FrameRate QStyleAnimation::frameRate() const
96 {
97     return _fps;
98 }
99 
setFrameRate(FrameRate fps)100 void QStyleAnimation::setFrameRate(FrameRate fps)
101 {
102     _fps = fps;
103 }
104 
updateTarget()105 void QStyleAnimation::updateTarget()
106 {
107     QEvent event(QEvent::StyleAnimationUpdate);
108     event.setAccepted(false);
109     QCoreApplication::sendEvent(target(), &event);
110     if (!event.isAccepted())
111         stop();
112 }
113 
start()114 void QStyleAnimation::start()
115 {
116     _skip = 0;
117     QAbstractAnimation::start(DeleteWhenStopped);
118 }
119 
isUpdateNeeded() const120 bool QStyleAnimation::isUpdateNeeded() const
121 {
122     return currentTime() > _delay;
123 }
124 
updateCurrentTime(int time)125 void QStyleAnimation::updateCurrentTime(int time)
126 {
127     if (++_skip >= _fps || time >= duration()) {
128         _skip = 0;
129         if (target() && isUpdateNeeded())
130             updateTarget();
131     }
132 }
133 
QProgressStyleAnimation(int speed,QObject * target)134 QProgressStyleAnimation::QProgressStyleAnimation(int speed, QObject *target) :
135     QStyleAnimation(target), _speed(speed), _step(-1)
136 {
137 }
138 
animationStep() const139 int QProgressStyleAnimation::animationStep() const
140 {
141     return currentTime() / (1000.0 / _speed);
142 }
143 
progressStep(int width) const144 int QProgressStyleAnimation::progressStep(int width) const
145 {
146     int step = animationStep();
147     int progress = (step * width / _speed) % width;
148     if (((step * width / _speed) % (2 * width)) >= width)
149         progress = width - progress;
150     return progress;
151 }
152 
speed() const153 int QProgressStyleAnimation::speed() const
154 {
155     return _speed;
156 }
157 
setSpeed(int speed)158 void QProgressStyleAnimation::setSpeed(int speed)
159 {
160     _speed = speed;
161 }
162 
isUpdateNeeded() const163 bool QProgressStyleAnimation::isUpdateNeeded() const
164 {
165     if (QStyleAnimation::isUpdateNeeded()) {
166         int current = animationStep();
167         if (_step == -1 || _step != current)
168         {
169             _step = current;
170             return true;
171         }
172     }
173     return false;
174 }
175 
QNumberStyleAnimation(QObject * target)176 QNumberStyleAnimation::QNumberStyleAnimation(QObject *target) :
177     QStyleAnimation(target), _start(0.0), _end(1.0), _prev(0.0)
178 {
179     setDuration(250);
180 }
181 
startValue() const182 qreal QNumberStyleAnimation::startValue() const
183 {
184     return _start;
185 }
186 
setStartValue(qreal value)187 void QNumberStyleAnimation::setStartValue(qreal value)
188 {
189     _start = value;
190 }
191 
endValue() const192 qreal QNumberStyleAnimation::endValue() const
193 {
194     return _end;
195 }
196 
setEndValue(qreal value)197 void QNumberStyleAnimation::setEndValue(qreal value)
198 {
199     _end = value;
200 }
201 
currentValue() const202 qreal QNumberStyleAnimation::currentValue() const
203 {
204     qreal step = qreal(currentTime() - delay()) / (duration() - delay());
205     return _start + qMax(qreal(0), step) * (_end - _start);
206 }
207 
isUpdateNeeded() const208 bool QNumberStyleAnimation::isUpdateNeeded() const
209 {
210     if (QStyleAnimation::isUpdateNeeded()) {
211         qreal current = currentValue();
212         if (!qFuzzyCompare(_prev, current))
213         {
214             _prev = current;
215             return true;
216         }
217     }
218     return false;
219 }
220 
QBlendStyleAnimation(Type type,QObject * target)221 QBlendStyleAnimation::QBlendStyleAnimation(Type type, QObject *target) :
222     QStyleAnimation(target), _type(type)
223 {
224     setDuration(250);
225 }
226 
startImage() const227 QImage QBlendStyleAnimation::startImage() const
228 {
229     return _start;
230 }
231 
setStartImage(const QImage & image)232 void QBlendStyleAnimation::setStartImage(const QImage& image)
233 {
234     _start = image;
235 }
236 
endImage() const237 QImage QBlendStyleAnimation::endImage() const
238 {
239     return _end;
240 }
241 
setEndImage(const QImage & image)242 void QBlendStyleAnimation::setEndImage(const QImage& image)
243 {
244     _end = image;
245 }
246 
currentImage() const247 QImage QBlendStyleAnimation::currentImage() const
248 {
249     return _current;
250 }
251 
252 /*! \internal
253 
254     A helper function to blend two images.
255 
256     The result consists of ((alpha)*startImage) + ((1-alpha)*endImage)
257 
258 */
blendedImage(const QImage & start,const QImage & end,float alpha)259 static QImage blendedImage(const QImage &start, const QImage &end, float alpha)
260 {
261     if (start.isNull() || end.isNull())
262         return QImage();
263 
264     QImage blended;
265     const int a = qRound(alpha*256);
266     const int ia = 256 - a;
267     const int sw = start.width();
268     const int sh = start.height();
269     const int bpl = start.bytesPerLine();
270     switch (start.depth()) {
271     case 32:
272         {
273             blended = QImage(sw, sh, start.format());
274             blended.setDevicePixelRatio(start.devicePixelRatio());
275             uchar *mixed_data = blended.bits();
276             const uchar *back_data = start.bits();
277             const uchar *front_data = end.bits();
278             for (int sy = 0; sy < sh; sy++) {
279                 quint32* mixed = (quint32*)mixed_data;
280                 const quint32* back = (const quint32*)back_data;
281                 const quint32* front = (const quint32*)front_data;
282                 for (int sx = 0; sx < sw; sx++) {
283                     quint32 bp = back[sx];
284                     quint32 fp = front[sx];
285                     mixed[sx] =  qRgba ((qRed(bp)*ia + qRed(fp)*a)>>8,
286                                         (qGreen(bp)*ia + qGreen(fp)*a)>>8,
287                                         (qBlue(bp)*ia + qBlue(fp)*a)>>8,
288                                         (qAlpha(bp)*ia + qAlpha(fp)*a)>>8);
289                 }
290                 mixed_data += bpl;
291                 back_data += bpl;
292                 front_data += bpl;
293             }
294         }
295     default:
296         break;
297     }
298     return blended;
299 }
300 
updateCurrentTime(int time)301 void QBlendStyleAnimation::updateCurrentTime(int time)
302 {
303     QStyleAnimation::updateCurrentTime(time);
304 
305     float alpha = 1.0;
306     if (duration() > 0) {
307         if (_type == Pulse) {
308             time = time % duration() * 2;
309             if (time > duration())
310                 time = duration() * 2 - time;
311         }
312 
313         alpha = time / static_cast<float>(duration());
314 
315         if (_type == Transition && time > duration()) {
316             alpha = 1.0;
317             stop();
318         }
319     } else if (time > 0) {
320         stop();
321     }
322 
323     _current = blendedImage(_start, _end, alpha);
324 }
325 
QScrollbarStyleAnimation(Mode mode,QObject * target)326 QScrollbarStyleAnimation::QScrollbarStyleAnimation(Mode mode, QObject *target) : QNumberStyleAnimation(target), _mode(mode), _active(false)
327 {
328     switch (mode) {
329     case Activating:
330         setDuration(ScrollBarFadeOutDuration);
331         setStartValue(0.0);
332         setEndValue(1.0);
333         break;
334     case Deactivating:
335         setDuration(ScrollBarFadeOutDelay + ScrollBarFadeOutDuration);
336         setDelay(ScrollBarFadeOutDelay);
337         setStartValue(1.0);
338         setEndValue(0.0);
339         break;
340     }
341 }
342 
mode() const343 QScrollbarStyleAnimation::Mode QScrollbarStyleAnimation::mode() const
344 {
345     return _mode;
346 }
347 
wasActive() const348 bool QScrollbarStyleAnimation::wasActive() const
349 {
350     return _active;
351 }
352 
setActive(bool active)353 void QScrollbarStyleAnimation::setActive(bool active)
354 {
355     _active = active;
356 }
357 
updateCurrentTime(int time)358 void QScrollbarStyleAnimation::updateCurrentTime(int time)
359 {
360     QNumberStyleAnimation::updateCurrentTime(time);
361     if (_mode == Deactivating && qFuzzyIsNull(currentValue()))
362         target()->setProperty("visible", false);
363 }
364 
365 QT_END_NAMESPACE
366 
367 #include "moc_qstyleanimation_p.cpp"
368