diff --git a/src/widget/wsearchrelatedtracksmenu.cpp b/src/widget/wsearchrelatedtracksmenu.cpp index cd2a9dcb381..51e47083df8 100644 --- a/src/widget/wsearchrelatedtracksmenu.cpp +++ b/src/widget/wsearchrelatedtracksmenu.cpp @@ -89,7 +89,8 @@ void WSearchRelatedTracksMenu::addTriggerSearchAction( auto pAction = make_parented(this); pAction->setDefaultWidget(pCheckBox.get()); // While the checkbox is selected (via keyboard, not hovered by pointer) - // pressing Space will toggle it whereas pressing Return triggers the action. + // pressing Space will toggle it whereas pressing Return triggers the action + // and closes the menu (see WTrackMenu). connect(pAction.get(), &QAction::triggered, this, diff --git a/src/widget/wtrackmenu.cpp b/src/widget/wtrackmenu.cpp index f9df992a90b..49ae7d3959a 100644 --- a/src/widget/wtrackmenu.cpp +++ b/src/widget/wtrackmenu.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -152,6 +153,25 @@ void WTrackMenu::closeEvent(QCloseEvent* event) { emit trackMenuVisible(false); } +bool WTrackMenu::eventFilter(QObject* pObj, QEvent* e) { + // If a checkbox in a QWidgetAction is focused, Left/Right keys are translated + // to Up/Down which prevents closing the submenus with Left key like in other + // submenus. We simply call hide() of the submenu if Left is pressed. + if (e->type() == QEvent::KeyPress) { + QCheckBox* cbx = qobject_cast(pObj); + if (cbx) { + // Note: if we ever add checkboxes to the top level we need to + // assert that cbx->parentWidget() != this. + QKeyEvent* pKe = static_cast(e); + if (pKe && pKe->key() == Qt::Key_Left) { + cbx->parentWidget()->hide(); + return true; + } + } + } + return QObject::eventFilter(pObj, e); +} + void WTrackMenu::popup(const QPoint& pos, QAction* at) { if (isEmpty()) { return; @@ -236,6 +256,16 @@ void WTrackMenu::createMenus() { } m_pSearchRelatedMenu->setEnabled( !m_pSearchRelatedMenu->isEmpty()); + if (!m_pSearchRelatedMenu->isEmpty()) { + // We're interested in keypress Qt::Key_Left, so use our + // event filter like we do for the crate checkboxes. + for (const auto ch : m_pSearchRelatedMenu->children()) { + QCheckBox* cb = qobject_cast(ch); + if (cb) { + cb->installEventFilter(this); + } + } + } }); connect(m_pSearchRelatedMenu, &WSearchRelatedTracksMenu::triggerSearch, @@ -1499,6 +1529,8 @@ void WTrackMenu::slotPopulateCrateMenu() { m_pCrateMenu); pCheckBox->setProperty("crateId", QVariant::fromValue(crate.getId())); pCheckBox->setEnabled(!crate.isLocked()); + // We're interested in keypress Qt::Key_Left + pCheckBox->installEventFilter(this); // Strangely, the normal styling of QActions does not automatically // apply to QWidgetActions. The :selected pseudo-state unfortunately // does not work with QWidgetAction. :hover works for selecting items diff --git a/src/widget/wtrackmenu.h b/src/widget/wtrackmenu.h index 23b0efda0b7..1109d31a73a 100644 --- a/src/widget/wtrackmenu.h +++ b/src/widget/wtrackmenu.h @@ -109,6 +109,8 @@ class WTrackMenu : public QMenu { void slotRemoveFromDisk(); const QString getDeckGroup() const; + bool eventFilter(QObject* pObj, QEvent* e) override; + signals: void loadTrackToPlayer(TrackPointer pTrack, const QString& group, bool play = false); void trackMenuVisible(bool visible);