Clean up font management

Default to b.userName instead of message->account()
Made font updatable in the Settings dialog with a font dialog
More work on subscription badge loading

Known issues:
  - Font isn't updated in a split until a new message is written in that split
  - When font/font size is changed, old messages don't have their size updated causing weird layout of old messages
This commit is contained in:
Rasmus Karlsson 2017-06-17 11:37:13 +02:00
parent d2cbef9dff
commit 1ecc6ff612
6 changed files with 204 additions and 104 deletions

View file

@ -1,63 +1,61 @@
#include "fontmanager.hpp"
#define DEFAULT_FONT "Arial"
#include <QDebug>
namespace chatterino {
FontManager FontManager::instance;
FontManager::FontManager()
: _generation(0)
: currentFontFamily("/appearance/currentFontFamily", "Arial")
, currentFontSize("/appearance/currentFontSize", 14)
, currentFont(this->currentFontFamily.getValue().c_str(), currentFontSize.getValue())
{
_medium = new QFont(DEFAULT_FONT, 14);
_mediumBold = new QFont(DEFAULT_FONT, 14);
_mediumItalic = new QFont(DEFAULT_FONT, 14);
_small = new QFont(DEFAULT_FONT, 10);
_large = new QFont(DEFAULT_FONT, 16);
_veryLarge = new QFont(DEFAULT_FONT, 18);
_metricsMedium = new QFontMetrics(*_medium);
_metricsMediumBold = new QFontMetrics(*_mediumBold);
_metricsMediumItalic = new QFontMetrics(*_mediumItalic);
_metricsSmall = new QFontMetrics(*_small);
_metricsLarge = new QFontMetrics(*_large);
_metricsVeryLarge = new QFontMetrics(*_veryLarge);
this->currentFontFamily.valueChanged.connect([this](const std::string &newValue) {
this->currentFont.setFamily(newValue.c_str()); //
});
this->currentFontSize.valueChanged.connect([this](const int &newValue) {
this->currentFont.setSize(newValue); //
});
}
QFont &FontManager::getFont(Type type)
{
if (type == Medium)
return *_medium;
if (type == MediumBold)
return *_mediumBold;
if (type == MediumItalic)
return *_mediumItalic;
if (type == Small)
return *_small;
if (type == Large)
return *_large;
if (type == VeryLarge)
return *_veryLarge;
return *_medium;
return this->currentFont.getFont(type);
}
QFontMetrics &FontManager::getFontMetrics(Type type)
{
if (type == Medium)
return *_metricsMedium;
if (type == MediumBold)
return *_metricsMediumBold;
if (type == MediumItalic)
return *_metricsMediumItalic;
if (type == Small)
return *_metricsSmall;
if (type == Large)
return *_metricsLarge;
if (type == VeryLarge)
return *_metricsVeryLarge;
return this->currentFont.getFontMetrics(type);
}
return *_metricsMedium;
FontManager::FontData &FontManager::Font::getFontData(Type type)
{
switch (type) {
case Small:
return this->small;
case Medium:
return this->medium;
case MediumBold:
return this->mediumBold;
case MediumItalic:
return this->mediumItalic;
case Large:
return this->large;
case VeryLarge:
return this->veryLarge;
default:
qDebug() << "Unknown font type:" << type << ", defaulting to medium";
return this->medium;
}
}
QFont &FontManager::Font::getFont(Type type)
{
return this->getFontData(type).font;
}
QFontMetrics &FontManager::Font::getFontMetrics(Type type)
{
return this->getFontData(type).metrics;
}
} // namespace chatterino

View file

