tdesktop/Telegram/SourceFiles/ui/effects/animations.cpp

175 lines
3.4 KiB
C++
Raw Normal View History

2019-02-04 13:34:50 +00:00
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "ui/effects/animations.h"
#include "core/application.h"
namespace Ui {
namespace Animations {
namespace {
constexpr auto kAnimationTick = crl::time(1000) / 120;
2019-02-04 13:34:50 +00:00
constexpr auto kIgnoreUpdatesTimeout = crl::time(4);
} // namespace
void Basic::start() {
2019-03-11 07:11:02 +00:00
if (animating()) {
restart();
} else {
2019-02-04 13:34:50 +00:00
Core::App().animationManager().start(this);
}
}
void Basic::stop() {
if (animating()) {
Core::App().animationManager().stop(this);
}
}
2019-03-11 07:11:02 +00:00
void Basic::restart() {
Expects(_started >= 0);
_started = crl::now();
Ensures(_started >= 0);
2019-03-11 07:11:02 +00:00
}
void Basic::markStarted() {
Expects(_started < 0);
_started = crl::now();
Ensures(_started >= 0);
2019-03-11 07:11:02 +00:00
}
void Basic::markStopped() {
Expects(_started >= 0);
_started = -1;
}
2019-03-07 13:23:19 +00:00
Manager::Manager() {
2019-05-28 11:39:38 +00:00
crl::on_main_update_requests(
) | rpl::filter([=] {
2019-04-04 15:20:28 +00:00
return (_lastUpdateTime + kIgnoreUpdatesTimeout < crl::now());
}) | rpl::start_with_next([=] {
update();
2019-03-07 13:23:19 +00:00
}, _lifetime);
}
2019-02-04 13:34:50 +00:00
void Manager::start(not_null<Basic*> animation) {
_forceImmediateUpdate = true;
2019-02-04 13:34:50 +00:00
if (_updating) {
2019-03-11 07:11:02 +00:00
_starting.emplace_back(animation.get());
} else {
schedule();
_active.emplace_back(animation.get());
2019-02-04 13:34:50 +00:00
}
}
void Manager::stop(not_null<Basic*> animation) {
2019-03-11 07:11:02 +00:00
if (empty(_active) && empty(_starting)) {
2019-02-04 13:34:50 +00:00
return;
}
2019-03-11 07:11:02 +00:00
const auto value = animation.get();
const auto proj = &ActiveBasicPointer::get;
auto &list = _updating ? _starting : _active;
list.erase(ranges::remove(list, value, proj), end(list));
2019-02-04 13:34:50 +00:00
if (_updating) {
2019-03-11 07:11:02 +00:00
const auto i = ranges::find(_active, value, proj);
2019-02-04 13:34:50 +00:00
if (i != end(_active)) {
*i = nullptr;
}
2019-03-11 07:11:02 +00:00
} else if (empty(_active)) {
2019-02-04 13:34:50 +00:00
stopTimer();
}
}
void Manager::update() {
if (_active.empty() || _updating || _scheduled) {
2019-02-04 13:34:50 +00:00
return;
}
const auto now = crl::now();
if (_forceImmediateUpdate) {
_forceImmediateUpdate = false;
2019-02-04 13:34:50 +00:00
}
schedule();
2019-02-04 13:34:50 +00:00
_updating = true;
const auto guard = gsl::finally([&] { _updating = false; });
_lastUpdateTime = now;
2019-03-11 07:11:02 +00:00
const auto isFinished = [&](const ActiveBasicPointer &element) {
return !element.call(now);
};
_active.erase(ranges::remove_if(_active, isFinished), end(_active));
2019-02-04 13:34:50 +00:00
if (!empty(_starting)) {
_active.insert(
end(_active),
std::make_move_iterator(begin(_starting)),
std::make_move_iterator(end(_starting)));
_starting.clear();
2019-02-04 13:34:50 +00:00
}
}
void Manager::updateQueued() {
Expects(_timerId == 0);
_timerId = -1;
InvokeQueued(delayedCallGuard(), [=] {
Expects(_timerId < 0);
_timerId = 0;
update();
});
}
void Manager::schedule() {
if (_scheduled || _timerId < 0) {
2019-02-04 13:34:50 +00:00
return;
}
stopTimer();
_scheduled = true;
Ui::PostponeCall(delayedCallGuard(), [=] {
_scheduled = false;
if (_forceImmediateUpdate) {
_forceImmediateUpdate = false;
updateQueued();
} else {
const auto next = _lastUpdateTime + kAnimationTick;
const auto now = crl::now();
if (now < next) {
_timerId = startTimer(next - now, Qt::PreciseTimer);
} else {
updateQueued();
}
}
2019-02-04 13:34:50 +00:00
});
}
not_null<const QObject*> Manager::delayedCallGuard() const {
return static_cast<const QObject*>(this);
}
2019-02-04 13:34:50 +00:00
void Manager::stopTimer() {
if (_timerId > 0) {
killTimer(base::take(_timerId));
2019-02-04 13:34:50 +00:00
}
}
void Manager::timerEvent(QTimerEvent *e) {
update();
2019-02-04 13:34:50 +00:00
}
} // namespace Animations
} // namespace Ui