From 7f7ac64c6de7c045a59b0a2bca55dd19c53441e8 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 9 Dec 2020 15:43:54 +0400 Subject: [PATCH] Init top bar blobs geometry safely. --- Telegram/SourceFiles/calls/calls_top_bar.cpp | 155 ++++++++++--------- Telegram/SourceFiles/calls/calls_top_bar.h | 15 +- Telegram/SourceFiles/mainwidget.cpp | 1 + 3 files changed, 85 insertions(+), 86 deletions(-) diff --git a/Telegram/SourceFiles/calls/calls_top_bar.cpp b/Telegram/SourceFiles/calls/calls_top_bar.cpp index c86897564..7234e03c2 100644 --- a/Telegram/SourceFiles/calls/calls_top_bar.cpp +++ b/Telegram/SourceFiles/calls/calls_top_bar.cpp @@ -226,13 +226,6 @@ TopBar::TopBar( , _mute(this, st::callBarMuteToggle) , _info(this) , _hangup(this, st::callBarHangup) -, _blobs(base::make_unique_q(parent)) -, _blobsPaint(std::make_unique( - LinearBlobs() | ranges::to_vector, - kBlobLevelDuration1, - kBlobLevelDuration2, - 1.)) -, _blobsLevelTimer([=] { _blobsLastLevel = 0.; }) , _gradients(Colors(), QPointF(), QPointF()) , _updateDurationTimer([=] { updateDurationText(); }) { initControls(); @@ -350,30 +343,56 @@ void TopBar::initControls() { } }); updateDurationText(); - - initBlobs(); } -void TopBar::initBlobs() { +void TopBar::initBlobsUnder( + QWidget *blobsParent, + rpl::producer barGeometry) { const auto group = _groupCall.get(); if (!group) { return; } - const auto &hideDuration = kBlobLevelDuration1 * 2; - const auto hideLastTime = _blobs->lifetime().make_state(0); - const auto lastTime = _blobs->lifetime().make_state(0); - const auto blobsRect = - _blobs->lifetime().make_state(_blobs->rect()); + static constexpr auto kHideDuration = kBlobLevelDuration1 * 2; - _blobsAnimation.init([=](crl::time now) { - if (const auto last = *hideLastTime; (last > 0) - && (now - last >= hideDuration)) { - _blobsAnimation.stop(); + struct State { + Ui::Paint::LinearBlobs paint = { + LinearBlobs() | ranges::to_vector, + kBlobLevelDuration1, + kBlobLevelDuration2, + 1. + }; + Ui::Animations::Simple hideAnimation; + Ui::Animations::Basic animation; + base::Timer levelTimer; + crl::time hideLastTime = 0; + crl::time lastTime = 0; + float lastLevel = 0.; + float levelBeforeLast = 0.; + int maxHeight = st::groupCallMinorBlobMinRadius + + st::groupCallMinorBlobMaxRadius; + }; + + _blobs = base::make_unique_q(blobsParent); + + const auto state = _blobs->lifetime().make_state(); + state->levelTimer.setCallback([=] { + state->levelBeforeLast = state->lastLevel; + state->lastLevel = 0.; + if (state->levelBeforeLast == 0.) { + state->paint.setLevel(0.); + state->levelTimer.cancel(); + } + }); + + state->animation.init([=](crl::time now) { + if (const auto last = state->hideLastTime; (last > 0) + && (now - last >= kHideDuration)) { + state->animation.stop(); return false; } - _blobsPaint->updateLevel(now - *lastTime); - *lastTime = now; + state->paint.updateLevel(now - state->lastTime); + state->lastTime = now; _blobs->update(); return true; @@ -408,44 +427,32 @@ void TopBar::initBlobs() { hideBlobs ) | rpl::start_with_next([=](bool hide) { if (hide) { - _blobsPaint->setLevel(0.); + state->paint.setLevel(0.); } - *hideLastTime = hide ? crl::now() : 0; - if (!hide && !_blobsAnimation.animating()) { - _blobsAnimation.start(); + state->hideLastTime = hide ? crl::now() : 0; + if (!hide && !state->animation.animating()) { + state->animation.start(); } if (hide) { - _blobsLevelTimer.cancel(); + state->levelTimer.cancel(); } else { - _blobsLastLevel = 0.; - _blobsLevelTimer.callEach(kBlobUpdateInterval); + state->lastLevel = 0.; } const auto from = hide ? 0. : 1.; const auto to = hide ? 1. : 0.; - _blobsHideAnimation.start([=](float64 value) { - blobsRect->setHeight(anim::interpolate(0, -20, value)); - }, from, to, hideDuration); + state->hideAnimation.start([=](float64) { + _blobs->update(); + }, from, to, kHideDuration); }, lifetime()); - /// - - const auto parent = static_cast(parentWidget()); - geometryValue( + std::move( + barGeometry ) | rpl::start_with_next([=](QRect rect) { - _blobs->resize(rect.width(), rect.height()); - - { - const auto &r = _blobs->rect(); - *blobsRect = QRect( - r.x(), - r.y(), - r.width() + st::groupCallBlobWidthAdditional, - 0); - } - - const auto relativePos = mapTo(parent, rect.topLeft()); - _blobs->moveToLeft(relativePos.x(), relativePos.y() + rect.height()); + _blobs->resize( + rect.width(), + std::min(state->maxHeight, rect.height())); + _blobs->moveToLeft(rect.x(), rect.y() + rect.height()); }, lifetime()); shownValue( @@ -455,44 +462,42 @@ void TopBar::initBlobs() { _blobs->paintRequest( ) | rpl::start_with_next([=](QRect clip) { - Painter p(_blobs); - - const auto alpha = 1. - _blobsHideAnimation.value(0.); - if (alpha < 1.) { - p.setOpacity(alpha); + const auto hidden = state->hideAnimation.value( + state->hideLastTime ? 1. : 0.); + if (hidden == 1.) { + return; } - _blobsPaint->paint(p, _groupBrush, *blobsRect, 0, 0); - }, _blobs->lifetime()); - rpl::single( - ) | rpl::then( - events( - ) | rpl::filter([](not_null e) { - return e->type() == QEvent::ZOrderChange; - }) | rpl::to_empty - ) | rpl::start_with_next([=] { - crl::on_main(_blobs.get(), [=] { - _blobs->raise(); - }); - }, lifetime()); + Painter p(_blobs); + if (hidden > 0.) { + p.setOpacity(1. - hidden); + } + const auto top = -_blobs->height() * hidden; + const auto drawUnder = QRect( + 0, + top, + _blobs->width() + st::groupCallBlobWidthAdditional, + 0); + state->paint.paint(p, _groupBrush, drawUnder, 0, 0); + }, _blobs->lifetime()); group->levelUpdates( ) | rpl::filter([=](const LevelUpdate &update) { - return !*hideLastTime && (update.value > _blobsLastLevel); + return !state->hideLastTime && (update.value > state->lastLevel); }) | rpl::start_with_next([=](const LevelUpdate &update) { - _blobsLastLevel = update.value; - _blobsPaint->setLevel(_blobsLastLevel); + if (state->lastLevel == 0.) { + state->levelTimer.callEach(kBlobUpdateInterval); + } + state->lastLevel = update.value; + state->paint.setLevel(update.value); }, _blobs->lifetime()); _blobs->setAttribute(Qt::WA_TransparentForMouseEvents); _blobs->show(); - _blobsAnimation.start(); - crl::on_main([=] { - const auto r = rect(); - const auto relativePos = mapTo(parent, r.topLeft()); - _blobs->moveToLeft(relativePos.x(), relativePos.y() + r.height()); - }); + if (!state->hideLastTime) { + state->animation.start(); + } } void TopBar::subscribeToMembersChanges(not_null call) { diff --git a/Telegram/SourceFiles/calls/calls_top_bar.h b/Telegram/SourceFiles/calls/calls_top_bar.h index e9ea27513..a87eb14f6 100644 --- a/Telegram/SourceFiles/calls/calls_top_bar.h +++ b/Telegram/SourceFiles/calls/calls_top_bar.h @@ -20,9 +20,6 @@ class IconButton; class AbstractButton; class LabelSimple; class FlatLabel; -namespace Paint { -class LinearBlobs; -} // namespace Paint } // namespace Ui namespace Main { @@ -41,9 +38,12 @@ class TopBar : public Ui::RpWidget { public: TopBar(QWidget *parent, const base::weak_ptr &call); TopBar(QWidget *parent, const base::weak_ptr &call); - ~TopBar(); + void initBlobsUnder( + QWidget *blobsParent, + rpl::producer barGeometry); + protected: void resizeEvent(QResizeEvent *e) override; void paintEvent(QPaintEvent *e) override; @@ -55,7 +55,6 @@ private: const base::weak_ptr &groupCall); void initControls(); - void initBlobs(); void updateInfoLabels(); void setInfoLabels(); void updateDurationText(); @@ -79,17 +78,11 @@ private: object_ptr _info; object_ptr _hangup; base::unique_qptr _blobs; - std::unique_ptr _blobsPaint; - float _blobsLastLevel = 0.; - base::Timer _blobsLevelTimer; QBrush _groupBrush; anim::linear_gradients _gradients; Ui::Animations::Simple _switchStateAnimation; - Ui::Animations::Simple _blobsHideAnimation; - Ui::Animations::Basic _blobsAnimation; - base::Timer _updateDurationTimer; }; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index bf47f7455..6802e12ba 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -1000,6 +1000,7 @@ void MainWidget::createCallTopBar() { (_currentCall ? object_ptr(this, _currentCall) : object_ptr(this, _currentGroupCall))); + _callTopBar->entity()->initBlobsUnder(this, _callTopBar->geometryValue()); _callTopBar->heightValue( ) | rpl::start_with_next([this](int value) { callTopBarHeightUpdated(value);