diff --git a/chatterino.pro b/chatterino.pro index a4cf99f03..5aff7da16 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -164,7 +164,8 @@ HEADERS += \ src/messages/messagecolor.hpp \ src/util/nativeeventhelper.hpp \ src/debug/log.hpp \ - src/messages/imageloadermanager.hpp + src/messages/imageloadermanager.hpp \ + src/util/benchmark.hpp PRECOMPILED_HEADER = diff --git a/src/emotemanager.cpp b/src/emotemanager.cpp index 8e6db3511..5f4182107 100644 --- a/src/emotemanager.cpp +++ b/src/emotemanager.cpp @@ -20,10 +20,14 @@ using namespace chatterino::messages; namespace chatterino { +EmoteManager *EmoteManager::instance = nullptr; + EmoteManager::EmoteManager(WindowManager &_windowManager) : windowManager(_windowManager) , findShortCodesRegex(":([-+\\w]+):") { + this->instance = this; + pajlada::Settings::Setting roomID( "/accounts/current/roomID", "", pajlada::Settings::SettingOption::DoNotWriteToJSON); diff --git a/src/emotemanager.hpp b/src/emotemanager.hpp index 16469430d..b64cbd85d 100644 --- a/src/emotemanager.hpp +++ b/src/emotemanager.hpp @@ -39,6 +39,8 @@ class EmoteManager public: explicit EmoteManager(WindowManager &_windowManager); + static EmoteManager *instance; + void loadGlobalEmotes(); void reloadBTTVChannelEmotes(const QString &channelName, diff --git a/src/messages/imageloadermanager.cpp b/src/messages/imageloadermanager.cpp index edfc2f125..735232297 100644 --- a/src/messages/imageloadermanager.cpp +++ b/src/messages/imageloadermanager.cpp @@ -3,6 +3,7 @@ #include "messages/lazyloadedimage.hpp" #include "windowmanager.hpp" +#include #include #include #include @@ -81,7 +82,7 @@ void ImageLoaderWorker::handleLoad(chatterino::messages::LazyLoadedImage *lli, Q lli->emoteManager.incGeneration(); lli->windowManager.layoutVisibleChatWidgets(); - delete reply; + reply->deleteLater(); delete this; } diff --git a/src/messages/limitedqueue.hpp.Tw3100 b/src/messages/limitedqueue.hpp.Tw3100 deleted file mode 100644 index 4f3b612ba..000000000 --- a/src/messages/limitedqueue.hpp.Tw3100 +++ /dev/null @@ -1,97 +0,0 @@ -#pragma once - -#include "messages/limitedqueuesnapshot.hpp" - -#include -#include -#include - -namespace chatterino { -namespace messages { - -template -class LimitedQueue -{ -public: - LimitedQueue(int _limit = 1000, int _buffer = 250) - : offset(0) - , limit(_limit) - , buffer(_buffer) - { - this->vector = std::make_shared>(); - this->vector->reserve(this->limit + this->buffer); - } - - void clear() - { - std::lockthis->guard lock(this->mutex); - - this->vector = std::make_shared>(); - this->vector->reserve(this->limit + this->buffer); - - this->offset = 0; - } - - // return true if an item was deleted - // deleted will be set if the item was deleted - bool appendItem(const T &item, T &deleted) - { - std::lock_guard lock(this->mutex); - - if (this->vector->size() >= this->limit) { - // vector is full - if (this->offset == this->buffer) { - deleted = this->vector->at(this->offset); - - // create new vector - auto newVector = std::make_shared>(); - newVector->reserve(this->limit + this->buffer); - - for (unsigned int i = 0; i < this->limit; ++i) { - newVector->pushthis->back(this->vector->at(i + this->offset)); - } - newVector->push_back(item); - - this->offset = 0; - this->vector = newVector; - - return true; - } else { - deleted = this->vector->at(this->offset); - - // append item and increment offset("deleting" first element) - this->vector->push_back(item); - this->offset++; - - return true; - } - } else { - // append item - this->vector->pushthis->back(item); - - return false; - } - } - - messages::LimitedQueueSnapshot getSnapshot() - { - std::lockthis->guard lock(this->mutex); - - if (this->vector->size() < this->limit) { - return LimitedQueueSnapshot(this->vector, this->offset, this->vector->size()); - } else { - return LimitedQueueSnapshot(this->vector, this->offset, this->limit); - } - } - -private: - std::shared_ptr> vector; - std::mutex mutex; - - unsigned int offset; - unsigned int limit; - unsigned int buffer; -}; - -} // namespace messages -} // namespace chatterino diff --git a/src/messages/messageref.cpp b/src/messages/messageref.cpp index ce55fb058..1b54d8754 100644 --- a/src/messages/messageref.cpp +++ b/src/messages/messageref.cpp @@ -30,84 +30,72 @@ int MessageRef::getHeight() const return this->height; } -bool MessageRef::layout(int width, bool enableEmoteMargins) +// return true if redraw is required +bool MessageRef::layout(int width) { - auto &settings = SettingsManager::getInstance(); + bool layoutRequired = false; - bool sizeChanged = width != this->currentLayoutWidth; - bool redraw = width != this->currentLayoutWidth; - int spaceWidth = 4; + // check if width changed + const bool widthChanged = width != this->currentLayoutWidth; + layoutRequired |= widthChanged; + this->currentLayoutWidth = width; + // check if emotes changed + const bool imagesChanged = this->emoteGeneration != EmoteManager::instance->getGeneration(); + layoutRequired |= imagesChanged; + this->emoteGeneration = EmoteManager::instance->getGeneration(); + // check if text changed + const bool textChanged = this->fontGeneration != FontManager::getInstance().getGeneration(); + layoutRequired |= textChanged; + this->fontGeneration = FontManager::getInstance().getGeneration(); + // check if work mask changed + const bool wordMaskChanged = + this->currentWordTypes != SettingsManager::getInstance().getWordTypeMask(); + layoutRequired |= wordMaskChanged; + this->currentWordTypes = SettingsManager::getInstance().getWordTypeMask(); - int mediumTextLineHeight = - FontManager::getInstance().getFontMetrics(FontManager::Medium).height(); + // update word sizes if needed + if (imagesChanged) { + this->updateImageSizes(); + } + if (textChanged) { + this->updateTextSizes(); + } + if (widthChanged) { + this->buffer = nullptr; + } - /* TODO(pajlada): Re-implement - bool recalculateImages = this->emoteGeneration != EmoteManager::getInstance().getGeneration(); - */ - bool recalculateImages = true; - - bool recalculateText = this->fontGeneration != FontManager::getInstance().getGeneration(); - bool newWordTypes = this->currentWordTypes != SettingsManager::getInstance().getWordTypeMask(); - - qreal emoteScale = settings.emoteScale.get(); - bool scaleEmotesByLineHeight = settings.scaleEmotesByLineHeight.get(); - - // calculate word sizes - if (!redraw && !recalculateImages && !recalculateText && !newWordTypes) { + // return if no layout is required + if (!layoutRequired) { return false; } - // this->emoteGeneration = EmoteManager::getInstance().getGeneration(); - this->fontGeneration = FontManager::getInstance().getGeneration(); + this->actuallyLayout(width); - for (auto &word : this->message->getWords()) { - if (word.isImage()) { - if (!recalculateImages) { - continue; - } + return true; +} - auto &image = word.getImage(); +void MessageRef::actuallyLayout(int width) +{ + auto &settings = SettingsManager::getInstance(); - qreal w = image.getWidth(); - qreal h = image.getHeight(); + const int spaceWidth = 4; + const int right = width - MARGIN_RIGHT; - if (scaleEmotesByLineHeight) { - word.setSize(w * mediumTextLineHeight / h * emoteScale, - mediumTextLineHeight * emoteScale); - } else { - word.setSize(w * image.getScale() * emoteScale, h * image.getScale() * emoteScale); - } - } else { - if (!recalculateText) { - continue; - } - - QFontMetrics &metrics = word.getFontMetrics(); - word.setSize(metrics.width(word.getText()), metrics.height()); - } - } - - if (newWordTypes) { - this->currentWordTypes = settings.getWordTypeMask(); - } + // clear word parts + this->wordParts.clear(); // layout - this->currentLayoutWidth = width; - int x = MARGIN_LEFT; int y = MARGIN_TOP; - int right = width - MARGIN_RIGHT; - int lineNumber = 0; int lineStart = 0; int lineHeight = 0; bool first = true; - this->wordParts.clear(); - uint32_t flags = settings.getWordTypeMask(); + // loop throught all the words and add them when a line is full for (auto it = this->message->getWords().begin(); it != this->message->getWords().end(); ++it) { Word &word = *it; @@ -118,64 +106,60 @@ bool MessageRef::layout(int width, bool enableEmoteMargins) int xOffset = 0, yOffset = 0; - if (enableEmoteMargins) { - if (word.isImage() && word.getImage().isHat()) { - xOffset = -word.getWidth() + 2; - } else { - xOffset = word.getXOffset(); - yOffset = word.getYOffset(); - } - } + /// if (enableEmoteMargins) { + /// if (word.isImage() && word.getImage().isHat()) { + /// xOffset = -word.getWidth() + 2; + /// } else { + xOffset = word.getXOffset(); + yOffset = word.getYOffset(); + /// } + /// } // word wrapping if (word.isText() && word.getWidth() + MARGIN_LEFT > right) { + // align and end the current line alignWordParts(lineStart, lineHeight, width); - y += lineHeight; - const QString &text = word.getText(); + int currentPartStart = 0; + int currentLineWidth = 0; - int start = 0; - QFontMetrics &metrics = word.getFontMetrics(); + // go through the text, break text when it doesn't fit in the line anymore + for (int i = 1; i <= word.getText().length(); i++) { + currentLineWidth += word.getCharWidth(i - 1); - int width = 0; + if (currentLineWidth + MARGIN_LEFT > right) { + // add the current line + QString mid = word.getText().mid(currentPartStart, i - currentPartStart - 1); - std::vector &charWidths = word.getCharacterWidthCache(); - int charOffset = 0; - - for (int i = 2; i <= text.length(); i++) { - if ((width = width + charWidths[i - 1]) + MARGIN_LEFT > right) { - QString mid = text.mid(start, i - start - 1); - - this->wordParts.push_back(WordPart(word, MARGIN_LEFT, y, width, + this->wordParts.push_back(WordPart(word, MARGIN_LEFT, y, currentLineWidth, word.getHeight(), lineNumber, mid, mid, - false, charOffset)); + false, currentPartStart)); - charOffset = i; + y += word.getFontMetrics().height(); - y += metrics.height(); + currentPartStart = i - 1; - start = i - 1; - - width = 0; + currentLineWidth = 0; lineNumber++; } } - QString mid(text.mid(start)); - width = metrics.width(mid); + QString mid(word.getText().mid(currentPartStart)); + currentLineWidth = word.getFontMetrics().width(mid); - this->wordParts.push_back(WordPart(word, MARGIN_LEFT, y - word.getHeight(), width, - word.getHeight(), lineNumber, mid, mid, charOffset)); - x = width + MARGIN_LEFT + spaceWidth; + this->wordParts.push_back(WordPart(word, MARGIN_LEFT, y - word.getHeight(), + currentLineWidth, word.getHeight(), lineNumber, mid, + mid, true, currentPartStart)); + x = currentLineWidth + MARGIN_LEFT + spaceWidth; lineHeight = word.getHeight(); - lineStart = this->wordParts.size() - 1; first = false; - } else if (first || x + word.getWidth() + xOffset <= right) { - // fits in the line + } + // fits in the current line + else if (first || x + word.getWidth() + xOffset <= right) { this->wordParts.push_back( WordPart(word, x, y - word.getHeight(), lineNumber, word.getCopyText())); @@ -185,8 +169,10 @@ bool MessageRef::layout(int width, bool enableEmoteMargins) lineHeight = std::max(word.getHeight(), lineHeight); first = false; - } else { - // doesn't fit in the line + } + // doesn't fit in the line + else { + // align and end the current line alignWordParts(lineStart, lineHeight, width); y += lineHeight; @@ -205,22 +191,56 @@ bool MessageRef::layout(int width, bool enableEmoteMargins) } } + // align and end the current line alignWordParts(lineStart, lineHeight, width); - if (this->height != y + lineHeight) { - sizeChanged = true; - this->height = y + lineHeight; - } + // update height + int oldHeight = this->height; + this->height = y + lineHeight + MARGIN_BOTTOM; - this->height += MARGIN_BOTTOM; - - if (sizeChanged) { - buffer = nullptr; + // invalidate buffer if height changed + if (oldHeight != this->height) { + this->buffer = nullptr; } updateBuffer = true; +} - return true; +void MessageRef::updateTextSizes() +{ + for (auto &word : this->message->getWords()) { + if (!word.isText()) + continue; + + QFontMetrics &metrics = word.getFontMetrics(); + word.setSize(metrics.width(word.getText()), metrics.height()); + } +} + +void MessageRef::updateImageSizes() +{ + const int mediumTextLineHeight = + FontManager::getInstance().getFontMetrics(FontManager::Medium).height(); + const qreal emoteScale = SettingsManager::getInstance().emoteScale.get(); + const bool scaleEmotesByLineHeight = + SettingsManager::getInstance().scaleEmotesByLineHeight.get(); + + for (auto &word : this->message->getWords()) { + if (!word.isImage()) + continue; + + auto &image = word.getImage(); + + qreal w = image.getWidth(); + qreal h = image.getHeight(); + + if (scaleEmotesByLineHeight) { + word.setSize(w * mediumTextLineHeight / h * emoteScale, + mediumTextLineHeight * emoteScale); + } else { + word.setSize(w * image.getScale() * emoteScale, h * image.getScale() * emoteScale); + } + } } const std::vector &MessageRef::getWordParts() const diff --git a/src/messages/messageref.hpp b/src/messages/messageref.hpp index 745c83b2f..673ed00bf 100644 --- a/src/messages/messageref.hpp +++ b/src/messages/messageref.hpp @@ -22,7 +22,7 @@ public: Message *getMessage(); int getHeight() const; - bool layout(int width, bool enableEmoteMargins = true); + bool layout(int width); const std::vector &getWordParts() const; @@ -30,7 +30,6 @@ public: bool updateBuffer = false; const Word *tryGetWordPart(QPoint point); - int getSelectionIndex(QPoint position); private: @@ -42,13 +41,15 @@ private: int currentLayoutWidth = -1; int fontGeneration = -1; - /* TODO(pajlada): Re-implement int emoteGeneration = -1; - */ + Word::Type currentWordTypes = Word::None; // methods + void actuallyLayout(int width); void alignWordParts(int lineStart, int lineHeight, int width); + void updateTextSizes(); + void updateImageSizes(); }; } // namespace messages diff --git a/src/messages/word.cpp b/src/messages/word.cpp index fc81a76f1..398b9b3f0 100644 --- a/src/messages/word.cpp +++ b/src/messages/word.cpp @@ -1,4 +1,5 @@ #include "messages/word.hpp" +#include "util/benchmark.hpp" namespace chatterino { namespace messages { @@ -127,6 +128,11 @@ int Word::getCharacterLength() const return this->isImage() ? 2 : this->getText().length() + 1; } +short Word::getCharWidth(int index) const +{ + return this->getCharacterWidthCache().at(index); +} + std::vector &Word::getCharacterWidthCache() const { // lock not required because there is only one gui thread diff --git a/src/messages/word.hpp b/src/messages/word.hpp index 0c0142d9f..9c8075d0d 100644 --- a/src/messages/word.hpp +++ b/src/messages/word.hpp @@ -115,7 +115,7 @@ public: void setOffset(int _xOffset, int _yOffset); int getCharacterLength() const; - std::vector &getCharacterWidthCache() const; + short getCharWidth(int index) const; private: LazyLoadedImage *image; @@ -136,6 +136,7 @@ private: FontManager::Type font = FontManager::Medium; Link link; + std::vector &getCharacterWidthCache() const; mutable std::vector charWidthCache; }; diff --git a/src/messages/wordpart.cpp b/src/messages/wordpart.cpp index dd6d6413e..e4182ea05 100644 --- a/src/messages/wordpart.cpp +++ b/src/messages/wordpart.cpp @@ -115,9 +115,9 @@ int WordPart::getCharacterLength() const return this->getWord().isImage() ? 2 : this->getText().length() + 1; } -short WordPart::getCharacterWidth(int index) const +short WordPart::getCharWidth(int index) const { - return this->getWord().getCharacterWidthCache().at(index + this->wordCharOffset); + return this->getWord().getCharWidth(index + this->wordCharOffset); } } // namespace messages } // namespace chatterino diff --git a/src/messages/wordpart.hpp b/src/messages/wordpart.hpp index f7b64cecd..110eb623e 100644 --- a/src/messages/wordpart.hpp +++ b/src/messages/wordpart.hpp @@ -33,7 +33,7 @@ public: const QString &getText() const; int getLineNumber() const; int getCharacterLength() const; - short getCharacterWidth(int index) const; + short getCharWidth(int index) const; private: Word &word; diff --git a/src/util/benchmark.hpp b/src/util/benchmark.hpp index 469c6362b..828f6d738 100644 --- a/src/util/benchmark.hpp +++ b/src/util/benchmark.hpp @@ -2,10 +2,12 @@ #include #include +#include #define BENCH(x) \ QElapsedTimer x; \ x.start(); -#define MARK(x) \ - qDebug() << __FILE__ << __LINE__ << static_cast(x.nsecsElapsed()) / 100000.0 << "ms"; +#define MARK(x) \ + qDebug() << BOOST_CURRENT_FUNCTION << __LINE__ \ + << static_cast(x.nsecsElapsed()) / 100000.0 << "ms"; diff --git a/src/widgets/channelview.cpp b/src/widgets/channelview.cpp index c1bb189bb..663429815 100644 --- a/src/widgets/channelview.cpp +++ b/src/widgets/channelview.cpp @@ -6,6 +6,7 @@ #include "messages/messageref.hpp" #include "settingsmanager.hpp" #include "ui_accountpopupform.h" +#include "util/benchmark.hpp" #include "util/distancebetweenpoints.hpp" #include "widgets/chatwidget.hpp" #include "windowmanager.hpp" @@ -46,12 +47,12 @@ ChannelView::ChannelView(WindowManager &windowManager, BaseWidget *parent) this->goToBottom->setVisible(this->scrollBar.isVisible() && !this->scrollBar.isAtBottom()); - this->update(); + this->queueUpdate(); }); this->repaintGifsConnection = windowManager.repaintGifs.connect([&] { this->updateGifEmotes(); }); - this->layoutConnection = windowManager.repaintGifs.connect([&] { this->layout(); }); + this->layoutConnection = windowManager.layout.connect([&] { this->layoutMessages(); }); this->goToBottom = new RippleEffectLabel(this, 0); this->goToBottom->setStyleSheet("background-color: rgba(0,0,0,0.5); color: #FFF;"); @@ -60,6 +61,16 @@ ChannelView::ChannelView(WindowManager &windowManager, BaseWidget *parent) connect(goToBottom, &RippleEffectLabel::clicked, this, [this] { QTimer::singleShot(180, [this] { this->scrollBar.scrollToBottom(); }); }); + + this->updateTimer.setInterval(1000 / 60); + this->updateTimer.setSingleShot(true); + connect(&this->updateTimer, &QTimer::timeout, this, [this] { + if (this->updateQueued) { + this->update(); + } + + this->updateTimer.start(); + }); } ChannelView::~ChannelView() @@ -68,17 +79,35 @@ ChannelView::~ChannelView() this, &ChannelView::wordTypeMaskChanged); } -bool ChannelView::layoutMessages() +void ChannelView::queueUpdate() { + if (this->updateTimer.isActive()) { + this->updateQueued = true; + } + + update(); + + this->updateTimer.start(); +} + +void ChannelView::layoutMessages() +{ + this->actuallyLayoutMessages(); +} + +void ChannelView::actuallyLayoutMessages() +{ + BENCH(timer) auto messages = this->getMessagesSnapshot(); if (messages.getLength() == 0) { this->scrollBar.setVisible(false); - return false; + + return; } + bool redrawRequired = false; bool showScrollbar = false; - bool redraw = false; // Bool indicating whether or not we were showing all messages // True if one of the following statements are true: @@ -97,7 +126,7 @@ bool ChannelView::layoutMessages() for (size_t i = start; i < messages.getLength(); ++i) { auto message = messages[i]; - redraw |= message->layout(layoutWidth, true); + redrawRequired |= message->layout(layoutWidth); y += message->getHeight(); @@ -113,7 +142,7 @@ bool ChannelView::layoutMessages() for (std::size_t i = messages.getLength() - 1; i > 0; i--) { auto *message = messages[i].get(); - message->layout(layoutWidth, true); + message->layout(layoutWidth); h -= message->getHeight(); @@ -144,7 +173,11 @@ bool ChannelView::layoutMessages() this->scrollBar.scrollToBottom(); } - return redraw; + MARK(timer); + + if (redrawRequired) { + this->queueUpdate(); + } } void ChannelView::clearMessages() @@ -154,13 +187,15 @@ void ChannelView::clearMessages() // Layout chat widget messages, and force an update regardless if there are no messages this->layoutMessages(); - this->update(); + this->queueUpdate(); } void ChannelView::updateGifEmotes() { - this->onlyUpdateEmotes = true; - this->update(); + if (!this->gifEmotes.empty()) { + this->onlyUpdateEmotes = true; + this->queueUpdate(); + } } ScrollBar &ChannelView::getScrollBar() @@ -278,7 +313,6 @@ void ChannelView::clearSelection() { this->selection = Selection(); layoutMessages(); - update(); } messages::LimitedQueueSnapshot ChannelView::getMessagesSnapshot() @@ -318,8 +352,7 @@ void ChannelView::setChannel(std::shared_ptr channel) this->selection.start.messageIndex--; this->selection.end.messageIndex--; - layoutMessages(); - update(); + this->layoutMessages(); }); auto snapshot = channel->getMessageSnapshot(); @@ -373,9 +406,10 @@ void ChannelView::setSelection(const SelectionItem &start, const SelectionItem & void ChannelView::paintEvent(QPaintEvent * /*event*/) { + // BENCH(timer); QPainter painter(this); - painter.setRenderHint(QPainter::SmoothPixmapTransform); +// painter.setRenderHint(QPainter::SmoothPixmapTransform); // only update gif emotes #ifndef Q_OS_MAC @@ -402,10 +436,11 @@ void ChannelView::paintEvent(QPaintEvent * /*event*/) // draw gif emotes for (GifEmoteData &item : this->gifEmotes) { - painter.fillRect(item.rect, this->colorScheme.ChatBackground); + // painter.fillRect(item.rect, this->colorScheme.ChatBackground); painter.drawPixmap(item.rect, *item.image->getPixmap()); } + // MARK(timer); } void ChannelView::drawMessages(QPainter &painter) @@ -423,14 +458,13 @@ void ChannelView::drawMessages(QPainter &painter) for (size_t i = start; i < messages.getLength(); ++i) { messages::MessageRef *messageRef = messages[i].get(); - std::shared_ptr bufferPtr = messageRef->buffer; - QPixmap *buffer = bufferPtr.get(); + std::shared_ptr buffer = messageRef->buffer; - bool updateBuffer = messageRef->updateBuffer; + // bool updateBuffer = messageRef->updateBuffer; + bool updateBuffer = false; - if (buffer == nullptr) { - buffer = new QPixmap(width(), messageRef->getHeight()); - bufferPtr = std::shared_ptr(buffer); + if (!buffer) { + buffer = std::shared_ptr(new QPixmap(width(), messageRef->getHeight())); updateBuffer = true; } @@ -438,7 +472,8 @@ void ChannelView::drawMessages(QPainter &painter) // update messages that have been changed if (updateBuffer) { - this->updateMessageBuffer(messageRef, buffer, i); + this->updateMessageBuffer(messageRef, buffer.get(), i); + qDebug() << "updating buffer xD"; } // get gif emotes @@ -459,11 +494,11 @@ void ChannelView::drawMessages(QPainter &painter) } } - messageRef->buffer = bufferPtr; + messageRef->buffer = buffer; - // if (buffer != nullptr) { - painter.drawPixmap(0, y, *buffer); - // } + if (buffer) { + painter.drawPixmap(0, y, *buffer.get()); + } y += messageRef->getHeight(); @@ -502,7 +537,7 @@ void ChannelView::updateMessageBuffer(messages::MessageRef *messageRef, QPixmap const QPixmap *image = lli.getPixmap(); - if (image != nullptr) { + if (image != nullptr && !lli.getAnimated()) { painter.drawPixmap(QRect(wordPart.getX(), wordPart.getY(), wordPart.getWidth(), wordPart.getHeight()), *image); @@ -582,7 +617,7 @@ void ChannelView::drawMessageSelection(QPainter &painter, messages::MessageRef * int offset = this->selection.min.charIndex - charIndex; for (int j = 0; j < offset; j++) { - rect.setLeft(rect.left() + part.getCharacterWidth(j)); + rect.setLeft(rect.left() + part.getCharWidth(j)); } if (isSingleWord) { @@ -591,7 +626,7 @@ void ChannelView::drawMessageSelection(QPainter &painter, messages::MessageRef * rect.setRight(part.getX()); for (int j = 0; j < offset + length; j++) { - rect.setRight(rect.right() + part.getCharacterWidth(j)); + rect.setRight(rect.right() + part.getCharWidth(j)); } painter.fillRect(rect, selectionColor); @@ -648,7 +683,7 @@ void ChannelView::drawMessageSelection(QPainter &painter, messages::MessageRef * rect.setRight(part.getX()); for (int j = 0; j < offset + length; j++) { - rect.setRight(rect.right() + part.getCharacterWidth(j)); + rect.setRight(rect.right() + part.getCharWidth(j)); } } else { if (this->selection.max.charIndex == charIndex) { diff --git a/src/widgets/channelview.hpp b/src/widgets/channelview.hpp index d232b5813..8353424e8 100644 --- a/src/widgets/channelview.hpp +++ b/src/widgets/channelview.hpp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -88,6 +89,7 @@ public: ~ChannelView(); void updateGifEmotes(); + void queueUpdate(); ScrollBar &getScrollBar(); QString getSelectedText(); bool hasSelection(); @@ -95,7 +97,7 @@ public: void setChannel(std::shared_ptr channel); messages::LimitedQueueSnapshot getMessagesSnapshot(); - bool layoutMessages(); + void layoutMessages(); void clearMessages(); @@ -122,8 +124,11 @@ private: }; WindowManager &windowManager; + QTimer updateTimer; + bool updateQueued = false; void detachChannel(); + void actuallyLayoutMessages(); void drawMessages(QPainter &painter); void updateMessageBuffer(messages::MessageRef *messageRef, QPixmap *buffer, int messageIndex); diff --git a/src/widgets/chatwidget.cpp b/src/widgets/chatwidget.cpp index 1b47a839e..778f03726 100644 --- a/src/widgets/chatwidget.cpp +++ b/src/widgets/chatwidget.cpp @@ -167,14 +167,9 @@ bool ChatWidget::showChangeChannelPopup(const char *dialogTitle, bool empty) return false; } -void ChatWidget::layoutMessages(bool forceUpdate) +void ChatWidget::layoutMessages() { this->view.layoutMessages(); - this->view.update(); - - // if (this->view.layoutMessages() || forceUpdate) { - // this->view.update(); - // } } void ChatWidget::updateGifEmotes() diff --git a/src/widgets/chatwidget.hpp b/src/widgets/chatwidget.hpp index 674478b6f..a355d4c9a 100644 --- a/src/widgets/chatwidget.hpp +++ b/src/widgets/chatwidget.hpp @@ -56,7 +56,7 @@ public: void giveFocus(Qt::FocusReason reason); bool hasFocus() const; - void layoutMessages(bool forceUpdate = false); + void layoutMessages(); void updateGifEmotes(); protected: