Files
qemby/src/qEmbyApp/components/playerlongpresshandler.cpp
T
dela ab1accc821 perf: smooth UI animations and reduce repaint overhead
Batch of performance and animation work: shared FadeHelper/MotionPrefs
primitives, hover animators, shadow pixmap caching, smooth scrolling,
seek time bubble, and widespread component repaint reductions.
2026-07-08 11:29:38 +08:00

826 lines
24 KiB
C++

#include "playerlongpresshandler.h"
#include <QAbstractAnimation>
#include <QDebug>
#include <QEasingCurve>
#include <QGraphicsOpacityEffect>
#include <QHBoxLayout>
#include <QIcon>
#include <QLabel>
#include <QPropertyAnimation>
#include <QStyle>
#include <QTimer>
#include <QWidget>
#include <cmath>
#include <config/config_keys.h>
#include <config/configstore.h>
#include "../tokens/AnimationTokens.h"
#include "../utils/motionprefs.h"
namespace
{
void stopPropertyAnimationSafely(QPropertyAnimation *animation)
{
if (!animation || !animation->targetObject() ||
animation->state() == QAbstractAnimation::Stopped)
{
return;
}
animation->stop();
}
}
PlayerLongPressHandler::PlayerLongPressHandler(QWidget *parent)
: QObject(parent), m_parentWidget(parent)
{
m_keyLongPressTimer = new QTimer(this);
connect(m_keyLongPressTimer, &QTimer::timeout, this,
&PlayerLongPressHandler::onKeyLongPressTimeout);
m_mouseEdgeTimer = new QTimer(this);
connect(m_mouseEdgeTimer, &QTimer::timeout, this,
&PlayerLongPressHandler::onMouseEdgeLongPressTimeout);
m_pulseTimer = new QTimer(this);
m_pulseTimer->setInterval(260);
connect(m_pulseTimer, &QTimer::timeout, this,
&PlayerLongPressHandler::updateIndicatorPulse);
m_leftIndicator = createIndicator(
QStringLiteral(":/svg/player/fast-rewind.svg"),
m_leftIndicatorIcon, m_leftIndicatorText,
m_leftIndicatorOpacity, m_leftIndicatorOpacityAnim,
m_leftIndicatorGeometryAnim, m_leftIndicatorIconAnim);
m_rightIndicator = createIndicator(
QStringLiteral(":/svg/player/fast-forward.svg"),
m_rightIndicatorIcon, m_rightIndicatorText,
m_rightIndicatorOpacity, m_rightIndicatorOpacityAnim,
m_rightIndicatorGeometryAnim, m_rightIndicatorIconAnim);
}
QWidget *PlayerLongPressHandler::createIndicator(
const QString &iconPath, QLabel *&iconLabel, QLabel *&textLabel,
QGraphicsOpacityEffect *&opacityEffect,
QPropertyAnimation *&opacityAnim,
QPropertyAnimation *&geometryAnim,
QPropertyAnimation *&iconAnim)
{
auto *overlay = new QWidget(m_parentWidget);
overlay->setObjectName("playerMouseEdgeIndicator");
overlay->setAttribute(Qt::WA_TransparentForMouseEvents, true);
overlay->setAttribute(Qt::WA_TranslucentBackground, true);
overlay->setProperty("gestureActive", false);
overlay->setProperty("indicatorVisible", false);
overlay->hide();
auto *layout = new QHBoxLayout(overlay);
layout->setContentsMargins(18, 12, 18, 12);
layout->setSpacing(12);
layout->setAlignment(Qt::AlignCenter);
iconLabel = new QLabel(overlay);
iconLabel->setObjectName("playerMouseEdgeIndicatorIcon");
iconLabel->setFixedSize(18, 18);
iconLabel->setAlignment(Qt::AlignCenter);
iconLabel->setPixmap(QIcon(iconPath).pixmap(18, 18));
layout->addWidget(iconLabel, 0, Qt::AlignCenter);
textLabel = new QLabel(overlay);
textLabel->setObjectName("playerMouseEdgeIndicatorText");
textLabel->setAlignment(Qt::AlignCenter);
textLabel->hide();
layout->addWidget(textLabel, 0, Qt::AlignCenter);
opacityEffect = new QGraphicsOpacityEffect(overlay);
opacityEffect->setOpacity(0.0);
overlay->setGraphicsEffect(opacityEffect);
opacityAnim = new QPropertyAnimation(opacityEffect, "opacity", this);
opacityAnim->setEasingCurve(AnimationTokens::Curve::enter());
geometryAnim = new QPropertyAnimation(overlay, "geometry", this);
geometryAnim->setEasingCurve(AnimationTokens::Curve::enter());
iconAnim = new QPropertyAnimation(iconLabel, "pos", this);
iconAnim->setDuration(AnimationTokens::DurationMs::kNormal);
iconAnim->setEasingCurve(AnimationTokens::Curve::oscillate());
connect(opacityAnim, &QPropertyAnimation::finished, overlay,
[overlay, opacityEffect]()
{
if (!overlay->property("indicatorVisible").toBool() &&
opacityEffect && opacityEffect->opacity() <= 0.01)
{
overlay->hide();
}
});
return overlay;
}
QString PlayerLongPressHandler::longPressMode() const
{
const QString mode =
ConfigStore::instance()->get<QString>(ConfigKeys::PlayerLongPressMode, "seek");
return mode == QStringLiteral("speed") ? mode : QStringLiteral("seek");
}
int PlayerLongPressHandler::longPressTriggerMs() const
{
const int triggerMs =
ConfigStore::instance()->get<QString>(ConfigKeys::PlayerLongPressTriggerMs, "500").toInt();
return triggerMs > 0 ? triggerMs : 500;
}
double PlayerLongPressHandler::nextPlaybackRate(double currentRate) const
{
static const QList<double> kSpeedSteps = {2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0};
for (double rate : kSpeedSteps)
{
if (rate > currentRate + 0.001)
{
return rate;
}
}
return kSpeedSteps.constLast();
}
bool PlayerLongPressHandler::canStartPropertyAnimation(const QPropertyAnimation *animation) const
{
return animation && animation->targetObject() && !MotionPrefs::reduceMotion();
}
bool PlayerLongPressHandler::isMouseEdgeLongPressEnabled() const
{
return ConfigStore::instance()->get<bool>(ConfigKeys::PlayerMouseEdgeLongPress, true);
}
QString PlayerLongPressHandler::formatSpeedText(double speed)
{
QString text = QString::number(speed, 'f', 2);
while (text.contains('.') && text.endsWith('0'))
{
text.chop(1);
}
if (text.endsWith('.'))
{
text.append('0');
}
return text + "X";
}
QString PlayerLongPressHandler::formatLongPressSeekText(double seconds)
{
QString text = QString::number(seconds, 'f', seconds >= 10.0 ? 0 : 1);
while (text.contains('.') && text.endsWith('0'))
{
text.chop(1);
}
if (text.endsWith('.'))
{
text.chop(1);
}
return text + "s";
}
void PlayerLongPressHandler::startKeyLongPress(int direction, bool silent)
{
m_teardown = false;
stopKeyLongPress(false);
m_keyDirection = direction;
m_keySeekRate = 2.0;
m_keyRestoreSpeed = 1.0;
m_keyCurrentSpeed = 1.0;
m_keySpeedTick = 0;
m_keyTriggered = false;
m_keySilent = silent;
m_keySpeedActive = false;
m_keyActiveMode = longPressMode();
const double step =
ConfigStore::instance()->get<QString>(ConfigKeys::PlayerSeekStep, "10").toDouble();
const bool longPressEnabled =
ConfigStore::instance()->get<bool>(ConfigKeys::PlayerLongPressSeek, true);
if (!longPressEnabled)
{
Q_EMIT seekRequested(direction * step, silent);
m_keyDirection = 0;
m_keySilent = false;
m_keyActiveMode.clear();
return;
}
if (m_keyActiveMode == QStringLiteral("seek"))
{
Q_EMIT seekRequested(direction * step, silent);
}
qDebug() << "[PlayerLongPressHandler] Direction key pressed"
<< "| direction:" << direction
<< "| mode:" << m_keyActiveMode
<< "| triggerMs:" << longPressTriggerMs();
m_keyLongPressTimer->setInterval(longPressTriggerMs());
m_keyLongPressTimer->start();
}
void PlayerLongPressHandler::stopKeyLongPress(bool applyShortPressFallback)
{
if (m_keyLongPressTimer)
{
m_keyLongPressTimer->stop();
}
if (m_keyDirection == 0)
{
return;
}
if (m_keyActiveMode == QStringLiteral("speed"))
{
if (!m_keySpeedActive && applyShortPressFallback)
{
const double step = ConfigStore::instance()
->get<QString>(ConfigKeys::PlayerSeekStep, "10")
.toDouble();
Q_EMIT seekRequested(m_keyDirection * step, m_keySilent);
}
}
m_keyDirection = 0;
m_keySeekRate = 2.0;
m_keyRestoreSpeed = 1.0;
m_keyCurrentSpeed = 1.0;
m_keySpeedTick = 0;
m_keyTriggered = false;
m_keySilent = false;
m_keySpeedActive = false;
m_keyActiveMode.clear();
updateIndicators();
}
void PlayerLongPressHandler::onKeyLongPressTimeout()
{
if (m_keyDirection == 0 || m_keyActiveMode.isEmpty())
{
return;
}
if (m_keyActiveMode == QStringLiteral("speed"))
{
if (!m_keyTriggered)
{
m_keyTriggered = true;
m_keySpeedActive = true;
m_keyCurrentSpeed = nextPlaybackRate(1.0);
m_keySpeedTick = 0;
const QString speedText = formatSpeedText(m_keyCurrentSpeed);
updateIndicators();
Q_EMIT toastRequested(tr("Speed: %1X").arg(speedText.chopped(1)));
qDebug() << "[PlayerLongPressHandler] Long press speed activated"
<< "| direction:" << m_keyDirection
<< "| targetSpeed:" << m_keyCurrentSpeed;
}
else if (m_keySpeedTick > 0 && m_keySpeedTick % 2 == 0)
{
const double nextSpeed = nextPlaybackRate(m_keyCurrentSpeed);
if (std::abs(nextSpeed - m_keyCurrentSpeed) > 0.001)
{
m_keyCurrentSpeed = nextSpeed;
const QString speedText = formatSpeedText(m_keyCurrentSpeed);
updateIndicators();
Q_EMIT toastRequested(tr("Speed: %1X").arg(speedText.chopped(1)));
qDebug() << "[PlayerLongPressHandler] Long press speed increased"
<< "| direction:" << m_keyDirection
<< "| targetSpeed:" << m_keyCurrentSpeed;
}
}
const double deltaSeconds = m_keyDirection * m_keyCurrentSpeed * 0.25;
Q_EMIT seekRequested(deltaSeconds, true);
++m_keySpeedTick;
m_keyLongPressTimer->setInterval(250);
return;
}
const bool wasTriggered = m_keyTriggered;
m_keyTriggered = true;
m_keyLongPressTimer->setInterval(100);
Q_EMIT seekRequested(m_keyDirection * m_keySeekRate, m_keySilent);
updateIndicators();
if (!wasTriggered)
{
qDebug() << "[PlayerLongPressHandler] Long press seek activated"
<< "| direction:" << m_keyDirection;
}
m_keySeekRate *= 1.15;
if (m_keySeekRate > 30.0)
{
m_keySeekRate = 30.0;
}
}
void PlayerLongPressHandler::startMouseEdgeLongPress(int direction)
{
m_teardown = false;
stopMouseEdgeLongPress();
if (!isMouseEdgeLongPressEnabled())
{
return;
}
m_mouseEdgeDirection = direction;
m_mouseEdgeTick = 0;
m_mouseEdgeSpeed = 1.0;
m_mouseEdgeActive = false;
qDebug() << "[PlayerLongPressHandler] Mouse edge long press armed"
<< "| direction:" << direction
<< "| triggerMs:" << longPressTriggerMs();
if (m_mouseEdgeTimer)
{
m_mouseEdgeTimer->setInterval(longPressTriggerMs());
m_mouseEdgeTimer->start();
}
}
bool PlayerLongPressHandler::stopMouseEdgeLongPress()
{
if (m_mouseEdgeTimer)
{
m_mouseEdgeTimer->stop();
}
const bool wasActive = m_mouseEdgeActive;
if (wasActive)
{
qDebug() << "[PlayerLongPressHandler] Mouse edge long press stopped"
<< "| direction:" << m_mouseEdgeDirection
<< "| speed:" << m_mouseEdgeSpeed;
}
m_mouseEdgeDirection = 0;
m_mouseEdgeTick = 0;
m_mouseEdgeSpeed = 1.0;
m_mouseEdgeActive = false;
updateIndicators();
return wasActive;
}
void PlayerLongPressHandler::onMouseEdgeLongPressTimeout()
{
if (m_mouseEdgeDirection == 0)
{
return;
}
if (!m_mouseEdgeActive)
{
m_mouseEdgeActive = true;
m_mouseEdgeSpeed = nextPlaybackRate(1.0);
updateIndicators();
qDebug() << "[PlayerLongPressHandler] Mouse edge long press activated"
<< "| direction:" << m_mouseEdgeDirection
<< "| speed:" << m_mouseEdgeSpeed;
}
else if (m_mouseEdgeTick > 0 && m_mouseEdgeTick % 2 == 0)
{
const double nextSpeed = nextPlaybackRate(m_mouseEdgeSpeed);
if (std::abs(nextSpeed - m_mouseEdgeSpeed) > 0.001)
{
m_mouseEdgeSpeed = nextSpeed;
updateIndicators();
qDebug() << "[PlayerLongPressHandler] Mouse edge long press accelerated"
<< "| direction:" << m_mouseEdgeDirection
<< "| speed:" << m_mouseEdgeSpeed;
}
}
const double deltaSeconds = m_mouseEdgeDirection * m_mouseEdgeSpeed * 0.25;
Q_EMIT seekRequested(deltaSeconds, true);
++m_mouseEdgeTick;
if (m_mouseEdgeTimer)
{
m_mouseEdgeTimer->setInterval(250);
}
}
bool PlayerLongPressHandler::isMouseEdgeActive() const
{
return m_mouseEdgeActive;
}
int PlayerLongPressHandler::mouseEdgeLongPressDirection() const
{
return m_mouseEdgeDirection;
}
bool PlayerLongPressHandler::isKeyLongPressTriggered() const
{
return m_keyTriggered;
}
int PlayerLongPressHandler::keyLongPressDirection() const
{
return m_keyDirection;
}
int PlayerLongPressHandler::activeLongPressDirection() const
{
if (m_mouseEdgeActive && m_mouseEdgeDirection != 0)
{
return m_mouseEdgeDirection;
}
if (m_keyTriggered && m_keyDirection != 0)
{
return m_keyDirection;
}
return 0;
}
void PlayerLongPressHandler::setTeardown(bool teardown)
{
m_teardown = teardown;
if (!m_teardown)
{
return;
}
if (m_keyLongPressTimer)
{
m_keyLongPressTimer->stop();
}
if (m_mouseEdgeTimer)
{
m_mouseEdgeTimer->stop();
}
stopIndicatorAnimations();
}
QRect PlayerLongPressHandler::indicatorGeometry(int direction, bool active) const
{
const int w = m_parentWidget ? m_parentWidget->width() : 800;
const int h = m_parentWidget ? m_parentWidget->height() : 600;
const int indicatorWidth = active ? 128 : 60;
const int indicatorHeight = 54;
const int indicatorMargin = 28;
const int indicatorY = qMax(m_topHudHeight + 24, (h - indicatorHeight) / 2);
const int indicatorX = direction < 0
? indicatorMargin
: w - indicatorWidth - indicatorMargin;
return QRect(indicatorX, indicatorY, indicatorWidth, indicatorHeight);
}
void PlayerLongPressHandler::animateIndicator(
QWidget *overlay, int direction, bool active, bool visible)
{
if (!overlay)
{
return;
}
QGraphicsOpacityEffect *opacityEffect =
direction < 0 ? m_leftIndicatorOpacity : m_rightIndicatorOpacity;
QPropertyAnimation *opacityAnim =
direction < 0 ? m_leftIndicatorOpacityAnim : m_rightIndicatorOpacityAnim;
QPropertyAnimation *geometryAnim =
direction < 0 ? m_leftIndicatorGeometryAnim : m_rightIndicatorGeometryAnim;
const QRect targetGeometry = indicatorGeometry(direction, active);
if (!opacityEffect || !opacityAnim || !geometryAnim)
{
overlay->setGeometry(targetGeometry);
overlay->setVisible(visible);
return;
}
if (!opacityAnim->targetObject() || !geometryAnim->targetObject() || m_teardown)
{
overlay->setProperty("indicatorVisible", visible);
overlay->setGeometry(targetGeometry);
opacityEffect->setOpacity(visible ? (active ? 1.0 : 0.62) : 0.0);
overlay->setVisible(visible);
return;
}
stopPropertyAnimationSafely(opacityAnim);
stopPropertyAnimationSafely(geometryAnim);
if (visible)
{
const bool wasVisible = overlay->isVisible();
const QRect startGeometry = wasVisible
? overlay->geometry()
: targetGeometry.translated(
direction < 0 ? -14 : 14, 0);
const qreal startOpacity = wasVisible ? opacityEffect->opacity() : 0.0;
const qreal targetOpacity = active ? 1.0 : 0.62;
overlay->setProperty("indicatorVisible", true);
overlay->setGeometry(startGeometry);
overlay->show();
overlay->raise();
opacityEffect->setOpacity(startOpacity);
opacityAnim->setDuration(wasVisible ? AnimationTokens::DurationMs::kMicro
: AnimationTokens::DurationMs::kFast);
opacityAnim->setStartValue(startOpacity);
opacityAnim->setEndValue(targetOpacity);
// Geometry lags the opacity slightly (140/200 vs 120/180) so the pill
// reads as sliding into place — tuned choreography, intentionally off
// the shared duration scale.
geometryAnim->setDuration(wasVisible ? 140 : 200);
geometryAnim->setStartValue(startGeometry);
geometryAnim->setEndValue(targetGeometry);
}
else
{
if (!overlay->isVisible())
{
opacityEffect->setOpacity(0.0);
return;
}
const QRect currentGeometry = overlay->geometry();
overlay->setProperty("indicatorVisible", false);
opacityAnim->setDuration(AnimationTokens::DurationMs::kMicro);
opacityAnim->setStartValue(opacityEffect->opacity());
opacityAnim->setEndValue(0.0);
geometryAnim->setDuration(AnimationTokens::DurationMs::kMicro);
geometryAnim->setStartValue(currentGeometry);
geometryAnim->setEndValue(
currentGeometry.translated(direction < 0 ? -10 : 10, 0));
}
if (canStartPropertyAnimation(opacityAnim))
{
opacityAnim->start();
}
else if (opacityEffect)
{
opacityEffect->setOpacity(visible ? (active ? 1.0 : 0.62) : 0.0);
if (!visible)
{
// The animated path hides via the opacityAnim finished handler;
// when snapping we must hide directly.
overlay->hide();
}
}
if (canStartPropertyAnimation(geometryAnim))
{
geometryAnim->start();
}
else
{
overlay->setGeometry(visible ? targetGeometry
: overlay->geometry().translated(
direction < 0 ? -10 : 10, 0));
}
}
void PlayerLongPressHandler::animateIndicatorIcon(
QLabel *iconLabel, int direction, bool active, bool immediate)
{
if (!iconLabel)
{
return;
}
QPropertyAnimation *iconAnim =
direction < 0 ? m_leftIndicatorIconAnim : m_rightIndicatorIconAnim;
if (!iconAnim)
{
return;
}
const QPoint basePos = iconLabel->property("basePos").toPoint();
const int offset = (active && m_pulseForward)
? (direction < 0 ? -4 : 4)
: 0;
const QPoint targetPos = basePos + QPoint(offset, 0);
if (immediate || !iconAnim->targetObject() || m_teardown)
{
iconLabel->move(targetPos);
return;
}
stopPropertyAnimationSafely(iconAnim);
iconAnim->setStartValue(iconLabel->pos());
iconAnim->setEndValue(targetPos);
if (canStartPropertyAnimation(iconAnim))
{
iconAnim->start();
}
else
{
iconLabel->move(targetPos);
}
}
void PlayerLongPressHandler::setIndicatorState(
QWidget *overlay, QLabel *iconLabel, QLabel *textLabel, int direction,
bool active, const QString &speedText)
{
if (!overlay || !iconLabel || !textLabel)
{
return;
}
overlay->setProperty("gestureActive", active);
overlay->style()->unpolish(overlay);
overlay->style()->polish(overlay);
overlay->update();
if (speedText.isEmpty())
{
textLabel->clear();
textLabel->hide();
}
else
{
textLabel->setText(speedText);
textLabel->show();
}
if (overlay->layout())
{
overlay->layout()->activate();
}
iconLabel->setProperty("basePos", iconLabel->pos());
animateIndicatorIcon(iconLabel, direction, active, true);
animateIndicator(overlay, direction, active, true);
}
void PlayerLongPressHandler::updateIndicatorPulse()
{
if (m_teardown)
{
stopIndicatorAnimations();
return;
}
const int activeDirection = activeLongPressDirection();
if (activeDirection == 0)
{
if (m_pulseTimer)
{
m_pulseTimer->stop();
}
m_pulseForward = false;
animateIndicatorIcon(m_leftIndicatorIcon, -1, false, true);
animateIndicatorIcon(m_rightIndicatorIcon, 1, false, true);
return;
}
m_pulseForward = !m_pulseForward;
animateIndicatorIcon(m_leftIndicatorIcon, -1, activeDirection < 0);
animateIndicatorIcon(m_rightIndicatorIcon, 1, activeDirection > 0);
}
void PlayerLongPressHandler::updateIndicators()
{
if (m_teardown)
{
stopIndicatorAnimations();
if (m_leftIndicator)
{
m_leftIndicator->hide();
}
if (m_rightIndicator)
{
m_rightIndicator->hide();
}
animateIndicatorIcon(m_leftIndicatorIcon, -1, false, true);
animateIndicatorIcon(m_rightIndicatorIcon, 1, false, true);
return;
}
const int activeDirection = activeLongPressDirection();
if (activeDirection == 0)
{
if (m_leftIndicator)
{
m_leftIndicator->setProperty("gestureActive", false);
m_leftIndicator->style()->unpolish(m_leftIndicator);
m_leftIndicator->style()->polish(m_leftIndicator);
animateIndicator(m_leftIndicator, -1, false, false);
}
if (m_rightIndicator)
{
m_rightIndicator->setProperty("gestureActive", false);
m_rightIndicator->style()->unpolish(m_rightIndicator);
m_rightIndicator->style()->polish(m_rightIndicator);
animateIndicator(m_rightIndicator, 1, false, false);
}
updateIndicatorPulse();
return;
}
const bool fromMouse = m_mouseEdgeActive && m_mouseEdgeDirection != 0;
const QString indicatorText =
fromMouse
? formatSpeedText(m_mouseEdgeSpeed)
: (m_keyActiveMode == QStringLiteral("speed")
? formatSpeedText(m_keyCurrentSpeed)
: formatLongPressSeekText(m_keySeekRate));
const bool leftActive = activeDirection < 0;
const bool rightActive = activeDirection > 0;
setIndicatorState(
m_leftIndicator, m_leftIndicatorIcon,
m_leftIndicatorText, -1, leftActive,
leftActive ? indicatorText : QString());
setIndicatorState(
m_rightIndicator, m_rightIndicatorIcon,
m_rightIndicatorText, 1, rightActive,
rightActive ? indicatorText : QString());
if (m_pulseTimer && !m_pulseTimer->isActive() && !MotionPrefs::reduceMotion())
{
m_pulseForward = false;
updateIndicatorPulse();
m_pulseTimer->start();
}
}
void PlayerLongPressHandler::stopIndicatorAnimations()
{
if (m_pulseTimer)
{
m_pulseTimer->stop();
}
const QList<QPropertyAnimation *> animations = {
m_leftIndicatorOpacityAnim, m_rightIndicatorOpacityAnim,
m_leftIndicatorGeometryAnim, m_rightIndicatorGeometryAnim,
m_leftIndicatorIconAnim, m_rightIndicatorIconAnim};
for (QPropertyAnimation *animation : animations)
{
stopPropertyAnimationSafely(animation);
}
}
void PlayerLongPressHandler::stopAllAnimations()
{
stopIndicatorAnimations();
}
void PlayerLongPressHandler::updateGeometry(int parentWidth, int parentHeight, int topHudHeight)
{
Q_UNUSED(parentHeight);
m_topHudHeight = topHudHeight;
auto syncGeometry = [this](QWidget *overlay, QPropertyAnimation *animation, int direction)
{
if (!overlay)
{
return;
}
const QRect targetGeometry = indicatorGeometry(
direction, overlay->property("gestureActive").toBool());
if (animation && animation->state() == QAbstractAnimation::Running)
{
animation->setEndValue(targetGeometry);
return;
}
overlay->setGeometry(targetGeometry);
};
syncGeometry(m_leftIndicator, m_leftIndicatorGeometryAnim, -1);
syncGeometry(m_rightIndicator, m_rightIndicatorGeometryAnim, 1);
}