QTimeLine: fix binding loops

... by using valueBypassingBindings() when accessing the properties
from the setters.

The most complicated case here is the currentTime property, because
its setter was calling the public currentValue() and currentFrame()
methods. Both methods are reading the same currentTime property.

Fix it by replacing the calls to these methods with the calls to
valueForTime() and frameForTime(). Both take an int parameter, so
the updated code can use valueBypassingBindings() to pass the current
time to these calls.

Task-number: QTBUG-116346
Change-Id: I5c3a05f3e21e4c9e53ed98c9f8d1dce76e40a00d
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
(cherry picked from commit 47d2788e0b99870cbd21044ac1e42d0c2cabb1f0)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Ivan Solovev 2023-08-25 15:08:41 +02:00 committed by Qt Cherry-pick Bot
parent d8f614648f
commit d2891e5d01

View File

@ -55,16 +55,16 @@ void QTimeLinePrivate::setCurrentTime(int msecs)
{ {
Q_Q(QTimeLine); Q_Q(QTimeLine);
currentTime.removeBindingUnlessInWrapper(); currentTime.removeBindingUnlessInWrapper();
auto previousCurrentTime = currentTime.value(); const auto previousCurrentTime = currentTime.valueBypassingBindings();
qreal lastValue = q->currentValue(); const qreal lastValue = q->valueForTime(previousCurrentTime);
int lastFrame = q->currentFrame(); const int lastFrame = q->frameForTime(previousCurrentTime);
// Determine if we are looping. // Determine if we are looping.
int elapsed = (direction == QTimeLine::Backward) ? (-msecs + duration) : msecs; const int elapsed = (direction == QTimeLine::Backward) ? (-msecs + duration) : msecs;
int loopCountNow = elapsed / duration; const int loopCountNow = elapsed / duration;
bool looping = (loopCountNow != currentLoopCount); const bool looping = (loopCountNow != currentLoopCount);
#ifdef QTIMELINE_DEBUG #ifdef QTIMELINE_DEBUG
qDebug() << "QTimeLinePrivate::setCurrentTime:" << msecs << duration << "with loopCountNow" qDebug() << "QTimeLinePrivate::setCurrentTime:" << msecs << duration << "with loopCountNow"
<< loopCountNow << "currentLoopCount" << currentLoopCount << "looping" << looping; << loopCountNow << "currentLoopCount" << currentLoopCount << "looping" << looping;
@ -75,7 +75,7 @@ void QTimeLinePrivate::setCurrentTime(int msecs)
// Normalize msecs to be between 0 and duration, inclusive. // Normalize msecs to be between 0 and duration, inclusive.
currentTime.setValueBypassingBindings(elapsed % duration); currentTime.setValueBypassingBindings(elapsed % duration);
if (direction.value() == QTimeLine::Backward) if (direction.value() == QTimeLine::Backward)
currentTime.setValueBypassingBindings(duration - currentTime); currentTime.setValueBypassingBindings(duration - currentTime.valueBypassingBindings());
// Check if we have reached the end of loopcount. // Check if we have reached the end of loopcount.
bool finished = false; bool finished = false;
@ -85,12 +85,14 @@ void QTimeLinePrivate::setCurrentTime(int msecs)
currentLoopCount = loopCount - 1; currentLoopCount = loopCount - 1;
} }
int currentFrame = q->frameForTime(currentTime); const int currentFrame = q->frameForTime(currentTime.valueBypassingBindings());
#ifdef QTIMELINE_DEBUG #ifdef QTIMELINE_DEBUG
qDebug() << "QTimeLinePrivate::setCurrentTime: frameForTime" << currentTime << currentFrame; qDebug() << "QTimeLinePrivate::setCurrentTime: frameForTime"
<< currentTime.valueBypassingBindings() << currentFrame;
#endif #endif
if (!qFuzzyCompare(lastValue, q->currentValue())) const qreal currentValue = q->valueForTime(currentTime.valueBypassingBindings());
emit q->valueChanged(q->currentValue(), QTimeLine::QPrivateSignal()); if (!qFuzzyCompare(lastValue, currentValue))
emit q->valueChanged(currentValue, QTimeLine::QPrivateSignal());
if (lastFrame != currentFrame) { if (lastFrame != currentFrame) {
const int transitionframe = (direction == QTimeLine::Forward ? endFrame : startFrame); const int transitionframe = (direction == QTimeLine::Forward ? endFrame : startFrame);
if (looping && !finished && transitionframe != currentFrame) { if (looping && !finished && transitionframe != currentFrame) {
@ -123,7 +125,7 @@ void QTimeLinePrivate::setCurrentTime(int msecs)
q->stop(); q->stop();
emit q->finished(QTimeLine::QPrivateSignal()); emit q->finished(QTimeLine::QPrivateSignal());
} }
if (currentTime.value() != previousCurrentTime) if (currentTime.valueBypassingBindings() != previousCurrentTime)
currentTime.notify(); currentTime.notify();
} }
QBindable<int> QTimeLine::bindableCurrentTime() QBindable<int> QTimeLine::bindableCurrentTime()
@ -334,11 +336,12 @@ QTimeLine::Direction QTimeLine::direction() const
void QTimeLine::setDirection(Direction direction) void QTimeLine::setDirection(Direction direction)
{ {
Q_D(QTimeLine); Q_D(QTimeLine);
auto previousDirection = d->direction.value(); d->direction.removeBindingUnlessInWrapper();
d->direction.setValue(direction); const auto previousDirection = d->direction.valueBypassingBindings();
d->direction.setValueBypassingBindings(direction);
d->startTime = d->currentTime; d->startTime = d->currentTime;
d->timer.start(); d->timer.start();
if (previousDirection != d->direction.value()) if (previousDirection != d->direction.valueBypassingBindings())
d->direction.notify(); d->direction.notify();
} }
@ -372,12 +375,11 @@ void QTimeLine::setDuration(int duration)
qWarning("QTimeLine::setDuration: cannot set duration <= 0"); qWarning("QTimeLine::setDuration: cannot set duration <= 0");
return; return;
} }
if (duration == d->duration) { d->duration.removeBindingUnlessInWrapper();
d->duration.removeBindingUnlessInWrapper(); if (duration != d->duration.valueBypassingBindings()) {
return; d->duration.setValueBypassingBindings(duration);
d->duration.notify();
} }
d->duration.setValue(duration);
d->duration.notify();
} }
QBindable<int> QTimeLine::bindableDuration() QBindable<int> QTimeLine::bindableDuration()