mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
perf: reduce repainting in animations
By profiling qTox using perf I discovered, that NotificationIcon::updateGradient takes significant amount of CPU time even though qTox is idle and no one is typing. This commit fixes: 1) correctly determine visibility of NotificationIcon 2) only invalidate boundingRect in fixed intervals 3) apply the same fixes to Spinner since it has the same problem
This commit is contained in:
parent
6a10abf1b3
commit
3c58b992c6
|
@ -50,11 +50,6 @@ void Broken::setWidth(qreal width)
|
|||
Q_UNUSED(width)
|
||||
}
|
||||
|
||||
void Broken::visibilityChanged(bool visible)
|
||||
{
|
||||
Q_UNUSED(visible)
|
||||
}
|
||||
|
||||
qreal Broken::getAscent() const
|
||||
{
|
||||
return 0.0;
|
||||
|
|
|
@ -33,7 +33,6 @@ public:
|
|||
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option,
|
||||
QWidget* widget) override;
|
||||
void setWidth(qreal width) override;
|
||||
void visibilityChanged(bool visible) override;
|
||||
qreal getAscent() const override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -30,13 +30,12 @@ NotificationIcon::NotificationIcon(QSize Size)
|
|||
{
|
||||
pmap = PixmapCache::getInstance().get(Style::getImagePath("chatArea/typing.svg"), size);
|
||||
|
||||
updateTimer = new QTimer(this);
|
||||
updateTimer->setInterval(1000 / 30);
|
||||
updateTimer->setSingleShot(false);
|
||||
// Timer for the animation, if the Widget is not redrawn, no paint events will
|
||||
// arrive and the timer will not be restarted, so this stops automatically
|
||||
updateTimer.setInterval(1000 / framerate);
|
||||
updateTimer.setSingleShot(true);
|
||||
|
||||
updateTimer->start();
|
||||
|
||||
connect(updateTimer, &QTimer::timeout, this, &NotificationIcon::updateGradient);
|
||||
connect(&updateTimer, &QTimer::timeout, this, &NotificationIcon::updateGradient);
|
||||
}
|
||||
|
||||
QRectF NotificationIcon::boundingRect() const
|
||||
|
@ -54,6 +53,10 @@ void NotificationIcon::paint(QPainter* painter, const QStyleOptionGraphicsItem*
|
|||
painter->fillRect(QRect(0, 0, size.width(), size.height()), grad);
|
||||
painter->drawPixmap(0, 0, size.width(), size.height(), pmap);
|
||||
|
||||
if (!updateTimer.isActive()) {
|
||||
updateTimer.start();
|
||||
}
|
||||
|
||||
Q_UNUSED(option)
|
||||
Q_UNUSED(widget)
|
||||
}
|
||||
|
@ -70,10 +73,12 @@ qreal NotificationIcon::getAscent() const
|
|||
|
||||
void NotificationIcon::updateGradient()
|
||||
{
|
||||
// Update for next frame
|
||||
alpha += 0.01;
|
||||
|
||||
if (alpha + dotWidth >= 1.0)
|
||||
if (alpha + dotWidth >= 1.0) {
|
||||
alpha = 0.0;
|
||||
}
|
||||
|
||||
grad = QLinearGradient(QPointF(-0.5 * size.width(), 0), QPointF(3.0 / 2.0 * size.width(), 0));
|
||||
grad.setColorAt(0, Qt::lightGray);
|
||||
|
@ -82,6 +87,7 @@ void NotificationIcon::updateGradient()
|
|||
grad.setColorAt(qMin(1.0, alpha + dotWidth), Qt::lightGray);
|
||||
grad.setColorAt(1, Qt::lightGray);
|
||||
|
||||
if (scene() && isVisible())
|
||||
if (scene() && isVisible()) {
|
||||
scene()->invalidate(sceneBoundingRect());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,8 +23,7 @@
|
|||
|
||||
#include <QLinearGradient>
|
||||
#include <QPixmap>
|
||||
|
||||
class QTimer;
|
||||
#include <QTimer>
|
||||
|
||||
class NotificationIcon : public ChatLineContent
|
||||
{
|
||||
|
@ -42,10 +41,12 @@ private slots:
|
|||
void updateGradient();
|
||||
|
||||
private:
|
||||
static constexpr int framerate = 30; // 30Hz
|
||||
|
||||
QSize size;
|
||||
QPixmap pmap;
|
||||
QLinearGradient grad;
|
||||
QTimer* updateTimer = nullptr;
|
||||
QTimer updateTimer;
|
||||
|
||||
qreal dotWidth = 0.2;
|
||||
qreal alpha = 0.0;
|
||||
|
|
|
@ -26,14 +26,18 @@
|
|||
#include <QTime>
|
||||
#include <QVariantAnimation>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
Spinner::Spinner(const QString& img, QSize Size, qreal speed)
|
||||
: size(Size)
|
||||
, rotSpeed(speed)
|
||||
{
|
||||
pmap = PixmapCache::getInstance().get(img, size);
|
||||
|
||||
timer.setInterval(1000 / 30); // 30Hz
|
||||
timer.setSingleShot(false);
|
||||
// Timer for the animation, if the Widget is not redrawn, no paint events will
|
||||
// arrive and the timer will not be restarted, so this stops automatically
|
||||
timer.setInterval(1000 / framerate);
|
||||
timer.setSingleShot(true);
|
||||
|
||||
blendAnimation = new QVariantAnimation(this);
|
||||
blendAnimation->setStartValue(0.0);
|
||||
|
@ -56,14 +60,17 @@ void Spinner::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, Q
|
|||
{
|
||||
painter->setClipRect(boundingRect());
|
||||
|
||||
QTransform trans = QTransform()
|
||||
.rotate(QTime::currentTime().msecsSinceStartOfDay() / 1000.0 * rotSpeed)
|
||||
QTransform trans = QTransform().rotate(curRot)
|
||||
.translate(-size.width() / 2.0, -size.height() / 2.0);
|
||||
painter->setOpacity(alpha);
|
||||
painter->setTransform(trans, true);
|
||||
painter->setRenderHint(QPainter::SmoothPixmapTransform);
|
||||
painter->drawPixmap(0, 0, pmap);
|
||||
|
||||
if (!timer.isActive()) {
|
||||
timer.start(); // update bounding rectangle for next frame
|
||||
}
|
||||
|
||||
Q_UNUSED(option)
|
||||
Q_UNUSED(widget)
|
||||
}
|
||||
|
@ -73,14 +80,6 @@ void Spinner::setWidth(qreal width)
|
|||
Q_UNUSED(width)
|
||||
}
|
||||
|
||||
void Spinner::visibilityChanged(bool visible)
|
||||
{
|
||||
if (visible)
|
||||
timer.start();
|
||||
else
|
||||
timer.stop();
|
||||
}
|
||||
|
||||
qreal Spinner::getAscent() const
|
||||
{
|
||||
return 0.0;
|
||||
|
@ -88,6 +87,12 @@ qreal Spinner::getAscent() const
|
|||
|
||||
void Spinner::timeout()
|
||||
{
|
||||
if (scene())
|
||||
// Use global time, so the animations are synced
|
||||
float angle = QTime::currentTime().msecsSinceStartOfDay() / 1000.0f * rotSpeed;
|
||||
// limit to the range [0.0 - 360.0]
|
||||
curRot = remainderf(angle, 360.0f);
|
||||
|
||||
if (scene()) {
|
||||
scene()->invalidate(sceneBoundingRect());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,16 +37,17 @@ public:
|
|||
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option,
|
||||
QWidget* widget) override;
|
||||
void setWidth(qreal width) override;
|
||||
void visibilityChanged(bool visible) override;
|
||||
qreal getAscent() const override;
|
||||
|
||||
private slots:
|
||||
void timeout();
|
||||
|
||||
private:
|
||||
static constexpr int framerate = 30; // 30Hz
|
||||
QSize size;
|
||||
QPixmap pmap;
|
||||
qreal rotSpeed;
|
||||
qreal curRot;
|
||||
QTimer timer;
|
||||
qreal alpha = 0.0;
|
||||
QVariantAnimation* blendAnimation;
|
||||
|
|
Loading…
Reference in New Issue
Block a user