diff --git a/src/controllers/controlpickermenu.cpp b/src/controllers/controlpickermenu.cpp index ac5f5e523e0f..baa074563557 100644 --- a/src/controllers/controlpickermenu.cpp +++ b/src/controllers/controlpickermenu.cpp @@ -354,47 +354,64 @@ ControlPickerMenu::ControlPickerMenu(QWidget* pParent) // Library Controls QMenu* libraryMenu = addSubmenu(tr("Library")); - addPrefixedControl("[Playlist]", "ToggleSelectedSidebarItem", - tr("Expand/Collapse View"), - tr("Expand/collapse the selected view (library, playlist..)"), + addPrefixedControl("[Library]", "MoveUp", + tr("Move up"), + tr("Equivalent to pressing the UP key on the keyboard"), m_libraryStr, libraryMenu); - - addPrefixedControl("[Playlist]", "SelectPlaylist", - tr("Switch Next/Previous View"), - tr("Switch to the next or previous view (library, playlist..)"), + addPrefixedControl("[Library]", "MoveDown", + tr("Move down"), + tr("Equivalent to pressing the DOWN key on the keyboard"), + m_libraryStr, libraryMenu); + addPrefixedControl("[Library]", "MoveVertical", + tr("Move up/down"), + tr("Move vertically in either direction using a knob, as if pressing UP/DOWN keys"), + m_libraryStr, libraryMenu); + addPrefixedControl("[Library]", "ScrollUp", + tr("Scroll Up"), + tr("Equivalent to pressing the PAGE UP key on the keyboard"), m_libraryStr, libraryMenu); - addPrefixedControl("[Playlist]", "SelectNextPlaylist", - tr("Switch To Next View"), - tr("Switch to the next view (library, playlist..)"), + addPrefixedControl("[Library]", "ScrollDown", + tr("Scroll Down"), + tr("Equivalent to pressing the PAGE DOWN key on the keyboard"), m_libraryStr, libraryMenu); - addPrefixedControl("[Playlist]", "SelectPrevPlaylist", - tr("Switch To Previous View"), - tr("Switch to the previous view (library, playlist..)"), + addPrefixedControl("[Library]", "ScrollVertical", + tr("Scroll up/down"), + tr("Scroll vertically in either direction using a knob, as if pressing PGUP/PGDOWN keys"), m_libraryStr, libraryMenu); - addPrefixedControl("[Playlist]", "SelectTrackKnob", - tr("Scroll To Next/Previous Track"), - tr("Scroll up or down in library/playlist"), + addPrefixedControl("[Library]", "MoveLeft", + tr("Move left"), + tr("Equivalent to pressing the LEFT key on the keyboard"), m_libraryStr, libraryMenu); - addPrefixedControl("[Playlist]", "SelectNextTrack", - tr("Scroll To Next Track"), - tr("Scroll to next track in library/playlist"), + addPrefixedControl("[Library]", "MoveRight", + tr("Move right"), + tr("Equivalent to pressing the RIGHT key on the keyboard"), m_libraryStr, libraryMenu); - addPrefixedControl("[Playlist]", "SelectPrevTrack", - tr("Scroll To Previous Track"), - tr("Scroll to previous track in library/playlist"), + addPrefixedControl("[Library]", "MoveHorizontal", + tr("Move left/right"), + tr("Move horizontall in either direction using a knob, as if pressing LEFT/RIGHT keys"), m_libraryStr, libraryMenu); - addPrefixedControl("[Playlist]", "LoadSelectedIntoFirstStopped", - tr("Load Track Into Stopped Deck"), - tr("Load selected track into first stopped deck"), + addPrefixedControl("[Library]", "MoveFocusForward", + tr("Move focus to right pane"), + tr("Equivalent to pressing the TAB key on the keyboard"), m_libraryStr, libraryMenu); - addPrefixedControl("[Playlist]", "AutoDjAddBottom", + addPrefixedControl("[Library]", "MoveFocusBackward", + tr("Move focus to left pane"), + tr("Equivalent to pressing the SHIFT+TAB key on the keyboard"), + m_libraryStr, libraryMenu); + addPrefixedControl("[Library]", "MoveFocus", + tr("Move focus to right/left pane"), + tr("Move focus one pane to right or left using a knob, as if pressing TAB/SHIFT+TAB keys"), + m_libraryStr, libraryMenu); + addPrefixedControl("[Library]", "AutoDjAddBottom", tr("Add to Auto DJ Queue (bottom)"), tr("Append the selected track to the Auto DJ Queue"), m_libraryStr, libraryMenu); - addPrefixedControl("[Playlist]", "AutoDjAddTop", + addPrefixedControl("[Library]", "AutoDjAddTop", tr("Add to Auto DJ Queue (top)"), tr("Prepend selected track to the Auto DJ Queue"), m_libraryStr, libraryMenu); + + // Load track (these can be loaded into any channel) addDeckAndSamplerControl("LoadSelectedTrack", tr("Load Track"), tr("Load selected track"), libraryMenu); diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index 9b2197e422e8..5ed512d8bf14 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -223,3 +223,7 @@ void DlgAutoDJ::updateSelectionInfo() { labelSelectionInfo->setEnabled(false); } } + +bool DlgAutoDJ::hasFocus() const { + return QWidget::hasFocus(); +} diff --git a/src/library/autodj/dlgautodj.h b/src/library/autodj/dlgautodj.h index fda36bcdcbbe..902c88d03b8c 100644 --- a/src/library/autodj/dlgautodj.h +++ b/src/library/autodj/dlgautodj.h @@ -23,13 +23,14 @@ class DlgAutoDJ : public QWidget, public Ui::DlgAutoDJ, public LibraryView { Library* pLibrary, AutoDJProcessor* pProcessor, TrackCollection* pTrackCollection, KeyboardEventFilter* pKeyboard); - virtual ~DlgAutoDJ(); - - void onShow(); - void onSearch(const QString& text); - void loadSelectedTrack(); - void loadSelectedTrackToGroup(QString group, bool play); - void moveSelection(int delta); + ~DlgAutoDJ() override; + + void onShow() override; + bool hasFocus() const override; + void onSearch(const QString& text) override; + void loadSelectedTrack() override; + void loadSelectedTrackToGroup(QString group, bool play) override; + void moveSelection(int delta) override; public slots: void shufflePlaylistButton(bool buttonChecked); diff --git a/src/library/dlganalysis.cpp b/src/library/dlganalysis.cpp index 6d8ec9f38012..56ea62176640 100644 --- a/src/library/dlganalysis.cpp +++ b/src/library/dlganalysis.cpp @@ -72,6 +72,10 @@ void DlgAnalysis::onShow() { m_pAnalysisLibraryTableModel->select(); } +bool DlgAnalysis::hasFocus() const { + return QWidget::hasFocus(); +} + void DlgAnalysis::onSearch(const QString& text) { m_pAnalysisLibraryTableModel->search(text); } diff --git a/src/library/dlganalysis.h b/src/library/dlganalysis.h index 84520b38cf66..012fadaffabc 100644 --- a/src/library/dlganalysis.h +++ b/src/library/dlganalysis.h @@ -18,15 +18,16 @@ class DlgAnalysis : public QWidget, public Ui::DlgAnalysis, public virtual Libra DlgAnalysis(QWidget *parent, UserSettingsPointer pConfig, TrackCollection* pTrackCollection); - virtual ~DlgAnalysis(); + ~DlgAnalysis() override; - virtual void onSearch(const QString& text); - virtual void onShow(); - virtual void loadSelectedTrack(); - virtual void loadSelectedTrackToGroup(QString group, bool play); - virtual void slotSendToAutoDJ(); - virtual void slotSendToAutoDJTop(); - virtual void moveSelection(int delta); + void onSearch(const QString& text) override; + void onShow() override; + bool hasFocus() const override; + void loadSelectedTrack() override; + void loadSelectedTrackToGroup(QString group, bool play) override; + void slotSendToAutoDJ() override; + void slotSendToAutoDJTop() override; + void moveSelection(int delta) override; inline const QString currentSearch() { return m_pAnalysisLibraryTableModel->currentSearch(); } diff --git a/src/library/dlghidden.cpp b/src/library/dlghidden.cpp index 9cddafb9912d..5335f5baa272 100644 --- a/src/library/dlghidden.cpp +++ b/src/library/dlghidden.cpp @@ -94,3 +94,7 @@ void DlgHidden::setTrackTableFont(const QFont& font) { void DlgHidden::setTrackTableRowHeight(int rowHeight) { m_pTrackTableView->setTrackTableRowHeight(rowHeight); } + +bool DlgHidden::hasFocus() const { + return QWidget::hasFocus(); +} diff --git a/src/library/dlghidden.h b/src/library/dlghidden.h index 6b78d85f1fca..a59a54254667 100644 --- a/src/library/dlghidden.h +++ b/src/library/dlghidden.h @@ -18,10 +18,11 @@ class DlgHidden : public QWidget, public Ui::DlgHidden, public LibraryView { DlgHidden(QWidget* parent, UserSettingsPointer pConfig, Library* pLibrary, TrackCollection* pTrackCollection, KeyboardEventFilter* pKeyboard); - virtual ~DlgHidden(); + ~DlgHidden() override; - void onShow(); - void onSearch(const QString& text); + void onShow() override; + bool hasFocus() const override; + void onSearch(const QString& text) override; public slots: void clicked(); diff --git a/src/library/dlgmissing.cpp b/src/library/dlgmissing.cpp index 3f5918bfb3ed..e5207b4d4406 100644 --- a/src/library/dlgmissing.cpp +++ b/src/library/dlgmissing.cpp @@ -87,3 +87,7 @@ void DlgMissing::setTrackTableFont(const QFont& font) { void DlgMissing::setTrackTableRowHeight(int rowHeight) { m_pTrackTableView->setTrackTableRowHeight(rowHeight); } + +bool DlgMissing::hasFocus() const { + return QWidget::hasFocus(); +} diff --git a/src/library/dlgmissing.h b/src/library/dlgmissing.h index fe287e8e8ef3..e3879a397ca1 100644 --- a/src/library/dlgmissing.h +++ b/src/library/dlgmissing.h @@ -17,10 +17,11 @@ class DlgMissing : public QWidget, public Ui::DlgMissing, public LibraryView { DlgMissing(QWidget* parent, UserSettingsPointer pConfig, Library* pLibrary, TrackCollection* pTrackCollection, KeyboardEventFilter* pKeyboard); - virtual ~DlgMissing(); + ~DlgMissing() override; - void onShow(); - void onSearch(const QString& text); + void onShow() override; + bool hasFocus() const override; + void onSearch(const QString& text) override; public slots: void clicked(); diff --git a/src/library/librarycontrol.cpp b/src/library/librarycontrol.cpp index 577b9fac1724..d8920456cdee 100644 --- a/src/library/librarycontrol.cpp +++ b/src/library/librarycontrol.cpp @@ -18,22 +18,19 @@ LoadToGroupController::LoadToGroupController(QObject* pParent, const QString& group) : QObject(pParent), m_group(group) { - m_pLoadControl = new ControlPushButton(ConfigKey(group, "LoadSelectedTrack")); - connect(m_pLoadControl, SIGNAL(valueChanged(double)), + m_pLoadControl = std::make_unique(ConfigKey(group, "LoadSelectedTrack")); + connect(m_pLoadControl.get(), SIGNAL(valueChanged(double)), this, SLOT(slotLoadToGroup(double))); - m_pLoadAndPlayControl = new ControlPushButton(ConfigKey(group, "LoadSelectedTrackAndPlay")); - connect(m_pLoadAndPlayControl, SIGNAL(valueChanged(double)), + m_pLoadAndPlayControl = std::make_unique(ConfigKey(group, "LoadSelectedTrackAndPlay")); + connect(m_pLoadAndPlayControl.get(), SIGNAL(valueChanged(double)), this, SLOT(slotLoadToGroupAndPlay(double))); connect(this, SIGNAL(loadToGroup(QString, bool)), pParent, SLOT(slotLoadSelectedTrackToGroup(QString, bool))); } -LoadToGroupController::~LoadToGroupController() { - delete m_pLoadControl; - delete m_pLoadAndPlayControl; -} +LoadToGroupController::~LoadToGroupController() = default; void LoadToGroupController::slotLoadToGroup(double v) { if (v > 0) { @@ -50,8 +47,8 @@ void LoadToGroupController::slotLoadToGroupAndPlay(double v) { LibraryControl::LibraryControl(Library* pLibrary) : QObject(pLibrary), m_pLibrary(pLibrary), - m_pLibraryWidget(NULL), - m_pSidebarWidget(NULL), + m_pLibraryWidget(nullptr), + m_pSidebarWidget(nullptr), m_numDecks("[Master]", "num_decks", this), m_numSamplers("[Master]", "num_samplers", this), m_numPreviewDecks("[Master]", "num_preview_decks", this) { @@ -63,89 +60,114 @@ LibraryControl::LibraryControl(Library* pLibrary) m_numSamplers.connectValueChanged(SLOT(slotNumSamplersChanged(double))); m_numPreviewDecks.connectValueChanged(SLOT(slotNumPreviewDecksChanged(double))); - // Make controls for library navigation and track loading. + // Controls to navigate vertically within currently focussed widget (up/down buttons) + m_pMoveUp = std::make_unique(ConfigKey("[Library]", "MoveUp")); + m_pMoveDown = std::make_unique(ConfigKey("[Library]", "MoveDown")); + m_pMoveVertical = std::make_unique(ConfigKey("[Library]", "MoveVertical"), false); + connect(m_pMoveUp.get(), SIGNAL(valueChanged(double)),this, SLOT(slotMoveUp(double))); + connect(m_pMoveDown.get(), SIGNAL(valueChanged(double)),this, SLOT(slotMoveDown(double))); + connect(m_pMoveVertical.get(), SIGNAL(valueChanged(double)),this, SLOT(slotMoveVertical(double))); + + // Controls to navigate vertically within currently focussed widget (up/down buttons) + m_pScrollUp = std::make_unique(ConfigKey("[Library]", "ScrollUp")); + m_pScrollDown = std::make_unique(ConfigKey("[Library]", "ScrollDown")); + m_pScrollVertical = std::make_unique(ConfigKey("[Library]", "ScrollVertical"), false); + connect(m_pScrollUp.get(), SIGNAL(valueChanged(double)),this, SLOT(slotScrollUp(double))); + connect(m_pScrollDown.get(), SIGNAL(valueChanged(double)),this, SLOT(slotScrollDown(double))); + connect(m_pScrollVertical.get(), SIGNAL(valueChanged(double)),this, SLOT(slotScrollVertical(double))); + + // Controls to navigate horizontally within currently selected item (left/right buttons) + m_pMoveLeft = std::make_unique(ConfigKey("[Library]", "MoveLeft")); + m_pMoveRight = std::make_unique(ConfigKey("[Library]", "MoveRight")); + m_pMoveHorizontal = std::make_unique(ConfigKey("[Library]", "MoveHorizontal"), false); + connect(m_pMoveLeft.get(), SIGNAL(valueChanged(double)),this, SLOT(slotMoveLeft(double))); + connect(m_pMoveRight.get(), SIGNAL(valueChanged(double)),this, SLOT(slotMoveRight(double))); + connect(m_pMoveHorizontal.get(), SIGNAL(valueChanged(double)),this, SLOT(slotMoveHorizontal(double))); + + // Control to navigate between widgets (tab/shit+tab button) + m_pMoveFocusForward = std::make_unique(ConfigKey("[Library]", "MoveFocusForward")); + m_pMoveFocusBackward = std::make_unique(ConfigKey("[Library]", "MoveFocusBackward")); + m_pMoveFocus = std::make_unique(ConfigKey("[Library]", "MoveFocus"), false); + connect(m_pMoveFocusForward.get(), SIGNAL(valueChanged(double)),this, SLOT(slotMoveFocusForward(double))); + connect(m_pMoveFocusBackward.get(), SIGNAL(valueChanged(double)),this, SLOT(slotMoveFocusBackward(double))); + connect(m_pMoveFocus.get(), SIGNAL(valueChanged(double)),this, SLOT(slotMoveFocus(double))); + + // Control to choose the currently selected item in focussed widget (double click) + m_pChooseItem = std::make_unique(ConfigKey("[Library]", "ChooseItem")); + connect(m_pChooseItem.get(), SIGNAL(valueChanged(double)), this, SLOT(slotChooseItem(double))); + + // Auto DJ controls + m_pAutoDjAddTop = std::make_unique(ConfigKey("[Library]","AutoDjAddTop")); + connect(m_pAutoDjAddTop.get(), SIGNAL(valueChanged(double)), + this, SLOT(slotAutoDjAddTop(double))); + + m_pAutoDjAddBottom = std::make_unique(ConfigKey("[Library]","AutoDjAddBottom")); + connect(m_pAutoDjAddBottom.get(), SIGNAL(valueChanged(double)), + this, SLOT(slotAutoDjAddBottom(double))); + + // Font sizes + m_pFontSizeKnob = std::make_unique( + ConfigKey("[Library]", "font_size_knob"), false); + connect(m_pFontSizeKnob.get(), SIGNAL(valueChanged(double)), + this, SLOT(slotFontSize(double))); + + m_pFontSizeDecrement = std::make_unique( + ConfigKey("[Library]", "font_size_decrement")); + connect(m_pFontSizeDecrement.get(), SIGNAL(valueChanged(double)), + this, SLOT(slotDecrementFontSize(double))); - m_pSelectNextTrack = new ControlPushButton(ConfigKey("[Playlist]", "SelectNextTrack")); - connect(m_pSelectNextTrack, SIGNAL(valueChanged(double)), + m_pFontSizeIncrement = std::make_unique( + ConfigKey("[Library]", "font_size_increment")); + connect(m_pFontSizeIncrement.get(), SIGNAL(valueChanged(double)), + this, SLOT(slotIncrementFontSize(double))); + + + /// Deprecated controls + m_pSelectNextTrack = std::make_unique(ConfigKey("[Playlist]", "SelectNextTrack")); + connect(m_pSelectNextTrack.get(), SIGNAL(valueChanged(double)), this, SLOT(slotSelectNextTrack(double))); - m_pSelectPrevTrack = new ControlPushButton(ConfigKey("[Playlist]", "SelectPrevTrack")); - connect(m_pSelectPrevTrack, SIGNAL(valueChanged(double)), + + m_pSelectPrevTrack = std::make_unique(ConfigKey("[Playlist]", "SelectPrevTrack")); + connect(m_pSelectPrevTrack.get(), SIGNAL(valueChanged(double)), this, SLOT(slotSelectPrevTrack(double))); // Ignoring no-ops is important since this is for +/- tickers. - m_pSelectTrack = new ControlObject(ConfigKey("[Playlist]","SelectTrackKnob"), false); - connect(m_pSelectTrack, SIGNAL(valueChanged(double)), + m_pSelectTrack = std::make_unique(ConfigKey("[Playlist]","SelectTrackKnob"), false); + connect(m_pSelectTrack.get(), SIGNAL(valueChanged(double)), this, SLOT(slotSelectTrack(double))); - m_pSelectNextSidebarItem = new ControlPushButton(ConfigKey("[Playlist]", "SelectNextPlaylist")); - connect(m_pSelectNextSidebarItem, SIGNAL(valueChanged(double)), + + m_pSelectNextSidebarItem = std::make_unique(ConfigKey("[Playlist]", "SelectNextPlaylist")); + connect(m_pSelectNextSidebarItem.get(), SIGNAL(valueChanged(double)), this, SLOT(slotSelectNextSidebarItem(double))); - m_pSelectPrevSidebarItem = new ControlPushButton(ConfigKey("[Playlist]", "SelectPrevPlaylist")); - connect(m_pSelectPrevSidebarItem, SIGNAL(valueChanged(double)), + m_pSelectPrevSidebarItem = std::make_unique(ConfigKey("[Playlist]", "SelectPrevPlaylist")); + connect(m_pSelectPrevSidebarItem.get(), SIGNAL(valueChanged(double)), this, SLOT(slotSelectPrevSidebarItem(double))); // Ignoring no-ops is important since this is for +/- tickers. - m_pSelectSidebarItem = new ControlObject(ConfigKey("[Playlist]", "SelectPlaylist"), false); - connect(m_pSelectSidebarItem, SIGNAL(valueChanged(double)), + m_pSelectSidebarItem = std::make_unique(ConfigKey("[Playlist]", "SelectPlaylist"), false); + connect(m_pSelectSidebarItem.get(), SIGNAL(valueChanged(double)), this, SLOT(slotSelectSidebarItem(double))); - m_pToggleSidebarItem = new ControlPushButton(ConfigKey("[Playlist]", "ToggleSelectedSidebarItem")); - connect(m_pToggleSidebarItem, SIGNAL(valueChanged(double)), + m_pToggleSidebarItem = std::make_unique(ConfigKey("[Playlist]", "ToggleSelectedSidebarItem")); + connect(m_pToggleSidebarItem.get(), SIGNAL(valueChanged(double)), this, SLOT(slotToggleSelectedSidebarItem(double))); - m_pLoadSelectedIntoFirstStopped = new ControlPushButton(ConfigKey("[Playlist]","LoadSelectedIntoFirstStopped")); - connect(m_pLoadSelectedIntoFirstStopped, SIGNAL(valueChanged(double)), + m_pLoadSelectedIntoFirstStopped = std::make_unique(ConfigKey("[Playlist]","LoadSelectedIntoFirstStopped")); + connect(m_pLoadSelectedIntoFirstStopped.get(), SIGNAL(valueChanged(double)), this, SLOT(slotLoadSelectedIntoFirstStopped(double))); - m_pAutoDjAddTop = new ControlPushButton(ConfigKey("[Playlist]","AutoDjAddTop")); - connect(m_pAutoDjAddTop, SIGNAL(valueChanged(double)), - this, SLOT(slotAutoDjAddTop(double))); - - m_pAutoDjAddBottom = new ControlPushButton(ConfigKey("[Playlist]","AutoDjAddBottom")); - connect(m_pAutoDjAddBottom, SIGNAL(valueChanged(double)), - this, SLOT(slotAutoDjAddBottom(double))); - - // Ignoring no-ops is important since this is for +/- tickers. - m_pFontSizeKnob = new ControlObject( - ConfigKey("[Library]", "font_size_knob"), false); - connect(m_pFontSizeKnob, SIGNAL(valueChanged(double)), - this, SLOT(slotFontSize(double))); - - m_pFontSizeDecrement = new ControlPushButton( - ConfigKey("[Library]", "font_size_decrement")); - connect(m_pFontSizeDecrement, SIGNAL(valueChanged(double)), - this, SLOT(slotDecrementFontSize(double))); - - m_pFontSizeIncrement = new ControlPushButton( - ConfigKey("[Library]", "font_size_increment")); - connect(m_pFontSizeIncrement, SIGNAL(valueChanged(double)), - this, SLOT(slotIncrementFontSize(double))); + ControlDoublePrivate::insertAlias(ConfigKey("[Playlist]", "AutoDjAddTop"), ConfigKey("[Library]", "AutoDjAddTop")); + ControlDoublePrivate::insertAlias(ConfigKey("[Playlist]", "AutoDjAddBottom"), ConfigKey("[Library]", "AutoDjAddBottom")); } -LibraryControl::~LibraryControl() { - delete m_pSelectNextTrack; - delete m_pSelectPrevTrack; - delete m_pSelectTrack; - delete m_pSelectNextSidebarItem; - delete m_pSelectPrevSidebarItem; - delete m_pSelectSidebarItem; - delete m_pToggleSidebarItem; - delete m_pLoadSelectedIntoFirstStopped; - delete m_pAutoDjAddTop; - delete m_pAutoDjAddBottom; - delete m_pFontSizeKnob; - delete m_pFontSizeDecrement; - delete m_pFontSizeIncrement; - deleteMapValues(&m_loadToGroupControllers); -} +LibraryControl::~LibraryControl() = default; void LibraryControl::maybeCreateGroupController(const QString& group) { - LoadToGroupController* pGroup = m_loadToGroupControllers.value(group, NULL); - if (pGroup == NULL) { - pGroup = new LoadToGroupController(this, group); - m_loadToGroupControllers[group] = pGroup; + if (m_loadToGroupControllers.find(group) == m_loadToGroupControllers.end()) { + m_loadToGroupControllers.emplace(group, std::make_unique(this, group)); } } @@ -173,6 +195,7 @@ void LibraryControl::slotNumSamplersChanged(double v) { } } + void LibraryControl::slotNumPreviewDecksChanged(double v) { int iNumPreviewDecks = v; @@ -186,7 +209,7 @@ void LibraryControl::slotNumPreviewDecksChanged(double v) { } void LibraryControl::bindSidebarWidget(WLibrarySidebar* pSidebarWidget) { - if (m_pSidebarWidget != NULL) { + if (m_pSidebarWidget) { disconnect(m_pSidebarWidget, 0, this, 0); } m_pSidebarWidget = pSidebarWidget; @@ -196,7 +219,7 @@ void LibraryControl::bindSidebarWidget(WLibrarySidebar* pSidebarWidget) { void LibraryControl::bindWidget(WLibrary* pLibraryWidget, KeyboardEventFilter* pKeyboard) { Q_UNUSED(pKeyboard); - if (m_pLibraryWidget != NULL) { + if (m_pLibraryWidget) { disconnect(m_pLibraryWidget, 0, this, 0); } m_pLibraryWidget = pLibraryWidget; @@ -205,15 +228,15 @@ void LibraryControl::bindWidget(WLibrary* pLibraryWidget, KeyboardEventFilter* p } void LibraryControl::libraryWidgetDeleted() { - m_pLibraryWidget = NULL; + m_pLibraryWidget = nullptr; } void LibraryControl::sidebarWidgetDeleted() { - m_pSidebarWidget = NULL; + m_pSidebarWidget = nullptr; } void LibraryControl::slotLoadSelectedTrackToGroup(QString group, bool play) { - if (m_pLibraryWidget == NULL) { + if (!m_pLibraryWidget) { return; } @@ -225,7 +248,7 @@ void LibraryControl::slotLoadSelectedTrackToGroup(QString group, bool play) { } void LibraryControl::slotLoadSelectedIntoFirstStopped(double v) { - if (m_pLibraryWidget == NULL) { + if (!m_pLibraryWidget) { return; } @@ -239,12 +262,12 @@ void LibraryControl::slotLoadSelectedIntoFirstStopped(double v) { } void LibraryControl::slotAutoDjAddTop(double v) { - if (m_pLibraryWidget == NULL) { + if (!m_pLibraryWidget) { return; } if (v > 0) { - LibraryView* activeView = m_pLibraryWidget->getActiveView(); + auto activeView = m_pLibraryWidget->getActiveView(); if (!activeView) { return; } @@ -253,12 +276,12 @@ void LibraryControl::slotAutoDjAddTop(double v) { } void LibraryControl::slotAutoDjAddBottom(double v) { - if (m_pLibraryWidget == NULL) { + if (!m_pLibraryWidget) { return; } if (v > 0) { - LibraryView* activeView = m_pLibraryWidget->getActiveView(); + auto activeView = m_pLibraryWidget->getActiveView(); if (!activeView) { return; } @@ -279,37 +302,123 @@ void LibraryControl::slotSelectPrevTrack(double v) { } void LibraryControl::slotSelectTrack(double v) { - if (m_pLibraryWidget == NULL) { + if (!m_pLibraryWidget) { return; } int i = (int)v; - LibraryView* activeView = m_pLibraryWidget->getActiveView(); + auto activeView = m_pLibraryWidget->getActiveView(); if (!activeView) { return; } activeView->moveSelection(i); } -void LibraryControl::slotSelectSidebarItem(double v) { - if (m_pSidebarWidget == NULL) { - return; + + +void LibraryControl::slotMoveUp(double v) { + if (v > 0) { + emitKeyEvent(QKeyEvent{QEvent::KeyPress, Qt::Key_Up, Qt::NoModifier}); } +} + +void LibraryControl::slotMoveDown(double v) { if (v > 0) { - QApplication::postEvent(m_pSidebarWidget, new QKeyEvent( - QEvent::KeyPress, - (int)Qt::Key_Down, Qt::NoModifier, QString(), true)); - QApplication::postEvent(m_pSidebarWidget, new QKeyEvent( - QEvent::KeyRelease, - (int)Qt::Key_Down, Qt::NoModifier, QString(), true)); - } else if (v < 0) { - QApplication::postEvent(m_pSidebarWidget, new QKeyEvent( - QEvent::KeyPress, - (int)Qt::Key_Up, Qt::NoModifier, QString(), true)); - QApplication::postEvent(m_pSidebarWidget, new QKeyEvent( - QEvent::KeyRelease, - (int)Qt::Key_Up, Qt::NoModifier, QString(), true)); + emitKeyEvent(QKeyEvent{QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier}); + } +} + +void LibraryControl::slotMoveVertical(double v) { + const auto key = (v < 0) ? Qt::Key_Up: Qt::Key_Down; + const auto times = static_cast(std::abs(v)); + emitKeyEvent(QKeyEvent{QEvent::KeyPress, key, Qt::NoModifier, QString(), false, times}); +} + +void LibraryControl::slotScrollUp(double v) { + if (v > 0) { + emitKeyEvent(QKeyEvent{QEvent::KeyPress, Qt::Key_PageUp, Qt::NoModifier}); + } +} + +void LibraryControl::slotScrollDown(double v) { + if (v > 0) { + emitKeyEvent(QKeyEvent{QEvent::KeyPress, Qt::Key_PageDown, Qt::NoModifier}); + } +} + +void LibraryControl::slotScrollVertical(double v) { + const auto key = (v < 0) ? Qt::Key_PageUp: Qt::Key_PageDown; + const auto times = static_cast(std::abs(v)); + emitKeyEvent(QKeyEvent{QEvent::KeyPress, key, Qt::NoModifier, QString(), false, times}); +} + +void LibraryControl::slotMoveLeft(double v) { + if (v > 0) { + emitKeyEvent(QKeyEvent{QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier}); + } +} + +void LibraryControl::slotMoveRight(double v) { + if (v > 0) { + emitKeyEvent(QKeyEvent{QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier}); + } +} + +void LibraryControl::slotMoveHorizontal(double v) { + const auto key = (v < 0) ? Qt::Key_Left: Qt::Key_Right; + const auto times = static_cast(std::abs(v)); + emitKeyEvent(QKeyEvent{QEvent::KeyPress, key, Qt::NoModifier, QString(), false, times}); +} + +void LibraryControl::slotMoveFocusForward(double v) { + if (v > 0) { + emitKeyEvent(QKeyEvent{QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier}); + } +} + +void LibraryControl::slotMoveFocusBackward(double v) { + if (v > 0) { + emitKeyEvent(QKeyEvent{QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier}); + } +} + +void LibraryControl::slotMoveFocus(double v) { + const auto shift = (v < 0) ? Qt::ShiftModifier: Qt::NoModifier; + const auto times = static_cast(std::abs(v)); + emitKeyEvent(QKeyEvent{QEvent::KeyPress, Qt::Key_Tab, shift, QString(), false, times}); +} + +void LibraryControl::emitKeyEvent(QKeyEvent&& event) { + // Ensure a valid widget has the keyboard focus + auto focusWidget = QApplication::focusWidget(); + if (!focusWidget) { + setLibraryFocus(); + focusWidget = QApplication::focusWidget(); + if (!focusWidget) { + return; + } + } + // Send the event pointer to the currently focused widget + for (auto i = 0; i < event.count(); ++i) { + QApplication::sendEvent(focusWidget, &event); + } +} + +void LibraryControl::setLibraryFocus() { + if (m_pSidebarWidget) { + // XXX: Set the focus of the library panel directly instead of sending tab from sidebar + m_pSidebarWidget->setFocus(); + QKeyEvent event(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier); + QApplication::sendEvent(m_pSidebarWidget, &event); + } +} + +void LibraryControl::slotSelectSidebarItem(double v) { + if (v != 0) { + const auto key = (v < 0) ? Qt::Key_Up : Qt::Key_Down; + emitKeyEvent(QKeyEvent{QEvent::KeyPress, key, Qt::NoModifier}); + emitKeyEvent(QKeyEvent{QEvent::KeyRelease, key, Qt::NoModifier}); } } @@ -326,11 +435,25 @@ void LibraryControl::slotSelectPrevSidebarItem(double v) { } void LibraryControl::slotToggleSelectedSidebarItem(double v) { - if (m_pSidebarWidget != NULL && v > 0) { + if (m_pSidebarWidget && v > 0) { m_pSidebarWidget->toggleSelectedItem(); } } +void LibraryControl::slotChooseItem(double v) { + // XXX: Make this more generic? If Enter key is mapped correctly maybe we can use that + if (!m_pLibraryWidget) { + return; + } + // Load current track if a LibraryView object has focus + const auto activeView = m_pLibraryWidget->getActiveView(); + if (activeView && activeView->hasFocus()) { + return slotLoadSelectedIntoFirstStopped(v); + } + // Otherwise toggle the sidebar item expanded state (like a double-click) + slotToggleSelectedSidebarItem(v); +} + void LibraryControl::slotFontSize(double v) { if (v == 0.0) { return; diff --git a/src/library/librarycontrol.h b/src/library/librarycontrol.h index 7b449d9c5a01..69e256ce12d2 100644 --- a/src/library/librarycontrol.h +++ b/src/library/librarycontrol.h @@ -4,6 +4,7 @@ #include #include "control/controlproxy.h" +#include "util/memory.h" class ControlObject; class ControlPushButton; @@ -27,8 +28,8 @@ class LoadToGroupController : public QObject { private: QString m_group; - ControlObject* m_pLoadControl; - ControlObject* m_pLoadAndPlayControl; + std::unique_ptr m_pLoadControl; + std::unique_ptr m_pLoadAndPlayControl; }; class LibraryControl : public QObject { @@ -43,6 +44,22 @@ class LibraryControl : public QObject { private slots: void libraryWidgetDeleted(); void sidebarWidgetDeleted(); + + void slotMoveUp(double); + void slotMoveDown(double); + void slotMoveVertical(double); + void slotScrollUp(double); + void slotScrollDown(double); + void slotScrollVertical(double); + void slotMoveLeft(double); + void slotMoveRight(double); + void slotMoveHorizontal(double); + void slotMoveFocusForward(double); + void slotMoveFocusBackward(double); + void slotMoveFocus(double); + void slotChooseItem(double v); + + // Deprecated navigation slots void slotLoadSelectedTrackToGroup(QString group, bool play); void slotSelectNextTrack(double v); void slotSelectPrevTrack(double v); @@ -67,29 +84,62 @@ class LibraryControl : public QObject { private: Library* m_pLibrary; - ControlObject* m_pSelectNextTrack; - ControlObject* m_pSelectPrevTrack; - ControlObject* m_pSelectTrack; - - ControlObject* m_pSelectSidebarItem; - ControlObject* m_pSelectPrevSidebarItem; - ControlObject* m_pSelectNextSidebarItem; - - ControlObject* m_pToggleSidebarItem; - ControlObject* m_pLoadSelectedIntoFirstStopped; - ControlObject* m_pAutoDjAddTop; - ControlObject* m_pAutoDjAddBottom; - - ControlObject* m_pFontSizeKnob; - ControlPushButton* m_pFontSizeIncrement; - ControlPushButton* m_pFontSizeDecrement; - + // Simulate pressing a key on the keyboard + void emitKeyEvent(QKeyEvent&& event); + // Give the keyboard focus to the main library pane + void setLibraryFocus(); + + // Controls to navigate vertically within currently focused widget (up/down buttons) + std::unique_ptr m_pMoveUp; + std::unique_ptr m_pMoveDown; + std::unique_ptr m_pMoveVertical; + + // Controls to QUICKLY navigate vertically within currently focused widget (pageup/pagedown buttons) + std::unique_ptr m_pScrollUp; + std::unique_ptr m_pScrollDown; + std::unique_ptr m_pScrollVertical; + + // Controls to navigate horizontally within currently selected item (left/right buttons) + std::unique_ptr m_pMoveLeft; + std::unique_ptr m_pMoveRight; + std::unique_ptr m_pMoveHorizontal; + + // Controls to navigate between widgets (tab/shit+tab button) + std::unique_ptr m_pMoveFocusForward; + std::unique_ptr m_pMoveFocusBackward; + std::unique_ptr m_pMoveFocus; + + // Control to choose the currently selected item in focused widget (double click) + std::unique_ptr m_pChooseItem; + + // Add to Auto-Dj Cueue + std::unique_ptr m_pAutoDjAddTop; + std::unique_ptr m_pAutoDjAddBottom; + + // Font sizes + std::unique_ptr m_pFontSizeIncrement; + std::unique_ptr m_pFontSizeDecrement; + std::unique_ptr m_pFontSizeKnob; + + // Direct navigation controls for specific widgets (deprecated) + std::unique_ptr m_pSelectNextTrack; + std::unique_ptr m_pSelectPrevTrack; + std::unique_ptr m_pSelectTrack; + std::unique_ptr m_pSelectSidebarItem; + std::unique_ptr m_pSelectPrevSidebarItem; + std::unique_ptr m_pSelectNextSidebarItem; + std::unique_ptr m_pToggleSidebarItem; + std::unique_ptr m_pLoadSelectedIntoFirstStopped; + + // Library widgets WLibrary* m_pLibraryWidget; WLibrarySidebar* m_pSidebarWidget; + + // Other variables ControlProxy m_numDecks; ControlProxy m_numSamplers; ControlProxy m_numPreviewDecks; - QMap m_loadToGroupControllers; + std::map> m_loadToGroupControllers; }; #endif //LIBRARYMIDICONTROL_H diff --git a/src/library/libraryview.h b/src/library/libraryview.h index 5ae34aee2fe6..1e5a5c03a289 100644 --- a/src/library/libraryview.h +++ b/src/library/libraryview.h @@ -14,6 +14,7 @@ class LibraryView { virtual ~LibraryView() {}; virtual void onShow() = 0; + virtual bool hasFocus() const = 0; // reimplement if LibraryView should be able to search virtual void onSearch(const QString& text) {Q_UNUSED(text);} diff --git a/src/library/recording/dlgrecording.cpp b/src/library/recording/dlgrecording.cpp index 043a9fffd152..0a6ea5c14af2 100644 --- a/src/library/recording/dlgrecording.cpp +++ b/src/library/recording/dlgrecording.cpp @@ -69,6 +69,10 @@ void DlgRecording::onShow() { m_browseModel.setPath(m_recordingDir); } +bool DlgRecording::hasFocus() const { + return QWidget::hasFocus(); +} + void DlgRecording::refreshBrowseModel() { m_browseModel.setPath(m_recordingDir); } diff --git a/src/library/recording/dlgrecording.h b/src/library/recording/dlgrecording.h index 53b515bf3223..caf8fd054722 100644 --- a/src/library/recording/dlgrecording.h +++ b/src/library/recording/dlgrecording.h @@ -22,15 +22,16 @@ class DlgRecording : public QWidget, public Ui::DlgRecording, public virtual Lib DlgRecording(QWidget *parent, UserSettingsPointer pConfig, Library* pLibrary, TrackCollection* pTrackCollection, RecordingManager* pRecManager, KeyboardEventFilter* pKeyboard); - virtual ~DlgRecording(); + ~DlgRecording() override; - virtual void onSearch(const QString& text); - virtual void onShow(); - virtual void loadSelectedTrack(); - virtual void slotSendToAutoDJ(); - virtual void slotSendToAutoDJTop(); - virtual void loadSelectedTrackToGroup(QString group, bool play); - virtual void moveSelection(int delta); + void onSearch(const QString& text) override; + void onShow() override; + bool hasFocus() const override; + void loadSelectedTrack() override; + void slotSendToAutoDJ() override; + void slotSendToAutoDJTop() override; + void loadSelectedTrackToGroup(QString group, bool play) override; + void moveSelection(int delta) override; inline const QString currentSearch() { return m_proxyModel.currentSearch(); } public slots: diff --git a/src/widget/wlibrarytextbrowser.cpp b/src/widget/wlibrarytextbrowser.cpp index a6dd78632604..52b295103891 100644 --- a/src/widget/wlibrarytextbrowser.cpp +++ b/src/widget/wlibrarytextbrowser.cpp @@ -6,3 +6,7 @@ WLibraryTextBrowser::WLibraryTextBrowser(QWidget* parent) : QTextBrowser(parent) { } + +bool WLibraryTextBrowser::hasFocus() const { + return QWidget::hasFocus(); +} diff --git a/src/widget/wlibrarytextbrowser.h b/src/widget/wlibrarytextbrowser.h index 2fedfd0fba96..e61c38efa09e 100644 --- a/src/widget/wlibrarytextbrowser.h +++ b/src/widget/wlibrarytextbrowser.h @@ -12,8 +12,8 @@ class WLibraryTextBrowser : public QTextBrowser, public LibraryView { Q_OBJECT public: explicit WLibraryTextBrowser(QWidget* parent = nullptr); - void onShow() override {} + bool hasFocus() const override; }; #endif /* WLIBRARYTEXTBROWSER_H */ diff --git a/src/widget/wtracktableview.cpp b/src/widget/wtracktableview.cpp index 8f74136f77e0..da32692e727b 100644 --- a/src/widget/wtracktableview.cpp +++ b/src/widget/wtracktableview.cpp @@ -1680,3 +1680,7 @@ void WTrackTableView::slotReloadCoverArt() { pCache->requestGuessCovers(selectedTracks); } } + +bool WTrackTableView::hasFocus() const { + return QWidget::hasFocus(); +} diff --git a/src/widget/wtracktableview.h b/src/widget/wtracktableview.h index 6e1172960ac4..0363e026e2ff 100644 --- a/src/widget/wtracktableview.h +++ b/src/widget/wtracktableview.h @@ -32,6 +32,7 @@ class WTrackTableView : public WLibraryTableView { void contextMenuEvent(QContextMenuEvent * event) override; void onSearch(const QString& text) override; void onShow() override; + bool hasFocus() const override; void keyPressEvent(QKeyEvent* event) override; void loadSelectedTrack() override; void loadSelectedTrackToGroup(QString group, bool play) override;