Handle emoji myself in custom macOS title.

This commit is contained in:
John Preston 2023-04-26 22:11:33 +04:00
parent 37531086ec
commit bfdd116000
12 changed files with 74 additions and 28 deletions

View file

@ -28,6 +28,8 @@ public:
void setGeometry(QRect rect) override; void setGeometry(QRect rect) override;
void close() override; void close() override;
const style::TextStyle &titleTextStyle() const override;
private: private:
class Private; class Private;
friend class Private; friend class Private;

View file

@ -422,6 +422,10 @@ void WindowHelper::close() {
_private->close(); _private->close();
} }
const style::TextStyle &WindowHelper::titleTextStyle() const {
return _title->textStyle();
}
void WindowHelper::init() { void WindowHelper::init() {
updateCustomTitleVisibility(true); updateCustomTitleVisibility(true);

View file

@ -6,6 +6,7 @@
// //
#pragma once #pragma once
#include "ui/text/text.h"
#include "ui/rp_widget.h" #include "ui/rp_widget.h"
#include "base/object_ptr.h" #include "base/object_ptr.h"
@ -14,6 +15,7 @@
namespace style { namespace style {
struct WindowTitle; struct WindowTitle;
struct TextStyle;
} // namespace style } // namespace style
namespace Ui { namespace Ui {
@ -25,12 +27,14 @@ namespace Platform {
class TitleWidget : public RpWidget { class TitleWidget : public RpWidget {
public: public:
TitleWidget(not_null<RpWidget*> parent, int height); TitleWidget(not_null<RpWidget*> parent, int height);
~TitleWidget();
void setText(const QString &text); void setText(const QString &text);
void setStyle(const style::WindowTitle &st); void setStyle(const style::WindowTitle &st);
void setControlsRect(const QRect &rect); void setControlsRect(const QRect &rect);
[[nodiscard]] QString text() const; [[nodiscard]] QString text() const;
[[nodiscard]] bool shouldBeHidden() const; [[nodiscard]] bool shouldBeHidden() const;
[[nodiscard]] const style::TextStyle &textStyle() const;
protected: protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
@ -43,11 +47,11 @@ private:
void init(int height); void init(int height);
not_null<const style::WindowTitle*> _st; not_null<const style::WindowTitle*> _st;
std::unique_ptr<style::TextStyle> _textStyle;
object_ptr<Ui::PlainShadow> _shadow; object_ptr<Ui::PlainShadow> _shadow;
QString _text; QString _text;
int _textWidth = 0; Ui::Text::String _string;
int _controlsRight = 0; int _controlsRight = 0;
QFont _font;
}; };

View file

@ -8,6 +8,7 @@
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/widgets/shadow.h" #include "ui/widgets/shadow.h"
#include "ui/painter.h"
#include "ui/ui_utility.h" #include "ui/ui_utility.h"
#include "base/debug_log.h" #include "base/debug_log.h"
#include "styles/style_widgets.h" #include "styles/style_widgets.h"
@ -27,10 +28,12 @@ TitleWidget::TitleWidget(not_null<RpWidget*> parent, int height)
init(height); init(height);
} }
TitleWidget::~TitleWidget() = default;
void TitleWidget::setText(const QString &text) { void TitleWidget::setText(const QString &text) {
if (_text != text) { if (_text != text) {
_text = text; _text = text;
_textWidth = QFontMetrics(_font).horizontalAdvance(_text); _string.setText(textStyle(), text);
update(); update();
} }
} }
@ -48,6 +51,10 @@ bool TitleWidget::shouldBeHidden() const {
return !_st->height; return !_st->height;
} }
const style::TextStyle &TitleWidget::textStyle() const {
return *_textStyle;
}
QString TitleWidget::text() const { QString TitleWidget::text() const {
return _text; return _text;
} }
@ -64,51 +71,55 @@ void TitleWidget::init(int height) {
setGeometry(0, 0, width, height); setGeometry(0, 0, width, height);
}, lifetime()); }, lifetime());
const auto setFromFont = [&](const style::font &font) {
_textStyle = std::make_unique<style::TextStyle>(style::TextStyle{
.font = font,
.linkFont = font,
.linkFontOver = font,
});
};
const auto families = QStringList{ const auto families = QStringList{
u".AppleSystemUIFont"_q, u".AppleSystemUIFont"_q,
u".SF NS Text"_q, u".SF NS Text"_q,
u"Helvetica Neue"_q, u"Helvetica Neue"_q,
}; };
for (auto family : families) { for (auto family : families) {
_font.setFamily(family); auto font = QFont();
if (QFontInfo(_font).family() == _font.family()) { font.setFamily(family);
if (QFontInfo(font).family() == font.family()) {
static const auto logged = [&] { static const auto logged = [&] {
LOG(("Title Font: %1").arg(family)); LOG(("Title Font: %1").arg(family));
return true; return true;
}(); }();
const auto apple = (family == u".AppleSystemUIFont"_q);
setFromFont(style::font(
apple ? 13 : (height * 15) / 24,
apple ? style::internal::FontBold : 0,
family));
break; break;
} }
} }
if (!_textStyle) {
if (QFontInfo(_font).family() != _font.family()) { setFromFont(style::font(13, style::internal::FontSemibold, 0));
_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);
} }
} }
void TitleWidget::paintEvent(QPaintEvent *e) { void TitleWidget::paintEvent(QPaintEvent *e) {
QPainter p(this); Painter p(this);
const auto active = isActiveWindow(); const auto active = isActiveWindow();
p.fillRect(rect(), active ? _st->bgActive : _st->bg); p.fillRect(rect(), active ? _st->bgActive : _st->bg);
p.setFont(_font);
p.setPen(active ? _st->fgActive : _st->fg); p.setPen(active ? _st->fgActive : _st->fg);
if ((width() - _controlsRight * 2) < _textWidth) { const auto top = (height() - _textStyle->font->height) / 2;
const auto elided = QFontMetrics(_font).elidedText( if ((width() - _controlsRight * 2) < _string.maxWidth()) {
_text, const auto left = _controlsRight;
Qt::ElideRight, _string.drawElided(p, left, top, width() - left);
width() - _controlsRight);
const auto padding = QMargins(_controlsRight, 0, 0, 0);
p.drawText(rect() - padding, elided, style::al_left);
} else { } else {
p.drawText(rect(), _text, style::al_center); const auto left = (width() - _string.maxWidth()) / 2;
_string.draw(p, left, top, width() - left);
} }
} }

