window_slide_animation.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "window/window_slide_animation.h"
  8. #include "styles/style_window.h"
  9. #include "styles/style_boxes.h"
  10. namespace Window {
  11. void SlideAnimation::paintContents(QPainter &p) const {
  12. const auto retina = style::DevicePixelRatio();
  13. const auto slideLeft = (_direction == SlideDirection::FromLeft);
  14. const auto progress = _animation.value(slideLeft ? 0. : 1.);
  15. if (_withFade) {
  16. const auto dt = slideLeft
  17. ? (1. - progress)
  18. : progress;
  19. const auto easeOut = anim::easeOutCirc(1., dt);
  20. const auto easeIn = anim::easeInCirc(1., dt);
  21. const auto arrivingAlpha = easeIn;
  22. const auto departingAlpha = 1. - easeOut;
  23. const auto leftWidthFull = _cacheUnder.width() / retina;
  24. const auto rightWidthFull = _cacheOver.width() / retina;
  25. const auto leftCoord = slideLeft
  26. ? anim::interpolate(-leftWidthFull, 0, easeOut)
  27. : anim::interpolate(0, -leftWidthFull, easeIn);
  28. const auto leftAlpha = (slideLeft ? arrivingAlpha : departingAlpha);
  29. const auto rightCoord = slideLeft
  30. ? anim::interpolate(0, rightWidthFull, easeIn)
  31. : anim::interpolate(rightWidthFull, 0, easeOut);
  32. const auto rightAlpha = (slideLeft ? departingAlpha : arrivingAlpha);
  33. const auto leftWidth = (leftWidthFull + leftCoord);
  34. const auto rightWidth = rightWidthFull - rightCoord;
  35. if (!_mask.isNull()) {
  36. auto frame = QImage(
  37. _mask.size(),
  38. QImage::Format_ARGB32_Premultiplied);
  39. frame.setDevicePixelRatio(_mask.devicePixelRatio());
  40. frame.fill(Qt::transparent);
  41. QPainter q(&frame);
  42. if (leftWidth > 0) {
  43. q.setOpacity(leftAlpha);
  44. q.drawPixmap(
  45. 0,
  46. 0,
  47. _cacheUnder,
  48. _cacheUnder.width()
  49. - leftWidth * style::DevicePixelRatio(),
  50. 0,
  51. leftWidth * style::DevicePixelRatio(),
  52. _topSkip * retina);
  53. }
  54. if (rightWidth > 0) {
  55. q.setOpacity(rightAlpha);
  56. q.drawPixmap(
  57. rightCoord,
  58. 0,
  59. _cacheOver,
  60. 0,
  61. 0,
  62. rightWidth * style::DevicePixelRatio(),
  63. _topSkip * retina);
  64. }
  65. q.setOpacity(1.);
  66. q.setCompositionMode(QPainter::CompositionMode_DestinationIn);
  67. q.drawPixmap(0, 0, _mask);
  68. p.drawImage(0, 0, frame);
  69. }
  70. if (leftWidth > 0) {
  71. p.setOpacity(leftAlpha);
  72. p.drawPixmap(
  73. 0,
  74. _topSkip,
  75. _cacheUnder,
  76. (_cacheUnder.width() - leftWidth * retina),
  77. _topSkip * retina,
  78. leftWidth * retina,
  79. _cacheUnder.height() - _topSkip * retina);
  80. }
  81. if (rightWidth > 0) {
  82. p.setOpacity(rightAlpha);
  83. p.drawPixmap(
  84. rightCoord,
  85. _topSkip,
  86. _cacheOver,
  87. 0,
  88. _topSkip * retina,
  89. rightWidth * retina,
  90. _cacheOver.height() - _topSkip * retina);
  91. }
  92. } else {
  93. const auto coordUnder = anim::interpolate(
  94. 0,
  95. -st::slideShift,
  96. progress);
  97. const auto coordOver = anim::interpolate(
  98. _cacheOver.width() / retina,
  99. 0,
  100. progress);
  101. if (coordOver) {
  102. p.drawPixmap(
  103. QRect(0, 0, coordOver, _cacheUnder.height() / retina),
  104. _cacheUnder,
  105. QRect(
  106. -coordUnder * retina,
  107. 0,
  108. coordOver * retina,
  109. _cacheUnder.height()));
  110. p.setOpacity(progress);
  111. p.fillRect(
  112. 0,
  113. 0,
  114. coordOver, _cacheUnder.height() / retina,
  115. st::slideFadeOutBg);
  116. p.setOpacity(1);
  117. }
  118. p.drawPixmap(
  119. QRect(QPoint(coordOver, 0), _cacheOver.size() / retina),
  120. _cacheOver,
  121. QRect(QPoint(), _cacheOver.size()));
  122. p.setOpacity(progress);
  123. st::slideShadow.fill(
  124. p,
  125. QRect(
  126. coordOver - st::slideShadow.width(),
  127. 0,
  128. st::slideShadow.width(),
  129. _cacheOver.height() / retina));
  130. }
  131. }
  132. float64 SlideAnimation::progress() const {
  133. const auto slideLeft = (_direction == SlideDirection::FromLeft);
  134. const auto progress = _animation.value(slideLeft ? 0. : 1.);
  135. return slideLeft ? (1. - progress) : progress;
  136. }
  137. void SlideAnimation::setDirection(SlideDirection direction) {
  138. _direction = direction;
  139. }
  140. void SlideAnimation::setPixmaps(
  141. const QPixmap &oldContentCache,
  142. const QPixmap &newContentCache) {
  143. _cacheUnder = oldContentCache;
  144. _cacheOver = newContentCache;
  145. }
  146. void SlideAnimation::setTopBarShadow(bool enabled) {
  147. _topBarShadowEnabled = enabled;
  148. }
  149. void SlideAnimation::setTopSkip(int skip) {
  150. _topSkip = skip;
  151. }
  152. void SlideAnimation::setWithFade(bool withFade) {
  153. _withFade = withFade;
  154. }
  155. void SlideAnimation::setRepaintCallback(RepaintCallback &&callback) {
  156. _repaintCallback = std::move(callback);
  157. }
  158. void SlideAnimation::setFinishedCallback(FinishedCallback &&callback) {
  159. _finishedCallback = std::move(callback);
  160. }
  161. void SlideAnimation::setTopBarMask(const QPixmap &mask) {
  162. _mask = mask;
  163. }
  164. void SlideAnimation::start() {
  165. const auto fromLeft = (_direction == SlideDirection::FromLeft);
  166. if (fromLeft) {
  167. std::swap(_cacheUnder, _cacheOver);
  168. }
  169. _animation.start(
  170. [this] { animationCallback(); },
  171. fromLeft ? 1. : 0.,
  172. fromLeft ? 0. : 1.,
  173. st::slideDuration,
  174. transition());
  175. if (const auto onstack = _repaintCallback) {
  176. onstack();
  177. }
  178. }
  179. void SlideAnimation::animationCallback() {
  180. if (const auto onstack = _repaintCallback) {
  181. onstack();
  182. }
  183. if (!_animation.animating()) {
  184. if (const auto onstack = _finishedCallback) {
  185. onstack();
  186. }
  187. }
  188. }
  189. } // namespace Window