animations.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. // This file is part of Desktop App Toolkit,
  2. // a set of libraries for developing nice desktop applications.
  3. //
  4. // For license and copyright information please follow this link:
  5. // https://github.com/desktop-app/legal/blob/master/LEGAL
  6. //
  7. #pragma once
  8. #include "ui/effects/animation_value.h"
  9. #include <crl/crl_time.h>
  10. #include <rpl/lifetime.h>
  11. #include <QtCore/QObject>
  12. namespace Ui {
  13. namespace Animations {
  14. class Manager;
  15. class Basic final {
  16. public:
  17. Basic() = default;
  18. Basic(const Basic &other) = delete;
  19. Basic &operator=(const Basic &other) = delete;
  20. template <typename Callback>
  21. explicit Basic(Callback &&callback);
  22. template <typename Callback>
  23. void init(Callback &&callback);
  24. void start();
  25. void stop();
  26. [[nodiscard]] crl::time started() const;
  27. [[nodiscard]] bool animating() const;
  28. ~Basic();
  29. private:
  30. friend class Manager;
  31. template <typename Callback>
  32. [[nodiscard]] static Fn<bool(crl::time)> Prepare(Callback &&callback);
  33. [[nodiscard]] bool call(crl::time now) const;
  34. void restart();
  35. void markStarted();
  36. void markStopped();
  37. crl::time _started = -1;
  38. Fn<bool(crl::time)> _callback;
  39. };
  40. class Simple final {
  41. public:
  42. template <typename Callback>
  43. void start(
  44. Callback &&callback,
  45. float64 from,
  46. float64 to,
  47. crl::time duration,
  48. anim::transition transition = anim::linear);
  49. void change(
  50. float64 to,
  51. crl::time duration,
  52. anim::transition transition = anim::linear);
  53. void stop();
  54. [[nodiscard]] bool animating() const;
  55. [[nodiscard]] float64 value(float64 final) const;
  56. private:
  57. class ShortTracker {
  58. public:
  59. ShortTracker() {
  60. restart();
  61. }
  62. ShortTracker(const ShortTracker &other) = delete;
  63. ShortTracker &operator=(const ShortTracker &other) = delete;
  64. ~ShortTracker() {
  65. release();
  66. }
  67. void restart() {
  68. if (!std::exchange(_paused, true)) {
  69. style::internal::StartShortAnimation();
  70. }
  71. }
  72. void release() {
  73. if (std::exchange(_paused, false)) {
  74. style::internal::StopShortAnimation();
  75. }
  76. }
  77. private:
  78. bool _paused = false;
  79. };
  80. struct Data {
  81. explicit Data(float64 initial) : value(initial) {
  82. }
  83. ~Data() {
  84. if (markOnDelete) {
  85. *markOnDelete = true;
  86. }
  87. }
  88. Basic animation;
  89. anim::transition transition;
  90. float64 from = 0.;
  91. float64 delta = 0.;
  92. float64 value = 0.;
  93. float64 duration = 0.;
  94. bool *markOnDelete = nullptr;
  95. ShortTracker tracker;
  96. };
  97. template <typename Callback>
  98. [[nodiscard]] static decltype(auto) Prepare(Callback &&callback);
  99. void prepare(float64 from, crl::time duration);
  100. void startPrepared(
  101. float64 to,
  102. crl::time duration,
  103. anim::transition transition);
  104. static constexpr auto kLongAnimationDuration = crl::time(1000);
  105. mutable std::unique_ptr<Data> _data;
  106. };
  107. class Manager final : private QObject {
  108. public:
  109. Manager();
  110. ~Manager();
  111. void update();
  112. private:
  113. class ActiveBasicPointer {
  114. public:
  115. ActiveBasicPointer(Basic *value = nullptr) : _value(value) {
  116. if (_value) {
  117. _value->markStarted();
  118. }
  119. }
  120. ActiveBasicPointer(ActiveBasicPointer &&other)
  121. : _value(base::take(other._value)) {
  122. }
  123. ActiveBasicPointer &operator=(ActiveBasicPointer &&other) {
  124. if (_value != other._value) {
  125. if (_value) {
  126. _value->markStopped();
  127. }
  128. _value = base::take(other._value);
  129. }
  130. return *this;
  131. }
  132. ~ActiveBasicPointer() {
  133. if (_value) {
  134. _value->markStopped();
  135. }
  136. }
  137. [[nodiscard]] bool call(crl::time now) const {
  138. return _value && _value->call(now);
  139. }
  140. friend inline bool operator==(
  141. const ActiveBasicPointer &a,
  142. const ActiveBasicPointer &b) {
  143. return a._value == b._value;
  144. }
  145. Basic *get() const {
  146. return _value;
  147. }
  148. private:
  149. Basic *_value = nullptr;
  150. };
  151. friend class Basic;
  152. void timerEvent(QTimerEvent *e) override;
  153. void start(not_null<Basic*> animation);
  154. void stop(not_null<Basic*> animation);
  155. void schedule();
  156. void updateQueued();
  157. void stopTimer();
  158. not_null<const QObject*> delayedCallGuard() const;
  159. crl::time _lastUpdateTime = 0;
  160. int _timerId = 0;
  161. bool _updating = false;
  162. bool _removedWhileUpdating = false;
  163. bool _scheduled = false;
  164. bool _forceImmediateUpdate = false;
  165. std::vector<ActiveBasicPointer> _active;
  166. std::vector<ActiveBasicPointer> _starting;
  167. rpl::lifetime _lifetime;
  168. };
  169. template <typename Callback>
  170. Fn<bool(crl::time)> Basic__PrepareCrlTime(Callback &&callback) {
  171. using Return = decltype(callback(crl::time(0)));
  172. if constexpr (std::is_convertible_v<Return, bool>) {
  173. return std::forward<Callback>(callback);
  174. } else if constexpr (std::is_same_v<Return, void>) {
  175. return [callback = std::forward<Callback>(callback)](
  176. crl::time time) {
  177. callback(time);
  178. return true;
  179. };
  180. } else {
  181. static_assert(false_t(callback), "Expected void or bool.");
  182. }
  183. }
  184. template <typename Callback>
  185. Fn<bool(crl::time)> Basic__PreparePlain(Callback &&callback) {
  186. using Return = decltype(callback());
  187. if constexpr (std::is_convertible_v<Return, bool>) {
  188. return [callback = std::forward<Callback>(callback)](crl::time) {
  189. return callback();
  190. };
  191. } else if constexpr (std::is_same_v<Return, void>) {
  192. return [callback = std::forward<Callback>(callback)](crl::time) {
  193. callback();
  194. return true;
  195. };
  196. } else {
  197. static_assert(false_t(callback), "Expected void or bool.");
  198. }
  199. }
  200. template <typename Callback>
  201. inline Fn<bool(crl::time)> Basic::Prepare(Callback &&callback) {
  202. if constexpr (rpl::details::is_callable_plain_v<Callback, crl::time>) {
  203. return Basic__PrepareCrlTime(std::forward<Callback>(callback));
  204. } else if constexpr (rpl::details::is_callable_plain_v<Callback>) {
  205. return Basic__PreparePlain(std::forward<Callback>(callback));
  206. } else {
  207. static_assert(false_t(callback), "Expected crl::time or no args.");
  208. }
  209. }
  210. template <typename Callback>
  211. inline Basic::Basic(Callback &&callback)
  212. : _callback(Prepare(std::forward<Callback>(callback))) {
  213. }
  214. template <typename Callback>
  215. inline void Basic::init(Callback &&callback) {
  216. _callback = Prepare(std::forward<Callback>(callback));
  217. }
  218. TG_FORCE_INLINE crl::time Basic::started() const {
  219. return _started;
  220. }
  221. TG_FORCE_INLINE bool Basic::animating() const {
  222. return (_started >= 0);
  223. }
  224. TG_FORCE_INLINE bool Basic::call(crl::time now) const {
  225. Expects(_started >= 0);
  226. // _started may be greater than now if we called restart while iterating.
  227. const auto onstack = _callback;
  228. return onstack(std::max(_started, now));
  229. }
  230. inline Basic::~Basic() {
  231. stop();
  232. }
  233. template <typename Callback>
  234. decltype(auto) Simple__PrepareFloat64(Callback &&callback) {
  235. using Return = decltype(callback(float64(0.)));
  236. if constexpr (std::is_convertible_v<Return, bool>) {
  237. return std::forward<Callback>(callback);
  238. } else if constexpr (std::is_same_v<Return, void>) {
  239. return [callback = std::forward<Callback>(callback)](
  240. float64 value) {
  241. callback(value);
  242. return true;
  243. };
  244. } else {
  245. static_assert(false_t(callback), "Expected void or float64.");
  246. }
  247. }
  248. template <typename Callback>
  249. decltype(auto) Simple__PreparePlain(Callback &&callback) {
  250. using Return = decltype(callback());
  251. if constexpr (std::is_convertible_v<Return, bool>) {
  252. return [callback = std::forward<Callback>(callback)](float64) {
  253. return callback();
  254. };
  255. } else if constexpr (std::is_same_v<Return, void>) {
  256. return [callback = std::forward<Callback>(callback)](float64) {
  257. callback();
  258. return true;
  259. };
  260. } else {
  261. static_assert(false_t(callback), "Expected void or bool.");
  262. }
  263. }
  264. template <typename Callback>
  265. decltype(auto) Simple::Prepare(Callback &&callback) {
  266. if constexpr (rpl::details::is_callable_plain_v<Callback, float64>) {
  267. return Simple__PrepareFloat64(std::forward<Callback>(callback));
  268. } else if constexpr (rpl::details::is_callable_plain_v<Callback>) {
  269. return Simple__PreparePlain(std::forward<Callback>(callback));
  270. } else {
  271. static_assert(false_t(callback), "Expected float64 or no args.");
  272. }
  273. }
  274. template <typename Callback>
  275. inline void Simple::start(
  276. Callback &&callback,
  277. float64 from,
  278. float64 to,
  279. crl::time duration,
  280. anim::transition transition) {
  281. prepare(from, duration);
  282. _data->animation.init([
  283. that = _data.get(),
  284. callback = Prepare(std::forward<Callback>(callback))
  285. ](crl::time now) {
  286. Assert(!std::isnan(double(now - that->animation.started())));
  287. const auto time = anim::Disabled()
  288. ? that->duration
  289. : (now - that->animation.started());
  290. Assert(!std::isnan(time));
  291. Assert(!std::isnan(that->delta));
  292. Assert(!std::isnan(that->duration));
  293. const auto finished = (time >= that->duration);
  294. Assert(finished || that->duration > 0);
  295. const auto progressRatio = finished ? 1. : time / that->duration;
  296. Assert(!std::isnan(progressRatio));
  297. const auto progress = finished
  298. ? that->delta
  299. : that->transition(that->delta, progressRatio);
  300. Assert(!std::isnan(that->from));
  301. Assert(!std::isnan(progress));
  302. that->value = that->from + progress;
  303. Assert(!std::isnan(that->value));
  304. if (finished) {
  305. that->animation.stop();
  306. }
  307. auto deleted = false;
  308. that->markOnDelete = &deleted;
  309. const auto result = callback(that->value) && !finished;
  310. if (!deleted) {
  311. that->markOnDelete = nullptr;
  312. if (!result) {
  313. that->tracker.release();
  314. }
  315. }
  316. return result;
  317. });
  318. startPrepared(to, duration, transition);
  319. }
  320. inline void Simple::change(
  321. float64 to,
  322. crl::time duration,
  323. anim::transition transition) {
  324. Expects(_data != nullptr);
  325. prepare(0. /* ignored */, duration);
  326. startPrepared(to, duration, transition);
  327. }
  328. inline void Simple::prepare(float64 from, crl::time duration) {
  329. const auto isLong = (duration > kLongAnimationDuration);
  330. if (!_data) {
  331. _data = std::make_unique<Data>(from);
  332. } else if (!isLong) {
  333. _data->tracker.restart();
  334. }
  335. if (isLong) {
  336. _data->tracker.release();
  337. }
  338. }
  339. inline void Simple::stop() {
  340. _data = nullptr;
  341. }
  342. inline bool Simple::animating() const {
  343. if (!_data) {
  344. return false;
  345. } else if (!_data->animation.animating()) {
  346. _data = nullptr;
  347. return false;
  348. }
  349. return true;
  350. }
  351. TG_FORCE_INLINE float64 Simple::value(float64 final) const {
  352. if (animating()) {
  353. Assert(!std::isnan(_data->value));
  354. return _data->value;
  355. }
  356. Assert(!std::isnan(final));
  357. return final;
  358. }
  359. inline void Simple::startPrepared(
  360. float64 to,
  361. crl::time duration,
  362. anim::transition transition) {
  363. _data->from = _data->value;
  364. _data->delta = to - _data->from;
  365. _data->duration = duration * anim::SlowMultiplier();
  366. _data->transition = transition;
  367. _data->animation.start();
  368. }
  369. } // namespace Animations
  370. } // namespace Ui