Force PopupMenu item selection when submenu is shown.

This commit is contained in:
John Preston 2021-09-08 13:46:34 +03:00
parent 6651d9f9b6
commit f4cf3094c2
5 changed files with 50 additions and 27 deletions

View file

@ -107,6 +107,11 @@ not_null<QAction*> Menu::addAction(base::unique_qptr<ItemBase> widget) {
widget->selects(
) | rpl::start_with_next([=](const CallbackData &data) {
if (!data.selected) {
if (!findSelectedAction()
&& data.index < _actionWidgets.size()
&& _childShownAction == data.action) {
_actionWidgets[data.index]->setSelected(true);
}
return;
}
for (auto i = 0; i < _actionWidgets.size(); i++) {
@ -282,7 +287,7 @@ void Menu::clearMouseSelection() {
const auto mouseSelection = selected
? (selected->lastTriggeredSource() == TriggeredSource::Mouse)
: false;
if (mouseSelection && !_childShown) {
if (mouseSelection && !_childShownAction) {
clearSelection();
}
}

View file

@ -45,8 +45,8 @@ public:
void clearSelection();
void setChildShown(bool shown) {
_childShown = shown;
void setChildShownAction(QAction *action) {
_childShownAction = action;
}
void setShowSource(TriggeredSource source);
void setForceWidth(int forceWidth);
@ -60,6 +60,8 @@ public:
_triggeredCallback = std::move(callback);
}
[[nodiscard]] ItemBase *findSelectedAction() const;
void setKeyPressDelegate(Fn<bool(int key)> delegate) {
_keyPressDelegate = std::move(delegate);
}
@ -102,8 +104,6 @@ private:
void itemPressed(TriggeredSource source);
ItemBase *findSelectedAction() const;
void resizeFromInner(int w, int h);
const style::Menu &_st;
@ -121,7 +121,7 @@ private:
int _forceWidth = 0;
bool _childShown = false;
QPointer<QAction> _childShownAction;
rpl::event_stream<> _resizesFromInner;

View file

@ -189,12 +189,6 @@ void Action::handleKeyPress(not_null<QKeyEvent*> e) {
setClicked(TriggeredSource::Keyboard);
return;
}
if (key == (style::RightToLeft() ? Qt::Key_Left : Qt::Key_Right)) {
if (hasSubmenu()) {
setClicked(TriggeredSource::Keyboard);
return;
}
}
}
} // namespace Ui::Menu

View file

@ -9,6 +9,7 @@
#include "ui/widgets/shadow.h"
#include "ui/image/image_prepare.h"
#include "ui/platform/ui_platform_utility.h"
#include "ui/widgets/menu//menu_item_base.h"
#include "ui/ui_utility.h"
#include "ui/delayed_activation.h"
#include "base/platform/base_platform_info.h"
@ -98,7 +99,22 @@ not_null<PopupMenu*> PopupMenu::ensureSubmenu(not_null<QAction*> action) {
}
void PopupMenu::removeSubmenu(not_null<QAction*> action) {
_submenus.remove(action);
const auto menu = _submenus.take(action);
if (menu && menu->get() == _activeSubmenu) {
base::take(_activeSubmenu)->hideMenu(true);
}
}
void PopupMenu::checkSubmenuShow() {
if (_activeSubmenu) {
return;
} else if (const auto item = _menu->findSelectedAction()) {
if (item->lastTriggeredSource() == Menu::TriggeredSource::Mouse) {
if (_submenus.contains(item->action())) {
item->setClicked(Menu::TriggeredSource::Mouse);
}
}
}
}
void PopupMenu::handleCompositingUpdate() {
@ -211,24 +227,24 @@ void PopupMenu::handleTriggered(const Menu::CallbackData &data) {
}
bool PopupMenu::popupSubmenuFromAction(const Menu::CallbackData &data) {
if (!data.action) {
return false;
}
if (const auto i = _submenus.find(data.action); i != end(_submenus)) {
const auto submenu = i->second.get();
if (_activeSubmenu == submenu) {
// There is a strange problem on macOS
// when a submenu closes arbitrarily
// if we try to move the cursor to it.
#ifndef Q_OS_MAC
submenu->hideMenu(true);
#endif
} else {
popupSubmenu(submenu, data.actionTop, data.source);
if (_activeSubmenu != submenu) {
popupSubmenu(data.action, submenu, data.actionTop, data.source);
}
return true;
}
return false;
}
void PopupMenu::popupSubmenu(not_null<PopupMenu*> submenu, int actionTop, TriggeredSource source) {
void PopupMenu::popupSubmenu(
not_null<QAction*> action,
not_null<PopupMenu*> submenu,
int actionTop,
TriggeredSource source) {
if (auto currentSubmenu = base::take(_activeSubmenu)) {
currentSubmenu->hideMenu(true);
}
@ -236,10 +252,7 @@ void PopupMenu::popupSubmenu(not_null<PopupMenu*> submenu, int actionTop, Trigge
QPoint p(_inner.x() + (style::RightToLeft() ? _padding.right() : _inner.width() - _padding.left()), _inner.y() + actionTop);
_activeSubmenu = submenu;
_activeSubmenu->showMenu(geometry().topLeft() + p, this, source);
_menu->setChildShown(true);
} else {
_menu->setChildShown(false);
_menu->setChildShownAction(action);
}
}
@ -261,6 +274,12 @@ bool PopupMenu::handleKeyPress(int key) {
hideMenu(true);
return true;
}
} else if (key == (style::RightToLeft() ? Qt::Key_Left : Qt::Key_Right)) {
if (const auto item = _menu->findSelectedAction()) {
if (_submenus.contains(item->action())) {
item->setClicked(Menu::TriggeredSource::Keyboard);
}
}
}
return false;
}
@ -337,6 +356,9 @@ void PopupMenu::childHiding(PopupMenu *child) {
if (_activeSubmenu && _activeSubmenu == child) {
_activeSubmenu = nullptr;
}
if (!_activeSubmenu) {
_menu->setChildShownAction(nullptr);
}
if (!_hiding && !isHidden()) {
raise();
activateWindow();

View file

@ -36,6 +36,7 @@ public:
[[nodiscard]] not_null<PopupMenu*> ensureSubmenu(
not_null<QAction*> action);
void removeSubmenu(not_null<QAction*> action);
void checkSubmenuShow();
bool empty() const;
void deleteOnHide(bool del);
@ -107,6 +108,7 @@ private:
bool popupSubmenuFromAction(const Menu::CallbackData &data);
void popupSubmenu(
not_null<QAction*> action,
not_null<PopupMenu*> submenu,
int actionTop,
TriggeredSource source);