diff --git a/CHANGELOG.md b/CHANGELOG.md index dca7de28..cd5457a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -132,6 +132,7 @@ - Dev: Fix `NotebookTab` emitting updates for every message. (#5068) - Dev: Added benchmark for parsing and building recent messages. (#5071) - Dev: Boost is depended on as a header-only library when using conan. (#5107) +- Dev: Added signal to invalidate paint buffers of channel views without forcing a relayout. (#5123) ## 2.4.6 diff --git a/src/messages/layouts/MessageLayout.cpp b/src/messages/layouts/MessageLayout.cpp index bc2b4679..bd80a5dc 100644 --- a/src/messages/layouts/MessageLayout.cpp +++ b/src/messages/layouts/MessageLayout.cpp @@ -74,7 +74,8 @@ int MessageLayout::getWidth() const // Layout // return true if redraw is required -bool MessageLayout::layout(int width, float scale, MessageElementFlags flags) +bool MessageLayout::layout(int width, float scale, MessageElementFlags flags, + bool shouldInvalidateBuffer) { // BenchmarkGuard benchmark("MessageLayout::layout()"); @@ -108,6 +109,11 @@ bool MessageLayout::layout(int width, float scale, MessageElementFlags flags) if (!layoutRequired) { + if (shouldInvalidateBuffer) + { + this->invalidateBuffer(); + return true; + } return false; } diff --git a/src/messages/layouts/MessageLayout.hpp b/src/messages/layouts/MessageLayout.hpp index 40275ff2..8a177227 100644 --- a/src/messages/layouts/MessageLayout.hpp +++ b/src/messages/layouts/MessageLayout.hpp @@ -56,7 +56,8 @@ public: MessageLayoutFlags flags; - bool layout(int width, float scale_, MessageElementFlags flags); + bool layout(int width, float scale_, MessageElementFlags flags, + bool shouldInvalidateBuffer); // Painting MessagePaintResult paint(const MessagePaintContext &ctx); diff --git a/src/singletons/WindowManager.cpp b/src/singletons/WindowManager.cpp index 32f7bfa2..bf75f0ed 100644 --- a/src/singletons/WindowManager.cpp +++ b/src/singletons/WindowManager.cpp @@ -211,6 +211,11 @@ void WindowManager::forceLayoutChannelViews() this->layoutChannelViews(nullptr); } +void WindowManager::invalidateChannelViewBuffers(Channel *channel) +{ + this->invalidateBuffersRequested.invoke(channel); +} + void WindowManager::repaintVisibleChatWidgets(Channel *channel) { this->layoutRequested.invoke(channel); @@ -407,10 +412,10 @@ void WindowManager::initialize(Settings &settings, const Paths &paths) this->forceLayoutChannelViews(); }); settings.alternateMessages.connect([this](auto, auto) { - this->forceLayoutChannelViews(); + this->invalidateChannelViewBuffers(); }); settings.separateMessages.connect([this](auto, auto) { - this->forceLayoutChannelViews(); + this->invalidateChannelViewBuffers(); }); settings.collpseMessagesMinLines.connect([this](auto, auto) { this->forceLayoutChannelViews(); diff --git a/src/singletons/WindowManager.hpp b/src/singletons/WindowManager.hpp index 8651fae6..927a5712 100644 --- a/src/singletons/WindowManager.hpp +++ b/src/singletons/WindowManager.hpp @@ -66,6 +66,10 @@ public: // This is called, for example, when the emote scale or timestamp format has // changed void forceLayoutChannelViews(); + + // Tell a channel (or all channels if channel is nullptr) to invalidate all paint buffers + void invalidateChannelViewBuffers(Channel *channel = nullptr); + void repaintVisibleChatWidgets(Channel *channel = nullptr); void repaintGifEmotes(); @@ -124,6 +128,9 @@ public: // This signal fires whenever views rendering a channel, or all views if the // channel is a nullptr, need to redo their layout pajlada::Signals::Signal layoutRequested; + // This signal fires whenever views rendering a channel, or all views if the + // channel is a nullptr, need to invalidate their paint buffers + pajlada::Signals::Signal invalidateBuffersRequested; pajlada::Signals::NoArgSignal wordFlagsChanged; diff --git a/src/widgets/helper/ChannelView.cpp b/src/widgets/helper/ChannelView.cpp index 3505a4a8..fbc28c6c 100644 --- a/src/widgets/helper/ChannelView.cpp +++ b/src/widgets/helper/ChannelView.cpp @@ -425,6 +425,16 @@ void ChannelView::initializeSignals() } }); + this->signalHolder_.managedConnect( + getIApp()->getWindows()->invalidateBuffersRequested, + [this](Channel *channel) { + if (this->isVisible() && + (channel == nullptr || this->channel_.get() == channel)) + { + this->invalidateBuffers(); + } + }); + this->signalHolder_.managedConnect(getIApp()->getFonts()->fontChanged, [this] { this->queueLayout(); @@ -590,6 +600,12 @@ void ChannelView::queueUpdate(const QRect &area) this->update(area); } +void ChannelView::invalidateBuffers() +{ + this->bufferInvalidationQueued_ = true; + this->queueLayout(); +} + void ChannelView::queueLayout() { if (this->isVisible()) @@ -651,12 +667,13 @@ void ChannelView::layoutVisibleMessages( { const auto &message = messages[i]; - redrawRequired |= - message->layout(layoutWidth, this->scale(), flags); + redrawRequired |= message->layout(layoutWidth, this->scale(), flags, + this->bufferInvalidationQueued_); y += message->getHeight(); } } + this->bufferInvalidationQueued_ = false; if (redrawRequired) { @@ -685,7 +702,7 @@ void ChannelView::updateScrollbar( { auto *message = messages[i].get(); - message->layout(layoutWidth, this->scale(), flags); + message->layout(layoutWidth, this->scale(), flags, false); h -= message->getHeight(); @@ -1656,7 +1673,8 @@ void ChannelView::wheelEvent(QWheelEvent *event) else { snapshot[i - 1]->layout(this->getLayoutWidth(), - this->scale(), this->getFlags()); + this->scale(), this->getFlags(), + false); scrollFactor = 1; currentScrollLeft = snapshot[i - 1]->getHeight(); } @@ -1690,7 +1708,8 @@ void ChannelView::wheelEvent(QWheelEvent *event) else { snapshot[i + 1]->layout(this->getLayoutWidth(), - this->scale(), this->getFlags()); + this->scale(), this->getFlags(), + false); scrollFactor = 1; currentScrollLeft = snapshot[i + 1]->getHeight(); diff --git a/src/widgets/helper/ChannelView.hpp b/src/widgets/helper/ChannelView.hpp index f1956cf9..e55e2cfe 100644 --- a/src/widgets/helper/ChannelView.hpp +++ b/src/widgets/helper/ChannelView.hpp @@ -148,7 +148,9 @@ public: bool hasSourceChannel() const; LimitedQueueSnapshot &getMessagesSnapshot(); + void queueLayout(); + void invalidateBuffers(); void clearMessages(); @@ -270,6 +272,7 @@ private: bool canReplyToMessages() const; bool layoutQueued_ = false; + bool bufferInvalidationQueued_ = false; bool lastMessageHasAlternateBackground_ = false; bool lastMessageHasAlternateBackgroundReverse_ = true;