arcs.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  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/paint/arcs.h"
  8. #include "ui/effects/animation_value.h"
  9. #include "ui/effects/animation_value_f.h"
  10. #include "ui/painter.h"
  11. namespace Ui::Paint {
  12. ArcsAnimation::ArcsAnimation(
  13. const style::ArcsAnimation &st,
  14. std::vector<float> thresholds,
  15. float64 startValue,
  16. Direction direction)
  17. : _st(st)
  18. , _direction(direction)
  19. , _startAngle(16
  20. * (st.deltaAngle
  21. + ((direction == Direction::Up)
  22. ? 90
  23. : (direction == Direction::Down)
  24. ? 270
  25. : (direction == Direction::Left)
  26. ? 180
  27. : 0)))
  28. , _spanAngle(-st.deltaAngle * 2 * 16)
  29. , _emptyRect(computeArcRect(0))
  30. , _currentValue(startValue) {
  31. initArcs(std::move(thresholds));
  32. }
  33. void ArcsAnimation::initArcs(std::vector<float> thresholds) {
  34. const auto count = thresholds.size();
  35. _arcs.reserve(count);
  36. for (auto i = 0; i < count; i++) {
  37. const auto threshold = thresholds[i];
  38. const auto progress = (threshold > _currentValue) ? 1. : 0.;
  39. auto arc = Arc{
  40. .rect = computeArcRect(i + 1),
  41. .threshold = threshold,
  42. .progress = progress,
  43. };
  44. _arcs.push_back(std::move(arc));
  45. }
  46. }
  47. bool ArcsAnimation::isHorizontal() const {
  48. return _direction == Direction::Left || _direction == Direction::Right;
  49. }
  50. QRectF ArcsAnimation::computeArcRect(int index) const {
  51. const auto w = _st.startWidth + _st.deltaWidth * index;
  52. const auto h = _st.startHeight + _st.deltaHeight * index;
  53. if (isHorizontal()) {
  54. auto rect = QRectF(0, -h / 2.0, w, h);
  55. if (_direction == Direction::Right) {
  56. rect.moveRight(index * _st.space);
  57. } else {
  58. rect.moveLeft(-index * _st.space);
  59. }
  60. return rect;
  61. } else {
  62. auto rect = QRectF(-w / 2.0, 0, w, h);
  63. if (_direction == Direction::Up) {
  64. rect.moveTop(-index * _st.space);
  65. } else {
  66. rect.moveBottom(index * _st.space);
  67. }
  68. return rect;
  69. }
  70. return QRectF();
  71. }
  72. void ArcsAnimation::update(crl::time now) {
  73. for (auto &arc : _arcs) {
  74. if (!isArcFinished(arc)) {
  75. const auto progress = std::clamp(
  76. (now - arc.startTime) / float64(_st.duration),
  77. 0.,
  78. 1.);
  79. arc.progress = (arc.threshold > _currentValue)
  80. ? progress
  81. : (1. - progress);
  82. }
  83. }
  84. if (isFinished()) {
  85. _stopUpdateRequests.fire({});
  86. }
  87. }
  88. void ArcsAnimation::setValue(float64 value) {
  89. if (_currentValue == value) {
  90. return;
  91. }
  92. const auto previousValue = _currentValue;
  93. _currentValue = value;
  94. if (!isFinished()) {
  95. const auto now = crl::now();
  96. _startUpdateRequests.fire({});
  97. for (auto &arc : _arcs) {
  98. updateArcStartTime(arc, previousValue, now);
  99. }
  100. }
  101. }
  102. void ArcsAnimation::updateArcStartTime(
  103. Arc &arc,
  104. float64 previousValue,
  105. crl::time now) {
  106. if ((arc.progress == 0.) || (arc.progress == 1.)) {
  107. arc.startTime = isArcFinished(arc) ? 0 : now;
  108. return;
  109. }
  110. const auto isPreviousToHide = (arc.threshold <= previousValue); // 0 -> 1
  111. const auto isCurrentToHide = (arc.threshold <= _currentValue);
  112. if (isPreviousToHide != isCurrentToHide) {
  113. const auto passedTime = _st.duration * arc.progress;
  114. const auto newDelta = isCurrentToHide
  115. ? (_st.duration - passedTime)
  116. : passedTime;
  117. arc.startTime = now - newDelta;
  118. }
  119. }
  120. float ArcsAnimation::width() const {
  121. if (_arcs.empty()) {
  122. return 0;
  123. }
  124. for (const auto &arc : ranges::views::reverse(_arcs)) {
  125. if ((arc.progress != 1.)) {
  126. return arc.rect.x() + arc.rect.width();
  127. }
  128. }
  129. return 0;
  130. }
  131. float ArcsAnimation::finishedWidth() const {
  132. if (_arcs.empty()) {
  133. return 0;
  134. }
  135. for (const auto &arc : ranges::views::reverse(_arcs)) {
  136. if (arc.threshold <= _currentValue) {
  137. return arc.rect.x() + arc.rect.width();
  138. }
  139. }
  140. return 0;
  141. }
  142. float ArcsAnimation::maxWidth() const {
  143. if (_arcs.empty()) {
  144. return 0;
  145. }
  146. const auto &r = _arcs.back().rect;
  147. return r.x() + r.width();
  148. }
  149. float ArcsAnimation::height() const {
  150. return _arcs.empty()
  151. ? 0
  152. : _arcs.back().rect.height();
  153. }
  154. rpl::producer<> ArcsAnimation::startUpdateRequests() {
  155. return _startUpdateRequests.events();
  156. }
  157. rpl::producer<> ArcsAnimation::stopUpdateRequests() {
  158. return _stopUpdateRequests.events();
  159. }
  160. bool ArcsAnimation::isFinished() const {
  161. return ranges::all_of(
  162. _arcs,
  163. [=](const Arc &arc) { return isArcFinished(arc); });
  164. }
  165. bool ArcsAnimation::isArcFinished(const Arc &arc) const {
  166. return ((arc.threshold > _currentValue) && (arc.progress == 1.))
  167. || ((arc.threshold <= _currentValue) && (arc.progress == 0.));
  168. }
  169. void ArcsAnimation::paint(QPainter &p, std::optional<QColor> colorOverride) {
  170. PainterHighQualityEnabler hq(p);
  171. QPen pen;
  172. if (_strokeRatio) {
  173. pen.setWidthF(_st.stroke * _strokeRatio);
  174. } else {
  175. pen.setWidth(_st.stroke);
  176. }
  177. pen.setCapStyle(Qt::RoundCap);
  178. pen.setColor(colorOverride ? (*colorOverride) : _st.fg->c);
  179. p.setPen(pen);
  180. for (auto i = 0; i < _arcs.size(); i++) {
  181. const auto &arc = _arcs[i];
  182. const auto previousRect = (!i) ? _emptyRect : _arcs[i - 1].rect;
  183. const auto progress = arc.progress;
  184. const auto opactity = (1. - progress);
  185. p.setOpacity(opactity * opactity);
  186. const auto rect = (progress == 0.)
  187. ? arc.rect
  188. : (progress == 1.)
  189. ? previousRect
  190. : anim::interpolatedRectF(arc.rect, previousRect, progress);
  191. p.drawArc(rect, _startAngle, _spanAngle);
  192. }
  193. p.setOpacity(1.);
  194. }
  195. void ArcsAnimation::setStrokeRatio(float ratio) {
  196. _strokeRatio = ratio;
  197. }
  198. } // namespace Ui::Paint