peer_list_widgets.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  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 "boxes/peer_list_widgets.h"
  8. #include "ui/painter.h"
  9. #include "ui/widgets/buttons.h"
  10. #include "ui/wrap/vertical_layout.h"
  11. #include "styles/style_boxes.h"
  12. namespace {
  13. using State = std::unique_ptr<PeerListState>;
  14. } // namespace
  15. PeerListWidgets::PeerListWidgets(
  16. not_null<Ui::RpWidget*> parent,
  17. not_null<PeerListController*> controller)
  18. : Ui::RpWidget(parent)
  19. , _controller(controller)
  20. , _st(controller->computeListSt()) {
  21. _content = base::make_unique_q<Ui::VerticalLayout>(this);
  22. parent->sizeValue() | rpl::start_with_next([this](const QSize &size) {
  23. _content->resizeToWidth(size.width());
  24. resize(size.width(), _content->height());
  25. }, lifetime());
  26. }
  27. crl::time PeerListWidgets::paintRow(
  28. Painter &p,
  29. crl::time now,
  30. bool selected,
  31. not_null<PeerListRow*> row) {
  32. const auto &st = row->computeSt(_st.item);
  33. row->lazyInitialize(st);
  34. const auto outerWidth = _content->width();
  35. const auto w = outerWidth;
  36. auto refreshStatusAt = row->refreshStatusTime();
  37. if (refreshStatusAt > 0 && now >= refreshStatusAt) {
  38. row->refreshStatus();
  39. refreshStatusAt = row->refreshStatusTime();
  40. }
  41. const auto refreshStatusIn = (refreshStatusAt > 0)
  42. ? std::max(refreshStatusAt - now, crl::time(1))
  43. : 0;
  44. row->paintUserpic(
  45. p,
  46. st,
  47. st.photoPosition.x(),
  48. st.photoPosition.y(),
  49. outerWidth);
  50. p.setPen(st::contactsNameFg);
  51. const auto skipRight = st.photoPosition.x();
  52. const auto rightActionSize = row->rightActionSize();
  53. const auto rightActionMargins = rightActionSize.isEmpty()
  54. ? QMargins()
  55. : row->rightActionMargins();
  56. const auto &name = row->name();
  57. const auto namePosition = st.namePosition;
  58. const auto namex = namePosition.x();
  59. const auto namey = namePosition.y();
  60. auto namew = outerWidth - namex - skipRight;
  61. if (!rightActionSize.isEmpty()
  62. && (namey < rightActionMargins.top() + rightActionSize.height())
  63. && (namey + st.nameStyle.font->height
  64. > rightActionMargins.top())) {
  65. namew -= rightActionMargins.left()
  66. + rightActionSize.width()
  67. + rightActionMargins.right()
  68. - skipRight;
  69. }
  70. const auto statusx = st.statusPosition.x();
  71. const auto statusy = st.statusPosition.y();
  72. auto statusw = outerWidth - statusx - skipRight;
  73. if (!rightActionSize.isEmpty()
  74. && (statusy < rightActionMargins.top() + rightActionSize.height())
  75. && (statusy + st::contactsStatusFont->height
  76. > rightActionMargins.top())) {
  77. statusw -= rightActionMargins.left()
  78. + rightActionSize.width()
  79. + rightActionMargins.right()
  80. - skipRight;
  81. }
  82. namew -= row->paintNameIconGetWidth(
  83. p,
  84. [=] { updateRow(row); },
  85. now,
  86. namex,
  87. namey,
  88. name.maxWidth(),
  89. namew,
  90. w,
  91. selected);
  92. auto nameCheckedRatio = row->disabled() ? 0. : row->checkedRatio();
  93. p.setPen(anim::pen(st.nameFg, st.nameFgChecked, nameCheckedRatio));
  94. name.drawLeftElided(p, namex, namey, namew, w);
  95. p.setFont(st::contactsStatusFont);
  96. row->paintStatusText(p, st, statusx, statusy, statusw, w, selected);
  97. row->elementsPaint(p, outerWidth, selected, 0);
  98. return refreshStatusIn;
  99. }
  100. void PeerListWidgets::appendRow(std::unique_ptr<PeerListRow> row) {
  101. Expects(row != nullptr);
  102. if (_rowsById.find(row->id()) == _rowsById.cend()) {
  103. const auto raw = row.get();
  104. const auto &st = raw->computeSt(_st.item);
  105. raw->setAbsoluteIndex(_rows.size());
  106. _rows.push_back(std::move(row));
  107. const auto widget = _content->add(
  108. object_ptr<Ui::AbstractButton>::fromRaw(
  109. Ui::CreateSimpleSettingsButton(
  110. _content.get(),
  111. st.button.ripple,
  112. st.button.textBgOver)));
  113. widget->resize(widget->width(), st.height);
  114. widget->paintRequest() | rpl::start_with_next([=, this] {
  115. auto p = Painter(widget);
  116. const auto selected = widget->isOver() || widget->isDown();
  117. paintRow(p, crl::now(), selected, raw);
  118. }, widget->lifetime());
  119. widget->setClickedCallback([this, raw] {
  120. _controller->rowClicked(raw);
  121. });
  122. }
  123. }
  124. PeerListRow *PeerListWidgets::findRow(PeerListRowId id) {
  125. const auto it = _rowsById.find(id);
  126. return (it == _rowsById.cend()) ? nullptr : it->second.get();
  127. }
  128. void PeerListWidgets::updateRow(not_null<PeerListRow*> row) {
  129. const auto it = ranges::find_if(
  130. _rows,
  131. [row](const auto &r) { return r.get() == row; });
  132. if (it != _rows.end()) {
  133. const auto index = std::distance(_rows.begin(), it);
  134. if (const auto widget = _content->widgetAt(index)) {
  135. widget->update();
  136. }
  137. }
  138. }
  139. int PeerListWidgets::fullRowsCount() {
  140. return _rows.size();
  141. }
  142. [[nodiscard]] not_null<PeerListRow*> PeerListWidgets::rowAt(int index) {
  143. Expects(index >= 0 && index < _rows.size());
  144. return _rows[index].get();
  145. }
  146. void PeerListWidgets::refreshRows() {
  147. _content->resizeToWidth(width());
  148. resize(width(), _content->height());
  149. }
  150. void PeerListWidgetsDelegate::setContent(PeerListWidgets *content) {
  151. _content = content;
  152. }
  153. void PeerListWidgetsDelegate::setUiShow(
  154. std::shared_ptr<Main::SessionShow> uiShow) {
  155. _uiShow = std::move(uiShow);
  156. }
  157. void PeerListWidgetsDelegate::peerListSetHideEmpty(bool hide) {
  158. Unexpected("...PeerListWidgetsDelegate::peerListSetHideEmpty");
  159. }
  160. void PeerListWidgetsDelegate::peerListAppendRow(
  161. std::unique_ptr<PeerListRow> row) {
  162. _content->appendRow(std::move(row));
  163. }
  164. void PeerListWidgetsDelegate::peerListAppendSearchRow(
  165. std::unique_ptr<PeerListRow> row) {
  166. Unexpected("...PeerListWidgetsDelegate::peerListAppendSearchRow");
  167. }
  168. void PeerListWidgetsDelegate::peerListAppendFoundRow(
  169. not_null<PeerListRow*> row) {
  170. Unexpected("...PeerListWidgetsDelegate::peerListAppendFoundRow");
  171. }
  172. void PeerListWidgetsDelegate::peerListPrependRow(
  173. std::unique_ptr<PeerListRow> row) {
  174. Unexpected("...PeerListWidgetsDelegate::peerListPrependRow");
  175. }
  176. void PeerListWidgetsDelegate::peerListPrependRowFromSearchResult(
  177. not_null<PeerListRow*> row) {
  178. Unexpected(
  179. "...PeerListWidgetsDelegate::peerListPrependRowFromSearchResult");
  180. }
  181. PeerListRow* PeerListWidgetsDelegate::peerListFindRow(PeerListRowId id) {
  182. return _content->findRow(id);
  183. }
  184. auto PeerListWidgetsDelegate::peerListLastRowMousePosition()
  185. -> std::optional<QPoint> {
  186. Unexpected("...PeerListWidgetsDelegate::peerListLastRowMousePosition");
  187. }
  188. void PeerListWidgetsDelegate::peerListUpdateRow(not_null<PeerListRow*> row) {
  189. _content->updateRow(row);
  190. }
  191. void PeerListWidgetsDelegate::peerListRemoveRow(not_null<PeerListRow*> row) {
  192. Unexpected("...PeerListWidgetsDelegate::peerListRemoveRow");
  193. }
  194. void PeerListWidgetsDelegate::peerListConvertRowToSearchResult(
  195. not_null<PeerListRow*> row) {
  196. Unexpected(
  197. "...PeerListWidgetsDelegate::peerListConvertRowToSearchResult");
  198. }
  199. void PeerListWidgetsDelegate::peerListSetRowChecked(
  200. not_null<PeerListRow*> row,
  201. bool checked) {
  202. Unexpected("...PeerListWidgetsDelegate::peerListSetRowChecked");
  203. }
  204. void PeerListWidgetsDelegate::peerListSetRowHidden(
  205. not_null<PeerListRow*> row,
  206. bool hidden) {
  207. Unexpected("...PeerListWidgetsDelegate::peerListSetRowHidden");
  208. }
  209. void PeerListWidgetsDelegate::peerListSetForeignRowChecked(
  210. not_null<PeerListRow*> row,
  211. bool checked,
  212. anim::type animated) {
  213. }
  214. int PeerListWidgetsDelegate::peerListFullRowsCount() {
  215. return _content->fullRowsCount();
  216. }
  217. not_null<PeerListRow*> PeerListWidgetsDelegate::peerListRowAt(int index) {
  218. return _content->rowAt(index);
  219. }
  220. int PeerListWidgetsDelegate::peerListSearchRowsCount() {
  221. Unexpected("...PeerListWidgetsDelegate::peerListSearchRowsCount");
  222. }
  223. not_null<PeerListRow*> PeerListWidgetsDelegate::peerListSearchRowAt(int) {
  224. Unexpected("...PeerListWidgetsDelegate::peerListSearchRowAt");
  225. }
  226. void PeerListWidgetsDelegate::peerListRefreshRows() {
  227. _content->refreshRows();
  228. }
  229. void PeerListWidgetsDelegate::peerListSetDescription(
  230. object_ptr<Ui::FlatLabel>) {
  231. Unexpected("...PeerListWidgetsDelegate::peerListSetDescription");
  232. }
  233. void PeerListWidgetsDelegate::peerListSetSearchNoResults(
  234. object_ptr<Ui::FlatLabel>) {
  235. Unexpected("...PeerListWidgetsDelegate::peerListSetSearchNoResults");
  236. }
  237. void PeerListWidgetsDelegate::peerListSetAboveWidget(
  238. object_ptr<Ui::RpWidget>) {
  239. Unexpected("...PeerListWidgetsDelegate::peerListSetAboveWidget");
  240. }
  241. void PeerListWidgetsDelegate::peerListSetAboveSearchWidget(
  242. object_ptr<Ui::RpWidget>) {
  243. Unexpected("...PeerListWidgetsDelegate::peerListSetAboveSearchWidget");
  244. }
  245. void PeerListWidgetsDelegate::peerListSetBelowWidget(
  246. object_ptr<Ui::RpWidget>) {
  247. Unexpected("...PeerListWidgetsDelegate::peerListSetBelowWidget");
  248. }
  249. void PeerListWidgetsDelegate::peerListSetSearchMode(PeerListSearchMode mode) {
  250. Unexpected("...PeerListWidgetsDelegate::peerListSetSearchMode");
  251. }
  252. void PeerListWidgetsDelegate::peerListMouseLeftGeometry() {
  253. Unexpected("...PeerListWidgetsDelegate::peerListMouseLeftGeometry");
  254. }
  255. void PeerListWidgetsDelegate::peerListSortRows(
  256. Fn<bool(const PeerListRow &, const PeerListRow &)>) {
  257. Unexpected("...PeerListWidgetsDelegate::peerListSortRows");
  258. }
  259. int PeerListWidgetsDelegate::peerListPartitionRows(
  260. Fn<bool(const PeerListRow &a)> border) {
  261. Unexpected("...PeerListWidgetsDelegate::peerListPartitionRows");
  262. }
  263. State PeerListWidgetsDelegate::peerListSaveState() const {
  264. Unexpected("...PeerListWidgetsDelegate::peerListSaveState");
  265. return nullptr;
  266. }
  267. void PeerListWidgetsDelegate::peerListRestoreState(
  268. std::unique_ptr<PeerListState> state) {
  269. Unexpected("...PeerListWidgetsDelegate::peerListRestoreState");
  270. }
  271. void PeerListWidgetsDelegate::peerListShowRowMenu(
  272. not_null<PeerListRow*> row,
  273. bool highlightRow,
  274. Fn<void(not_null<Ui::PopupMenu*>)> destroyed) {
  275. }
  276. void PeerListWidgetsDelegate::peerListSelectSkip(int direction) {
  277. // _content->selectSkip(direction);
  278. }
  279. void PeerListWidgetsDelegate::peerListPressLeftToContextMenu(bool shown) {
  280. Unexpected("...PeerListWidgetsDelegate::peerListPressLeftToContextMenu");
  281. }
  282. bool PeerListWidgetsDelegate::peerListTrackRowPressFromGlobal(QPoint) {
  283. return false;
  284. }
  285. std::shared_ptr<Main::SessionShow> PeerListWidgetsDelegate::peerListUiShow() {
  286. Expects(_uiShow != nullptr);
  287. return _uiShow;
  288. }
  289. void PeerListWidgetsDelegate::peerListAddSelectedPeerInBunch(
  290. not_null<PeerData*> peer) {
  291. Unexpected("...PeerListWidgetsDelegate::peerListAddSelectedPeerInBunch");
  292. }
  293. void PeerListWidgetsDelegate::peerListAddSelectedRowInBunch(
  294. not_null<PeerListRow*> row) {
  295. Unexpected("...PeerListWidgetsDelegate::peerListAddSelectedRowInBunch");
  296. }
  297. void PeerListWidgetsDelegate::peerListFinishSelectedRowsBunch() {
  298. Unexpected("...PeerListWidgetsDelegate::peerListFinishSelectedRowsBunch");
  299. }
  300. void PeerListWidgetsDelegate::peerListSetTitle(rpl::producer<QString> title) {
  301. Unexpected("...PeerListWidgetsDelegate::peerListSetTitle");
  302. }
  303. void PeerListWidgetsDelegate::peerListSetAdditionalTitle(
  304. rpl::producer<QString> title) {
  305. Unexpected("...PeerListWidgetsDelegate::peerListSetAdditionalTitle");
  306. }
  307. bool PeerListWidgetsDelegate::peerListIsRowChecked(
  308. not_null<PeerListRow*> row) {
  309. Unexpected("...PeerListWidgetsDelegate::peerListIsRowChecked");
  310. return false;
  311. }
  312. void PeerListWidgetsDelegate::peerListScrollToTop() {
  313. Unexpected("...PeerListWidgetsDelegate::peerListScrollToTop");
  314. }
  315. int PeerListWidgetsDelegate::peerListSelectedRowsCount() {
  316. Unexpected("...PeerListWidgetsDelegate::peerListSelectedRowsCount");
  317. return 0;
  318. }