boost_badge.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  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 "info/channel_statistics/boosts/giveaway/boost_badge.h"
  8. #include "ui/effects/radial_animation.h"
  9. #include "ui/painter.h"
  10. #include "ui/rect.h"
  11. #include "ui/rp_widget.h"
  12. #include "ui/widgets/labels.h"
  13. #include "styles/style_giveaway.h"
  14. #include "styles/style_statistics.h"
  15. #include "styles/style_widgets.h"
  16. namespace Info::Statistics {
  17. not_null<Ui::RpWidget*> InfiniteRadialAnimationWidget(
  18. not_null<Ui::RpWidget*> parent,
  19. int size,
  20. const style::InfiniteRadialAnimation *st) {
  21. class Widget final : public Ui::RpWidget {
  22. public:
  23. Widget(
  24. not_null<Ui::RpWidget*> p,
  25. int size,
  26. const style::InfiniteRadialAnimation *st)
  27. : Ui::RpWidget(p)
  28. , _st(st ? st : &st::startGiveawayButtonLoading)
  29. , _animation([=] { update(); }, *_st) {
  30. resize(size, size);
  31. shownValue() | rpl::start_with_next([=](bool v) {
  32. return v
  33. ? _animation.start()
  34. : _animation.stop(anim::type::instant);
  35. }, lifetime());
  36. }
  37. protected:
  38. void paintEvent(QPaintEvent *e) override {
  39. auto p = QPainter(this);
  40. p.setPen(st::activeButtonFg);
  41. p.setBrush(st::activeButtonFg);
  42. const auto r = rect() - Margins(_st->thickness);
  43. _animation.draw(p, r.topLeft(), r.size(), width());
  44. }
  45. private:
  46. const style::InfiniteRadialAnimation *_st;
  47. Ui::InfiniteRadialAnimation _animation;
  48. };
  49. return Ui::CreateChild<Widget>(parent.get(), size, st);
  50. }
  51. void AddChildToWidgetCenter(
  52. not_null<Ui::RpWidget*> parent,
  53. not_null<Ui::RpWidget*> child) {
  54. parent->sizeValue(
  55. ) | rpl::start_with_next([=](const QSize &s) {
  56. const auto size = child->size();
  57. child->moveToLeft(
  58. (s.width() - size.width()) / 2,
  59. (s.height() - size.height()) / 2);
  60. }, child->lifetime());
  61. }
  62. QImage CreateBadge(
  63. const style::TextStyle &textStyle,
  64. const QString &text,
  65. int badgeHeight,
  66. const style::margins &textPadding,
  67. const style::color &bg,
  68. const style::color &fg,
  69. float64 bgOpacity,
  70. const style::margins &iconPadding,
  71. const style::icon &icon) {
  72. auto badgeText = Ui::Text::String(textStyle, text);
  73. const auto badgeTextWidth = badgeText.maxWidth();
  74. const auto badgex = 0;
  75. const auto badgey = 0;
  76. const auto badgeh = 0 + badgeHeight;
  77. const auto badgew = badgeTextWidth
  78. + rect::m::sum::h(textPadding);
  79. auto result = QImage(
  80. QSize(badgew, badgeh) * style::DevicePixelRatio(),
  81. QImage::Format_ARGB32_Premultiplied);
  82. result.fill(Qt::transparent);
  83. result.setDevicePixelRatio(style::DevicePixelRatio());
  84. {
  85. auto p = Painter(&result);
  86. p.setPen(Qt::NoPen);
  87. p.setBrush(bg);
  88. const auto r = QRect(badgex, badgey, badgew, badgeh);
  89. {
  90. auto hq = PainterHighQualityEnabler(p);
  91. auto o = ScopedPainterOpacity(p, bgOpacity);
  92. p.drawRoundedRect(r, badgeh / 2, badgeh / 2);
  93. }
  94. p.setPen(fg);
  95. p.setBrush(Qt::NoBrush);
  96. badgeText.drawLeftElided(
  97. p,
  98. r.x() + textPadding.left(),
  99. badgey + textPadding.top(),
  100. badgew,
  101. badgew * 2);
  102. icon.paint(
  103. p,
  104. QPoint(r.x() + iconPadding.left(), r.y() + iconPadding.top()),
  105. badgew * 2);
  106. }
  107. return result;
  108. }
  109. void AddLabelWithBadgeToButton(
  110. not_null<Ui::RpWidget*> parent,
  111. rpl::producer<QString> text,
  112. rpl::producer<int> number,
  113. rpl::producer<bool> shown) {
  114. struct State {
  115. QImage badge;
  116. };
  117. const auto state = parent->lifetime().make_state<State>();
  118. const auto label = Ui::CreateChild<Ui::LabelSimple>(
  119. parent.get(),
  120. st::startGiveawayButtonLabelSimple);
  121. std::move(
  122. text
  123. ) | rpl::start_with_next([=](const QString &s) {
  124. label->setText(s);
  125. }, label->lifetime());
  126. const auto count = Ui::CreateChild<Ui::RpWidget>(parent.get());
  127. count->paintRequest(
  128. ) | rpl::start_with_next([=] {
  129. auto p = QPainter(count);
  130. p.drawImage(0, 0, state->badge);
  131. }, count->lifetime());
  132. std::move(
  133. number
  134. ) | rpl::start_with_next([=](int c) {
  135. state->badge = Info::Statistics::CreateBadge(
  136. st::startGiveawayButtonTextStyle,
  137. QString::number(c),
  138. st::boostsListBadgeHeight,
  139. st::startGiveawayButtonBadgeTextPadding,
  140. st::activeButtonFg,
  141. st::activeButtonBg,
  142. 1.,
  143. st::boostsListMiniIconPadding,
  144. st::startGiveawayButtonMiniIcon);
  145. count->resize(state->badge.size() / style::DevicePixelRatio());
  146. count->update();
  147. }, count->lifetime());
  148. std::move(
  149. shown
  150. ) | rpl::start_with_next([=](bool shown) {
  151. count->setVisible(shown);
  152. label->setVisible(shown);
  153. }, count->lifetime());
  154. rpl::combine(
  155. parent->sizeValue(),
  156. label->sizeValue(),
  157. count->sizeValue()
  158. ) | rpl::start_with_next([=](
  159. const QSize &s,
  160. const QSize &s1,
  161. const QSize &s2) {
  162. const auto sum = st::startGiveawayButtonMiniIconSkip
  163. + s1.width()
  164. + s2.width();
  165. const auto contentLeft = (s.width() - sum) / 2;
  166. label->moveToLeft(contentLeft, (s.height() - s1.height()) / 2);
  167. count->moveToLeft(
  168. contentLeft + sum - s2.width(),
  169. (s.height() - s2.height()) / 2 + st::boostsListMiniIconSkip);
  170. }, parent->lifetime());
  171. }
  172. } // namespace Info::Statistics