@ -2,52 +2,126 @@
#include <QFont>
#include <QFontMetrics>
#include <pajlada/settings/setting.hpp>
namespace chatterino {
class FontManager
{
public:
enum Type : char { Medium, MediumBold, MediumItalic, Small, Large, VeryLarge };
enum Type : uint8_t {
Small,
Medium,
MediumBold,
MediumItalic,
Large,
VeryLarge,
};
// FontManager is initialized only once, on first use
static FontManager &getInstance()
{
static FontManager instance;
return instance;
}
QFont &getFont(Type type);
QFontMetrics &getFontMetrics(Type type);
int getGeneration()
int getGeneration() const
{
return _generation;
return this->generation;
}
void incGeneration()
{
_generation++;
this->generation++;
}
private:
static FontManager instance;
pajlada::Settings::Setting<std::string> currentFontFamily;
pajlada::Settings::Setting<int> currentFontSize;
private:
FontManager();
QFont *_medium;
QFont *_mediumBold;
QFont *_mediumItalic;
QFont *_small;
QFont *_large;
QFont *_veryLarge;
struct FontData {
FontData(QFont &&_font)
: font(_font)
, metrics(this->font)
{
}
QFontMetrics *_metricsMedium;
QFontMetrics *_metricsMediumBold;
QFontMetrics *_metricsMediumItalic;
QFontMetrics *_metricsSmall;
QFontMetrics *_metricsLarge;
QFontMetrics *_metricsVeryLarge;
QFont font;
QFontMetrics metrics;
};
int _generation;
struct Font {
Font() = delete;
explicit Font(const char *fontFamilyName, int mediumSize)
: small(QFont(fontFamilyName, mediumSize - 4))
, medium(QFont(fontFamilyName, mediumSize))
, mediumBold(QFont(fontFamilyName, mediumSize, 50))
, mediumItalic(QFont(fontFamilyName, mediumSize, -1, true))
, large(QFont(fontFamilyName, mediumSize))
, veryLarge(QFont(fontFamilyName, mediumSize))
{
}
void setFamily(const char *newFamily)
{
this->small.font.setFamily(newFamily);
this->medium.font.setFamily(newFamily);
this->mediumBold.font.setFamily(newFamily);
this->mediumItalic.font.setFamily(newFamily);
this->large.font.setFamily(newFamily);
this->veryLarge.font.setFamily(newFamily);
this->updateMetrics();
}
void setSize(int newMediumSize)
{
this->small.font.setPointSize(newMediumSize - 4);
this->medium.font.setPointSize(newMediumSize);
this->mediumBold.font.setPointSize(newMediumSize);
this->mediumItalic.font.setPointSize(newMediumSize);
this->large.font.setPointSize(newMediumSize + 2);
this->veryLarge.font.setPointSize(newMediumSize + 4);
this->updateMetrics();
}
void updateMetrics()
{
this->small.metrics = QFontMetrics(this->small.font);
this->medium.metrics = QFontMetrics(this->medium.font);
this->mediumBold.metrics = QFontMetrics(this->mediumBold.font);
this->mediumItalic.metrics = QFontMetrics(this->mediumItalic.font);
this->large.metrics = QFontMetrics(this->large.font);
this->veryLarge.metrics = QFontMetrics(this->veryLarge.font);
}
FontData &getFontData(Type type);
QFont &getFont(Type type);
QFontMetrics &getFontMetrics(Type type);
FontData small;
FontData medium;
FontData mediumBold;
FontData mediumItalic;
FontData large;
FontData veryLarge;
};
// Future plans:
// Could have multiple fonts in here, such as "Menu font", "Application font", "Chat font"
Font currentFont;
int generation = 0;
};
} // namespace chatterino

View file

