Remove getApp and getSettings calls from Message-Rendering (#4535)

* refactor: remove singletons from message rendering

* chore: add changelog entry

* Disable the `cppcoreguidelines-avoid-const-or-ref-data-members` clang-tidy check

* auto *app

* Selection is a struct, not a class

* Use ChannelView's `signalHolder_` instead of `channelConnections_`

* Remove `applySettings` step, instead just connect & set each setting individually

* rename & constify some context values

* Handle empty "last message color" setting value better (as it was
        originally in this pr before I removed that change :-)

* unrelated mini refactor cleanup

* let painSelection handle size_t instead of int

* Add some more comments to the MessageLayoutContext structs

---------

Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
This commit is contained in:
nerix 2023-07-30 14:52:39 +02:00 committed by GitHub
parent 95aee044e2
commit 71594ad0d8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 312 additions and 131 deletions

View file

@ -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,

View file

@ -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

View file

@ -209,6 +209,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

View file

@ -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 <size_t N>
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)

View file

@ -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,83 +196,76 @@ 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<Qt::BrushStyle>(
getSettings()->lastMessagePattern.getValue()));
QBrush brush(color, ctx.preferences.lastMessagePattern);
painter.fillRect(0, y + this->container_.getHeight() - 1,
ctx.painter.fillRect(0, ctx.y + this->container_.getHeight() - 1,
pixmap->width(), 1, brush);
}
@ -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())
{
backgroundColor = blendColors(backgroundColor,
*ColorProvider::instance().color(
ColorType::ElevatedMessageHighlight));
}
else if (this->message_->flags.has(MessageFlag::FirstMessage) &&
getSettings()->enableFirstMessageHighlight.getValue())
ctx.preferences.enableElevatedMessageHighlight)
{
backgroundColor = blendColors(
backgroundColor,
*ColorProvider::instance().color(ColorType::FirstMessageHighlight));
*ctx.colorProvider.color(ColorType::ElevatedMessageHighlight));
}
else if (this->message_->flags.has(MessageFlag::FirstMessage) &&
ctx.preferences.enableFirstMessageHighlight)
{
backgroundColor = blendColors(
backgroundColor,
*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

View file

@ -18,6 +18,7 @@ using MessagePtr = std::shared_ptr<const Message>;
struct Selection;
struct MessageLayoutContainer;
class MessageLayoutElement;
struct MessagePaintContext;
enum class MessageElementFlag : int64_t;
using MessageElementFlags = FlagsEnum<MessageElementFlag>;
@ -49,9 +50,7 @@ public:
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 @@ public:
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);

View file

@ -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<MessageLayoutElement> &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,11 +857,9 @@ void MessageLayoutContainer::addSelectionText(QString &str, uint32_t from,
element->addCopyTextToString(str, 0, to - index);
break;
}
else
{
element->addCopyTextToString(str);
}
}
index += indexCount;
}

View file

@ -18,6 +18,7 @@ enum class FirstWord { Neutral, RTL, LTR };
using MessageFlags = FlagsEnum<MessageFlag>;
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 {

View file

@ -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<Qt::BrushStyle>(newValue);
},
holder);
}
} // namespace chatterino

View file

@ -0,0 +1,74 @@
#pragma once
#include <QColor>
#include <QPainter>
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

View file

@ -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 <QDebug>
@ -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;

View file

@ -21,6 +21,7 @@ class Image;
using ImagePtr = std::shared_ptr<Image>;
enum class FontStyle : uint8_t;
enum class MessageElementFlag : int64_t;
struct MessageColors;
class MessageLayoutElement : boost::noncopyable
{
@ -44,7 +45,8 @@ public:
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 @@ protected:
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 @@ protected:
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 @@ public:
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 @@ public:
int padding);
protected:
void paint(QPainter &painter) override;
void paint(QPainter &painter, const MessageColors &messageColors) override;
private:
const QColor color_;
@ -147,7 +149,7 @@ protected:
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 @@ protected:
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 @@ public:
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;

View file

@ -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 <functional>
#include <memory>
#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)
{
isLastMessage = this->lastReadMessage_.get() == layout;
ctx.isLastReadMessage = this->lastReadMessage_.get() == layout;
}
else
{
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<QColor>());
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;
}

View file

@ -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 @@ private:
std::unordered_set<std::shared_ptr<MessageLayout>> messagesOnScreen_;
MessageColors messageColors_;
MessagePreferences messagePreferences_;
static constexpr int leftPadding = 8;
static constexpr int scrollbarPadding = 8;