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

View file

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

View file

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

View file

@ -9,6 +9,7 @@
#include "ui/widgets/shadow.h" #include "ui/widgets/shadow.h"
#include "ui/image/image_prepare.h" #include "ui/image/image_prepare.h"
#include "ui/platform/ui_platform_utility.h" #include "ui/platform/ui_platform_utility.h"
#include "ui/widgets/menu//menu_item_base.h"
#include "ui/ui_utility.h" #include "ui/ui_utility.h"
#include "ui/delayed_activation.h" #include "ui/delayed_activation.h"
#include "base/platform/base_platform_info.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) { 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() { void PopupMenu::handleCompositingUpdate() {
@ -211,24 +227,24 @@ void PopupMenu::handleTriggered(const Menu::CallbackData &data) {
} }
bool PopupMenu::popupSubmenuFromAction(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)) { if (const auto i = _submenus.find(data.action); i != end(_submenus)) {
const auto submenu = i->second.get(); const auto submenu = i->second.get();
if (_activeSubmenu == submenu) { if (_activeSubmenu != submenu) {
// There is a strange problem on macOS popupSubmenu(data.action, submenu, data.actionTop, data.source);
// 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);
} }
return true; return true;
} }
return false; 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)) { if (auto currentSubmenu = base::take(_activeSubmenu)) {
currentSubmenu->hideMenu(true); 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); QPoint p(_inner.x() + (style::RightToLeft() ? _padding.right() : _inner.width() - _padding.left()), _inner.y() + actionTop);
_activeSubmenu = submenu; _activeSubmenu = submenu;
_activeSubmenu->showMenu(geometry().topLeft() + p, this, source); _activeSubmenu->showMenu(geometry().topLeft() + p, this, source);
_menu->setChildShownAction(action);
_menu->setChildShown(true);
} else {
_menu->setChildShown(false);
} }
} }
@ -261,6 +274,12 @@ bool PopupMenu::handleKeyPress(int key) {
hideMenu(true); hideMenu(true);
return 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; return false;
} }
@ -337,6 +356,9 @@ void PopupMenu::childHiding(PopupMenu *child) {
if (_activeSubmenu && _activeSubmenu == child) { if (_activeSubmenu && _activeSubmenu == child) {
_activeSubmenu = nullptr; _activeSubmenu = nullptr;
} }
if (!_activeSubmenu) {
_menu->setChildShownAction(nullptr);
}
if (!_hiding && !isHidden()) { if (!_hiding && !isHidden()) {
raise(); raise();
activateWindow(); activateWindow();

View file

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