View file

@ -205,6 +205,10 @@ void BasicWindowHelper::setBodyTitleArea(
_bodyTitleAreaTestMethod = std::move(testMethod); _bodyTitleAreaTestMethod = std::move(testMethod);
} }
const style::TextStyle &BasicWindowHelper::titleTextStyle() const {
return st::defaultWindowTitle.style;
}
QMargins BasicWindowHelper::nativeFrameMargins() const { QMargins BasicWindowHelper::nativeFrameMargins() const {
const auto inner = window()->geometry(); const auto inner = window()->geometry();
const auto outer = window()->frameGeometry(); const auto outer = window()->frameGeometry();

View file

@ -12,6 +12,7 @@
namespace style { namespace style {
struct WindowTitle; struct WindowTitle;
struct TextStyle;
} // namespace style } // namespace style
namespace Ui { namespace Ui {
@ -62,6 +63,8 @@ public:
virtual int manualRoundingRadius() const; virtual int manualRoundingRadius() const;
void setBodyTitleArea(Fn<WindowTitleHitTestFlags(QPoint)> testMethod); void setBodyTitleArea(Fn<WindowTitleHitTestFlags(QPoint)> testMethod);
[[nodiscard]] virtual const style::TextStyle &titleTextStyle() const;
protected: protected:
[[nodiscard]] WindowTitleHitTestFlags bodyTitleAreaHit( [[nodiscard]] WindowTitleHitTestFlags bodyTitleAreaHit(
QPoint point) const { QPoint point) const {

View file

@ -26,7 +26,7 @@ void SetCustomFonts(const CustomFont &regular, const CustomFont &bold) {
BoldFont = bold; BoldFont = bold;
} }
QFont ResolveFont(uint32 flags, int size) { QFont ResolveFont(const QString &familyOverride, uint32 flags, int size) {
static auto Database = QFontDatabase(); static auto Database = QFontDatabase();
const auto bold = ((flags & FontBold) || (flags & FontSemibold)); const auto bold = ((flags & FontBold) || (flags & FontSemibold));
@ -35,7 +35,12 @@ QFont ResolveFont(uint32 flags, int size) {
const auto useCustom = !custom.family.isEmpty(); const auto useCustom = !custom.family.isEmpty();
auto result = QFont(QGuiApplication::font().family()); 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()); result.setFamily(MonospaceFont());
} else if (useCustom) { } else if (useCustom) {
const auto sizes = Database.smoothSizes(custom.family, custom.style); const auto sizes = Database.smoothSizes(custom.family, custom.style);

View file

@ -40,6 +40,6 @@ inline bool operator>=(const CustomFont &a, const CustomFont &b) {
void SetCustomFonts(const CustomFont &regular, const CustomFont &bold); void SetCustomFonts(const CustomFont &regular, const CustomFont &bold);
[[nodiscard]] QFont ResolveFont(uint32 flags, int size); [[nodiscard]] QFont ResolveFont(const QString &familyOverride, uint32 flags, int size);
} // namespace style } // namespace style

View file

@ -300,7 +300,7 @@ int CeilTextWidth(const QFont &font, const QString &text) {
} }
FontData::FontData(int size, uint32 flags, int family, Font *other) FontData::FontData(int size, uint32 flags, int family, Font *other)
: f(ResolveFont(flags, size)) : f(ResolveFont(family ? fontFamilies[family] : QString(), flags, size))
, _m(f) , _m(f)
, _size(size) , _size(size)
, _flags(flags) , _flags(flags)

View file

@ -103,4 +103,8 @@ int RpWindow::manualRoundingRadius() const {
return _helper->manualRoundingRadius(); return _helper->manualRoundingRadius();
} }
const style::TextStyle &RpWindow::titleTextStyle() const {
return _helper->titleTextStyle();
}
} // namespace Ui } // namespace Ui

View file

@ -11,6 +11,7 @@
namespace style { namespace style {
struct WindowTitle; struct WindowTitle;
struct TextStyle;
} // namespace style } // namespace style
namespace Ui { namespace Ui {
@ -68,6 +69,8 @@ public:
[[nodiscard]] int manualRoundingRadius() const; [[nodiscard]] int manualRoundingRadius() const;
void setBodyTitleArea(Fn<WindowTitleHitTestFlags(QPoint)> testMethod); void setBodyTitleArea(Fn<WindowTitleHitTestFlags(QPoint)> testMethod);
[[nodiscard]] const style::TextStyle &titleTextStyle() const;
private: private:
const std::unique_ptr<Platform::BasicWindowHelper> _helper; const std::unique_ptr<Platform::BasicWindowHelper> _helper;

View file

@ -555,6 +555,7 @@ WindowTitle {
bgActive: color; bgActive: color;
fg: color; fg: color;
fgActive: color; fgActive: color;
style: TextStyle;
minimize: IconButton; minimize: IconButton;
minimizeIconActive: icon; minimizeIconActive: icon;
minimizeIconActiveOver: icon; minimizeIconActiveOver: icon;
@ -1420,6 +1421,11 @@ defaultWindowTitle: WindowTitle {
bgActive: titleBgActive; bgActive: titleBgActive;
fg: titleFg; fg: titleFg;
fgActive: titleFgActive; fgActive: titleFgActive;
style: TextStyle(defaultTextStyle) {
font: font(semibold 12px);
linkFont: font(semibold 12px);
linkFontOver: font(semibold 12px underline);
}
minimize: IconButton(windowTitleButton) { minimize: IconButton(windowTitleButton) {
icon: icon { icon: icon {
{ windowTitleButtonSize, titleButtonBg }, { windowTitleButtonSize, titleButtonBg },