dialogs_list.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  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 "dialogs/dialogs_list.h"
  8. #include "dialogs/dialogs_entry.h"
  9. #include "dialogs/ui/dialogs_layout.h"
  10. #include "data/data_session.h"
  11. namespace Dialogs {
  12. List::List(SortMode sortMode, FilterId filterId)
  13. : _sortMode(sortMode)
  14. , _filterId(filterId) {
  15. }
  16. List::const_iterator List::cfind(Row *value) const {
  17. return value
  18. ? (cbegin() + value->index())
  19. : cend();
  20. }
  21. not_null<Row*> List::addToEnd(Key key) {
  22. if (const auto result = getRow(key)) {
  23. return result;
  24. }
  25. const auto result = _rowByKey.emplace(
  26. key,
  27. std::make_unique<Row>(key, _rows.size(), height())
  28. ).first->second.get();
  29. result->recountHeight(_narrowRatio, _filterId);
  30. _rows.emplace_back(result);
  31. if (_sortMode == SortMode::Date) {
  32. adjustByDate(result);
  33. }
  34. return result;
  35. }
  36. Row *List::adjustByName(Key key) {
  37. Expects(_sortMode == SortMode::Name);
  38. const auto row = getRow(key);
  39. if (!row) {
  40. return nullptr;
  41. }
  42. adjustByName(row);
  43. return row;
  44. }
  45. not_null<Row*> List::addByName(Key key) {
  46. Expects(_sortMode == SortMode::Name);
  47. const auto row = addToEnd(key);
  48. adjustByName(key);
  49. return row;
  50. }
  51. void List::adjustByName(not_null<Row*> row) {
  52. Expects(row->index() >= 0 && row->index() < _rows.size());
  53. const auto &key = row->entry()->chatListNameSortKey();
  54. const auto index = row->index();
  55. const auto i = _rows.begin() + index;
  56. const auto before = std::find_if(i + 1, _rows.end(), [&](Row *row) {
  57. return row->entry()->chatListNameSortKey().compare(key) >= 0;
  58. });
  59. if (before != i + 1) {
  60. rotate(i, i + 1, before);
  61. } else if (i != _rows.begin()) {
  62. const auto from = std::make_reverse_iterator(i);
  63. const auto after = std::find_if(from, _rows.rend(), [&](Row *row) {
  64. return row->entry()->chatListNameSortKey().compare(key) <= 0;
  65. }).base();
  66. if (after != i) {
  67. rotate(after, i, i + 1);
  68. }
  69. }
  70. }
  71. void List::adjustByDate(not_null<Row*> row) {
  72. Expects(_sortMode == SortMode::Date);
  73. const auto key = row->sortKey(_filterId);
  74. const auto index = row->index();
  75. const auto i = _rows.begin() + index;
  76. const auto before = std::find_if(i + 1, _rows.end(), [&](Row *row) {
  77. return (row->sortKey(_filterId) <= key);
  78. });
  79. if (before != i + 1) {
  80. rotate(i, i + 1, before);
  81. } else {
  82. const auto from = std::make_reverse_iterator(i);
  83. const auto after = std::find_if(from, _rows.rend(), [&](Row *row) {
  84. return (row->sortKey(_filterId) >= key);
  85. }).base();
  86. if (after != i) {
  87. rotate(after, i, i + 1);
  88. }
  89. }
  90. }
  91. bool List::updateHeight(Key key, float64 narrowRatio) {
  92. const auto i = _rowByKey.find(key);
  93. if (i == _rowByKey.cend()) {
  94. return false;
  95. }
  96. const auto row = i->second.get();
  97. const auto index = row->index();
  98. auto top = row->top();
  99. const auto was = row->height();
  100. row->recountHeight(narrowRatio, _filterId);
  101. if (row->height() == was) {
  102. return false;
  103. }
  104. for (auto i = _rows.begin() + index, e = _rows.end(); i != e; ++i) {
  105. (*i)->_top = top;
  106. top += (*i)->height();
  107. }
  108. return true;
  109. }
  110. bool List::updateHeights(float64 narrowRatio) {
  111. _narrowRatio = narrowRatio;
  112. auto was = height();
  113. auto top = 0;
  114. for (const auto &row : _rows) {
  115. row->_top = top;
  116. row->recountHeight(narrowRatio, _filterId);
  117. top += row->height();
  118. }
  119. return (height() != was);
  120. }
  121. bool List::moveToTop(Key key) {
  122. const auto i = _rowByKey.find(key);
  123. if (i == _rowByKey.cend()) {
  124. return false;
  125. }
  126. const auto index = i->second->index();
  127. const auto begin = _rows.begin();
  128. rotate(begin, begin + index, begin + index + 1);
  129. return true;
  130. }
  131. void List::rotate(
  132. std::vector<not_null<Row*>>::iterator first,
  133. std::vector<not_null<Row*>>::iterator middle,
  134. std::vector<not_null<Row*>>::iterator last) {
  135. auto top = (*first)->top();
  136. std::rotate(first, middle, last);
  137. auto count = (last - first);
  138. auto index = (first - _rows.begin());
  139. while (count--) {
  140. const auto row = *first++;
  141. row->_index = index++;
  142. row->_top = top;
  143. top += row->height();
  144. }
  145. }
  146. bool List::remove(Key key, Row *replacedBy) {
  147. auto i = _rowByKey.find(key);
  148. if (i == _rowByKey.cend()) {
  149. return false;
  150. }
  151. const auto row = i->second.get();
  152. row->entry()->owner().dialogsRowReplaced({ row, replacedBy });
  153. auto top = row->top();
  154. const auto index = row->index();
  155. _rows.erase(_rows.begin() + index);
  156. for (auto i = index, count = int(_rows.size()); i != count; ++i) {
  157. const auto row = _rows[i];
  158. row->_index = i;
  159. row->_top = top;
  160. top += row->height();
  161. }
  162. _rowByKey.erase(i);
  163. return true;
  164. }
  165. Row *List::rowAtY(int y) const {
  166. const auto i = findByY(y);
  167. if (i == cend()) {
  168. return nullptr;
  169. }
  170. const auto row = *i;
  171. const auto top = row->top();
  172. const auto bottom = top + row->height();
  173. return (top <= y && bottom > y) ? row.get() : nullptr;
  174. }
  175. List::iterator List::findByY(int y) const {
  176. return ranges::lower_bound(_rows, y, ranges::less(), [](const Row *row) {
  177. return row->top() + row->height() - 1;
  178. });
  179. }
  180. } // namespace Dialogs