From ffa047754d143d0dde872a6978150784bf89de93 Mon Sep 17 00:00:00 2001 From: RadRussianRus Date: Thu, 15 Sep 2022 23:17:03 +0300 Subject: [PATCH] [Option][GUI] Font options --- ui/integration.cpp | 5 ++ ui/integration.h | 6 ++ ui/painter.h | 11 ++- ui/style/style_core_custom_font.cpp | 36 ++++++--- ui/style/style_core_custom_font.h | 10 +++ ui/style/style_core_font.cpp | 120 ++++++++++++++++++++-------- ui/style/style_core_font.h | 1 + ui/widgets/input_fields.cpp | 21 +++++ 8 files changed, 163 insertions(+), 47 deletions(-) diff --git a/ui/integration.cpp b/ui/integration.cpp index 495e17a..3566ef6 100644 --- a/ui/integration.cpp +++ b/ui/integration.cpp @@ -6,6 +6,7 @@ // #include "ui/integration.h" +#include "ui/style/style_core_custom_font.h" #include "ui/gl/gl_detection.h" #include "ui/text/text_entity.h" #include "ui/text/text_block.h" @@ -43,6 +44,10 @@ void Integration::textActionsUpdated() { void Integration::activationFromTopPanel() { } +style::CustomFontSettings Integration::fontSettings() { + return {}; +} + bool Integration::screenIsLocked() { return false; } diff --git a/ui/integration.h b/ui/integration.h index 09b4da0..e1172ce 100644 --- a/ui/integration.h +++ b/ui/integration.h @@ -22,6 +22,10 @@ struct TextParseOptions; class ClickHandler; struct EntityLinkData; +namespace style { +struct CustomFontSettings; +} // namespace style + namespace Ui { namespace Emoji { class One; @@ -48,6 +52,8 @@ public: virtual void textActionsUpdated(); virtual void activationFromTopPanel(); + virtual style::CustomFontSettings fontSettings(); + [[nodiscard]] virtual bool screenIsLocked(); [[nodiscard]] virtual std::shared_ptr createLinkHandler( diff --git a/ui/painter.h b/ui/painter.h index 4d15b82..53cd5a1 100644 --- a/ui/painter.h +++ b/ui/painter.h @@ -22,13 +22,15 @@ public: void drawTextLeft(int x, int y, int outerw, const QString &text, int textWidth = -1) { QFontMetrics m(fontMetrics()); + auto ascent = (_ascent == 0 ? m.ascent() : _ascent); if (style::RightToLeft() && textWidth < 0) textWidth = m.horizontalAdvance(text); - drawText(style::RightToLeft() ? (outerw - x - textWidth) : x, y + m.ascent(), text); + drawText(style::RightToLeft() ? (outerw - x - textWidth) : x, y + ascent, text); } void drawTextRight(int x, int y, int outerw, const QString &text, int textWidth = -1) { QFontMetrics m(fontMetrics()); + auto ascent = (_ascent == 0 ? m.ascent() : _ascent); if (!style::RightToLeft() && textWidth < 0) textWidth = m.horizontalAdvance(text); - drawText(style::RightToLeft() ? x : (outerw - x - textWidth), y + m.ascent(), text); + drawText(style::RightToLeft() ? x : (outerw - x - textWidth), y + ascent, text); } void drawPixmapLeft(int x, int y, int outerw, const QPixmap &pix, const QRect &from) { drawPixmap(QPoint(style::RightToLeft() ? (outerw - x - (from.width() / pix.devicePixelRatio())) : x, y), pix, from); @@ -82,6 +84,10 @@ public: [[nodiscard]] bool inactive() const { return _inactive; } + void setFont(const style::font &font) { + _ascent = font->ascent; + QPainter::setFont(font->f); + } void setTextSpoilerMess(not_null mess) { _spoilerMess = mess; } @@ -96,6 +102,7 @@ private: const style::TextPalette *_textPalette = nullptr; Ui::Text::SpoilerMess *_spoilerMess = nullptr; bool _inactive = false; + int _ascent = 0; }; diff --git a/ui/style/style_core_custom_font.cpp b/ui/style/style_core_custom_font.cpp index 8f42baf..3ed437f 100644 --- a/ui/style/style_core_custom_font.cpp +++ b/ui/style/style_core_custom_font.cpp @@ -7,6 +7,8 @@ #include "ui/style/style_core_custom_font.h" #include "ui/style/style_core_font.h" +#include "ui/style/style_core_scale.h" +#include "ui/integration.h" #include #include @@ -29,6 +31,9 @@ void SetCustomFonts(const CustomFont ®ular, const CustomFont &bold) { QFont ResolveFont(const QString &familyOverride, uint32 flags, int size) { static auto Database = QFontDatabase(); + const auto fontSettings = Ui::Integration::Instance().fontSettings(); + const auto overrideIsEmpty = GetPossibleEmptyOverride(flags).isEmpty(); + const auto bold = ((flags & FontBold) || (flags & FontSemibold)); const auto italic = (flags & FontItalic); const auto &custom = bold ? BoldFont : RegularFont; @@ -50,18 +55,29 @@ QFont ResolveFont(const QString &familyOverride, uint32 flags, int size) { const auto point = good.isEmpty() ? size : good.front(); result = Database.font(custom.family, custom.style, point); } else { - result.setFamily(GetFontOverride(flags)); + if (!fontSettings.useSystemFont || !overrideIsEmpty) { + result.setFamily(GetFontOverride(flags)); + } if (bold) { + if (fontSettings.semiboldIsBold) { + result.setBold(true); #ifdef DESKTOP_APP_USE_PACKAGED_FONTS - result.setWeight(QFont::DemiBold); -#else // DESKTOP_APP_USE_PACKAGED_FONTS - result.setBold(true); -#endif // !DESKTOP_APP_USE_PACKAGED_FONTS - - if (flags & FontItalic) { - result.setStyleName("Semibold Italic"); } else { - result.setStyleName("Semibold"); + result.setWeight(QFont::DemiBold); +#else // DESKTOP_APP_USE_PACKAGED_FONTS + } else if (fontSettings.useSystemFont) { + result.setWeight(QFont::DemiBold); + } else { + result.setBold(true); +#endif // !DESKTOP_APP_USE_PACKAGED_FONTS + } + + if (!fontSettings.semiboldIsBold) { + if (flags & FontItalic) { + result.setStyleName("Semibold Italic"); + } else { + result.setStyleName("Semibold"); + } } } } @@ -71,7 +87,7 @@ QFont ResolveFont(const QString &familyOverride, uint32 flags, int size) { result.setUnderline(flags & FontUnderline); result.setStrikeOut(flags & FontStrikeOut); - result.setPixelSize(size); + result.setPixelSize(size + ConvertScale(fontSettings.fontSize)); return result; } diff --git a/ui/style/style_core_custom_font.h b/ui/style/style_core_custom_font.h index 25999ae..289168b 100644 --- a/ui/style/style_core_custom_font.h +++ b/ui/style/style_core_custom_font.h @@ -13,6 +13,16 @@ struct CustomFont { QString style; }; +struct CustomFontSettings { + QString mainFont; + QString semiboldFont; + QString monospaceFont; + int fontSize = 0; + bool semiboldIsBold = false; + bool useSystemFont = false; + bool useOriginalMetrics = false; +}; + inline bool operator==(const CustomFont &a, const CustomFont &b) { return (a.family == b.family) && (a.style == b.style); } diff --git a/ui/style/style_core_font.cpp b/ui/style/style_core_font.cpp index 4ca722c..7237e18 100644 --- a/ui/style/style_core_font.cpp +++ b/ui/style/style_core_font.cpp @@ -96,6 +96,11 @@ bool LoadCustomFont(const QString &filePath, const QString &familyName, int flag return QFontDatabase::systemFont(type).family(); } +bool TryFont(const QString &attempt) { + const auto resolved = QFontInfo(QFont(attempt)).family(); + return !resolved.trimmed().compare(attempt, Qt::CaseInsensitive); +} + [[nodiscard]] QString ManualMonospaceFont() { const auto kTryFirst = std::initializer_list{ "Cascadia Mono", @@ -105,14 +110,23 @@ bool LoadCustomFont(const QString &filePath, const QString &familyName, int flag "Courier" }; for (const auto &family : kTryFirst) { - const auto resolved = QFontInfo(QFont(family)).family(); - if (!resolved.trimmed().compare(family, Qt::CaseInsensitive)) { + if (TryFont(family)) { return family; } } return QString(); } +QFontMetrics GetFontMetrics(int size) { +#ifdef DESKTOP_APP_USE_PACKAGED_FONTS + QFont originalFont("Open Sans"); +#else // !DESKTOP_APP_USE_PACKAGED_FONTS + QFont originalFont("DAOpenSansRegular"); +#endif // !DESKTOP_APP_USE_PACKAGED_FONTS + originalFont.setPixelSize(size); + return QFontMetrics(originalFont); +} + enum { FontTypeRegular = 0, FontTypeRegularItalic, @@ -179,52 +193,72 @@ void StartFonts() { style_InitFontsResource(); + const auto fontSettings = Ui::Integration::Instance().fontSettings(); + #ifndef DESKTOP_APP_USE_PACKAGED_FONTS - [[maybe_unused]] bool areGood[FontTypesCount] = { false }; - for (auto i = 0; i != FontTypesCount; ++i) { - const auto file = FontTypeFiles[i]; - const auto name = FontTypeNames[i]; - const auto flags = FontTypeFlags[i]; - areGood[i] = LoadCustomFont(":/gui/fonts/" + file + ".ttf", name, flags); - Overrides[i] = name; + if (!fontSettings.useSystemFont) { + [[maybe_unused]] bool areGood[FontTypesCount] = { false }; + for (auto i = 0; i != FontTypesCount; ++i) { + const auto file = FontTypeFiles[i]; + const auto name = FontTypeNames[i]; + const auto flags = FontTypeFlags[i]; + areGood[i] = LoadCustomFont(":/gui/fonts/" + file + ".ttf", name, flags); + Overrides[i] = name; const auto persianFallbackFile = FontTypePersianFallbackFiles[i]; const auto persianFallback = FontTypePersianFallback[i]; LoadCustomFont(":/gui/fonts/" + persianFallbackFile + ".ttf", persianFallback, flags); #ifdef Q_OS_WIN - // Attempt to workaround a strange font bug with Open Sans Semibold not loading. - // See https://github.com/telegramdesktop/tdesktop/issues/3276 for details. - // Crash happens on "options.maxh / _t->_st->font->height" with "division by zero". - // In that place "_t->_st->font" is "semiboldFont" is "font(13 "Open Sans Semibold"). - const auto fallback = "Segoe UI"; - if (!areGood[i]) { - if (ValidateFont(fallback, flags)) { - Overrides[i] = fallback; - LOG(("Fonts Info: Using '%1' instead of '%2'.").arg(fallback).arg(name)); + // Attempt to workaround a strange font bug with Open Sans Semibold not loading. + // See https://github.com/telegramdesktop/tdesktop/issues/3276 for details. + // Crash happens on "options.maxh / _t->_st->font->height" with "division by zero". + // In that place "_t->_st->font" is "semiboldFont" is "font(13 "Open Sans Semibold"). + const auto fallback = "Segoe UI"; + if (!areGood[i]) { + if (ValidateFont(fallback, flags)) { + Overrides[i] = fallback; + LOG(("Fonts Info: Using '%1' instead of '%2'.").arg(fallback).arg(name)); + } } - } - // Disable default fallbacks to Segoe UI, see: - // https://github.com/telegramdesktop/tdesktop/issues/5368 - // - //QFont::insertSubstitution(name, fallback); + // Disable default fallbacks to Segoe UI, see: + // https://github.com/telegramdesktop/tdesktop/issues/5368 + // + //QFont::insertSubstitution(name, fallback); #endif // Q_OS_WIN QFont::insertSubstitution(name, persianFallback); } #ifdef Q_OS_MAC - auto list = QStringList(); - list.append("STIXGeneral"); - list.append(".SF NS Text"); - list.append("Helvetica Neue"); - list.append("Lucida Grande"); - for (const auto &name : FontTypeNames) { - QFont::insertSubstitutions(name, list); - } + auto list = QStringList(); + list.append("STIXGeneral"); + list.append(".SF NS Text"); + list.append("Helvetica Neue"); + list.append("Lucida Grande"); + for (const auto &name : FontTypeNames) { + QFont::insertSubstitutions(name, list); + } #endif // Q_OS_MAC + } #endif // !DESKTOP_APP_USE_PACKAGED_FONTS + if (!fontSettings.mainFont.isEmpty() && ValidateFont(fontSettings.mainFont)) { + Overrides[FontTypeRegular] = fontSettings.mainFont; + Overrides[FontTypeRegularItalic] = fontSettings.mainFont; + } + if (!fontSettings.semiboldFont.isEmpty() && ValidateFont(fontSettings.semiboldFont)) { + Overrides[FontTypeBold] = fontSettings.semiboldFont; + Overrides[FontTypeBoldItalic] = fontSettings.semiboldFont; + Overrides[FontTypeSemibold] = fontSettings.semiboldFont; + Overrides[FontTypeSemiboldItalic] = fontSettings.semiboldFont; + } else if (!fontSettings.mainFont.isEmpty() && ValidateFont(fontSettings.mainFont)) { + Overrides[FontTypeBold] = fontSettings.mainFont; + Overrides[FontTypeBoldItalic] = fontSettings.mainFont; + Overrides[FontTypeSemibold] = fontSettings.mainFont; + Overrides[FontTypeSemiboldItalic] = fontSettings.mainFont; + } + auto appFont = QApplication::font(); appFont.setStyleStrategy(QFont::PreferQuality); QApplication::setFont(appFont); @@ -257,6 +291,12 @@ QString GetFontOverride(int32 flags) { QString MonospaceFont() { static const auto family = [&]() -> QString { + const auto fontSettings = Ui::Integration::Instance().fontSettings(); + + if (TryFont(fontSettings.monospaceFont)) { + return fontSettings.monospaceFont; + } + const auto manual = ManualMonospaceFont(); const auto system = SystemMonospaceFont(); @@ -269,7 +309,7 @@ QString MonospaceFont() { const auto useSystem = manual.isEmpty() || (metrics.horizontalAdvance(QChar('i')) == metrics.horizontalAdvance(QChar('W'))); #endif // Q_OS_WIN - return useSystem ? system : manual; + return (useSystem || fontSettings.useSystemFont) ? system : manual; }(); return family; @@ -303,9 +343,19 @@ FontData::FontData(int size, uint32 flags, int family, Font *other) } _modified[_flags] = Font(this); - height = int(base::SafeRound(_m.height())); - ascent = int(base::SafeRound(_m.ascent())); - descent = int(base::SafeRound(_m.descent())); + const auto fontSettings = Ui::Integration::Instance().fontSettings(); + if (fontSettings.useOriginalMetrics && !(_flags & FontMonospace)) { + const auto mOrig = GetFontMetrics(size); + + height = int(base::SafeRound(mOrig.height())); + ascent = int(base::SafeRound(mOrig.ascent())); + descent = int(base::SafeRound(mOrig.descent())); + } else { + height = int(base::SafeRound(_m.height())); + ascent = int(base::SafeRound(_m.ascent())); + descent = int(base::SafeRound(_m.descent())); + } + spacew = width(QLatin1Char(' ')); elidew = width("..."); } diff --git a/ui/style/style_core_font.h b/ui/style/style_core_font.h index 898fd75..f26c125 100644 --- a/ui/style/style_core_font.h +++ b/ui/style/style_core_font.h @@ -17,6 +17,7 @@ namespace style { namespace internal { void StartFonts(); +[[nodiscard]] QString GetPossibleEmptyOverride(int32 flags = 0); [[nodiscard]] QString GetFontOverride(int32 flags = 0); [[nodiscard]] QString MonospaceFont(); diff --git a/ui/widgets/input_fields.cpp b/ui/widgets/input_fields.cpp index ba59c44..f838103 100644 --- a/ui/widgets/input_fields.cpp +++ b/ui/widgets/input_fields.cpp @@ -11,6 +11,7 @@ #include "ui/emoji_config.h" #include "ui/ui_utility.h" #include "ui/painter.h" +#include "ui/style/style_core_custom_font.h" #include "base/invoke_queued.h" #include "base/random.h" #include "base/platform/base_platform_info.h" @@ -1233,6 +1234,14 @@ InputField::InputField( _inner->viewport()->setAutoFillBackground(false); _inner->setContentsMargins(0, 0, 0, 0); + const auto fontSettings = Integration::Instance().fontSettings(); + if (fontSettings.useOriginalMetrics) { + const auto metrics = QFontMetricsF(_st.font->f); + const auto heightDelta = (_st.font->height - metrics.height()); + const auto topMargin = (_st.font->ascent - metrics.ascent()) + + (heightDelta ? heightDelta / 2 : 0); + _inner->setViewportMargins(0, topMargin, 0, 0); + } _inner->document()->setDocumentMargin(0); setAttribute(Qt::WA_AcceptTouchEvents); @@ -1742,6 +1751,18 @@ void InputField::paintEvent(QPaintEvent *e) { auto r = rect().marginsRemoved(_st.textMargins + _st.placeholderMargins); r.moveLeft(r.left() + placeholderLeft); if (style::RightToLeft()) r.moveLeft(width() - r.left() - r.width()); + const auto fontSettings = Integration::Instance().fontSettings(); + if (fontSettings.useOriginalMetrics) { + const auto metrics = QFontMetricsF(_st.placeholderFont->f); + if (_mode == Mode::SingleLine) { + const auto heightDelta = (_st.placeholderFont->height - metrics.height()); + const auto topMargin = (_st.placeholderFont->ascent - metrics.ascent()) + + (heightDelta ? heightDelta / 2 : 0); + r.moveTop(r.top() + topMargin); + } else { + r.moveTop(r.top() + _st.placeholderFont->ascent - metrics.ascent()); + } + } p.drawText(r, _placeholder, _st.placeholderAlign); }