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
void Basic::start() {
if (!animating()) {
if (animating()) {
restart();
} else {
Core::App().animationManager().start(this);
}
_started = crl::now();
}
void Basic::stop() {
if (animating()) {
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() {
Core::Sandbox::Instance().widgetUpdateRequests(
) | rpl::start_with_next([=] {
@ -42,28 +60,30 @@ Manager::Manager() {
void Manager::start(not_null<Basic*> animation) {
if (_updating) {
_starting.push_back(animation);
_starting.emplace_back(animation.get());
} else {
if (empty(_active)) {
updateQueued();
}
_active.push_back(animation);
_active.emplace_back(animation.get());
}
}
void Manager::stop(not_null<Basic*> animation) {
if (empty(_active)) {
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, animation.get());
const auto i = ranges::find(_active, value, proj);
if (i != end(_active)) {
*i = nullptr;
}
return;
}
_active.erase(ranges::remove(_active, animation.get()), end(_active));
if (empty(_active)) {
} else if (empty(_active)) {
stopTimer();
}
}
@ -82,13 +102,17 @@ void Manager::update() {
const auto guard = gsl::finally([&] { _updating = false; });
_lastUpdateTime = now;
_active.erase(ranges::remove_if(_active, [&](Basic *element) {
return !element || !element->call(now);
}), end(_active));
const auto isFinished = [&](const ActiveBasicPointer &element) {
return !element.call(now);
};
_active.erase(ranges::remove_if(_active, isFinished), end(_active));
if (!empty(_starting)) {
auto starting = std::move(_starting);
_active.insert(end(_active), begin(starting), end(starting));
_active.insert(
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]] bool call(crl::time now) const;
void restart();
void markStarted();
void markStopped();
crl::time _started = -1;
Fn<bool(crl::time)> _callback;
@ -98,6 +102,50 @@ public:
void update();
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;
void timerEvent(QTimerEvent *e) override;
@ -113,8 +161,8 @@ private:
int _timerId = 0;
bool _updating = false;
bool _scheduled = false;
std::vector<Basic*> _active;
std::vector<not_null<Basic*>> _starting;
std::vector<ActiveBasicPointer> _active;
std::vector<ActiveBasicPointer> _starting;
rpl::lifetime _lifetime;
};