diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp index 04258c3d2..096273a75 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp @@ -962,6 +962,11 @@ void Suggestions::setupChats() { }); }, _topPeers->lifetime()); + _topPeers->scrollToRequests( + ) | rpl::start_with_next([this](Ui::ScrollToRequest request) { + _chatsScroll->scrollToY(request.ymin, request.ymax); + }, _topPeers->lifetime()); + _chatsScroll->setVisible(_tab.current() == Tab::Chats); } @@ -1015,19 +1020,19 @@ void Suggestions::selectJumpChats(Qt::Key direction, int pageSize) { } else if (direction == Qt::Key_Up) { if (_recentSelectJump(direction, pageSize) == JumpResult::AppliedAndOut) { - _topPeers->selectByKeyboard({}); - _chatsScroll->scrollTo(0); - } else { - _topPeers->deselectByKeyboard(); + _topPeers->selectByKeyboard(direction); + } else if (_topPeers->selectedByKeyboard()) { + _topPeers->selectByKeyboard(direction); } } else if (direction == Qt::Key_Down) { - if (_topPeers->selectedByKeyboard()) { - if (_recentCount.current() > 0) { + if (!_topPeersWrap->toggled() || recentHasSelection()) { + _recentSelectJump(direction, pageSize); + } else if (_topPeers->selectedByKeyboard()) { + if (!_topPeers->selectByKeyboard(direction) + && _recentCount.current() > 0) { _topPeers->deselectByKeyboard(); _recentSelectJump(direction, pageSize); } - } else if (!_topPeersWrap->toggled() || recentHasSelection()) { - _recentSelectJump(direction, pageSize); } else { _topPeers->selectByKeyboard({}); _chatsScroll->scrollTo(0); @@ -1035,7 +1040,6 @@ void Suggestions::selectJumpChats(Qt::Key direction, int pageSize) { } else if (direction == Qt::Key_Left || direction == Qt::Key_Right) { if (!recentHasSelection()) { _topPeers->selectByKeyboard(direction); - _chatsScroll->scrollTo(0); } } } diff --git a/Telegram/SourceFiles/dialogs/ui/top_peers_strip.cpp b/Telegram/SourceFiles/dialogs/ui/top_peers_strip.cpp index 3438c29ba..d32d32814 100644 --- a/Telegram/SourceFiles/dialogs/ui/top_peers_strip.cpp +++ b/Telegram/SourceFiles/dialogs/ui/top_peers_strip.cpp @@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/labels.h" #include "ui/widgets/menu/menu_add_action_callback_factory.h" #include "ui/widgets/popup_menu.h" +#include "ui/widgets/scroll_area.h" #include "ui/dynamic_image.h" #include "ui/painter.h" #include "ui/unread_badge_paint.h" @@ -242,8 +243,12 @@ void TopPeersStrip::stripWheelEvent(QWheelEvent *e) { } void TopPeersStrip::stripLeaveEvent(QEvent *e) { - setSelected(-1); - _selectionByKeyboard = false; + if (!_selectionByKeyboard) { + setSelected(-1); + } + if (!_dragging) { + _lastMousePosition = std::nullopt; + } } void TopPeersStrip::stripMousePressEvent(QMouseEvent *e) { @@ -251,6 +256,7 @@ void TopPeersStrip::stripMousePressEvent(QMouseEvent *e) { return; } _lastMousePosition = e->globalPos(); + _selectionByKeyboard = false; updateSelected(); _mouseDownPosition = _lastMousePosition; @@ -280,7 +286,13 @@ void TopPeersStrip::stripMousePressEvent(QMouseEvent *e) { } void TopPeersStrip::stripMouseMoveEvent(QMouseEvent *e) { - if (_lastMousePosition == e->globalPos() && _selectionByKeyboard) { + if (!_lastMousePosition) { + _lastMousePosition = e->globalPos(); + if (_selectionByKeyboard) { + return; + } + } else if (_selectionByKeyboard + && (_lastMousePosition == e->globalPos())) { return; } _lastMousePosition = e->globalPos(); @@ -288,7 +300,7 @@ void TopPeersStrip::stripMouseMoveEvent(QMouseEvent *e) { updateSelected(); if (!_dragging && _mouseDownPosition) { - if ((_lastMousePosition - *_mouseDownPosition).manhattanLength() + if ((*_lastMousePosition - *_mouseDownPosition).manhattanLength() >= QApplication::startDragDistance()) { if (!_expandAnimation.animating()) { _dragging = true; @@ -303,7 +315,7 @@ void TopPeersStrip::checkDragging() { if (_dragging && !_expandAnimation.animating()) { const auto sign = (style::RightToLeft() ? -1 : 1); const auto newLeft = std::clamp( - (sign * (_mouseDownPosition->x() - _lastMousePosition.x()) + (sign * (_mouseDownPosition->x() - _lastMousePosition->x()) + _startDraggingLeft), 0, _scrollLeftMax); @@ -367,6 +379,7 @@ void TopPeersStrip::stripMouseReleaseEvent(QMouseEvent *e) { if (finishDragging()) { return; } + _selectionByKeyboard = false; updateSelected(); if (_selected >= 0 && _selected == pressed) { Assert(_selected < _entries.size()); @@ -412,6 +425,11 @@ auto TopPeersStrip::showMenuRequests() const return _showMenuRequests.events(); } +auto TopPeersStrip::scrollToRequests() const +-> rpl::producer { + return _scrollToRequests.events(); +} + void TopPeersStrip::removeLocally(uint64 id) { if (!id) { unsubscribeUserpics(true); @@ -446,34 +464,76 @@ bool TopPeersStrip::selectedByKeyboard() const { return _selectionByKeyboard && _selected >= 0; } -void TopPeersStrip::selectByKeyboard(Qt::Key direction) { +bool TopPeersStrip::selectByKeyboard(Qt::Key direction) { if (_entries.empty()) { - return; - } - if (direction == Qt::Key()) { + return false; + } else if (direction == Qt::Key()) { _selectionByKeyboard = true; if (_selected < 0) { setSelected(0); scrollToSelected(); + return true; } } else if (direction == Qt::Key_Left) { if (_selected > 0) { _selectionByKeyboard = true; setSelected(_selected - 1); scrollToSelected(); + return true; } } else if (direction == Qt::Key_Right) { if (_selected + 1 < _entries.size()) { _selectionByKeyboard = true; setSelected(_selected + 1); scrollToSelected(); + return true; + } + } else if (direction == Qt::Key_Up) { + const auto layout = currentLayout(); + if (_selected < 0) { + _selectionByKeyboard = true; + const auto rows = _expanded.current() + ? ((int(_entries.size()) + layout.inrow - 1) / layout.inrow) + : 1; + setSelected((rows - 1) * layout.inrow); + scrollToSelected(); + return true; + } else if (!_expanded.current()) { + deselectByKeyboard(); + } else if (_selected >= 0) { + const auto row = _selected / layout.inrow; + if (row > 0) { + _selectionByKeyboard = true; + setSelected(_selected - layout.inrow); + scrollToSelected(); + return true; + } else { + deselectByKeyboard(); + } + } + } else if (direction == Qt::Key_Down) { + if (_selected >= 0 && _expanded.current()) { + const auto layout = currentLayout(); + const auto row = _selected / layout.inrow; + const auto rows = (int(_entries.size()) + layout.inrow - 1) + / layout.inrow; + if (row + 1 < rows) { + _selectionByKeyboard = true; + setSelected(std::min( + _selected + layout.inrow, + int(_entries.size()) - 1)); + scrollToSelected(); + return true; + } else { + deselectByKeyboard(); + } } } + return false; } void TopPeersStrip::deselectByKeyboard() { if (_selectionByKeyboard) { - _selectionByKeyboard = false; setSelected(-1); } } @@ -760,6 +820,7 @@ void TopPeersStrip::stripContextMenuEvent(QContextMenuEvent *e) { if (e->reason() == QContextMenuEvent::Mouse) { _lastMousePosition = e->globalPos(); + _selectionByKeyboard = false; updateSelected(); } if (_selected < 0 || _entries.empty()) { @@ -781,6 +842,7 @@ void TopPeersStrip::stripContextMenuEvent(QContextMenuEvent *e) { const auto globalPosition = QCursor::pos(); if (rect().contains(mapFromGlobal(globalPosition))) { _lastMousePosition = globalPosition; + _selectionByKeyboard = false; updateSelected(); } }; @@ -798,6 +860,7 @@ bool TopPeersStrip::finishDragging() { } checkDragging(); _dragging = false; + _selectionByKeyboard = false; updateSelected(); return true; } @@ -818,10 +881,10 @@ TopPeersStrip::Layout TopPeersStrip::currentLayout() const { } void TopPeersStrip::updateSelected() { - if (_pressed >= 0) { + if (_pressed >= 0 || !_lastMousePosition || _selectionByKeyboard) { return; } - const auto p = _strip.mapFromGlobal(_lastMousePosition); + const auto p = _strip.mapFromGlobal(*_lastMousePosition); const auto expanded = _expanded.current(); const auto row = expanded ? (p.y() / st::topPeers.height) : 0; const auto layout = currentLayout(); @@ -844,14 +907,24 @@ void TopPeersStrip::setSelected(int selected) { void TopPeersStrip::scrollToSelected() { if (_selected < 0) { return; - } - const auto single = outer().width(); - const auto left = _selected * single; - const auto right = left + single; - if (_scrollLeft > left) { - _scrollLeft = std::clamp(left, 0, _scrollLeftMax); - } else if (_scrollLeft + width() < right) { - _scrollLeft = std::clamp(right - width(), 0, _scrollLeftMax); + } else if (_expanded.current()) { + const auto layout = currentLayout(); + const auto row = _selected / layout.inrow; + const auto header = _header.height(); + const auto top = header + row * st::topPeers.height; + const auto bottom = top + st::topPeers.height; + _scrollToRequests.fire({ top - (row ? 0 : header), bottom}); + } else { + const auto single = outer().width(); + const auto left = _selected * single; + const auto right = left + single; + if (_scrollLeft > left) { + _scrollLeft = std::clamp(left, 0, _scrollLeftMax); + } else if (_scrollLeft + width() < right) { + _scrollLeft = std::clamp(right - width(), 0, _scrollLeftMax); + } + const auto height = _header.height() + st::topPeers.height; + _scrollToRequests.fire({ 0, height }); } } diff --git a/Telegram/SourceFiles/dialogs/ui/top_peers_strip.h b/Telegram/SourceFiles/dialogs/ui/top_peers_strip.h index ac3c73257..f23b3da11 100644 --- a/Telegram/SourceFiles/dialogs/ui/top_peers_strip.h +++ b/Telegram/SourceFiles/dialogs/ui/top_peers_strip.h @@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Ui { class DynamicImage; class LinkButton; +struct ScrollToRequest; } // namespace Ui namespace Dialogs { @@ -51,11 +52,13 @@ public: [[nodiscard]] rpl::producer clicks() const; [[nodiscard]] auto showMenuRequests() const -> rpl::producer; + [[nodiscard]] auto scrollToRequests() const + -> rpl::producer; void removeLocally(uint64 id = 0); [[nodiscard]] bool selectedByKeyboard() const; - void selectByKeyboard(Qt::Key direction); + bool selectByKeyboard(Qt::Key direction); void deselectByKeyboard(); bool chooseRow(); @@ -106,7 +109,7 @@ private: rpl::event_stream _showMenuRequests; rpl::event_stream> _verticalScrollEvents; - QPoint _lastMousePosition; + std::optional _lastMousePosition; std::optional _mouseDownPosition; int _startDraggingLeft = 0; int _scrollLeft = 0; @@ -122,6 +125,8 @@ private: Ui::Animations::Simple _expandAnimation; rpl::variable _expanded = false; + rpl::event_stream _scrollToRequests; + Ui::RoundRect _selection; base::unique_qptr _menu; base::has_weak_ptr _menuGuard;