From bfdd116000813504a0db60176f700df85690c748 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 26 Apr 2023 22:11:33 +0400 Subject: [PATCH] Handle emoji myself in custom macOS title. --- ui/platform/mac/ui_window_mac.h | 2 + ui/platform/mac/ui_window_mac.mm | 4 ++ ui/platform/mac/ui_window_title_mac.h | 8 +++- ui/platform/mac/ui_window_title_mac.mm | 55 +++++++++++++++----------- ui/platform/ui_platform_window.cpp | 4 ++ ui/platform/ui_platform_window.h | 3 ++ ui/style/style_core_custom_font.cpp | 9 ++++- ui/style/style_core_custom_font.h | 2 +- ui/style/style_core_font.cpp | 2 +- ui/widgets/rp_window.cpp | 4 ++ ui/widgets/rp_window.h | 3 ++ ui/widgets/widgets.style | 6 +++ 12 files changed, 74 insertions(+), 28 deletions(-) diff --git a/ui/platform/mac/ui_window_mac.h b/ui/platform/mac/ui_window_mac.h index dd5b9bd..e3da674 100644 --- a/ui/platform/mac/ui_window_mac.h +++ b/ui/platform/mac/ui_window_mac.h @@ -28,6 +28,8 @@ public: void setGeometry(QRect rect) override; void close() override; + const style::TextStyle &titleTextStyle() const override; + private: class Private; friend class Private; diff --git a/ui/platform/mac/ui_window_mac.mm b/ui/platform/mac/ui_window_mac.mm index 38334c4..514ef32 100644 --- a/ui/platform/mac/ui_window_mac.mm +++ b/ui/platform/mac/ui_window_mac.mm @@ -422,6 +422,10 @@ void WindowHelper::close() { _private->close(); } +const style::TextStyle &WindowHelper::titleTextStyle() const { + return _title->textStyle(); +} + void WindowHelper::init() { updateCustomTitleVisibility(true); diff --git a/ui/platform/mac/ui_window_title_mac.h b/ui/platform/mac/ui_window_title_mac.h index 1dd161d..9b1b097 100644 --- a/ui/platform/mac/ui_window_title_mac.h +++ b/ui/platform/mac/ui_window_title_mac.h @@ -6,6 +6,7 @@ // #pragma once +#include "ui/text/text.h" #include "ui/rp_widget.h" #include "base/object_ptr.h" @@ -14,6 +15,7 @@ namespace style { struct WindowTitle; +struct TextStyle; } // namespace style namespace Ui { @@ -25,12 +27,14 @@ namespace Platform { class TitleWidget : public RpWidget { public: TitleWidget(not_null parent, int height); + ~TitleWidget(); void setText(const QString &text); void setStyle(const style::WindowTitle &st); void setControlsRect(const QRect &rect); [[nodiscard]] QString text() const; [[nodiscard]] bool shouldBeHidden() const; + [[nodiscard]] const style::TextStyle &textStyle() const; protected: void paintEvent(QPaintEvent *e) override; @@ -43,11 +47,11 @@ private: void init(int height); not_null _st; + std::unique_ptr _textStyle; object_ptr _shadow; QString _text; - int _textWidth = 0; + Ui::Text::String _string; int _controlsRight = 0; - QFont _font; }; diff --git a/ui/platform/mac/ui_window_title_mac.mm b/ui/platform/mac/ui_window_title_mac.mm index 76e9c88..0511e82 100644 --- a/ui/platform/mac/ui_window_title_mac.mm +++ b/ui/platform/mac/ui_window_title_mac.mm @@ -8,6 +8,7 @@ #include "ui/widgets/buttons.h" #include "ui/widgets/shadow.h" +#include "ui/painter.h" #include "ui/ui_utility.h" #include "base/debug_log.h" #include "styles/style_widgets.h" @@ -27,10 +28,12 @@ TitleWidget::TitleWidget(not_null parent, int height) init(height); } +TitleWidget::~TitleWidget() = default; + void TitleWidget::setText(const QString &text) { if (_text != text) { _text = text; - _textWidth = QFontMetrics(_font).horizontalAdvance(_text); + _string.setText(textStyle(), text); update(); } } @@ -48,6 +51,10 @@ bool TitleWidget::shouldBeHidden() const { return !_st->height; } +const style::TextStyle &TitleWidget::textStyle() const { + return *_textStyle; +} + QString TitleWidget::text() const { return _text; } @@ -64,51 +71,55 @@ void TitleWidget::init(int height) { setGeometry(0, 0, width, height); }, lifetime()); + const auto setFromFont = [&](const style::font &font) { + _textStyle = std::make_unique(style::TextStyle{ + .font = font, + .linkFont = font, + .linkFontOver = font, + }); + }; + const auto families = QStringList{ u".AppleSystemUIFont"_q, u".SF NS Text"_q, u"Helvetica Neue"_q, }; for (auto family : families) { - _font.setFamily(family); - if (QFontInfo(_font).family() == _font.family()) { + auto font = QFont(); + font.setFamily(family); + if (QFontInfo(font).family() == font.family()) { static const auto logged = [&] { LOG(("Title Font: %1").arg(family)); return true; }(); + const auto apple = (family == u".AppleSystemUIFont"_q); + setFromFont(style::font( + apple ? 13 : (height * 15) / 24, + apple ? style::internal::FontBold : 0, + family)); break; } } - - if (QFontInfo(_font).family() != _font.family()) { - _font = st::semiboldFont; - _font.setPixelSize(13); - } else if (_font.family() == u".AppleSystemUIFont"_q) { - _font.setBold(true); - _font.setPixelSize(13); - } else { - _font.setPixelSize((height * 15) / 24); + if (!_textStyle) { + setFromFont(style::font(13, style::internal::FontSemibold, 0)); } } void TitleWidget::paintEvent(QPaintEvent *e) { - QPainter p(this); + Painter p(this); const auto active = isActiveWindow(); p.fillRect(rect(), active ? _st->bgActive : _st->bg); - p.setFont(_font); p.setPen(active ? _st->fgActive : _st->fg); - if ((width() - _controlsRight * 2) < _textWidth) { - const auto elided = QFontMetrics(_font).elidedText( - _text, - Qt::ElideRight, - width() - _controlsRight); - const auto padding = QMargins(_controlsRight, 0, 0, 0); - p.drawText(rect() - padding, elided, style::al_left); + const auto top = (height() - _textStyle->font->height) / 2; + if ((width() - _controlsRight * 2) < _string.maxWidth()) { + const auto left = _controlsRight; + _string.drawElided(p, left, top, width() - left); } else { - p.drawText(rect(), _text, style::al_center); + const auto left = (width() - _string.maxWidth()) / 2; + _string.draw(p, left, top, width() - left); } } diff --git a/ui/platform/ui_platform_window.cpp b/ui/platform/ui_platform_window.cpp index f08b233..5cada35 100644 --- a/ui/platform/ui_platform_window.cpp +++ b/ui/platform/ui_platform_window.cpp @@ -205,6 +205,10 @@ void BasicWindowHelper::setBodyTitleArea( _bodyTitleAreaTestMethod = std::move(testMethod); } +const style::TextStyle &BasicWindowHelper::titleTextStyle() const { + return st::defaultWindowTitle.style; +} + QMargins BasicWindowHelper::nativeFrameMargins() const { const auto inner = window()->geometry(); const auto outer = window()->frameGeometry(); diff --git a/ui/platform/ui_platform_window.h b/ui/platform/ui_platform_window.h index 2d52e7b..e1e8514 100644 --- a/ui/platform/ui_platform_window.h +++ b/ui/platform/ui_platform_window.h @@ -12,6 +12,7 @@ namespace style { struct WindowTitle; +struct TextStyle; } // namespace style namespace Ui { @@ -62,6 +63,8 @@ public: virtual int manualRoundingRadius() const; void setBodyTitleArea(Fn testMethod); + [[nodiscard]] virtual const style::TextStyle &titleTextStyle() const; + protected: [[nodiscard]] WindowTitleHitTestFlags bodyTitleAreaHit( QPoint point) const { diff --git a/ui/style/style_core_custom_font.cpp b/ui/style/style_core_custom_font.cpp index 825726f..8f42baf 100644 --- a/ui/style/style_core_custom_font.cpp +++ b/ui/style/style_core_custom_font.cpp @@ -26,7 +26,7 @@ void SetCustomFonts(const CustomFont ®ular, const CustomFont &bold) { BoldFont = bold; } -QFont ResolveFont(uint32 flags, int size) { +QFont ResolveFont(const QString &familyOverride, uint32 flags, int size) { static auto Database = QFontDatabase(); const auto bold = ((flags & FontBold) || (flags & FontSemibold)); @@ -35,7 +35,12 @@ QFont ResolveFont(uint32 flags, int size) { const auto useCustom = !custom.family.isEmpty(); auto result = QFont(QGuiApplication::font().family()); - if (flags & FontMonospace) { + if (!familyOverride.isEmpty()) { + result.setFamily(familyOverride); + if (bold) { + result.setBold(true); + } + } else if (flags & FontMonospace) { result.setFamily(MonospaceFont()); } else if (useCustom) { const auto sizes = Database.smoothSizes(custom.family, custom.style); diff --git a/ui/style/style_core_custom_font.h b/ui/style/style_core_custom_font.h index 14ee48b..25999ae 100644 --- a/ui/style/style_core_custom_font.h +++ b/ui/style/style_core_custom_font.h @@ -40,6 +40,6 @@ inline bool operator>=(const CustomFont &a, const CustomFont &b) { void SetCustomFonts(const CustomFont ®ular, const CustomFont &bold); -[[nodiscard]] QFont ResolveFont(uint32 flags, int size); +[[nodiscard]] QFont ResolveFont(const QString &familyOverride, uint32 flags, int size); } // namespace style diff --git a/ui/style/style_core_font.cpp b/ui/style/style_core_font.cpp index d87de63..55fb7cc 100644 --- a/ui/style/style_core_font.cpp +++ b/ui/style/style_core_font.cpp @@ -300,7 +300,7 @@ int CeilTextWidth(const QFont &font, const QString &text) { } FontData::FontData(int size, uint32 flags, int family, Font *other) -: f(ResolveFont(flags, size)) +: f(ResolveFont(family ? fontFamilies[family] : QString(), flags, size)) , _m(f) , _size(size) , _flags(flags) diff --git a/ui/widgets/rp_window.cpp b/ui/widgets/rp_window.cpp index 0226774..90a8d70 100644 --- a/ui/widgets/rp_window.cpp +++ b/ui/widgets/rp_window.cpp @@ -103,4 +103,8 @@ int RpWindow::manualRoundingRadius() const { return _helper->manualRoundingRadius(); } +const style::TextStyle &RpWindow::titleTextStyle() const { + return _helper->titleTextStyle(); +} + } // namespace Ui diff --git a/ui/widgets/rp_window.h b/ui/widgets/rp_window.h index 57d1335..96cac73 100644 --- a/ui/widgets/rp_window.h +++ b/ui/widgets/rp_window.h @@ -11,6 +11,7 @@ namespace style { struct WindowTitle; +struct TextStyle; } // namespace style namespace Ui { @@ -68,6 +69,8 @@ public: [[nodiscard]] int manualRoundingRadius() const; void setBodyTitleArea(Fn testMethod); + [[nodiscard]] const style::TextStyle &titleTextStyle() const; + private: const std::unique_ptr _helper; diff --git a/ui/widgets/widgets.style b/ui/widgets/widgets.style index 323a884..e14072b 100644 --- a/ui/widgets/widgets.style +++ b/ui/widgets/widgets.style @@ -555,6 +555,7 @@ WindowTitle { bgActive: color; fg: color; fgActive: color; + style: TextStyle; minimize: IconButton; minimizeIconActive: icon; minimizeIconActiveOver: icon; @@ -1420,6 +1421,11 @@ defaultWindowTitle: WindowTitle { bgActive: titleBgActive; fg: titleFg; fgActive: titleFgActive; + style: TextStyle(defaultTextStyle) { + font: font(semibold 12px); + linkFont: font(semibold 12px); + linkFontOver: font(semibold 12px underline); + } minimize: IconButton(windowTitleButton) { icon: icon { { windowTitleButtonSize, titleButtonBg },