animation_value.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  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/style/style_core.h"
  9. #include "base/basic_types.h"
  10. #include <QtGui/QPainterPath>
  11. #include <crl/crl_time.h>
  12. namespace anim {
  13. enum class type : uchar {
  14. normal,
  15. instant,
  16. };
  17. enum class activation : uchar {
  18. normal,
  19. background,
  20. };
  21. enum class repeat : uchar {
  22. loop,
  23. once,
  24. };
  25. using transition = Fn<float64(float64 delta, float64 dt)>;
  26. extern transition linear;
  27. extern transition sineInOut;
  28. extern transition halfSine;
  29. extern transition easeOutBack;
  30. extern transition easeInCirc;
  31. extern transition easeOutCirc;
  32. extern transition easeInCubic;
  33. extern transition easeOutCubic;
  34. extern transition easeInQuint;
  35. extern transition easeOutQuint;
  36. inline transition bumpy(float64 bump) {
  37. auto dt0 = (bump - sqrt(bump * (bump - 1.)));
  38. auto k = (1 / (2 * dt0 - 1));
  39. return [bump, dt0, k](float64 delta, float64 dt) {
  40. return delta * (bump - k * (dt - dt0) * (dt - dt0));
  41. };
  42. }
  43. // Basic animated value.
  44. class value {
  45. public:
  46. using ValueType = float64;
  47. value() = default;
  48. value(float64 from) : _cur(from), _from(from) {
  49. }
  50. value(float64 from, float64 to) : _cur(from), _from(from), _delta(to - from) {
  51. }
  52. void start(float64 to) {
  53. _from = _cur;
  54. _delta = to - _from;
  55. }
  56. void restart() {
  57. _delta = _from + _delta - _cur;
  58. _from = _cur;
  59. }
  60. float64 from() const {
  61. return _from;
  62. }
  63. float64 current() const {
  64. return _cur;
  65. }
  66. float64 to() const {
  67. return _from + _delta;
  68. }
  69. void add(float64 delta) {
  70. _from += delta;
  71. _cur += delta;
  72. }
  73. value &update(float64 dt, transition func) {
  74. _cur = _from + func(_delta, dt);
  75. return *this;
  76. }
  77. void finish() {
  78. _cur = _from + _delta;
  79. _from = _cur;
  80. _delta = 0;
  81. }
  82. private:
  83. float64 _cur = 0.;
  84. float64 _from = 0.;
  85. float64 _delta = 0.;
  86. };
  87. TG_FORCE_INLINE float64 interpolateToF(int a, int b, float64 b_ratio) {
  88. return a + float64(b - a) * b_ratio;
  89. }
  90. TG_FORCE_INLINE int interpolate(int a, int b, float64 b_ratio) {
  91. return base::SafeRound(interpolateToF(a, b, b_ratio));
  92. }
  93. #ifdef ARCH_CPU_32_BITS
  94. #define SHIFTED_USE_32BIT
  95. #endif // ARCH_CPU_32_BITS
  96. #ifdef SHIFTED_USE_32BIT
  97. using ShiftedMultiplier = uint32;
  98. struct Shifted {
  99. Shifted() = default;
  100. Shifted(uint32 low, uint32 high) : low(low), high(high) {
  101. }
  102. uint32 low = 0;
  103. uint32 high = 0;
  104. };
  105. TG_FORCE_INLINE Shifted operator+(Shifted a, Shifted b) {
  106. return Shifted(a.low + b.low, a.high + b.high);
  107. }
  108. TG_FORCE_INLINE Shifted operator*(Shifted shifted, ShiftedMultiplier multiplier) {
  109. return Shifted(shifted.low * multiplier, shifted.high * multiplier);
  110. }
  111. TG_FORCE_INLINE Shifted operator*(ShiftedMultiplier multiplier, Shifted shifted) {
  112. return Shifted(shifted.low * multiplier, shifted.high * multiplier);
  113. }
  114. TG_FORCE_INLINE Shifted shifted(uint32 components) {
  115. return Shifted(
  116. (components & 0x000000FFU) | ((components & 0x0000FF00U) << 8),
  117. ((components & 0x00FF0000U) >> 16) | ((components & 0xFF000000U) >> 8));
  118. }
  119. TG_FORCE_INLINE uint32 unshifted(Shifted components) {
  120. return ((components.low & 0x0000FF00U) >> 8)
  121. | ((components.low & 0xFF000000U) >> 16)
  122. | ((components.high & 0x0000FF00U) << 8)
  123. | (components.high & 0xFF000000U);
  124. }
  125. TG_FORCE_INLINE Shifted reshifted(Shifted components) {
  126. return Shifted((components.low >> 8) & 0x00FF00FFU, (components.high >> 8) & 0x00FF00FFU);
  127. }
  128. TG_FORCE_INLINE Shifted shifted(QColor color) {
  129. // Make it premultiplied.
  130. auto alpha = static_cast<uint32>((color.alpha() & 0xFF) + 1);
  131. auto components = Shifted(static_cast<uint32>(color.blue() & 0xFF) | (static_cast<uint32>(color.green() & 0xFF) << 16),
  132. static_cast<uint32>(color.red() & 0xFF) | (static_cast<uint32>(255) << 16));
  133. return reshifted(components * alpha);
  134. }
  135. TG_FORCE_INLINE uint32 getPremultiplied(QColor color) {
  136. // Make it premultiplied.
  137. auto alpha = static_cast<uint32>((color.alpha() & 0xFF) + 1);
  138. auto components = Shifted(static_cast<uint32>(color.blue() & 0xFF) | (static_cast<uint32>(color.green() & 0xFF) << 16),
  139. static_cast<uint32>(color.red() & 0xFF) | (static_cast<uint32>(255) << 16));
  140. return unshifted(components * alpha);
  141. }
  142. TG_FORCE_INLINE uint32 getAlpha(Shifted components) {
  143. return (components.high & 0x00FF0000U) >> 16;
  144. }
  145. TG_FORCE_INLINE Shifted non_premultiplied(QColor color) {
  146. return Shifted(static_cast<uint32>(color.blue() & 0xFF) | (static_cast<uint32>(color.green() & 0xFF) << 16),
  147. static_cast<uint32>(color.red() & 0xFF) | (static_cast<uint32>(color.alpha() & 0xFF) << 16));
  148. }
  149. TG_FORCE_INLINE QColor color(QColor a, QColor b, float64 b_ratio) {
  150. auto bOpacity = std::clamp(interpolate(0, 255, b_ratio), 0, 255) + 1;
  151. auto aOpacity = (256 - bOpacity);
  152. auto components = (non_premultiplied(a) * aOpacity + non_premultiplied(b) * bOpacity);
  153. return {
  154. static_cast<int>((components.high >> 8) & 0xFF),
  155. static_cast<int>((components.low >> 24) & 0xFF),
  156. static_cast<int>((components.low >> 8) & 0xFF),
  157. static_cast<int>((components.high >> 24) & 0xFF),
  158. };
  159. }
  160. #else // SHIFTED_USE_32BIT
  161. using ShiftedMultiplier = uint64;
  162. struct Shifted {
  163. Shifted() = default;
  164. Shifted(uint32 value) : value(value) {
  165. }
  166. Shifted(uint64 value) : value(value) {
  167. }
  168. uint64 value = 0;
  169. };
  170. TG_FORCE_INLINE Shifted operator+(Shifted a, Shifted b) {
  171. return Shifted(a.value + b.value);
  172. }
  173. TG_FORCE_INLINE Shifted operator*(Shifted shifted, ShiftedMultiplier multiplier) {
  174. return Shifted(shifted.value * multiplier);
  175. }
  176. TG_FORCE_INLINE Shifted operator*(ShiftedMultiplier multiplier, Shifted shifted) {
  177. return Shifted(shifted.value * multiplier);
  178. }
  179. TG_FORCE_INLINE Shifted shifted(uint32 components) {
  180. auto wide = static_cast<uint64>(components);
  181. return (wide & 0x00000000000000FFULL)
  182. | ((wide & 0x000000000000FF00ULL) << 8)
  183. | ((wide & 0x0000000000FF0000ULL) << 16)
  184. | ((wide & 0x00000000FF000000ULL) << 24);
  185. }
  186. TG_FORCE_INLINE uint32 unshifted(Shifted components) {
  187. return static_cast<uint32>((components.value & 0x000000000000FF00ULL) >> 8)
  188. | static_cast<uint32>((components.value & 0x00000000FF000000ULL) >> 16)
  189. | static_cast<uint32>((components.value & 0x0000FF0000000000ULL) >> 24)
  190. | static_cast<uint32>((components.value & 0xFF00000000000000ULL) >> 32);
  191. }
  192. TG_FORCE_INLINE Shifted reshifted(Shifted components) {
  193. return (components.value >> 8) & 0x00FF00FF00FF00FFULL;
  194. }
  195. TG_FORCE_INLINE Shifted shifted(QColor color) {
  196. // Make it premultiplied.
  197. auto alpha = static_cast<uint64>((color.alpha() & 0xFF) + 1);
  198. auto components = static_cast<uint64>(color.blue() & 0xFF)
  199. | (static_cast<uint64>(color.green() & 0xFF) << 16)
  200. | (static_cast<uint64>(color.red() & 0xFF) << 32)
  201. | (static_cast<uint64>(255) << 48);
  202. return reshifted(components * alpha);
  203. }
  204. TG_FORCE_INLINE uint32 getPremultiplied(QColor color) {
  205. // Make it premultiplied.
  206. auto alpha = static_cast<uint64>((color.alpha() & 0xFF) + 1);
  207. auto components = static_cast<uint64>(color.blue() & 0xFF)
  208. | (static_cast<uint64>(color.green() & 0xFF) << 16)
  209. | (static_cast<uint64>(color.red() & 0xFF) << 32)
  210. | (static_cast<uint64>(255) << 48);
  211. return unshifted(components * alpha);
  212. }
  213. TG_FORCE_INLINE uint32 getAlpha(Shifted components) {
  214. return (components.value & 0x00FF000000000000ULL) >> 48;
  215. }
  216. TG_FORCE_INLINE Shifted non_premultiplied(QColor color) {
  217. return static_cast<uint64>(color.blue() & 0xFF)
  218. | (static_cast<uint64>(color.green() & 0xFF) << 16)
  219. | (static_cast<uint64>(color.red() & 0xFF) << 32)
  220. | (static_cast<uint64>(color.alpha() & 0xFF) << 48);
  221. }
  222. TG_FORCE_INLINE QColor color(QColor a, QColor b, float64 b_ratio) {
  223. auto bOpacity = std::clamp(interpolate(0, 255, b_ratio), 0, 255) + 1;
  224. auto aOpacity = (256 - bOpacity);
  225. auto components = (non_premultiplied(a) * aOpacity + non_premultiplied(b) * bOpacity);
  226. return {
  227. static_cast<int>((components.value >> 40) & 0xFF),
  228. static_cast<int>((components.value >> 24) & 0xFF),
  229. static_cast<int>((components.value >> 8) & 0xFF),
  230. static_cast<int>((components.value >> 56) & 0xFF),
  231. };
  232. }
  233. #endif // SHIFTED_USE_32BIT
  234. TG_FORCE_INLINE QColor color(style::color a, QColor b, float64 b_ratio) {
  235. return color(a->c, b, b_ratio);
  236. }
  237. TG_FORCE_INLINE QColor color(QColor a, style::color b, float64 b_ratio) {
  238. return color(a, b->c, b_ratio);
  239. }
  240. TG_FORCE_INLINE QColor color(style::color a, style::color b, float64 b_ratio) {
  241. return color(a->c, b->c, b_ratio);
  242. }
  243. TG_FORCE_INLINE QPen pen(QColor a, QColor b, float64 b_ratio) {
  244. return color(a, b, b_ratio);
  245. }
  246. TG_FORCE_INLINE QPen pen(style::color a, QColor b, float64 b_ratio) {
  247. return (b_ratio > 0) ? pen(a->c, b, b_ratio) : a;
  248. }
  249. TG_FORCE_INLINE QPen pen(QColor a, style::color b, float64 b_ratio) {
  250. return (b_ratio < 1) ? pen(a, b->c, b_ratio) : b;
  251. }
  252. TG_FORCE_INLINE QPen pen(style::color a, style::color b, float64 b_ratio) {
  253. return (b_ratio > 0) ? ((b_ratio < 1) ? pen(a->c, b->c, b_ratio) : b) : a;
  254. }
  255. TG_FORCE_INLINE QBrush brush(QColor a, QColor b, float64 b_ratio) {
  256. return color(a, b, b_ratio);
  257. }
  258. TG_FORCE_INLINE QBrush brush(style::color a, QColor b, float64 b_ratio) {
  259. return (b_ratio > 0) ? brush(a->c, b, b_ratio) : a;
  260. }
  261. TG_FORCE_INLINE QBrush brush(QColor a, style::color b, float64 b_ratio) {
  262. return (b_ratio < 1) ? brush(a, b->c, b_ratio) : b;
  263. }
  264. TG_FORCE_INLINE QBrush brush(style::color a, style::color b, float64 b_ratio) {
  265. return (b_ratio > 0) ? ((b_ratio < 1) ? brush(a->c, b->c, b_ratio) : b) : a;
  266. }
  267. TG_FORCE_INLINE QColor with_alpha(QColor color, float64 alpha) {
  268. color.setAlphaF(color.alphaF() * alpha);
  269. return color;
  270. }
  271. template <int N>
  272. QPainterPath interpolate(QPointF (&from)[N], QPointF (&to)[N], float64 k) {
  273. static_assert(N > 1, "Wrong points count in path!");
  274. auto from_coef = 1. - k, to_coef = k;
  275. QPainterPath result;
  276. auto x = from[0].x() * from_coef + to[0].x() * to_coef;
  277. auto y = from[0].y() * from_coef + to[0].y() * to_coef;
  278. result.moveTo(x, y);
  279. for (int i = 1; i != N; ++i) {
  280. result.lineTo(from[i].x() * from_coef + to[i].x() * to_coef, from[i].y() * from_coef + to[i].y() * to_coef);
  281. }
  282. result.lineTo(x, y);
  283. return result;
  284. }
  285. template <int N>
  286. QPainterPath path(QPointF (&from)[N]) {
  287. static_assert(N > 1, "Wrong points count in path!");
  288. QPainterPath result;
  289. auto x = from[0].x();
  290. auto y = from[0].y();
  291. result.moveTo(x, y);
  292. for (int i = 1; i != N; ++i) {
  293. result.lineTo(from[i].x(), from[i].y());
  294. }
  295. result.lineTo(x, y);
  296. return result;
  297. }
  298. rpl::producer<bool> Disables();
  299. bool Disabled();
  300. void SetDisabled(bool disabled);
  301. int SlowMultiplier();
  302. void SetSlowMultiplier(int multiplier); // 1 - default, 10 - slow x10.
  303. void DrawStaticLoading(
  304. QPainter &p,
  305. QRectF rect,
  306. float64 stroke,
  307. QPen pen,
  308. QBrush brush = Qt::NoBrush);
  309. class continuous_value {
  310. public:
  311. continuous_value() = default;
  312. continuous_value(float64 duration) : _duration(duration) {
  313. }
  314. void start(float64 to, float64 duration) {
  315. _to = to;
  316. _delta = (_to - _cur) / duration;
  317. }
  318. void start(float64 to) {
  319. start(to, _duration);
  320. }
  321. void reset() {
  322. _to = _cur = _delta = 0.;
  323. }
  324. float64 current() const {
  325. return _cur;
  326. }
  327. float64 to() const {
  328. return _to;
  329. }
  330. float64 delta() const {
  331. return _delta;
  332. }
  333. void update(crl::time dt, Fn<void(float64 &)> &&callback = nullptr) {
  334. if (_to != _cur) {
  335. _cur += _delta * dt;
  336. if ((_to != _cur) && ((_delta > 0) == (_cur > _to))) {
  337. _cur = _to;
  338. }
  339. if (callback) {
  340. callback(_cur);
  341. }
  342. }
  343. }
  344. private:
  345. float64 _duration = 0.;
  346. float64 _to = 0.;
  347. float64 _cur = 0.;
  348. float64 _delta = 0.;
  349. };
  350. } // namespace anim