Fix ripple glitch on theme switching.

This commit is contained in:
John Preston 2018-10-25 14:02:37 +04:00
parent eb099c70e6
commit 9aa23dac80
4 changed files with 56 additions and 33 deletions

View File

@ -11,21 +11,22 @@ namespace Ui {
class RippleAnimation::Ripple {
public:
Ripple(const style::RippleAnimation &st, QPoint origin, int startRadius, const QPixmap &mask, const UpdateCallback &update);
Ripple(const style::RippleAnimation &st, const QPixmap &mask, const UpdateCallback &update);
Ripple(const style::RippleAnimation &st, QPoint origin, int startRadius, const QPixmap &mask, Fn<void()> update);
Ripple(const style::RippleAnimation &st, const QPixmap &mask, Fn<void()> update);
void paint(QPainter &p, const QPixmap &mask, TimeMs ms, const QColor *colorOverride);
void stop();
void unstop();
void finish();
void clearCache();
bool finished() const {
return _hiding && !_hide.animating();
}
private:
const style::RippleAnimation &_st;
UpdateCallback _update;
Fn<void()> _update;
QPoint _origin;
int _radiusFrom = 0;
@ -39,7 +40,7 @@ private:
};
RippleAnimation::Ripple::Ripple(const style::RippleAnimation &st, QPoint origin, int startRadius, const QPixmap &mask, const UpdateCallback &update)
RippleAnimation::Ripple::Ripple(const style::RippleAnimation &st, QPoint origin, int startRadius, const QPixmap &mask, Fn<void()> update)
: _st(st)
, _update(update)
, _origin(origin)
@ -58,10 +59,10 @@ RippleAnimation::Ripple::Ripple(const style::RippleAnimation &st, QPoint origin,
}
_radiusTo = qRound(sqrt(_radiusTo));
_show.start(UpdateCallback(_update), 0., 1., _st.showDuration, anim::easeOutQuint);
_show.start(_update, 0., 1., _st.showDuration, anim::easeOutQuint);
}
RippleAnimation::Ripple::Ripple(const style::RippleAnimation &st, const QPixmap &mask, const UpdateCallback &update)
RippleAnimation::Ripple::Ripple(const style::RippleAnimation &st, const QPixmap &mask, Fn<void()> update)
: _st(st)
, _update(update)
, _origin(mask.width() / (2 * cIntRetinaFactor()), mask.height() / (2 * cIntRetinaFactor()))
@ -69,7 +70,7 @@ RippleAnimation::Ripple::Ripple(const style::RippleAnimation &st, const QPixmap
, _frame(mask.size(), QImage::Format_ARGB32_Premultiplied) {
_frame.setDevicePixelRatio(mask.devicePixelRatio());
_radiusTo = _radiusFrom;
_hide.start(UpdateCallback(_update), 0., 1., _st.hideDuration);
_hide.start(_update, 0., 1., _st.hideDuration);
}
void RippleAnimation::Ripple::paint(QPainter &p, const QPixmap &mask, TimeMs ms, const QColor *colorOverride) {
@ -112,13 +113,13 @@ void RippleAnimation::Ripple::paint(QPainter &p, const QPixmap &mask, TimeMs ms,
void RippleAnimation::Ripple::stop() {
_hiding = true;
_hide.start(UpdateCallback(_update), 1., 0., _st.hideDuration);
_hide.start(_update, 1., 0., _st.hideDuration);
}
void RippleAnimation::Ripple::unstop() {
if (_hiding) {
if (_hide.animating()) {
_hide.start(UpdateCallback(_update), 0., 1., _st.hideDuration);
_hide.start(_update, 0., 1., _st.hideDuration);
}
_hiding = false;
}
@ -132,7 +133,11 @@ void RippleAnimation::Ripple::finish() {
_hide.finish();
}
RippleAnimation::RippleAnimation(const style::RippleAnimation &st, QImage mask, const UpdateCallback &callback)
void RippleAnimation::Ripple::clearCache() {
_cache = QPixmap();
}
RippleAnimation::RippleAnimation(const style::RippleAnimation &st, QImage mask, Fn<void()> callback)
: _st(st)
, _mask(App::pixmapFromImageInPlace(std::move(mask)))
, _update(callback) {
@ -141,40 +146,49 @@ RippleAnimation::RippleAnimation(const style::RippleAnimation &st, QImage mask,
void RippleAnimation::add(QPoint origin, int startRadius) {
lastStop();
_ripples.push_back(new Ripple(_st, origin, startRadius, _mask, _update));
_ripples.push_back(std::make_unique<Ripple>(_st, origin, startRadius, _mask, _update));
}
void RippleAnimation::addFading() {
lastStop();
_ripples.push_back(new Ripple(_st, _mask, _update));
_ripples.push_back(std::make_unique<Ripple>(_st, _mask, _update));
}
void RippleAnimation::lastStop() {
if (!_ripples.isEmpty()) {
if (!_ripples.empty()) {
_ripples.back()->stop();
}
}
void RippleAnimation::lastUnstop() {
if (!_ripples.isEmpty()) {
if (!_ripples.empty()) {
_ripples.back()->unstop();
}
}
void RippleAnimation::lastFinish() {
if (!_ripples.isEmpty()) {
if (!_ripples.empty()) {
_ripples.back()->finish();
}
}
void RippleAnimation::forceRepaint() {
for (const auto &ripple : _ripples) {
ripple->clearCache();
}
if (_update) {
_update();
}
}
void RippleAnimation::paint(QPainter &p, int x, int y, int outerWidth, TimeMs ms, const QColor *colorOverride) {
if (_ripples.isEmpty()) {
if (_ripples.empty()) {
return;
}
if (rtl()) x = outerWidth - x - (_mask.width() / cIntRetinaFactor());
p.translate(x, y);
for (auto ripple : _ripples) {
for (const auto &ripple : _ripples) {
ripple->paint(p, _mask, ms, colorOverride);
}
p.translate(-x, -y);
@ -213,16 +227,15 @@ QImage RippleAnimation::ellipseMask(QSize size) {
}
void RippleAnimation::clearFinished() {
while (!_ripples.isEmpty() && _ripples.front()->finished()) {
delete base::take(_ripples.front());
while (!_ripples.empty() && _ripples.front()->finished()) {
_ripples.pop_front();
}
}
void RippleAnimation::clear() {
for (auto ripple : base::take(_ripples)) {
delete ripple;
}
_ripples.clear();
}
RippleAnimation::~RippleAnimation() = default;
} // namespace Ui

View File

@ -13,21 +13,20 @@ namespace Ui {
class RippleAnimation {
public:
using UpdateCallback = Fn<void()>;
// White upon transparent mask, like colorizeImage(black-white-mask, white).
RippleAnimation(const style::RippleAnimation &st, QImage mask, const UpdateCallback &update);
RippleAnimation(const style::RippleAnimation &st, QImage mask, Fn<void()> update);
void add(QPoint origin, int startRadius = 0);
void addFading();
void lastStop();
void lastUnstop();
void lastFinish();
void forceRepaint();
void paint(QPainter &p, int x, int y, int outerWidth, TimeMs ms, const QColor *colorOverride = nullptr);
bool empty() const {
return _ripples.isEmpty();
return _ripples.empty();
}
static QImage maskByDrawer(QSize size, bool filled, Fn<void(QPainter &p)> drawer);
@ -35,9 +34,7 @@ public:
static QImage roundRectMask(QSize size, int radius);
static QImage ellipseMask(QSize size);
~RippleAnimation() {
clear();
}
~RippleAnimation();
private:
void clear();
@ -45,10 +42,10 @@ private:
const style::RippleAnimation &_st;
QPixmap _mask;
UpdateCallback _update;
Fn<void()> _update;
class Ripple;
QList<Ripple*> _ripples;
std::deque<std::unique_ptr<Ripple>> _ripples;
};

View File

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/effects/cross_animation.h"
#include "ui/effects/numbers_animation.h"
#include "ui/image/image_prepare.h"
#include "window/themes/window_theme.h"
#include "lang/lang_instance.h"
namespace Ui {
@ -89,14 +90,25 @@ void RippleButton::setForceRippled(
if (_forceRippled != rippled) {
_forceRippled = rippled;
if (_forceRippled) {
_forceRippledSubscription = base::ObservableViewer(
*Window::Theme::Background()
) | rpl::start_with_next([=](
const Window::Theme::BackgroundUpdate &update) {
if (update.paletteChanged() && _ripple) {
_ripple->forceRepaint();
}
});
ensureRipple();
if (_ripple->empty()) {
_ripple->addFading();
} else {
_ripple->lastUnstop();
}
} else if (_ripple) {
_ripple->lastStop();
} else {
if (_ripple) {
_ripple->lastStop();
}
_forceRippledSubscription.destroy();
}
}
if (animated == anim::type::instant && _ripple) {

View File

@ -73,6 +73,7 @@ private:
const style::RippleAnimation &_st;
std::unique_ptr<RippleAnimation> _ripple;
bool _forceRippled = false;
rpl::lifetime _forceRippledSubscription;
};