emoji_fly_animation.cpp 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  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 "ui/effects/emoji_fly_animation.h"
  8. #include "data/stickers/data_custom_emoji.h"
  9. #include "ui/text/text_custom_emoji.h"
  10. #include "ui/animated_icon.h"
  11. #include "ui/ui_utility.h"
  12. #include "styles/style_info.h"
  13. #include "styles/style_chat.h"
  14. namespace Ui {
  15. namespace {
  16. [[nodiscard]] int ComputeFlySize(Data::CustomEmojiSizeTag tag) {
  17. using Tag = Data::CustomEmojiSizeTag;
  18. if (tag == Tag::Normal) {
  19. return st::reactionInlineImage;
  20. }
  21. return int(base::SafeRound(
  22. (st::reactionInlineImage * Data::FrameSizeFromTag(tag)
  23. / float64(Data::FrameSizeFromTag(Tag::Normal)))));
  24. }
  25. } // namespace
  26. EmojiFlyAnimation::EmojiFlyAnimation(
  27. not_null<Ui::RpWidget*> body,
  28. not_null<Data::Reactions*> owner,
  29. ReactionFlyAnimationArgs &&args,
  30. Fn<void()> repaint,
  31. Fn<QColor()> textColor,
  32. Data::CustomEmojiSizeTag tag)
  33. : _flySize(ComputeFlySize(tag))
  34. , _textColor(std::move(textColor))
  35. , _fly(
  36. owner,
  37. std::move(args),
  38. std::move(repaint),
  39. _flySize,
  40. tag)
  41. , _layer(body) {
  42. body->sizeValue() | rpl::start_with_next([=](QSize size) {
  43. _layer.setGeometry(QRect(QPoint(), size));
  44. }, _layer.lifetime());
  45. _layer.paintRequest(
  46. ) | rpl::start_with_next([=](QRect clip) {
  47. const auto target = _target.data();
  48. if (!target || !target->isVisible()) {
  49. return;
  50. }
  51. auto p = QPainter(&_layer);
  52. const auto rect = Ui::MapFrom(&_layer, target, target->rect());
  53. const auto skipx = (rect.width() - _flySize) / 2;
  54. const auto skipy = (rect.height() - _flySize) / 2;
  55. const auto area = _fly.paintGetArea(
  56. p,
  57. QPoint(),
  58. QRect(
  59. rect.topLeft() + QPoint(skipx, skipy),
  60. QSize(_flySize, _flySize)),
  61. (_textColor ? _textColor() : st::infoPeerBadge.premiumFg->c),
  62. clip,
  63. crl::now());
  64. if (_areaUpdated || _area.isEmpty()) {
  65. _area = area;
  66. } else {
  67. _area = _area.united(area);
  68. }
  69. }, _layer.lifetime());
  70. _layer.setAttribute(Qt::WA_TransparentForMouseEvents);
  71. _layer.show();
  72. }
  73. not_null<Ui::RpWidget*> EmojiFlyAnimation::layer() {
  74. return &_layer;
  75. }
  76. bool EmojiFlyAnimation::finished() const {
  77. if (const auto target = _target.data()) {
  78. return _fly.finished() || !target->isVisible();
  79. }
  80. return true;
  81. }
  82. void EmojiFlyAnimation::repaint() {
  83. if (_area.isEmpty()) {
  84. _layer.update();
  85. } else {
  86. _layer.update(_area);
  87. _areaUpdated = true;
  88. }
  89. }
  90. bool EmojiFlyAnimation::paintBadgeFrame(not_null<QWidget*> widget) {
  91. _target = widget;
  92. return !_fly.finished();
  93. }
  94. ReactionFlyCenter EmojiFlyAnimation::grabBadgeCenter() {
  95. auto result = _fly.takeCenter();
  96. result.size = _flySize;
  97. return result;
  98. }
  99. } // namespace Ui