diff --git a/lib/settings b/lib/settings index 4bf19ff04..c05bec45f 160000 --- a/lib/settings +++ b/lib/settings @@ -1 +1 @@ -Subproject commit 4bf19ff04c77c51883886af2586753df0638ffa4 +Subproject commit c05bec45f3ccb829d5014b46b6a02ee9e9c6b81f diff --git a/src/application.cpp b/src/application.cpp index 575f9bdd9..7d4d8bce7 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -1,18 +1,25 @@ #include "application.hpp" #include "colorscheme.hpp" +#include "logging/loggingmanager.hpp" #include "settingsmanager.hpp" namespace chatterino { +// this class is responsible for handling the workflow of Chatterino +// It will create the instances of the major classes, and connect their signals to each other + Application::Application() - : windowManager(this->channelManager) + : windowManager(this->channelManager, this->colorScheme) + , colorScheme(this->windowManager) , emoteManager(this->windowManager, this->resources) , resources(this->emoteManager, this->windowManager) , channelManager(this->windowManager, this->emoteManager, this->ircManager) , ircManager(this->channelManager, this->resources, this->emoteManager, this->windowManager) + , messageFactory(this->resources, this->emoteManager, this->windowManager) { // TODO(pajlada): Get rid of all singletons - ColorScheme::getInstance().init(this->windowManager); + logging::init(); + SettingsManager::getInstance().load(); // Initialize everything we need this->emoteManager.loadGlobalEmotes(); @@ -21,11 +28,28 @@ Application::Application() SettingsManager::getInstance().updateWordTypeMask(); this->windowManager.load(); + + this->ircManager.onPrivateMessage.connect([=](Communi::IrcPrivateMessage *message) { + QString channelName = message->target().mid(1); + + auto channel = this->channelManager.getChannel(channelName); + + if (channel == nullptr) { + // The message doesn't have a channel we listen to + return; + } + + messages::MessageParseArgs args; + + this->messageFactory.buildMessage(message, *channel.get(), args); + }); } Application::~Application() { this->windowManager.save(); + + chatterino::SettingsManager::getInstance().save(); } int Application::run(QApplication &qtApp) diff --git a/src/application.hpp b/src/application.hpp index 93e929600..196fd7100 100644 --- a/src/application.hpp +++ b/src/application.hpp @@ -1,8 +1,10 @@ #pragma once #include "channelmanager.hpp" +#include "colorscheme.hpp" #include "emotemanager.hpp" #include "ircmanager.hpp" +#include "messagefactory.hpp" #include "resources.hpp" #include "windowmanager.hpp" @@ -19,10 +21,12 @@ public: int run(QApplication &qtApp); WindowManager windowManager; + ColorScheme colorScheme; EmoteManager emoteManager; Resources resources; ChannelManager channelManager; IrcManager ircManager; + MessageFactory messageFactory; }; } // namespace chatterino diff --git a/src/colorscheme.cpp b/src/colorscheme.cpp index 2ae4f5059..8c4b9d6f9 100644 --- a/src/colorscheme.cpp +++ b/src/colorscheme.cpp @@ -8,62 +8,65 @@ namespace chatterino { -void ColorScheme::init(WindowManager &windowManager) +namespace detail { + +double getMultiplierByTheme(const std::string &themeName) { - static bool initiated = false; - - if (!initiated) { - initiated = true; - ColorScheme::getInstance().update(); - - SettingsManager::getInstance().theme.valueChanged.connect([](const QString &) { - ColorScheme::getInstance().update(); // - }); - - SettingsManager::getInstance().themeHue.valueChanged.connect([](const float &) { - ColorScheme::getInstance().update(); // - }); - - ColorScheme::getInstance().updated.connect([&windowManager] { - windowManager.repaintVisibleChatWidgets(); // - }); + if (themeName == "Light") { + return 0.8; + } else if (themeName == "White") { + return 1.0; + } else if (themeName == "Black") { + return -1.0; + } else if (themeName == "Dark") { + return -0.8; } + + return -0.8; +} + +} // namespace detail + +ColorScheme::ColorScheme(WindowManager &windowManager) +{ + this->update(); + + SettingsManager::getInstance().themeName.getValueChangedSignal().connect([=](const auto &) { + this->update(); // + }); + + SettingsManager::getInstance().themeHue.getValueChangedSignal().connect([=](const auto &) { + this->update(); // + }); + + this->updated.connect([&windowManager] { + windowManager.repaintVisibleChatWidgets(); // + }); } void ColorScheme::update() { - QString theme = SettingsManager::getInstance().theme.get(); - theme = theme.toLower(); + SettingsManager &settings = SettingsManager::getInstance(); - qreal hue = SettingsManager::getInstance().themeHue.get(); - - if (theme == "light") { - setColors(hue, 0.8); - } else if (theme == "white") { - setColors(hue, 1); - } else if (theme == "black") { - setColors(hue, -1); - } else { - setColors(hue, -0.8); - } + this->setColors(settings.themeHue, detail::getMultiplierByTheme(settings.themeName)); } // hue: theme color (0 - 1) -// multiplyer: 1 = white, 0.8 = light, -0.8 dark, -1 black -void ColorScheme::setColors(float hue, float multiplyer) +// multiplier: 1 = white, 0.8 = light, -0.8 dark, -1 black +void ColorScheme::setColors(double hue, double multiplier) { - IsLightTheme = multiplyer > 0; + lightTheme = multiplier > 0; bool hasDarkBorder = false; SystemMessageColor = QColor(140, 127, 127); - auto getColor = [multiplyer](qreal h, qreal s, qreal l, qreal a = 1.0) { - return QColor::fromHslF(h, s, (((l - 0.5) * multiplyer) + 0.5), a); + auto getColor = [multiplier](double h, double s, double l, double a = 1.0) { + return QColor::fromHslF(h, s, (((l - 0.5) * multiplier) + 0.5), a); }; DropPreviewBackground = getColor(hue, 0.5, 0.5, 0.6); - Text = TextCaret = IsLightTheme ? QColor(0, 0, 0) : QColor(255, 255, 255); + Text = TextCaret = lightTheme ? QColor(0, 0, 0) : QColor(255, 255, 255); // tab if (hasDarkBorder) { @@ -119,26 +122,26 @@ void ColorScheme::setColors(float hue, float multiplyer) updated(); } -void ColorScheme::fillLookupTableValues(qreal (&array)[360], qreal from, qreal to, qreal fromValue, - qreal toValue) +void ColorScheme::fillLookupTableValues(double (&array)[360], double from, double to, + double fromValue, double toValue) { - qreal diff = toValue - fromValue; + double diff = toValue - fromValue; int start = from * LOOKUP_COLOR_COUNT; int end = to * LOOKUP_COLOR_COUNT; int length = end - start; for (int i = 0; i < length; i++) { - array[start + i] = fromValue + (diff * ((qreal)i / length)); + array[start + i] = fromValue + (diff * ((double)i / length)); } } void ColorScheme::normalizeColor(QColor &color) { - // qreal l = color.lightnessF(); - // qreal s = color.saturationF(); - // qreal x = this->colorLookupTable[std::max(0, color.hue())]; - // qreal newL = (l - 1) * x + 1; + // double l = color.lightnessF(); + // double s = color.saturationF(); + // double x = this->colorLookupTable[std::max(0, color.hue())]; + // double newL = (l - 1) * x + 1; // newL = s * newL + (1 - s) * l; @@ -146,16 +149,16 @@ void ColorScheme::normalizeColor(QColor &color) // color.setHslF(color.hueF(), s, newL); - qreal l = color.lightnessF(); - qreal s = color.saturationF(); + double l = color.lightnessF(); + double s = color.saturationF(); int h = std::max(0, color.hue()); - qreal x = this->middleLookupTable[h]; + double x = this->middleLookupTable[h]; x = s * 0.5 + (1 - s) * x; - qreal min = this->minLookupTable[h]; + double min = this->minLookupTable[h]; min = (1 - s) * 0.5 + s * min; - qreal newL; + double newL; if (l < x) { newL = l * ((x - min) / x) + min; @@ -168,7 +171,7 @@ void ColorScheme::normalizeColor(QColor &color) color.setHslF(color.hueF(), s, newL); - // qreal newL = (l - 1) * x + 1; + // double newL = (l - 1) * x + 1; // newL = s * newL + (1 - s) * l; diff --git a/src/colorscheme.hpp b/src/colorscheme.hpp index 91d7d3c07..17a77d245 100644 --- a/src/colorscheme.hpp +++ b/src/colorscheme.hpp @@ -11,7 +11,12 @@ class WindowManager; class ColorScheme { public: - bool IsLightTheme; + explicit ColorScheme(WindowManager &windowManager); + + inline bool isLightTheme() const + { + return this->lightTheme; + } QString InputStyleSheet; @@ -62,13 +67,6 @@ public: const int HighlightColorCount = 3; QColor HighlightColors[3]; - static ColorScheme &getInstance() - { - static ColorScheme instance; - - return instance; - } - void init(WindowManager &windowManager); void normalizeColor(QColor &color); @@ -77,18 +75,15 @@ public: boost::signals2::signal updated; private: - ColorScheme() - : updated() - { - } + void setColors(double hue, double multiplier); - void setColors(float hue, float multiplyer); + double middleLookupTable[360] = {}; + double minLookupTable[360] = {}; - qreal middleLookupTable[360] = {}; - qreal minLookupTable[360] = {}; + void fillLookupTableValues(double (&array)[360], double from, double to, double fromValue, + double toValue); - void fillLookupTableValues(qreal (&array)[360], qreal from, qreal to, qreal fromValue, - qreal toValue); + bool lightTheme; }; } // namespace chatterino diff --git a/src/emojis.cpp b/src/emojis.cpp index 0673b7e18..84d075827 100644 --- a/src/emojis.cpp +++ b/src/emojis.cpp @@ -9,116 +9,4 @@ namespace chatterino { QRegularExpression Emojis::findShortCodesRegex(":([-+\\w]+):"); -QMap Emojis::shortCodeToEmoji; -QMap Emojis::emojiToShortCode; -QMap> Emojis::firstEmojiChars; - -ConcurrentMap Emojis::imageCache; - -QString Emojis::replaceShortCodes(const QString &text) -{ - // TODO: Implement this xD - return text; -} - -void Emojis::parseEmojis(std::vector> &vector, - const QString &text) -{ - long lastSlice = 0; - - for (auto i = 0; i < text.length() - 1; i++) { - if (!text.at(i).isLowSurrogate()) { - auto iter = firstEmojiChars.find(text.at(i)); - - if (iter != firstEmojiChars.end()) { - for (auto j = std::min(8, text.length() - i); j > 0; j--) { - QString emojiString = text.mid(i, 2); - auto emojiIter = iter.value().find(emojiString); - - if (emojiIter != iter.value().end()) { - QString url = "https://cdnjs.cloudflare.com/ajax/libs/" - "emojione/2.2.6/assets/png/" + - emojiIter.value() + ".png"; - - if (i - lastSlice != 0) { - vector.push_back(std::tuple( - nullptr, text.mid(lastSlice, i - lastSlice))); - } - - vector.push_back(std::tuple( - imageCache.getOrAdd(url, - [/*&url*/] { - /* TODO: re-implement - return new messages::LazyLoadedImage(url, - 0.35); // - */ - return nullptr; - }), - QString())); - - i += j - 1; - - lastSlice = i + 1; - - break; - } - } - } - } - } - - if (lastSlice < text.length()) { - vector.push_back( - std::tuple(nullptr, text.mid(lastSlice))); - } -} - -void Emojis::loadEmojis() -{ - QFile file(":/emojidata.txt"); - file.open(QFile::ReadOnly); - QTextStream in(&file); - - uint emotes[4]; - - while (!in.atEnd()) { - QString line = in.readLine(); - - if (line.length() < 3 || line.at(0) == '#') - continue; - - QStringList a = line.split(' '); - if (a.length() < 2) - continue; - - QStringList b = a.at(1).split('-'); - if (b.length() < 1) - continue; - - int i = 0; - - for (const QString &item : b) { - emotes[i++] = QString(item).toUInt(nullptr, 16); - } - - shortCodeToEmoji.insert(a.at(0), Emojis::EmojiData{QString::fromUcs4(emotes, i), a.at(1)}); - } - - for (auto const &emoji : shortCodeToEmoji.toStdMap()) { - emojiToShortCode.insert(emoji.second.value, emoji.first); - } - - for (auto const &emoji : shortCodeToEmoji.toStdMap()) { - auto iter = firstEmojiChars.find(emoji.first.at(0)); - - if (iter != firstEmojiChars.end()) { - iter.value().insert(emoji.second.value, emoji.second.value); - continue; - } - - firstEmojiChars.insert(emoji.first.at(0), - QMap{{emoji.second.value, emoji.second.code}}); - } -} - } // namespace chatterino diff --git a/src/emojis.hpp b/src/emojis.hpp index 7fe7ea8a1..9418daa3f 100644 --- a/src/emojis.hpp +++ b/src/emojis.hpp @@ -11,33 +11,18 @@ namespace chatterino { +struct EmojiData { + QString value; + QString code; +}; + class Emojis { public: - static void parseEmojis(std::vector> &vector, - const QString &text); - - static void loadEmojis(); - static QString replaceShortCodes(const QString &text); - struct EmojiData { - QString value; - QString code; - }; - private: static QRegularExpression findShortCodesRegex; - - static QMap shortCodeToEmoji; - static QMap emojiToShortCode; - static QMap> firstEmojiChars; - - static ConcurrentMap imageCache; - - Emojis() - { - } }; } // namespace chatterino diff --git a/src/emotemanager.cpp b/src/emotemanager.cpp index 4b8bbc3b9..727dd5bb9 100644 --- a/src/emotemanager.cpp +++ b/src/emotemanager.cpp @@ -29,6 +29,7 @@ EmoteManager::EmoteManager(WindowManager &_windowManager, Resources &_resources) void EmoteManager::loadGlobalEmotes() { + this->loadEmojis(); this->loadBTTVEmotes(); this->loadFFZEmotes(); } @@ -39,7 +40,7 @@ void EmoteManager::reloadBTTVChannelEmotes(const QString &channelName, printf("[EmoteManager] Reload BTTV Channel Emotes for channel %s\n", qPrintable(channelName)); QString url("https://api.betterttv.net/2/channels/" + channelName); - util::urlJsonFetch(url, [this, &channelEmoteMap](QJsonObject &rootNode) { + util::urlFetchJSON(url, [this, &channelEmoteMap](QJsonObject &rootNode) { channelEmoteMap.clear(); auto emotesNode = rootNode.value("emotes").toArray(); @@ -77,7 +78,7 @@ void EmoteManager::reloadFFZChannelEmotes( QString url("http://api.frankerfacez.com/v1/room/" + channelName); - util::urlJsonFetch(url, [this, &channelEmoteMap](QJsonObject &rootNode) { + util::urlFetchJSON(url, [this, &channelEmoteMap](QJsonObject &rootNode) { channelEmoteMap.clear(); auto setsNode = rootNode.value("sets").toObject(); @@ -148,6 +149,116 @@ ConcurrentMap &EmoteManager::getMiscImageF return _miscImageFromCache; } +void EmoteManager::loadEmojis() +{ + QFile file(":/emojidata.txt"); + file.open(QFile::ReadOnly); + QTextStream in(&file); + + uint unicodeBytes[4]; + + while (!in.atEnd()) { + // Line example: sunglasses 1f60e + QString line = in.readLine(); + + if (line.at(0) == '#') { + // Ignore lines starting with # (comments) + continue; + } + + QStringList parts = line.split(' '); + if (parts.length() < 2) { + continue; + } + + QString shortCode = parts[0]; + QString code = parts[1]; + + QStringList unicodeCharacters = code.split('-'); + if (unicodeCharacters.length() < 1) { + continue; + } + + int numUnicodeBytes = 0; + + for (const QString &unicodeCharacter : unicodeCharacters) { + unicodeBytes[numUnicodeBytes++] = QString(unicodeCharacter).toUInt(nullptr, 16); + } + + EmojiData emojiData{ + QString::fromUcs4(unicodeBytes, numUnicodeBytes), // + code, // + }; + + shortCodeToEmoji.insert(shortCode, emojiData); + emojiToShortCode.insert(emojiData.value, shortCode); + } + + /* + for (auto const &emoji : shortCodeToEmoji.toStdMap()) { + auto iter = firstEmojiChars.find(emoji.first.at(0)); + + if (iter != firstEmojiChars.end()) { + iter.value().insert(emoji.second.value, emoji.second.value); + continue; + } + + firstEmojiChars.insert(emoji.first.at(0), + QMap{{emoji.second.value, emoji.second.code}}); + } + */ +} + +void EmoteManager::parseEmojis( + std::vector> &vector, const QString &text) +{ + // TODO(pajlada): Add this method to EmoteManager instead + long lastSlice = 0; + + for (auto i = 0; i < text.length() - 1; i++) { + if (!text.at(i).isLowSurrogate()) { + auto iter = firstEmojiChars.find(text.at(i)); + + if (iter != firstEmojiChars.end()) { + for (auto j = std::min(8, text.length() - i); j > 0; j--) { + QString emojiString = text.mid(i, 2); + auto emojiIter = iter.value().find(emojiString); + + if (emojiIter != iter.value().end()) { + QString url = "https://cdnjs.cloudflare.com/ajax/libs/" + "emojione/2.2.6/assets/png/" + + emojiIter.value() + ".png"; + + if (i - lastSlice != 0) { + vector.push_back(std::tuple( + nullptr, text.mid(lastSlice, i - lastSlice))); + } + + vector.push_back(std::tuple( + emojis.getOrAdd(url, + [this, &url] { + return new LazyLoadedImage( + *this, this->windowManager, url, 0.35); // + }), + QString())); + + i += j - 1; + + lastSlice = i + 1; + + break; + } + } + } + } + } + + if (lastSlice < text.length()) { + vector.push_back( + std::tuple(nullptr, text.mid(lastSlice))); + } +} + void EmoteManager::loadBTTVEmotes() { // bttv diff --git a/src/emotemanager.hpp b/src/emotemanager.hpp index cc68a70c7..3f5ee5814 100644 --- a/src/emotemanager.hpp +++ b/src/emotemanager.hpp @@ -3,11 +3,13 @@ #define GIF_FRAME_LENGTH 33 #include "concurrentmap.hpp" +#include "emojis.hpp" #include "messages/lazyloadedimage.hpp" #include "twitch/emotevalue.hpp" #include #include +#include #include #include @@ -60,16 +62,47 @@ private: WindowManager &windowManager; Resources &resources; - ConcurrentMap bttvChannelEmotes; - ConcurrentMap ffzChannelEmotes; + // Emojis + // shortCodeToEmoji maps strings like ":sunglasses:" to the unicode character + QMap shortCodeToEmoji; + // emojiToShortCode maps the unicode character to the shortcode like ":sunglasses:" + QMap emojiToShortCode; + + // TODO(pajlada): Figure out what this is for + QMap> firstEmojiChars; + + ConcurrentMap emojis; + + void loadEmojis(); + +public: + void parseEmojis(std::vector> &vector, + const QString &text); + +private: + // Twitch emotes ConcurrentMap _twitchEmotes; - ConcurrentMap _bttvEmotes; - ConcurrentMap _ffzEmotes; - ConcurrentMap _chatterinoEmotes; - ConcurrentMap _bttvChannelEmoteFromCaches; - ConcurrentMap _ffzChannelEmoteFromCaches; ConcurrentMap _twitchEmoteFromCache; + + // BTTV emotes + ConcurrentMap bttvChannelEmotes; + ConcurrentMap _bttvEmotes; + ConcurrentMap _bttvChannelEmoteFromCaches; + + void loadBTTVEmotes(); + + // FFZ emotes + ConcurrentMap ffzChannelEmotes; + ConcurrentMap _ffzEmotes; + ConcurrentMap _ffzChannelEmoteFromCaches; + + void loadFFZEmotes(); + + // Chatterino emotes + ConcurrentMap _chatterinoEmotes; + + // ??? ConcurrentMap _miscImageFromCache; boost::signals2::signal _gifUpdateTimerSignal; @@ -80,9 +113,6 @@ private: // methods static QString getTwitchEmoteLink(long id, qreal &scale); - - void loadFFZEmotes(); - void loadBTTVEmotes(); }; } // namespace chatterino diff --git a/src/fontmanager.cpp b/src/fontmanager.cpp index e0005dc34..71fba83d6 100644 --- a/src/fontmanager.cpp +++ b/src/fontmanager.cpp @@ -9,10 +9,10 @@ FontManager::FontManager() , currentFontSize("/appearance/currentFontSize", 14) , currentFont(this->currentFontFamily.getValue().c_str(), currentFontSize.getValue()) { - this->currentFontFamily.valueChanged.connect([this](const std::string &newValue) { + this->currentFontFamily.getValueChangedSignal().connect([this](const std::string &newValue) { this->currentFont.setFamily(newValue.c_str()); // }); - this->currentFontSize.valueChanged.connect([this](const int &newValue) { + this->currentFontSize.getValueChangedSignal().connect([this](const int &newValue) { this->currentFont.setSize(newValue); // }); } diff --git a/src/ircmanager.cpp b/src/ircmanager.cpp index 5c17d524d..081f4b9bb 100644 --- a/src/ircmanager.cpp +++ b/src/ircmanager.cpp @@ -8,6 +8,7 @@ #include "twitch/twitchmessagebuilder.hpp" #include "twitch/twitchparsemessage.hpp" #include "twitch/twitchuser.hpp" +#include "util/urlfetch.hpp" #include "windowmanager.hpp" #include @@ -132,28 +133,29 @@ void IrcManager::refreshIgnoredUsers(const QString &username, const QString &oau void IrcManager::refreshTwitchEmotes(const QString &username, const QString &oauthClient, const QString &oauthToken) { - QNetworkRequest req(QUrl("https://api.twitch.tv/kraken/users/" + username + - "/emotes?oauth_token=" + oauthToken + "&client_id=" + oauthClient)); - QNetworkReply *reply = _accessManager.get(req); + QString url("https://api.twitch.tv/kraken/users/" + username + + "/emotes?oauth_token=" + oauthToken + "&client_id=" + oauthClient); - QObject::connect(reply, &QNetworkReply::finished, [=] { - QByteArray data = reply->readAll(); - QJsonDocument jsonDoc(QJsonDocument::fromJson(data)); - QJsonObject root = jsonDoc.object(); + if (true) { + util::urlFetchJSONTimeout(url, + [=](QJsonObject &root) { + // nextLink = + // root.value("_links").toObject().value("next").toString(); - // nextLink = - // root.value("_links").toObject().value("next").toString(); + auto blocks = root.value("blocks").toArray(); - auto blocks = root.value("blocks").toArray(); - - _twitchBlockedUsersMutex.lock(); - for (QJsonValue block : blocks) { - QJsonObject user = block.toObject().value("user").toObject(); - // display_name - _twitchBlockedUsers.insert(user.value("name").toString().toLower(), true); - } - _twitchBlockedUsersMutex.unlock(); - }); + _twitchBlockedUsersMutex.lock(); + for (QJsonValue block : blocks) { + QJsonObject user = block.toObject().value("user").toObject(); + // display_name + _twitchBlockedUsers.insert( + user.value("name").toString().toLower(), true); + } + _twitchBlockedUsersMutex.unlock(); + qDebug() << "XD"; + }, + 3000, &this->_accessManager); + } } void IrcManager::beginConnecting() @@ -209,14 +211,13 @@ void IrcManager::sendMessage(const QString &channelName, const QString &message) this->connectionMutex.unlock(); // DEBUGGING -#if 0 + /* Communi::IrcPrivateMessage msg(this->readConnection.get()); QStringList params{"#pajlada", message}; qDebug() << params; - /* if (message == "COMIC SANS LOL") { FontManager::getInstance().currentFontFamily = "Comic Sans MS"; } else if (message == "ARIAL LOL") { @@ -224,14 +225,13 @@ void IrcManager::sendMessage(const QString &channelName, const QString &message) } else if (message == "WINGDINGS LOL") { FontManager::getInstance().currentFontFamily = "Wingdings"; } - */ msg.setParameters(params); msg.setPrefix("pajlada!pajlada@pajlada"); this->privateMessageReceived(&msg); -#endif + */ } void IrcManager::joinChannel(const QString &channelName) @@ -260,6 +260,7 @@ void IrcManager::partChannel(const QString &channelName) void IrcManager::privateMessageReceived(Communi::IrcPrivateMessage *message) { + this->onPrivateMessage.invoke(message); auto c = this->channelManager.getChannel(message->target().mid(1)); if (c != nullptr) { diff --git a/src/ircmanager.hpp b/src/ircmanager.hpp index a6f2eea23..c9200a188 100644 --- a/src/ircmanager.hpp +++ b/src/ircmanager.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -50,6 +51,8 @@ public: const twitch::TwitchUser &getUser() const; void setUser(const twitch::TwitchUser &account); + pajlada::Signals::Signal onPrivateMessage; + private: ChannelManager &channelManager; Resources &resources; diff --git a/src/main.cpp b/src/main.cpp index 528521bf8..54f8a118f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,20 +1,8 @@ #include "application.hpp" -#include "channelmanager.hpp" -#include "colorscheme.hpp" -#include "emojis.hpp" -#include "emotemanager.hpp" -#include "ircmanager.hpp" -#include "logging/loggingmanager.hpp" -#include "resources.hpp" -#include "settingsmanager.hpp" -#include "widgets/mainwindow.hpp" -#include "windowmanager.hpp" #include -#include #include #include -#include #include namespace { @@ -67,10 +55,6 @@ int main(int argc, char *argv[]) return 1; } - chatterino::logging::init(); - chatterino::SettingsManager::getInstance().load(); - chatterino::Emojis::loadEmojis(); - int ret = 0; { @@ -83,8 +67,6 @@ int main(int argc, char *argv[]) // Application will go out of scope here and deinitialize itself } - chatterino::SettingsManager::getInstance().save(); - // Save settings pajlada::Settings::SettingManager::save(); diff --git a/src/messagefactory.cpp b/src/messagefactory.cpp index 0d1dc8fc4..30ec947f7 100644 --- a/src/messagefactory.cpp +++ b/src/messagefactory.cpp @@ -1,6 +1,20 @@ -#include "messagefactory.hpp" - -MessageFactory::MessageFactory() -{ - -} +#include "messagefactory.hpp" + +namespace chatterino { + +MessageFactory::MessageFactory(Resources &_resources, EmoteManager &_emoteManager, + WindowManager &_windowManager) + : resources(_resources) + , emoteManager(_emoteManager) + , windowManager(_windowManager) +{ +} + +messages::SharedMessage MessageFactory::buildMessage(Communi::IrcPrivateMessage *message, + Channel &channel, + const messages::MessageParseArgs &args) +{ + return nullptr; +} + +} // namespace chatterino diff --git a/src/messagefactory.hpp b/src/messagefactory.hpp index b27195d75..a72e3320e 100644 --- a/src/messagefactory.hpp +++ b/src/messagefactory.hpp @@ -1,11 +1,26 @@ -#ifndef MESSAGEFACTORY_HPP -#define MESSAGEFACTORY_HPP - - -class MessageFactory -{ -public: - MessageFactory(); -}; - -#endif // MESSAGEFACTORY_HPP \ No newline at end of file +#pragma once + +#include "messages/message.hpp" + +namespace chatterino { + +class Resources; +class EmoteManager; +class WindowManager; + +class MessageFactory +{ +public: + explicit MessageFactory(Resources &_resources, EmoteManager &_emoteManager, + WindowManager &_windowManager); + + messages::SharedMessage buildMessage(Communi::IrcPrivateMessage *message, Channel &channel, + const messages::MessageParseArgs &args); + +private: + Resources &resources; + EmoteManager &emoteManager; + WindowManager &windowManager; +}; + +} // namespace chatterino diff --git a/src/messages/limitedqueuesnapshot.hpp b/src/messages/limitedqueuesnapshot.hpp index 479161cbc..aa2fffcc4 100644 --- a/src/messages/limitedqueuesnapshot.hpp +++ b/src/messages/limitedqueuesnapshot.hpp @@ -10,28 +10,29 @@ template class LimitedQueueSnapshot { public: - LimitedQueueSnapshot(std::shared_ptr> vector, int offset, int size) - : _vector(vector) - , _offset(offset) - , _length(size) + LimitedQueueSnapshot(std::shared_ptr> _vector, std::size_t _offset, + std::size_t _size) + : vector(_vector) + , offset(_offset) + , length(_size) { } - int getSize() + std::size_t getLength() { - return _length; + return length; } - T const &operator[](int index) const + T const &operator[](std::size_t index) const { - return _vector->at(index + _offset); + return vector->at(index + offset); } private: - std::shared_ptr> _vector; + std::shared_ptr> vector; - int _offset; - int _length; + std::size_t offset; + std::size_t length; }; } // namespace messages diff --git a/src/messages/message.cpp b/src/messages/message.cpp index 119ffef5c..36ec05263 100644 --- a/src/messages/message.cpp +++ b/src/messages/message.cpp @@ -20,12 +20,14 @@ namespace chatterino { namespace messages { +/* Message::Message(const QString &text) : text(text) { this->words.push_back( Word(text, Word::Text, ColorScheme::getInstance().SystemMessageColor, text, QString())); } +*/ Message::Message(const QString &text, const std::vector &words) : text(text) diff --git a/src/messages/message.hpp b/src/messages/message.hpp index 533bc8c82..f6a843f41 100644 --- a/src/messages/message.hpp +++ b/src/messages/message.hpp @@ -23,7 +23,7 @@ typedef std::shared_ptr SharedMessage; class Message { public: - explicit Message(const QString &text); + // explicit Message(const QString &text); explicit Message(const QString &text, const std::vector &words); bool getCanHighlightTab() const; diff --git a/src/messages/messagebuilder.cpp b/src/messages/messagebuilder.cpp index 5171287f4..091e947a6 100644 --- a/src/messages/messagebuilder.cpp +++ b/src/messages/messagebuilder.cpp @@ -33,17 +33,21 @@ void MessageBuilder::appendTimestamp(time_t time) { char timeStampBuffer[69]; + // TODO(pajlada): Fix this + QColor systemMessageColor(140, 127, 127); + // QColor &systemMessageColor = ColorScheme::getInstance().SystemMessageColor; + // Add word for timestamp with no seconds strftime(timeStampBuffer, 69, "%H:%M", localtime(&time)); QString timestampNoSeconds(timeStampBuffer); - appendWord(Word(timestampNoSeconds, Word::TimestampNoSeconds, - ColorScheme::getInstance().SystemMessageColor, QString(), QString())); + appendWord(Word(timestampNoSeconds, Word::TimestampNoSeconds, systemMessageColor, QString(), + QString())); // Add word for timestamp with seconds strftime(timeStampBuffer, 69, "%H:%M:%S", localtime(&time)); QString timestampWithSeconds(timeStampBuffer); - appendWord(Word(timestampWithSeconds, Word::TimestampWithSeconds, - ColorScheme::getInstance().SystemMessageColor, QString(), QString())); + appendWord(Word(timestampWithSeconds, Word::TimestampWithSeconds, systemMessageColor, QString(), + QString())); } QString MessageBuilder::matchLink(const QString &string) diff --git a/src/messages/word.hpp b/src/messages/word.hpp index c5395a875..0cee04635 100644 --- a/src/messages/word.hpp +++ b/src/messages/word.hpp @@ -75,7 +75,7 @@ public: ButtonTimeout = (1 << 22), EmojiImage = (1 << 23), - EmojiText = (1 << 34), + EmojiText = (1 << 24), Default = TimestampNoSeconds | Badges | Username | BitsStatic | FfzEmoteImage | BttvEmoteImage | BttvGifEmoteImage | TwitchEmoteImage | BitsAmount | Text | @@ -85,6 +85,7 @@ public: Word() { } + explicit Word(LazyLoadedImage *_image, Type getType, const QString ©text, const QString &getTooltip, const Link &getLink = Link()); explicit Word(const QString &_text, Type getType, const QColor &getColor, diff --git a/src/resources.cpp b/src/resources.cpp index 6b75afd76..8cb8cd39a 100644 --- a/src/resources.cpp +++ b/src/resources.cpp @@ -40,7 +40,7 @@ Resources::Resources(EmoteManager &em, WindowManager &wm) { QString badgesUrl("https://badges.twitch.tv/v1/badges/global/display?language=en"); - util::urlJsonFetch(badgesUrl, [this](QJsonObject &root) { + util::urlFetchJSON(badgesUrl, [this](QJsonObject &root) { QJsonObject sets = root.value("badge_sets").toObject(); for (QJsonObject::iterator it = sets.begin(); it != sets.end(); ++it) { @@ -86,7 +86,7 @@ void Resources::loadChannelData(const std::string &roomID, bool bypassCache) QString url = "https://badges.twitch.tv/v1/badges/channels/" + QString::fromStdString(roomID) + "/display?language=en"; - util::urlJsonFetch(url, [this](QJsonObject &root) { + util::urlFetchJSON(url, [this](QJsonObject &root) { QJsonObject sets = root.value("badge_sets").toObject(); for (QJsonObject::iterator it = sets.begin(); it != sets.end(); ++it) { diff --git a/src/settingsmanager.cpp b/src/settingsmanager.cpp index 391a0ab5c..fe5bc49f5 100644 --- a/src/settingsmanager.cpp +++ b/src/settingsmanager.cpp @@ -11,15 +11,15 @@ namespace chatterino { SettingsManager::SettingsManager() : _settings(Path::getAppdataPath() + "settings.ini", QSettings::IniFormat) - , theme(_settingsItems, "theme", "dark") - , themeHue(_settingsItems, "themeHue", 0) + , showTimestamps("/appearance/messages/showTimestamps", true) + , showTimestampSeconds("/appearance/messages/showTimestampSeconds", true) + , showBadges("/appearance/messages/showBadges", true) + , themeName("/appearance/theme/name", "Dark") + , themeHue("/appearance/theme/hue", 0.0) , selectedUser(_settingsItems, "selectedUser", "") , emoteScale(_settingsItems, "emoteScale", 1.0) , mouseScrollMultiplier(_settingsItems, "mouseScrollMultiplier", 1.0) , scaleEmotesByLineHeight(_settingsItems, "scaleEmotesByLineHeight", false) - , showTimestamps("/appearance/messages/showTimestamps", true) - , showTimestampSeconds("/appearance/messages/showTimestampSeconds", true) - , showBadges("/appearance/messages/showBadges", true) , showLastMessageIndicator(_settingsItems, "showLastMessageIndicator", false) , allowDouplicateMessages(_settingsItems, "allowDouplicateMessages", true) , linksDoubleClickOnly(_settingsItems, "linksDoubleClickOnly", false) diff --git a/src/settingsmanager.hpp b/src/settingsmanager.hpp index a300ef877..767cc3619 100644 --- a/src/settingsmanager.hpp +++ b/src/settingsmanager.hpp @@ -42,10 +42,10 @@ public: pajlada::Settings::Setting showTimestamps; pajlada::Settings::Setting showTimestampSeconds; pajlada::Settings::Setting showBadges; + pajlada::Settings::Setting themeName; + pajlada::Settings::Setting themeHue; // Settings - Setting theme; - Setting themeHue; Setting selectedUser; Setting emoteScale; Setting mouseScrollMultiplier; diff --git a/src/twitch/twitchmessagebuilder.cpp b/src/twitch/twitchmessagebuilder.cpp index 90fce4096..b7dbb0de8 100644 --- a/src/twitch/twitchmessagebuilder.cpp +++ b/src/twitch/twitchmessagebuilder.cpp @@ -60,6 +60,8 @@ SharedMessage TwitchMessageBuilder::parse(const Communi::IrcPrivateMessage *ircM // badges iterator = tags.find("badges"); + ColorScheme &colorScheme = windowManager.colorScheme; + const auto &channelResources = resources.channels[roomID]; if (iterator != tags.end()) { @@ -69,7 +71,7 @@ SharedMessage TwitchMessageBuilder::parse(const Communi::IrcPrivateMessage *ircM } // color - QColor usernameColor = ColorScheme::getInstance().SystemMessageColor; + QColor &usernameColor = colorScheme.SystemMessageColor; iterator = tags.find("color"); if (iterator != tags.end()) { @@ -79,7 +81,7 @@ SharedMessage TwitchMessageBuilder::parse(const Communi::IrcPrivateMessage *ircM // channel name if (args.includeChannelName) { QString channelName("#" + channel->getName()); - b.appendWord(Word(channelName, Word::Misc, ColorScheme::getInstance().SystemMessageColor, + b.appendWord(Word(channelName, Word::Misc, colorScheme.SystemMessageColor, QString(channelName), QString(), Link(Link::Url, channel->getName() + "\n" + b.messageId))); } @@ -157,7 +159,7 @@ SharedMessage TwitchMessageBuilder::parse(const Communi::IrcPrivateMessage *ircM auto currentTwitchEmote = twitchEmotes.begin(); // words - QColor textColor = ircMessage->isAction() ? usernameColor : ColorScheme::getInstance().Text; + QColor textColor = ircMessage->isAction() ? usernameColor : colorScheme.Text; const QString &originalMessage = ircMessage->content(); b.originalMessage = originalMessage; @@ -184,7 +186,7 @@ SharedMessage TwitchMessageBuilder::parse(const Communi::IrcPrivateMessage *ircM // split words std::vector> parsed; - Emojis::parseEmojis(parsed, split); + emoteManager.parseEmojis(parsed, split); for (const std::tuple &tuple : parsed) { LazyLoadedImage *image = std::get<0>(tuple); @@ -257,7 +259,11 @@ SharedMessage TwitchMessageBuilder::parse(const Communi::IrcPrivateMessage *ircM // bttv / ffz emotes LazyLoadedImage *bttvEmote; - // TODO: Implement this (ignored emotes) + // TODO: Implement ignored emotes + // Format of ignored emotes: + // Emote name: "forsenPuke" - if string in ignoredEmotes + // Will match emote regardless of source (i.e. bttv, ffz) + // Emote source + name: "bttv:nyanPls" if (emoteManager.getBTTVEmotes().tryGet(string, bttvEmote) || channel->getBttvChannelEmotes().tryGet(string, bttvEmote) || emoteManager.getFFZEmotes().tryGet(string, bttvEmote) || diff --git a/src/widgets/basewidget.hpp b/src/widgets/basewidget.hpp index 6dafaca83..c98a211ba 100644 --- a/src/widgets/basewidget.hpp +++ b/src/widgets/basewidget.hpp @@ -1,4 +1,34 @@ -#ifndef BASEWIDGET_HPP -#define BASEWIDGET_HPP +#pragma once -#endif // BASEWIDGET_HPP +#include "colorscheme.hpp" + +#include + +namespace chatterino { + +class ColorScheme; + +namespace widgets { + +class BaseWidget : public QWidget +{ + Q_OBJECT + +public: + explicit BaseWidget(ColorScheme &_colorScheme, QWidget *parent) + : QWidget(parent) + , colorScheme(_colorScheme) + { + } + + explicit BaseWidget(BaseWidget *parent) + : QWidget(parent) + , colorScheme(parent->colorScheme) + { + } + + ColorScheme &colorScheme; +}; + +} // namespace widgets +} // namespace chatterino diff --git a/src/widgets/chatwidget.cpp b/src/widgets/chatwidget.cpp index afe51b67e..60c55f7ae 100644 --- a/src/widgets/chatwidget.cpp +++ b/src/widgets/chatwidget.cpp @@ -30,8 +30,8 @@ inline void ezShortcut(ChatWidget *w, const char *key, T t) } // namespace -ChatWidget::ChatWidget(ChannelManager &_channelManager, QWidget *parent) - : QWidget(parent) +ChatWidget::ChatWidget(ChannelManager &_channelManager, NotebookPage *parent) + : BaseWidget(parent) , channelManager(_channelManager) , channel(_channelManager.getEmpty()) , vbox(this) @@ -142,7 +142,7 @@ void ChatWidget::setChannel(std::shared_ptr _newChannel) auto snapshot = this->channel->getMessageSnapshot(); - for (int i = 0; i < snapshot.getSize(); i++) { + for (int i = 0; i < snapshot.getLength(); i++) { SharedMessageRef deleted; auto messageRef = new MessageRef(snapshot[i]); @@ -199,7 +199,7 @@ void ChatWidget::paintEvent(QPaintEvent *) // color the background of the chat QPainter painter(this); - painter.fillRect(this->rect(), ColorScheme::getInstance().ChatBackground); + painter.fillRect(this->rect(), this->colorScheme.ChatBackground); } void ChatWidget::load(const boost::property_tree::ptree &tree) @@ -241,7 +241,8 @@ void ChatWidget::doChangeChannel() void ChatWidget::doPopup() { // TODO: Copy signals and stuff too - auto widget = new ChatWidget(this->channelManager); + auto widget = + new ChatWidget(this->channelManager, static_cast(this->parentWidget())); widget->setChannelName(this->getChannelName()); widget->show(); } diff --git a/src/widgets/chatwidget.hpp b/src/widgets/chatwidget.hpp index 2cc359ae0..60230c0a3 100644 --- a/src/widgets/chatwidget.hpp +++ b/src/widgets/chatwidget.hpp @@ -5,6 +5,7 @@ #include "messages/messageref.hpp" #include "messages/word.hpp" #include "messages/wordpart.hpp" +#include "widgets/basewidget.hpp" #include "widgets/chatwidgetheader.hpp" #include "widgets/chatwidgetinput.hpp" #include "widgets/chatwidgetview.hpp" @@ -19,9 +20,12 @@ namespace chatterino { class ChannelManager; +class ColorScheme; namespace widgets { +class NotebookPage; + // Each ChatWidget consists of three sub-elements that handle their own part of the chat widget: // ChatWidgetHeader // - Responsible for rendering which channel the ChatWidget is in, and the menu in the top-left of @@ -32,12 +36,12 @@ namespace widgets { // - Responsible for rendering and handling user text input // // Each sub-element has a reference to the parent Chat Widget -class ChatWidget : public QWidget +class ChatWidget : public BaseWidget { Q_OBJECT public: - ChatWidget(ChannelManager &_channelManager, QWidget *parent = nullptr); + ChatWidget(ChannelManager &_channelManager, NotebookPage *parent); ~ChatWidget(); std::shared_ptr getChannel() const; diff --git a/src/widgets/chatwidgetheader.cpp b/src/widgets/chatwidgetheader.cpp index ca7c00c20..490225d6a 100644 --- a/src/widgets/chatwidgetheader.cpp +++ b/src/widgets/chatwidgetheader.cpp @@ -12,9 +12,11 @@ namespace chatterino { namespace widgets { ChatWidgetHeader::ChatWidgetHeader(ChatWidget *_chatWidget) - : QWidget(_chatWidget) + : BaseWidget(_chatWidget) , chatWidget(_chatWidget) + , leftLabel(this) , leftMenu(this) + , rightLabel(this) , rightMenu(this) { this->setFixedHeight(32); @@ -68,7 +70,7 @@ ChatWidgetHeader::ChatWidgetHeader(ChatWidget *_chatWidget) void ChatWidgetHeader::updateColors() { QPalette palette; - palette.setColor(QPalette::Foreground, ColorScheme::getInstance().Text); + palette.setColor(QPalette::Foreground, this->colorScheme.Text); this->leftLabel.setPalette(palette); this->channelNameLabel.setPalette(palette); @@ -86,8 +88,8 @@ void ChatWidgetHeader::paintEvent(QPaintEvent *) { QPainter painter(this); - painter.fillRect(rect(), ColorScheme::getInstance().ChatHeaderBackground); - painter.setPen(ColorScheme::getInstance().ChatHeaderBorder); + painter.fillRect(rect(), this->colorScheme.ChatHeaderBackground); + painter.setPen(this->colorScheme.ChatHeaderBorder); painter.drawRect(0, 0, width() - 1, height() - 1); } diff --git a/src/widgets/chatwidgetheader.hpp b/src/widgets/chatwidgetheader.hpp index e0e50d67f..b880df0ca 100644 --- a/src/widgets/chatwidgetheader.hpp +++ b/src/widgets/chatwidgetheader.hpp @@ -1,6 +1,7 @@ #pragma once #include "signallabel.hpp" +#include "widgets/basewidget.hpp" #include "widgets/chatwidgetheaderbutton.hpp" #include @@ -13,10 +14,14 @@ #include namespace chatterino { + +class ColorScheme; + namespace widgets { + class ChatWidget; -class ChatWidgetHeader : public QWidget +class ChatWidgetHeader : public BaseWidget { Q_OBJECT diff --git a/src/widgets/chatwidgetheaderbutton.cpp b/src/widgets/chatwidgetheaderbutton.cpp index df6ce075c..a8a79208f 100644 --- a/src/widgets/chatwidgetheaderbutton.cpp +++ b/src/widgets/chatwidgetheaderbutton.cpp @@ -1,5 +1,6 @@ #include "widgets/chatwidgetheaderbutton.hpp" #include "colorscheme.hpp" +#include "widgets/chatwidgetheader.hpp" #include #include @@ -7,24 +8,23 @@ namespace chatterino { namespace widgets { -ChatWidgetHeaderButton::ChatWidgetHeaderButton(int spacing) - : QWidget() - , _hbox() - , _label() - , _mouseOver(false) - , _mouseDown(false) +ChatWidgetHeaderButton::ChatWidgetHeaderButton(BaseWidget *parent, int spacing) + : BaseWidget(parent) + , mouseOver(false) + , mouseDown(false) { - setLayout(&_hbox); + setLayout(&this->ui.hbox); - _label.setAlignment(Qt::AlignCenter); + this->ui.label.setAlignment(Qt::AlignCenter); - _hbox.setMargin(0); - _hbox.addSpacing(spacing); - _hbox.addWidget(&_label); - _hbox.addSpacing(spacing); + this->ui.hbox.setMargin(0); + this->ui.hbox.addSpacing(spacing); + this->ui.hbox.addWidget(&this->ui.label); + this->ui.hbox.addSpacing(spacing); - QObject::connect(&_label, &SignalLabel::mouseUp, this, &ChatWidgetHeaderButton::labelMouseUp); - QObject::connect(&_label, &SignalLabel::mouseDown, this, + QObject::connect(&this->ui.label, &SignalLabel::mouseUp, this, + &ChatWidgetHeaderButton::labelMouseUp); + QObject::connect(&this->ui.label, &SignalLabel::mouseDown, this, &ChatWidgetHeaderButton::labelMouseDown); } @@ -32,14 +32,14 @@ void ChatWidgetHeaderButton::paintEvent(QPaintEvent *) { QPainter painter(this); - QBrush brush(ColorScheme::getInstance().IsLightTheme ? QColor(0, 0, 0, 32) - : QColor(255, 255, 255, 32)); + QBrush brush(this->colorScheme.isLightTheme() ? QColor(0, 0, 0, 32) + : QColor(255, 255, 255, 32)); - if (_mouseDown) { + if (mouseDown) { painter.fillRect(rect(), brush); } - if (_mouseOver) { + if (mouseOver) { painter.fillRect(rect(), brush); } } @@ -47,7 +47,7 @@ void ChatWidgetHeaderButton::paintEvent(QPaintEvent *) void ChatWidgetHeaderButton::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { - _mouseDown = true; + mouseDown = true; update(); } @@ -56,7 +56,7 @@ void ChatWidgetHeaderButton::mousePressEvent(QMouseEvent *event) void ChatWidgetHeaderButton::mouseReleaseEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { - _mouseDown = false; + mouseDown = false; update(); @@ -66,21 +66,21 @@ void ChatWidgetHeaderButton::mouseReleaseEvent(QMouseEvent *event) void ChatWidgetHeaderButton::enterEvent(QEvent *) { - _mouseOver = true; + mouseOver = true; update(); } void ChatWidgetHeaderButton::leaveEvent(QEvent *) { - _mouseOver = false; + mouseOver = false; update(); } void ChatWidgetHeaderButton::labelMouseUp() { - _mouseDown = false; + mouseDown = false; update(); @@ -89,7 +89,7 @@ void ChatWidgetHeaderButton::labelMouseUp() void ChatWidgetHeaderButton::labelMouseDown() { - _mouseDown = true; + mouseDown = true; update(); } diff --git a/src/widgets/chatwidgetheaderbutton.hpp b/src/widgets/chatwidgetheaderbutton.hpp index 5428d2161..47c6d3b29 100644 --- a/src/widgets/chatwidgetheaderbutton.hpp +++ b/src/widgets/chatwidgetheaderbutton.hpp @@ -1,5 +1,6 @@ #pragma once +#include "widgets/basewidget.hpp" #include "widgets/signallabel.hpp" #include @@ -8,38 +9,45 @@ #include namespace chatterino { + +class ColorScheme; + namespace widgets { -class ChatWidgetHeaderButton : public QWidget +class ChatWidgetHeader; + +class ChatWidgetHeaderButton : public BaseWidget { Q_OBJECT public: - explicit ChatWidgetHeaderButton(int spacing = 6); + explicit ChatWidgetHeaderButton(BaseWidget *parent, int spacing = 6); SignalLabel &getLabel() { - return _label; + return this->ui.label; } signals: void clicked(); protected: - void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE; + virtual void paintEvent(QPaintEvent *) override; - void enterEvent(QEvent *) Q_DECL_OVERRIDE; - void leaveEvent(QEvent *) Q_DECL_OVERRIDE; + virtual void enterEvent(QEvent *) override; + virtual void leaveEvent(QEvent *) override; - void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; - void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + virtual void mousePressEvent(QMouseEvent *event) override; + virtual void mouseReleaseEvent(QMouseEvent *event) override; private: - QHBoxLayout _hbox; - SignalLabel _label; + struct { + QHBoxLayout hbox; + SignalLabel label; + } ui; - bool _mouseOver; - bool _mouseDown; + bool mouseOver = false; + bool mouseDown = false; void labelMouseUp(); void labelMouseDown(); diff --git a/src/widgets/chatwidgetinput.cpp b/src/widgets/chatwidgetinput.cpp index 4e0cc734b..5cb34fb52 100644 --- a/src/widgets/chatwidgetinput.cpp +++ b/src/widgets/chatwidgetinput.cpp @@ -12,8 +12,9 @@ namespace chatterino { namespace widgets { ChatWidgetInput::ChatWidgetInput(ChatWidget *_chatWidget) - : QWidget(_chatWidget) + : BaseWidget(_chatWidget) , chatWidget(_chatWidget) + , emotesLabel(this) { this->setMaximumHeight(150); @@ -93,11 +94,11 @@ void ChatWidgetInput::refreshTheme() { QPalette palette; - palette.setColor(QPalette::Foreground, ColorScheme::getInstance().Text); + palette.setColor(QPalette::Foreground, this->colorScheme.Text); this->textLengthLabel.setPalette(palette); - this->textInput.setStyleSheet(ColorScheme::getInstance().InputStyleSheet); + this->textInput.setStyleSheet(this->colorScheme.InputStyleSheet); } void ChatWidgetInput::editTextChanged() @@ -118,8 +119,8 @@ void ChatWidgetInput::paintEvent(QPaintEvent *) { QPainter painter(this); - painter.fillRect(this->rect(), ColorScheme::getInstance().ChatInputBackground); - painter.setPen(ColorScheme::getInstance().ChatInputBorder); + painter.fillRect(this->rect(), this->colorScheme.ChatInputBackground); + painter.setPen(this->colorScheme.ChatInputBorder); painter.drawRect(0, 0, this->width() - 1, this->height() - 1); } diff --git a/src/widgets/chatwidgetinput.hpp b/src/widgets/chatwidgetinput.hpp index 03a9419cf..1c5d300ab 100644 --- a/src/widgets/chatwidgetinput.hpp +++ b/src/widgets/chatwidgetinput.hpp @@ -1,6 +1,7 @@ #pragma once #include "resizingtextedit.hpp" +#include "widgets/basewidget.hpp" #include "widgets/chatwidgetheaderbutton.hpp" #include @@ -16,7 +17,7 @@ namespace widgets { class ChatWidget; -class ChatWidgetInput : public QWidget +class ChatWidgetInput : public BaseWidget { Q_OBJECT diff --git a/src/widgets/chatwidgetview.cpp b/src/widgets/chatwidgetview.cpp index b04e7cbb1..1a518163c 100644 --- a/src/widgets/chatwidgetview.cpp +++ b/src/widgets/chatwidgetview.cpp @@ -20,7 +20,7 @@ namespace chatterino { namespace widgets { ChatWidgetView::ChatWidgetView(ChatWidget *_chatWidget) - : QWidget(_chatWidget) + : BaseWidget(_chatWidget) , chatWidget(_chatWidget) , scrollBar(this) , userPopupWidget(_chatWidget->getChannelRef()) @@ -47,7 +47,7 @@ bool ChatWidgetView::layoutMessages() { auto messages = this->chatWidget->getMessagesSnapshot(); - if (messages.getSize() == 0) { + if (messages.getLength() == 0) { this->scrollBar.setVisible(false); return false; } @@ -65,10 +65,10 @@ bool ChatWidgetView::layoutMessages() int layoutWidth = this->scrollBar.isVisible() ? width() - this->scrollBar.width() : width(); // layout the visible messages in the view - if (messages.getSize() > start) { + if (messages.getLength() > start) { int y = -(messages[start]->getHeight() * (fmod(this->scrollBar.getCurrentValue(), 1))); - for (int i = start; i < messages.getSize(); ++i) { + for (int i = start; i < messages.getLength(); ++i) { auto message = messages[i]; redraw |= message->layout(layoutWidth, true); @@ -84,7 +84,7 @@ bool ChatWidgetView::layoutMessages() // layout the messages at the bottom to determine the scrollbar thumb size int h = height() - 8; - for (int i = messages.getSize() - 1; i >= 0; i--) { + for (std::size_t i = messages.getLength() - 1; i > 0; i--) { auto *message = messages[i].get(); message->layout(layoutWidth, true); @@ -92,7 +92,7 @@ bool ChatWidgetView::layoutMessages() h -= message->getHeight(); if (h < 0) { - this->scrollBar.setLargeChange((messages.getSize() - i) + + this->scrollBar.setLargeChange((messages.getLength() - i) + (qreal)h / message->getHeight()); this->scrollBar.setDesiredValue(this->scrollBar.getDesiredValue()); @@ -107,7 +107,7 @@ bool ChatWidgetView::layoutMessages() this->scrollBar.setDesiredValue(0); } - this->scrollBar.setMaximum(messages.getSize()); + this->scrollBar.setMaximum(messages.getLength()); if (this->showingLatestMessages && showScrollbar) { // If we were showing the latest messages and the scrollbar now wants to be rendered, scroll @@ -148,14 +148,12 @@ void ChatWidgetView::paintEvent(QPaintEvent * /*event*/) _painter.setRenderHint(QPainter::SmoothPixmapTransform); - ColorScheme &scheme = ColorScheme::getInstance(); - // only update gif emotes if (this->onlyUpdateEmotes) { this->onlyUpdateEmotes = false; for (const GifEmoteData &item : this->gifEmotes) { - _painter.fillRect(item.rect, scheme.ChatBackground); + _painter.fillRect(item.rect, this->colorScheme.ChatBackground); _painter.drawPixmap(item.rect, *item.image->getPixmap()); } @@ -166,7 +164,7 @@ void ChatWidgetView::paintEvent(QPaintEvent * /*event*/) // update all messages this->gifEmotes.clear(); - _painter.fillRect(rect(), scheme.ChatBackground); + _painter.fillRect(rect(), this->colorScheme.ChatBackground); // code for tesing colors /* @@ -205,13 +203,13 @@ void ChatWidgetView::paintEvent(QPaintEvent * /*event*/) int start = this->scrollBar.getCurrentValue(); - if (start >= messages.getSize()) { + if (start >= messages.getLength()) { return; } int y = -(messages[start].get()->getHeight() * (fmod(this->scrollBar.getCurrentValue(), 1))); - for (int i = start; i < messages.getSize(); ++i) { + for (int i = start; i < messages.getLength(); ++i) { messages::MessageRef *messageRef = messages[i].get(); std::shared_ptr bufferPtr = messageRef->buffer; @@ -228,7 +226,7 @@ void ChatWidgetView::paintEvent(QPaintEvent * /*event*/) // update messages that have been changed if (updateBuffer) { QPainter painter(buffer); - painter.fillRect(buffer->rect(), scheme.ChatBackground); + painter.fillRect(buffer->rect(), this->colorScheme.ChatBackground); for (messages::WordPart const &wordPart : messageRef->getWordParts()) { // image @@ -247,7 +245,7 @@ void ChatWidgetView::paintEvent(QPaintEvent * /*event*/) else { QColor color = wordPart.getWord().getColor(); - ColorScheme::getInstance().normalizeColor(color); + this->colorScheme.normalizeColor(color); painter.setPen(color); painter.setFont(wordPart.getWord().getFont()); @@ -266,14 +264,14 @@ void ChatWidgetView::paintEvent(QPaintEvent * /*event*/) messages::LazyLoadedImage &lli = wordPart.getWord().getImage(); if (lli.getAnimated()) { - GifEmoteData data; - data.image = &lli; + GifEmoteData gifEmoteData; + gifEmoteData.image = &lli; QRect rect(wordPart.getX(), wordPart.getY() + y, wordPart.getWidth(), wordPart.getHeight()); - data.rect = rect; + gifEmoteData.rect = rect; - this->gifEmotes.push_back(data); + this->gifEmotes.push_back(gifEmoteData); } } } @@ -290,7 +288,7 @@ void ChatWidgetView::paintEvent(QPaintEvent * /*event*/) } for (GifEmoteData &item : this->gifEmotes) { - _painter.fillRect(item.rect, scheme.ChatBackground); + _painter.fillRect(item.rect, this->colorScheme.ChatBackground); _painter.drawPixmap(item.rect, *item.image->getPixmap()); } @@ -401,13 +399,13 @@ bool ChatWidgetView::tryGetMessageAt(QPoint p, std::shared_ptrscrollBar.getCurrentValue(); - if (start >= messages.getSize()) { + if (start >= messages.getLength()) { return false; } int y = -(messages[start]->getHeight() * (fmod(this->scrollBar.getCurrentValue(), 1))); - for (int i = start; i < messages.getSize(); ++i) { + for (int i = start; i < messages.getLength(); ++i) { auto message = messages[i]; if (p.y() < y + message->getHeight()) { diff --git a/src/widgets/chatwidgetview.hpp b/src/widgets/chatwidgetview.hpp index b5652fdf9..f22ea6ed5 100644 --- a/src/widgets/chatwidgetview.hpp +++ b/src/widgets/chatwidgetview.hpp @@ -5,6 +5,7 @@ #include "messages/messageref.hpp" #include "messages/word.hpp" #include "widgets/accountpopup.hpp" +#include "widgets/basewidget.hpp" #include "widgets/scrollbar.hpp" #include @@ -17,7 +18,7 @@ namespace widgets { class ChatWidget; -class ChatWidgetView : public QWidget +class ChatWidgetView : public BaseWidget { public: explicit ChatWidgetView(ChatWidget *_chatWidget); diff --git a/src/widgets/fancybutton.cpp b/src/widgets/fancybutton.cpp index 7fc6e97f5..b363893b9 100644 --- a/src/widgets/fancybutton.cpp +++ b/src/widgets/fancybutton.cpp @@ -6,49 +6,42 @@ namespace chatterino { namespace widgets { -FancyButton::FancyButton(QWidget *parent) - : QWidget(parent) - , _selected() - , _mouseOver() - , _mouseDown() - , _mousePos() - , _hoverMultiplier() - , _effectTimer() - , _mouseEffectColor(QColor(255, 255, 255)) +FancyButton::FancyButton(BaseWidget *parent) + : BaseWidget(parent) { - connect(&_effectTimer, &QTimer::timeout, this, &FancyButton::onMouseEffectTimeout); + connect(&effectTimer, &QTimer::timeout, this, &FancyButton::onMouseEffectTimeout); - _effectTimer.setInterval(20); - _effectTimer.start(); + this->effectTimer.setInterval(20); + this->effectTimer.start(); } void FancyButton::setMouseEffectColor(QColor color) { - _mouseEffectColor = color; + this->mouseEffectColor = color; } void FancyButton::paintEvent(QPaintEvent *) { QPainter painter; - fancyPaint(painter); + this->fancyPaint(painter); } void FancyButton::fancyPaint(QPainter &painter) { - QColor &c = _mouseEffectColor; + QColor &c = this->mouseEffectColor; - if (_hoverMultiplier > 0) { - QRadialGradient gradient(_mousePos.x(), _mousePos.y(), 50, _mousePos.x(), _mousePos.y()); + if (this->hoverMultiplier > 0) { + QRadialGradient gradient(mousePos.x(), mousePos.y(), 50, mousePos.x(), mousePos.y()); - gradient.setColorAt(0, QColor(c.red(), c.green(), c.blue(), (int)(24 * _hoverMultiplier))); - gradient.setColorAt(1, QColor(c.red(), c.green(), c.blue(), (int)(12 * _hoverMultiplier))); + gradient.setColorAt(0, QColor(c.red(), c.green(), c.blue(), (int)(24 * this->hoverMultiplier))); + gradient.setColorAt(1, QColor(c.red(), c.green(), c.blue(), (int)(12 * this->hoverMultiplier))); painter.fillRect(this->rect(), gradient); } - for (auto effect : _clickEffects) { + for (auto effect : this->clickEffects) { QRadialGradient gradient(effect.position.x(), effect.position.y(), effect.progress * (float)width() * 2, effect.position.x(), effect.position.y()); @@ -65,12 +58,12 @@ void FancyButton::fancyPaint(QPainter &painter) void FancyButton::enterEvent(QEvent *) { - _mouseOver = true; + this->mouseOver = true; } void FancyButton::leaveEvent(QEvent *) { - _mouseOver = false; + this->mouseOver = false; } void FancyButton::mousePressEvent(QMouseEvent *event) @@ -79,9 +72,9 @@ void FancyButton::mousePressEvent(QMouseEvent *event) return; } - _clickEffects.push_back(ClickEffect(event->pos())); + this->clickEffects.push_back(ClickEffect(event->pos())); - _mouseDown = true; + this->mouseDown = true; } void FancyButton::mouseReleaseEvent(QMouseEvent *event) @@ -90,43 +83,43 @@ void FancyButton::mouseReleaseEvent(QMouseEvent *event) return; } - _mouseDown = false; + this->mouseDown = false; } void FancyButton::mouseMoveEvent(QMouseEvent *event) { - _mousePos = event->pos(); + this->mousePos = event->pos(); } void FancyButton::onMouseEffectTimeout() { bool performUpdate = false; - if (_selected) { - if (_hoverMultiplier != 0) { - _hoverMultiplier = std::max(0.0, _hoverMultiplier - 0.1); + if (selected) { + if (this->hoverMultiplier != 0) { + this->hoverMultiplier = std::max(0.0, this->hoverMultiplier - 0.1); performUpdate = true; } - } else if (_mouseOver) { - if (_hoverMultiplier != 1) { - _hoverMultiplier = std::min(1.0, _hoverMultiplier + 0.5); + } else if (mouseOver) { + if (this->hoverMultiplier != 1) { + this->hoverMultiplier = std::min(1.0, this->hoverMultiplier + 0.5); performUpdate = true; } } else { - if (_hoverMultiplier != 0) { - _hoverMultiplier = std::max(0.0, _hoverMultiplier - 0.3); + if (this->hoverMultiplier != 0) { + this->hoverMultiplier = std::max(0.0, this->hoverMultiplier - 0.3); performUpdate = true; } } - if (_clickEffects.size() != 0) { + if (this->clickEffects.size() != 0) { performUpdate = true; - for (auto it = _clickEffects.begin(); it != _clickEffects.end();) { - (*it).progress += _mouseDown ? 0.02 : 0.07; + for (auto it = this->clickEffects.begin(); it != this->clickEffects.end();) { + (*it).progress += mouseDown ? 0.02 : 0.07; if ((*it).progress >= 1.0) { - it = _clickEffects.erase(it); + it = this->clickEffects.erase(it); } else { it++; } diff --git a/src/widgets/fancybutton.hpp b/src/widgets/fancybutton.hpp index 6d21b3f22..3fd154ebe 100644 --- a/src/widgets/fancybutton.hpp +++ b/src/widgets/fancybutton.hpp @@ -1,5 +1,7 @@ #pragma once +#include "widgets/basewidget.hpp" + #include #include #include @@ -9,43 +11,42 @@ namespace chatterino { namespace widgets { -class FancyButton : public QWidget +class FancyButton : public BaseWidget { struct ClickEffect { - float progress; + double progress = 0.0; QPoint position; - ClickEffect(QPoint position) - : progress() - , position(position) + ClickEffect(QPoint _position) + : position(_position) { } }; public: - FancyButton(QWidget *parent = nullptr); + FancyButton(BaseWidget *parent); void setMouseEffectColor(QColor color); protected: - void paintEvent(QPaintEvent *) override; - void enterEvent(QEvent *) override; - void leaveEvent(QEvent *) override; - void mousePressEvent(QMouseEvent *event) override; - void mouseReleaseEvent(QMouseEvent *event) override; - void mouseMoveEvent(QMouseEvent *event) override; + virtual void paintEvent(QPaintEvent *) override; + virtual void enterEvent(QEvent *) override; + virtual void leaveEvent(QEvent *) override; + virtual void mousePressEvent(QMouseEvent *event) override; + virtual void mouseReleaseEvent(QMouseEvent *event) override; + virtual void mouseMoveEvent(QMouseEvent *event) override; void fancyPaint(QPainter &painter); private: - bool _selected; - bool _mouseOver; - bool _mouseDown; - QPoint _mousePos; - float _hoverMultiplier; - QTimer _effectTimer; - std::vector _clickEffects; - QColor _mouseEffectColor; + bool selected = false; + bool mouseOver = false; + bool mouseDown = false; + QPoint mousePos; + double hoverMultiplier = 0.0; + QTimer effectTimer; + std::vector clickEffects; + QColor mouseEffectColor = {255, 255, 255}; void onMouseEffectTimeout(); }; diff --git a/src/widgets/mainwindow.cpp b/src/widgets/mainwindow.cpp index f4a423dd9..97704131a 100644 --- a/src/widgets/mainwindow.cpp +++ b/src/widgets/mainwindow.cpp @@ -19,12 +19,12 @@ namespace chatterino { namespace widgets { -MainWindow::MainWindow(ChannelManager &_channelManager, QWidget *parent) - : QWidget(parent) +MainWindow::MainWindow(ChannelManager &_channelManager, ColorScheme &_colorScheme) + : BaseWidget(_colorScheme, nullptr) , channelManager(_channelManager) + , colorScheme(_colorScheme) , notebook(this->channelManager, this) - , _loaded(false) - , _titleBar() + , windowGeometry("/windows/0/geometry") { QVBoxLayout *layout = new QVBoxLayout(this); @@ -44,10 +44,17 @@ MainWindow::MainWindow(ChannelManager &_channelManager, QWidget *parent) // } QPalette palette; - palette.setColor(QPalette::Background, ColorScheme::getInstance().TabPanelBackground); + palette.setColor(QPalette::Background, this->colorScheme.TabPanelBackground); setPalette(palette); - resize(1280, 800); + if (this->windowGeometry->isFilled()) { + // Load geometry from settings file + this->setGeometry(this->windowGeometry.getValueRef()); + } else { + // Set default geometry + // Default position is in the middle of the current monitor or the primary monitor + this->resize(1280, 800); + } // Initialize program-wide hotkeys { @@ -122,7 +129,7 @@ void MainWindow::load(const boost::property_tree::ptree &tree) { this->notebook.load(tree); - _loaded = true; + loaded = true; } boost::property_tree::ptree MainWindow::save() @@ -140,12 +147,12 @@ void MainWindow::loadDefaults() { this->notebook.loadDefaults(); - _loaded = true; + loaded = true; } bool MainWindow::isLoaded() const { - return _loaded; + return loaded; } Notebook &MainWindow::getNotebook() @@ -153,5 +160,11 @@ Notebook &MainWindow::getNotebook() return this->notebook; } +void MainWindow::closeEvent(QCloseEvent *event) +{ + // Save closing window position + this->windowGeometry = this->geometry(); +} + } // namespace widgets } // namespace chatterino diff --git a/src/widgets/mainwindow.hpp b/src/widgets/mainwindow.hpp index d8c50c1b8..2da4aa9e7 100644 --- a/src/widgets/mainwindow.hpp +++ b/src/widgets/mainwindow.hpp @@ -1,5 +1,6 @@ #pragma once +#include "widgets/basewidget.hpp" #include "widgets/notebook.hpp" #include "widgets/titlebar.hpp" @@ -9,19 +10,22 @@ #include #include +#include +#include namespace chatterino { class ChannelManager; +class ColorScheme; namespace widgets { -class MainWindow : public QWidget +class MainWindow : public BaseWidget { Q_OBJECT public: - explicit MainWindow(ChannelManager &_channelManager, QWidget *parent = nullptr); + explicit MainWindow(ChannelManager &_channelManager, ColorScheme &_colorScheme); ~MainWindow(); void layoutVisibleChatWidgets(Channel *channel = nullptr); @@ -36,12 +40,108 @@ public: Notebook &getNotebook(); +protected: + virtual void closeEvent(QCloseEvent *event) override; + private: ChannelManager &channelManager; + ColorScheme &colorScheme; Notebook notebook; - bool _loaded; - TitleBar _titleBar; + bool loaded = false; + TitleBar titleBar; + + class QRectWrapper : public pajlada::Settings::ISettingData, public QRect + { + public: + QRectWrapper() + : QRect(-1, -1, -1, -1) + { + } + + pajlada::Signals::Signal valueChanged; + + /* + operator const QRect &() const + { + return static_cast(*this); + // return this->getValue(); + } + */ + + const QRectWrapper &getValueRef() const + { + return *this; + } + + virtual rapidjson::Value marshalInto(rapidjson::Document &d) override + { + using namespace pajlada::Settings; + + rapidjson::Value obj(rapidjson::kObjectType); + + auto _x = serializeToJSON::serialize(this->x(), d.GetAllocator()); + auto _y = serializeToJSON::serialize(this->y(), d.GetAllocator()); + auto _width = serializeToJSON::serialize(this->width(), d.GetAllocator()); + auto _height = serializeToJSON::serialize(this->height(), d.GetAllocator()); + + obj.AddMember("x", _x, d.GetAllocator()); + obj.AddMember("y", _y, d.GetAllocator()); + obj.AddMember("width", _width, d.GetAllocator()); + obj.AddMember("height", _height, d.GetAllocator()); + + return obj; + } + + virtual bool unmarshalFrom(rapidjson::Document &document) override + { + using namespace pajlada::Settings; + + auto vXp = this->getValueWithSuffix("/x", document); + auto vYp = this->getValueWithSuffix("/y", document); + auto vWidthp = this->getValueWithSuffix("/width", document); + auto vHeightp = this->getValueWithSuffix("/height", document); + if (vXp != nullptr) { + this->setX(deserializeJSON::deserialize(*vXp)); + this->filled = true; + } + if (vYp != nullptr) { + this->setY(deserializeJSON::deserialize(*vYp)); + this->filled = true; + } + if (vWidthp != nullptr) { + this->setWidth(deserializeJSON::deserialize(*vWidthp)); + this->filled = true; + } + if (vHeightp != nullptr) { + this->setHeight(deserializeJSON::deserialize(*vHeightp)); + this->filled = true; + } + + return true; + } + + virtual void registerDocument(rapidjson::Document &d) override + { + this->valueChanged.connect([this, &d](const auto &) { + this->marshalInto(d); // + }); + } + + QRectWrapper &operator=(const QRect &rhs) + { + static_cast(*this) = rhs; + + return *this; + } + + void setValue(const QRect &rhs) + { + static_cast(*this) = rhs; + } + }; + + pajlada::Settings::Setting windowGeometry; }; } // namespace widgets diff --git a/src/widgets/notebook.cpp b/src/widgets/notebook.cpp index 2f56ec4ab..f9d2ba78d 100644 --- a/src/widgets/notebook.cpp +++ b/src/widgets/notebook.cpp @@ -18,26 +18,26 @@ namespace chatterino { namespace widgets { -Notebook::Notebook(ChannelManager &_channelManager, QWidget *parent) - : QWidget(parent) - , channelManager(_channelManager) - , _addButton(this) - , _settingsButton(this) - , _userButton(this) - , _selectedPage(nullptr) +Notebook::Notebook(ChannelManager &_channelManager, BaseWidget *parent) + : BaseWidget(parent) + , channelManager(_channelManager) + , addButton(this) + , settingsButton(this) + , userButton(this) + , selectedPage(nullptr) { - connect(&_settingsButton, SIGNAL(clicked()), this, SLOT(settingsButtonClicked())); - connect(&_userButton, SIGNAL(clicked()), this, SLOT(usersButtonClicked())); - connect(&_addButton, SIGNAL(clicked()), this, SLOT(addPageButtonClicked())); + connect(&settingsButton, SIGNAL(clicked()), this, SLOT(settingsButtonClicked())); + connect(&userButton, SIGNAL(clicked()), this, SLOT(usersButtonClicked())); + connect(&addButton, SIGNAL(clicked()), this, SLOT(addPageButtonClicked())); - _settingsButton.resize(24, 24); - _settingsButton.icon = NotebookButton::IconSettings; + settingsButton.resize(24, 24); + settingsButton.icon = NotebookButton::IconSettings; - _userButton.resize(24, 24); - _userButton.move(24, 0); - _userButton.icon = NotebookButton::IconUser; + userButton.resize(24, 24); + userButton.move(24, 0); + userButton.icon = NotebookButton::IconUser; - _addButton.resize(24, 24); + addButton.resize(24, 24); SettingsManager::getInstance().hidePreferencesButton.valueChanged.connect( [this](const bool &) { performLayout(); }); @@ -52,11 +52,11 @@ NotebookPage *Notebook::addPage(bool select) tab->show(); - if (select || _pages.count() == 0) { + if (select || pages.count() == 0) { this->select(page); } - _pages.append(page); + pages.append(page); performLayout(); @@ -65,22 +65,22 @@ NotebookPage *Notebook::addPage(bool select) void Notebook::removePage(NotebookPage *page) { - int index = _pages.indexOf(page); + int index = pages.indexOf(page); - if (_pages.size() == 1) { + if (pages.size() == 1) { select(nullptr); - } else if (index == _pages.count() - 1) { - select(_pages[index - 1]); + } else if (index == pages.count() - 1) { + select(pages[index - 1]); } else { - select(_pages[index + 1]); + select(pages[index + 1]); } delete page->getTab(); delete page; - _pages.removeOne(page); + pages.removeOne(page); - if (_pages.size() == 0) { + if (pages.size() == 0) { addPage(); } @@ -89,7 +89,7 @@ void Notebook::removePage(NotebookPage *page) void Notebook::select(NotebookPage *page) { - if (page == _selectedPage) + if (page == selectedPage) return; if (page != nullptr) { @@ -98,12 +98,12 @@ void Notebook::select(NotebookPage *page) page->getTab()->raise(); } - if (_selectedPage != nullptr) { - _selectedPage->setHidden(true); - _selectedPage->getTab()->setSelected(false); + if (selectedPage != nullptr) { + selectedPage->setHidden(true); + selectedPage->getTab()->setSelected(false); } - _selectedPage = page; + selectedPage = page; performLayout(); } @@ -112,7 +112,7 @@ NotebookPage *Notebook::tabAt(QPoint point, int &index) { int i = 0; - for (auto *page : _pages) { + for (auto *page : pages) { if (page->getTab()->getDesiredRect().contains(point)) { index = i; return page; @@ -127,7 +127,7 @@ NotebookPage *Notebook::tabAt(QPoint point, int &index) void Notebook::rearrangePage(NotebookPage *page, int index) { - _pages.move(_pages.indexOf(page), index); + pages.move(pages.indexOf(page), index); performLayout(); } @@ -137,26 +137,26 @@ void Notebook::performLayout(bool animated) int x = 0, y = 0; if (SettingsManager::getInstance().hidePreferencesButton.get()) { - _settingsButton.hide(); + settingsButton.hide(); } else { - _settingsButton.show(); + settingsButton.show(); x += 24; } if (SettingsManager::getInstance().hideUserButton.get()) { - _userButton.hide(); + userButton.hide(); } else { - _userButton.move(x, 0); - _userButton.show(); + userButton.move(x, 0); + userButton.show(); x += 24; } int tabHeight = 16; bool first = true; - for (auto &i : _pages) { + for (auto &i : pages) { tabHeight = i->getTab()->height(); - if (!first && (i == _pages.last() ? tabHeight : 0) + x + i->getTab()->width() > width()) { + if (!first && (i == pages.last() ? tabHeight : 0) + x + i->getTab()->width() > width()) { y += i->getTab()->height(); i->getTab()->moveAnimated(QPoint(0, y), animated); x = i->getTab()->width(); @@ -168,11 +168,11 @@ void Notebook::performLayout(bool animated) first = false; } - _addButton.move(x, y); + addButton.move(x, y); - if (_selectedPage != nullptr) { - _selectedPage->move(0, y + tabHeight); - _selectedPage->resize(width(), height() - y - tabHeight); + if (selectedPage != nullptr) { + selectedPage->move(0, y + tabHeight); + selectedPage->resize(width(), height() - y - tabHeight); } } @@ -211,7 +211,7 @@ void Notebook::load(const boost::property_tree::ptree &tree) // can't read tabs } - if (_pages.size() == 0) { + if (pages.size() == 0) { // No pages saved, show default stuff loadDefaults(); } @@ -222,7 +222,7 @@ void Notebook::save(boost::property_tree::ptree &tree) boost::property_tree::ptree tabs; // Iterate through all tabs and add them to our tabs property thing - for (const auto &page : _pages) { + for (const auto &page : pages) { boost::property_tree::ptree pTab = page->getTab()->save(); boost::property_tree::ptree pChats = page->save(); diff --git a/src/widgets/notebook.hpp b/src/widgets/notebook.hpp index 08491ba18..d510584dd 100644 --- a/src/widgets/notebook.hpp +++ b/src/widgets/notebook.hpp @@ -1,5 +1,6 @@ #pragma once +#include "widgets/basewidget.hpp" #include "widgets/notebookbutton.hpp" #include "widgets/notebookpage.hpp" #include "widgets/notebooktab.hpp" @@ -11,17 +12,18 @@ namespace chatterino { class ChannelManager; +class ColorScheme; namespace widgets { -class Notebook : public QWidget +class Notebook : public BaseWidget { Q_OBJECT public: enum HighlightType { none, highlighted, newMessage }; - Notebook(ChannelManager &_channelManager, QWidget *parent); + explicit Notebook(ChannelManager &_channelManager, BaseWidget *parent); NotebookPage *addPage(bool select = false); @@ -30,7 +32,7 @@ public: NotebookPage *getSelectedPage() { - return _selectedPage; + return selectedPage; } void performLayout(bool animate = true); @@ -51,13 +53,13 @@ public slots: private: ChannelManager &channelManager; - QList _pages; + QList pages; - NotebookButton _addButton; - NotebookButton _settingsButton; - NotebookButton _userButton; + NotebookButton addButton; + NotebookButton settingsButton; + NotebookButton userButton; - NotebookPage *_selectedPage; + NotebookPage *selectedPage; public: void load(const boost::property_tree::ptree &tree); diff --git a/src/widgets/notebookbutton.cpp b/src/widgets/notebookbutton.cpp index 765aaf475..896559e20 100644 --- a/src/widgets/notebookbutton.cpp +++ b/src/widgets/notebookbutton.cpp @@ -10,7 +10,7 @@ namespace chatterino { namespace widgets { -NotebookButton::NotebookButton(QWidget *parent) +NotebookButton::NotebookButton(BaseWidget *parent) : FancyButton(parent) { setMouseEffectColor(QColor(0, 0, 0)); @@ -23,17 +23,15 @@ void NotebookButton::paintEvent(QPaintEvent *) QColor background; QColor foreground; - auto &colorScheme = ColorScheme::getInstance(); - - if (_mouseDown) { - background = colorScheme.TabSelectedBackground; - foreground = colorScheme.TabSelectedText; - } else if (_mouseOver) { - background = colorScheme.TabHoverBackground; - foreground = colorScheme.TabSelectedBackground; + if (mouseDown) { + background = this->colorScheme.TabSelectedBackground; + foreground = this->colorScheme.TabSelectedText; + } else if (mouseOver) { + background = this->colorScheme.TabHoverBackground; + foreground = this->colorScheme.TabSelectedBackground; } else { - background = colorScheme.TabPanelBackground; - // foreground = colorScheme.TabSelectedBackground; + background = this->colorScheme.TabPanelBackground; + // foreground = this->colorScheme.TabSelectedBackground; foreground = QColor(230, 230, 230); } @@ -93,7 +91,7 @@ void NotebookButton::paintEvent(QPaintEvent *) void NotebookButton::mouseReleaseEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { - _mouseDown = false; + mouseDown = false; update(); diff --git a/src/widgets/notebookbutton.hpp b/src/widgets/notebookbutton.hpp index fb3e9d692..438b27df8 100644 --- a/src/widgets/notebookbutton.hpp +++ b/src/widgets/notebookbutton.hpp @@ -18,7 +18,7 @@ public: int icon = 0; - NotebookButton(QWidget *parent); + NotebookButton(BaseWidget *parent); protected: void paintEvent(QPaintEvent *) override; @@ -28,9 +28,9 @@ signals: void clicked(); private: - bool _mouseOver = false; - bool _mouseDown = false; - QPoint _mousePos; + bool mouseOver = false; + bool mouseDown = false; + QPoint mousePos; }; } // namespace widgets diff --git a/src/widgets/notebookpage.cpp b/src/widgets/notebookpage.cpp index 9fae9a3c7..523276c78 100644 --- a/src/widgets/notebookpage.cpp +++ b/src/widgets/notebookpage.cpp @@ -1,6 +1,7 @@ #include "widgets/notebookpage.hpp" #include "colorscheme.hpp" #include "widgets/chatwidget.hpp" +#include "widgets/notebook.hpp" #include "widgets/notebooktab.hpp" #include @@ -19,8 +20,8 @@ bool NotebookPage::isDraggingSplit = false; ChatWidget *NotebookPage::draggingSplit = nullptr; std::pair NotebookPage::dropPosition = std::pair(-1, -1); -NotebookPage::NotebookPage(ChannelManager &_channelManager, QWidget *parent, NotebookTab *_tab) - : QWidget(parent) +NotebookPage::NotebookPage(ChannelManager &_channelManager, Notebook *parent, NotebookTab *_tab) + : BaseWidget(parent->colorScheme, parent) , channelManager(_channelManager) , tab(_tab) , _parentbox(this) @@ -52,7 +53,7 @@ NotebookTab *NotebookPage::getTab() const void NotebookPage::addChat(bool openChannelNameDialog) { - ChatWidget *w = new ChatWidget(this->channelManager); + ChatWidget *w = this->createChatWidget(); if (openChannelNameDialog) { w->showChangeChannelPopup(); @@ -130,9 +131,9 @@ void NotebookPage::addToLayout(ChatWidget *widget, void NotebookPage::enterEvent(QEvent *) { if (_hbox.count() == 0) { - setCursor(QCursor(Qt::PointingHandCursor)); + this->setCursor(QCursor(Qt::PointingHandCursor)); } else { - setCursor(QCursor(Qt::ArrowCursor)); + this->setCursor(QCursor(Qt::ArrowCursor)); } } @@ -144,9 +145,9 @@ void NotebookPage::mouseReleaseEvent(QMouseEvent *event) { if (_hbox.count() == 0 && event->button() == Qt::LeftButton) { // "Add Chat" was clicked - addToLayout(new ChatWidget(this->channelManager), std::pair(-1, -1)); + this->addToLayout(this->createChatWidget(), std::pair(-1, -1)); - setCursor(QCursor(Qt::ArrowCursor)); + this->setCursor(QCursor(Qt::ArrowCursor)); } } @@ -236,16 +237,16 @@ void NotebookPage::paintEvent(QPaintEvent *) QPainter painter(this); if (_hbox.count() == 0) { - painter.fillRect(rect(), ColorScheme::getInstance().ChatBackground); + painter.fillRect(rect(), this->colorScheme.ChatBackground); - painter.fillRect(0, 0, width(), 2, ColorScheme::getInstance().TabSelectedBackground); + painter.fillRect(0, 0, width(), 2, this->colorScheme.TabSelectedBackground); - painter.setPen(ColorScheme::getInstance().Text); + painter.setPen(this->colorScheme.Text); painter.drawText(rect(), "Add Chat", QTextOption(Qt::AlignCenter)); } else { - painter.fillRect(rect(), ColorScheme::getInstance().TabSelectedBackground); + painter.fillRect(rect(), this->colorScheme.TabSelectedBackground); - painter.fillRect(0, 0, width(), 2, ColorScheme::getInstance().TabSelectedBackground); + painter.fillRect(0, 0, width(), 2, this->colorScheme.TabSelectedBackground); } } @@ -269,6 +270,11 @@ std::pair NotebookPage::getChatPosition(const ChatWidget *chatWidget) return getWidgetPositionInLayout(layout, chatWidget); } +ChatWidget *NotebookPage::createChatWidget() +{ + return new ChatWidget(this->channelManager, this); +} + void NotebookPage::load(const boost::property_tree::ptree &tree) { try { @@ -276,7 +282,7 @@ void NotebookPage::load(const boost::property_tree::ptree &tree) for (const auto &v : tree.get_child("columns.")) { int row = 0; for (const auto &innerV : v.second.get_child("")) { - auto widget = new ChatWidget(this->channelManager); + auto widget = this->createChatWidget(); widget->load(innerV.second); addToLayout(widget, std::pair(column, row)); ++row; diff --git a/src/widgets/notebookpage.hpp b/src/widgets/notebookpage.hpp index 6ca554b68..bba5ec032 100644 --- a/src/widgets/notebookpage.hpp +++ b/src/widgets/notebookpage.hpp @@ -1,5 +1,6 @@ #pragma once +#include "widgets/basewidget.hpp" #include "widgets/chatwidget.hpp" #include "widgets/notebookpage.hpp" #include "widgets/notebookpagedroppreview.hpp" @@ -20,12 +21,14 @@ class ChannelManager; namespace widgets { -class NotebookPage : public QWidget +class NotebookPage : public BaseWidget { Q_OBJECT public: - NotebookPage(ChannelManager &_channelManager, QWidget *parent, NotebookTab *_tab); + NotebookPage(ChannelManager &_channelManager, Notebook *parent, NotebookTab *_tab); + + ChannelManager &channelManager; std::pair removeFromLayout(ChatWidget *widget); void addToLayout(ChatWidget *widget, std::pair position); @@ -52,8 +55,6 @@ protected: void dropEvent(QDropEvent *event) override; private: - ChannelManager &channelManager; - struct DropRegion { QRect rect; std::pair position; @@ -79,6 +80,8 @@ private: std::pair getChatPosition(const ChatWidget *chatWidget); + ChatWidget *createChatWidget(); + public: void load(const boost::property_tree::ptree &tree); boost::property_tree::ptree save(); diff --git a/src/widgets/notebookpagedroppreview.cpp b/src/widgets/notebookpagedroppreview.cpp index d344cbca5..a278a8ff8 100644 --- a/src/widgets/notebookpagedroppreview.cpp +++ b/src/widgets/notebookpagedroppreview.cpp @@ -1,5 +1,4 @@ #include "widgets/notebookpagedroppreview.hpp" -#include "colorscheme.hpp" #include #include @@ -7,11 +6,9 @@ namespace chatterino { namespace widgets { -NotebookPageDropPreview::NotebookPageDropPreview(QWidget *parent) - : QWidget(parent) +NotebookPageDropPreview::NotebookPageDropPreview(BaseWidget *parent) + : BaseWidget(parent) , positionAnimation(this, "geometry") - , desiredGeometry() - , animate(false) { this->positionAnimation.setEasingCurve(QEasingCurve(QEasingCurve::InCubic)); this->setHidden(true); @@ -21,13 +18,12 @@ void NotebookPageDropPreview::paintEvent(QPaintEvent *) { QPainter painter(this); - painter.fillRect(8, 8, width() - 17, height() - 17, - ColorScheme::getInstance().DropPreviewBackground); + painter.fillRect(8, 8, width() - 17, height() - 17, this->colorScheme.DropPreviewBackground); } void NotebookPageDropPreview::hideEvent(QHideEvent *) { - animate = false; + this->animate = false; } void NotebookPageDropPreview::setBounds(const QRect &rect) @@ -36,7 +32,7 @@ void NotebookPageDropPreview::setBounds(const QRect &rect) return; } - if (animate) { + if (this->animate) { this->positionAnimation.stop(); this->positionAnimation.setDuration(50); this->positionAnimation.setStartValue(this->geometry()); @@ -48,7 +44,7 @@ void NotebookPageDropPreview::setBounds(const QRect &rect) this->desiredGeometry = rect; - animate = true; + this->animate = true; } } // namespace widgets diff --git a/src/widgets/notebookpagedroppreview.hpp b/src/widgets/notebookpagedroppreview.hpp index 98a6a0383..ae5a51be2 100644 --- a/src/widgets/notebookpagedroppreview.hpp +++ b/src/widgets/notebookpagedroppreview.hpp @@ -1,26 +1,27 @@ #pragma once +#include "widgets/basewidget.hpp" + #include #include namespace chatterino { namespace widgets { -class NotebookPageDropPreview : public QWidget +class NotebookPageDropPreview : public BaseWidget { public: - NotebookPageDropPreview(QWidget *parent); + NotebookPageDropPreview(BaseWidget *parent); void setBounds(const QRect &rect); protected: - void paintEvent(QPaintEvent *); - - void hideEvent(QHideEvent *); + virtual void paintEvent(QPaintEvent *) override; + virtual void hideEvent(QHideEvent *) override; QPropertyAnimation positionAnimation; QRect desiredGeometry; - bool animate; + bool animate = false; }; } // namespace widgets diff --git a/src/widgets/notebooktab.cpp b/src/widgets/notebooktab.cpp index b70e901eb..c6a2bfc31 100644 --- a/src/widgets/notebooktab.cpp +++ b/src/widgets/notebooktab.cpp @@ -10,17 +10,9 @@ namespace widgets { NotebookTab::NotebookTab(Notebook *notebook) : QWidget(notebook) + , colorScheme(notebook->colorScheme) , _posAnimation(this, "pos") - , _posAnimated(false) - , _posAnimationDesired() , _notebook(notebook) - , _title("") - , _selected(false) - , _mouseOver(false) - , _mouseDown(false) - , _mouseOverX(false) - , _mouseDownX(false) - , _highlightStyle(HighlightNone) { this->calcSize(); this->setAcceptDrops(true); @@ -122,23 +114,21 @@ void NotebookTab::paintEvent(QPaintEvent *) QColor fg = QColor(0, 0, 0); - auto &colorScheme = ColorScheme::getInstance(); - if (_selected) { - painter.fillRect(rect(), colorScheme.TabSelectedBackground); - fg = colorScheme.TabSelectedText; + painter.fillRect(rect(), this->colorScheme.TabSelectedBackground); + fg = this->colorScheme.TabSelectedText; } else if (_mouseOver) { - painter.fillRect(rect(), colorScheme.TabHoverBackground); - fg = colorScheme.TabHoverText; + painter.fillRect(rect(), this->colorScheme.TabHoverBackground); + fg = this->colorScheme.TabHoverText; } else if (_highlightStyle == HighlightHighlighted) { - painter.fillRect(rect(), colorScheme.TabHighlightedBackground); - fg = colorScheme.TabHighlightedText; + painter.fillRect(rect(), this->colorScheme.TabHighlightedBackground); + fg = this->colorScheme.TabHighlightedText; } else if (_highlightStyle == HighlightNewMessage) { - painter.fillRect(rect(), colorScheme.TabNewMessageBackground); - fg = colorScheme.TabHighlightedText; + painter.fillRect(rect(), this->colorScheme.TabNewMessageBackground); + fg = this->colorScheme.TabHighlightedText; } else { - painter.fillRect(rect(), colorScheme.TabBackground); - fg = colorScheme.TabText; + painter.fillRect(rect(), this->colorScheme.TabBackground); + fg = this->colorScheme.TabText; } painter.setPen(fg); diff --git a/src/widgets/notebooktab.hpp b/src/widgets/notebooktab.hpp index cc4d90319..287fe72c5 100644 --- a/src/widgets/notebooktab.hpp +++ b/src/widgets/notebooktab.hpp @@ -7,6 +7,9 @@ #include namespace chatterino { + +class ColorScheme; + namespace widgets { class Notebook; @@ -22,6 +25,8 @@ public: explicit NotebookTab(Notebook *_notebook); ~NotebookTab(); + ColorScheme &colorScheme; + void calcSize(); NotebookPage *page; @@ -55,20 +60,20 @@ private: boost::signals2::connection _hideXConnection; QPropertyAnimation _posAnimation; - bool _posAnimated; + bool _posAnimated = false; QPoint _posAnimationDesired; Notebook *_notebook; - QString _title; + QString _title = ""; - bool _selected; - bool _mouseOver; - bool _mouseDown; - bool _mouseOverX; - bool _mouseDownX; + bool _selected = false; + bool _mouseOver = false; + bool _mouseDown = false; + bool _mouseOverX = false; + bool _mouseDownX = false; - HighlightStyle _highlightStyle; + HighlightStyle _highlightStyle = HighlightStyle::HighlightNone; QRect getXRect() { diff --git a/src/widgets/scrollbar.cpp b/src/widgets/scrollbar.cpp index 3601e0589..ea50f5183 100644 --- a/src/widgets/scrollbar.cpp +++ b/src/widgets/scrollbar.cpp @@ -1,5 +1,6 @@ #include "widgets/scrollbar.hpp" #include "colorscheme.hpp" +#include "widgets/chatwidgetview.hpp" #include #include @@ -10,8 +11,8 @@ namespace chatterino { namespace widgets { -ScrollBar::ScrollBar(QWidget *widget) - : QWidget(widget) +ScrollBar::ScrollBar(ChatWidgetView *parent) + : BaseWidget(parent) , _currentValueAnimation(this, "currentValue") , _highlights(nullptr) { @@ -197,7 +198,7 @@ void ScrollBar::printCurrentState(const QString &prefix) const void ScrollBar::paintEvent(QPaintEvent *) { QPainter painter(this); - painter.fillRect(rect(), ColorScheme::getInstance().ScrollbarBG); + painter.fillRect(rect(), this->colorScheme.ScrollbarBG); painter.fillRect(QRect(0, 0, width(), _buttonHeight), QColor(255, 0, 0)); painter.fillRect(QRect(0, height() - _buttonHeight, width(), _buttonHeight), QColor(255, 0, 0)); diff --git a/src/widgets/scrollbar.hpp b/src/widgets/scrollbar.hpp index aba821ab6..626b1dcd4 100644 --- a/src/widgets/scrollbar.hpp +++ b/src/widgets/scrollbar.hpp @@ -1,5 +1,6 @@ #pragma once +#include "widgets/basewidget.hpp" #include "widgets/scrollbarhighlight.hpp" #include @@ -8,14 +9,19 @@ #include namespace chatterino { + +class ColorScheme; + namespace widgets { -class ScrollBar : public QWidget +class ChatWidgetView; + +class ScrollBar : public BaseWidget { Q_OBJECT public: - ScrollBar(QWidget *parent = 0); + ScrollBar(ChatWidgetView *parent = 0); ~ScrollBar(); void removeHighlightsWhere(std::function func); diff --git a/src/widgets/scrollbarhighlight.cpp b/src/widgets/scrollbarhighlight.cpp index 5e912d052..516be9329 100644 --- a/src/widgets/scrollbarhighlight.cpp +++ b/src/widgets/scrollbarhighlight.cpp @@ -1,14 +1,17 @@ #include "widgets/scrollbarhighlight.hpp" #include "colorscheme.hpp" +#include "widgets/scrollbar.hpp" namespace chatterino { namespace widgets { -ScrollBarHighlight::ScrollBarHighlight(float position, int colorIndex, Style style, QString tag) - : _style(style) - , _position(position) - , _colorIndex(std::max(0, std::min(ColorScheme::getInstance().HighlightColorCount, colorIndex))) - , _tag(tag) +ScrollBarHighlight::ScrollBarHighlight(double _position, int _colorIndex, ScrollBar *parent, + Style _style, QString _tag) + : colorScheme(parent->colorScheme) + , position(_position) + , colorIndex(std::max(0, std::min(this->colorScheme.HighlightColorCount, _colorIndex))) + , style(_style) + , tag(_tag) { } diff --git a/src/widgets/scrollbarhighlight.hpp b/src/widgets/scrollbarhighlight.hpp index 53ecd3e85..cca7215d2 100644 --- a/src/widgets/scrollbarhighlight.hpp +++ b/src/widgets/scrollbarhighlight.hpp @@ -3,43 +3,50 @@ #include "QString" namespace chatterino { + +class ColorScheme; + namespace widgets { +class ScrollBar; + class ScrollBarHighlight { public: enum Style { Default, Left, Right, SingleLine }; - ScrollBarHighlight(float getPosition, int getColorIndex, Style getStyle = Default, + ScrollBarHighlight(double _position, int _colorIndex, ScrollBar *parent, Style _style = Default, QString _tag = ""); - Style getStyle() - { - return _style; - } + ColorScheme &colorScheme; - float getPosition() + double getPosition() { - return _position; + return this->position; } int getColorIndex() { - return _colorIndex; + return this->colorIndex; + } + + Style getStyle() + { + return this->style; } QString getTag() { - return _tag; + return this->tag; } ScrollBarHighlight *next = nullptr; private: - Style _style; - float _position; - int _colorIndex; - QString _tag; + double position; + int colorIndex; + Style style; + QString tag; }; } // namespace widgets diff --git a/src/widgets/settingsdialog.cpp b/src/widgets/settingsdialog.cpp index 6f6bf81fb..948a9039d 100644 --- a/src/widgets/settingsdialog.cpp +++ b/src/widgets/settingsdialog.cpp @@ -108,10 +108,31 @@ 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 fontLayout = new QHBoxLayout(); + auto fontFamilyLabel = new QLabel("Current font family"); + auto fontSizeLabel = new QLabel("Current font size"); + auto fontButton = new QPushButton("Select"); + + fontLayout->addWidget(fontButton); + fontLayout->addWidget(fontFamilyLabel); + fontLayout->addWidget(fontSizeLabel); + + { + auto fontManager = FontManager::getInstance(); + + fontManager.currentFontFamily.getValueChangedSignal().connect( + [fontFamilyLabel](const std::string &newValue) { + fontFamilyLabel->setText(QString::fromStdString(newValue)); // + }); + + fontManager.currentFontSize.getValueChangedSignal().connect( + [fontSizeLabel](const int &newValue) { + fontSizeLabel->setText(QString(QString::number(newValue))); // + }); + } + + fontButton->connect(fontButton, &QPushButton::clicked, []() { auto fontManager = FontManager::getInstance(); QFontDialog dialog(fontManager.getFont(FontManager::Medium)); @@ -131,48 +152,61 @@ void SettingsDialog::addTabs() auto hideUserButton = createCheckbox("Hide user button", settings.hideUserButton); form->addRow("Theme:", combo); - form->addRow("Theme color:", slider); - form->addRow("Font:", font); - form->addRow("Tabbar:", compactTabs); + + { + auto hbox = new QHBoxLayout(); + + auto slider = new QSlider(Qt::Horizontal); + // Theme hue + slider->setMinimum(0); + slider->setMaximum(1000); + + slider->setValue(std::min(std::max(settings.themeHue.getValue(), 0.0), 1.0) * 1000); + + hbox->addWidget(slider); + + auto button = new QPushButton(); + button->setFlat(true); + + hbox->addWidget(button); + + form->addRow("Theme color:", hbox); + + QObject::connect(slider, &QSlider::valueChanged, this, [&settings, button](int value) { + settings.themeHue.setValue(value / 1000.0); + + QPalette pal = button->palette(); + QColor color; + color.setHsvF(settings.themeHue.getValue(), 1.0, 1.0, 1.0); + pal.setColor(QPalette::Button, color); + button->setAutoFillBackground(true); + button->setPalette(pal); + button->update(); + + // TODO(pajlada): re-implement + // this->windowManager.updateAll(); + }); + } + + form->addRow("Font:", fontLayout); + form->addRow("Tab bar:", compactTabs); form->addRow("", hidePreferencesButton); form->addRow("", hideUserButton); - // theme + // Theme name combo->addItem("White"); combo->addItem("Light"); combo->addItem("Dark"); combo->addItem("Black"); - QString theme = settings.theme.get(); - theme = theme.toLower(); + auto xD = QString::fromStdString(settings.themeName); - if (theme == "light") { - combo->setCurrentIndex(0); - } else if (theme == "white") { - combo->setCurrentIndex(1); - } else if (theme == "black") { - combo->setCurrentIndex(3); - } else { - combo->setCurrentIndex(2); - } + combo->setCurrentText(xD); QObject::connect(combo, &QComboBox::currentTextChanged, this, - [&settings](const QString &value) { settings.theme.set(value); }); - - // theme hue - slider->setMinimum(0); - slider->setMaximum(1000); - - float hue = settings.themeHue.get(); - - slider->setValue(std::min(std::max(hue, (float)0.0), (float)1.0) * 1000); - - QObject::connect(slider, &QSlider::valueChanged, this, [&settings](int value) { - settings.themeHue.set(value / 1000.0); - - // TODO(pajlada): re-implement - // this->windowManager.updateAll(); - }); + [&settings](const QString &value) { + settings.themeName.setValue(value.toStdString()); // + }); group->setLayout(form); diff --git a/src/windowmanager.cpp b/src/windowmanager.cpp index 8bfee6753..b3d7fd594 100644 --- a/src/windowmanager.cpp +++ b/src/windowmanager.cpp @@ -1,6 +1,7 @@ #include "windowmanager.hpp" #include "appdatapath.hpp" #include "channelmanager.hpp" +#include "colorscheme.hpp" #include #include @@ -9,8 +10,9 @@ namespace chatterino { -WindowManager::WindowManager(ChannelManager &_channelManager) +WindowManager::WindowManager(ChannelManager &_channelManager, ColorScheme &_colorScheme) : channelManager(_channelManager) + , colorScheme(_colorScheme) { } @@ -54,7 +56,7 @@ widgets::MainWindow &WindowManager::getMainWindow() std::lock_guard lock(this->windowMutex); if (this->mainWindow == nullptr) { - this->mainWindow = new widgets::MainWindow(this->channelManager); + this->mainWindow = new widgets::MainWindow(this->channelManager, this->colorScheme); } return *this->mainWindow; diff --git a/src/windowmanager.hpp b/src/windowmanager.hpp index cf81433a4..4cdb05520 100644 --- a/src/windowmanager.hpp +++ b/src/windowmanager.hpp @@ -7,11 +7,15 @@ namespace chatterino { class ChannelManager; +class ColorScheme; class WindowManager { public: - explicit WindowManager(ChannelManager &_channelManager); + explicit WindowManager(ChannelManager &_channelManager, ColorScheme &_colorScheme); + + ChannelManager &channelManager; + ColorScheme &colorScheme; void layoutVisibleChatWidgets(Channel *channel = nullptr); void repaintVisibleChatWidgets(Channel *channel = nullptr); @@ -24,8 +28,6 @@ public: void save(); private: - ChannelManager &channelManager; - std::mutex windowMutex; // TODO(pajlada): Store as a value instead of a pointer