path_shift_gradient.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  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. #include "ui/effects/path_shift_gradient.h"
  8. #include "base/call_delayed.h"
  9. #include "ui/effects/animations.h"
  10. namespace Ui {
  11. namespace {
  12. constexpr auto kSlideDuration = crl::time(1000);
  13. constexpr auto kWaitDuration = crl::time(1000);
  14. constexpr auto kFullDuration = kSlideDuration + kWaitDuration;
  15. } // namespace
  16. struct PathShiftGradient::AnimationData {
  17. Ui::Animations::Simple animation;
  18. base::flat_set<not_null<PathShiftGradient*>> active;
  19. bool scheduled = false;
  20. };
  21. std::weak_ptr<PathShiftGradient::AnimationData> PathShiftGradient::Animation;
  22. PathShiftGradient::PathShiftGradient(
  23. const style::color &bg,
  24. const style::color &fg,
  25. Fn<void()> animationCallback,
  26. rpl::producer<> paletteUpdated)
  27. : _bg(bg)
  28. , _fg(fg)
  29. , _animationCallback(std::move(animationCallback)) {
  30. refreshColors();
  31. if (!paletteUpdated) {
  32. paletteUpdated = style::PaletteChanged();
  33. }
  34. std::move(
  35. paletteUpdated
  36. ) | rpl::start_with_next([=] {
  37. refreshColors();
  38. }, _lifetime);
  39. }
  40. PathShiftGradient::~PathShiftGradient() {
  41. if (const auto strong = _animation.get()) {
  42. strong->active.erase(this);
  43. }
  44. }
  45. void PathShiftGradient::overrideColors(
  46. const style::color &bg,
  47. const style::color &fg) {
  48. _colorsOverriden = true;
  49. refreshColors(bg, fg);
  50. }
  51. void PathShiftGradient::clearOverridenColors() {
  52. if (!_colorsOverriden) {
  53. return;
  54. }
  55. _colorsOverriden = false;
  56. refreshColors();
  57. }
  58. void PathShiftGradient::startFrame(
  59. int viewportLeft,
  60. int viewportWidth,
  61. int gradientWidth) {
  62. _viewportLeft = viewportLeft;
  63. _viewportWidth = viewportWidth;
  64. _gradientWidth = gradientWidth;
  65. _geometryUpdated = false;
  66. }
  67. void PathShiftGradient::updateGeometry() {
  68. if (_geometryUpdated) {
  69. return;
  70. }
  71. _geometryUpdated = true;
  72. const auto now = crl::now();
  73. const auto period = now % kFullDuration;
  74. if (period >= kSlideDuration) {
  75. _gradientEnabled = false;
  76. return;
  77. }
  78. const auto progress = period / float64(kSlideDuration);
  79. _gradientStart = anim::interpolate(
  80. _viewportLeft - _gradientWidth,
  81. _viewportLeft + _viewportWidth,
  82. progress);
  83. _gradientFinalStop = _gradientStart + _gradientWidth;
  84. _gradientEnabled = true;
  85. }
  86. bool PathShiftGradient::paint(Fn<bool(const Background&)> painter) {
  87. updateGeometry();
  88. if (_gradientEnabled) {
  89. _gradient.setStart(_gradientStart, 0);
  90. _gradient.setFinalStop(_gradientFinalStop, 0);
  91. }
  92. const auto background = _gradientEnabled
  93. ? Background(&_gradient)
  94. : _bgOverride
  95. ? *_bgOverride
  96. : _bg;
  97. if (!painter(background)) {
  98. return false;
  99. }
  100. activateAnimation();
  101. return true;
  102. }
  103. void PathShiftGradient::activateAnimation() {
  104. if (_animationActive) {
  105. return;
  106. }
  107. _animationActive = true;
  108. if (!_animation) {
  109. _animation = Animation.lock();
  110. if (!_animation) {
  111. _animation = std::make_shared<AnimationData>();
  112. Animation = _animation;
  113. }
  114. }
  115. const auto raw = _animation.get();
  116. if (_animationCallback) {
  117. raw->active.emplace(this);
  118. }
  119. const auto globalCallback = [] {
  120. const auto strong = Animation.lock();
  121. if (!strong) {
  122. return;
  123. }
  124. strong->scheduled = false;
  125. while (!strong->active.empty()) {
  126. const auto entry = strong->active.back();
  127. strong->active.erase(strong->active.end() - 1);
  128. entry->_animationActive = false;
  129. entry->_animationCallback();
  130. }
  131. };
  132. const auto now = crl::now();
  133. const auto period = now % kFullDuration;
  134. if (period >= kSlideDuration) {
  135. const auto tillWaitFinish = kFullDuration - period;
  136. if (!raw->scheduled) {
  137. raw->scheduled = true;
  138. raw->animation.stop();
  139. base::call_delayed(tillWaitFinish, globalCallback);
  140. }
  141. } else {
  142. const auto tillSlideFinish = kSlideDuration - period;
  143. if (!raw->animation.animating()) {
  144. raw->animation.start(globalCallback, 0., 1., tillSlideFinish);
  145. }
  146. }
  147. }
  148. void PathShiftGradient::refreshColors() {
  149. refreshColors(_bg, _fg);
  150. }
  151. void PathShiftGradient::refreshColors(
  152. const style::color &bg,
  153. const style::color &fg) {
  154. _gradient.setStops({
  155. { 0., bg->c },
  156. { 0.5, fg->c },
  157. { 1., bg->c },
  158. });
  159. _bgOverride = _colorsOverriden ? &bg : nullptr;
  160. }
  161. } // namespace Ui