diff --git a/.clang-tidy b/.clang-tidy index 2610cd3e784..db94ae838fb 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -18,6 +18,7 @@ Checks: "-*, -cppcoreguidelines-pro-bounds-array-to-pointer-decay, -cppcoreguidelines-owning-memory, -cppcoreguidelines-avoid-magic-numbers, + -cppcoreguidelines-avoid-const-or-ref-data-members, -readability-magic-numbers, -performance-noexcept-move-constructor, -misc-non-private-member-variables-in-classes, diff --git a/CHANGELOG.md b/CHANGELOG.md index f354bb112bd..62f7f4ee9cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ - Dev: Moved preprocessor Git and date definitions to executables only. (#4681) - Dev: Refactored tests to be able to use `ctest` and run in debug builds. (#4700) - Dev: Added the ability to use an alternate linker using the `-DUSE_ALTERNATE_LINKER=...` CMake parameter. (#4711) +- Dev: Removed `getApp` and `getSettings` calls from message rendering. (#4535) ## 2.4.4 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b1df0023ae8..ec57cc6dbda 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -206,6 +206,8 @@ set(SOURCE_FILES messages/layouts/MessageLayout.hpp messages/layouts/MessageLayoutContainer.cpp messages/layouts/MessageLayoutContainer.hpp + messages/layouts/MessageLayoutContext.cpp + messages/layouts/MessageLayoutContext.hpp messages/layouts/MessageLayoutElement.cpp messages/layouts/MessageLayoutElement.hpp messages/search/AuthorPredicate.cpp diff --git a/src/common/Literals.hpp b/src/common/Literals.hpp index fdf9822a36b..b7276d499cf 100644 --- a/src/common/Literals.hpp +++ b/src/common/Literals.hpp @@ -24,7 +24,6 @@ namespace chatterino::literals { namespace detail { // NOLINTBEGIN(modernize-avoid-c-arrays) // NOLINTBEGIN(cppcoreguidelines-avoid-c-arrays) - // NOLINTBEGIN(cppcoreguidelines-avoid-const-or-ref-data-members) template struct LiteralResolver { @@ -95,7 +94,6 @@ namespace detail { } }; - // NOLINTEND(cppcoreguidelines-avoid-const-or-ref-data-members) // NOLINTEND(cppcoreguidelines-avoid-c-arrays) // NOLINTEND(modernize-avoid-c-arrays) diff --git a/src/messages/layouts/MessageLayout.cpp b/src/messages/layouts/MessageLayout.cpp index 00bc3b46daf..e5b1800917f 100644 --- a/src/messages/layouts/MessageLayout.cpp +++ b/src/messages/layouts/MessageLayout.cpp @@ -1,16 +1,14 @@ #include "messages/layouts/MessageLayout.hpp" #include "Application.hpp" -#include "debug/Benchmark.hpp" #include "messages/layouts/MessageLayoutContainer.hpp" +#include "messages/layouts/MessageLayoutContext.hpp" #include "messages/layouts/MessageLayoutElement.hpp" #include "messages/Message.hpp" #include "messages/MessageElement.hpp" #include "messages/Selection.hpp" #include "providers/colors/ColorProvider.hpp" -#include "singletons/Emotes.hpp" #include "singletons/Settings.hpp" -#include "singletons/Theme.hpp" #include "singletons/WindowManager.hpp" #include "util/DebugCount.hpp" #include "util/StreamerMode.hpp" @@ -198,84 +196,77 @@ void MessageLayout::actuallyLayout(int width, MessageElementFlags flags) } // Painting -void MessageLayout::paint(QPainter &painter, int width, int y, int messageIndex, - Selection &selection, bool isLastReadMessage, - bool isWindowFocused, bool isMentions) +void MessageLayout::paint(const MessagePaintContext &ctx) { - auto app = getApp(); - QPixmap *pixmap = this->ensureBuffer(painter, width); + QPixmap *pixmap = this->ensureBuffer(ctx.painter, ctx.canvasWidth); - if (!this->bufferValid_ || !selection.isEmpty()) + if (!this->bufferValid_ || !ctx.selection.isEmpty()) { - this->updateBuffer(pixmap, messageIndex, selection); + this->updateBuffer(pixmap, ctx); } // draw on buffer - painter.drawPixmap(0, y, *pixmap); - // painter.drawPixmap(0, y, this->container.width, - // this->container.getHeight(), *pixmap); + ctx.painter.drawPixmap(0, ctx.y, *pixmap); // draw gif emotes - this->container_.paintAnimatedElements(painter, y); + this->container_.paintAnimatedElements(ctx.painter, ctx.y); // draw disabled if (this->message_->flags.has(MessageFlag::Disabled)) { - painter.fillRect(0, y, pixmap->width(), pixmap->height(), - app->themes->messages.disabled); - // painter.fillRect(0, y, pixmap->width(), pixmap->height(), - // QBrush(QColor(64, 64, 64, 64))); + ctx.painter.fillRect(0, ctx.y, pixmap->width(), pixmap->height(), + ctx.messageColors.disabled); } if (this->message_->flags.has(MessageFlag::RecentMessage)) { - painter.fillRect(0, y, pixmap->width(), pixmap->height(), - app->themes->messages.disabled); + ctx.painter.fillRect(0, ctx.y, pixmap->width(), pixmap->height(), + ctx.messageColors.disabled); } - if (!isMentions && + if (!ctx.isMentions && (this->message_->flags.has(MessageFlag::RedeemedChannelPointReward) || this->message_->flags.has(MessageFlag::RedeemedHighlight)) && - getSettings()->enableRedeemedHighlight.getValue()) + ctx.preferences.enableRedeemedHighlight) { - painter.fillRect( - 0, y, this->scale_ * 4, pixmap->height(), + ctx.painter.fillRect( + 0, ctx.y, int(this->scale_ * 4), pixmap->height(), *ColorProvider::instance().color(ColorType::RedeemedHighlight)); } // draw selection - if (!selection.isEmpty()) + if (!ctx.selection.isEmpty()) { - this->container_.paintSelection(painter, messageIndex, selection, y); + this->container_.paintSelection(ctx.painter, ctx.messageIndex, + ctx.selection, ctx.y); } // draw message seperation line - if (getSettings()->separateMessages.getValue()) + if (ctx.preferences.separateMessages) { - painter.fillRect(0, y, this->container_.getWidth() + 64, 1, - app->themes->splits.messageSeperator); + ctx.painter.fillRect(0, ctx.y, this->container_.getWidth() + 64, 1, + ctx.messageColors.messageSeperator); } // draw last read message line - if (isLastReadMessage) + if (ctx.isLastReadMessage) { QColor color; - if (getSettings()->lastMessageColor != QStringLiteral("")) + if (ctx.preferences.lastMessageColor.isValid()) { - color = QColor(getSettings()->lastMessageColor.getValue()); + color = ctx.preferences.lastMessageColor; } else { - color = isWindowFocused - ? app->themes->tabs.selected.backgrounds.regular - : app->themes->tabs.selected.backgrounds.unfocused; + color = ctx.isWindowFocused + ? ctx.messageColors.focusedLastMessageLine + : ctx.messageColors.unfocusedLastMessageLine; } - QBrush brush(color, static_cast( - getSettings()->lastMessagePattern.getValue())); + QBrush brush(color, ctx.preferences.lastMessagePattern); - painter.fillRect(0, y + this->container_.getHeight() - 1, - pixmap->width(), 1, brush); + ctx.painter.fillRect(0, ctx.y + this->container_.getHeight() - 1, + pixmap->width(), 1, brush); } this->bufferValid_ = true; @@ -305,45 +296,42 @@ QPixmap *MessageLayout::ensureBuffer(QPainter &painter, int width) return this->buffer_.get(); } -void MessageLayout::updateBuffer(QPixmap *buffer, int /*messageIndex*/, - Selection & /*selection*/) +void MessageLayout::updateBuffer(QPixmap *buffer, + const MessagePaintContext &ctx) { if (buffer->isNull()) + { return; - - auto app = getApp(); - auto settings = getSettings(); + } QPainter painter(buffer); painter.setRenderHint(QPainter::SmoothPixmapTransform); // draw background - QColor backgroundColor = [this, &app] { - if (getSettings()->alternateMessages.getValue() && + QColor backgroundColor = [&] { + if (ctx.preferences.alternateMessages && this->flags.has(MessageLayoutFlag::AlternateBackground)) { - return app->themes->messages.backgrounds.alternate; - } - else - { - return app->themes->messages.backgrounds.regular; + return ctx.messageColors.alternate; } + + return ctx.messageColors.regular; }(); if (this->message_->flags.has(MessageFlag::ElevatedMessage) && - getSettings()->enableElevatedMessageHighlight.getValue()) + ctx.preferences.enableElevatedMessageHighlight) { - backgroundColor = blendColors(backgroundColor, - *ColorProvider::instance().color( - ColorType::ElevatedMessageHighlight)); + backgroundColor = blendColors( + backgroundColor, + *ctx.colorProvider.color(ColorType::ElevatedMessageHighlight)); } else if (this->message_->flags.has(MessageFlag::FirstMessage) && - getSettings()->enableFirstMessageHighlight.getValue()) + ctx.preferences.enableFirstMessageHighlight) { backgroundColor = blendColors( backgroundColor, - *ColorProvider::instance().color(ColorType::FirstMessageHighlight)); + *ctx.colorProvider.color(ColorType::FirstMessageHighlight)); } else if ((this->message_->flags.has(MessageFlag::Highlighted) || this->message_->flags.has(MessageFlag::HighlightedWhisper)) && @@ -354,22 +342,21 @@ void MessageLayout::updateBuffer(QPixmap *buffer, int /*messageIndex*/, blendColors(backgroundColor, *this->message_->highlightColor); } else if (this->message_->flags.has(MessageFlag::Subscription) && - getSettings()->enableSubHighlight) + ctx.preferences.enableSubHighlight) { // Blend highlight color with usual background color backgroundColor = blendColors( - backgroundColor, - *ColorProvider::instance().color(ColorType::Subscription)); + backgroundColor, *ctx.colorProvider.color(ColorType::Subscription)); } else if ((this->message_->flags.has(MessageFlag::RedeemedHighlight) || this->message_->flags.has( MessageFlag::RedeemedChannelPointReward)) && - settings->enableRedeemedHighlight.getValue()) + ctx.preferences.enableRedeemedHighlight) { // Blend highlight color with usual background color - backgroundColor = blendColors( - backgroundColor, - *ColorProvider::instance().color(ColorType::RedeemedHighlight)); + backgroundColor = + blendColors(backgroundColor, + *ctx.colorProvider.color(ColorType::RedeemedHighlight)); } else if (this->message_->flags.has(MessageFlag::AutoMod)) { @@ -383,7 +370,7 @@ void MessageLayout::updateBuffer(QPixmap *buffer, int /*messageIndex*/, painter.fillRect(buffer->rect(), backgroundColor); // draw message - this->container_.paintElements(painter); + this->container_.paintElements(painter, ctx); #ifdef FOURTF // debug diff --git a/src/messages/layouts/MessageLayout.hpp b/src/messages/layouts/MessageLayout.hpp index c0e64709f53..81d7e403508 100644 --- a/src/messages/layouts/MessageLayout.hpp +++ b/src/messages/layouts/MessageLayout.hpp @@ -18,6 +18,7 @@ using MessagePtr = std::shared_ptr; struct Selection; struct MessageLayoutContainer; class MessageLayoutElement; +struct MessagePaintContext; enum class MessageElementFlag : int64_t; using MessageElementFlags = FlagsEnum; @@ -49,9 +50,7 @@ class MessageLayout : boost::noncopyable bool layout(int width, float scale_, MessageElementFlags flags); // Painting - void paint(QPainter &painter, int width, int y, int messageIndex, - Selection &selection, bool isLastReadMessage, - bool isWindowFocused, bool isMentions); + void paint(const MessagePaintContext &ctx); void invalidateBuffer(); void deleteBuffer(); void deleteCache(); @@ -72,7 +71,7 @@ class MessageLayout : boost::noncopyable private: // methods void actuallyLayout(int width, MessageElementFlags flags); - void updateBuffer(QPixmap *pixmap, int messageIndex, Selection &selection); + void updateBuffer(QPixmap *buffer, const MessagePaintContext &ctx); // Create new buffer if required, returning the buffer QPixmap *ensureBuffer(QPainter &painter, int width); diff --git a/src/messages/layouts/MessageLayoutContainer.cpp b/src/messages/layouts/MessageLayoutContainer.cpp index 8f279788040..0081759703a 100644 --- a/src/messages/layouts/MessageLayoutContainer.cpp +++ b/src/messages/layouts/MessageLayoutContainer.cpp @@ -1,6 +1,7 @@ #include "MessageLayoutContainer.hpp" #include "Application.hpp" +#include "messages/layouts/MessageLayoutContext.hpp" #include "messages/layouts/MessageLayoutElement.hpp" #include "messages/Message.hpp" #include "messages/MessageElement.hpp" @@ -151,7 +152,7 @@ void MessageLayoutContainer::_addElement(MessageLayoutElement *element, } // top margin - if (this->elements_.size() == 0) + if (this->elements_.empty()) { this->currentY_ = int(this->margin.top * this->scale_); } @@ -386,7 +387,7 @@ void MessageLayoutContainer::breakLine() element->getRect().y() + this->lineHeight_ + yExtra)); } - if (this->lines_.size() != 0) + if (!this->lines_.empty()) { this->lines_.back().endIndex = this->lineStart_; this->lines_.back().endCharIndex = this->charIndex_; @@ -395,7 +396,7 @@ void MessageLayoutContainer::breakLine() {(int)lineStart_, 0, this->charIndex_, 0, QRect(-100000, this->currentY_, 200000, lineHeight_)}); - for (int i = this->lineStart_; i < this->elements_.size(); i++) + for (auto i = this->lineStart_; i < this->elements_.size(); i++) { this->charIndex_ += this->elements_[i]->getSelectionIndexCount(); } @@ -465,7 +466,7 @@ void MessageLayoutContainer::end() this->height_ += this->lineHeight_; - if (this->lines_.size() != 0) + if (!this->lines_.empty()) { this->lines_[0].rect.setTop(-100000); this->lines_.back().rect.setBottom(100000); @@ -480,7 +481,7 @@ bool MessageLayoutContainer::canCollapse() this->flags_.has(MessageFlag::Collapsed); } -bool MessageLayoutContainer::isCollapsed() +bool MessageLayoutContainer::isCollapsed() const { return this->isCollapsed_; } @@ -499,7 +500,8 @@ MessageLayoutElement *MessageLayoutContainer::getElementAt(QPoint point) } // painting -void MessageLayoutContainer::paintElements(QPainter &painter) +void MessageLayoutContainer::paintElements(QPainter &painter, + const MessagePaintContext &ctx) { for (const std::unique_ptr &element : this->elements_) { @@ -508,7 +510,7 @@ void MessageLayoutContainer::paintElements(QPainter &painter) painter.drawRect(element->getRect()); #endif - element->paint(painter); + element->paint(painter, ctx.messageColors); } } @@ -521,10 +523,12 @@ void MessageLayoutContainer::paintAnimatedElements(QPainter &painter, } } -void MessageLayoutContainer::paintSelection(QPainter &painter, int messageIndex, - Selection &selection, int yOffset) +void MessageLayoutContainer::paintSelection(QPainter &painter, + size_t messageIndex, + const Selection &selection, + int yOffset) { - auto app = getApp(); + auto *app = getApp(); QColor selectionColor = app->themes->messages.selection; // don't draw anything @@ -713,7 +717,7 @@ void MessageLayoutContainer::paintSelection(QPainter &painter, int messageIndex, // selection int MessageLayoutContainer::getSelectionIndex(QPoint point) { - if (this->elements_.size() == 0) + if (this->elements_.empty()) { return 0; } @@ -774,7 +778,7 @@ int MessageLayoutContainer::getSelectionIndex(QPoint point) // fourtf: no idea if this is acurate LOL int MessageLayoutContainer::getLastCharacterIndex() const { - if (this->lines_.size() == 0) + if (this->lines_.empty()) { return 0; } @@ -791,7 +795,7 @@ int MessageLayoutContainer::getFirstMessageCharacterIndex() const // Get the index of the first character of the real message int index = 0; - for (auto &element : this->elements_) + for (const auto &element : this->elements_) { if (element->getFlags().hasAny(skippedFlags)) { @@ -853,10 +857,8 @@ void MessageLayoutContainer::addSelectionText(QString &str, uint32_t from, element->addCopyTextToString(str, 0, to - index); break; } - else - { - element->addCopyTextToString(str); - } + + element->addCopyTextToString(str); } index += indexCount; diff --git a/src/messages/layouts/MessageLayoutContainer.hpp b/src/messages/layouts/MessageLayoutContainer.hpp index 41bb0d941c8..bdbe1b486f9 100644 --- a/src/messages/layouts/MessageLayoutContainer.hpp +++ b/src/messages/layouts/MessageLayoutContainer.hpp @@ -18,6 +18,7 @@ enum class FirstWord { Neutral, RTL, LTR }; using MessageFlags = FlagsEnum; class MessageLayoutElement; struct Selection; +struct MessagePaintContext; struct Margin { int top; @@ -73,10 +74,10 @@ struct MessageLayoutContainer { MessageLayoutElement *getElementAt(QPoint point); // painting - void paintElements(QPainter &painter); + void paintElements(QPainter &painter, const MessagePaintContext &ctx); void paintAnimatedElements(QPainter &painter, int yOffset); - void paintSelection(QPainter &painter, int messageIndex, - Selection &selection, int yOffset); + void paintSelection(QPainter &painter, size_t messageIndex, + const Selection &selection, int yOffset); // selection int getSelectionIndex(QPoint point); @@ -85,7 +86,7 @@ struct MessageLayoutContainer { void addSelectionText(QString &str, uint32_t from, uint32_t to, CopyMode copymode); - bool isCollapsed(); + bool isCollapsed() const; private: struct Line { diff --git a/src/messages/layouts/MessageLayoutContext.cpp b/src/messages/layouts/MessageLayoutContext.cpp new file mode 100644 index 00000000000..82b158485fe --- /dev/null +++ b/src/messages/layouts/MessageLayoutContext.cpp @@ -0,0 +1,82 @@ +#include "messages/layouts/MessageLayoutContext.hpp" + +#include "singletons/Settings.hpp" +#include "singletons/Theme.hpp" + +namespace chatterino { + +void MessageColors::applyTheme(Theme *theme) +{ + this->regular = theme->messages.backgrounds.regular; + this->alternate = theme->messages.backgrounds.alternate; + + this->disabled = theme->messages.disabled; + this->selection = theme->messages.selection; + this->system = theme->messages.textColors.system; + + this->messageSeperator = theme->splits.messageSeperator; + + this->focusedLastMessageLine = theme->tabs.selected.backgrounds.regular; + this->unfocusedLastMessageLine = theme->tabs.selected.backgrounds.unfocused; +} + +void MessagePreferences::connectSettings(Settings *settings, + pajlada::Signals::SignalHolder &holder) +{ + settings->enableRedeemedHighlight.connect( + [this](const auto &newValue) { + this->enableRedeemedHighlight = newValue; + }, + holder); + + settings->enableElevatedMessageHighlight.connect( + [this](const auto &newValue) { + this->enableElevatedMessageHighlight = newValue; + }, + holder); + + settings->enableFirstMessageHighlight.connect( + [this](const auto &newValue) { + this->enableFirstMessageHighlight = newValue; + }, + holder); + + settings->enableSubHighlight.connect( + [this](const auto &newValue) { + this->enableSubHighlight = newValue; + }, + holder); + + settings->alternateMessages.connect( + [this](const auto &newValue) { + this->alternateMessages = newValue; + }, + holder); + + settings->separateMessages.connect( + [this](const auto &newValue) { + this->separateMessages = newValue; + }, + holder); + + settings->lastMessageColor.connect( + [this](const auto &newValue) { + if (newValue.isEmpty()) + { + this->lastMessageColor = QColor(); + } + else + { + this->lastMessageColor = QColor(newValue); + } + }, + holder); + + settings->lastMessagePattern.connect( + [this](const auto &newValue) { + this->lastMessagePattern = static_cast(newValue); + }, + holder); +} + +} // namespace chatterino diff --git a/src/messages/layouts/MessageLayoutContext.hpp b/src/messages/layouts/MessageLayoutContext.hpp new file mode 100644 index 00000000000..a64d98bb448 --- /dev/null +++ b/src/messages/layouts/MessageLayoutContext.hpp @@ -0,0 +1,74 @@ +#pragma once + +#include +#include + +namespace pajlada::Signals { +class SignalHolder; +} // namespace pajlada::Signals + +namespace chatterino { + +class ColorProvider; +class Theme; +class Settings; +struct Selection; + +// TODO: Figure out if this could be a subset of Theme instead (e.g. Theme::MessageColors) +struct MessageColors { + QColor regular; + QColor alternate; + QColor disabled; + QColor selection; + QColor system; + + QColor messageSeperator; + + QColor focusedLastMessageLine; + QColor unfocusedLastMessageLine; + + void applyTheme(Theme *theme); +}; + +// TODO: Explore if we can let settings own this +struct MessagePreferences { + QColor lastMessageColor; + Qt::BrushStyle lastMessagePattern{}; + + bool enableRedeemedHighlight{}; + bool enableElevatedMessageHighlight{}; + bool enableFirstMessageHighlight{}; + bool enableSubHighlight{}; + + bool alternateMessages{}; + bool separateMessages{}; + + void connectSettings(Settings *settings, + pajlada::Signals::SignalHolder &holder); +}; + +struct MessagePaintContext { + QPainter &painter; + const Selection &selection; + const ColorProvider &colorProvider; + const MessageColors &messageColors; + const MessagePreferences &preferences; + + // width of the area we have to draw on + const int canvasWidth{}; + // whether the painting should be treated as if this view's window is focused + const bool isWindowFocused{}; + // whether the painting should be treated as if this view is the special mentions view + const bool isMentions{}; + + // y coordinate we're currently painting at + int y{}; + + // Index of the message that is currently being painted + // This index refers to the snapshot being used in the painting + size_t messageIndex{}; + + bool isLastReadMessage{}; +}; + +} // namespace chatterino diff --git a/src/messages/layouts/MessageLayoutElement.cpp b/src/messages/layouts/MessageLayoutElement.cpp index cd071b4f252..fc525d4e406 100644 --- a/src/messages/layouts/MessageLayoutElement.cpp +++ b/src/messages/layouts/MessageLayoutElement.cpp @@ -3,9 +3,9 @@ #include "Application.hpp" #include "messages/Emote.hpp" #include "messages/Image.hpp" +#include "messages/layouts/MessageLayoutContext.hpp" #include "messages/MessageElement.hpp" #include "providers/twitch/TwitchEmotes.hpp" -#include "singletons/Theme.hpp" #include "util/DebugCount.hpp" #include @@ -137,7 +137,8 @@ int ImageLayoutElement::getSelectionIndexCount() const return this->trailingSpace ? 2 : 1; } -void ImageLayoutElement::paint(QPainter &painter) +void ImageLayoutElement::paint(QPainter &painter, + const MessageColors & /*messageColors*/) { if (this->image_ == nullptr) { @@ -228,7 +229,8 @@ int LayeredImageLayoutElement::getSelectionIndexCount() const return this->trailingSpace ? 2 : 1; } -void LayeredImageLayoutElement::paint(QPainter &painter) +void LayeredImageLayoutElement::paint(QPainter &painter, + const MessageColors & /*messageColors*/) { auto fullRect = QRectF(this->getRect()); @@ -329,7 +331,8 @@ ImageWithBackgroundLayoutElement::ImageWithBackgroundLayoutElement( { } -void ImageWithBackgroundLayoutElement::paint(QPainter &painter) +void ImageWithBackgroundLayoutElement::paint( + QPainter &painter, const MessageColors & /*messageColors*/) { if (this->image_ == nullptr) { @@ -360,7 +363,8 @@ ImageWithCircleBackgroundLayoutElement::ImageWithCircleBackgroundLayoutElement( { } -void ImageWithCircleBackgroundLayoutElement::paint(QPainter &painter) +void ImageWithCircleBackgroundLayoutElement::paint( + QPainter &painter, const MessageColors & /*messageColors*/) { if (this->image_ == nullptr) { @@ -423,7 +427,8 @@ int TextLayoutElement::getSelectionIndexCount() const return this->getText().length() + (this->trailingSpace ? 1 : 0); } -void TextLayoutElement::paint(QPainter &painter) +void TextLayoutElement::paint(QPainter &painter, + const MessageColors & /*messageColors*/) { auto app = getApp(); QString text = this->getText(); @@ -532,13 +537,14 @@ int TextIconLayoutElement::getSelectionIndexCount() const return this->trailingSpace ? 2 : 1; } -void TextIconLayoutElement::paint(QPainter &painter) +void TextIconLayoutElement::paint(QPainter &painter, + const MessageColors &messageColors) { - auto app = getApp(); + auto *app = getApp(); QFont font = app->fonts->getFont(FontStyle::Tiny, this->scale); - painter.setPen(app->themes->messages.textColors.system); + painter.setPen(messageColors.system); painter.setFont(font); QTextOption option; @@ -598,7 +604,8 @@ ReplyCurveLayoutElement::ReplyCurveLayoutElement(MessageElement &creator, { } -void ReplyCurveLayoutElement::paint(QPainter &painter) +void ReplyCurveLayoutElement::paint(QPainter &painter, + const MessageColors & /*messageColors*/) { QRectF paintRect(this->getRect()); QPainterPath path; diff --git a/src/messages/layouts/MessageLayoutElement.hpp b/src/messages/layouts/MessageLayoutElement.hpp index e4c930845b0..2a4ec030e1e 100644 --- a/src/messages/layouts/MessageLayoutElement.hpp +++ b/src/messages/layouts/MessageLayoutElement.hpp @@ -21,6 +21,7 @@ class Image; using ImagePtr = std::shared_ptr; enum class FontStyle : uint8_t; enum class MessageElementFlag : int64_t; +struct MessageColors; class MessageLayoutElement : boost::noncopyable { @@ -44,7 +45,8 @@ class MessageLayoutElement : boost::noncopyable virtual void addCopyTextToString(QString &str, uint32_t from = 0, uint32_t to = UINT32_MAX) const = 0; virtual int getSelectionIndexCount() const = 0; - virtual void paint(QPainter &painter) = 0; + virtual void paint(QPainter &painter, + const MessageColors &messageColors) = 0; virtual void paintAnimated(QPainter &painter, int yOffset) = 0; virtual int getMouseOverIndex(const QPoint &abs) const = 0; virtual int getXFromIndex(int index) = 0; @@ -75,7 +77,7 @@ class ImageLayoutElement : public MessageLayoutElement void addCopyTextToString(QString &str, uint32_t from = 0, uint32_t to = UINT32_MAX) const override; int getSelectionIndexCount() const override; - void paint(QPainter &painter) override; + void paint(QPainter &painter, const MessageColors &messageColors) override; void paintAnimated(QPainter &painter, int yOffset) override; int getMouseOverIndex(const QPoint &abs) const override; int getXFromIndex(int index) override; @@ -94,7 +96,7 @@ class LayeredImageLayoutElement : public MessageLayoutElement void addCopyTextToString(QString &str, uint32_t from = 0, uint32_t to = UINT32_MAX) const override; int getSelectionIndexCount() const override; - void paint(QPainter &painter) override; + void paint(QPainter &painter, const MessageColors &messageColors) override; void paintAnimated(QPainter &painter, int yOffset) override; int getMouseOverIndex(const QPoint &abs) const override; int getXFromIndex(int index) override; @@ -110,7 +112,7 @@ class ImageWithBackgroundLayoutElement : public ImageLayoutElement const QSize &size, QColor color); protected: - void paint(QPainter &painter) override; + void paint(QPainter &painter, const MessageColors &messageColors) override; private: QColor color_; @@ -125,7 +127,7 @@ class ImageWithCircleBackgroundLayoutElement : public ImageLayoutElement int padding); protected: - void paint(QPainter &painter) override; + void paint(QPainter &painter, const MessageColors &messageColors) override; private: const QColor color_; @@ -147,7 +149,7 @@ class TextLayoutElement : public MessageLayoutElement void addCopyTextToString(QString &str, uint32_t from = 0, uint32_t to = UINT32_MAX) const override; int getSelectionIndexCount() const override; - void paint(QPainter &painter) override; + void paint(QPainter &painter, const MessageColors &messageColors) override; void paintAnimated(QPainter &painter, int yOffset) override; int getMouseOverIndex(const QPoint &abs) const override; int getXFromIndex(int index) override; @@ -171,7 +173,7 @@ class TextIconLayoutElement : public MessageLayoutElement void addCopyTextToString(QString &str, uint32_t from = 0, uint32_t to = UINT32_MAX) const override; int getSelectionIndexCount() const override; - void paint(QPainter &painter) override; + void paint(QPainter &painter, const MessageColors &messageColors) override; void paintAnimated(QPainter &painter, int yOffset) override; int getMouseOverIndex(const QPoint &abs) const override; int getXFromIndex(int index) override; @@ -189,7 +191,7 @@ class ReplyCurveLayoutElement : public MessageLayoutElement float radius, float neededMargin); protected: - void paint(QPainter &painter) override; + void paint(QPainter &painter, const MessageColors &messageColors) override; void paintAnimated(QPainter &painter, int yOffset) override; int getMouseOverIndex(const QPoint &abs) const override; int getXFromIndex(int index) override; diff --git a/src/widgets/helper/ChannelView.cpp b/src/widgets/helper/ChannelView.cpp index 15dd806fa63..89fd07502bc 100644 --- a/src/widgets/helper/ChannelView.cpp +++ b/src/widgets/helper/ChannelView.cpp @@ -11,12 +11,14 @@ #include "messages/Emote.hpp" #include "messages/Image.hpp" #include "messages/layouts/MessageLayout.hpp" +#include "messages/layouts/MessageLayoutContext.hpp" #include "messages/layouts/MessageLayoutElement.hpp" #include "messages/LimitedQueueSnapshot.hpp" #include "messages/Message.hpp" #include "messages/MessageBuilder.hpp" #include "messages/MessageElement.hpp" #include "messages/MessageThread.hpp" +#include "providers/colors/ColorProvider.hpp" #include "providers/LinkResolver.hpp" #include "providers/twitch/TwitchAccount.hpp" #include "providers/twitch/TwitchChannel.hpp" @@ -61,7 +63,6 @@ #include #include -#define DRAW_WIDTH (this->width()) #define SELECTION_RESUME_SCROLLING_MSG_THRESHOLD 3 #define CHAT_HOVER_PAUSE_DURATION 1000 #define TOOLTIP_EMOTE_ENTRIES_LIMIT 7 @@ -201,6 +202,10 @@ ChannelView::ChannelView(BaseWidget *parent, Split *split, Context context, auto curve = QEasingCurve(); curve.setCustomType(highlightEasingFunction); this->highlightAnimation_.setEasingCurve(curve); + + this->messageColors_.applyTheme(getTheme()); + this->messagePreferences_.connectSettings(getSettings(), + this->signalHolder_); } void ChannelView::initializeLayout() @@ -378,6 +383,7 @@ void ChannelView::themeChangedEvent() this->setupHighlightAnimationColors(); this->queueLayout(); + this->messageColors_.applyTheme(getTheme()); } void ChannelView::setupHighlightAnimationColors() @@ -1247,32 +1253,47 @@ void ChannelView::drawMessages(QPainter &painter) return; } - int y = int(-(messagesSnapshot[start].get()->getHeight() * - (fmod(this->scrollBar_->getRelativeCurrentValue(), 1)))); - MessageLayout *end = nullptr; - bool windowFocused = this->window() == QApplication::activeWindow(); - auto app = getApp(); - bool isMentions = this->underlyingChannel_ == app->twitch->mentionsChannel; + MessagePaintContext ctx = { + .painter = painter, + .selection = this->selection_, + .colorProvider = ColorProvider::instance(), + .messageColors = this->messageColors_, + .preferences = this->messagePreferences_, - for (size_t i = start; i < messagesSnapshot.size(); ++i) + .canvasWidth = this->width(), + .isWindowFocused = this->window() == QApplication::activeWindow(), + .isMentions = + this->underlyingChannel_ == getApp()->twitch->mentionsChannel, + + .y = int(-(messagesSnapshot[start]->getHeight() * + (fmod(this->scrollBar_->getRelativeCurrentValue(), 1)))), + .messageIndex = start, + .isLastReadMessage = false, + + }; + bool showLastMessageIndicator = getSettings()->showLastMessageIndicator; + + for (; ctx.messageIndex < messagesSnapshot.size(); ++ctx.messageIndex) { - MessageLayout *layout = messagesSnapshot[i].get(); + MessageLayout *layout = messagesSnapshot[ctx.messageIndex].get(); - bool isLastMessage = false; - if (getSettings()->showLastMessageIndicator) + if (showLastMessageIndicator) + { + ctx.isLastReadMessage = this->lastReadMessage_.get() == layout; + } + else { - isLastMessage = this->lastReadMessage_.get() == layout; + ctx.isLastReadMessage = false; } - layout->paint(painter, DRAW_WIDTH, y, i, this->selection_, - isLastMessage, windowFocused, isMentions); + layout->paint(ctx); if (this->highlightedMessage_ == layout) { painter.fillRect( - 0, y, layout->getWidth(), layout->getHeight(), + 0, ctx.y, layout->getWidth(), layout->getHeight(), this->highlightAnimation_.currentValue().value()); if (this->highlightAnimation_.state() == QVariantAnimation::Stopped) { @@ -1280,10 +1301,10 @@ void ChannelView::drawMessages(QPainter &painter) } } - y += layout->getHeight(); + ctx.y += layout->getHeight(); end = layout; - if (y > this->height()) + if (ctx.y > this->height()) { break; } diff --git a/src/widgets/helper/ChannelView.hpp b/src/widgets/helper/ChannelView.hpp index a3112176828..f5a7da1742a 100644 --- a/src/widgets/helper/ChannelView.hpp +++ b/src/widgets/helper/ChannelView.hpp @@ -1,6 +1,7 @@ #pragma once #include "common/FlagsEnum.hpp" +#include "messages/layouts/MessageLayoutContext.hpp" #include "messages/LimitedQueue.hpp" #include "messages/LimitedQueueSnapshot.hpp" #include "messages/Selection.hpp" @@ -343,6 +344,9 @@ class ChannelView final : public BaseWidget std::unordered_set> messagesOnScreen_; + MessageColors messageColors_; + MessagePreferences messagePreferences_; + static constexpr int leftPadding = 8; static constexpr int scrollbarPadding = 8;