diff --git a/ui/widgets/menu/menu.cpp b/ui/widgets/menu/menu.cpp index b5fb3c9..8b7a90e 100644 --- a/ui/widgets/menu/menu.cpp +++ b/ui/widgets/menu/menu.cpp @@ -9,6 +9,7 @@ #include "ui/widgets/menu/menu_action.h" #include "ui/widgets/menu/menu_item_base.h" #include "ui/widgets/menu/menu_separator.h" +#include "ui/widgets/scroll_area.h" #include @@ -212,6 +213,10 @@ rpl::producer<> Menu::resizesFromInner() const { return _resizesFromInner.events(); } +rpl::producer Menu::scrollToRequests() const { + return _scrollToRequests.events(); +} + void Menu::setShowSource(TriggeredSource source) { const auto mouseSelection = (source == TriggeredSource::Mouse); setSelected( @@ -314,6 +319,13 @@ void Menu::setSelected(int selected, bool isMouseSelection) { const auto source = isMouseSelection ? TriggeredSource::Mouse : TriggeredSource::Keyboard; + if (selected >= 0 && source == TriggeredSource::Keyboard) { + const auto widget = _actionWidgets[selected].get(); + _scrollToRequests.fire({ + widget->y(), + widget->y() + widget->height(), + }); + } if (const auto selectedItem = findSelectedAction()) { if (selectedItem->index() == selected) { return; @@ -321,7 +333,7 @@ void Menu::setSelected(int selected, bool isMouseSelection) { selectedItem->setSelected(false, source); } if (selected >= 0) { - _actionWidgets[selected]->setSelected(true, source); + _actionWidgets[selected].get()->setSelected(true, source); } } diff --git a/ui/widgets/menu/menu.h b/ui/widgets/menu/menu.h index d60547b..0af9898 100644 --- a/ui/widgets/menu/menu.h +++ b/ui/widgets/menu/menu.h @@ -13,6 +13,10 @@ #include +namespace Ui { +struct ScrollToRequest; +} // namespace Ui + namespace Ui::Menu { class ItemBase; @@ -82,7 +86,8 @@ public: } void handleMouseRelease(QPoint globalPosition); - rpl::producer<> resizesFromInner() const; + [[nodiscard]] rpl::producer<> resizesFromInner() const; + [[nodiscard]] rpl::producer scrollToRequests() const; protected: void keyPressEvent(QKeyEvent *e) override; @@ -125,6 +130,7 @@ private: QPointer _childShownAction; rpl::event_stream<> _resizesFromInner; + rpl::event_stream _scrollToRequests; }; diff --git a/ui/widgets/popup_menu.cpp b/ui/widgets/popup_menu.cpp index 1bde6e6..6a7cc17 100644 --- a/ui/widgets/popup_menu.cpp +++ b/ui/widgets/popup_menu.cpp @@ -222,6 +222,16 @@ void PopupMenu::init() { } }, paddingWrap->lifetime()); + _menu->scrollToRequests( + ) | rpl::start_with_next([=](ScrollToRequest request) { + _scroll->scrollTo({ + request.ymin ? (_st.scrollPadding.top() + request.ymin) : 0, + (request.ymax == _menu->height() + ? paddingWrap->height() + : (_st.scrollPadding.top() + request.ymax)), + }); + }, _menu->lifetime()); + _menu->resizesFromInner( ) | rpl::start_with_next([=] { handleMenuResize();