/**************************************************************************** ** ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWidgets module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qstyleanimation_p.h" #include #include #include QT_BEGIN_NAMESPACE static const qreal ScrollBarFadeOutDuration = 200.0; static const qreal ScrollBarFadeOutDelay = 450.0; QStyleAnimation::QStyleAnimation(QObject *target) : QAbstractAnimation(target), _delay(0), _duration(-1), _startTime(QTime::currentTime()), _fps(ThirtyFps), _skip(0) { } QStyleAnimation::~QStyleAnimation() { } QObject *QStyleAnimation::target() const { return parent(); } int QStyleAnimation::duration() const { return _duration; } void QStyleAnimation::setDuration(int duration) { _duration = duration; } int QStyleAnimation::delay() const { return _delay; } void QStyleAnimation::setDelay(int delay) { _delay = delay; } QTime QStyleAnimation::startTime() const { return _startTime; } void QStyleAnimation::setStartTime(QTime time) { _startTime = time; } QStyleAnimation::FrameRate QStyleAnimation::frameRate() const { return _fps; } void QStyleAnimation::setFrameRate(FrameRate fps) { _fps = fps; } void QStyleAnimation::updateTarget() { QEvent event(QEvent::StyleAnimationUpdate); event.setAccepted(false); QCoreApplication::sendEvent(target(), &event); if (!event.isAccepted()) stop(); } void QStyleAnimation::start() { _skip = 0; QAbstractAnimation::start(DeleteWhenStopped); } bool QStyleAnimation::isUpdateNeeded() const { return currentTime() > _delay; } void QStyleAnimation::updateCurrentTime(int time) { if (++_skip >= _fps || time >= duration()) { _skip = 0; if (target() && isUpdateNeeded()) updateTarget(); } } QProgressStyleAnimation::QProgressStyleAnimation(int speed, QObject *target) : QStyleAnimation(target), _speed(speed), _step(-1) { } int QProgressStyleAnimation::animationStep() const { return currentTime() / (1000.0 / _speed); } int QProgressStyleAnimation::progressStep(int width) const { int step = animationStep(); int progress = (step * width / _speed) % width; if (((step * width / _speed) % (2 * width)) >= width) progress = width - progress; return progress; } int QProgressStyleAnimation::speed() const { return _speed; } void QProgressStyleAnimation::setSpeed(int speed) { _speed = speed; } bool QProgressStyleAnimation::isUpdateNeeded() const { if (QStyleAnimation::isUpdateNeeded()) { int current = animationStep(); if (_step == -1 || _step != current) { _step = current; return true; } } return false; } QNumberStyleAnimation::QNumberStyleAnimation(QObject *target) : QStyleAnimation(target), _start(0.0), _end(1.0), _prev(0.0) { setDuration(250); } qreal QNumberStyleAnimation::startValue() const { return _start; } void QNumberStyleAnimation::setStartValue(qreal value) { _start = value; } qreal QNumberStyleAnimation::endValue() const { return _end; } void QNumberStyleAnimation::setEndValue(qreal value) { _end = value; } qreal QNumberStyleAnimation::currentValue() const { qreal step = qreal(currentTime() - delay()) / (duration() - delay()); return _start + qMax(qreal(0), step) * (_end - _start); } bool QNumberStyleAnimation::isUpdateNeeded() const { if (QStyleAnimation::isUpdateNeeded()) { qreal current = currentValue(); if (!qFuzzyCompare(_prev, current)) { _prev = current; return true; } } return false; } QBlendStyleAnimation::QBlendStyleAnimation(Type type, QObject *target) : QStyleAnimation(target), _type(type) { setDuration(250); } QImage QBlendStyleAnimation::startImage() const { return _start; } void QBlendStyleAnimation::setStartImage(const QImage& image) { _start = image; } QImage QBlendStyleAnimation::endImage() const { return _end; } void QBlendStyleAnimation::setEndImage(const QImage& image) { _end = image; } QImage QBlendStyleAnimation::currentImage() const { return _current; } /*! \internal A helper function to blend two images. The result consists of ((alpha)*startImage) + ((1-alpha)*endImage) */ static QImage blendedImage(const QImage &start, const QImage &end, float alpha) { if (start.isNull() || end.isNull()) return QImage(); QImage blended; const int a = qRound(alpha*256); const int ia = 256 - a; const int sw = start.width(); const int sh = start.height(); const qsizetype bpl = start.bytesPerLine(); switch (start.depth()) { case 32: { blended = QImage(sw, sh, start.format()); blended.setDevicePixelRatio(start.devicePixelRatio()); uchar *mixed_data = blended.bits(); const uchar *back_data = start.bits(); const uchar *front_data = end.bits(); for (int sy = 0; sy < sh; sy++) { quint32* mixed = (quint32*)mixed_data; const quint32* back = (const quint32*)back_data; const quint32* front = (const quint32*)front_data; for (int sx = 0; sx < sw; sx++) { quint32 bp = back[sx]; quint32 fp = front[sx]; mixed[sx] = qRgba ((qRed(bp)*ia + qRed(fp)*a)>>8, (qGreen(bp)*ia + qGreen(fp)*a)>>8, (qBlue(bp)*ia + qBlue(fp)*a)>>8, (qAlpha(bp)*ia + qAlpha(fp)*a)>>8); } mixed_data += bpl; back_data += bpl; front_data += bpl; } } default: break; } return blended; } void QBlendStyleAnimation::updateCurrentTime(int time) { QStyleAnimation::updateCurrentTime(time); float alpha = 1.0; if (duration() > 0) { if (_type == Pulse) { time = time % duration() * 2; if (time > duration()) time = duration() * 2 - time; } alpha = time / static_cast(duration()); if (_type == Transition && time > duration()) { alpha = 1.0; stop(); } } else if (time > 0) { stop(); } _current = blendedImage(_start, _end, alpha); } QScrollbarStyleAnimation::QScrollbarStyleAnimation(Mode mode, QObject *target) : QNumberStyleAnimation(target), _mode(mode), _active(false) { switch (mode) { case Activating: setDuration(ScrollBarFadeOutDuration); setStartValue(0.0); setEndValue(1.0); break; case Deactivating: setDuration(ScrollBarFadeOutDelay + ScrollBarFadeOutDuration); setDelay(ScrollBarFadeOutDelay); setStartValue(1.0); setEndValue(0.0); break; } } QScrollbarStyleAnimation::Mode QScrollbarStyleAnimation::mode() const { return _mode; } bool QScrollbarStyleAnimation::wasActive() const { return _active; } void QScrollbarStyleAnimation::setActive(bool active) { _active = active; } void QScrollbarStyleAnimation::updateCurrentTime(int time) { QNumberStyleAnimation::updateCurrentTime(time); if (_mode == Deactivating && qFuzzyIsNull(currentValue())) target()->setProperty("visible", false); } QT_END_NAMESPACE #include "moc_qstyleanimation_p.cpp"