| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194 |
- /*
- 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
- */
- #pragma once
- #include "ui/rp_widget.h"
- #include "ui/empty_userpic.h"
- #include "ui/unread_badge.h"
- #include "ui/userpic_view.h"
- #include "ui/layers/box_content.h"
- #include "base/timer.h"
- namespace style {
- struct PeerList;
- struct PeerListItem;
- struct MultiSelect;
- } // namespace style
- namespace Main {
- class Session;
- class SessionShow;
- } // namespace Main
- namespace Ui {
- class RippleAnimation;
- class RoundImageCheckbox;
- class MultiSelect;
- template <typename Widget>
- class SlideWrap;
- class FlatLabel;
- struct ScrollToRequest;
- class PopupMenu;
- struct OutlineSegment;
- } // namespace Ui
- using PaintRoundImageCallback = Fn<void(
- Painter &p,
- int x,
- int y,
- int outerWidth,
- int size)>;
- [[nodiscard]] PaintRoundImageCallback PaintUserpicCallback(
- not_null<PeerData*> peer,
- bool respectSavedMessagesChat);
- [[nodiscard]] PaintRoundImageCallback ForceRoundUserpicCallback(
- not_null<PeerData*> peer);
- using PeerListRowId = uint64;
- [[nodiscard]] PeerListRowId UniqueRowIdFromString(const QString &d);
- class PeerListRow {
- public:
- enum class State {
- Active,
- Disabled,
- DisabledChecked,
- };
- explicit PeerListRow(not_null<PeerData*> peer);
- PeerListRow(not_null<PeerData*> peer, PeerListRowId id);
- virtual ~PeerListRow();
- void setDisabledState(State state) {
- _disabledState = state;
- }
- // Checked state is controlled by the box with multiselect,
- // not by the row itself, so there is no setChecked() method.
- // We can query the checked state from row, but before it is
- // added to the box it is always false.
- [[nodiscard]] bool checked() const;
- [[nodiscard]] bool special() const {
- return !_peer;
- }
- [[nodiscard]] not_null<PeerData*> peer() const {
- Expects(!special());
- return _peer;
- }
- [[nodiscard]] PeerListRowId id() const {
- return _id;
- }
- [[nodiscard]] Ui::PeerUserpicView &ensureUserpicView();
- [[nodiscard]] virtual QString generateName();
- [[nodiscard]] virtual QString generateShortName();
- [[nodiscard]] virtual auto generatePaintUserpicCallback(
- bool forceRound) -> PaintRoundImageCallback;
- virtual void paintUserpicOverlay(
- Painter &p,
- const style::PeerListItem &st,
- int x,
- int y,
- int outerWidth) {
- }
- [[nodiscard]] virtual auto generateNameFirstLetters() const
- -> const base::flat_set<QChar> &;
- [[nodiscard]] virtual auto generateNameWords() const
- -> const base::flat_set<QString> &;
- [[nodiscard]] virtual const style::PeerListItem &computeSt(
- const style::PeerListItem &st) const;
- virtual void preloadUserpic();
- void setCustomStatus(const QString &status, bool active = false);
- void clearCustomStatus();
- // Box interface.
- virtual int paintNameIconGetWidth(
- Painter &p,
- Fn<void()> repaint,
- crl::time now,
- int nameLeft,
- int nameTop,
- int nameWidth,
- int availableWidth,
- int outerWidth,
- bool selected);
- virtual QSize rightActionSize() const {
- return QSize();
- }
- virtual QMargins rightActionMargins() const {
- return QMargins();
- }
- virtual bool rightActionDisabled() const {
- return false;
- }
- virtual void rightActionPaint(
- Painter &p,
- int x,
- int y,
- int outerWidth,
- bool selected,
- bool actionSelected) {
- }
- virtual void rightActionAddRipple(
- QPoint point,
- Fn<void()> updateCallback) {
- }
- virtual void rightActionStopLastRipple() {
- }
- [[nodiscard]] virtual float64 opacity() {
- return 1.;
- }
- // By default elements code falls back to a simple right action code.
- virtual int elementsCount() const;
- virtual QRect elementGeometry(int element, int outerWidth) const;
- virtual bool elementDisabled(int element) const;
- virtual bool elementOnlySelect(int element) const;
- virtual void elementAddRipple(
- int element,
- QPoint point,
- Fn<void()> updateCallback);
- virtual void elementsStopLastRipple();
- virtual void elementsPaint(
- Painter &p,
- int outerWidth,
- bool selected,
- int selectedElement);
- virtual void refreshName(const style::PeerListItem &st);
- const Ui::Text::String &name() const {
- return _name;
- }
- virtual bool useForumLikeUserpic() const;
- enum class StatusType {
- Online,
- LastSeen,
- Custom,
- CustomActive,
- };
- virtual void refreshStatus();
- crl::time refreshStatusTime() const;
- void setAbsoluteIndex(int index) {
- _absoluteIndex = index;
- }
- int absoluteIndex() const {
- return _absoluteIndex;
- }
- bool disabled() const {
- return (_disabledState != State::Active);
- }
- bool isSearchResult() const {
- return _isSearchResult;
- }
- void setIsSearchResult(bool isSearchResult) {
- _isSearchResult = isSearchResult;
- }
- void setSavedMessagesChatStatus(QString savedMessagesStatus) {
- _savedMessagesStatus = savedMessagesStatus;
- }
- void setIsRepliesMessagesChat(bool isRepliesMessagesChat) {
- _isRepliesMessagesChat = isRepliesMessagesChat;
- }
- void setIsVerifyCodesChat(bool isVerifyCodesChat) {
- _isVerifyCodesChat = isVerifyCodesChat;
- }
- template <typename UpdateCallback>
- void setChecked(
- bool checked,
- const style::RoundImageCheckbox &st,
- anim::type animated,
- UpdateCallback callback) {
- if (checked && !_checkbox) {
- createCheckbox(st, std::move(callback));
- }
- setCheckedInternal(checked, animated);
- }
- void setCustomizedCheckSegments(
- std::vector<Ui::OutlineSegment> segments);
- void setHidden(bool hidden) {
- _hidden = hidden;
- }
- [[nodiscard]] bool hidden() const {
- return _hidden;
- }
- void finishCheckedAnimation();
- void invalidatePixmapsCache();
- template <typename MaskGenerator, typename UpdateCallback>
- void addRipple(
- const style::PeerListItem &st,
- MaskGenerator &&maskGenerator,
- QPoint point,
- UpdateCallback &&updateCallback);
- void stopLastRipple();
- void paintRipple(
- Painter &p,
- const style::PeerListItem &st,
- int x,
- int y,
- int outerWidth);
- void paintUserpic(
- Painter &p,
- const style::PeerListItem &st,
- int x,
- int y,
- int outerWidth);
- float64 checkedRatio();
- void setNameFirstLetters(const base::flat_set<QChar> &firstLetters) {
- _nameFirstLetters = firstLetters;
- }
- const base::flat_set<QChar> &nameFirstLetters() const {
- return _nameFirstLetters;
- }
- void setSkipPeerBadge(bool skip) {
- _skipPeerBadge = skip;
- }
- virtual void lazyInitialize(const style::PeerListItem &st);
- virtual void paintStatusText(
- Painter &p,
- const style::PeerListItem &st,
- int x,
- int y,
- int availableWidth,
- int outerWidth,
- bool selected);
- protected:
- bool isInitialized() const {
- return _initialized;
- }
- explicit PeerListRow(PeerListRowId id);
- private:
- void createCheckbox(
- const style::RoundImageCheckbox &st,
- Fn<void()> updateCallback);
- void setCheckedInternal(bool checked, anim::type animated);
- void paintDisabledCheckUserpic(
- Painter &p,
- const style::PeerListItem &st,
- int x,
- int y,
- int outerWidth) const;
- void setStatusText(const QString &text);
- PeerListRowId _id = 0;
- PeerData *_peer = nullptr;
- mutable Ui::PeerUserpicView _userpic;
- std::unique_ptr<Ui::RippleAnimation> _ripple;
- std::unique_ptr<Ui::RoundImageCheckbox> _checkbox;
- Ui::Text::String _name;
- Ui::Text::String _status;
- Ui::PeerBadge _badge;
- StatusType _statusType = StatusType::Online;
- crl::time _statusValidTill = 0;
- base::flat_set<QChar> _nameFirstLetters;
- QString _savedMessagesStatus;
- int _absoluteIndex = -1;
- State _disabledState = State::Active;
- bool _hidden : 1 = false;
- bool _initialized : 1 = false;
- bool _isSearchResult : 1 = false;
- bool _isRepliesMessagesChat : 1 = false;
- bool _isVerifyCodesChat : 1 = false;
- bool _skipPeerBadge : 1 = false;
- };
- enum class PeerListSearchMode {
- Disabled,
- Enabled,
- };
- struct PeerListState;
- class PeerListDelegate {
- public:
- virtual void peerListSetTitle(rpl::producer<QString> title) = 0;
- virtual void peerListSetAdditionalTitle(rpl::producer<QString> title) = 0;
- virtual void peerListSetHideEmpty(bool hide) = 0;
- virtual void peerListSetDescription(object_ptr<Ui::FlatLabel> description) = 0;
- virtual void peerListSetSearchNoResults(object_ptr<Ui::FlatLabel> noResults) = 0;
- virtual void peerListSetAboveWidget(object_ptr<Ui::RpWidget> aboveWidget) = 0;
- virtual void peerListSetAboveSearchWidget(object_ptr<Ui::RpWidget> aboveWidget) = 0;
- virtual void peerListSetBelowWidget(object_ptr<Ui::RpWidget> belowWidget) = 0;
- virtual void peerListMouseLeftGeometry() = 0;
- virtual void peerListSetSearchMode(PeerListSearchMode mode) = 0;
- virtual void peerListAppendRow(std::unique_ptr<PeerListRow> row) = 0;
- virtual void peerListAppendSearchRow(std::unique_ptr<PeerListRow> row) = 0;
- virtual void peerListAppendFoundRow(not_null<PeerListRow*> row) = 0;
- virtual void peerListPrependRow(std::unique_ptr<PeerListRow> row) = 0;
- virtual void peerListPrependRowFromSearchResult(not_null<PeerListRow*> row) = 0;
- virtual void peerListUpdateRow(not_null<PeerListRow*> row) = 0;
- virtual void peerListRemoveRow(not_null<PeerListRow*> row) = 0;
- virtual void peerListConvertRowToSearchResult(not_null<PeerListRow*> row) = 0;
- virtual bool peerListIsRowChecked(not_null<PeerListRow*> row) = 0;
- virtual void peerListSetRowChecked(not_null<PeerListRow*> row, bool checked) = 0;
- virtual void peerListSetRowHidden(not_null<PeerListRow*> row, bool hidden) = 0;
- virtual void peerListSetForeignRowChecked(
- not_null<PeerListRow*> row,
- bool checked,
- anim::type animated) = 0;
- virtual not_null<PeerListRow*> peerListRowAt(int index) = 0;
- virtual void peerListRefreshRows() = 0;
- virtual void peerListScrollToTop() = 0;
- virtual int peerListFullRowsCount() = 0;
- virtual PeerListRow *peerListFindRow(PeerListRowId id) = 0;
- virtual int peerListSearchRowsCount() = 0;
- virtual not_null<PeerListRow*> peerListSearchRowAt(int index) = 0;
- virtual std::optional<QPoint> peerListLastRowMousePosition() = 0;
- virtual void peerListSortRows(Fn<bool(const PeerListRow &a, const PeerListRow &b)> compare) = 0;
- virtual int peerListPartitionRows(Fn<bool(const PeerListRow &a)> border) = 0;
- virtual std::shared_ptr<Main::SessionShow> peerListUiShow() = 0;
- virtual void peerListSelectSkip(int direction) = 0;
- virtual void peerListPressLeftToContextMenu(bool shown) = 0;
- virtual bool peerListTrackRowPressFromGlobal(QPoint globalPosition) = 0;
- template <typename PeerDataRange>
- void peerListAddSelectedPeers(PeerDataRange &&range) {
- for (const auto peer : range) {
- peerListAddSelectedPeerInBunch(peer);
- }
- peerListFinishSelectedRowsBunch();
- }
- template <typename PeerListRowRange>
- void peerListAddSelectedRows(PeerListRowRange &&range) {
- for (const auto row : range) {
- peerListAddSelectedRowInBunch(row);
- }
- peerListFinishSelectedRowsBunch();
- }
- virtual void peerListShowRowMenu(
- not_null<PeerListRow*> row,
- bool highlightRow,
- Fn<void(not_null<Ui::PopupMenu*>)> destroyed = nullptr) = 0;
- virtual int peerListSelectedRowsCount() = 0;
- virtual std::unique_ptr<PeerListState> peerListSaveState() const = 0;
- virtual void peerListRestoreState(
- std::unique_ptr<PeerListState> state) = 0;
- virtual ~PeerListDelegate() = default;
- private:
- virtual void peerListAddSelectedPeerInBunch(not_null<PeerData*> peer) = 0;
- virtual void peerListAddSelectedRowInBunch(not_null<PeerListRow*> row) = 0;
- virtual void peerListFinishSelectedRowsBunch() = 0;
- };
- class PeerListSearchDelegate {
- public:
- virtual void peerListSearchAddRow(not_null<PeerData*> peer) = 0;
- virtual void peerListSearchAddRow(PeerListRowId id) = 0;
- virtual void peerListSearchRefreshRows() = 0;
- virtual ~PeerListSearchDelegate() = default;
- };
- class PeerListSearchController {
- public:
- struct SavedStateBase {
- virtual ~SavedStateBase() = default;
- };
- virtual void searchQuery(const QString &query) = 0;
- virtual bool isLoading() = 0;
- virtual bool loadMoreRows() = 0;
- virtual ~PeerListSearchController() = default;
- void setDelegate(not_null<PeerListSearchDelegate*> delegate) {
- _delegate = delegate;
- }
- virtual std::unique_ptr<SavedStateBase> saveState() const {
- return nullptr;
- }
- virtual void restoreState(
- std::unique_ptr<SavedStateBase> state) {
- }
- rpl::lifetime &lifetime() {
- return _lifetime;
- }
- protected:
- not_null<PeerListSearchDelegate*> delegate() const {
- return _delegate;
- }
- private:
- PeerListSearchDelegate *_delegate = nullptr;
- rpl::lifetime _lifetime;
- };
- class PeerListController : public PeerListSearchDelegate {
- public:
- struct SavedStateBase {
- virtual ~SavedStateBase() = default;
- };
- // Search works only with RowId == peer->id.
- PeerListController(
- std::unique_ptr<PeerListSearchController> searchController = {});
- void setDelegate(not_null<PeerListDelegate*> delegate) {
- _delegate = delegate;
- prepare();
- }
- [[nodiscard]] not_null<PeerListDelegate*> delegate() const {
- return _delegate;
- }
- void setStyleOverrides(
- const style::PeerList *listSt,
- const style::MultiSelect *selectSt = nullptr) {
- _listSt = listSt;
- _selectSt = selectSt;
- }
- const style::PeerList *listSt() const {
- return _listSt;
- }
- const style::MultiSelect *selectSt() const {
- return _selectSt;
- }
- const style::PeerList &computeListSt() const;
- const style::MultiSelect &computeSelectSt() const;
- virtual Main::Session &session() const = 0;
- virtual void prepare() = 0;
- virtual void showFinished() {
- }
- virtual void rowClicked(not_null<PeerListRow*> row) = 0;
- virtual void rowMiddleClicked(not_null<PeerListRow*> row) {
- }
- virtual void rowRightActionClicked(not_null<PeerListRow*> row) {
- }
- // By default elements code falls back to a simple right action code.
- virtual void rowElementClicked(not_null<PeerListRow*> row, int element) {
- if (element == 1) {
- rowRightActionClicked(row);
- }
- }
- virtual bool rowTrackPress(not_null<PeerListRow*> row) {
- return false;
- }
- virtual void rowTrackPressCancel() {
- }
- virtual bool rowTrackPressSkipMouseSelection() {
- return false;
- }
- virtual void loadMoreRows() {
- }
- virtual void itemDeselectedHook(not_null<PeerData*> peer) {
- }
- virtual bool isForeignRow(PeerListRowId itemId) {
- return false;
- }
- virtual bool handleDeselectForeignRow(PeerListRowId itemId) {
- return false;
- }
- virtual base::unique_qptr<Ui::PopupMenu> rowContextMenu(
- QWidget *parent,
- not_null<PeerListRow*> row);
- bool isSearchLoading() const {
- return _searchController ? _searchController->isLoading() : false;
- }
- virtual std::unique_ptr<PeerListRow> createSearchRow(
- not_null<PeerData*> peer) {
- return nullptr;
- }
- virtual std::unique_ptr<PeerListRow> createSearchRow(PeerListRowId id);
- virtual std::unique_ptr<PeerListRow> createRestoredRow(
- not_null<PeerData*> peer) {
- return nullptr;
- }
- virtual std::unique_ptr<PeerListState> saveState() const;
- virtual void restoreState(
- std::unique_ptr<PeerListState> state);
- [[nodiscard]] virtual int contentWidth() const;
- [[nodiscard]] virtual rpl::producer<int> boxHeightValue() const;
- [[nodiscard]] virtual int descriptionTopSkipMin() const;
- [[nodiscard]] bool isRowSelected(not_null<PeerListRow*> row) {
- return delegate()->peerListIsRowChecked(row);
- }
- virtual bool trackSelectedList() {
- return true;
- }
- virtual bool searchInLocal() {
- return true;
- }
- [[nodiscard]] bool hasComplexSearch() const;
- void search(const QString &query);
- void peerListSearchAddRow(not_null<PeerData*> peer) override;
- void peerListSearchAddRow(PeerListRowId id) override;
- void peerListSearchRefreshRows() override;
- [[nodiscard]] virtual QString savedMessagesChatStatus() const {
- return QString();
- }
- [[nodiscard]] virtual int customRowHeight() {
- Unexpected("PeerListController::customRowHeight.");
- }
- virtual void customRowPaint(
- Painter &p,
- crl::time now,
- not_null<PeerListRow*> row,
- bool selected) {
- Unexpected("PeerListController::customRowPaint.");
- }
- [[nodiscard]] virtual bool customRowSelectionPoint(
- not_null<PeerListRow*> row,
- int x,
- int y) {
- Unexpected("PeerListController::customRowSelectionPoint.");
- }
- [[nodiscard]] virtual Fn<QImage()> customRowRippleMaskGenerator() {
- Unexpected("PeerListController::customRowRippleMaskGenerator.");
- }
- virtual bool overrideKeyboardNavigation(
- int direction,
- int fromIndex,
- int toIndex) {
- return false;
- }
- [[nodiscard]] rpl::lifetime &lifetime() {
- return _lifetime;
- }
- virtual ~PeerListController() = default;
- protected:
- PeerListSearchController *searchController() const {
- return _searchController.get();
- }
- void setDescriptionText(const QString &text);
- void setSearchNoResultsText(const QString &text);
- void setDescription(object_ptr<Ui::FlatLabel> description) {
- delegate()->peerListSetDescription(std::move(description));
- }
- void setSearchNoResults(object_ptr<Ui::FlatLabel> noResults) {
- delegate()->peerListSetSearchNoResults(std::move(noResults));
- }
- void sortByName();
- private:
- PeerListDelegate *_delegate = nullptr;
- std::unique_ptr<PeerListSearchController> _searchController = nullptr;
- const style::PeerList *_listSt = nullptr;
- const style::MultiSelect *_selectSt = nullptr;
- rpl::lifetime _lifetime;
- };
- struct PeerListState {
- PeerListState() = default;
- PeerListState(PeerListState &&other) = delete;
- PeerListState &operator=(PeerListState &&other) = delete;
- std::unique_ptr<PeerListController::SavedStateBase> controllerState;
- std::vector<not_null<PeerData*>> list;
- std::vector<not_null<PeerData*>> filterResults;
- QString searchQuery;
- };
- class PeerListContent : public Ui::RpWidget {
- public:
- PeerListContent(
- QWidget *parent,
- not_null<PeerListController*> controller);
- struct SkipResult {
- int shouldMoveTo = 0;
- int reallyMovedTo = 0;
- };
- SkipResult selectSkip(int direction);
- void selectSkipPage(int height, int direction);
- void selectLast();
- enum class Mode {
- Default,
- Custom,
- };
- void setMode(Mode mode);
- [[nodiscard]] rpl::producer<int> selectedIndexValue() const;
- [[nodiscard]] int selectedIndex() const;
- [[nodiscard]] bool hasSelection() const;
- [[nodiscard]] bool hasPressed() const;
- void clearSelection();
- void searchQueryChanged(QString query);
- bool submitted();
- PeerListRowId updateFromParentDrag(QPoint globalPosition);
- void dragLeft();
- void setIgnoreHiddenRowsOnSearch(bool value);
- // Interface for the controller.
- void appendRow(std::unique_ptr<PeerListRow> row);
- void appendSearchRow(std::unique_ptr<PeerListRow> row);
- void appendFoundRow(not_null<PeerListRow*> row);
- void prependRow(std::unique_ptr<PeerListRow> row);
- void prependRowFromSearchResult(not_null<PeerListRow*> row);
- PeerListRow *findRow(PeerListRowId id);
- std::optional<QPoint> lastRowMousePosition() const;
- void updateRow(not_null<PeerListRow*> row) {
- updateRow(row, RowIndex());
- }
- void removeRow(not_null<PeerListRow*> row);
- void convertRowToSearchResult(not_null<PeerListRow*> row);
- int fullRowsCount() const;
- not_null<PeerListRow*> rowAt(int index) const;
- int searchRowsCount() const;
- not_null<PeerListRow*> searchRowAt(int index) const;
- void setDescription(object_ptr<Ui::FlatLabel> description);
- void setSearchLoading(object_ptr<Ui::FlatLabel> loading);
- void setSearchNoResults(object_ptr<Ui::FlatLabel> noResults);
- void setAboveWidget(object_ptr<Ui::RpWidget> widget);
- void setAboveSearchWidget(object_ptr<Ui::RpWidget> widget);
- void setBelowWidget(object_ptr<Ui::RpWidget> width);
- void setHideEmpty(bool hide);
- void refreshRows();
- void mouseLeftGeometry();
- void pressLeftToContextMenu(bool shown);
- bool trackRowPressFromGlobal(QPoint globalPosition);
- void setSearchMode(PeerListSearchMode mode);
- void changeCheckState(
- not_null<PeerListRow*> row,
- bool checked,
- anim::type animated);
- void setRowHidden(
- not_null<PeerListRow*> row,
- bool hidden);
- template <typename ReorderCallback>
- void reorderRows(ReorderCallback &&callback) {
- callback(_rows.begin(), _rows.end());
- for (auto &searchEntity : _searchIndex) {
- callback(searchEntity.second.begin(), searchEntity.second.end());
- }
- refreshIndices();
- if (!_hiddenRows.empty()) {
- callback(_filterResults.begin(), _filterResults.end());
- }
- update();
- }
- [[nodiscard]] std::unique_ptr<PeerListState> saveState() const;
- void restoreState(std::unique_ptr<PeerListState> state);
- void showRowMenu(
- not_null<PeerListRow*> row,
- bool highlightRow,
- Fn<void(not_null<Ui::PopupMenu*>)> destroyed);
- [[nodiscard]] auto scrollToRequests() const {
- return _scrollToRequests.events();
- }
- [[nodiscard]] auto noSearchSubmits() const {
- return _noSearchSubmits.events();
- }
- ~PeerListContent();
- protected:
- int resizeGetHeight(int newWidth) override;
- void visibleTopBottomUpdated(
- int visibleTop,
- int visibleBottom) override;
- void paintEvent(QPaintEvent *e) override;
- void enterEventHook(QEnterEvent *e) override;
- void leaveEventHook(QEvent *e) override;
- void mouseMoveEvent(QMouseEvent *e) override;
- void mousePressEvent(QMouseEvent *e) override;
- void mouseReleaseEvent(QMouseEvent *e) override;
- void contextMenuEvent(QContextMenuEvent *e) override;
- private:
- void refreshIndices();
- void removeRowAtIndex(std::vector<std::unique_ptr<PeerListRow>> &from, int index);
- void handleNameChanged(not_null<PeerData*> peer);
- void invalidatePixmapsCache();
- struct RowIndex {
- RowIndex() {
- }
- explicit RowIndex(int value) : value(value) {
- }
- int value = -1;
- };
- friend inline bool operator==(RowIndex a, RowIndex b) {
- return (a.value == b.value);
- }
- friend inline bool operator!=(RowIndex a, RowIndex b) {
- return !(a == b);
- }
- struct Selected {
- Selected() {
- }
- Selected(RowIndex index, int element)
- : index(index)
- , element(element) {
- }
- Selected(int index, int element)
- : index(index)
- , element(element) {
- }
- RowIndex index;
- int element = 0;
- };
- friend inline bool operator==(Selected a, Selected b) {
- return (a.index == b.index) && (a.element == b.element);
- }
- friend inline bool operator!=(Selected a, Selected b) {
- return !(a == b);
- }
- struct SelectedSaved {
- SelectedSaved(PeerListRowId id, Selected old)
- : id(id), old(old) {
- }
- PeerListRowId id = 0;
- Selected old;
- };
- void setSelected(Selected selected);
- void setPressed(Selected pressed);
- void setContexted(Selected contexted);
- void restoreSelection();
- SelectedSaved saveSelectedData(Selected from);
- Selected restoreSelectedData(SelectedSaved from);
- void selectByMouse(QPoint globalPosition);
- void loadProfilePhotos();
- void checkScrollForPreload();
- void updateRow(not_null<PeerListRow*> row, RowIndex hint);
- void updateRow(RowIndex row);
- int getRowTop(RowIndex row) const;
- PeerListRow *getRow(RowIndex element);
- RowIndex findRowIndex(
- not_null<PeerListRow*> row,
- RowIndex hint = RowIndex());
- QRect getElementRect(
- not_null<PeerListRow*> row,
- RowIndex index,
- int element) const;
- bool showRowMenu(
- RowIndex index,
- PeerListRow *row,
- QPoint globalPos,
- bool highlightRow,
- Fn<void(not_null<Ui::PopupMenu*>)> destroyed = nullptr);
- crl::time paintRow(Painter &p, crl::time now, RowIndex index);
- void addRowEntry(not_null<PeerListRow*> row);
- void addToSearchIndex(not_null<PeerListRow*> row);
- bool addingToSearchIndex() const;
- void removeFromSearchIndex(not_null<PeerListRow*> row);
- void setSearchQuery(const QString &query, const QString &normalizedQuery);
- bool showingSearch() const {
- return !_hiddenRows.empty() || !_searchQuery.isEmpty();
- }
- int shownRowsCount() const {
- return showingSearch() ? _filterResults.size() : _rows.size();
- }
- template <typename Callback>
- bool enumerateShownRows(Callback callback);
- template <typename Callback>
- bool enumerateShownRows(int from, int to, Callback callback);
- int rowsTop() const;
- int labelHeight() const;
- void clearSearchRows();
- void clearAllContent();
- void handleMouseMove(QPoint globalPosition);
- void mousePressReleased(Qt::MouseButton button);
- void initDecorateWidget(Ui::RpWidget *widget);
- const style::PeerList &_st;
- not_null<PeerListController*> _controller;
- PeerListSearchMode _searchMode = PeerListSearchMode::Disabled;
- Mode _mode = Mode::Default;
- int _rowHeight = 0;
- int _visibleTop = 0;
- int _visibleBottom = 0;
- Selected _selected;
- Selected _pressed;
- Selected _contexted;
- rpl::variable<int> _selectedIndex = -1;
- bool _mouseSelection = false;
- std::optional<QPoint> _lastMousePosition;
- Qt::MouseButton _pressButton = Qt::LeftButton;
- std::optional<QPoint> _trackPressStart;
- rpl::event_stream<Ui::ScrollToRequest> _scrollToRequests;
- std::vector<std::unique_ptr<PeerListRow>> _rows;
- std::map<PeerListRowId, not_null<PeerListRow*>> _rowsById;
- std::map<PeerData*, std::vector<not_null<PeerListRow*>>> _rowsByPeer;
- std::map<QChar, std::vector<not_null<PeerListRow*>>> _searchIndex;
- QString _searchQuery;
- QString _normalizedSearchQuery;
- QString _mentionHighlight;
- std::vector<not_null<PeerListRow*>> _filterResults;
- base::flat_set<not_null<PeerListRow*>> _hiddenRows;
- int _aboveHeight = 0;
- int _belowHeight = 0;
- bool _hideEmpty = false;
- bool _ignoreHiddenRowsOnSearch = false;
- object_ptr<Ui::RpWidget> _aboveWidget = { nullptr };
- object_ptr<Ui::RpWidget> _aboveSearchWidget = { nullptr };
- object_ptr<Ui::RpWidget> _belowWidget = { nullptr };
- object_ptr<Ui::FlatLabel> _description = { nullptr };
- object_ptr<Ui::FlatLabel> _searchNoResults = { nullptr };
- object_ptr<Ui::FlatLabel> _searchLoading = { nullptr };
- object_ptr<Ui::RpWidget> _loadingAnimation = { nullptr };
- rpl::event_stream<> _noSearchSubmits;
- std::vector<std::unique_ptr<PeerListRow>> _searchRows;
- base::Timer _repaintByStatus;
- base::unique_qptr<Ui::PopupMenu> _contextMenu;
- };
- class PeerListContentDelegate : public PeerListDelegate {
- public:
- void setContent(PeerListContent *content) {
- _content = content;
- }
- void peerListSetHideEmpty(bool hide) override {
- _content->setHideEmpty(hide);
- }
- void peerListAppendRow(
- std::unique_ptr<PeerListRow> row) override {
- _content->appendRow(std::move(row));
- }
- void peerListAppendSearchRow(
- std::unique_ptr<PeerListRow> row) override {
- _content->appendSearchRow(std::move(row));
- }
- void peerListAppendFoundRow(
- not_null<PeerListRow*> row) override {
- _content->appendFoundRow(row);
- }
- void peerListPrependRow(
- std::unique_ptr<PeerListRow> row) override {
- _content->prependRow(std::move(row));
- }
- void peerListPrependRowFromSearchResult(
- not_null<PeerListRow*> row) override {
- _content->prependRowFromSearchResult(row);
- }
- PeerListRow *peerListFindRow(PeerListRowId id) override {
- return _content->findRow(id);
- }
- std::optional<QPoint> peerListLastRowMousePosition() override {
- return _content->lastRowMousePosition();
- }
- void peerListUpdateRow(not_null<PeerListRow*> row) override {
- _content->updateRow(row);
- }
- void peerListRemoveRow(not_null<PeerListRow*> row) override {
- _content->removeRow(row);
- }
- void peerListConvertRowToSearchResult(
- not_null<PeerListRow*> row) override {
- _content->convertRowToSearchResult(row);
- }
- void peerListSetRowChecked(
- not_null<PeerListRow*> row,
- bool checked) override {
- _content->changeCheckState(row, checked, anim::type::normal);
- }
- void peerListSetRowHidden(
- not_null<PeerListRow*> row,
- bool hidden) override {
- _content->setRowHidden(row, hidden);
- }
- void peerListSetForeignRowChecked(
- not_null<PeerListRow*> row,
- bool checked,
- anim::type animated) override {
- }
- int peerListFullRowsCount() override {
- return _content->fullRowsCount();
- }
- not_null<PeerListRow*> peerListRowAt(int index) override {
- return _content->rowAt(index);
- }
- int peerListSearchRowsCount() override {
- return _content->searchRowsCount();
- }
- not_null<PeerListRow*> peerListSearchRowAt(int index) override {
- return _content->searchRowAt(index);
- }
- void peerListRefreshRows() override {
- _content->refreshRows();
- }
- void peerListSetDescription(object_ptr<Ui::FlatLabel> description) override {
- _content->setDescription(std::move(description));
- }
- void peerListSetSearchNoResults(object_ptr<Ui::FlatLabel> noResults) override {
- _content->setSearchNoResults(std::move(noResults));
- }
- void peerListSetAboveWidget(object_ptr<Ui::RpWidget> aboveWidget) override {
- _content->setAboveWidget(std::move(aboveWidget));
- }
- void peerListSetAboveSearchWidget(object_ptr<Ui::RpWidget> aboveWidget) override {
- _content->setAboveSearchWidget(std::move(aboveWidget));
- }
- void peerListSetBelowWidget(object_ptr<Ui::RpWidget> belowWidget) override {
- _content->setBelowWidget(std::move(belowWidget));
- }
- void peerListSetSearchMode(PeerListSearchMode mode) override {
- _content->setSearchMode(mode);
- }
- void peerListMouseLeftGeometry() override {
- _content->mouseLeftGeometry();
- }
- void peerListSortRows(
- Fn<bool(const PeerListRow &a, const PeerListRow &b)> compare) override {
- _content->reorderRows([&](
- auto &&begin,
- auto &&end) {
- std::stable_sort(begin, end, [&](auto &&a, auto &&b) {
- return compare(*a, *b);
- });
- });
- }
- int peerListPartitionRows(
- Fn<bool(const PeerListRow &a)> border) override {
- auto result = 0;
- _content->reorderRows([&](
- auto &&begin,
- auto &&end) {
- auto edge = std::stable_partition(begin, end, [&](
- auto &¤t) {
- return border(*current);
- });
- result = (edge - begin);
- });
- return result;
- }
- std::unique_ptr<PeerListState> peerListSaveState() const override {
- return _content->saveState();
- }
- void peerListRestoreState(
- std::unique_ptr<PeerListState> state) override {
- _content->restoreState(std::move(state));
- }
- void peerListShowRowMenu(
- not_null<PeerListRow*> row,
- bool highlightRow,
- Fn<void(not_null<Ui::PopupMenu*>)> destroyed = nullptr) override;
- void peerListSelectSkip(int direction) override {
- _content->selectSkip(direction);
- }
- void peerListPressLeftToContextMenu(bool shown) override {
- _content->pressLeftToContextMenu(shown);
- }
- bool peerListTrackRowPressFromGlobal(QPoint globalPosition) override {
- return _content->trackRowPressFromGlobal(globalPosition);
- }
- protected:
- not_null<PeerListContent*> content() const {
- return _content;
- }
- private:
- PeerListContent *_content = nullptr;
- };
- class PeerListContentDelegateSimple : public PeerListContentDelegate {
- public:
- void peerListSetTitle(rpl::producer<QString> title) override {
- }
- void peerListSetAdditionalTitle(rpl::producer<QString> title) override {
- }
- bool peerListIsRowChecked(not_null<PeerListRow*> row) override {
- return false;
- }
- int peerListSelectedRowsCount() override {
- return 0;
- }
- void peerListScrollToTop() override {
- }
- void peerListAddSelectedPeerInBunch(
- not_null<PeerData*> peer) override {
- Unexpected("...DelegateSimple::peerListAddSelectedPeerInBunch");
- }
- void peerListAddSelectedRowInBunch(not_null<PeerListRow*> row) override {
- Unexpected("...DelegateSimple::peerListAddSelectedRowInBunch");
- }
- void peerListFinishSelectedRowsBunch() override {
- Unexpected("...DelegateSimple::peerListFinishSelectedRowsBunch");
- }
- void peerListSetDescription(
- object_ptr<Ui::FlatLabel> description) override {
- description.destroy();
- }
- std::shared_ptr<Main::SessionShow> peerListUiShow() override {
- Unexpected("...DelegateSimple::peerListUiShow");
- }
- };
- class PeerListContentDelegateShow : public PeerListContentDelegateSimple {
- public:
- explicit PeerListContentDelegateShow(
- std::shared_ptr<Main::SessionShow> show);
- std::shared_ptr<Main::SessionShow> peerListUiShow() override;
- private:
- std::shared_ptr<Main::SessionShow> _show;
- };
- class PeerListBox
- : public Ui::BoxContent
- , public PeerListContentDelegate {
- public:
- PeerListBox(
- QWidget*,
- std::unique_ptr<PeerListController> controller,
- Fn<void(not_null<PeerListBox*>)> init);
- [[nodiscard]] std::vector<PeerListRowId> collectSelectedIds();
- [[nodiscard]] std::vector<not_null<PeerData*>> collectSelectedRows();
- [[nodiscard]] rpl::producer<int> multiSelectHeightValue() const;
- [[nodiscard]] rpl::producer<> noSearchSubmits() const;
- void peerListSetTitle(rpl::producer<QString> title) override {
- setTitle(std::move(title));
- }
- void peerListSetAdditionalTitle(rpl::producer<QString> title) override {
- setAdditionalTitle(std::move(title));
- }
- void peerListSetSearchMode(PeerListSearchMode mode) override;
- void peerListSetRowChecked(
- not_null<PeerListRow*> row,
- bool checked) override;
- void peerListSetForeignRowChecked(
- not_null<PeerListRow*> row,
- bool checked,
- anim::type animated) override;
- bool peerListIsRowChecked(not_null<PeerListRow*> row) override;
- int peerListSelectedRowsCount() override;
- void peerListScrollToTop() override;
- std::shared_ptr<Main::SessionShow> peerListUiShow() override;
- void setAddedTopScrollSkip(int skip);
- void showFinished() override;
- void appendQueryChangedCallback(Fn<void(QString)>);
- protected:
- void prepare() override;
- void setInnerFocus() override;
- void keyPressEvent(QKeyEvent *e) override;
- void resizeEvent(QResizeEvent *e) override;
- void paintEvent(QPaintEvent *e) override;
- private:
- void peerListAddSelectedPeerInBunch(
- not_null<PeerData*> peer) override {
- addSelectItem(peer, anim::type::instant);
- }
- void peerListAddSelectedRowInBunch(not_null<PeerListRow*> row) override {
- addSelectItem(row, anim::type::instant);
- }
- void peerListFinishSelectedRowsBunch() override;
- void addSelectItem(
- not_null<PeerData*> peer,
- anim::type animated);
- void addSelectItem(
- not_null<PeerListRow*> row,
- anim::type animated);
- void addSelectItem(
- uint64 itemId,
- const QString &text,
- PaintRoundImageCallback paintUserpic,
- anim::type animated);
- void createMultiSelect();
- int getTopScrollSkip() const;
- void updateScrollSkips();
- void searchQueryChanged(const QString &query);
- object_ptr<Ui::SlideWrap<Ui::MultiSelect>> _select = { nullptr };
- const std::shared_ptr<Main::SessionShow> _show;
- Fn<void(QString)> _customQueryChangedCallback;
- std::unique_ptr<PeerListController> _controller;
- Fn<void(PeerListBox*)> _init;
- bool _scrollBottomFixed = false;
- int _addedTopScrollSkip = 0;
- };
|