| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 |
- // This file is part of Desktop App Toolkit,
- // a set of libraries for developing nice desktop applications.
- //
- // For license and copyright information please follow this link:
- // https://github.com/desktop-app/legal/blob/master/LEGAL
- //
- #include "ui/effects/animations.h"
- #include "base/invoke_queued.h"
- #include "ui/ui_utility.h"
- #include "styles/style_basic.h"
- #include <QtCore/QPointer>
- #include <crl/crl_on_main.h>
- #include <crl/crl.h>
- #include <rpl/filter.h>
- #include <range/v3/algorithm/remove_if.hpp>
- #include <range/v3/algorithm/remove.hpp>
- #include <range/v3/algorithm/find.hpp>
- namespace Ui {
- namespace Animations {
- namespace {
- constexpr auto kAnimationTick = crl::time(1000) / st::universalDuration;
- constexpr auto kIgnoreUpdatesTimeout = crl::time(4);
- Manager *ManagerInstance = nullptr;
- } // namespace
- void Basic::start() {
- Expects(ManagerInstance != nullptr);
- if (animating()) {
- restart();
- } else {
- ManagerInstance->start(this);
- }
- }
- void Basic::stop() {
- Expects(ManagerInstance != nullptr);
- if (animating()) {
- ManagerInstance->stop(this);
- }
- }
- void Basic::restart() {
- Expects(_started >= 0);
- _started = crl::now();
- Ensures(_started >= 0);
- }
- void Basic::markStarted() {
- Expects(_started < 0);
- _started = crl::now();
- Ensures(_started >= 0);
- }
- void Basic::markStopped() {
- Expects(_started >= 0);
- _started = -1;
- }
- Manager::Manager() {
- Expects(ManagerInstance == nullptr);
- ManagerInstance = this;
- crl::on_main_update_requests(
- ) | rpl::filter([=] {
- return (_lastUpdateTime + kIgnoreUpdatesTimeout < crl::now());
- }) | rpl::start_with_next([=] {
- update();
- }, _lifetime);
- }
- Manager::~Manager() {
- Expects(ManagerInstance == this);
- Expects(_active.empty());
- Expects(_starting.empty());
- ManagerInstance = nullptr;
- }
- void Manager::start(not_null<Basic*> animation) {
- _forceImmediateUpdate = true;
- if (_updating) {
- _starting.emplace_back(animation.get());
- } else {
- schedule();
- _active.emplace_back(animation.get());
- }
- }
- void Manager::stop(not_null<Basic*> animation) {
- if (empty(_active) && empty(_starting)) {
- return;
- }
- const auto value = animation.get();
- const auto proj = &ActiveBasicPointer::get;
- auto &list = _updating ? _starting : _active;
- list.erase(ranges::remove(list, value, proj), end(list));
- if (_updating) {
- const auto i = ranges::find(_active, value, proj);
- if (i != end(_active)) {
- *i = nullptr;
- _removedWhileUpdating = true;
- }
- } else if (empty(_active)) {
- stopTimer();
- }
- }
- void Manager::update() {
- if (_active.empty() || _updating || _scheduled) {
- return;
- }
- const auto now = crl::now();
- if (_forceImmediateUpdate) {
- _forceImmediateUpdate = false;
- }
- schedule();
- _updating = true;
- const auto guard = gsl::finally([&] { _updating = false; });
- _lastUpdateTime = now;
- const auto isFinished = [&](const ActiveBasicPointer &element) {
- return !element.call(now);
- };
- _active.erase(ranges::remove_if(_active, isFinished), end(_active));
- if (_removedWhileUpdating) {
- _removedWhileUpdating = false;
- const auto proj = &ActiveBasicPointer::get;
- _active.erase(ranges::remove(_active, nullptr, proj), end(_active));
- }
- if (!empty(_starting)) {
- _active.insert(
- end(_active),
- std::make_move_iterator(begin(_starting)),
- std::make_move_iterator(end(_starting)));
- _starting.clear();
- }
- }
- void Manager::updateQueued() {
- Expects(_timerId == 0);
- _timerId = -1;
- InvokeQueued(delayedCallGuard(), [=] {
- Expects(_timerId < 0);
- _timerId = 0;
- update();
- });
- }
- void Manager::schedule() {
- if (_scheduled || _timerId < 0) {
- return;
- }
- stopTimer();
- _scheduled = true;
- PostponeCall(delayedCallGuard(), [=] {
- _scheduled = false;
- if (_active.empty()) {
- return;
- }
- 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();
- }
- }
- });
- }
- not_null<const QObject*> Manager::delayedCallGuard() const {
- return static_cast<const QObject*>(this);
- }
- void Manager::stopTimer() {
- if (_timerId > 0) {
- killTimer(base::take(_timerId));
- }
- }
- void Manager::timerEvent(QTimerEvent *e) {
- update();
- }
- } // namespace Animations
- } // namespace Ui
|