aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVlad Zagorodniy <[email protected]>2018-10-24 12:11:17 +0300
committerVlad Zagorodniy <[email protected]>2018-11-17 13:43:39 +0200
commite02573263f72c43731203929912fbe5569f174b2 (patch)
tree836cd79afaacc9e2ed9c6b7765fcca50393a448e
parentaa58a8c4ddcf663ff5f769ae618ff181ac3c39d3 (diff)
[libkwineffects] Introduce timeline redirect modes
Summary: The redirect modes control behavior of the timeline when its direction is changed at the start or target position. For example, consider the following piece of code: TimeLine timeLine(1000ms, TimeLine::Forward); timeLine.setDirection(TimeLine::Backward); What should happen when the direction of the timeline was changed to go backward? Should the current value of the timeline go from 1 to 0, or should the timeline stop its "execution"? In the relaxed mode, the timeline will go from 1 to 0. In the strict mode, the timeline will stop its execution. Different effects may prefer different modes for source and target positions. For example, most C++ effect would prefer relaxed mode for source position, and strict mode for target position. On the other side, scripted effects(AnimationEffect) would prefer strict mode for source position, and relaxed mode for target position(because of set). Reviewers: #kwin, graesslin Reviewed By: #kwin, graesslin Subscribers: kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D16447
-rw-r--r--autotests/libkwineffects/timelinetest.cpp158
-rw-r--r--libkwineffects/kwineffects.cpp37
-rw-r--r--libkwineffects/kwineffects.h60
3 files changed, 253 insertions, 2 deletions
diff --git a/autotests/libkwineffects/timelinetest.cpp b/autotests/libkwineffects/timelinetest.cpp
index 8483562..8ab426b 100644
--- a/autotests/libkwineffects/timelinetest.cpp
+++ b/autotests/libkwineffects/timelinetest.cpp
@@ -43,6 +43,14 @@ private Q_SLOTS:
void testSetDurationRetargeting();
void testSetDurationRetargetingSmallDuration();
void testRunning();
+ void testStrictRedirectSourceMode_data();
+ void testStrictRedirectSourceMode();
+ void testRelaxedRedirectSourceMode_data();
+ void testRelaxedRedirectSourceMode();
+ void testStrictRedirectTargetMode_data();
+ void testStrictRedirectTargetMode();
+ void testRelaxedRedirectTargetMode_data();
+ void testRelaxedRedirectTargetMode();
};
void TimeLineTest::testUpdateForward()
@@ -251,6 +259,156 @@ void TimeLineTest::testRunning()
QVERIFY(timeLine.done());
}
+void TimeLineTest::testStrictRedirectSourceMode_data()
+{
+ QTest::addColumn<KWin::TimeLine::Direction>("initialDirection");
+ QTest::addColumn<qreal>("initialValue");
+ QTest::addColumn<KWin::TimeLine::Direction>("finalDirection");
+ QTest::addColumn<qreal>("finalValue");
+
+ QTest::newRow("forward -> backward") << KWin::TimeLine::Forward << 0.0 << KWin::TimeLine::Backward << 0.0;
+ QTest::newRow("backward -> forward") << KWin::TimeLine::Backward << 1.0 << KWin::TimeLine::Forward << 1.0;
+}
+
+void TimeLineTest::testStrictRedirectSourceMode()
+{
+ QFETCH(KWin::TimeLine::Direction, initialDirection);
+ KWin::TimeLine timeLine(1000ms, initialDirection);
+ timeLine.setEasingCurve(QEasingCurve::Linear);
+ timeLine.setSourceRedirectMode(KWin::TimeLine::RedirectMode::Strict);
+
+ QTEST(timeLine.direction(), "initialDirection");
+ QTEST(timeLine.value(), "initialValue");
+ QCOMPARE(timeLine.sourceRedirectMode(), KWin::TimeLine::RedirectMode::Strict);
+ QVERIFY(!timeLine.running());
+ QVERIFY(!timeLine.done());
+
+ QFETCH(KWin::TimeLine::Direction, finalDirection);
+ timeLine.setDirection(finalDirection);
+
+ QTEST(timeLine.direction(), "finalDirection");
+ QTEST(timeLine.value(), "finalValue");
+ QCOMPARE(timeLine.sourceRedirectMode(), KWin::TimeLine::RedirectMode::Strict);
+ QVERIFY(!timeLine.running());
+ QVERIFY(timeLine.done());
+}
+
+void TimeLineTest::testRelaxedRedirectSourceMode_data()
+{
+ QTest::addColumn<KWin::TimeLine::Direction>("initialDirection");
+ QTest::addColumn<qreal>("initialValue");
+ QTest::addColumn<KWin::TimeLine::Direction>("finalDirection");
+ QTest::addColumn<qreal>("finalValue");
+
+ QTest::newRow("forward -> backward") << KWin::TimeLine::Forward << 0.0 << KWin::TimeLine::Backward << 1.0;
+ QTest::newRow("backward -> forward") << KWin::TimeLine::Backward << 1.0 << KWin::TimeLine::Forward << 0.0;
+}
+
+void TimeLineTest::testRelaxedRedirectSourceMode()
+{
+ QFETCH(KWin::TimeLine::Direction, initialDirection);
+ KWin::TimeLine timeLine(1000ms, initialDirection);
+ timeLine.setEasingCurve(QEasingCurve::Linear);
+ timeLine.setSourceRedirectMode(KWin::TimeLine::RedirectMode::Relaxed);
+
+ QTEST(timeLine.direction(), "initialDirection");
+ QTEST(timeLine.value(), "initialValue");
+ QCOMPARE(timeLine.sourceRedirectMode(), KWin::TimeLine::RedirectMode::Relaxed);
+ QVERIFY(!timeLine.running());
+ QVERIFY(!timeLine.done());
+
+ QFETCH(KWin::TimeLine::Direction, finalDirection);
+ timeLine.setDirection(finalDirection);
+
+ QTEST(timeLine.direction(), "finalDirection");
+ QTEST(timeLine.value(), "finalValue");
+ QCOMPARE(timeLine.sourceRedirectMode(), KWin::TimeLine::RedirectMode::Relaxed);
+ QVERIFY(!timeLine.running());
+ QVERIFY(!timeLine.done());
+}
+
+void TimeLineTest::testStrictRedirectTargetMode_data()
+{
+ QTest::addColumn<KWin::TimeLine::Direction>("initialDirection");
+ QTest::addColumn<qreal>("initialValue");
+ QTest::addColumn<KWin::TimeLine::Direction>("finalDirection");
+ QTest::addColumn<qreal>("finalValue");
+
+ QTest::newRow("forward -> backward") << KWin::TimeLine::Forward << 0.0 << KWin::TimeLine::Backward << 1.0;
+ QTest::newRow("backward -> forward") << KWin::TimeLine::Backward << 1.0 << KWin::TimeLine::Forward << 0.0;
+}
+
+void TimeLineTest::testStrictRedirectTargetMode()
+{
+ QFETCH(KWin::TimeLine::Direction, initialDirection);
+ KWin::TimeLine timeLine(1000ms, initialDirection);
+ timeLine.setEasingCurve(QEasingCurve::Linear);
+ timeLine.setTargetRedirectMode(KWin::TimeLine::RedirectMode::Strict);
+
+ QTEST(timeLine.direction(), "initialDirection");
+ QTEST(timeLine.value(), "initialValue");
+ QCOMPARE(timeLine.targetRedirectMode(), KWin::TimeLine::RedirectMode::Strict);
+ QVERIFY(!timeLine.running());
+ QVERIFY(!timeLine.done());
+
+ timeLine.update(1000ms);
+ QTEST(timeLine.value(), "finalValue");
+ QVERIFY(!timeLine.running());
+ QVERIFY(timeLine.done());
+
+ QFETCH(KWin::TimeLine::Direction, finalDirection);
+ timeLine.setDirection(finalDirection);
+
+ QTEST(timeLine.direction(), "finalDirection");
+ QTEST(timeLine.value(), "finalValue");
+ QVERIFY(!timeLine.running());
+ QVERIFY(timeLine.done());
+}
+
+void TimeLineTest::testRelaxedRedirectTargetMode_data()
+{
+ QTest::addColumn<KWin::TimeLine::Direction>("initialDirection");
+ QTest::addColumn<qreal>("initialValue");
+ QTest::addColumn<KWin::TimeLine::Direction>("finalDirection");
+ QTest::addColumn<qreal>("finalValue");
+
+ QTest::newRow("forward -> backward") << KWin::TimeLine::Forward << 0.0 << KWin::TimeLine::Backward << 1.0;
+ QTest::newRow("backward -> forward") << KWin::TimeLine::Backward << 1.0 << KWin::TimeLine::Forward << 0.0;
+}
+
+void TimeLineTest::testRelaxedRedirectTargetMode()
+{
+ QFETCH(KWin::TimeLine::Direction, initialDirection);
+ KWin::TimeLine timeLine(1000ms, initialDirection);
+ timeLine.setEasingCurve(QEasingCurve::Linear);
+ timeLine.setTargetRedirectMode(KWin::TimeLine::RedirectMode::Relaxed);
+
+ QTEST(timeLine.direction(), "initialDirection");
+ QTEST(timeLine.value(), "initialValue");
+ QCOMPARE(timeLine.targetRedirectMode(), KWin::TimeLine::RedirectMode::Relaxed);
+ QVERIFY(!timeLine.running());
+ QVERIFY(!timeLine.done());
+
+ timeLine.update(1000ms);
+ QTEST(timeLine.value(), "finalValue");
+ QVERIFY(!timeLine.running());
+ QVERIFY(timeLine.done());
+
+ QFETCH(KWin::TimeLine::Direction, finalDirection);
+ timeLine.setDirection(finalDirection);
+
+ QTEST(timeLine.direction(), "finalDirection");
+ QTEST(timeLine.value(), "finalValue");
+ QVERIFY(!timeLine.running());
+ QVERIFY(!timeLine.done());
+
+ timeLine.update(1000ms);
+ QTEST(timeLine.direction(), "finalDirection");
+ QTEST(timeLine.value(), "initialValue");
+ QVERIFY(!timeLine.running());
+ QVERIFY(timeLine.done());
+}
+
QTEST_MAIN(TimeLineTest)
#include "timelinetest.moc"
diff --git a/libkwineffects/kwineffects.cpp b/libkwineffects/kwineffects.cpp
index 1e43281..5ddce91 100644
--- a/libkwineffects/kwineffects.cpp
+++ b/libkwineffects/kwineffects.cpp
@@ -1953,6 +1953,8 @@ public:
std::chrono::milliseconds elapsed = std::chrono::milliseconds::zero();
bool done = false;
+ RedirectMode sourceRedirectMode = RedirectMode::Relaxed;
+ RedirectMode targetRedirectMode = RedirectMode::Strict;
};
TimeLine::TimeLine(std::chrono::milliseconds duration, Direction direction)
@@ -2038,10 +2040,21 @@ void TimeLine::setDirection(TimeLine::Direction direction)
if (d->direction == direction) {
return;
}
- if (d->elapsed > std::chrono::milliseconds::zero()) {
+
+ d->direction = direction;
+
+ if (d->elapsed > std::chrono::milliseconds::zero()
+ || d->sourceRedirectMode == RedirectMode::Strict) {
d->elapsed = d->duration - d->elapsed;
}
- d->direction = direction;
+
+ if (d->done && d->targetRedirectMode == RedirectMode::Relaxed) {
+ d->done = false;
+ }
+
+ if (d->elapsed >= d->duration) {
+ d->done = true;
+ }
}
void TimeLine::toggleDirection()
@@ -2081,6 +2094,26 @@ void TimeLine::reset()
d->done = false;
}
+TimeLine::RedirectMode TimeLine::sourceRedirectMode() const
+{
+ return d->sourceRedirectMode;
+}
+
+void TimeLine::setSourceRedirectMode(RedirectMode mode)
+{
+ d->sourceRedirectMode = mode;
+}
+
+TimeLine::RedirectMode TimeLine::targetRedirectMode() const
+{
+ return d->targetRedirectMode;
+}
+
+void TimeLine::setTargetRedirectMode(RedirectMode mode)
+{
+ d->targetRedirectMode = mode;
+}
+
TimeLine &TimeLine::operator=(const TimeLine &other)
{
d = other.d;
diff --git a/libkwineffects/kwineffects.h b/libkwineffects/kwineffects.h
index 7bbc8f0..e2f121e 100644
--- a/libkwineffects/kwineffects.h
+++ b/libkwineffects/kwineffects.h
@@ -3584,6 +3584,65 @@ public:
**/
void reset();
+ enum class RedirectMode {
+ Strict,
+ Relaxed
+ };
+
+ /**
+ * Returns the redirect mode for the source position.
+ *
+ * The redirect mode controls behavior of the timeline when its direction is
+ * changed at the source position, e.g. what should we do when the timeline
+ * initially goes forward and we change its direction to go backward.
+ *
+ * In the strict mode, the timeline will stop.
+ *
+ * In the relaxed mode, the timeline will go in the new direction. For example,
+ * if the timeline goes forward(from 0 to 1), then with the new direction it
+ * will go backward(from 1 to 0).
+ *
+ * The default is RedirectMode::Relaxed.
+ *
+ * @see targetRedirectMode
+ * @since 5.15
+ **/
+ RedirectMode sourceRedirectMode() const;
+
+ /**
+ * Sets the redirect mode for the source position.
+ *
+ * @param mode The new mode.
+ * @since 5.15
+ **/
+ void setSourceRedirectMode(RedirectMode mode);
+
+ /**
+ * Returns the redirect mode for the target position.
+ *
+ * The redirect mode controls behavior of the timeline when its direction is
+ * changed at the target position.
+ *
+ * In the strict mode, subsequent update calls won't have any effect on the
+ * current value of the timeline.
+ *
+ * In the relaxed mode, the timeline will go in the new direction.
+ *
+ * The default is RedirectMode::Strict.
+ *
+ * @see sourceRedirectMode
+ * @since 5.15
+ **/
+ RedirectMode targetRedirectMode() const;
+
+ /**
+ * Sets the redirect mode for the target position.
+ *
+ * @param mode The new mode.
+ * @since 5.15
+ **/
+ void setTargetRedirectMode(RedirectMode mode);
+
TimeLine &operator=(const TimeLine &other);
private:
@@ -3824,6 +3883,7 @@ void Effect::initConfig()
Q_DECLARE_METATYPE(KWin::EffectWindow*)
Q_DECLARE_METATYPE(QList<KWin::EffectWindow*>)
Q_DECLARE_METATYPE(KWin::TimeLine)
+Q_DECLARE_METATYPE(KWin::TimeLine::Direction)
/** @} */