Optimized drawing of ministars in premium settings.

This commit is contained in:
23rd 2022-05-29 06:50:29 +03:00
parent ea0466aaa3
commit f1ebf3d9f6

View file

@ -217,7 +217,7 @@ void SendScreenAccept(not_null<Window::SessionController*> controller) {
class MiniStars final { class MiniStars final {
public: public:
MiniStars(Fn<void()> updateCallback); MiniStars(Fn<void(const QRect &r)> updateCallback);
void paint(Painter &p, const QRectF &rect); void paint(Painter &p, const QRectF &rect);
@ -260,9 +260,11 @@ private:
crl::time _nextBirthTime = 0; crl::time _nextBirthTime = 0;
QRect _rectToUpdate;
}; };
MiniStars::MiniStars(Fn<void()> updateCallback) MiniStars::MiniStars(Fn<void(const QRect &r)> updateCallback)
: _availableAngles({ : _availableAngles({
Interval{ -10, 40 }, Interval{ -10, 40 },
Interval{ 180 + 10 - 40, 40 }, Interval{ 180 + 10 - 40, 40 },
@ -283,14 +285,16 @@ MiniStars::MiniStars(Fn<void()> updateCallback)
createStar(now); createStar(now);
_nextBirthTime = now + randomInterval(_lifeLength); _nextBirthTime = now + randomInterval(_lifeLength);
} }
updateCallback(); if (_rectToUpdate.isValid()) {
updateCallback(base::take(_rectToUpdate));
}
}) { }) {
if (anim::Disabled()) { if (anim::Disabled()) {
const auto from = _deathTime.from + _deathTime.length; const auto from = _deathTime.from + _deathTime.length;
for (auto i = -from; i < 0; i += randomInterval(_lifeLength)) { for (auto i = -from; i < 0; i += randomInterval(_lifeLength)) {
createStar(i); createStar(i);
} }
updateCallback(); updateCallback(_rectToUpdate);
} else { } else {
_animation.start(); _animation.start();
} }
@ -346,7 +350,7 @@ void MiniStars::paint(Painter &p, const QRectF &rect) {
const auto starHeight = starSide const auto starHeight = starSide
* (!widthFade ? alphaProgress : 1.) * (!widthFade ? alphaProgress : 1.)
* deformH; * deformH;
_sprite.render(&p, QRectF( const auto renderRect = QRectF(
center.x() center.x()
+ anim::interpolateF(0, end.x(), distanceProgress) + anim::interpolateF(0, end.x(), distanceProgress)
- starWidth / 2., - starWidth / 2.,
@ -354,7 +358,9 @@ void MiniStars::paint(Painter &p, const QRectF &rect) {
+ anim::interpolateF(0, end.y(), distanceProgress) + anim::interpolateF(0, end.y(), distanceProgress)
- starHeight / 2., - starHeight / 2.,
starWidth, starWidth,
starHeight)); starHeight);
_sprite.render(&p, renderRect);
_rectToUpdate |= renderRect.toRect();
} }
p.setOpacity(opacity); p.setOpacity(opacity);
} }
@ -393,8 +399,13 @@ public:
protected: protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
void resizeEvent(QResizeEvent *e) override;
private: private:
[[nodiscard]] QRectF starRect(
float64 topProgress,
float64 sizeProgress) const;
const style::font &_titleFont; const style::font &_titleFont;
const style::margins &_titlePadding; const style::margins &_titlePadding;
const style::TextStyle &_aboutSt; const style::TextStyle &_aboutSt;
@ -402,6 +413,16 @@ private:
QSvgRenderer _star; QSvgRenderer _star;
Ui::Text::String _about; Ui::Text::String _about;
struct {
float64 top = 0.;
float64 body = 0.;
float64 title = 0.;
float64 scaleTitle = 0.;
} _progress;
QRectF _ministarsRect;
QRectF _starRect;
QPoint _titlePosition; QPoint _titlePosition;
QPainterPath _titlePath; QPainterPath _titlePath;
bool _roundEdges = true; bool _roundEdges = true;
@ -413,7 +434,7 @@ TopBar::TopBar(not_null<QWidget*> parent)
, _titleFont(st::boxTitle.style.font) , _titleFont(st::boxTitle.style.font)
, _titlePadding(st::settingsPremiumTitlePadding) , _titlePadding(st::settingsPremiumTitlePadding)
, _aboutSt(st::settingsPremiumAboutTextStyle) , _aboutSt(st::settingsPremiumAboutTextStyle)
, _ministars([=] { update(); }) , _ministars([=](const QRect &r) { update(r); })
, _star(u":/gui/icons/settings/star.svg"_q) { , _star(u":/gui/icons/settings/star.svg"_q) {
_titlePath.addText( _titlePath.addText(
0, 0,
@ -434,19 +455,37 @@ void TopBar::setTextPosition(int x, int y) {
_titlePosition = { x, y }; _titlePosition = { x, y };
} }
void TopBar::paintEvent(QPaintEvent *e) { QRectF TopBar::starRect(float64 topProgress, float64 sizeProgress) const {
Painter p(this); const auto starSize = st::settingsPremiumStarSize * sizeProgress;
return QRectF(
QPointF(
(width() - starSize.width()) / 2,
st::settingsPremiumStarTopSkip * topProgress),
starSize);
};
p.fillRect(e->rect(), Qt::transparent); void TopBar::resizeEvent(QResizeEvent *e) {
const auto progress = (e->size().height() - minimumHeight())
const auto progress = (height() - minimumHeight())
/ float64(maximumHeight() - minimumHeight()); / float64(maximumHeight() - minimumHeight());
const auto topProgress = 1. - _progress.top = 1. -
std::clamp( std::clamp(
(1. - progress) / kBodyAnimationPart, (1. - progress) / kBodyAnimationPart,
0., 0.,
1.); 1.);
const auto bodyProgress = topProgress; _progress.body = _progress.top;
_progress.title = 1. - progress;
_progress.scaleTitle = 1. + kTitleAdditionalScale * progress;
_ministarsRect = starRect(_progress.top, 1.);
_starRect = starRect(_progress.top, _progress.body);
Ui::RpWidget::resizeEvent(e);
}
void TopBar::paintEvent(QPaintEvent *e) {
Painter p(this);
p.fillRect(e->rect(), Qt::transparent);
const auto r = rect(); const auto r = rect();
auto pathTop = QPainterPath(); auto pathTop = QPainterPath();
@ -472,32 +511,23 @@ void TopBar::paintEvent(QPaintEvent *e) {
PainterHighQualityEnabler hq(p); PainterHighQualityEnabler hq(p);
p.fillPath(pathTop + pathBottom, gradient); p.fillPath(pathTop + pathBottom, gradient);
p.setOpacity(bodyProgress); p.setOpacity(_progress.body);
p.translate(_starRect.center());
const auto starRect = [&](float64 topProgress, float64 sizeProgress) { p.scale(_progress.body, _progress.body);
const auto starSize = st::settingsPremiumStarSize * sizeProgress; p.translate(-_starRect.center());
return QRectF( if (_progress.top) {
QPointF( _ministars.paint(p, _ministarsRect);
(width() - starSize.width()) / 2, }
st::settingsPremiumStarTopSkip * topProgress),
starSize);
};
const auto currentStarRect = starRect(topProgress, bodyProgress);
p.translate(currentStarRect.center());
p.scale(bodyProgress, bodyProgress);
p.translate(-currentStarRect.center());
_ministars.paint(p, starRect(topProgress, 1.));
p.resetTransform(); p.resetTransform();
_star.render(&p, currentStarRect); _star.render(&p, _starRect);
p.setPen(st::premiumButtonFg); p.setPen(st::premiumButtonFg);
const auto &padding = st::boxRowPadding; const auto &padding = st::boxRowPadding;
const auto availableWidth = width() - padding.left() - padding.right(); const auto availableWidth = width() - padding.left() - padding.right();
const auto titleTop = currentStarRect.top() const auto titleTop = _starRect.top()
+ currentStarRect.height() + _starRect.height()
+ _titlePadding.top(); + _titlePadding.top();
const auto titlePathRect = _titlePath.boundingRect(); const auto titlePathRect = _titlePath.boundingRect();
const auto aboutTop = titleTop const auto aboutTop = titleTop
@ -510,7 +540,6 @@ void TopBar::paintEvent(QPaintEvent *e) {
// Title. // Title.
p.setOpacity(1.); p.setOpacity(1.);
p.setFont(_titleFont); p.setFont(_titleFont);
const auto titleProgress = 1. - progress;
const auto fullStarRect = starRect(1., 1.); const auto fullStarRect = starRect(1., 1.);
const auto fullTitleTop = fullStarRect.top() const auto fullTitleTop = fullStarRect.top()
+ fullStarRect.height() + fullStarRect.height()
@ -519,12 +548,11 @@ void TopBar::paintEvent(QPaintEvent *e) {
anim::interpolate( anim::interpolate(
(width() - titlePathRect.width()) / 2, (width() - titlePathRect.width()) / 2,
_titlePosition.x(), _titlePosition.x(),
titleProgress), _progress.title),
anim::interpolate(fullTitleTop, _titlePosition.y(), titleProgress)); anim::interpolate(fullTitleTop, _titlePosition.y(), _progress.title));
const auto scale = 1. + kTitleAdditionalScale * (1. - titleProgress);
p.translate(titlePathRect.center()); p.translate(titlePathRect.center());
p.scale(scale, scale); p.scale(_progress.scaleTitle, _progress.scaleTitle);
p.translate(-titlePathRect.center()); p.translate(-titlePathRect.center());
p.fillPath(_titlePath, st::premiumButtonFg); p.fillPath(_titlePath, st::premiumButtonFg);
} }