| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- /*
- 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 "profile/profile_block_peer_list.h"
- #include "ui/effects/ripple_animation.h"
- #include "ui/text/text_options.h"
- #include "ui/painter.h"
- #include "data/data_peer.h"
- #include "data/data_cloud_file.h"
- #include "main/main_session.h"
- #include "styles/style_profile.h"
- #include "styles/style_widgets.h"
- namespace Profile {
- PeerListWidget::Item::Item(not_null<PeerData*> peer) : peer(peer) {
- }
- PeerListWidget::Item::~Item() = default;
- PeerListWidget::PeerListWidget(
- QWidget *parent,
- PeerData *peer,
- const QString &title,
- const style::PeerListItem &st,
- const QString &removeText)
- : BlockWidget(parent, peer, title)
- , _st(st)
- , _removeText(removeText)
- , _removeWidth(st::normalFont->width(_removeText)) {
- setMouseTracking(true);
- peer->session().downloaderTaskFinished(
- ) | rpl::start_with_next([=] {
- update();
- }, lifetime());
- }
- int PeerListWidget::resizeGetHeight(int newWidth) {
- auto newHeight = getListTop();
- newHeight += _items.size() * _st.height;
- return newHeight + _st.bottom;
- }
- void PeerListWidget::visibleTopBottomUpdated(int visibleTop, int visibleBottom) {
- _visibleTop = visibleTop;
- _visibleBottom = visibleBottom;
- if (_preloadMoreCallback) {
- if (_visibleTop + PreloadHeightsCount * (_visibleBottom - _visibleTop) > height()) {
- _preloadMoreCallback();
- }
- }
- }
- void PeerListWidget::paintContents(Painter &p) {
- auto left = getListLeft();
- auto top = getListTop();
- const auto count = int(_items.size());
- auto from = floorclamp(_visibleTop - top, _st.height, 0, count);
- auto to = ceilclamp(_visibleBottom - top, _st.height, 0, count);
- for (auto i = from; i < to; ++i) {
- auto y = top + i * _st.height;
- auto selected = (_pressed >= 0) ? (i == _pressed) : (i == _selected);
- auto selectedRemove = selected && _selectedRemove;
- if (_pressed >= 0 && !_pressedRemove) {
- selectedRemove = false;
- }
- paintItem(p, left, y, _items[i], selected, selectedRemove);
- }
- }
- void PeerListWidget::paintItem(Painter &p, int x, int y, Item *item, bool selected, bool selectedKick) {
- if (_updateItemCallback) {
- _updateItemCallback(item);
- }
- auto memberRowWidth = rowWidth();
- if (selected) {
- paintItemRect(p, x, y, memberRowWidth, _st.height);
- }
- if (auto &ripple = item->ripple) {
- ripple->paint(p, x, y, width());
- if (ripple->empty()) {
- ripple.reset();
- }
- }
- int skip = _st.photoPosition.x();
- item->peer->paintUserpicLeft(p, item->userpic, x + _st.photoPosition.x(), y + _st.photoPosition.y(), width(), _st.photoSize);
- if (item->name.isEmpty()) {
- item->name.setText(
- st::semiboldTextStyle,
- item->peer->name(),
- Ui::NameTextOptions());
- }
- int nameLeft = x + _st.namePosition.x();
- int nameTop = y + _st.namePosition.y();
- int nameWidth = memberRowWidth - _st.namePosition.x() - skip;
- if (item->hasRemoveLink && selected) {
- p.setFont(selectedKick ? st::normalFont->underline() : st::normalFont);
- p.setPen(st::windowActiveTextFg);
- p.drawTextLeft(nameLeft + nameWidth - _removeWidth, nameTop, width(), _removeText, _removeWidth);
- nameWidth -= _removeWidth + skip;
- } else if (item->rank) {
- p.setFont(st::normalFont);
- p.setPen(st::windowActiveTextFg);
- p.drawTextLeft(nameLeft + nameWidth - item->rankWidth, nameTop, width(), *item->rank, item->rankWidth);
- nameWidth -= item->rankWidth + skip;
- }
- p.setPen(st::profileMemberNameFg);
- item->name.drawLeftElided(p, nameLeft, nameTop, nameWidth, width());
- if (item->statusHasOnlineColor) {
- p.setPen(_st.statusFgActive);
- } else {
- p.setPen(selected ? _st.statusFgOver : _st.statusFg);
- }
- p.setFont(st::normalFont);
- p.drawTextLeft(x + _st.statusPosition.x(), y + _st.statusPosition.y(), width(), item->statusText);
- }
- void PeerListWidget::paintItemRect(Painter &p, int x, int y, int w, int h) const {
- p.fillRect(style::rtlrect(x, y, w, h, width()), _st.button.textBgOver);
- }
- void PeerListWidget::mouseMoveEvent(QMouseEvent *e) {
- _mousePosition = e->globalPos();
- updateSelection();
- }
- void PeerListWidget::mousePressEvent(QMouseEvent *e) {
- _mousePosition = e->globalPos();
- updateSelection();
- _pressButton = e->button();
- _pressed = _selected;
- _pressedRemove = _selectedRemove;
- if (_pressed >= 0 && !_pressedRemove) {
- const auto item = _items[_pressed];
- if (!item->ripple) {
- auto memberRowWidth = rowWidth();
- auto mask = Ui::RippleAnimation::RectMask(QSize(memberRowWidth, _st.height));
- item->ripple = std::make_unique<Ui::RippleAnimation>(_st.button.ripple, std::move(mask), [this, index = _pressed] {
- repaintRow(index);
- });
- }
- auto left = getListLeft();
- auto top = getListTop() + _st.height * _pressed;
- item->ripple->add(e->pos() - QPoint(left, top));
- }
- }
- void PeerListWidget::mouseReleaseEvent(QMouseEvent *e) {
- mousePressReleased(e->button());
- }
- void PeerListWidget::mousePressReleased(Qt::MouseButton button) {
- repaintRow(_pressed);
- auto pressed = std::exchange(_pressed, -1);
- auto pressedRemove = base::take(_pressedRemove);
- if (pressed >= 0 && pressed < _items.size()) {
- if (const auto &ripple = _items[pressed]->ripple) {
- ripple->lastStop();
- }
- if (pressed == _selected && pressedRemove == _selectedRemove && button == Qt::LeftButton) {
- InvokeQueued(this, [this, pressedRemove, peer = _items[pressed]->peer] {
- if (auto &callback = (pressedRemove ? _removedCallback : _selectedCallback)) {
- callback(peer);
- }
- });
- }
- }
- setCursor(_selectedRemove ? style::cur_pointer : style::cur_default);
- repaintSelectedRow();
- }
- void PeerListWidget::enterEventHook(QEnterEvent *e) {
- _mousePosition = QCursor::pos();
- updateSelection();
- }
- void PeerListWidget::leaveEventHook(QEvent *e) {
- _mousePosition = QPoint(-1, -1);
- updateSelection();
- }
- void PeerListWidget::updateSelection() {
- auto selected = -1;
- auto selectedKick = false;
- auto mouse = mapFromGlobal(_mousePosition);
- if (rtl()) mouse.setX(width() - mouse.x());
- auto left = getListLeft();
- auto top = getListTop();
- auto memberRowWidth = rowWidth();
- if (mouse.x() >= left && mouse.x() < left + memberRowWidth && mouse.y() >= top) {
- selected = (mouse.y() - top) / _st.height;
- if (selected >= _items.size()) {
- selected = -1;
- } else if (_items[selected]->hasRemoveLink) {
- int skip = _st.photoPosition.x();
- int nameLeft = left + _st.namePosition.x();
- int nameTop = top + _selected * _st.height + _st.namePosition.y();
- int nameWidth = memberRowWidth - _st.namePosition.x() - skip;
- if (mouse.x() >= nameLeft + nameWidth - _removeWidth && mouse.x() < nameLeft + nameWidth) {
- if (mouse.y() >= nameTop && mouse.y() < nameTop + st::normalFont->height) {
- selectedKick = true;
- }
- }
- }
- }
- setSelected(selected, selectedKick);
- }
- void PeerListWidget::setSelected(int selected, bool selectedRemove) {
- if (_selected == selected && _selectedRemove == selectedRemove) {
- return;
- }
- repaintSelectedRow();
- if (_selectedRemove != selectedRemove) {
- _selectedRemove = selectedRemove;
- if (_pressed < 0) {
- setCursor(_selectedRemove ? style::cur_pointer : style::cur_default);
- }
- }
- if (_selected != selected) {
- _selected = selected;
- repaintSelectedRow();
- }
- }
- void PeerListWidget::repaintSelectedRow() {
- repaintRow(_selected);
- }
- void PeerListWidget::repaintRow(int index) {
- if (index >= 0) {
- auto left = getListLeft();
- rtlupdate(left, getListTop() + index * _st.height, width() - left, _st.height);
- }
- }
- int PeerListWidget::getListLeft() const {
- return _st.left;
- }
- int PeerListWidget::rowWidth() const {
- return _st.maximalWidth
- ? qMin(width() - getListLeft(), _st.maximalWidth)
- : width() - getListLeft();
- }
- void PeerListWidget::preloadPhotos() {
- int top = getListTop();
- int preloadFor = (_visibleBottom - _visibleTop) * PreloadHeightsCount;
- int from = floorclamp(_visibleTop - top, _st.height, 0, _items.size());
- int to = ceilclamp(_visibleBottom + preloadFor - top, _st.height, 0, _items.size());
- for (int i = from; i < to; ++i) {
- _items[i]->peer->loadUserpic();
- }
- }
- void PeerListWidget::refreshVisibility() {
- setVisible(!_items.empty());
- }
- } // namespace Profile
|