requests_bar.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  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/chat/requests_bar.h"
  8. #include "ui/chat/group_call_userpics.h"
  9. #include "ui/widgets/shadow.h"
  10. #include "ui/text/text_options.h"
  11. #include "ui/painter.h"
  12. #include "lang/lang_keys.h"
  13. #include "styles/style_chat_helpers.h"
  14. #include "styles/style_calls.h"
  15. #include "styles/style_info.h" // st::topBarArrowPadding, like TopBarWidget.
  16. #include "styles/style_window.h" // st::columnMinimalWidthLeft
  17. #include "styles/palette.h"
  18. #include <QtGui/QtEvents>
  19. namespace Ui {
  20. RequestsBar::RequestsBar(
  21. not_null<QWidget*> parent,
  22. rpl::producer<RequestsBarContent> content)
  23. : _wrap(parent, object_ptr<RpWidget>(parent))
  24. , _inner(_wrap.entity())
  25. , _shadow(std::make_unique<PlainShadow>(_wrap.parentWidget()))
  26. , _userpics(std::make_unique<GroupCallUserpics>(
  27. st::historyRequestsUserpics,
  28. rpl::single(false),
  29. [=] { _inner->update(); })) {
  30. _wrap.hide(anim::type::instant);
  31. _shadow->hide();
  32. _wrap.entity()->paintRequest(
  33. ) | rpl::start_with_next([=](QRect clip) {
  34. QPainter(_wrap.entity()).fillRect(clip, st::historyPinnedBg);
  35. }, lifetime());
  36. _wrap.setAttribute(Qt::WA_OpaquePaintEvent);
  37. auto copy = std::move(
  38. content
  39. ) | rpl::start_spawning(_wrap.lifetime());
  40. rpl::duplicate(
  41. copy
  42. ) | rpl::start_with_next([=](RequestsBarContent &&content) {
  43. _content = content;
  44. if (_content.count > 0) {
  45. if (_content.count == 1 && !_content.nameFull.isEmpty()) {
  46. _textFull.setText(
  47. st::defaultMessageBar.title,
  48. tr::lng_group_requests_pending_user(
  49. tr::now,
  50. lt_user,
  51. _content.nameFull),
  52. Ui::NameTextOptions());
  53. _textShort.setText(
  54. st::defaultMessageBar.title,
  55. tr::lng_group_requests_pending_user(
  56. tr::now,
  57. lt_user,
  58. _content.nameShort),
  59. Ui::NameTextOptions());
  60. } else {
  61. _textShort.setText(
  62. st::defaultMessageBar.title,
  63. tr::lng_group_requests_pending(
  64. tr::now,
  65. lt_count_decimal,
  66. _content.count),
  67. Ui::NameTextOptions());
  68. _textFull.clear();
  69. }
  70. }
  71. _userpics->update(_content.users, !_wrap.isHidden());
  72. _inner->update();
  73. }, lifetime());
  74. std::move(
  75. copy
  76. ) | rpl::map([=](const RequestsBarContent &content) {
  77. return !content.count;
  78. }) | rpl::start_with_next_done([=](bool hidden) {
  79. _shouldBeShown = !hidden;
  80. if (!_forceHidden) {
  81. _wrap.toggle(_shouldBeShown, anim::type::normal);
  82. }
  83. }, [=] {
  84. _forceHidden = true;
  85. _wrap.toggle(false, anim::type::normal);
  86. }, lifetime());
  87. _userpics->widthValue(
  88. ) | rpl::start_with_next([=](int width) {
  89. _userpicsWidth = width;
  90. }, lifetime());
  91. setupInner();
  92. }
  93. RequestsBar::~RequestsBar() = default;
  94. void RequestsBar::setupInner() {
  95. _inner->resize(0, st::historyRequestsHeight);
  96. _inner->paintRequest(
  97. ) | rpl::start_with_next([=](QRect rect) {
  98. auto p = Painter(_inner);
  99. paint(p);
  100. }, _inner->lifetime());
  101. // Clicks.
  102. _inner->setCursor(style::cur_pointer);
  103. _inner->events(
  104. ) | rpl::filter([=](not_null<QEvent*> event) {
  105. return (event->type() == QEvent::MouseButtonPress);
  106. }) | rpl::map([=] {
  107. return _inner->events(
  108. ) | rpl::filter([=](not_null<QEvent*> event) {
  109. return (event->type() == QEvent::MouseButtonRelease);
  110. }) | rpl::take(1) | rpl::filter([=](not_null<QEvent*> event) {
  111. return _inner->rect().contains(
  112. static_cast<QMouseEvent*>(event.get())->pos());
  113. });
  114. }) | rpl::flatten_latest(
  115. ) | rpl::to_empty | rpl::start_to_stream(_barClicks, _inner->lifetime());
  116. _wrap.geometryValue(
  117. ) | rpl::start_with_next([=](QRect rect) {
  118. updateShadowGeometry(rect);
  119. updateControlsGeometry(rect);
  120. }, _inner->lifetime());
  121. }
  122. void RequestsBar::paint(Painter &p) {
  123. p.fillRect(_inner->rect(), st::historyComposeAreaBg);
  124. const auto userpicsSize = st::historyRequestsUserpics.size;
  125. const auto userpicsTop = st::lineWidth + (st::historyRequestsHeight
  126. - st::lineWidth
  127. - userpicsSize) / 2;
  128. const auto userpicsLeft = userpicsTop * 2;
  129. const auto textTop = st::lineWidth + (st::historyRequestsHeight
  130. - st::lineWidth
  131. - st::semiboldFont->height) / 2;
  132. const auto width = _inner->width();
  133. const auto &font = st::defaultMessageBar.title.font;
  134. p.setPen(st::defaultMessageBar.titleFg);
  135. p.setFont(font);
  136. if (width >= st::columnMinimalWidthLeft / 2) {
  137. const auto textLeft = userpicsLeft + _userpicsWidth + userpicsLeft;
  138. const auto available = width - textLeft - userpicsLeft;
  139. if (_textFull.isEmpty() || available < _textFull.maxWidth()) {
  140. _textShort.drawElided(p, textLeft, textTop, available);
  141. } else {
  142. _textFull.drawElided(p, textLeft, textTop, available);
  143. }
  144. }
  145. // Skip shadow of the bar above.
  146. _userpics->paint(p, userpicsLeft, userpicsTop, userpicsSize);
  147. }
  148. void RequestsBar::updateControlsGeometry(QRect wrapGeometry) {
  149. const auto hidden = _wrap.isHidden() || !wrapGeometry.height();
  150. if (_shadow->isHidden() != hidden) {
  151. _shadow->setVisible(!hidden);
  152. }
  153. }
  154. void RequestsBar::setShadowGeometryPostprocess(Fn<QRect(QRect)> postprocess) {
  155. _shadowGeometryPostprocess = std::move(postprocess);
  156. updateShadowGeometry(_wrap.geometry());
  157. }
  158. void RequestsBar::updateShadowGeometry(QRect wrapGeometry) {
  159. const auto regular = QRect(
  160. wrapGeometry.x(),
  161. wrapGeometry.y() + wrapGeometry.height(),
  162. wrapGeometry.width(),
  163. st::lineWidth);
  164. _shadow->setGeometry(_shadowGeometryPostprocess
  165. ? _shadowGeometryPostprocess(regular)
  166. : regular);
  167. }
  168. void RequestsBar::show() {
  169. if (!_forceHidden) {
  170. return;
  171. }
  172. _forceHidden = false;
  173. if (_shouldBeShown) {
  174. _wrap.show(anim::type::instant);
  175. _shadow->show();
  176. }
  177. }
  178. void RequestsBar::hide() {
  179. if (_forceHidden) {
  180. return;
  181. }
  182. _forceHidden = true;
  183. _wrap.hide(anim::type::instant);
  184. _shadow->hide();
  185. }
  186. void RequestsBar::raise() {
  187. _wrap.raise();
  188. _shadow->raise();
  189. }
  190. void RequestsBar::finishAnimating() {
  191. _wrap.finishAnimating();
  192. }
  193. void RequestsBar::move(int x, int y) {
  194. _wrap.move(x, y);
  195. }
  196. void RequestsBar::resizeToWidth(int width) {
  197. _wrap.entity()->resizeToWidth(width);
  198. _inner->resizeToWidth(width);
  199. }
  200. int RequestsBar::height() const {
  201. return !_forceHidden
  202. ? _wrap.height()
  203. : _shouldBeShown
  204. ? st::historyRequestsHeight
  205. : 0;
  206. }
  207. rpl::producer<int> RequestsBar::heightValue() const {
  208. return _wrap.heightValue();
  209. }
  210. rpl::producer<> RequestsBar::barClicks() const {
  211. return _barClicks.events();
  212. }
  213. } // namespace Ui