File indexing completed on 2024-05-12 05:47:31

0001 /*
0002  * SPDX-FileCopyrightText: 2011 Peter Penz <peter.penz19@gmail.com>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kitemlistviewanimation.h"
0008 #include "kitemviews/kitemlistview.h"
0009 
0010 #include <QPropertyAnimation>
0011 
0012 KItemListViewAnimation::KItemListViewAnimation(QObject *parent)
0013     : QObject(parent)
0014     , m_scrollOrientation(Qt::Vertical)
0015     , m_scrollOffset(0)
0016     , m_animation()
0017 {
0018 }
0019 
0020 KItemListViewAnimation::~KItemListViewAnimation()
0021 {
0022     for (int type = 0; type < AnimationTypeCount; ++type) {
0023         qDeleteAll(m_animation[type]);
0024     }
0025 }
0026 
0027 void KItemListViewAnimation::setScrollOrientation(Qt::Orientation orientation)
0028 {
0029     m_scrollOrientation = orientation;
0030 }
0031 
0032 Qt::Orientation KItemListViewAnimation::scrollOrientation() const
0033 {
0034     return m_scrollOrientation;
0035 }
0036 
0037 void KItemListViewAnimation::setScrollOffset(qreal offset)
0038 {
0039     const qreal diff = m_scrollOffset - offset;
0040     m_scrollOffset = offset;
0041 
0042     // The change of the offset requires that the position of all
0043     // animated QGraphicsWidgets get adjusted. An exception is made
0044     // for the delete animation that should just fade away on the
0045     // existing position.
0046     for (int type = 0; type < AnimationTypeCount; ++type) {
0047         if (type == DeleteAnimation) {
0048             continue;
0049         }
0050 
0051         QHashIterator<QGraphicsWidget *, QPropertyAnimation *> it(m_animation[type]);
0052         while (it.hasNext()) {
0053             it.next();
0054 
0055             QGraphicsWidget *widget = it.key();
0056             QPropertyAnimation *propertyAnim = it.value();
0057 
0058             QPointF currentPos = widget->pos();
0059             if (m_scrollOrientation == Qt::Vertical) {
0060                 currentPos.ry() += diff;
0061             } else {
0062                 currentPos.rx() += diff;
0063             }
0064 
0065             if (type == MovingAnimation) {
0066                 // Stop the animation, calculate the moved start- and end-value
0067                 // and restart the animation for the remaining duration.
0068                 const int remainingDuration = propertyAnim->duration() - propertyAnim->currentTime();
0069 
0070                 const bool block = propertyAnim->signalsBlocked();
0071                 propertyAnim->blockSignals(true);
0072                 propertyAnim->stop();
0073 
0074                 QPointF endPos = propertyAnim->endValue().toPointF();
0075                 if (m_scrollOrientation == Qt::Vertical) {
0076                     endPos.ry() += diff;
0077                 } else {
0078                     endPos.rx() += diff;
0079                 }
0080 
0081                 propertyAnim->setDuration(remainingDuration);
0082                 propertyAnim->setStartValue(currentPos);
0083                 propertyAnim->setEndValue(endPos);
0084                 propertyAnim->start();
0085                 propertyAnim->blockSignals(block);
0086             } else {
0087                 widget->setPos(currentPos);
0088             }
0089         }
0090     }
0091 }
0092 
0093 qreal KItemListViewAnimation::scrollOffset() const
0094 {
0095     return m_scrollOffset;
0096 }
0097 
0098 void KItemListViewAnimation::start(QGraphicsWidget *widget, AnimationType type, const QVariant &endValue)
0099 {
0100     stop(widget, type);
0101 
0102     QPropertyAnimation *propertyAnim = nullptr;
0103     const int animationDuration = widget->style()->styleHint(QStyle::SH_Widget_Animate) ? 200 : 1;
0104 
0105     switch (type) {
0106     case MovingAnimation: {
0107         const QPointF newPos = endValue.toPointF();
0108         if (newPos == widget->pos()) {
0109             return;
0110         }
0111 
0112         propertyAnim = new QPropertyAnimation(widget, "pos");
0113         propertyAnim->setDuration(animationDuration);
0114         propertyAnim->setEndValue(newPos);
0115         break;
0116     }
0117 
0118     case CreateAnimation: {
0119         propertyAnim = new QPropertyAnimation(widget, "opacity");
0120         propertyAnim->setEasingCurve(QEasingCurve::InQuart);
0121         propertyAnim->setDuration(animationDuration);
0122         propertyAnim->setStartValue(0.0);
0123         propertyAnim->setEndValue(1.0);
0124         break;
0125     }
0126 
0127     case DeleteAnimation: {
0128         propertyAnim = new QPropertyAnimation(widget, "opacity");
0129         propertyAnim->setEasingCurve(QEasingCurve::OutQuart);
0130         propertyAnim->setDuration(animationDuration);
0131         propertyAnim->setStartValue(1.0);
0132         propertyAnim->setEndValue(0.0);
0133         break;
0134     }
0135 
0136     case ResizeAnimation: {
0137         const QSizeF newSize = endValue.toSizeF();
0138         if (newSize == widget->size()) {
0139             return;
0140         }
0141 
0142         propertyAnim = new QPropertyAnimation(widget, "size");
0143         propertyAnim->setDuration(animationDuration);
0144         propertyAnim->setEndValue(newSize);
0145         break;
0146     }
0147 
0148     case IconResizeAnimation: {
0149         propertyAnim = new QPropertyAnimation(widget, QByteArrayLiteral("iconSize"));
0150         propertyAnim->setDuration(animationDuration);
0151         propertyAnim->setEndValue(endValue);
0152         break;
0153     }
0154 
0155     default:
0156         Q_UNREACHABLE();
0157         break;
0158     }
0159 
0160     Q_ASSERT(propertyAnim);
0161     connect(propertyAnim, &QPropertyAnimation::finished, this, &KItemListViewAnimation::slotFinished);
0162     m_animation[type].insert(widget, propertyAnim);
0163 
0164     propertyAnim->start();
0165 }
0166 
0167 void KItemListViewAnimation::stop(QGraphicsWidget *widget, AnimationType type)
0168 {
0169     QPropertyAnimation *propertyAnim = m_animation[type].value(widget);
0170     if (propertyAnim) {
0171         propertyAnim->stop();
0172 
0173         switch (type) {
0174         case MovingAnimation:
0175             break;
0176         case CreateAnimation:
0177             widget->setOpacity(1.0);
0178             break;
0179         case DeleteAnimation:
0180             widget->setOpacity(0.0);
0181             break;
0182         case ResizeAnimation:
0183             break;
0184         default:
0185             break;
0186         }
0187 
0188         m_animation[type].remove(widget);
0189         delete propertyAnim;
0190 
0191         Q_EMIT finished(widget, type);
0192     }
0193 }
0194 
0195 void KItemListViewAnimation::stop(QGraphicsWidget *widget)
0196 {
0197     for (int type = 0; type < AnimationTypeCount; ++type) {
0198         stop(widget, static_cast<AnimationType>(type));
0199     }
0200 }
0201 
0202 bool KItemListViewAnimation::isStarted(QGraphicsWidget *widget, AnimationType type) const
0203 {
0204     return m_animation[type].value(widget);
0205 }
0206 
0207 bool KItemListViewAnimation::isStarted(QGraphicsWidget *widget) const
0208 {
0209     for (int type = 0; type < AnimationTypeCount; ++type) {
0210         if (isStarted(widget, static_cast<AnimationType>(type))) {
0211             return true;
0212         }
0213     }
0214     return false;
0215 }
0216 
0217 void KItemListViewAnimation::slotFinished()
0218 {
0219     QPropertyAnimation *finishedAnim = qobject_cast<QPropertyAnimation *>(sender());
0220     for (int type = 0; type < AnimationTypeCount; ++type) {
0221         QMutableHashIterator<QGraphicsWidget *, QPropertyAnimation *> it(m_animation[type]);
0222         while (it.hasNext()) {
0223             it.next();
0224             QPropertyAnimation *propertyAnim = it.value();
0225             if (propertyAnim == finishedAnim) {
0226                 QGraphicsWidget *widget = it.key();
0227                 it.remove();
0228                 finishedAnim->deleteLater();
0229 
0230                 Q_EMIT finished(widget, static_cast<AnimationType>(type));
0231                 return;
0232             }
0233         }
0234     }
0235     Q_ASSERT(false);
0236 }
0237 
0238 #include "moc_kitemlistviewanimation.cpp"