diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 231bba6b1..98956f32f 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -1720,7 +1720,10 @@ void Widget::escape() { } void Widget::submit() { - if (_inner->chooseRow()) { + if (_suggestions) { + _suggestions->chooseRow(); + return; + } else if (_inner->chooseRow()) { return; } const auto state = _inner->state(); @@ -3142,13 +3145,34 @@ void Widget::keyPressEvent(QKeyEvent *e) { } else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) { submit(); } else if (e->key() == Qt::Key_Down) { - _inner->selectSkip(1); + if (_suggestions) { + _suggestions->selectSkip(1); + } else { + _inner->selectSkip(1); + } } else if (e->key() == Qt::Key_Up) { + if (_suggestions) { + _suggestions->selectSkip(-1); + } else { + _inner->selectSkip(-1); + } _inner->selectSkip(-1); + } else if (e->key() == Qt::Key_Left && _suggestions) { + _suggestions->selectLeft(); + } else if (e->key() == Qt::Key_Right && _suggestions) { + _suggestions->selectRight(); } else if (e->key() == Qt::Key_PageDown) { - _inner->selectSkipPage(_scroll->height(), 1); + if (_suggestions) { + _suggestions->selectSkipPage(_scroll->height(), 1); + } else { + _inner->selectSkipPage(_scroll->height(), 1); + } } else if (e->key() == Qt::Key_PageUp) { - _inner->selectSkipPage(_scroll->height(), -1); + if (_suggestions) { + _suggestions->selectSkipPage(_scroll->height(), -1); + } else { + _inner->selectSkipPage(_scroll->height(), -1); + } } else if (!(e->modifiers() & ~Qt::ShiftModifier) && e->key() != Qt::Key_Shift && !_openedFolder diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp index 62e63d554..b62c662c4 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp @@ -100,6 +100,43 @@ Suggestions::Suggestions( Suggestions::~Suggestions() = default; +void Suggestions::selectSkip(int delta) { + if (!delta) { + return; + } else if (delta > 0) { + const auto hasRecent = false; + if (hasRecent && (_topPeers->selectedByKeyboard() || delta > 1)) { + _topPeers->deselectByKeyboard(); + } else { + _topPeers->selectByKeyboard(0); + } + } else { + if (_topPeers->selectedByKeyboard()) { + _topPeers->deselectByKeyboard(); + } + } +} + +void Suggestions::selectSkipPage(int height, int direction) { + if (_topPeers->selectedByKeyboard()) { + _topPeers->deselectByKeyboard(); + } +} + +void Suggestions::chooseRow() { + if (_topPeers->chooseRow()) { + return; + } +} + +void Suggestions::selectLeft() { + _topPeers->selectLeft(); +} + +void Suggestions::selectRight() { + _topPeers->selectRight(); +} + void Suggestions::paintEvent(QPaintEvent *e) { QPainter(this).fillRect(e->rect(), st::windowBg); } diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.h b/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.h index f40455f17..aa6491f42 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.h +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.h @@ -36,6 +36,12 @@ public: rpl::producer topPeers); ~Suggestions(); + void selectSkip(int delta); + void selectSkipPage(int height, int direction); + void selectLeft(); + void selectRight(); + void chooseRow(); + [[nodiscard]] rpl::producer topPeerChosen() const { return _topPeerChosen.events(); } diff --git a/Telegram/SourceFiles/dialogs/ui/top_peers_strip.cpp b/Telegram/SourceFiles/dialogs/ui/top_peers_strip.cpp index 2c8e53d36..74756f53c 100644 --- a/Telegram/SourceFiles/dialogs/ui/top_peers_strip.cpp +++ b/Telegram/SourceFiles/dialogs/ui/top_peers_strip.cpp @@ -94,6 +94,11 @@ void TopPeersStrip::wheelEvent(QWheelEvent *e) { e->accept(); } +void TopPeersStrip::leaveEventHook(QEvent *e) { + setSelected(-1); + _selectionByKeyboard = false; +} + void TopPeersStrip::mousePressEvent(QMouseEvent *e) { if (e->button() != Qt::LeftButton) { return; @@ -123,7 +128,11 @@ void TopPeersStrip::mousePressEvent(QMouseEvent *e) { } void TopPeersStrip::mouseMoveEvent(QMouseEvent *e) { + if (_lastMousePosition == e->globalPos() && _selectionByKeyboard) { + return; + } _lastMousePosition = e->globalPos(); + _selectionByKeyboard = false; updateSelected(); if (!_dragging && _mouseDownPosition) { @@ -259,6 +268,58 @@ void TopPeersStrip::removeLocally(uint64 id) { update(); } +bool TopPeersStrip::selectedByKeyboard() const { + return _selectionByKeyboard && _selected >= 0; +} + +void TopPeersStrip::selectByKeyboard(int delta) { + if (_entries.empty()) { + return; + } + _selectionByKeyboard = true; + if (!delta) { + if (_selected < 0) { + setSelected(0); + scrollToSelected(); + } + return; + } + setSelected(std::clamp(_selected + delta, 0, int(_entries.size()) - 1)); + scrollToSelected(); +} + +void TopPeersStrip::deselectByKeyboard() { + if (_selectionByKeyboard) { + _selectionByKeyboard = false; + setSelected(-1); + } +} + +void TopPeersStrip::selectLeft() { + if (_selected > 0) { + _selectionByKeyboard = true; + setSelected(_selected - 1); + scrollToSelected(); + } +} + +void TopPeersStrip::selectRight() { + if (_selected + 1 < _entries.size()) { + _selectionByKeyboard = true; + setSelected(_selected + 1); + scrollToSelected(); + } +} + +bool TopPeersStrip::chooseRow() { + if (_selected >= 0) { + Assert(_selected < _entries.size()); + _clicks.fire_copy(_entries[_selected].id); + return true; + } + return false; +} + void TopPeersStrip::apply(const TopPeersList &list) { auto now = std::vector(); @@ -542,9 +603,10 @@ void TopPeersStrip::updateSelected() { const auto x = p.x(); const auto single = st.photoLeft * 2 + st.photo; const auto index = (_scrollLeft + x) / single; - const auto selected = (index < 0 || index >= _entries.size()) - ? -1 - : index; + setSelected((index < 0 || index >= _entries.size()) ? -1 : index); +} + +void TopPeersStrip::setSelected(int selected) { if (_selected != selected) { const auto over = (selected >= 0); if (over != (_selected >= 0)) { @@ -555,4 +617,19 @@ void TopPeersStrip::updateSelected() { } } +void TopPeersStrip::scrollToSelected() { + if (_selected < 0) { + return; + } + const auto &st = st::topPeers; + const auto single = st.photoLeft * 2 + st.photo; + 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); + } +} + } // namespace Dialogs diff --git a/Telegram/SourceFiles/dialogs/ui/top_peers_strip.h b/Telegram/SourceFiles/dialogs/ui/top_peers_strip.h index 0eead5cc5..5a4c9c2b1 100644 --- a/Telegram/SourceFiles/dialogs/ui/top_peers_strip.h +++ b/Telegram/SourceFiles/dialogs/ui/top_peers_strip.h @@ -52,6 +52,13 @@ public: void removeLocally(uint64 id); + [[nodiscard]] bool selectedByKeyboard() const; + void selectByKeyboard(int delta); + void selectLeft(); + void selectRight(); + void deselectByKeyboard(); + bool chooseRow(); + private: struct Entry; @@ -62,9 +69,12 @@ private: void mouseMoveEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; void contextMenuEvent(QContextMenuEvent *e) override; + void leaveEventHook(QEvent *e) override; void updateScrollMax(); void updateSelected(); + void setSelected(int selected); + void scrollToSelected(); void checkDragging(); bool finishDragging(); void subscribeUserpic(Entry &entry); @@ -94,6 +104,7 @@ private: int _selected = -1; int _pressed = -1; + bool _selectionByKeyboard = false; Ui::RoundRect _selection; base::unique_qptr _menu;