From 3a1d168a331b86e18fd69421e4bde7944fe7bc7c Mon Sep 17 00:00:00 2001 From: dustinface <35775977+xdustinface@users.noreply.github.com> Date: Thu, 6 May 2021 19:15:47 +0200 Subject: [PATCH] qt: Fix some font weight related issues (#4131) * qt: Add missing -font-family overridden check * qt: Add missing `QFont::ExtraBold` * qt: Remove settings depencency from GUIUtil::loadFonts and load earlier * qt: Modify supportedWeightToIndex Return -1 in case of failure * qt: Add GUIUtil::isSupportedWeight * qt: Make sure there are always supported weights in the settings * qt: Add "supported defaults" + store weights based on font family * qt: Use supported defaults in update weight sliders * qt: Use supported defaults when updating weight sliders * qt: Fix tests --- src/qt/appearancewidget.cpp | 18 ++--- src/qt/appearancewidget.h | 2 +- src/qt/dash.cpp | 4 +- src/qt/guiutil.cpp | 137 +++++++++++++++++++++++------------- src/qt/guiutil.h | 8 +++ src/qt/optionsmodel.cpp | 52 ++++++++++++-- src/qt/test/wallettests.cpp | 1 - 7 files changed, 156 insertions(+), 66 deletions(-) diff --git a/src/qt/appearancewidget.cpp b/src/qt/appearancewidget.cpp index c08a05e2b2..93f49e033d 100644 --- a/src/qt/appearancewidget.cpp +++ b/src/qt/appearancewidget.cpp @@ -47,7 +47,7 @@ AppearanceWidget::AppearanceWidget(QWidget* parent) : mapper->setOrientation(Qt::Vertical); connect(ui->theme, SIGNAL(currentTextChanged(const QString&)), this, SLOT(updateTheme(const QString&))); - connect(ui->fontFamily, SIGNAL(activated(int)), this, SLOT(updateFontFamily(int))); + connect(ui->fontFamily, SIGNAL(currentIndexChanged(int)), this, SLOT(updateFontFamily(int))); connect(ui->fontScaleSlider, SIGNAL(valueChanged(int)), this, SLOT(updateFontScale(int))); connect(ui->fontWeightNormalSlider, SIGNAL(valueChanged(int)), this, SLOT(updateFontWeightNormal(int))); connect(ui->fontWeightBoldSlider, SIGNAL(valueChanged(int)), this, SLOT(updateFontWeightBold(int))); @@ -118,7 +118,7 @@ void AppearanceWidget::updateTheme(const QString& theme) void AppearanceWidget::updateFontFamily(int index) { GUIUtil::setFontFamily(static_cast(ui->fontFamily->itemData(index).toInt())); - updateWeightSlider(); + updateWeightSlider(true); } void AppearanceWidget::updateFontScale(int nScale) @@ -148,7 +148,7 @@ void AppearanceWidget::updateFontWeightBold(int nValue, bool fForce) GUIUtil::setFontWeightBold(GUIUtil::supportedWeightFromIndex(ui->fontWeightBoldSlider->value())); } -void AppearanceWidget::updateWeightSlider() +void AppearanceWidget::updateWeightSlider(const bool fForce) { int nMaximum = GUIUtil::getSupportedWeights().size() - 1; @@ -158,11 +158,11 @@ void AppearanceWidget::updateWeightSlider() ui->fontWeightBoldSlider->setMinimum(0); ui->fontWeightBoldSlider->setMaximum(nMaximum); - if (nMaximum < 4) { - updateFontWeightNormal(0, true); - updateFontWeightBold(nMaximum, true); - } else { - updateFontWeightNormal(1, true); - updateFontWeightBold(4, true); + if (fForce || !GUIUtil::isSupportedWeight(prevWeightNormal) || !GUIUtil::isSupportedWeight(prevWeightBold)) { + int nIndexNormal = GUIUtil::supportedWeightToIndex(GUIUtil::getSupportedFontWeightNormalDefault()); + int nIndexBold = GUIUtil::supportedWeightToIndex(GUIUtil::getSupportedFontWeightBoldDefault()); + assert(nIndexNormal != -1 && nIndexBold != -1); + updateFontWeightNormal(nIndexNormal, true); + updateFontWeightBold(nIndexBold, true); } } diff --git a/src/qt/appearancewidget.h b/src/qt/appearancewidget.h index a1d2d895df..632750d472 100644 --- a/src/qt/appearancewidget.h +++ b/src/qt/appearancewidget.h @@ -53,7 +53,7 @@ private: QFont::Weight prevWeightNormal; QFont::Weight prevWeightBold; - void updateWeightSlider(); + void updateWeightSlider(bool fForce = false); }; #endif // BITCOIN_QT_APPEARANCEWIDGET_H diff --git a/src/qt/dash.cpp b/src/qt/dash.cpp index 92b2dee985..cf636b836a 100644 --- a/src/qt/dash.cpp +++ b/src/qt/dash.cpp @@ -714,14 +714,14 @@ int main(int argc, char *argv[]) qInstallMessageHandler(DebugMessageHandler); // Allow parameter interaction before we create the options model app.parameterSetup(); - // Load GUI settings from QSettings - app.createOptionsModel(gArgs.GetBoolArg("-resetguisettings", false)); // Load custom application fonts and setup font management if (!GUIUtil::loadFonts()) { QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), QObject::tr("Error: Failed to load application fonts.")); return EXIT_FAILURE; } + // Load GUI settings from QSettings + app.createOptionsModel(gArgs.GetBoolArg("-resetguisettings", false)); // Validate/set font family if (gArgs.IsArgSet("-font-family")) { GUIUtil::FontFamily family; diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index df1a8280d4..40c0110091 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -126,11 +126,9 @@ static const int defaultFontScale = 0; static FontFamily fontFamily = defaultFontFamily; // Application font scale value. May be overwritten by -font-scale. static int fontScale = defaultFontScale; -// Application font weight for normal text. May be overwritten by -font-weight-normal. -static QFont::Weight fontWeightNormal = defaultFontWeightNormal; -// Application font weight for bold text. May be overwritten by -font-weight-bold. -static QFont::Weight fontWeightBold = defaultFontWeightBold; - +// Contains the weight settings separated for all available fonts +static std::map> mapDefaultWeights; +static std::map> mapWeights; // Contains all widgets and its font attributes (weight, italic, size) with font changes due to GUIUtil::setFont static std::map, std::tuple> mapFontUpdates; // Contains a list of supported font weights for all members of GUIUtil::FontFamily @@ -290,23 +288,6 @@ void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent, bool fAllow void setupAppearance(QWidget* parent, OptionsModel* model) { if (!QSettings().value("fAppearanceSetupDone", false).toBool()) { - std::vector vecWeights = getSupportedWeights(); - // See if the default value for normal weight is available - if (std::find(vecWeights.begin(), vecWeights.end(), defaultFontWeightNormal) == vecWeights.end()) { - // If not, use the lightest available weight as normal weight - fontWeightNormal = vecWeights.front(); - } - - // See if the default value for bold weight is available - if (std::find(vecWeights.begin(), vecWeights.end(), defaultFontWeightBold) == vecWeights.end()) { - // If not, use the second lightest available weight as bold weight default or also the lightest if there is only one - int nBoldOffset = vecWeights.size() > 1 ? 1 : 0; - fontWeightBold = vecWeights[nBoldOffset]; - } - - QSettings().setValue("fontWeightNormal", weightToArg(fontWeightNormal)); - QSettings().setValue("fontWeightBold", weightToArg(fontWeightBold)); - // Create the dialog QDialog dlg(parent); dlg.setObjectName("AppearanceSetup"); @@ -1260,12 +1241,18 @@ QFont::Weight toQFontWeight(FontWeight weight) QFont::Weight getFontWeightNormal() { - return fontWeightNormal; + if (!mapWeights.count(fontFamily)) { + return defaultFontWeightNormal; + } + return mapWeights[fontFamily].first; } void setFontWeightNormal(QFont::Weight weight) { - fontWeightNormal = weight; + if (!mapWeights.count(fontFamily)) { + throw std::runtime_error(strprintf("%s: Font family not loaded: %s", __func__, fontFamilyToString(fontFamily).toStdString())); + } + mapWeights[fontFamily].first = weight; updateFonts(); } @@ -1276,12 +1263,18 @@ QFont::Weight getFontWeightBoldDefault() QFont::Weight getFontWeightBold() { - return fontWeightBold; + if (!mapWeights.count(fontFamily)) { + return defaultFontWeightBold; + } + return mapWeights[fontFamily].second; } void setFontWeightBold(QFont::Weight weight) { - fontWeightBold = weight; + if (!mapWeights.count(fontFamily)) { + throw std::runtime_error(strprintf("%s: Font family not loaded: %s", __func__, fontFamilyToString(fontFamily).toStdString())); + } + mapWeights[fontFamily].second = weight; updateFonts(); } @@ -1367,26 +1360,6 @@ bool loadFonts() } } - // Load font related settings - QSettings settings; - QFont::Weight weight; - - if (!gArgs.IsArgSet("-font-family")) { - fontFamily = fontFamilyFromString(settings.value("fontFamily").toString()); - } - - if (!gArgs.IsArgSet("-font-scale")) { - fontScale = settings.value("fontScale").toInt(); - } - - if (!gArgs.IsArgSet("-font-weight-normal") && weightFromArg(settings.value("fontWeightNormal").toInt(), weight)) { - fontWeightNormal = weight; - } - - if (!gArgs.IsArgSet("-font-weight-bold") && weightFromArg(settings.value("fontWeightBold").toInt(), weight)) { - fontWeightBold = weight; - } - setApplicationFont(); // Initialize supported font weights for all available fonts @@ -1398,7 +1371,7 @@ bool loadFonts() }; std::vector vecWeights{QFont::Thin, QFont::ExtraLight, QFont::Light, QFont::Normal, QFont::Medium, QFont::DemiBold, - QFont::Bold, QFont::Black}; + QFont::Bold, QFont::ExtraBold, QFont::Black}; std::vector vecSupported; QFont::Weight prevWeight = vecWeights.front(); for (auto weight = vecWeights.begin() + 1; weight != vecWeights.end(); ++weight) { @@ -1416,11 +1389,55 @@ bool loadFonts() mapSupportedWeights.insert(std::make_pair(FontFamily::SystemDefault, supportedWeights(FontFamily::SystemDefault))); mapSupportedWeights.insert(std::make_pair(FontFamily::Montserrat, supportedWeights(FontFamily::Montserrat))); + auto getBestMatch = [&](FontFamily fontFamily, QFont::Weight targetWeight) { + auto& vecSupported = mapSupportedWeights[fontFamily]; + auto it = vecSupported.begin(); + QFont::Weight bestWeight = *it; + int nBestDiff = abs(*it - targetWeight); + while (++it != vecSupported.end()) { + int nDiff = abs(*it - targetWeight); + if (nDiff < nBestDiff) { + bestWeight = *it; + nBestDiff = nDiff; + } + } + return bestWeight; + }; + + auto addBestDefaults = [&](FontFamily family) -> auto { + QFont::Weight normalWeight = getBestMatch(family, defaultFontWeightNormal); + QFont::Weight boldWeight = getBestMatch(family, defaultFontWeightBold); + if (normalWeight == boldWeight) { + // If the results are the same use the next possible weight for bold font + auto& vecSupported = mapSupportedWeights[fontFamily]; + auto it = std::find(vecSupported.begin(), vecSupported.end(),normalWeight); + if (++it != vecSupported.end()) { + boldWeight = *it; + } + } + mapDefaultWeights.emplace(family, std::make_pair(normalWeight, boldWeight)); + }; + + addBestDefaults(FontFamily::SystemDefault); + addBestDefaults(FontFamily::Montserrat); + + // Load supported defaults. May become overwritten later. + mapWeights = mapDefaultWeights; + return true; } +bool fontsLoaded() +{ + return osDefaultFont != nullptr; +} + void setApplicationFont() { + if (!fontsLoaded()) { + return; + } + std::unique_ptr font; if (fontFamily == FontFamily::Montserrat) { @@ -1569,6 +1586,9 @@ void updateFonts() QFont getFont(FontFamily family, QFont::Weight qWeight, bool fItalic, int nPointSize) { QFont font; + if (!fontsLoaded()) { + return font; + } if (family == FontFamily::Montserrat) { static std::map mapMontserratMapping{ @@ -1645,6 +1665,22 @@ QFont getFontBold() return getFont(FontWeight::Bold); } +QFont::Weight getSupportedFontWeightNormalDefault() +{ + if (!mapDefaultWeights.count(fontFamily)) { + throw std::runtime_error(strprintf("%s: Font family not loaded: %s", __func__, fontFamilyToString(fontFamily).toStdString())); + } + return mapDefaultWeights[fontFamily].first; +} + +QFont::Weight getSupportedFontWeightBoldDefault() +{ + if (!mapDefaultWeights.count(fontFamily)) { + throw std::runtime_error(strprintf("%s: Font family not loaded: %s", __func__, fontFamilyToString(fontFamily).toStdString())); + } + return mapDefaultWeights[fontFamily].second; +} + std::vector getSupportedWeights() { assert(mapSupportedWeights.count(fontFamily)); @@ -1666,7 +1702,12 @@ int supportedWeightToIndex(QFont::Weight weight) return index; } } - assert(false); + return -1; +} + +bool isSupportedWeight(const QFont::Weight weight) +{ + return supportedWeightToIndex(weight) != -1; } QString getActiveTheme() diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 7447be338a..01970100b8 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -321,6 +321,8 @@ namespace GUIUtil /** Load dash specific appliciation fonts */ bool loadFonts(); + /** Check if the fonts have been loaded successfully */ + bool fontsLoaded(); /** Set an application wide default font, depends on the selected theme */ void setApplicationFont(); @@ -345,12 +347,18 @@ namespace GUIUtil /** Get the default bold QFont */ QFont getFontBold(); + /** Return supported normal default for the current font family */ + QFont::Weight getSupportedFontWeightNormalDefault(); + /** Return supported bold default for the current font family */ + QFont::Weight getSupportedFontWeightBoldDefault(); /** Return supported weights for the current font family */ std::vector getSupportedWeights(); /** Convert an index to a weight in the supported weights vector */ QFont::Weight supportedWeightFromIndex(int nIndex); /** Convert a weight to an index in the supported weights vector */ int supportedWeightToIndex(QFont::Weight weight); + /** Check if a weight is supported by the current font family */ + bool isSupportedWeight(QFont::Weight weight); /** Return the name of the currently active theme.*/ QString getActiveTheme(); diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 9196760e37..143ac52de1 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -85,21 +85,59 @@ void OptionsModel::Init(bool resetSettings) if (!settings.contains("fontFamily")) settings.setValue("fontFamily", GUIUtil::fontFamilyToString(GUIUtil::getFontFamilyDefault())); + if (m_node.softSetArg("-font-family", settings.value("fontFamily").toString().toStdString())) { + if (GUIUtil::fontsLoaded()) { + GUIUtil::setFontFamily(GUIUtil::fontFamilyFromString(settings.value("fontFamily").toString())); + } + } else { + addOverriddenOption("-font-family"); + } if (!settings.contains("fontScale")) settings.setValue("fontScale", GUIUtil::getFontScaleDefault()); - if (!m_node.softSetArg("-font-scale", settings.value("fontScale").toString().toStdString())) + if (m_node.softSetArg("-font-scale", settings.value("fontScale").toString().toStdString())) { + if (GUIUtil::fontsLoaded()) { + GUIUtil::setFontScale(settings.value("fontScale").toInt()); + } + } else { addOverriddenOption("-font-scale"); + } if (!settings.contains("fontWeightNormal")) settings.setValue("fontWeightNormal", GUIUtil::weightToArg(GUIUtil::getFontWeightNormalDefault())); - if (!m_node.softSetArg("-font-weight-normal", settings.value("fontWeightNormal").toString().toStdString())) + if (m_node.softSetArg("-font-weight-normal", settings.value("fontWeightNormal").toString().toStdString())) { + if (GUIUtil::fontsLoaded()) { + QFont::Weight weight; + GUIUtil::weightFromArg(settings.value("fontWeightNormal").toInt(), weight); + if (!GUIUtil::isSupportedWeight(weight)) { + // If the currently selected weight is not supported fallback to the lightest weight for normal font. + weight = GUIUtil::getSupportedWeights().front(); + settings.setValue("fontWeightNormal", GUIUtil::weightToArg(weight)); + } + GUIUtil::setFontWeightNormal(weight); + } + } else { addOverriddenOption("-font-weight-normal"); + } if (!settings.contains("fontWeightBold")) settings.setValue("fontWeightBold", GUIUtil::weightToArg(GUIUtil::getFontWeightBoldDefault())); - if (!m_node.softSetArg("-font-weight-bold", settings.value("fontWeightBold").toString().toStdString())) + if (m_node.softSetArg("-font-weight-bold", settings.value("fontWeightBold").toString().toStdString())) { + if (GUIUtil::fontsLoaded()) { + QFont::Weight weight; + GUIUtil::weightFromArg(settings.value("fontWeightBold").toInt(), weight); + if (!GUIUtil::isSupportedWeight(weight)) { + // If the currently selected weight is not supported fallback to the second lightest weight for bold font + // or the lightest if there is only one. + auto vecSupported = GUIUtil::getSupportedWeights(); + weight = vecSupported[vecSupported.size() > 1 ? 1 : 0]; + settings.setValue("fontWeightBold", GUIUtil::weightToArg(weight)); + } + GUIUtil::setFontWeightBold(weight); + } + } else { addOverriddenOption("-font-weight-bold"); + } #ifdef ENABLE_WALLET if (!settings.contains("fCoinControlFeatures")) @@ -388,12 +426,16 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const case FontWeightNormal: { QFont::Weight weight; GUIUtil::weightFromArg(settings.value("fontWeightNormal").toInt(), weight); - return GUIUtil::supportedWeightToIndex(weight); + int nIndex = GUIUtil::supportedWeightToIndex(weight); + assert(nIndex != -1); + return nIndex; } case FontWeightBold: { QFont::Weight weight; GUIUtil::weightFromArg(settings.value("fontWeightBold").toInt(), weight); - return GUIUtil::supportedWeightToIndex(weight); + int nIndex = GUIUtil::supportedWeightToIndex(weight); + assert(nIndex != -1); + return nIndex; } case Language: return settings.value("language"); diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index 314fb67c4f..6c624e935b 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -113,7 +113,6 @@ QModelIndex FindTx(const QAbstractItemModel& model, const uint256& txid) // src/qt/test/test_dash-qt -platform cocoa # macOS void TestGUI() { - GUIUtil::loadFonts(); // Set up wallet and chain with 105 blocks (5 mature blocks for spending). TestChain100Setup test; for (int i = 0; i < 5; ++i) {