[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
master
Vlad Zagorodniy 6 years ago
parent aa58a8c4dd
commit e02573263f

@ -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"

@ -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;

@ -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)
/** @} */

Loading…
Cancel
Save