Fix new animations engine restarts.

This commit is contained in:
John Preston 2019-03-11 11:11:02 +04:00
parent b0ff443eac
commit aa00f9bd34
2 changed files with 90 additions and 18 deletions

View File

@ -20,19 +20,37 @@ constexpr auto kIgnoreUpdatesTimeout = crl::time(4);
} // namespace } // namespace
void Basic::start() { void Basic::start() {
if (!animating()) { if (animating()) {
restart();
} else {
Core::App().animationManager().start(this); Core::App().animationManager().start(this);
} }
_started = crl::now();
} }
void Basic::stop() { void Basic::stop() {
if (animating()) { if (animating()) {
Core::App().animationManager().stop(this); Core::App().animationManager().stop(this);
_started = -1;
} }
} }
void Basic::restart() {
Expects(_started >= 0);
_started = crl::now();
}
void Basic::markStarted() {
Expects(_started < 0);
_started = crl::now();
}
void Basic::markStopped() {
Expects(_started >= 0);
_started = -1;
}
Manager::Manager() { Manager::Manager() {
Core::Sandbox::Instance().widgetUpdateRequests( Core::Sandbox::Instance().widgetUpdateRequests(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
@ -42,28 +60,30 @@ Manager::Manager() {
void Manager::start(not_null<Basic*> animation) { void Manager::start(not_null<Basic*> animation) {
if (_updating) { if (_updating) {
_starting.push_back(animation); _starting.emplace_back(animation.get());
} else { } else {
if (empty(_active)) { if (empty(_active)) {
updateQueued(); updateQueued();
} }
_active.push_back(animation); _active.emplace_back(animation.get());
} }
} }
void Manager::stop(not_null<Basic*> animation) { void Manager::stop(not_null<Basic*> animation) {
if (empty(_active)) { if (empty(_active) && empty(_starting)) {
return; 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) { if (_updating) {
const auto i = ranges::find(_active, animation.get()); const auto i = ranges::find(_active, value, proj);
if (i != end(_active)) { if (i != end(_active)) {
*i = nullptr; *i = nullptr;
} }
return; } else if (empty(_active)) {
}
_active.erase(ranges::remove(_active, animation.get()), end(_active));
if (empty(_active)) {
stopTimer(); stopTimer();
} }
} }
@ -82,13 +102,17 @@ void Manager::update() {
const auto guard = gsl::finally([&] { _updating = false; }); const auto guard = gsl::finally([&] { _updating = false; });
_lastUpdateTime = now; _lastUpdateTime = now;
_active.erase(ranges::remove_if(_active, [&](Basic *element) { const auto isFinished = [&](const ActiveBasicPointer &element) {
return !element || !element->call(now); return !element.call(now);
}), end(_active)); };
_active.erase(ranges::remove_if(_active, isFinished), end(_active));
if (!empty(_starting)) { if (!empty(_starting)) {
auto starting = std::move(_starting); _active.insert(
_active.insert(end(_active), begin(starting), end(starting)); end(_active),
std::make_move_iterator(begin(_starting)),
std::make_move_iterator(end(_starting)));
_starting.clear();
} }
} }

View File

@ -37,6 +37,10 @@ private:
[[nodiscard]] static Fn<bool(crl::time)> Prepare(Callback &&callback); [[nodiscard]] static Fn<bool(crl::time)> Prepare(Callback &&callback);
[[nodiscard]] bool call(crl::time now) const; [[nodiscard]] bool call(crl::time now) const;
void restart();
void markStarted();
void markStopped();
crl::time _started = -1; crl::time _started = -1;
Fn<bool(crl::time)> _callback; Fn<bool(crl::time)> _callback;
@ -98,6 +102,50 @@ public:
void update(); void update();
private: private:
class ActiveBasicPointer {
public:
ActiveBasicPointer(Basic *value = nullptr) : _value(value) {
if (_value) {
_value->markStarted();
}
}
ActiveBasicPointer(ActiveBasicPointer &&other)
: _value(base::take(other._value)) {
}
ActiveBasicPointer &operator=(ActiveBasicPointer &&other) {
if (_value != other._value) {
if (_value) {
_value->markStopped();
}
_value = base::take(other._value);
}
return *this;
}
~ActiveBasicPointer() {
if (_value) {
_value->markStopped();
}
}
[[nodiscard]] bool call(crl::time now) const {
return _value && _value->call(now);
}
friend inline bool operator==(
const ActiveBasicPointer &a,
const ActiveBasicPointer &b) {
return a._value == b._value;
}
Basic *get() const {
return _value;
}
private:
Basic *_value = nullptr;
};
friend class Basic; friend class Basic;
void timerEvent(QTimerEvent *e) override; void timerEvent(QTimerEvent *e) override;
@ -113,8 +161,8 @@ private:
int _timerId = 0; int _timerId = 0;
bool _updating = false; bool _updating = false;
bool _scheduled = false; bool _scheduled = false;
std::vector<Basic*> _active; std::vector<ActiveBasicPointer> _active;
std::vector<not_null<Basic*>> _starting; std::vector<ActiveBasicPointer> _starting;
rpl::lifetime _lifetime; rpl::lifetime _lifetime;
}; };