diff --git a/core/LogParam.cpp b/core/LogParam.cpp index 9f93d1a6..54b7062b 100644 --- a/core/LogParam.cpp +++ b/core/LogParam.cpp @@ -1129,10 +1129,10 @@ void LogParam::setMainWindowAlertBeep(bool state) bool LogParam::getMainWindowDarkMode() { - return getParam("mainwindow/darkmode", false).toBool(); + return getParam("mainwindow/darkmode", 0).toInt(); } -void LogParam::setMainWindowDarkMode(bool state) +void LogParam::setMainWindowDarkMode(int state) { setParam("mainwindow/darkmode", state); } diff --git a/core/LogParam.h b/core/LogParam.h index 5e750ec9..003576f1 100644 --- a/core/LogParam.h +++ b/core/LogParam.h @@ -344,7 +344,7 @@ class LogParam : public QObject static bool getMainWindowAlertBeep(); static void setMainWindowAlertBeep(bool state); static bool getMainWindowDarkMode(); - static void setMainWindowDarkMode(bool state); + static void setMainWindowDarkMode(int state); static QByteArray getMainWindowGeometry(); static void setMainWindowGeometry(const QByteArray &state); static QByteArray getMainWindowState(); diff --git a/data/MainLayoutProfile.cpp b/data/MainLayoutProfile.cpp index 7d0f1d06..6f4ce2c1 100644 --- a/data/MainLayoutProfile.cpp +++ b/data/MainLayoutProfile.cpp @@ -71,7 +71,7 @@ MainLayoutProfilesManager::MainLayoutProfilesManager() : profileDB.detailColC = toIntList(profileQuery.value(5).toString()); profileDB.mainGeometry = QByteArray::fromBase64(profileQuery.value(6).toString().toUtf8()); profileDB.mainState = QByteArray::fromBase64(profileQuery.value(7).toString().toUtf8()); - profileDB.darkMode = profileQuery.value(8).toBool(); + profileDB.darkMode = profileQuery.value(8).toInt(); profileDB.tabsexpanded = profileQuery.value(9).toBool(); profileDB.addlBandmaps = toPairStringList(profileQuery.value(10).toString()); addProfile(profileDB.profileName, profileDB); diff --git a/data/MainLayoutProfile.h b/data/MainLayoutProfile.h index 527bf7fc..2bdaad70 100644 --- a/data/MainLayoutProfile.h +++ b/data/MainLayoutProfile.h @@ -11,7 +11,11 @@ class MainLayoutProfile { public: - MainLayoutProfile(){darkMode = false; tabsexpanded = true;}; + MainLayoutProfile() + { + darkMode = 0; + tabsexpanded = true; + }; QString profileName; QList rowA; @@ -21,7 +25,7 @@ class MainLayoutProfile QList detailColC; QByteArray mainGeometry; QByteArray mainState; - bool darkMode; + int darkMode; bool tabsexpanded; QList> addlBandmaps; diff --git a/res/icons/color-palette-dark.svg b/res/icons/color-palette-dark.svg new file mode 100644 index 00000000..fc4a3a5e --- /dev/null +++ b/res/icons/color-palette-dark.svg @@ -0,0 +1 @@ + diff --git a/res/icons/color-palette-light.svg b/res/icons/color-palette-light.svg new file mode 100644 index 00000000..cda903ac --- /dev/null +++ b/res/icons/color-palette-light.svg @@ -0,0 +1 @@ + diff --git a/res/icons/icons.qrc b/res/icons/icons.qrc index 046a6b9c..76eb333a 100644 --- a/res/icons/icons.qrc +++ b/res/icons/icons.qrc @@ -17,7 +17,6 @@ cancel-24px.svg info-24px.svg close-24px.svg - light-dark-24px.svg alert.svg connect.svg disconnect.svg @@ -35,5 +34,7 @@ delete-button.svg new-window.svg clear-button.svg + color-palette-light.svg + color-palette-dark.svg diff --git a/res/icons/light-dark-24px.svg b/res/icons/light-dark-24px.svg deleted file mode 100644 index 43c9e6bc..00000000 --- a/res/icons/light-dark-24px.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/ui/MainWindow.cpp b/ui/MainWindow.cpp index 57ba9c4b..3cd6b771 100644 --- a/ui/MainWindow.cpp +++ b/ui/MainWindow.cpp @@ -47,19 +47,24 @@ MainWindow::MainWindow(QWidget* parent) : restoreContestMenuDupeType(); restoreContestMenuLinkExchange(); - darkLightModeSwith = new SwitchButton("", ui->statusBar); - darkIconLabel = new QLabel("",ui->statusBar); + themeButton = new QPushButton(this); + themeButton->setToolTip(tr("Color Theme")); + themeButton->setIcon(QIcon(QPixmap(":/icons/color-palette-dark.svg"))); + themeButton->setFlat(true); + + QMenu *themeMenu = new QMenu(this); + themeMenu->addAction(ui->actionThemeNative); + themeMenu->addAction(ui->actionThemeLight); + themeMenu->addAction(ui->actionThemeDark); + themeButton->setMenu(themeMenu); /* Dark Mode is supported only in case of Fusion Style */ if ( QApplication::style()->objectName().compare("fusion", Qt::CaseSensitivity::CaseInsensitive) != 0) { isFusionStyle = false; - darkLightModeSwith->setEnabled(false); - darkIconLabel->setEnabled(false); - darkLightModeSwith->setToolTip(tr("Not enabled for non-Fusion style")); - darkModeToggle(Qt::Unchecked); - + themeButton->setEnabled(false); + themeButton->setToolTip(tr("Not enabled for non-Fusion style")); } else { @@ -136,8 +141,7 @@ MainWindow::MainWindow(QWidget* parent) : ui->statusBar->addPermanentWidget(alertTextButton); ui->statusBar->addPermanentWidget(alertButton); - ui->statusBar->addPermanentWidget(darkLightModeSwith); - ui->statusBar->addPermanentWidget(darkIconLabel); + ui->statusBar->addPermanentWidget(themeButton); setContestMode(LogParam::getContestID()); @@ -187,8 +191,15 @@ MainWindow::MainWindow(QWidget* parent) : connect(this, &MainWindow::themeChanged, ui->rotatorWidget, &RotatorWidget::redrawMap); connect(this, &MainWindow::themeChanged, stats, &StatisticsWidget::changeTheme); - connect(darkLightModeSwith, &SwitchButton::stateChanged, this, &MainWindow::darkModeToggle); - darkLightModeSwith->setChecked(LogParam::getMainWindowDarkMode()); + connect(ui->actionThemeNative, &QAction::triggered, this, [this](bool checked) { + this->themeInit(0); + }); + connect(ui->actionThemeDark, &QAction::triggered, this, [this](bool checked) { + this->themeInit(1); + }); + connect(ui->actionThemeLight, &QAction::triggered, this, [this](bool checked) { + this->themeInit(2); + }); connect(Rig::instance(), &Rig::rigErrorPresent, this, &MainWindow::rigErrorHandler); connect(Rig::instance(), &Rig::rigCWKeyOpenRequest, this, &MainWindow::cwKeyerConnectProfile); @@ -536,7 +547,8 @@ QStringList MainWindow::getBuiltInStaticShortcutList() const const QList allShortcuts = findChildren(); for ( QShortcut* shortcut : allShortcuts) { - if ( !shortcut->key().toString().isEmpty() ) + if (!shortcut->key().toString().isEmpty()) + { qCDebug(runtime) << "Built-In nonchangeble shortcut" << shortcut->key().toString(QKeySequence::NativeText); @@ -815,26 +827,125 @@ void MainWindow::showUpdateDialog(const QString &newVersion, const QString &repo settings.setValue("seenversion", newVersion); // platform-depend parameter } -void MainWindow::darkModeToggle(int mode) +void MainWindow::setDarkTheme() { FCT_IDENTIFICATION; - qCDebug(function_parameters) << mode; + QPalette darkPalette; + QColor darkColor = QColor(45, 45, 45); + QColor disabledColor = QColor(127, 127, 127); + darkPalette.setColor(QPalette::Window, darkColor); + darkPalette.setColor(QPalette::WindowText, Qt::white); + darkPalette.setColor(QPalette::Base, QColor(18, 18, 18)); + darkPalette.setColor(QPalette::AlternateBase, darkColor); + darkPalette.setColor(QPalette::Text, Qt::white); + darkPalette.setColor(QPalette::Disabled, QPalette::Text, disabledColor); + darkPalette.setColor(QPalette::Button, darkColor); + darkPalette.setColor(QPalette::ButtonText, Qt::white); + darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, disabledColor); + darkPalette.setColor(QPalette::BrightText, Qt::red); + darkPalette.setColor(QPalette::Link, QColor(42, 130, 218)); + darkPalette.setColor(QPalette::Highlight, QColor(42, 130, 218)); + darkPalette.setColor(QPalette::HighlightedText, Qt::black); + darkPalette.setColor(QPalette::Disabled, QPalette::HighlightedText, disabledColor); - bool darkMode = (mode == Qt::Checked) ? true: false; - LogParam::setMainWindowDarkMode(darkMode); + qApp->setPalette(darkPalette); +} - if ( mode == Qt::Checked) - setDarkMode(); - else - setLightMode(); +void MainWindow::setLightTheme() +{ + FCT_IDENTIFICATION; + + QPalette lightPalette; + QColor lightColor = QColor(239, 239, 239); + QColor disabledColor = QColor(190, 190, 190); + lightPalette.setColor(QPalette::Window, lightColor); + lightPalette.setColor(QPalette::WindowText, Qt::black); + lightPalette.setColor(QPalette::Base, Qt::white); + lightPalette.setColor(QPalette::AlternateBase, lightColor); + lightPalette.setColor(QPalette::Text, Qt::black); + lightPalette.setColor(QPalette::Disabled, QPalette::Text, disabledColor); + lightPalette.setColor(QPalette::Button, lightColor); + lightPalette.setColor(QPalette::ButtonText, Qt::black); + lightPalette.setColor(QPalette::Disabled, QPalette::ButtonText, disabledColor); + lightPalette.setColor(QPalette::BrightText, Qt::white); + lightPalette.setColor(QPalette::Link, QColor(0, 0, 255)); + lightPalette.setColor(QPalette::Highlight, QColor(48, 140, 198)); + lightPalette.setColor(QPalette::HighlightedText, Qt::white); + lightPalette.setColor(QPalette::Disabled, QPalette::HighlightedText, Qt::white); + + qApp->setPalette(lightPalette); + +} + +bool MainWindow::setNativeTheme() +{ + FCT_IDENTIFICATION; + + qApp->setPalette(this->style()->standardPalette()); + bool isDark = false; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) + const auto scheme = QGuiApplication::styleHints()->colorScheme(); + isDark = scheme == Qt::ColorScheme::Dark; +#else + const QPalette defaultPalette = this->style()->standardPalette(); + const auto text = defaultPalette.color(QPalette::WindowText); + const auto window = defaultPalette.color(QPalette::Window); + isDark = text.lightness() > window.lightness(); +#endif // QT_VERSION + + return isDark; +} + +void MainWindow::themeInit(int mode) +{ + FCT_IDENTIFICATION; + + LogParam::setMainWindowDarkMode(mode); + + ui->actionThemeNative->setChecked(false); + ui->actionThemeLight->setChecked(false); + ui->actionThemeDark->setChecked(false); + bool isDark = false; + switch (mode) { + case 0: + ui->actionThemeNative->setChecked(true); + isDark = this->setNativeTheme(); + break; + case 1: + ui->actionThemeDark->setChecked(true); + this->setDarkTheme(); + isDark = true; + break; + case 2: + ui->actionThemeLight->setChecked(true); + this->setLightTheme(); + break; + } QFile style(":/res/stylesheet.css"); style.open(QFile::ReadOnly | QIODevice::Text); qApp->setStyleSheet(style.readAll()); style.close(); - emit themeChanged(darkMode); + if (isDark) { + themeButton->setIcon(QIcon(QPixmap(":/icons/color-palette-dark.svg"))); + } else { + themeButton->setIcon(QIcon(QPixmap(":/icons/color-palette-light.svg"))); + } + + emit themeChanged(mode, isDark); +} + +void MainWindow::changeEvent(QEvent *event) +{ + if (event->type() == QEvent::ThemeChange) { + if (ui->actionThemeNative->isChecked()) { + this->themeInit(0); + } + } + QMainWindow::changeEvent(event); } void MainWindow::processSpotAlert(SpotAlert alert) @@ -935,9 +1046,12 @@ void MainWindow::setLayoutGeometry() QByteArray newGeometry; QByteArray newState; - bool darkMode = false; - const QList> bandmapWidgets = (layoutProfile.profileName.isEmpty()) ? MainLayoutProfilesManager::toPairStringList(LogParam::getMainWindowBandmapWidgets()) - : layoutProfile.addlBandmaps; + int darkMode = 0; + const QList> bandmapWidgets + = (layoutProfile.profileName.isEmpty()) + ? MainLayoutProfilesManager::toPairStringList(LogParam::getMainWindowBandmapWidgets()) + : layoutProfile.addlBandmaps; + if ( layoutProfile.mainGeometry != QByteArray() || layoutProfile.mainState != QByteArray() ) { @@ -970,7 +1084,7 @@ void MainWindow::setLayoutGeometry() connect(nt, &QTimer::timeout, this, [this, darkMode, newState]() { restoreState(newState); - darkLightModeSwith->setChecked(isFusionStyle && darkMode); + this->themeInit(isFusionStyle ? darkMode : 0); connect(MainLayoutProfilesManager::instance(), &MainLayoutProfilesManager::profileChanged, this, &MainWindow::setSimplyLayoutGeometry); }); @@ -1011,7 +1125,7 @@ void MainWindow::setSimplyLayoutGeometry() connect(nt, &QTimer::timeout, this, [this, layoutProfile]() { restoreState(layoutProfile.mainState); - darkLightModeSwith->setChecked(isFusionStyle && layoutProfile.darkMode); + this->themeInit(isFusionStyle ? layoutProfile.darkMode : 0); }); nt->connect(nt, &QTimer::timeout, nt, &QTimer::deleteLater); nt->start(); @@ -1029,8 +1143,13 @@ void MainWindow::saveProfileLayoutGeometry() layoutProfile.addlBandmaps = getNonVfoBandmapsParams(); layoutProfile.mainGeometry = saveGeometry(); layoutProfile.mainState = saveState(); - layoutProfile.darkMode = darkLightModeSwith->isChecked(); - layoutProfile.tabsexpanded = ui->newContactWidget->getTabCollapseState(); + layoutProfile.darkMode = 0; + if (ui->actionThemeDark->isChecked()) { + layoutProfile.darkMode = 1; + } else if (ui->actionThemeLight->isChecked()) { + layoutProfile.darkMode = 2; + } + layoutProfile.tabsexpanded = ui->newContactWidget->getTabCollapseState(); MainLayoutProfilesManager::instance()->addProfile(layoutProfile.profileName, layoutProfile); MainLayoutProfilesManager::instance()->blockSignals(true); // prevent screen flashing MainLayoutProfilesManager::instance()->save(); @@ -1047,40 +1166,6 @@ void MainWindow::setEquipmentKeepOptions(bool) //saveEquipmentConnOptions(); } - - -void MainWindow::setDarkMode() -{ - FCT_IDENTIFICATION; - - QPalette darkPalette; - QColor darkColor = QColor(45,45,45); - QColor disabledColor = QColor(127,127,127); - darkPalette.setColor(QPalette::Window, darkColor); - darkPalette.setColor(QPalette::WindowText, Qt::white); - darkPalette.setColor(QPalette::Base, QColor(18,18,18)); - darkPalette.setColor(QPalette::AlternateBase, darkColor); - darkPalette.setColor(QPalette::Text, Qt::white); - darkPalette.setColor(QPalette::Disabled, QPalette::Text, disabledColor); - darkPalette.setColor(QPalette::Button, darkColor); - darkPalette.setColor(QPalette::ButtonText, Qt::white); - darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, disabledColor); - darkPalette.setColor(QPalette::BrightText, Qt::red); - darkPalette.setColor(QPalette::Link, QColor(42, 130, 218)); - darkPalette.setColor(QPalette::Highlight, QColor(42, 130, 218)); - darkPalette.setColor(QPalette::HighlightedText, Qt::black); - darkPalette.setColor(QPalette::Disabled, QPalette::HighlightedText, disabledColor); - - qApp->setPalette(darkPalette); -} - -void MainWindow::setLightMode() -{ - FCT_IDENTIFICATION; - - qApp->setPalette(this->style()->standardPalette()); -} - void MainWindow::setupActivitiesMenu() { FCT_IDENTIFICATION; diff --git a/ui/MainWindow.h b/ui/MainWindow.h index 63c5819e..8e7687ef 100644 --- a/ui/MainWindow.h +++ b/ui/MainWindow.h @@ -24,12 +24,14 @@ class MainWindow : public QMainWindow { void closeEvent(QCloseEvent* event); void keyReleaseEvent(QKeyEvent *event); + void changeEvent(QEvent *event); + QList getUserDefinedShortcutActionList(); QStringList getBuiltInStaticShortcutList() const; signals: void settingsChanged(); - void themeChanged(int); + void themeChanged(int themeMode, bool isDark); void altBackslash(bool active); void manualMode(bool); void contestStopped(); @@ -64,7 +66,6 @@ private slots: void conditionsUpdated(); void QSOFilterSetting(); void alertRuleSetting(); - void darkModeToggle(int); void processSpotAlert(SpotAlert alert); void clearAlertEvent(); void beepSettingAlerts(); @@ -99,8 +100,7 @@ private slots: QLabel* contestLabel; QPushButton* alertButton; QPushButton* alertTextButton; - SwitchButton* darkLightModeSwith; - QLabel* darkIconLabel; + QPushButton *themeButton; StatisticsWidget* stats; NetworkNotification networknotification; AlertEvaluator alertEvaluator; @@ -113,9 +113,6 @@ private slots: QActionGroup *linkExchangeGroup; QPushButton *activityButton; - void setDarkMode(); - void setLightMode(); - void setupActivitiesMenu(); void restoreUserDefinedShortcuts(); @@ -130,6 +127,10 @@ private slots: void openNonVfoBandmaps(const QList> &list); void clearNonVfoBandmaps(); QList> getNonVfoBandmapsParams() const; + void themeInit(int mode); + bool setNativeTheme(); + void setLightTheme(); + void setDarkTheme(); }; #endif // QLOG_UI_MAINWINDOW_H diff --git a/ui/MainWindow.ui b/ui/MainWindow.ui index 4d0f129e..6fbf5992 100644 --- a/ui/MainWindow.ui +++ b/ui/MainWindow.ui @@ -883,6 +883,39 @@ true + + + true + + + Theme: Native + + + QAction::MenuRole::TextHeuristicRole + + + + + true + + + Theme: QLog Light + + + QAction::MenuRole::TextHeuristicRole + + + + + true + + + Theme: QLog Dark + + + QAction::MenuRole::TextHeuristicRole + + diff --git a/ui/OnlineMapWidget.cpp b/ui/OnlineMapWidget.cpp index 160ec946..5e2ae229 100644 --- a/ui/OnlineMapWidget.cpp +++ b/ui/OnlineMapWidget.cpp @@ -86,17 +86,21 @@ void OnlineMapWidget::setTarget(double lat, double lon) antPositionChanged(lastSeenAzimuth, lastSeenElevation); } -void OnlineMapWidget::changeTheme(int theme) +void OnlineMapWidget::changeTheme(int theme, bool isDark) { FCT_IDENTIFICATION; - qCDebug(function_parameters) << theme; + qCDebug(function_parameters) << theme << isDark; QString themeJavaScript; //theme == 1 dart - themeJavaScript = ( theme == 1 ) ? QLatin1String("map.getPanes().tilePane.style.webkitFilter=\"brightness(0.6) invert(1) contrast(3) hue-rotate(200deg) saturate(0.3) brightness(0.9)\";") - : QLatin1String("map.getPanes().tilePane.style.webkitFilter=\"\";"); + themeJavaScript + = (isDark == 1) + ? QLatin1String( + "map.getPanes().tilePane.style.webkitFilter=\"brightness(0.6) invert(1) " + "contrast(3) hue-rotate(200deg) saturate(0.3) brightness(0.9)\";") + : QLatin1String("map.getPanes().tilePane.style.webkitFilter=\"\";"); runJavaScript(themeJavaScript); } diff --git a/ui/OnlineMapWidget.h b/ui/OnlineMapWidget.h index 23b83faa..b6bb1057 100644 --- a/ui/OnlineMapWidget.h +++ b/ui/OnlineMapWidget.h @@ -33,7 +33,7 @@ class OnlineMapWidget : public QWebEngineView public slots: void setTarget(double lat, double lon); - void changeTheme(int); + void changeTheme(int, bool isDark); void auroraDataUpdate(); void mufDataUpdate(); void setIBPBand(VFOID, double, double, double); diff --git a/ui/StatisticsWidget.cpp b/ui/StatisticsWidget.cpp index 5e4eac99..8c3c01be 100644 --- a/ui/StatisticsWidget.cpp +++ b/ui/StatisticsWidget.cpp @@ -400,15 +400,15 @@ void StatisticsWidget::mapLoaded(bool) layerControlHandler.restoreLayerControlStates(main_page); } -void StatisticsWidget::changeTheme(int theme) +void StatisticsWidget::changeTheme(int theme, bool isDark) { FCT_IDENTIFICATION; - qCDebug(function_parameters) << theme; + qCDebug(function_parameters) << theme << isDark; QString themeJavaScript; - if ( theme == 1 ) /* dark mode */ + if (isDark) /* dark mode */ themeJavaScript = "map.getPanes().tilePane.style.webkitFilter=\"brightness(0.6) invert(1) contrast(3) hue-rotate(200deg) saturate(0.3) brightness(0.9)\";"; else themeJavaScript = "map.getPanes().tilePane.style.webkitFilter=\"\";"; diff --git a/ui/StatisticsWidget.h b/ui/StatisticsWidget.h index 99b591be..1ff4bae0 100644 --- a/ui/StatisticsWidget.h +++ b/ui/StatisticsWidget.h @@ -27,7 +27,7 @@ public slots: void mainStatChanged(int); void dateRangeCheckBoxChanged(int); void mapLoaded(bool); - void changeTheme(int); + void changeTheme(int, bool isDark); void refreshWidget(); private slots: