| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- /*
- This file is part of Telegram Desktop,
- the official desktop application for the Telegram messaging service.
- For license and copyright information please follow this link:
- https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
- */
- #include "dialogs/dialogs_list.h"
- #include "dialogs/dialogs_entry.h"
- #include "dialogs/ui/dialogs_layout.h"
- #include "data/data_session.h"
- namespace Dialogs {
- List::List(SortMode sortMode, FilterId filterId)
- : _sortMode(sortMode)
- , _filterId(filterId) {
- }
- List::const_iterator List::cfind(Row *value) const {
- return value
- ? (cbegin() + value->index())
- : cend();
- }
- not_null<Row*> List::addToEnd(Key key) {
- if (const auto result = getRow(key)) {
- return result;
- }
- const auto result = _rowByKey.emplace(
- key,
- std::make_unique<Row>(key, _rows.size(), height())
- ).first->second.get();
- result->recountHeight(_narrowRatio, _filterId);
- _rows.emplace_back(result);
- if (_sortMode == SortMode::Date) {
- adjustByDate(result);
- }
- return result;
- }
- Row *List::adjustByName(Key key) {
- Expects(_sortMode == SortMode::Name);
- const auto row = getRow(key);
- if (!row) {
- return nullptr;
- }
- adjustByName(row);
- return row;
- }
- not_null<Row*> List::addByName(Key key) {
- Expects(_sortMode == SortMode::Name);
- const auto row = addToEnd(key);
- adjustByName(key);
- return row;
- }
- void List::adjustByName(not_null<Row*> row) {
- Expects(row->index() >= 0 && row->index() < _rows.size());
- const auto &key = row->entry()->chatListNameSortKey();
- const auto index = row->index();
- const auto i = _rows.begin() + index;
- const auto before = std::find_if(i + 1, _rows.end(), [&](Row *row) {
- return row->entry()->chatListNameSortKey().compare(key) >= 0;
- });
- if (before != i + 1) {
- rotate(i, i + 1, before);
- } else if (i != _rows.begin()) {
- const auto from = std::make_reverse_iterator(i);
- const auto after = std::find_if(from, _rows.rend(), [&](Row *row) {
- return row->entry()->chatListNameSortKey().compare(key) <= 0;
- }).base();
- if (after != i) {
- rotate(after, i, i + 1);
- }
- }
- }
- void List::adjustByDate(not_null<Row*> row) {
- Expects(_sortMode == SortMode::Date);
- const auto key = row->sortKey(_filterId);
- const auto index = row->index();
- const auto i = _rows.begin() + index;
- const auto before = std::find_if(i + 1, _rows.end(), [&](Row *row) {
- return (row->sortKey(_filterId) <= key);
- });
- if (before != i + 1) {
- rotate(i, i + 1, before);
- } else {
- const auto from = std::make_reverse_iterator(i);
- const auto after = std::find_if(from, _rows.rend(), [&](Row *row) {
- return (row->sortKey(_filterId) >= key);
- }).base();
- if (after != i) {
- rotate(after, i, i + 1);
- }
- }
- }
- bool List::updateHeight(Key key, float64 narrowRatio) {
- const auto i = _rowByKey.find(key);
- if (i == _rowByKey.cend()) {
- return false;
- }
- const auto row = i->second.get();
- const auto index = row->index();
- auto top = row->top();
- const auto was = row->height();
- row->recountHeight(narrowRatio, _filterId);
- if (row->height() == was) {
- return false;
- }
- for (auto i = _rows.begin() + index, e = _rows.end(); i != e; ++i) {
- (*i)->_top = top;
- top += (*i)->height();
- }
- return true;
- }
- bool List::updateHeights(float64 narrowRatio) {
- _narrowRatio = narrowRatio;
- auto was = height();
- auto top = 0;
- for (const auto &row : _rows) {
- row->_top = top;
- row->recountHeight(narrowRatio, _filterId);
- top += row->height();
- }
- return (height() != was);
- }
- bool List::moveToTop(Key key) {
- const auto i = _rowByKey.find(key);
- if (i == _rowByKey.cend()) {
- return false;
- }
- const auto index = i->second->index();
- const auto begin = _rows.begin();
- rotate(begin, begin + index, begin + index + 1);
- return true;
- }
- void List::rotate(
- std::vector<not_null<Row*>>::iterator first,
- std::vector<not_null<Row*>>::iterator middle,
- std::vector<not_null<Row*>>::iterator last) {
- auto top = (*first)->top();
- std::rotate(first, middle, last);
- auto count = (last - first);
- auto index = (first - _rows.begin());
- while (count--) {
- const auto row = *first++;
- row->_index = index++;
- row->_top = top;
- top += row->height();
- }
- }
- bool List::remove(Key key, Row *replacedBy) {
- auto i = _rowByKey.find(key);
- if (i == _rowByKey.cend()) {
- return false;
- }
- const auto row = i->second.get();
- row->entry()->owner().dialogsRowReplaced({ row, replacedBy });
- auto top = row->top();
- const auto index = row->index();
- _rows.erase(_rows.begin() + index);
- for (auto i = index, count = int(_rows.size()); i != count; ++i) {
- const auto row = _rows[i];
- row->_index = i;
- row->_top = top;
- top += row->height();
- }
- _rowByKey.erase(i);
- return true;
- }
- Row *List::rowAtY(int y) const {
- const auto i = findByY(y);
- if (i == cend()) {
- return nullptr;
- }
- const auto row = *i;
- const auto top = row->top();
- const auto bottom = top + row->height();
- return (top <= y && bottom > y) ? row.get() : nullptr;
- }
- List::iterator List::findByY(int y) const {
- return ranges::lower_bound(_rows, y, ranges::less(), [](const Row *row) {
- return row->top() + row->height() - 1;
- });
- }
- } // namespace Dialogs
|