From 9f3b8bc101e23c2a1dc29d9cfcb40f1f967aa14d Mon Sep 17 00:00:00 2001 From: Paul Johnson Date: Tue, 4 Nov 2025 19:27:43 +0000 Subject: [PATCH] Configurable initial startup view (#4718) --- src/Core/Settings.h | 1 + src/Gui/AbstractView.cpp | 8 +++---- src/Gui/AbstractView.h | 2 +- src/Gui/AthleteTab.cpp | 6 ++++- src/Gui/MainWindow.cpp | 10 ++++++++- src/Gui/NavigationModel.cpp | 3 ++- src/Gui/Pages.cpp | 16 ++++++++++++++ src/Gui/Pages.h | 1 + src/Gui/Views.cpp | 44 +++++++++++++++++++++---------------- src/Gui/Views.h | 5 ++++- 10 files changed, 67 insertions(+), 29 deletions(-) diff --git a/src/Core/Settings.h b/src/Core/Settings.h index 89f1fd8f4..f2b3b9c4e 100644 --- a/src/Core/Settings.h +++ b/src/Core/Settings.h @@ -164,6 +164,7 @@ #define GC_TELEMETRY_UPDATE_COUNTER "telemetryUpdateCounter" #define GC_LAST_VERSION_CHECKED "lastVersionChecked" #define GC_LAST_VERSION_CHECK_DATE "lastVersionCheckDate" +#define GC_STARTUP_VIEW "startupView" diff --git a/src/Gui/AbstractView.cpp b/src/Gui/AbstractView.cpp index cde953908..64552c5f8 100644 --- a/src/Gui/AbstractView.cpp +++ b/src/Gui/AbstractView.cpp @@ -737,11 +737,9 @@ AbstractView::setPerspectives(QComboBox *perspectiveSelector, bool selectChart) if (!loaded || selectChart) { loaded = true; - // generally we just go to the first perspective - perspectiveSelected(0); - - // allow views to override the default perspective (if required) - setViewSpecificPerspective(); + // generally we just go to the first perspective, but we allow + // the views to override the default perspective (if required) + perspectiveSelected(getViewSpecificPerspective()); // due to visibility optimisation we need to force the first tab to be selected in tab mode if (perspective_->currentStyle == 0 && perspective_->charts.count()) perspective_->tabSelected(0); diff --git a/src/Gui/AbstractView.h b/src/Gui/AbstractView.h index 69b23b962..9f76ee36e 100644 --- a/src/Gui/AbstractView.h +++ b/src/Gui/AbstractView.h @@ -188,7 +188,7 @@ class AbstractView : public QWidget virtual void notifyViewStateRestored(); virtual void notifyViewPerspectiveAdded(Perspective* page); virtual void notifyViewSidebarChanged() {} - virtual void setViewSpecificPerspective() {} + virtual int getViewSpecificPerspective() { return 0; } virtual void notifyViewSplitterMoved() {} private slots: diff --git a/src/Gui/AthleteTab.cpp b/src/Gui/AthleteTab.cpp index da512c3df..ed0825548 100644 --- a/src/Gui/AthleteTab.cpp +++ b/src/Gui/AthleteTab.cpp @@ -169,7 +169,11 @@ AthleteTab::view(int index) void AthleteTab::selectView(int index) { - if (views->currentIndex() == index) return; // not changing + // ensure an initial viewChanged() event occurs for the navigation model, otherwise if the + // startup view is trends (value zero) the guard rejects the selection as views->currentIndex() is zero + static bool startupView = true; + if (!startupView && views->currentIndex() == index) return; // not changing + startupView = false; emit viewChanged(index); diff --git a/src/Gui/MainWindow.cpp b/src/Gui/MainWindow.cpp index 1f0037025..e640fa22f 100644 --- a/src/Gui/MainWindow.cpp +++ b/src/Gui/MainWindow.cpp @@ -707,7 +707,15 @@ MainWindow::MainWindow(const QDir &home) //connect(this, SIGNAL(rideClean()), this, SLOT(enableSaveButton())); saveGCState(currentAthleteTab->context); // set to whatever we started with - selectAnalysis(); + + // switch to the startup view, default is analysis. + switch (appsettings->value(NULL, GC_STARTUP_VIEW, "1").toInt()) { + case 0: selectTrends(); break; + case 1: selectAnalysis(); break; + case 2: selectDiary(); break; + case 3: selectTrain(); break; + default: selectAnalysis(); qDebug() << "Unknown startup view"; break; + } //grab focus currentAthleteTab->setFocus(); diff --git a/src/Gui/NavigationModel.cpp b/src/Gui/NavigationModel.cpp index 0b619f2ff..9adc35fba 100644 --- a/src/Gui/NavigationModel.cpp +++ b/src/Gui/NavigationModel.cpp @@ -227,7 +227,7 @@ NavigationModel::forward() stack[stackpointer+2].after.toInt() == 1) { // switch to analysis stackpointer++; - action(false, stack[stackpointer]); + action(true, stack[stackpointer]); } // redo @@ -235,4 +235,5 @@ NavigationModel::forward() action(true, stack[stackpointer]); } } + } diff --git a/src/Gui/Pages.cpp b/src/Gui/Pages.cpp index 6d2c53d41..d133ca6ab 100644 --- a/src/Gui/Pages.cpp +++ b/src/Gui/Pages.cpp @@ -243,6 +243,16 @@ GeneralPage::GeneralPage(Context *context) : context(context) connect(athleteBrowseButton, SIGNAL(clicked()), this, SLOT(browseAthleteDir())); + startupView = new QComboBox(); + startupView->addItem(tr("Trends")); + startupView->addItem(tr("Analysis")); + startupView->addItem(tr("Train")); + + // map view indexes to combo box values, given that plan/diary is not available + int startView = appsettings->value(NULL, GC_STARTUP_VIEW, "1").toInt(); + if (startView == 3) startView = 2; + startupView->setCurrentIndex(startView); + QFormLayout *form = newQFormLayout(); form->addRow(new QLabel(HLO + tr("Localization") + HLC)); form->addRow(tr("Language"), langCombo); @@ -252,6 +262,7 @@ GeneralPage::GeneralPage(Context *context) : context(context) form->addItem(new QSpacerItem(0, 15 * dpiYFactor)); form->addRow(new QLabel(HLO + tr("Application Behaviour") + HLC)); form->addRow(tr("Athlete Library"), athleteDirectoryLayout); + form->addRow(tr("Startup View"), startupView); form->addRow("", warnOnExit); form->addRow("", openLastAthlete); form->addRow("", opendata); @@ -305,6 +316,11 @@ GeneralPage::saveClicked() }; appsettings->setValue(GC_LANG, langs[langCombo->currentIndex()]); + // map combo box values to view indexes, given that plan/diary is not available + int startView = startupView->currentIndex(); + if (startView == 2) startView = 3; + appsettings->setValue(GC_STARTUP_VIEW, startView); + // Garmin and cranks appsettings->setValue(GC_GARMIN_HWMARK, garminHWMarkedit->value()); appsettings->setValue(GC_GARMIN_SMARTRECORD, garminSmartRecord->checkState()); diff --git a/src/Gui/Pages.h b/src/Gui/Pages.h index 9ee7f8172..aa5fbaedf 100644 --- a/src/Gui/Pages.h +++ b/src/Gui/Pages.h @@ -98,6 +98,7 @@ class GeneralPage : public QWidget Context *context; QComboBox *langCombo; + QComboBox* startupView; QComboBox *wbalForm; QCheckBox *garminSmartRecord; QCheckBox *warnOnExit; diff --git a/src/Gui/Views.cpp b/src/Gui/Views.cpp index eae0ec80e..46772a65e 100644 --- a/src/Gui/Views.cpp +++ b/src/Gui/Views.cpp @@ -77,23 +77,12 @@ AnalysisView::setRide(RideItem *ride) // then lets go find one to switch to.. if (context->mainWindow->athleteTab()->currentView() == 1 && page()->relevant(ride) != true) { - // lets find one to switch to - Perspective *found=page(); - foreach(Perspective *p, perspectives_){ - if (p->relevant(ride)) { - found =p; - break; - } - } - - // none of them want to be selected, so we can stay on the current one - // so long as it doesn't have an expression that failed... - if (found == page() && page()->expression() != "") - found = perspectives_[0]; + // lets find a perspective to switch to + int ridePerspectiveIdx = findRidesPerspective(ride); // if we need to switch, i.e. not already on it - if (found != page()) { - context->mainWindow->switchPerspective(perspectives_.indexOf(found)); + if (ridePerspectiveIdx != perspectives_.indexOf(page())) { + context->mainWindow->switchPerspective(ridePerspectiveIdx); } } @@ -101,6 +90,24 @@ AnalysisView::setRide(RideItem *ride) page()->setProperty("ride", QVariant::fromValue(dynamic_cast(ride))); } +int +AnalysisView::findRidesPerspective(RideItem* ride) +{ + // lets find one to switch to + foreach(Perspective *p, perspectives_) { + if (p->relevant(ride)) { + return perspectives_.indexOf(p); + } + } + + // none of them want to be selected, so we can stay on the current one + // so long as it doesn't have an expression that failed... + if (page()->expression() != "") return 0; + + // we can just return the current one + return perspectives_.indexOf(page()); +} + void AnalysisView::addIntervals() { @@ -137,12 +144,11 @@ AnalysisView::notifyViewSidebarChanged() { } } -void -AnalysisView::setViewSpecificPerspective() { +int +AnalysisView::getViewSpecificPerspective() { // Setting the ride for analysis view also sets the perspective. - RideItem* ride = (RideItem*)context->currentRideItem(); - if (ride != NULL) setRide(ride); + return findRidesPerspective(const_cast(context->currentRideItem())); } void diff --git a/src/Gui/Views.h b/src/Gui/Views.h index 53a72261d..fd0a636ea 100644 --- a/src/Gui/Views.h +++ b/src/Gui/Views.h @@ -50,9 +50,12 @@ class AnalysisView : public AbstractView protected: void notifyViewSidebarChanged() override; - void setViewSpecificPerspective() override; + int getViewSpecificPerspective() override; void notifyViewSplitterMoved() override; + private: + + int findRidesPerspective(RideItem* ride); }; class DiarySidebar;