emoji_button.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  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/controls/emoji_button.h"
  8. #include "ui/effects/radial_animation.h"
  9. #include "ui/effects/ripple_animation.h"
  10. #include "ui/painter.h"
  11. #include "styles/style_chat_helpers.h"
  12. namespace Ui {
  13. EmojiButton::EmojiButton(QWidget *parent, const style::EmojiButton &st)
  14. : RippleButton(parent, st.inner.ripple)
  15. , _st(st) {
  16. resize(_st.inner.width, _st.inner.height);
  17. setCursor(style::cur_pointer);
  18. }
  19. void EmojiButton::paintEvent(QPaintEvent *e) {
  20. auto p = QPainter(this);
  21. p.fillRect(e->rect(), _st.bg);
  22. const auto &st = _st.inner;
  23. paintRipple(p, st.rippleAreaPosition.x(), st.rippleAreaPosition.y(), _rippleOverride ? &(*_rippleOverride)->c : nullptr);
  24. const auto over = isOver();
  25. const auto loadingState = _loading
  26. ? _loading->computeState()
  27. : RadialState{ 0., 0, RadialState::kFull };
  28. const auto icon = _iconOverride ? _iconOverride : &(over ? st.iconOver : st.icon);
  29. auto position = st.iconPosition;
  30. if (position.x() < 0) {
  31. position.setX((width() - icon->width()) / 2);
  32. }
  33. if (position.y() < 0) {
  34. position.setY((height() - icon->height()) / 2);
  35. }
  36. const auto skipx = icon->width() / 4;
  37. const auto skipy = icon->height() / 4;
  38. const auto inner = QRect(
  39. position + QPoint(skipx, skipy),
  40. QSize(icon->width() - 2 * skipx, icon->height() - 2 * skipy));
  41. if (loadingState.shown < 1.) {
  42. p.setOpacity(1. - loadingState.shown);
  43. icon->paint(p, position, width());
  44. p.setOpacity(1.);
  45. }
  46. const auto color = (_colorOverride
  47. ? *_colorOverride
  48. : (over ? _st.lineFgOver : _st.lineFg));
  49. const auto line = style::ConvertScaleExact(st::historyEmojiCircleLine);
  50. if (anim::Disabled() && _loading && _loading->animating()) {
  51. anim::DrawStaticLoading(p, inner, line, color);
  52. } else {
  53. auto pen = color->p;
  54. pen.setWidthF(line);
  55. pen.setCapStyle(Qt::RoundCap);
  56. p.setPen(pen);
  57. p.setBrush(Qt::NoBrush);
  58. PainterHighQualityEnabler hq(p);
  59. if (loadingState.arcLength < RadialState::kFull) {
  60. p.drawArc(inner, loadingState.arcFrom, loadingState.arcLength);
  61. } else {
  62. p.drawEllipse(inner);
  63. }
  64. }
  65. }
  66. void EmojiButton::loadingAnimationCallback() {
  67. if (!anim::Disabled()) {
  68. update();
  69. }
  70. }
  71. void EmojiButton::setLoading(bool loading) {
  72. if (loading && !_loading) {
  73. _loading = std::make_unique<InfiniteRadialAnimation>(
  74. [=] { loadingAnimationCallback(); },
  75. st::defaultInfiniteRadialAnimation);
  76. }
  77. if (loading) {
  78. _loading->start();
  79. update();
  80. } else if (_loading) {
  81. _loading->stop();
  82. update();
  83. }
  84. }
  85. void EmojiButton::setColorOverrides(const style::icon *iconOverride, const style::color *colorOverride, const style::color *rippleOverride) {
  86. _iconOverride = iconOverride;
  87. _colorOverride = colorOverride;
  88. _rippleOverride = rippleOverride;
  89. update();
  90. }
  91. void EmojiButton::onStateChanged(State was, StateChangeSource source) {
  92. RippleButton::onStateChanged(was, source);
  93. auto wasOver = static_cast<bool>(was & StateFlag::Over);
  94. if (isOver() != wasOver) {
  95. update();
  96. }
  97. }
  98. QPoint EmojiButton::prepareRippleStartPosition() const {
  99. if (!_st.inner.rippleAreaSize) {
  100. return DisabledRippleStartPosition();
  101. }
  102. return mapFromGlobal(QCursor::pos()) - _st.inner.rippleAreaPosition;
  103. }
  104. QImage EmojiButton::prepareRippleMask() const {
  105. const auto size = _st.inner.rippleAreaSize;
  106. return RippleAnimation::EllipseMask(QSize(size, size));
  107. }
  108. } // namespace Ui