Skip to content

Commit 6546404

Browse files
author
Milkii Brewster
committed
add quick access to controller learning wizard via options menu
implements feature request from issue #12262 to provide quicker access to the midi controller learning wizard. ## changes ### options menu submenu - added "controller learning wizard" submenu under options menu - dynamically populated with enabled controllers only - shows "no controllers enabled" when no controllers are enabled - updates automatically when controllers are enabled/disabled ### navigation - clicking a controller menu item opens preferences dialog - automatically navigates to that specific controller's page - expands the controllers tree and selects the correct item - user can then click the "learning wizard" button on that page ### implementation - wmainmenubar: added menu creation and signal emission - mixxxmainwindow: connected signals, filters to show only enabled controllers - dlgprefcontrollers: added method to navigate to specific controller - dlgpreferences: added method to delegate to controllers dialog follows the same architectural pattern as the existing vinyl control menu implementation for consistency. fixes #12262
1 parent 086f48e commit 6546404

File tree

9 files changed

+153
-2
lines changed

9 files changed

+153
-2
lines changed

src/controllers/dlgprefcontroller.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ class DlgPrefController : public DlgPreferencePage {
3838
QUrl helpUrl() const override;
3939
void keyPressEvent(QKeyEvent* pEvent) override;
4040

41+
Controller* controller() const {
42+
return m_pController;
43+
}
44+
45+
// Open the MIDI learning wizard for this controller
46+
void showLearningWizard();
47+
4148
public slots:
4249
/// Called when the preference dialog (not this page) is shown to the user.
4350
void slotUpdate() override;
@@ -78,7 +85,6 @@ class DlgPrefController : public DlgPreferencePage {
7885

7986
// Input mappings
8087
void addInputMapping();
81-
void showLearningWizard();
8288
void removeInputMappings();
8389
void clearAllInputMappings();
8490

src/controllers/dlgprefcontrollers.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,3 +286,40 @@ void DlgPrefControllers::slotMidiThroughChanged(bool checked) {
286286
}
287287
#endif
288288
#endif
289+
290+
void DlgPrefControllers::openLearningWizard(Controller* pController) {
291+
if (!pController) {
292+
return;
293+
}
294+
295+
// Find the DlgPrefController for this controller by matching the controller pointer
296+
for (int i = 0; i < m_controllerPages.size(); ++i) {
297+
DlgPrefController* pControllerDlg = m_controllerPages.at(i);
298+
if (pControllerDlg && pControllerDlg->controller() == pController) {
299+
// Temporarily disconnect the mappingEnded signal to prevent
300+
// showing the preferences dialog when the wizard closes
301+
disconnect(pControllerDlg,
302+
&DlgPrefController::mappingEnded,
303+
m_pDlgPreferences,
304+
&DlgPreferences::show);
305+
306+
// Reconnect after wizard closes to restore normal behavior
307+
connect(
308+
pControllerDlg,
309+
&DlgPrefController::mappingEnded,
310+
this,
311+
[this, pControllerDlg]() {
312+
// Restore the connection for future uses from preferences
313+
connect(pControllerDlg,
314+
&DlgPrefController::mappingEnded,
315+
m_pDlgPreferences,
316+
&DlgPreferences::show);
317+
},
318+
Qt::SingleShotConnection);
319+
320+
// Open the learning wizard directly
321+
pControllerDlg->showLearningWizard();
322+
return;
323+
}
324+
}
325+
}

src/controllers/dlgprefcontrollers.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "preferences/usersettings.h"
88
#include "util/parented_ptr.h"
99

10+
class Controller;
1011
class ControlProxy;
1112
class DlgPreferences;
1213
class DlgPrefController;
@@ -28,6 +29,7 @@ class DlgPrefControllers : public DlgPreferencePage, public Ui::DlgPrefControlle
2829

2930
bool handleTreeItemClick(QTreeWidgetItem* clickedItem);
3031
QUrl helpUrl() const override;
32+
void openLearningWizard(Controller* pController);
3133

3234
public slots:
3335
/// Called when the preference dialog (not this page) is shown to the user.

src/mixxxmainwindow.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#include "widget/winitialglwidget.h"
2222
#endif
2323

24+
#include "controllers/controller.h"
25+
#include "controllers/controllermanager.h"
2426
#include "controllers/keyboard/keyboardeventfilter.h"
2527
#include "coreservices.h"
2628
#include "defs_urls.h"
@@ -947,6 +949,22 @@ void MixxxMainWindow::connectMenuBar() {
947949
m_pMenuBar->onNumberOfDecksChanged(pPlayerManager->numberOfDecks());
948950
}
949951

952+
// Controller learning wizard menu
953+
if (m_pCoreServices->getControllerManager()) {
954+
connect(m_pCoreServices->getControllerManager().get(),
955+
&ControllerManager::devicesChanged,
956+
this,
957+
&MixxxMainWindow::slotUpdateControllerLearningMenu,
958+
Qt::UniqueConnection);
959+
connect(m_pMenuBar,
960+
&WMainMenuBar::openControllerLearningWizard,
961+
this,
962+
&MixxxMainWindow::slotOpenControllerLearningWizard,
963+
Qt::UniqueConnection);
964+
// Initialize the menu with current controllers
965+
slotUpdateControllerLearningMenu();
966+
}
967+
950968
if (m_pCoreServices->getTrackCollectionManager()) {
951969
connect(m_pMenuBar,
952970
&WMainMenuBar::rescanLibrary,
@@ -1147,6 +1165,32 @@ void MixxxMainWindow::slotNoVinylControlInputConfigured() {
11471165
}
11481166
}
11491167

1168+
void MixxxMainWindow::slotUpdateControllerLearningMenu() {
1169+
if (!m_pCoreServices->getControllerManager()) {
1170+
return;
1171+
}
1172+
// Only show enabled/opened input controllers
1173+
// Use getControllerList(false, true) to get input devices only
1174+
QList<Controller*> allControllers =
1175+
m_pCoreServices->getControllerManager()->getControllerList(
1176+
false, true);
1177+
QList<Controller*> enabledControllers;
1178+
for (Controller* pController : std::as_const(allControllers)) {
1179+
if (pController && pController->isOpen()) {
1180+
enabledControllers.append(pController);
1181+
}
1182+
}
1183+
m_pMenuBar->onControllersChanged(enabledControllers);
1184+
}
1185+
1186+
void MixxxMainWindow::slotOpenControllerLearningWizard(Controller* pController) {
1187+
if (!pController) {
1188+
return;
1189+
}
1190+
// Open the learning wizard directly for this controller
1191+
m_pPrefDlg->openControllerLearningWizard(pController);
1192+
}
1193+
11501194
void MixxxMainWindow::slotNoDeckPassthroughInputConfigured() {
11511195
if (m_noPassthroughInputDialog && m_noPassthroughInputDialog->isVisible()) {
11521196
// Don't show redundant dialogs.

src/mixxxmainwindow.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "util/parented_ptr.h"
1111

1212
class ControlObject;
13+
class Controller;
1314
class DlgDeveloperTools;
1415
class DlgPreferences;
1516
class DlgKeywheel;
@@ -81,6 +82,9 @@ class MixxxMainWindow : public QMainWindow {
8182
void slotNoAuxiliaryInputConfigured();
8283
void slotNoDeckPassthroughInputConfigured();
8384
void slotNoVinylControlInputConfigured();
85+
/// Controller learning wizard menu management
86+
void slotUpdateControllerLearningMenu();
87+
void slotOpenControllerLearningWizard(Controller* pController);
8488
#ifndef __APPLE__
8589
/// Update whether the menubar is toggled pressing the Alt key and show/hide
8690
/// it accordingly

src/preferences/dialog/dlgpreferences.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <QScrollArea>
99
#include <QtGlobal>
1010

11+
#include "controllers/controller.h"
1112
#include "controllers/dlgprefcontrollers.h"
1213
#include "library/library.h"
1314
#include "library/trackcollectionmanager.h"
@@ -306,11 +307,17 @@ void DlgPreferences::showSoundHardwarePage(
306307
std::optional<mixxx::preferences::SoundHardwareTab> tab) {
307308
switchToPage(m_soundPage.pTreeItem->text(0), m_soundPage.pDlg);
308309
contentsTreeWidget->setCurrentItem(m_soundPage.pTreeItem);
309-
if (tab.has_value()) {
310+
if (tab) {
310311
m_pSoundDlg->selectIOTab(*tab);
311312
}
312313
}
313314

315+
void DlgPreferences::openControllerLearningWizard(Controller* pController) {
316+
if (m_pControllersDlg) {
317+
m_pControllersDlg->openLearningWizard(pController);
318+
}
319+
}
320+
314321
bool DlgPreferences::eventFilter(QObject* o, QEvent* e) {
315322
// Send a close signal if dialog is closing
316323
if (e->type() == QEvent::Hide) {

src/preferences/dialog/dlgpreferences.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "preferences/settingsmanager.h"
1515
#include "preferences/usersettings.h"
1616

17+
class Controller;
1718
class ControllerManager;
1819
class DlgPrefControllers;
1920
class DlgPrefSound;
@@ -67,6 +68,7 @@ class DlgPreferences : public QDialog, public Ui::DlgPreferencesDlg {
6768
void showSoundHardwarePage(
6869
std::optional<mixxx::preferences::SoundHardwareTab> tab =
6970
std::nullopt);
71+
void openControllerLearningWizard(Controller* pController);
7072
void slotButtonPressed(QAbstractButton* pButton);
7173
signals:
7274
void closeDlg();

src/widget/wmainmenubar.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "config.h"
1010
#include "control/controlproxy.h"
11+
#include "controllers/controller.h"
1112
#include "defs_urls.h"
1213
#include "moc_wmainmenubar.cpp"
1314
#include "util/cmdlineargs.h"
@@ -470,6 +471,17 @@ void WMainMenuBar::initialize() {
470471
pOptionsMenu->addSeparator();
471472
#endif
472473

474+
// Controller Learning submenu
475+
m_pControllerLearningMenu = new QMenu(tr("&Controller Learning Wizard"), this);
476+
QString controllerLearningText = tr(
477+
"Open the MIDI learning wizard for an enabled controller");
478+
m_pControllerLearningMenu->setStatusTip(controllerLearningText);
479+
m_pControllerLearningMenu->setWhatsThis(buildWhatsThis(
480+
tr("Controller Learning Wizard"), controllerLearningText));
481+
// Menu will be populated dynamically with enabled controllers
482+
pOptionsMenu->addMenu(m_pControllerLearningMenu);
483+
pOptionsMenu->addSeparator();
484+
473485
QString recordTitle = tr("&Record Mix");
474486
QString recordText = tr("Record your mix to a file");
475487
auto* pOptionsRecord = new QAction(recordTitle, this);
@@ -998,3 +1010,35 @@ void VisibilityControlConnection::slotActionToggled(bool toggle) {
9981010
m_pControl->set(toggle ? 1.0 : 0.0);
9991011
}
10001012
}
1013+
1014+
void WMainMenuBar::onControllersChanged(const QList<Controller*>& controllers) {
1015+
// Clear existing actions
1016+
for (QAction* pAction : std::as_const(m_controllerLearningActions)) {
1017+
m_pControllerLearningMenu->removeAction(pAction);
1018+
delete pAction;
1019+
}
1020+
m_controllerLearningActions.clear();
1021+
1022+
// Add menu item for each controller
1023+
for (Controller* pController : controllers) {
1024+
if (!pController) {
1025+
continue;
1026+
}
1027+
QString controllerName = pController->getName();
1028+
auto* pAction = new QAction(controllerName, this);
1029+
pAction->setStatusTip(tr("Open learning wizard for %1").arg(controllerName));
1030+
connect(pAction, &QAction::triggered, this, [this, pController]() {
1031+
emit openControllerLearningWizard(pController);
1032+
});
1033+
m_pControllerLearningMenu->addAction(pAction);
1034+
m_controllerLearningActions.append(pAction);
1035+
}
1036+
1037+
// Show "No controllers enabled" if list is empty
1038+
if (m_controllerLearningActions.isEmpty()) {
1039+
auto* pNoControllersAction = new QAction(tr("No controllers enabled"), this);
1040+
pNoControllersAction->setEnabled(false);
1041+
m_pControllerLearningMenu->addAction(pNoControllersAction);
1042+
m_controllerLearningActions.append(pNoControllersAction);
1043+
}
1044+
}

src/widget/wmainmenubar.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "preferences/usersettings.h"
1111

1212
class QAction;
13+
class Controller;
1314

1415
class VisibilityControlConnection : public QObject {
1516
Q_OBJECT
@@ -54,6 +55,7 @@ class WMainMenuBar : public QMenuBar {
5455
void onVinylControlDeckEnabledStateChange(int deck, bool enabled);
5556
void onNumberOfDecksChanged(int decks);
5657
void onKeywheelChange(int state);
58+
void onControllersChanged(const QList<Controller*>& controllers);
5759
#ifndef __APPLE__
5860
void slotToggleMenuBar();
5961
#endif
@@ -80,6 +82,7 @@ class WMainMenuBar : public QMenuBar {
8082
void toggleBroadcasting(bool toggle);
8183
void toggleRecording(bool enabled);
8284
void toggleVinylControl(int deck);
85+
void openControllerLearningWizard(Controller* pController);
8386
void visitUrl(const QString& url);
8487
void quit();
8588

@@ -115,4 +118,6 @@ class WMainMenuBar : public QMenuBar {
115118
ConfigObject<ConfigValueKbd>* m_pKbdConfig;
116119
QList<QAction*> m_loadToDeckActions;
117120
QList<QAction*> m_vinylControlEnabledActions;
121+
QMenu* m_pControllerLearningMenu;
122+
QList<QAction*> m_controllerLearningActions;
118123
};

0 commit comments

Comments
 (0)