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

0001 /*
0002     SPDX-FileCopyrightText: 2018 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "effect/timeline.h"
0008 
0009 namespace KWin
0010 {
0011 
0012 class Q_DECL_HIDDEN TimeLine::Data : public QSharedData
0013 {
0014 public:
0015     std::chrono::milliseconds duration;
0016     Direction direction;
0017     QEasingCurve easingCurve;
0018 
0019     std::chrono::milliseconds elapsed = std::chrono::milliseconds::zero();
0020     std::optional<std::chrono::milliseconds> lastTimestamp = std::nullopt;
0021     bool done = false;
0022     RedirectMode sourceRedirectMode = RedirectMode::Relaxed;
0023     RedirectMode targetRedirectMode = RedirectMode::Strict;
0024 };
0025 
0026 TimeLine::TimeLine(std::chrono::milliseconds duration, Direction direction)
0027     : d(new Data)
0028 {
0029     Q_ASSERT(duration > std::chrono::milliseconds::zero());
0030     d->duration = duration;
0031     d->direction = direction;
0032 }
0033 
0034 TimeLine::TimeLine(const TimeLine &other)
0035     : d(other.d)
0036 {
0037 }
0038 
0039 TimeLine::~TimeLine() = default;
0040 
0041 qreal TimeLine::progress() const
0042 {
0043     return static_cast<qreal>(d->elapsed.count()) / d->duration.count();
0044 }
0045 
0046 qreal TimeLine::value() const
0047 {
0048     const qreal t = progress();
0049     return d->easingCurve.valueForProgress(
0050         d->direction == Backward ? 1.0 - t : t);
0051 }
0052 
0053 void TimeLine::advance(std::chrono::milliseconds timestamp)
0054 {
0055     if (d->done) {
0056         return;
0057     }
0058 
0059     std::chrono::milliseconds delta = std::chrono::milliseconds::zero();
0060     if (d->lastTimestamp.has_value()) {
0061         delta = timestamp - d->lastTimestamp.value();
0062     }
0063 
0064     Q_ASSERT(delta >= std::chrono::milliseconds::zero());
0065     d->lastTimestamp = timestamp;
0066 
0067     d->elapsed += delta;
0068     if (d->elapsed >= d->duration) {
0069         d->elapsed = d->duration;
0070         d->done = true;
0071         d->lastTimestamp = std::nullopt;
0072     }
0073 }
0074 
0075 std::chrono::milliseconds TimeLine::elapsed() const
0076 {
0077     return d->elapsed;
0078 }
0079 
0080 void TimeLine::setElapsed(std::chrono::milliseconds elapsed)
0081 {
0082     Q_ASSERT(elapsed >= std::chrono::milliseconds::zero());
0083     if (elapsed == d->elapsed) {
0084         return;
0085     }
0086 
0087     reset();
0088 
0089     d->elapsed = elapsed;
0090 
0091     if (d->elapsed >= d->duration) {
0092         d->elapsed = d->duration;
0093         d->done = true;
0094         d->lastTimestamp = std::nullopt;
0095     }
0096 }
0097 
0098 std::chrono::milliseconds TimeLine::duration() const
0099 {
0100     return d->duration;
0101 }
0102 
0103 void TimeLine::setDuration(std::chrono::milliseconds duration)
0104 {
0105     Q_ASSERT(duration > std::chrono::milliseconds::zero());
0106     if (duration == d->duration) {
0107         return;
0108     }
0109     d->elapsed = std::chrono::milliseconds(qRound(progress() * duration.count()));
0110     d->duration = duration;
0111     if (d->elapsed == d->duration) {
0112         d->done = true;
0113         d->lastTimestamp = std::nullopt;
0114     }
0115 }
0116 
0117 TimeLine::Direction TimeLine::direction() const
0118 {
0119     return d->direction;
0120 }
0121 
0122 void TimeLine::setDirection(TimeLine::Direction direction)
0123 {
0124     if (d->direction == direction) {
0125         return;
0126     }
0127 
0128     d->direction = direction;
0129 
0130     if (d->elapsed > std::chrono::milliseconds::zero()
0131         || d->sourceRedirectMode == RedirectMode::Strict) {
0132         d->elapsed = d->duration - d->elapsed;
0133     }
0134 
0135     if (d->done && d->targetRedirectMode == RedirectMode::Relaxed) {
0136         d->done = false;
0137     }
0138 
0139     if (d->elapsed >= d->duration) {
0140         d->done = true;
0141         d->lastTimestamp = std::nullopt;
0142     }
0143 }
0144 
0145 void TimeLine::toggleDirection()
0146 {
0147     setDirection(d->direction == Forward ? Backward : Forward);
0148 }
0149 
0150 QEasingCurve TimeLine::easingCurve() const
0151 {
0152     return d->easingCurve;
0153 }
0154 
0155 void TimeLine::setEasingCurve(const QEasingCurve &easingCurve)
0156 {
0157     d->easingCurve = easingCurve;
0158 }
0159 
0160 void TimeLine::setEasingCurve(QEasingCurve::Type type)
0161 {
0162     d->easingCurve.setType(type);
0163 }
0164 
0165 bool TimeLine::running() const
0166 {
0167     return d->elapsed != std::chrono::milliseconds::zero()
0168         && d->elapsed != d->duration;
0169 }
0170 
0171 bool TimeLine::done() const
0172 {
0173     return d->done;
0174 }
0175 
0176 void TimeLine::reset()
0177 {
0178     d->lastTimestamp = std::nullopt;
0179     d->elapsed = std::chrono::milliseconds::zero();
0180     d->done = false;
0181 }
0182 
0183 TimeLine::RedirectMode TimeLine::sourceRedirectMode() const
0184 {
0185     return d->sourceRedirectMode;
0186 }
0187 
0188 void TimeLine::setSourceRedirectMode(RedirectMode mode)
0189 {
0190     d->sourceRedirectMode = mode;
0191 }
0192 
0193 TimeLine::RedirectMode TimeLine::targetRedirectMode() const
0194 {
0195     return d->targetRedirectMode;
0196 }
0197 
0198 void TimeLine::setTargetRedirectMode(RedirectMode mode)
0199 {
0200     d->targetRedirectMode = mode;
0201 }
0202 
0203 TimeLine &TimeLine::operator=(const TimeLine &other)
0204 {
0205     d = other.d;
0206     return *this;
0207 }
0208 
0209 } // namespace KWin