From cd780b22474d91ac987eed1dc09b8a9efa71a5a3 Mon Sep 17 00:00:00 2001 From: Paul Johnson Date: Fri, 22 Aug 2025 21:47:59 +0100 Subject: [PATCH] NewSideBar Button ids as an enum class and View Stack Ids (#4688) Updates the NewSideBar button ids to use an enum class, and viewStack identifiers to provide strong typing, and aid the clarity of the code. --- src/Gui/AthleteTab.cpp | 2 +- src/Gui/MainWindow.cpp | 101 ++++++++++++++++++------------------ src/Gui/MainWindow.h | 5 +- src/Gui/NavigationModel.cpp | 15 ++---- src/Gui/NewSideBar.cpp | 53 ++++++++++++------- src/Gui/NewSideBar.h | 66 +++++++++++++++++------ 6 files changed, 146 insertions(+), 96 deletions(-) diff --git a/src/Gui/AthleteTab.cpp b/src/Gui/AthleteTab.cpp index dd7187616..17a67dc0c 100644 --- a/src/Gui/AthleteTab.cpp +++ b/src/Gui/AthleteTab.cpp @@ -211,7 +211,7 @@ AthleteTab::rideSelected(RideItem*) // as important to be aware that perspectives are loaded // when the view is selected by the user and no earlier if (analysisView->page() != NULL) { - context->mainWindow->newSidebar()->setItemSelected(3, true); + context->mainWindow->newSidebar()->setItemSelected(GcSideBarBtnId::ACTIVITIES_BTN, true); selectView(1); } } diff --git a/src/Gui/MainWindow.cpp b/src/Gui/MainWindow.cpp index b5d8e7a13..1f0037025 100644 --- a/src/Gui/MainWindow.cpp +++ b/src/Gui/MainWindow.cpp @@ -81,7 +81,6 @@ // GUI Widgets #include "AthleteTab.h" #include "GcToolBar.h" -#include "NewSideBar.h" #include "HelpWindow.h" #include "Perspective.h" #include "PerspectiveDialog.h" @@ -115,6 +114,12 @@ #include "WindowsCrashHandler.cpp" #endif +// The order of the GcViewStackIdx values below must match the viewStack widget's tab order, see the MainWindow's constructor below. +namespace GcViewStackIdx { +// use constexpr instead of enum class to prevent unecessary casting +constexpr int SELECT_ATHLETE_VIEW = 0; +constexpr int ATHLETE_TAB_STACK = 1; +}; // We keep track of all theopen mainwindows QList mainwindows; @@ -207,34 +212,34 @@ MainWindow::MainWindow(const QDir &home) HelpWhatsThis *helpNewSideBar = new HelpWhatsThis(sidebar); sidebar->setWhatsThis(helpNewSideBar->getWhatsThisText(HelpWhatsThis::ScopeBar)); - sidebar->addItem(QImage(":sidebar/athlete.png"), tr("athletes"), 0, helpNewSideBar->getWhatsThisText(HelpWhatsThis::ScopeBar_Athletes)); - sidebar->setItemEnabled(1, false); + // The ids of the sidebar buttons below are defined in NewSideBar.h + sidebar->addItem(QImage(":sidebar/athlete.png"), tr("athletes"), GcSideBarBtnId::SELECT_ATHLETE_BTN, helpNewSideBar->getWhatsThisText(HelpWhatsThis::ScopeBar_Athletes)); - sidebar->addItem(QImage(":sidebar/plan.png"), tr("plan"), 1), tr("Feature not implemented yet"); - sidebar->setItemEnabled(1, false); + sidebar->addItem(QImage(":sidebar/plan.png"), tr("plan"), GcSideBarBtnId::PLAN_BTN, tr("Feature not implemented yet")); + sidebar->setItemEnabled(GcSideBarBtnId::PLAN_BTN, false); - sidebar->addItem(QImage(":sidebar/trends.png"), tr("trends"), 2, helpNewSideBar->getWhatsThisText(HelpWhatsThis::ScopeBar_Trends)); - sidebar->addItem(QImage(":sidebar/assess.png"), tr("activities"), 3, helpNewSideBar->getWhatsThisText(HelpWhatsThis::ScopeBar_Rides)); - sidebar->setItemSelected(3, true); + sidebar->addItem(QImage(":sidebar/trends.png"), tr("trends"), GcSideBarBtnId::TRENDS_BTN, helpNewSideBar->getWhatsThisText(HelpWhatsThis::ScopeBar_Trends)); - sidebar->addItem(QImage(":sidebar/reflect.png"), tr("reflect"), 4), tr("Feature not implemented yet"); - sidebar->setItemEnabled(4, false); + sidebar->addItem(QImage(":sidebar/assess.png"), tr("activities"), GcSideBarBtnId::ACTIVITIES_BTN, helpNewSideBar->getWhatsThisText(HelpWhatsThis::ScopeBar_Rides)); - sidebar->addItem(QImage(":sidebar/train.png"), tr("train"), 5, helpNewSideBar->getWhatsThisText(HelpWhatsThis::ScopeBar_Train)); + sidebar->addItem(QImage(":sidebar/reflect.png"), tr("reflect"), GcSideBarBtnId::REFLECT_BTN, tr("Feature not implemented yet")); + sidebar->setItemEnabled(GcSideBarBtnId::REFLECT_BTN, false); + + sidebar->addItem(QImage(":sidebar/train.png"), tr("train"), GcSideBarBtnId::TRAIN_BTN, helpNewSideBar->getWhatsThisText(HelpWhatsThis::ScopeBar_Train)); sidebar->addStretch(); - sidebar->addItem(QImage(":sidebar/apps.png"), tr("apps"), 6, tr("Feature not implemented yet")); - sidebar->setItemEnabled(6, false); + sidebar->addItem(QImage(":sidebar/apps.png"), tr("apps"), GcSideBarBtnId::APPS_BTN, tr("Feature not implemented yet")); + sidebar->setItemEnabled(GcSideBarBtnId::APPS_BTN, false); sidebar->addStretch(); // we can click on the quick icons, but they aren't selectable views - sidebar->addItem(QImage(":sidebar/sync.png"), tr("sync"), 7, helpNewSideBar->getWhatsThisText(HelpWhatsThis::ScopeBar_Sync)); - sidebar->setItemSelectable(7, false); - sidebar->addItem(QImage(":sidebar/prefs.png"), tr("options"), 8, helpNewSideBar->getWhatsThisText(HelpWhatsThis::ScopeBar_Options)); - sidebar->setItemSelectable(8, false); + sidebar->addItem(QImage(":sidebar/sync.png"), tr("sync"), GcSideBarBtnId::SYNC_BTN, helpNewSideBar->getWhatsThisText(HelpWhatsThis::ScopeBar_Sync)); + sidebar->setItemSelectable(GcSideBarBtnId::SYNC_BTN, false); + sidebar->addItem(QImage(":sidebar/prefs.png"), tr("options"), GcSideBarBtnId::OPTIONS_BTN, helpNewSideBar->getWhatsThisText(HelpWhatsThis::ScopeBar_Options)); + sidebar->setItemSelectable(GcSideBarBtnId::OPTIONS_BTN, false); - connect(sidebar, SIGNAL(itemClicked(int)), this, SLOT(sidebarClicked(int))); - connect(sidebar, SIGNAL(itemSelected(int)), this, SLOT(sidebarSelected(int))); + connect(sidebar, SIGNAL(itemClicked(GcSideBarBtnId)), this, SLOT(sidebarClicked(GcSideBarBtnId))); + connect(sidebar, SIGNAL(itemSelected(GcSideBarBtnId)), this, SLOT(sidebarSelected(GcSideBarBtnId))); /*---------------------------------------------------------------------- * What's this Context Help @@ -416,6 +421,7 @@ MainWindow::MainWindow(const QDir &home) tabbar->setDocumentMode(true); #endif + // Note: The order of the viewStack tabs below, must match the GcViewStackIdx definitions above. athleteView = new AthleteView(context); viewStack = new QStackedWidget(this); viewStack->addWidget(athleteView); @@ -1217,37 +1223,32 @@ MainWindow::support() } void -MainWindow::sidebarClicked(int id) +MainWindow::sidebarClicked(GcSideBarBtnId id) { - // sync quick link - if (id == 7) checkCloud(); - - // prefs - if (id == 8) showOptions(); - + switch (id) { + case GcSideBarBtnId::SYNC_BTN: checkCloud(); break; // sync quick link + case GcSideBarBtnId::OPTIONS_BTN: showOptions(); break; // prefs + } } void -MainWindow::sidebarSelected(int id) +MainWindow::sidebarSelected(GcSideBarBtnId id) { switch (id) { - case 0: selectAthlete(); break; - case 1: // plan not written yet - break; - case 2: selectTrends(); break; - case 3: selectAnalysis(); break; - case 4: // reflect not written yet - break; - case 5: selectTrain(); break; - case 6: // apps not written yet - break; + case GcSideBarBtnId::SELECT_ATHLETE_BTN: selectAthlete(); break; + case GcSideBarBtnId::PLAN_BTN: break; // plan not written yet + case GcSideBarBtnId::TRENDS_BTN: selectTrends(); break; + case GcSideBarBtnId::ACTIVITIES_BTN: selectAnalysis(); break; + case GcSideBarBtnId::REFLECT_BTN: break; // reflect not written yet + case GcSideBarBtnId::TRAIN_BTN: selectTrain(); break; + case GcSideBarBtnId::APPS_BTN: break;// apps not written yet } } void MainWindow::selectAthlete() { - viewStack->setCurrentIndex(0); + viewStack->setCurrentIndex(GcViewStackIdx::SELECT_ATHLETE_VIEW); back->hide(); forward->hide(); perspectiveSelector->hide(); @@ -1260,8 +1261,8 @@ MainWindow::selectAnalysis() { resetPerspective(1); //currentTab->analysisView->setPerspectives(perspectiveSelector); - viewStack->setCurrentIndex(1); - sidebar->setItemSelected(3, true); + viewStack->setCurrentIndex(GcViewStackIdx::ATHLETE_TAB_STACK); + sidebar->setItemSelected(GcSideBarBtnId::ACTIVITIES_BTN, true); currentAthleteTab->selectView(1); back->show(); forward->show(); @@ -1276,8 +1277,8 @@ MainWindow::selectTrain() { resetPerspective(3); //currentTab->trainView->setPerspectives(perspectiveSelector); - viewStack->setCurrentIndex(1); - sidebar->setItemSelected(5, true); + viewStack->setCurrentIndex(GcViewStackIdx::ATHLETE_TAB_STACK); + sidebar->setItemSelected(GcSideBarBtnId::TRAIN_BTN, true); currentAthleteTab->selectView(3); back->show(); forward->show(); @@ -1292,7 +1293,7 @@ MainWindow::selectDiary() { resetPerspective(2); //currentTab->diaryView->setPerspectives(perspectiveSelector); - viewStack->setCurrentIndex(1); + viewStack->setCurrentIndex(GcViewStackIdx::ATHLETE_TAB_STACK); currentAthleteTab->selectView(2); back->show(); forward->show(); @@ -1307,8 +1308,8 @@ MainWindow::selectTrends() { resetPerspective(0); //currentTab->homeView->setPerspectives(perspectiveSelector); - viewStack->setCurrentIndex(1); - sidebar->setItemSelected(2, true); + viewStack->setCurrentIndex(GcViewStackIdx::ATHLETE_TAB_STACK); + sidebar->setItemSelected(GcSideBarBtnId::TRENDS_BTN, true); currentAthleteTab->selectView(0); back->show(); forward->show(); @@ -2269,18 +2270,18 @@ MainWindow::saveGCState(Context *context) void MainWindow::restoreGCState(Context *context) { - if (viewStack->currentIndex() != 0) { + if (viewStack->currentIndex() != GcViewStackIdx::SELECT_ATHLETE_VIEW) { // not on athlete view... resetPerspective(currentAthleteTab->currentView()); // will lazy load, hence doing it first // restore window state from the supplied context switch(currentAthleteTab->currentView()) { - case 0: sidebar->setItemSelected(2,true); break; - case 1: sidebar->setItemSelected(3,true); break; + case 0: sidebar->setItemSelected(GcSideBarBtnId::TRENDS_BTN,true); break; + case 1: sidebar->setItemSelected(GcSideBarBtnId::ACTIVITIES_BTN,true); break; case 2: break; // diary not an icon - case 3: sidebar->setItemSelected(5, true); break; - default: sidebar->setItemSelected(0, true); break; + case 3: sidebar->setItemSelected(GcSideBarBtnId::TRAIN_BTN, true); break; + default: sidebar->setItemSelected(GcSideBarBtnId::SELECT_ATHLETE_BTN, true); break; } } diff --git a/src/Gui/MainWindow.h b/src/Gui/MainWindow.h index 772d5373c..98ee7f5c6 100644 --- a/src/Gui/MainWindow.h +++ b/src/Gui/MainWindow.h @@ -20,6 +20,7 @@ #ifndef _GC_MainWindow_h #define _GC_MainWindow_h 1 #include "GoldenCheetah.h" +#include "NewSideBar.h" #include #include @@ -175,8 +176,8 @@ class MainWindow : public QMainWindow void switchAthleteTab(int index); // for switching between one tab and another // sidebar selecting views and actions - void sidebarClicked(int id); - void sidebarSelected(int id); + void sidebarClicked(GcSideBarBtnId id); + void sidebarSelected(GcSideBarBtnId id); // Athlete Backup void setBackupAthleteMenu(); diff --git a/src/Gui/NavigationModel.cpp b/src/Gui/NavigationModel.cpp index 00f4f55ae..0b619f2ff 100644 --- a/src/Gui/NavigationModel.cpp +++ b/src/Gui/NavigationModel.cpp @@ -153,17 +153,12 @@ NavigationModel::action(bool redo, NavigationEvent event) { view = redo ? event.after.toInt() : event.before.toInt(); - // new side bar uses a different id, which will - // eventually be refactored to be the only id - // but for now we need to map this - int id=0; - switch(view) { - case 0: id=2; break; // trends - case 1: id=3; break; // analysis - case 2: id=0; break; // diary - case 3: id=5; break; // train + switch (view) { + case 0: tab->context->mainWindow->selectTrends(); break; + case 1: tab->context->mainWindow->selectAnalysis(); break; + case 2: tab->context->mainWindow->selectDiary(); break; + case 3: tab->context->mainWindow->selectTrain(); break; } - tab->context->mainWindow->sidebarSelected(id); } break; diff --git a/src/Gui/NewSideBar.cpp b/src/Gui/NewSideBar.cpp index f27d42110..bfbc5d289 100644 --- a/src/Gui/NewSideBar.cpp +++ b/src/Gui/NewSideBar.cpp @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2020 Mark Liversedge + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + #include "Context.h" #include "NewSideBar.h" #include "Colors.h" @@ -11,7 +29,7 @@ NewSideBar::NewSideBar(Context *context, QWidget *parent) : QWidget(parent), con { setFixedWidth(gl_itemwidth *dpiXFactor); setAutoFillBackground(true); - lastid=0; + lastid=GcSideBarBtnId::NO_BUTTON_SET; QVBoxLayout *mainlayout = new QVBoxLayout(this); mainlayout->setSpacing(0); @@ -35,18 +53,18 @@ NewSideBar::NewSideBar(Context *context, QWidget *parent) : QWidget(parent), con } void -NewSideBar::clicked(int id) +NewSideBar::clicked(GcSideBarBtnId id) { // un selectable item was clicked (e.g. symc or settings) emit itemClicked(id); } void -NewSideBar::selected(int id) +NewSideBar::selected(GcSideBarBtnId id) { // we selected one, so need to set it selected // and deselect everyone else - QMapIteratori(items); + QMapIteratori(items); while(i.hasNext()) { i.next(); if (i.key() == id) i.value()->setSelected(true); @@ -56,16 +74,15 @@ NewSideBar::selected(int id) emit itemSelected(id); } -int -NewSideBar::addItem(QImage icon, QString name, int id, QString whatsThisText) +GcSideBarBtnId +NewSideBar::addItem(QImage icon, const QString& name, GcSideBarBtnId id, const QString& whatsThisText) { - // allocated an id - if (id == -1) id=lastid++; - - NewSideBarItem *add = new NewSideBarItem(this, id, icon, name); - if (!whatsThisText.isEmpty()) add->setWhatsThis(whatsThisText); - layout->addWidget(add); - items.insert(id, add); + if (id != GcSideBarBtnId::NO_BUTTON_SET) { + NewSideBarItem *add = new NewSideBarItem(this, id, icon, name); + if (!whatsThisText.isEmpty()) add->setWhatsThis(whatsThisText); + layout->addWidget(add); + items.insert(id, add); + } return id; } @@ -80,14 +97,14 @@ NewSideBar::addStretch() // is it shown, is it usable? void -NewSideBar::setItemVisible(int id, bool x) +NewSideBar::setItemVisible(GcSideBarBtnId id, bool x) { NewSideBarItem *item = items.value(id, NULL); if (item) item->setVisible(x); } void -NewSideBar::setItemEnabled(int id, bool x) +NewSideBar::setItemEnabled(GcSideBarBtnId id, bool x) { NewSideBarItem *item = items.value(id, NULL); if (item) item->setEnabled(x); @@ -95,14 +112,14 @@ NewSideBar::setItemEnabled(int id, bool x) // can we select it, select it by program? void -NewSideBar::setItemSelectable(int id, bool x) +NewSideBar::setItemSelectable(GcSideBarBtnId id, bool x) { NewSideBarItem *item = items.value(id, NULL); if (item) item->setSelectable(x); } void -NewSideBar::setItemSelected(int id, bool x) +NewSideBar::setItemSelected(GcSideBarBtnId id, bool x) { NewSideBarItem *item = items.value(id, NULL); if (item) item->setSelected(x); @@ -131,7 +148,7 @@ NewSideBar::configChanged(qint32) middle->setStyleSheet(style); } -NewSideBarItem::NewSideBarItem(NewSideBar *sidebar, int id, QImage icon, QString name) : QWidget(sidebar), sidebar(sidebar), id(id), icon(icon), name(name) +NewSideBarItem::NewSideBarItem(NewSideBar *sidebar, GcSideBarBtnId id, QImage icon, QString name) : QWidget(sidebar), sidebar(sidebar), id(id), icon(icon), name(name) { clicked = selected = false; selectable = enabled = true; diff --git a/src/Gui/NewSideBar.h b/src/Gui/NewSideBar.h index ca7dc07ef..f95341e74 100644 --- a/src/Gui/NewSideBar.h +++ b/src/Gui/NewSideBar.h @@ -1,13 +1,48 @@ +/* + * Copyright (c) 2020 Mark Liversedge + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _GC_NewSideBar_h +#define _GC_NewSideBar_h 1 + #include #include #include +enum class GcSideBarBtnId : int { + NO_BUTTON_SET = -1, + SELECT_ATHLETE_BTN = 0, + PLAN_BTN = 1, + TRENDS_BTN = 2, + ACTIVITIES_BTN = 3, + REFLECT_BTN = 4, + TRAIN_BTN = 5, + APPS_BTN = 6, + SYNC_BTN = 7, + OPTIONS_BTN = 8 +}; + class Context; class NewSideBarItem; class NewSideBar : public QWidget { Q_OBJECT + Q_ENUM(GcSideBarBtnId) friend class ::NewSideBarItem; @@ -16,32 +51,31 @@ class NewSideBar : public QWidget public slots: - // managing items - the id can be assigned or will get a default - // it returns the id used - int addItem(QImage icon, QString name, int id=-1, QString whatsThisText=""); + // managing items - addItem returns the id of the button added, or NO_BUTTON_SET. + GcSideBarBtnId addItem(QImage icon, const QString& name, GcSideBarBtnId id, const QString& whatsThisText); // leave a gap- we have main icons, gap, apps, gap, sync, prefs void addStretch(); // is it shown, is it usable? - void setItemVisible(int id, bool); - void setItemEnabled(int id, bool); + void setItemVisible(GcSideBarBtnId id, bool); + void setItemEnabled(GcSideBarBtnId id, bool); // can we select it, select it by program? - void setItemSelectable(int id, bool); - void setItemSelected(int id, bool); + void setItemSelectable(GcSideBarBtnId id, bool); + void setItemSelected(GcSideBarBtnId id, bool); // config changed void configChanged(qint32); // called by children - void clicked(int id); - void selected(int id); + void clicked(GcSideBarBtnId id); + void selected(GcSideBarBtnId id); signals: - void itemSelected(int id); - void itemClicked(int id); + void itemSelected(GcSideBarBtnId id); + void itemClicked(GcSideBarBtnId id); protected: Context *context; @@ -49,9 +83,9 @@ class NewSideBar : public QWidget private: QWidget *top, *middle, *bottom; // bars at top and the bottom - QMap items; + QMap items; - int lastid; // when autoallocating + GcSideBarBtnId lastid; // when autoallocating QVBoxLayout *layout; }; @@ -62,7 +96,7 @@ class NewSideBarItem : public QWidget public: - NewSideBarItem(NewSideBar *sidebar, int id, QImage icon, QString name); + NewSideBarItem(NewSideBar *sidebar, GcSideBarBtnId id, QImage icon, QString name); void setSelectable(bool); void setEnabled(bool); @@ -87,7 +121,7 @@ class NewSideBarItem : public QWidget private: NewSideBar *sidebar; // for emitting signals - int id; + GcSideBarBtnId id; // pre-rendered/calculated icons and colors QImage icon; @@ -103,3 +137,5 @@ class NewSideBarItem : public QWidget bool enabled; bool clicked; }; + +#endif // _GC_NewSideBar_h