Init top bar blobs geometry safely.

This commit is contained in:
John Preston 2020-12-09 15:43:54 +04:00
parent 9f2903f81d
commit 7f7ac64c6d
3 changed files with 85 additions and 86 deletions

View file

@ -226,13 +226,6 @@ TopBar::TopBar(
, _mute(this, st::callBarMuteToggle) , _mute(this, st::callBarMuteToggle)
, _info(this) , _info(this)
, _hangup(this, st::callBarHangup) , _hangup(this, st::callBarHangup)
, _blobs(base::make_unique_q<Ui::RpWidget>(parent))
, _blobsPaint(std::make_unique<Ui::Paint::LinearBlobs>(
LinearBlobs() | ranges::to_vector,
kBlobLevelDuration1,
kBlobLevelDuration2,
1.))
, _blobsLevelTimer([=] { _blobsLastLevel = 0.; })
, _gradients(Colors(), QPointF(), QPointF()) , _gradients(Colors(), QPointF(), QPointF())
, _updateDurationTimer([=] { updateDurationText(); }) { , _updateDurationTimer([=] { updateDurationText(); }) {
initControls(); initControls();
@ -350,30 +343,56 @@ void TopBar::initControls() {
} }
}); });
updateDurationText(); updateDurationText();
initBlobs();
} }
void TopBar::initBlobs() { void TopBar::initBlobsUnder(
QWidget *blobsParent,
rpl::producer<QRect> barGeometry) {
const auto group = _groupCall.get(); const auto group = _groupCall.get();
if (!group) { if (!group) {
return; return;
} }
const auto &hideDuration = kBlobLevelDuration1 * 2; static constexpr auto kHideDuration = kBlobLevelDuration1 * 2;
const auto hideLastTime = _blobs->lifetime().make_state<crl::time>(0);
const auto lastTime = _blobs->lifetime().make_state<crl::time>(0);
const auto blobsRect =
_blobs->lifetime().make_state<QRect>(_blobs->rect());
_blobsAnimation.init([=](crl::time now) { struct State {
if (const auto last = *hideLastTime; (last > 0) Ui::Paint::LinearBlobs paint = {
&& (now - last >= hideDuration)) { LinearBlobs() | ranges::to_vector,
_blobsAnimation.stop(); 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<Ui::RpWidget>(blobsParent);
const auto state = _blobs->lifetime().make_state<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; return false;
} }
_blobsPaint->updateLevel(now - *lastTime); state->paint.updateLevel(now - state->lastTime);
*lastTime = now; state->lastTime = now;
_blobs->update(); _blobs->update();
return true; return true;
@ -408,44 +427,32 @@ void TopBar::initBlobs() {
hideBlobs hideBlobs
) | rpl::start_with_next([=](bool hide) { ) | rpl::start_with_next([=](bool hide) {
if (hide) { if (hide) {
_blobsPaint->setLevel(0.); state->paint.setLevel(0.);
} }
*hideLastTime = hide ? crl::now() : 0; state->hideLastTime = hide ? crl::now() : 0;
if (!hide && !_blobsAnimation.animating()) { if (!hide && !state->animation.animating()) {
_blobsAnimation.start(); state->animation.start();
} }
if (hide) { if (hide) {
_blobsLevelTimer.cancel(); state->levelTimer.cancel();
} else { } else {
_blobsLastLevel = 0.; state->lastLevel = 0.;
_blobsLevelTimer.callEach(kBlobUpdateInterval);
} }
const auto from = hide ? 0. : 1.; const auto from = hide ? 0. : 1.;
const auto to = hide ? 1. : 0.; const auto to = hide ? 1. : 0.;
_blobsHideAnimation.start([=](float64 value) { state->hideAnimation.start([=](float64) {
blobsRect->setHeight(anim::interpolate(0, -20, value)); _blobs->update();
}, from, to, hideDuration); }, from, to, kHideDuration);
}, lifetime()); }, lifetime());
/// std::move(
barGeometry
const auto parent = static_cast<Ui::RpWidget*>(parentWidget());
geometryValue(
) | rpl::start_with_next([=](QRect rect) { ) | rpl::start_with_next([=](QRect rect) {
_blobs->resize(rect.width(), rect.height()); _blobs->resize(
rect.width(),
{ std::min(state->maxHeight, rect.height()));
const auto &r = _blobs->rect(); _blobs->moveToLeft(rect.x(), rect.y() + rect.height());
*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());
}, lifetime()); }, lifetime());
shownValue( shownValue(
@ -455,44 +462,42 @@ void TopBar::initBlobs() {
_blobs->paintRequest( _blobs->paintRequest(
) | rpl::start_with_next([=](QRect clip) { ) | rpl::start_with_next([=](QRect clip) {
Painter p(_blobs); const auto hidden = state->hideAnimation.value(
state->hideLastTime ? 1. : 0.);
const auto alpha = 1. - _blobsHideAnimation.value(0.); if (hidden == 1.) {
if (alpha < 1.) { return;
p.setOpacity(alpha);
} }
_blobsPaint->paint(p, _groupBrush, *blobsRect, 0, 0);
}, _blobs->lifetime());
rpl::single( Painter p(_blobs);
) | rpl::then( if (hidden > 0.) {
events( p.setOpacity(1. - hidden);
) | rpl::filter([](not_null<QEvent*> e) { }
return e->type() == QEvent::ZOrderChange; const auto top = -_blobs->height() * hidden;
}) | rpl::to_empty const auto drawUnder = QRect(
) | rpl::start_with_next([=] { 0,
crl::on_main(_blobs.get(), [=] { top,
_blobs->raise(); _blobs->width() + st::groupCallBlobWidthAdditional,
}); 0);
}, lifetime()); state->paint.paint(p, _groupBrush, drawUnder, 0, 0);
}, _blobs->lifetime());
group->levelUpdates( group->levelUpdates(
) | rpl::filter([=](const LevelUpdate &update) { ) | rpl::filter([=](const LevelUpdate &update) {
return !*hideLastTime && (update.value > _blobsLastLevel); return !state->hideLastTime && (update.value > state->lastLevel);
}) | rpl::start_with_next([=](const LevelUpdate &update) { }) | rpl::start_with_next([=](const LevelUpdate &update) {
_blobsLastLevel = update.value; if (state->lastLevel == 0.) {
_blobsPaint->setLevel(_blobsLastLevel); state->levelTimer.callEach(kBlobUpdateInterval);
}
state->lastLevel = update.value;
state->paint.setLevel(update.value);
}, _blobs->lifetime()); }, _blobs->lifetime());
_blobs->setAttribute(Qt::WA_TransparentForMouseEvents); _blobs->setAttribute(Qt::WA_TransparentForMouseEvents);
_blobs->show(); _blobs->show();
_blobsAnimation.start();
crl::on_main([=] { if (!state->hideLastTime) {
const auto r = rect(); state->animation.start();
const auto relativePos = mapTo(parent, r.topLeft()); }
_blobs->moveToLeft(relativePos.x(), relativePos.y() + r.height());
});
} }
void TopBar::subscribeToMembersChanges(not_null<GroupCall*> call) { void TopBar::subscribeToMembersChanges(not_null<GroupCall*> call) {

View file

@ -20,9 +20,6 @@ class IconButton;
class AbstractButton; class AbstractButton;
class LabelSimple; class LabelSimple;
class FlatLabel; class FlatLabel;
namespace Paint {
class LinearBlobs;
} // namespace Paint
} // namespace Ui } // namespace Ui
namespace Main { namespace Main {
@ -41,9 +38,12 @@ class TopBar : public Ui::RpWidget {
public: public:
TopBar(QWidget *parent, const base::weak_ptr<Call> &call); TopBar(QWidget *parent, const base::weak_ptr<Call> &call);
TopBar(QWidget *parent, const base::weak_ptr<GroupCall> &call); TopBar(QWidget *parent, const base::weak_ptr<GroupCall> &call);
~TopBar(); ~TopBar();
void initBlobsUnder(
QWidget *blobsParent,
rpl::producer<QRect> barGeometry);
protected: protected:
void resizeEvent(QResizeEvent *e) override; void resizeEvent(QResizeEvent *e) override;
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
@ -55,7 +55,6 @@ private:
const base::weak_ptr<GroupCall> &groupCall); const base::weak_ptr<GroupCall> &groupCall);
void initControls(); void initControls();
void initBlobs();
void updateInfoLabels(); void updateInfoLabels();
void setInfoLabels(); void setInfoLabels();
void updateDurationText(); void updateDurationText();
@ -79,17 +78,11 @@ private:
object_ptr<Ui::AbstractButton> _info; object_ptr<Ui::AbstractButton> _info;
object_ptr<Ui::IconButton> _hangup; object_ptr<Ui::IconButton> _hangup;
base::unique_qptr<Ui::RpWidget> _blobs; base::unique_qptr<Ui::RpWidget> _blobs;
std::unique_ptr<Ui::Paint::LinearBlobs> _blobsPaint;
float _blobsLastLevel = 0.;
base::Timer _blobsLevelTimer;
QBrush _groupBrush; QBrush _groupBrush;
anim::linear_gradients<MuteState> _gradients; anim::linear_gradients<MuteState> _gradients;
Ui::Animations::Simple _switchStateAnimation; Ui::Animations::Simple _switchStateAnimation;
Ui::Animations::Simple _blobsHideAnimation;
Ui::Animations::Basic _blobsAnimation;
base::Timer _updateDurationTimer; base::Timer _updateDurationTimer;
}; };

View file

@ -1000,6 +1000,7 @@ void MainWidget::createCallTopBar() {
(_currentCall (_currentCall
? object_ptr<Calls::TopBar>(this, _currentCall) ? object_ptr<Calls::TopBar>(this, _currentCall)
: object_ptr<Calls::TopBar>(this, _currentGroupCall))); : object_ptr<Calls::TopBar>(this, _currentGroupCall)));
_callTopBar->entity()->initBlobsUnder(this, _callTopBar->geometryValue());
_callTopBar->heightValue( _callTopBar->heightValue(
) | rpl::start_with_next([this](int value) { ) | rpl::start_with_next([this](int value) {
callTopBarHeightUpdated(value); callTopBarHeightUpdated(value);