refactor: Fonts (#5228)

This commit is contained in:
pajlada 2024-03-10 14:27:08 +01:00 committed by GitHub
parent e56f7136a9
commit e7508332ff
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 128 additions and 143 deletions

View file

@ -151,6 +151,7 @@
- Dev: Move `clang-tidy` checker to its own CI job. (#4996) - Dev: Move `clang-tidy` checker to its own CI job. (#4996)
- Dev: Refactored the Image Uploader feature. (#4971) - Dev: Refactored the Image Uploader feature. (#4971)
- Dev: Refactored the SplitOverlay code. (#5082) - Dev: Refactored the SplitOverlay code. (#5082)
- Dev: Refactored the Fonts code, making it less of a singleton. (#5228)
- Dev: Refactored the TwitchBadges structure, making it less of a singleton. (#5096, #5144) - Dev: Refactored the TwitchBadges structure, making it less of a singleton. (#5096, #5144)
- Dev: Refactored emotes out of TwitchIrcServer. (#5120, #5146) - Dev: Refactored emotes out of TwitchIrcServer. (#5120, #5146)
- Dev: Refactored the ChatterinoBadges structure, making it less of a singleton. (#5103) - Dev: Refactored the ChatterinoBadges structure, making it less of a singleton. (#5103)

View file

@ -5,6 +5,8 @@
#include "singletons/Paths.hpp" #include "singletons/Paths.hpp"
#include "singletons/Updates.hpp" #include "singletons/Updates.hpp"
#include <QTemporaryDir>
namespace chatterino::mock { namespace chatterino::mock {
class EmptyApplication : public IApplication class EmptyApplication : public IApplication
@ -235,7 +237,8 @@ public:
return nullptr; return nullptr;
} }
private: protected:
QTemporaryDir settingsDir;
Paths paths_; Paths paths_;
Args args_; Args args_;
Updates updates_; Updates updates_;

View file

@ -118,7 +118,7 @@ Application::Application(Settings &_settings, const Paths &paths,
: paths_(paths) : paths_(paths)
, args_(_args) , args_(_args)
, themes(&this->emplace<Theme>()) , themes(&this->emplace<Theme>())
, fonts(&this->emplace<Fonts>()) , fonts(new Fonts(_settings))
, emotes(&this->emplace<Emotes>()) , emotes(&this->emplace<Emotes>())
, accounts(&this->emplace<AccountController>()) , accounts(&this->emplace<AccountController>())
, hotkeys(&this->emplace<HotkeyController>()) , hotkeys(&this->emplace<HotkeyController>())
@ -170,6 +170,7 @@ void Application::fakeDtor()
this->bttvEmotes.reset(); this->bttvEmotes.reset();
this->ffzEmotes.reset(); this->ffzEmotes.reset();
this->seventvEmotes.reset(); this->seventvEmotes.reset();
this->fonts.reset();
} }
void Application::initialize(Settings &settings, const Paths &paths) void Application::initialize(Settings &settings, const Paths &paths)
@ -335,8 +336,9 @@ Theme *Application::getThemes()
Fonts *Application::getFonts() Fonts *Application::getFonts()
{ {
assertInGuiThread(); assertInGuiThread();
assert(this->fonts);
return this->fonts; return this->fonts.get();
} }
IEmotes *Application::getEmotes() IEmotes *Application::getEmotes()

View file

@ -135,7 +135,7 @@ public:
private: private:
Theme *const themes{}; Theme *const themes{};
Fonts *const fonts{}; std::unique_ptr<Fonts> fonts{};
Emotes *const emotes{}; Emotes *const emotes{};
AccountController *const accounts{}; AccountController *const accounts{};
HotkeyController *const hotkeys{}; HotkeyController *const hotkeys{};

View file

@ -8,119 +8,73 @@
#include <QDebug> #include <QDebug>
#include <QtGlobal> #include <QtGlobal>
#ifdef Q_OS_WIN32
# define DEFAULT_FONT_FAMILY "Segoe UI"
# define DEFAULT_FONT_SIZE 10
#else
# ifdef Q_OS_MACOS
# define DEFAULT_FONT_FAMILY "Helvetica Neue"
# define DEFAULT_FONT_SIZE 12
# else
# define DEFAULT_FONT_FAMILY "Arial"
# define DEFAULT_FONT_SIZE 11
# endif
#endif
namespace chatterino {
namespace { namespace {
int getBoldness()
{ using namespace chatterino;
int getBoldness()
{
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
// From qfont.cpp // From qfont.cpp
// https://github.com/qt/qtbase/blob/589c6d066f84833a7c3dda1638037f4b2e91b7aa/src/gui/text/qfont.cpp#L143-L169 // https://github.com/qt/qtbase/blob/589c6d066f84833a7c3dda1638037f4b2e91b7aa/src/gui/text/qfont.cpp#L143-L169
static constexpr std::array<std::array<int, 2>, 9> legacyToOpenTypeMap{{ static constexpr std::array<std::array<int, 2>, 9> legacyToOpenTypeMap{{
{0, QFont::Thin}, {0, QFont::Thin},
{12, QFont::ExtraLight}, {12, QFont::ExtraLight},
{25, QFont::Light}, {25, QFont::Light},
{50, QFont::Normal}, {50, QFont::Normal},
{57, QFont::Medium}, {57, QFont::Medium},
{63, QFont::DemiBold}, {63, QFont::DemiBold},
{75, QFont::Bold}, {75, QFont::Bold},
{81, QFont::ExtraBold}, {81, QFont::ExtraBold},
{87, QFont::Black}, {87, QFont::Black},
}}; }};
const int target = getSettings()->boldScale.getValue(); const int target = getSettings()->boldScale.getValue();
int result = QFont::Medium; int result = QFont::Medium;
int closestDist = INT_MAX; int closestDist = INT_MAX;
// Go through and find the closest mapped value // Go through and find the closest mapped value
for (const auto [weightOld, weightNew] : legacyToOpenTypeMap) for (const auto [weightOld, weightNew] : legacyToOpenTypeMap)
{
const int dist = qAbs(weightOld - target);
if (dist < closestDist)
{ {
const int dist = qAbs(weightOld - target); result = weightNew;
if (dist < closestDist) closestDist = dist;
{ }
result = weightNew; else
closestDist = dist; {
} // Break early since following values will be further away
else break;
{
// Break early since following values will be further away
break;
}
} }
return result;
#else
return getSettings()->boldScale.getValue();
#endif
} }
return result;
#else
return getSettings()->boldScale.getValue();
#endif
}
} // namespace } // namespace
Fonts *Fonts::instance = nullptr; namespace chatterino {
Fonts::Fonts() Fonts::Fonts(Settings &settings)
: chatFontFamily("/appearance/currentFontFamily", DEFAULT_FONT_FAMILY)
, chatFontSize("/appearance/currentFontSize", DEFAULT_FONT_SIZE)
{ {
Fonts::instance = this;
this->fontsByType_.resize(size_t(FontStyle::EndType)); this->fontsByType_.resize(size_t(FontStyle::EndType));
}
void Fonts::initialize(Settings &, const Paths &) this->fontChangedListener.setCB([this] {
{ assertInGuiThread();
this->chatFontFamily.connect(
[this]() {
assertInGuiThread();
for (auto &map : this->fontsByType_) for (auto &map : this->fontsByType_)
{ {
map.clear(); map.clear();
} }
this->fontChanged.invoke(); this->fontChanged.invoke();
}, });
false); this->fontChangedListener.addSetting(settings.chatFontFamily);
this->fontChangedListener.addSetting(settings.chatFontSize);
this->chatFontSize.connect( this->fontChangedListener.addSetting(settings.boldScale);
[this]() {
assertInGuiThread();
for (auto &map : this->fontsByType_)
{
map.clear();
}
this->fontChanged.invoke();
},
false);
#ifdef CHATTERINO
getSettings()->boldScale.connect(
[this]() {
assertInGuiThread();
// REMOVED
getIApp()->getWindows()->incGeneration();
for (auto &map : this->fontsByType_)
{
map.clear();
}
this->fontChanged.invoke();
},
false);
#endif
} }
QFont Fonts::getFont(FontStyle type, float scale) QFont Fonts::getFont(FontStyle type, float scale)
@ -159,6 +113,8 @@ Fonts::FontData &Fonts::getOrCreateFontData(FontStyle type, float scale)
Fonts::FontData Fonts::createFontData(FontStyle type, float scale) Fonts::FontData Fonts::createFontData(FontStyle type, float scale)
{ {
auto *settings = getSettings();
// check if it's a chat (scale the setting) // check if it's a chat (scale the setting)
if (type >= FontStyle::ChatStart && type <= FontStyle::ChatEnd) if (type >= FontStyle::ChatStart && type <= FontStyle::ChatEnd)
{ {
@ -176,8 +132,8 @@ Fonts::FontData Fonts::createFontData(FontStyle type, float scale)
QFont::Weight(getBoldness())}; QFont::Weight(getBoldness())};
auto data = sizeScale[type]; auto data = sizeScale[type];
return FontData( return FontData(
QFont(this->chatFontFamily.getValue(), QFont(settings->chatFontFamily.getValue(),
int(this->chatFontSize.getValue() * data.scale * scale), int(settings->chatFontSize.getValue() * data.scale * scale),
data.weight, data.italic)); data.weight, data.italic));
} }
@ -205,9 +161,4 @@ Fonts::FontData Fonts::createFontData(FontStyle type, float scale)
} }
} }
Fonts *getFonts()
{
return Fonts::instance;
}
} // namespace chatterino } // namespace chatterino

View file

@ -1,15 +1,13 @@
#pragma once #pragma once
#include "common/ChatterinoSetting.hpp" #include "pajlada/settings/settinglistener.hpp"
#include "common/Singleton.hpp"
#include <pajlada/signals/signal.hpp> #include <pajlada/signals/signal.hpp>
#include <QFont> #include <QFont>
#include <QFontDatabase>
#include <QFontMetrics> #include <QFontMetrics>
#include <array>
#include <unordered_map> #include <unordered_map>
#include <vector>
namespace chatterino { namespace chatterino {
@ -38,23 +36,17 @@ enum class FontStyle : uint8_t {
ChatEnd = ChatVeryLarge, ChatEnd = ChatVeryLarge,
}; };
class Fonts final : public Singleton class Fonts final
{ {
public: public:
Fonts(); explicit Fonts(Settings &settings);
void initialize(Settings &settings, const Paths &paths) override;
// font data gets set in createFontData(...) // font data gets set in createFontData(...)
QFont getFont(FontStyle type, float scale); QFont getFont(FontStyle type, float scale);
QFontMetrics getFontMetrics(FontStyle type, float scale); QFontMetrics getFontMetrics(FontStyle type, float scale);
QStringSetting chatFontFamily;
IntSetting chatFontSize;
pajlada::Signals::NoArgSignal fontChanged; pajlada::Signals::NoArgSignal fontChanged;
static Fonts *instance;
private: private:
struct FontData { struct FontData {
@ -85,8 +77,8 @@ private:
FontData createFontData(FontStyle type, float scale); FontData createFontData(FontStyle type, float scale);
std::vector<std::unordered_map<float, FontData>> fontsByType_; std::vector<std::unordered_map<float, FontData>> fontsByType_;
pajlada::SettingListener fontChangedListener;
}; };
Fonts *getFonts();
} // namespace chatterino } // namespace chatterino

View file

@ -25,6 +25,19 @@ using TimeoutButton = std::pair<QString, int>;
namespace chatterino { namespace chatterino {
#ifdef Q_OS_WIN32
# define DEFAULT_FONT_FAMILY "Segoe UI"
# define DEFAULT_FONT_SIZE 10
#else
# ifdef Q_OS_MACOS
# define DEFAULT_FONT_FAMILY "Helvetica Neue"
# define DEFAULT_FONT_SIZE 12
# else
# define DEFAULT_FONT_FAMILY "Arial"
# define DEFAULT_FONT_SIZE 11
# endif
#endif
void _actuallyRegisterSetting( void _actuallyRegisterSetting(
std::weak_ptr<pajlada::Settings::SettingData> setting); std::weak_ptr<pajlada::Settings::SettingData> setting);
@ -134,6 +147,14 @@ public:
// BoolSetting collapseLongMessages = // BoolSetting collapseLongMessages =
// {"/appearance/messages/collapseLongMessages", false}; // {"/appearance/messages/collapseLongMessages", false};
QStringSetting chatFontFamily{
"/appearance/currentFontFamily",
DEFAULT_FONT_FAMILY,
};
IntSetting chatFontSize{
"/appearance/currentFontSize",
DEFAULT_FONT_SIZE,
};
BoolSetting hideReplyContext = {"/appearance/hideReplyContext", false}; BoolSetting hideReplyContext = {"/appearance/hideReplyContext", false};
BoolSetting showReplyButton = {"/appearance/showReplyButton", false}; BoolSetting showReplyButton = {"/appearance/showReplyButton", false};
BoolSetting stripReplyMention = {"/appearance/stripReplyMention", true}; BoolSetting stripReplyMention = {"/appearance/stripReplyMention", true};

View file

@ -9,7 +9,6 @@
#include "providers/irc/IrcChannel2.hpp" #include "providers/irc/IrcChannel2.hpp"
#include "providers/irc/IrcServer.hpp" #include "providers/irc/IrcServer.hpp"
#include "providers/twitch/TwitchIrcServer.hpp" #include "providers/twitch/TwitchIrcServer.hpp"
#include "singletons/Fonts.hpp"
#include "singletons/Paths.hpp" #include "singletons/Paths.hpp"
#include "singletons/Settings.hpp" #include "singletons/Settings.hpp"
#include "singletons/Theme.hpp" #include "singletons/Theme.hpp"

View file

@ -775,7 +775,8 @@ void BaseWindow::scaleChangedEvent(float scale)
this->calcButtonsSizes(); this->calcButtonsSizes();
#endif #endif
this->setFont(getFonts()->getFont(FontStyle::UiTabs, this->qtFontScale())); this->setFont(
getIApp()->getFonts()->getFont(FontStyle::UiTabs, this->qtFontScale()));
} }
void BaseWindow::paintEvent(QPaintEvent *) void BaseWindow::paintEvent(QPaintEvent *)

View file

@ -1,4 +1,6 @@
#include "Label.hpp" #include "widgets/Label.hpp"
#include "Application.hpp"
#include <QPainter> #include <QPainter>
@ -14,9 +16,10 @@ Label::Label(BaseWidget *parent, QString text, FontStyle style)
, text_(std::move(text)) , text_(std::move(text))
, fontStyle_(style) , fontStyle_(style)
{ {
this->connections_.managedConnect(getFonts()->fontChanged, [this] { this->connections_.managedConnect(getIApp()->getFonts()->fontChanged,
this->updateSize(); [this] {
}); this->updateSize();
});
} }
const QString &Label::getText() const const QString &Label::getText() const
@ -92,12 +95,12 @@ void Label::paintEvent(QPaintEvent *)
1.0; 1.0;
#endif #endif
QFontMetrics metrics = getFonts()->getFontMetrics( QFontMetrics metrics = getIApp()->getFonts()->getFontMetrics(
this->getFontStyle(), this->getFontStyle(),
this->scale() * 96.f / this->scale() * 96.f /
std::max<float>( std::max<float>(
0.01F, static_cast<float>(this->logicalDpiX() * deviceDpi))); 0.01F, static_cast<float>(this->logicalDpiX() * deviceDpi)));
painter.setFont(getFonts()->getFont( painter.setFont(getIApp()->getFonts()->getFont(
this->getFontStyle(), this->getFontStyle(),
this->scale() * 96.f / this->scale() * 96.f /
std::max<float>( std::max<float>(
@ -128,7 +131,7 @@ void Label::paintEvent(QPaintEvent *)
void Label::updateSize() void Label::updateSize()
{ {
QFontMetrics metrics = QFontMetrics metrics =
getFonts()->getFontMetrics(this->fontStyle_, this->scale()); getIApp()->getFonts()->getFontMetrics(this->fontStyle_, this->scale());
int width = int width =
metrics.horizontalAdvance(this->text_) + (2 * this->getOffset()); metrics.horizontalAdvance(this->text_) + (2 * this->getOffset());

View file

@ -47,9 +47,10 @@ TooltipWidget::TooltipWidget(BaseWidget *parent)
this->setLayout(this->vLayout_); this->setLayout(this->vLayout_);
this->currentStyle_ = TooltipStyle::Vertical; this->currentStyle_ = TooltipStyle::Vertical;
this->connections_.managedConnect(getFonts()->fontChanged, [this] { this->connections_.managedConnect(getIApp()->getFonts()->fontChanged,
this->updateFont(); [this] {
}); this->updateFont();
});
this->updateFont(); this->updateFont();
auto *windows = getIApp()->getWindows(); auto *windows = getIApp()->getWindows();
@ -299,8 +300,8 @@ void TooltipWidget::scaleChangedEvent(float)
void TooltipWidget::updateFont() void TooltipWidget::updateFont()
{ {
this->setFont( this->setFont(getIApp()->getFonts()->getFont(FontStyle::ChatMediumSmall,
getFonts()->getFont(FontStyle::ChatMediumSmall, this->scale())); this->scale()));
} }
void TooltipWidget::setWordWrap(bool wrap) void TooltipWidget::setWordWrap(bool wrap)

View file

@ -572,7 +572,8 @@ void UserInfoPopup::themeChangedEvent()
for (auto &&child : this->findChildren<QCheckBox *>()) for (auto &&child : this->findChildren<QCheckBox *>())
{ {
child->setFont(getFonts()->getFont(FontStyle::UiMedium, this->scale())); child->setFont(
getIApp()->getFonts()->getFont(FontStyle::UiMedium, this->scale()));
} }
} }

View file

@ -620,7 +620,7 @@ void ChannelView::scaleChangedEvent(float scale)
0.01, this->logicalDpiX() * this->devicePixelRatioF()); 0.01, this->logicalDpiX() * this->devicePixelRatioF());
#endif #endif
this->goToBottom_->getLabel().setFont( this->goToBottom_->getLabel().setFont(
getFonts()->getFont(FontStyle::UiMedium, factor)); getIApp()->getFonts()->getFont(FontStyle::UiMedium, factor));
} }
} }

View file

@ -166,8 +166,7 @@ void GeneralPage::initLayout(GeneralPageView &layout)
} }
layout.addDropdown<QString>( layout.addDropdown<QString>(
"Font", {"Segoe UI", "Arial", "Choose..."}, "Font", {"Segoe UI", "Arial", "Choose..."}, s.chatFontFamily,
getIApp()->getFonts()->chatFontFamily,
[](auto val) { [](auto val) {
return val; return val;
}, },
@ -177,7 +176,7 @@ void GeneralPage::initLayout(GeneralPageView &layout)
true, "", true); true, "", true);
layout.addDropdown<int>( layout.addDropdown<int>(
"Font size", {"9pt", "10pt", "12pt", "14pt", "16pt", "20pt"}, "Font size", {"9pt", "10pt", "12pt", "14pt", "16pt", "20pt"},
getIApp()->getFonts()->chatFontSize, s.chatFontSize,
[](auto val) { [](auto val) {
return QString::number(val) + "pt"; return QString::number(val) + "pt";
}, },

View file

@ -5,6 +5,7 @@
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "mocks/EmptyApplication.hpp" #include "mocks/EmptyApplication.hpp"
#include "singletons/Fonts.hpp" #include "singletons/Fonts.hpp"
#include "singletons/Settings.hpp"
#include "singletons/Theme.hpp" #include "singletons/Theme.hpp"
#include "widgets/Notebook.hpp" #include "widgets/Notebook.hpp"
@ -21,6 +22,11 @@ namespace {
class MockApplication : mock::EmptyApplication class MockApplication : mock::EmptyApplication
{ {
public: public:
MockApplication()
: settings(this->settingsDir.filePath("settings.json"))
, fonts(this->settings)
{
}
Theme *getThemes() override Theme *getThemes() override
{ {
return &this->theme; return &this->theme;
@ -36,6 +42,7 @@ public:
return &this->fonts; return &this->fonts;
} }
Settings settings;
Theme theme; Theme theme;
HotkeyController hotkeys; HotkeyController hotkeys;
Fonts fonts; Fonts fonts;

View file

@ -9,6 +9,7 @@
#include "singletons/Emotes.hpp" #include "singletons/Emotes.hpp"
#include "singletons/Fonts.hpp" #include "singletons/Fonts.hpp"
#include "singletons/Paths.hpp" #include "singletons/Paths.hpp"
#include "singletons/Settings.hpp"
#include "singletons/Theme.hpp" #include "singletons/Theme.hpp"
#include "singletons/WindowManager.hpp" #include "singletons/WindowManager.hpp"
#include "widgets/Notebook.hpp" #include "widgets/Notebook.hpp"
@ -28,7 +29,9 @@ class MockApplication : mock::EmptyApplication
{ {
public: public:
MockApplication() MockApplication()
: windowManager(this->paths) : settings(this->settingsDir.filePath("settings.json"))
, fonts(this->settings)
, windowManager(this->paths)
{ {
} }
Theme *getThemes() override Theme *getThemes() override
@ -66,6 +69,7 @@ public:
return &this->emotes; return &this->emotes;
} }
Settings settings;
Theme theme; Theme theme;
HotkeyController hotkeys; HotkeyController hotkeys;
Fonts fonts; Fonts fonts;