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)
, _info(this)
, _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())
, _updateDurationTimer([=] { updateDurationText(); }) {
initControls();
@ -350,30 +343,56 @@ void TopBar::initControls() {
}
});
updateDurationText();
initBlobs();
}
void TopBar::initBlobs() {
void TopBar::initBlobsUnder(
QWidget *blobsParent,
rpl::producer<QRect> barGeometry) {
const auto group = _groupCall.get();
if (!group) {
return;
}
const auto &hideDuration = 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());
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<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;
}
_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<Ui::RpWidget*>(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<QEvent*> 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<GroupCall*> call) {

View File

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

View File

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