From 630fbb5c3e9ac7a5fa7d8c1a46d39de40cfca80e Mon Sep 17 00:00:00 2001 From: xdustinface Date: Mon, 8 Jun 2020 03:39:49 +0200 Subject: [PATCH 1/3] qt: Change themes path from ":themes" to ":css" Required for the introduction of a custom css directory which will happen with the follow-up commits. --- src/qt/dash.qrc | 8 +++----- src/qt/guiutil.cpp | 13 ++++++++++++- src/qt/guiutil.h | 3 +++ src/qt/optionsdialog.cpp | 3 +-- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/qt/dash.qrc b/src/qt/dash.qrc index 2d4ba4a8c4aa..c567898589b4 100644 --- a/src/qt/dash.qrc +++ b/src/qt/dash.qrc @@ -57,6 +57,9 @@ res/css/general.css res/css/scrollbars.css + res/css/dark.css + res/css/light.css + res/css/trad.css res/fonts/Montserrat/Montserrat-Black.otf @@ -78,11 +81,6 @@ res/fonts/Montserrat/Montserrat-Thin.otf res/fonts/Montserrat/Montserrat-ThinItalic.otf - - res/css/dark.css - res/css/light.css - res/css/trad.css - res/images/arrow_down_normal.png res/images/arrow_down_hover.png diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 5ce10d864db0..228bacb6b95c 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -971,6 +971,17 @@ void migrateQtSettings() } } +const std::vector listThemes() +{ + std::vector vecThemes; + for (const auto& it : mapStyleToTheme) { + if (!it.second.isEmpty()) { + vecThemes.push_back(it.second); + } + } + return vecThemes; +} + // Open CSS when configured QString loadStyleSheet() { @@ -1006,7 +1017,7 @@ QString loadStyleSheet() #endif } - QFile qFileTheme(":themes/" + theme); + QFile qFileTheme(":css/" + theme); if (qFileTheme.open(QFile::ReadOnly)) { stylesheet.get()->append(QLatin1String(qFileTheme.readAll())); } diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 59fd9dde1a12..727d026e0922 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -230,6 +230,9 @@ namespace GUIUtil /** Modify Qt network specific settings on migration */ void migrateQtSettings(); + /** Return a list of all theme css files */ + const std::vector listThemes(); + /** Load global CSS theme */ QString loadStyleSheet(); diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 01a5fa3b5698..0fd78378d49c 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -90,8 +90,7 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) : } /* Theme selector */ - QDir themes(":themes"); - for (const QString &entry : themes.entryList()) { + for (const QString& entry : GUIUtil::listThemes()) { ui->theme->addItem(entry, QVariant(entry)); } From c24ecaad25f610b47c79344ddb9959cdcffd9515 Mon Sep 17 00:00:00 2001 From: xdustinface Date: Mon, 8 Jun 2020 03:40:00 +0200 Subject: [PATCH 2/3] qt: Renamed trad.css to traditional.css --- src/Makefile.qt.include | 2 +- src/qt/dash.qrc | 2 +- src/qt/res/css/general.css | 4 ++-- src/qt/res/css/{trad.css => traditional.css} | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) rename src/qt/res/css/{trad.css => traditional.css} (97%) diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 8561587c1fc1..b975e8161342 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -353,7 +353,7 @@ RES_CSS = \ qt/res/css/general.css \ qt/res/css/light.css \ qt/res/css/scrollbars.css \ - qt/res/css/trad.css + qt/res/css/traditional.css RES_FONTS = \ qt/res/fonts/Montserrat/Montserrat-Black.otf \ diff --git a/src/qt/dash.qrc b/src/qt/dash.qrc index c567898589b4..392e0ce6cf8c 100644 --- a/src/qt/dash.qrc +++ b/src/qt/dash.qrc @@ -59,7 +59,7 @@ res/css/scrollbars.css res/css/dark.css res/css/light.css - res/css/trad.css + res/css/traditional.css res/fonts/Montserrat/Montserrat-Black.otf diff --git a/src/qt/res/css/general.css b/src/qt/res/css/general.css index 7ce269b14aa9..0c7c6dc73a8f 100644 --- a/src/qt/res/css/general.css +++ b/src/qt/res/css/general.css @@ -10,7 +10,7 @@ loaded and combined in `GUIUtil::loadStyleSheet()` in guitil.cpp. Hierarchy: -* general.css - base layout: Loaded first if selected theme is not "Traditional" (trad.css) +* general.css - base layout: Loaded first if selected theme is not "Traditional" (traditional.css) * scrollbars.css - custom scrollbars: Loaded second only for windows/linux if general.css is loaded * - theme css file: Always loaded and loaded last. @@ -18,7 +18,7 @@ To replace there are currently the following themes available: * Dark (dark.css) * Light (light.css) -* Traditional (trad.css) +* Traditional (traditional.css) NOTE: This file is only the base layout which is getting shared between all full themes (e.g. Dark or Light). It may contain diff --git a/src/qt/res/css/trad.css b/src/qt/res/css/traditional.css similarity index 97% rename from src/qt/res/css/trad.css rename to src/qt/res/css/traditional.css index 23d618ff5013..57aea5e1599a 100644 --- a/src/qt/res/css/trad.css +++ b/src/qt/res/css/traditional.css @@ -17,7 +17,7 @@ Loaded in GUIUtil::loadStyleSheet() in guitil.cpp. /* do not modify! section updated by update-css-files.py -# Used colors in trad.css for commit 3bebd1a5c +# Used colors in traditional.css for commit 3bebd1a5c #fff #ccfafafa From b63d661b4db16e751ad87040ccd15e1f388fd718 Mon Sep 17 00:00:00 2001 From: xdustinface Date: Mon, 8 Jun 2020 03:44:34 +0200 Subject: [PATCH 3/3] qt: Add -custom-css-dir startup parameter This allows to load a custom directory as css directory. The custom directory currently needs to have the files: - general.css - dark.css - light.css - traditional.css - scrollbars.css --- src/qt/dash.cpp | 35 ++++++++++++++++++++++ src/qt/guiutil.cpp | 64 ++++++++++++++++++++++++++++------------ src/qt/guiutil.h | 10 +++++++ src/qt/utilitydialog.cpp | 1 + 4 files changed, 91 insertions(+), 19 deletions(-) diff --git a/src/qt/dash.cpp b/src/qt/dash.cpp index fd0e31715b09..dfcd3b8cde75 100644 --- a/src/qt/dash.cpp +++ b/src/qt/dash.cpp @@ -740,6 +740,41 @@ int main(int argc, char *argv[]) } GUIUtil::setFontScale(nScale); } + // Validate/set custom css directory + if (gArgs.IsArgSet("-custom-css-dir")) { + fs::path customDir = fs::path(gArgs.GetArg("-custom-css-dir", "")); + QString strCustomDir = QString::fromStdString(customDir.string()); + std::vector vecRequiredFiles = GUIUtil::listStyleSheets(); + QString strFile; + + if (!fs::is_directory(customDir)) { + QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), + QObject::tr("Error: Invalid -custom-css-dir path.") + "\n\n" + strCustomDir); + return EXIT_FAILURE; + } + + for (auto itCustomDir = fs::directory_iterator(customDir); itCustomDir != fs::directory_iterator(); ++itCustomDir) { + if (fs::is_regular_file(*itCustomDir) && itCustomDir->path().extension() == ".css") { + strFile = QString::fromStdString(itCustomDir->path().filename().string()); + auto itFile = std::find(vecRequiredFiles.begin(), vecRequiredFiles.end(), strFile); + if (itFile != vecRequiredFiles.end()) { + vecRequiredFiles.erase(itFile); + } + } + } + + if (vecRequiredFiles.size()) { + QString strMissingFiles; + for (const auto& strMissingFile : vecRequiredFiles) { + strMissingFiles += strMissingFile + "\n"; + } + QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), + QObject::tr("Error: %1 CSS file(s) missing in -custom-css-dir path.").arg(vecRequiredFiles.size()) + "\n\n" + strMissingFiles); + return EXIT_FAILURE; + } + + GUIUtil::setStyleSheetDirectory(strCustomDir); + } // Subscribe to global signals from core uiInterface.InitMessage.connect(InitMessage); diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 228bacb6b95c..5f7f2073791b 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -80,12 +80,24 @@ void ForceActivation(); namespace GUIUtil { +// The default stylesheet directory +static const QString defaultStylesheetDirectory = ":css"; +// The actual stylesheet directory +static QString stylesheetDirectory = defaultStylesheetDirectory; // The name of the traditional theme static const QString traditionalTheme = "Traditional"; // The theme to set by default if settings are missing or incorrect static const QString defaultTheme = "Light"; // The prefix a theme name should have if we want to apply dark colors and styles to it static const QString darkThemePrefix = "Dark"; +// Mapping css file => theme. +static const std::map mapStyleToTheme{ + {"general.css", ""}, + {"dark.css", "Dark"}, + {"light.css", "Light"}, + {"traditional.css", "Traditional"}, + {"scrollbars.css", ""} +}; /** Font related default values. */ static const FontFamily defaultFontFamily = FontFamily::SystemDefault; @@ -971,6 +983,25 @@ void migrateQtSettings() } } +void setStyleSheetDirectory(const QString& path) +{ + stylesheetDirectory = path; +} + +bool isStyleSheetDirectoryCustom() +{ + return stylesheetDirectory != defaultStylesheetDirectory; +} + +const std::vector listStyleSheets() +{ + std::vector vecStylesheets; + for (const auto& it : mapStyleToTheme) { + vecStylesheets.push_back(it.first); + } + return vecStylesheets; +} + const std::vector listThemes() { std::vector vecThemes; @@ -987,43 +1018,38 @@ QString loadStyleSheet() { static std::unique_ptr stylesheet; - if (stylesheet.get() == nullptr) { - + if (stylesheet == nullptr) { stylesheet = std::make_unique(); QSettings settings; - QDir themes(":themes"); + QDir themes(":css"); QString theme = settings.value("theme", "").toString(); // Make sure settings are pointing to an existent theme - if (theme.isEmpty() || !themes.exists(theme)) { + if (!isStyleSheetDirectoryCustom() && (theme.isEmpty() || !themes.exists(theme))) { theme = defaultTheme; settings.setValue("theme", theme); } - // If light/dark theme is used load general styles first - if (dashThemeActive()) { - QFile qFileGeneral(":css/general"); - if (qFileGeneral.open(QFile::ReadOnly)) { - stylesheet.get()->append(QLatin1String(qFileGeneral.readAll())); + auto loadFile = [&](const QString& name) { + QFile qFile(stylesheetDirectory + "/" + name + (isStyleSheetDirectoryCustom() ? ".css" : "")); + if (qFile.open(QFile::ReadOnly)) { + stylesheet->append(QLatin1String(qFile.readAll())); } + }; + // If light/dark theme is used load general styles first + if (dashThemeActive()) { + loadFile("general"); #ifndef Q_OS_MAC - // Apply some styling to scrollbars - QFile qFileScrollbars(QString(":/css/scrollbars")); - if (qFileScrollbars.open(QFile::ReadOnly)) { - stylesheet.get()->append(QLatin1String(qFileScrollbars.readAll())); - } + loadFile("scrollbars"); #endif } - QFile qFileTheme(":css/" + theme); - if (qFileTheme.open(QFile::ReadOnly)) { - stylesheet.get()->append(QLatin1String(qFileTheme.readAll())); - } + loadFile(theme); } - return *stylesheet.get(); + return *stylesheet; } FontFamily fontFamilyFromString(const QString& strFamily) diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 727d026e0922..ce6e55f4fe50 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -230,6 +230,16 @@ namespace GUIUtil /** Modify Qt network specific settings on migration */ void migrateQtSettings(); + /** Change the stylesheet directory. This is used by + the parameter -custom-css-dir.*/ + void setStyleSheetDirectory(const QString& path); + + /** Check if a custom css directory has been set with -custom-css-dir */ + bool isStyleSheetDirectoryCustom(); + + /** Return a list of all required css files */ + const std::vector listStyleSheets(); + /** Return a list of all theme css files */ const std::vector listThemes(); diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index 54b27280c56f..5a6bbe5e7f24 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -88,6 +88,7 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, HelpMode helpMode) : strUsage += HelpMessageOpt("-allowselfsignedrootcertificates", strprintf("Allow self signed root certificates (default: %u)", DEFAULT_SELFSIGNED_ROOTCERTS)); } strUsage += HelpMessageOpt("-choosedatadir", strprintf(tr("Choose data directory on startup (default: %u)").toStdString(), DEFAULT_CHOOSE_DATADIR)); + strUsage += HelpMessageOpt("-custom-css-dir", "Set a directory which contains custom css files. Those will be used as stylesheets for the UI."); strUsage += HelpMessageOpt("-font-family", tr("Set the font family. Possible values: %1. (default: %2)").arg("SystemDefault, Montserrat").arg(GUIUtil::fontFamilyToString(GUIUtil::getFontFamilyDefault())).toStdString()); strUsage += HelpMessageOpt("-font-scale", tr("Set a scale factor which gets applied to the base font size. Possible range %1 (smallest fonts) to %2 (largest fonts). (default: %3)").arg(-100).arg(100).arg(GUIUtil::getFontScaleDefault()).toStdString()); strUsage += HelpMessageOpt("-font-weight-bold", tr("Set the font weight for bold texts. Possible range %1 to %2 (default: %3)").arg(0).arg(8).arg(GUIUtil::weightToArg(GUIUtil::getFontWeightBoldDefault())).toStdString());