@ -18,27 +18,29 @@ inline messages::LazyLoadedImage *lli(EmoteManager &emoteManager, WindowManager
} // namespace
Resources::Resources(EmoteManager &emoteManager, WindowManager &windowManager)
: badgeStaff(lli(emoteManager, windowManager, ":/images/staff_bg.png"))
, badgeAdmin(lli(emoteManager, windowManager, ":/images/admin_bg.png"))
, badgeGlobalModerator(lli(emoteManager, windowManager, ":/images/globalmod_bg.png"))
, badgeModerator(lli(emoteManager, windowManager, ":/images/moderator_bg.png"))
, badgeTurbo(lli(emoteManager, windowManager, ":/images/turbo_bg.png"))
, badgeBroadcaster(lli(emoteManager, windowManager, ":/images/broadcaster_bg.png"))
, badgePremium(lli(emoteManager, windowManager, ":/images/twitchprime_bg.png"))
, badgeVerified(lli(emoteManager, windowManager, ":/images/verified.png", 0.25))
, cheerBadge100000(lli(emoteManager, windowManager, ":/images/cheer100000"))
, cheerBadge10000(lli(emoteManager, windowManager, ":/images/cheer10000"))
, cheerBadge5000(lli(emoteManager, windowManager, ":/images/cheer5000"))
, cheerBadge1000(lli(emoteManager, windowManager, ":/images/cheer1000"))
, cheerBadge100(lli(emoteManager, windowManager, ":/images/cheer100"))
, cheerBadge1(lli(emoteManager, windowManager, ":/images/cheer1"))
, buttonBan(lli(emoteManager, windowManager, ":/images/button_ban.png", 0.25))
, buttonTimeout(lli(emoteManager, windowManager, ":/images/button_timeout.png", 0.25))
Resources::Resources(EmoteManager &em, WindowManager &wm)
: emoteManager(em)
, windowManager(wm)
, badgeStaff(lli(em, wm, ":/images/staff_bg.png"))
, badgeAdmin(lli(em, wm, ":/images/admin_bg.png"))
, badgeGlobalModerator(lli(em, wm, ":/images/globalmod_bg.png"))
, badgeModerator(lli(em, wm, ":/images/moderator_bg.png"))
, badgeTurbo(lli(em, wm, ":/images/turbo_bg.png"))
, badgeBroadcaster(lli(em, wm, ":/images/broadcaster_bg.png"))
, badgePremium(lli(em, wm, ":/images/twitchprime_bg.png"))
, badgeVerified(lli(em, wm, ":/images/verified.png", 0.25))
, cheerBadge100000(lli(em, wm, ":/images/cheer100000"))
, cheerBadge10000(lli(em, wm, ":/images/cheer10000"))
, cheerBadge5000(lli(em, wm, ":/images/cheer5000"))
, cheerBadge1000(lli(em, wm, ":/images/cheer1000"))
, cheerBadge100(lli(em, wm, ":/images/cheer100"))
, cheerBadge1(lli(em, wm, ":/images/cheer1"))
, buttonBan(lli(em, wm, ":/images/button_ban.png", 0.25))
, buttonTimeout(lli(em, wm, ":/images/button_timeout.png", 0.25))
{
QString badgesUrl("https://badges.twitch.tv/v1/badges/global/display?language=en");
util::urlJsonFetch(badgesUrl, [this, &emoteManager, &windowManager](QJsonObject &root) {
util::urlJsonFetch(badgesUrl, [this](QJsonObject &root) {
QJsonObject sets = root.value("badge_sets").toObject();
for (QJsonObject::iterator it = sets.begin(); it != sets.end(); ++it) {
@ -51,7 +53,7 @@ Resources::Resources(EmoteManager &emoteManager, WindowManager &windowManager)
++versionIt) {
std::string kkey = versionIt.key().toStdString();
QJsonObject versionObj = versionIt.value().toObject();
BadgeVersion v(std::move(versionObj), emoteManager, windowManager);
BadgeVersion v(std::move(versionObj), this->emoteManager, this->windowManager);
versionsMap.emplace(kkey, v);
}
}
@ -75,24 +77,35 @@ Resources::BadgeVersion::BadgeVersion(QJsonObject &&root, EmoteManager &emoteMan
{
}
void Resources::Channel::loadData()
{
/*
if (this->loaded) {
return;
}
this->loaded = true;
if (this->id.empty()) {
//util::urlJsonFetch()
}
*/
}
void Resources::loadChannelData(const std::string &roomID, bool bypassCache)
{
qDebug() << "Load channel data for" << QString::fromStdString(roomID);
// Step 1: Get
QString url = "https://badges.twitch.tv/v1/badges/channels/" + QString::fromStdString(roomID) +
"/display?language=en";
util::urlJsonFetch(url, [this](QJsonObject &root) {
QJsonObject sets = root.value("badge_sets").toObject();
for (QJsonObject::iterator it = sets.begin(); it != sets.end(); ++it) {
QJsonObject versions = it.value().toObject().value("versions").toObject();
auto &badgeSet = this->badgeSets[it.key().toStdString()];
auto &versionsMap = badgeSet.versions;
for (auto versionIt = std::begin(versions); versionIt != std::end(versions);
++versionIt) {
std::string kkey = versionIt.key().toStdString();
QJsonObject versionObj = versionIt.value().toObject();
BadgeVersion v(std::move(versionObj), this->emoteManager, this->windowManager);
versionsMap.emplace(kkey, v);
}
}
this->dynamicBadgesLoaded = true;
});
}
} // namespace chatterino

View file

@ -12,6 +12,9 @@ class WindowManager;
class Resources
{
EmoteManager &emoteManager;
WindowManager &windowManager;
public:
explicit Resources(EmoteManager &emoteManager, WindowManager &windowManager);
@ -60,13 +63,9 @@ public:
messages::LazyLoadedImage *buttonTimeout;
struct Channel {
std::string id;
std::map<std::string, BadgeSet> badgeSets;
std::mutex globalMapMutex;
void loadData();
// std::atomic<bool> loaded = false;
bool loaded = false;
};
// channelId

View file

@ -95,7 +95,7 @@ SharedMessage TwitchMessageBuilder::parse(const Communi::IrcPrivateMessage *ircM
iterator = tags.find("display-name");
if (iterator == tags.end()) {
displayName = ircMessage->account();
displayName = b.userName;
} else {
displayName = iterator.value().toString();
}

View file

@ -7,6 +7,7 @@
#include <QComboBox>
#include <QDebug>
#include <QFile>
#include <QFontDialog>
#include <QFormLayout>
#include <QGroupBox>
#include <QLabel>
@ -108,7 +109,22 @@ void SettingsDialog::addTabs()
auto form = new QFormLayout();
auto combo = new QComboBox();
auto slider = new QSlider(Qt::Horizontal);
auto font = new QPushButton("select");
font->connect(font, &QPushButton::clicked, []() {
auto fontManager = FontManager::getInstance();
QFontDialog dialog(fontManager.getFont(FontManager::Medium));
dialog.connect(&dialog, &QFontDialog::fontSelected, [&dialog](const QFont &font) {
auto fontManager = FontManager::getInstance();
fontManager.currentFontFamily = font.family().toStdString();
fontManager.currentFontSize = font.pointSize();
});
dialog.show();
dialog.exec();
});
auto compactTabs = createCheckbox("Hide tab X", settings.hideTabX);
auto hidePreferencesButton = createCheckbox("Hide preferences button (ctrl+p to show)",
settings.hidePreferencesButton);