From c6c90d9f50fab3af179be3c4dc9dfb03883ef372 Mon Sep 17 00:00:00 2001 From: fourtf Date: Thu, 2 Feb 2017 22:15:09 +0100 Subject: [PATCH] added another level of unneeded abstraction --- chatterino.pro | 6 +- messages/limitedqueue.h | 13 ++- messages/message.cpp | 186 ---------------------------------- messages/message.h | 34 +------ messages/messageref.cpp | 202 +++++++++++++++++++++++++++++++++++++ messages/messageref.h | 59 +++++++++++ widgets/chatwidget.cpp | 25 +++++ widgets/chatwidget.h | 15 +++ widgets/chatwidgetview.cpp | 26 ++--- widgets/chatwidgetview.h | 1 + 10 files changed, 330 insertions(+), 237 deletions(-) create mode 100644 messages/messageref.cpp create mode 100644 messages/messageref.h diff --git a/chatterino.pro b/chatterino.pro index cea928404..7b582562c 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -53,7 +53,8 @@ SOURCES += main.cpp\ widgets/settingsdialogtab.cpp \ widgets/textinputdialog.cpp \ windows.cpp \ - logging.cpp + logging.cpp \ + messages/messageref.cpp HEADERS += account.h \ asyncexec.h \ @@ -97,7 +98,8 @@ HEADERS += account.h \ settingssnapshot.h \ logging.h \ messages/limitedqueue.h \ - messages/limitedqueuesnapshot.h + messages/limitedqueuesnapshot.h \ + messages/messageref.h PRECOMPILED_HEADER = diff --git a/messages/limitedqueue.h b/messages/limitedqueue.h index b7f764c0a..9e6356ba4 100644 --- a/messages/limitedqueue.h +++ b/messages/limitedqueue.h @@ -24,7 +24,18 @@ public: , limit(limit) , buffer(buffer) { - ; + } + + void + clear() + { + std::lock_guard lock(this->mutex); + + this->vector = new std::vector(this->limit + this->buffer); + this->vectorPtr = std::shared_ptr>(this->vector); + + this->offset = 0; + this->length = 0; } // return true if an item was deleted diff --git a/messages/message.cpp b/messages/message.cpp index 5cb45d109..80700f003 100644 --- a/messages/message.cpp +++ b/messages/message.cpp @@ -14,11 +14,6 @@ #include #include -#define MARGIN_LEFT 8 -#define MARGIN_RIGHT 8 -#define MARGIN_TOP 8 -#define MARGIN_BOTTOM 8 - namespace chatterino { namespace messages { @@ -403,187 +398,6 @@ Message::Message(const IrcPrivateMessage &ircMessage, Channel &channel, // } } -bool -Message::layout(int width, bool enableEmoteMargins) -{ - auto &settings = Settings::getInstance(); - - width = width - (width % 2); - - int mediumTextLineHeight = Fonts::getFontMetrics(Fonts::Medium).height(); - int spaceWidth = 4; - - bool redraw = width != this->currentLayoutWidth || this->relayoutRequested; - - bool recalculateImages = this->emoteGeneration != Emotes::getGeneration(); - bool recalculateText = this->fontGeneration != Fonts::getGeneration(); - - qreal emoteScale = settings.emoteScale.get(); - bool scaleEmotesByLineHeight = settings.scaleEmotesByLineHeight.get(); - - if (recalculateImages || recalculateText) { - this->emoteGeneration = Emotes::getGeneration(); - this->fontGeneration = Fonts::getGeneration(); - - redraw = true; - - for (auto &word : this->words) { - if (word.isImage()) { - if (recalculateImages) { - 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); - } - } - } else { - if (recalculateText) { - QFontMetrics &metrics = word.getFontMetrics(); - word.setSize(metrics.width(word.getText()), - metrics.height()); - } - } - } - } - - if (!redraw) { - return false; - } - - int x = MARGIN_LEFT; - int y = MARGIN_TOP; - - int right = width - MARGIN_RIGHT - MARGIN_LEFT; - - int lineStart = 0; - int lineHeight = 0; - bool first = true; - - this->wordParts.clear(); - - uint32_t flags = Settings::getInstance().getWordTypeMask(); - - for (auto it = this->words.begin(); it != this->words.end(); ++it) { - Word &word = *it; - - if ((word.getType() & flags) == Word::None) { - continue; - } - - int xOffset = 0, yOffset = 0; - - if (enableEmoteMargins) { - if (word.isImage() && word.getImage().getIsHat()) { - xOffset = -word.getWidth() + 2; - } else { - xOffset = word.getXOffset(); - yOffset = word.getYOffset(); - } - } - - // word wrapping - if (word.isText() && word.getWidth() + MARGIN_LEFT > right) { - this->alignWordParts(lineStart, lineHeight); - - y += lineHeight; - - const QString &text = word.getText(); - - int start = 0; - QFontMetrics &metrics = word.getFontMetrics(); - - int width = 0; - - std::vector &charWidths = word.getCharacterWidthCache(); - - if (charWidths.size() == 0) { - for (int i = 0; i < text.length(); i++) { - charWidths.push_back(metrics.charWidth(text, i)); - } - } - - 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, word.getHeight(), - mid, mid)); - - y += metrics.height(); - - start = i - 1; - - width = 0; - } - } - - QString mid(text.mid(start)); - width = metrics.width(mid); - - this->wordParts.push_back(WordPart(word, MARGIN_LEFT, - y - word.getHeight(), width, - word.getHeight(), mid, mid)); - x = width + 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 - this->wordParts.push_back( - WordPart(word, x, y - word.getHeight(), word.getCopyText())); - - x += word.getWidth() + xOffset; - x += spaceWidth; - - lineHeight = std::max(word.getHeight(), lineHeight); - - first = false; - } else { - // doesn't fit in the line - this->alignWordParts(lineStart, lineHeight); - - y += lineHeight; - - this->wordParts.push_back(WordPart( - word, MARGIN_LEFT, y - word.getHeight(), word.getCopyText())); - - lineStart = this->wordParts.size() - 1; - - lineHeight = word.getHeight(); - - x = word.getWidth() + MARGIN_LEFT; - x += spaceWidth; - } - } - - this->alignWordParts(lineStart, lineHeight); - - this->height = y + lineHeight; - - return true; -} - -void -Message::alignWordParts(int lineStart, int lineHeight) -{ - for (size_t i = lineStart; i < this->wordParts.size(); i++) { - WordPart &wordPart2 = this->wordParts.at(i); - - wordPart2.setY(wordPart2.getY() + lineHeight); - } -} - QString Message::matchLink(const QString &string) { diff --git a/messages/message.h b/messages/message.h index 9540523c6..e017c8778 100644 --- a/messages/message.h +++ b/messages/message.h @@ -54,18 +54,12 @@ public: return displayName; } - const std::vector & - getWords() const + std::vector & + getWords() { return words; } - const std::vector & - getWordParts() const - { - return wordParts; - } - bool getDisabled() const { @@ -78,20 +72,6 @@ public: return id; } - int - getHeight() const - { - return height; - } - - bool layout(int width, bool enableEmoteMargins = true); - - void - requestRelayout() - { - relayoutRequested = true; - } - private: static LazyLoadedImage *badgeStaff; static LazyLoadedImage *badgeAdmin; @@ -113,17 +93,7 @@ private: QString displayName = ""; QString id = ""; - int height = 0; - std::vector words; - std::vector wordParts; - - long currentLayoutWidth = -1; - bool relayoutRequested = true; - int fontGeneration = -1; - int emoteGeneration = -1; - - void alignWordParts(int lineStart, int lineHeight); static QString matchLink(const QString &string); diff --git a/messages/messageref.cpp b/messages/messageref.cpp new file mode 100644 index 000000000..cbb42dd5b --- /dev/null +++ b/messages/messageref.cpp @@ -0,0 +1,202 @@ +#include "messageref.h" +#include "emotes.h" +#include "settings.h" + +#define MARGIN_LEFT 8 +#define MARGIN_RIGHT 8 +#define MARGIN_TOP 8 +#define MARGIN_BOTTOM 8 + +namespace chatterino { +namespace messages { + +MessageRef::MessageRef(std::shared_ptr message) + : message(message.get()) + , messagePtr(message) + , wordParts() +{ +} + +bool +MessageRef::layout(int width, bool enableEmoteMargins) +{ + auto &settings = Settings::getInstance(); + + width = width - (width % 2); + + int mediumTextLineHeight = Fonts::getFontMetrics(Fonts::Medium).height(); + int spaceWidth = 4; + + bool redraw = width != this->currentLayoutWidth || this->relayoutRequested; + + bool recalculateImages = this->emoteGeneration != Emotes::getGeneration(); + bool recalculateText = this->fontGeneration != Fonts::getGeneration(); + + qreal emoteScale = settings.emoteScale.get(); + bool scaleEmotesByLineHeight = settings.scaleEmotesByLineHeight.get(); + + if (recalculateImages || recalculateText) { + this->emoteGeneration = Emotes::getGeneration(); + this->fontGeneration = Fonts::getGeneration(); + + redraw = true; + + for (auto &word : this->message->getWords()) { + if (word.isImage()) { + if (recalculateImages) { + 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); + } + } + } else { + if (recalculateText) { + QFontMetrics &metrics = word.getFontMetrics(); + word.setSize(metrics.width(word.getText()), + metrics.height()); + } + } + } + } + + if (!redraw) { + return false; + } + + int x = MARGIN_LEFT; + int y = MARGIN_TOP; + + int right = width - MARGIN_RIGHT - MARGIN_LEFT; + + int lineStart = 0; + int lineHeight = 0; + bool first = true; + + this->wordParts.clear(); + + uint32_t flags = Settings::getInstance().getWordTypeMask(); + + for (auto it = this->message->getWords().begin(); + it != this->message->getWords().end(); ++it) { + Word &word = *it; + + if ((word.getType() & flags) == Word::None) { + continue; + } + + int xOffset = 0, yOffset = 0; + + if (enableEmoteMargins) { + if (word.isImage() && word.getImage().getIsHat()) { + xOffset = -word.getWidth() + 2; + } else { + xOffset = word.getXOffset(); + yOffset = word.getYOffset(); + } + } + + // word wrapping + if (word.isText() && word.getWidth() + MARGIN_LEFT > right) { + this->alignWordParts(lineStart, lineHeight); + + y += lineHeight; + + const QString &text = word.getText(); + + int start = 0; + QFontMetrics &metrics = word.getFontMetrics(); + + int width = 0; + + std::vector &charWidths = word.getCharacterWidthCache(); + + if (charWidths.size() == 0) { + for (int i = 0; i < text.length(); i++) { + charWidths.push_back(metrics.charWidth(text, i)); + } + } + + 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, word.getHeight(), + mid, mid)); + + y += metrics.height(); + + start = i - 1; + + width = 0; + } + } + + QString mid(text.mid(start)); + width = metrics.width(mid); + + this->wordParts.push_back(WordPart(word, MARGIN_LEFT, + y - word.getHeight(), width, + word.getHeight(), mid, mid)); + x = width + 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 + this->wordParts.push_back( + WordPart(word, x, y - word.getHeight(), word.getCopyText())); + + x += word.getWidth() + xOffset; + x += spaceWidth; + + lineHeight = std::max(word.getHeight(), lineHeight); + + first = false; + } else { + // doesn't fit in the line + this->alignWordParts(lineStart, lineHeight); + + y += lineHeight; + + this->wordParts.push_back(WordPart( + word, MARGIN_LEFT, y - word.getHeight(), word.getCopyText())); + + lineStart = this->wordParts.size() - 1; + + lineHeight = word.getHeight(); + + x = word.getWidth() + MARGIN_LEFT; + x += spaceWidth; + } + } + + this->alignWordParts(lineStart, lineHeight); + + this->height = y + lineHeight; + + return true; +} + +void +MessageRef::alignWordParts(int lineStart, int lineHeight) +{ + for (size_t i = lineStart; i < this->wordParts.size(); i++) { + WordPart &wordPart2 = this->wordParts.at(i); + + wordPart2.setY(wordPart2.getY() + lineHeight); + } +} +} +} diff --git a/messages/messageref.h b/messages/messageref.h new file mode 100644 index 000000000..1ed7a0d0c --- /dev/null +++ b/messages/messageref.h @@ -0,0 +1,59 @@ +#ifndef MESSAGEREF_H +#define MESSAGEREF_H + +#include +#include "messages/message.h" + +namespace chatterino { +namespace messages { + +class MessageRef +{ +public: + MessageRef(std::shared_ptr message); + + Message * + getMessage() + { + return this->message; + } + + int + getHeight() const + { + return height; + } + + bool layout(int width, bool enableEmoteMargins = true); + + void + requestRelayout() + { + relayoutRequested = true; + } + + const std::vector & + getWordParts() const + { + return wordParts; + } + +private: + Message *message; + std::shared_ptr messagePtr; + + std::vector wordParts; + + int height = 0; + + int currentLayoutWidth = -1; + bool relayoutRequested = true; + int fontGeneration = -1; + int emoteGeneration = -1; + + void alignWordParts(int lineStart, int lineHeight); +}; +} +} + +#endif // MESSAGEREF_H diff --git a/widgets/chatwidget.cpp b/widgets/chatwidget.cpp index 020a7a867..7a599092d 100644 --- a/widgets/chatwidget.cpp +++ b/widgets/chatwidget.cpp @@ -8,12 +8,14 @@ #include #include #include +#include namespace chatterino { namespace widgets { ChatWidget::ChatWidget(QWidget *parent) : QWidget(parent) + , messages() , channel(Channels::getEmpty()) , channelName(QString()) , vbox(this) @@ -52,12 +54,35 @@ ChatWidget::setChannelName(const QString &name) if (!this->channelName.isEmpty()) { Channels::removeChannel(this->channelName); + + messageAppendedConnection.disconnect(); + messageRemovedConnection.disconnect(); } + messages.clear(); + if (channel.isEmpty()) { this->channel = NULL; + } else { this->channel = Channels::addChannel(channel); + + messageAppendedConnection = + this->channel.get()->messageAppended.connect([this]( + std::shared_ptr &message) { + + std::shared_ptr deleted; + + auto messageRef = new messages::MessageRef(message); + + this->messages.appendItem( + std::shared_ptr(messageRef), deleted); + + }); + + messageRemovedConnection = + this->channel.get()->messageRemovedFromStart.connect( + [this](std::shared_ptr &message) {}); } this->view.layoutMessages(); diff --git a/widgets/chatwidget.h b/widgets/chatwidget.h index a8f456ca2..4f0734b55 100644 --- a/widgets/chatwidget.h +++ b/widgets/chatwidget.h @@ -2,7 +2,10 @@ #define CHATWIDGET_H #include "channel.h" +#include "messages/limitedqueuesnapshot.h" +#include "messages/messageref.h" #include "messages/word.h" +#include "messages/wordpart.h" #include "widgets/chatwidgetheader.h" #include "widgets/chatwidgetinput.h" #include "widgets/chatwidgetview.h" @@ -11,6 +14,7 @@ #include #include #include +#include namespace chatterino { namespace widgets { @@ -45,10 +49,18 @@ public: void showChangeChannelPopup(); + messages::LimitedQueueSnapshot> + getMessagesSnapshot() + { + return messages.getSnapshot(); + } + protected: void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE; private: + messages::LimitedQueue> messages; + std::shared_ptr channel; QString channelName; @@ -58,6 +70,9 @@ private: ChatWidgetView view; ChatWidgetInput input; + boost::signals2::connection messageAppendedConnection; + boost::signals2::connection messageRemovedConnection; + public: void load(const boost::property_tree::ptree &tree); boost::property_tree::ptree save(); diff --git a/widgets/chatwidgetview.cpp b/widgets/chatwidgetview.cpp index 0a462cff2..8a2aa921f 100644 --- a/widgets/chatwidgetview.cpp +++ b/widgets/chatwidgetview.cpp @@ -37,17 +37,9 @@ ChatWidgetView::~ChatWidgetView() bool ChatWidgetView::layoutMessages() { - auto c = this->chatWidget->getChannel(); - - if (c == NULL) { - this->scrollbar.hide(); - - return false; - } - bool showScrollbar = false; - auto messages = c->getMessageSnapshot(); + auto messages = chatWidget->getMessagesSnapshot(); bool redraw = false; @@ -99,7 +91,7 @@ ChatWidgetView::paintEvent(QPaintEvent *) painter.setRenderHint(QPainter::SmoothPixmapTransform); - auto c = this->chatWidget->getChannel(); + // auto c = this->chatWidget->getChannel(); QColor color; @@ -137,10 +129,12 @@ ChatWidgetView::paintEvent(QPaintEvent *) painter.fillRect(QRect(0, 9, 500, 2), QColor(0, 0, 0));*/ - if (c == NULL) - return; + // if (c == NULL) + // return; - auto messages = c->getMessageSnapshot(); + // auto messages = c->getMessageSnapshot(); + + auto messages = chatWidget->getMessagesSnapshot(); int start = this->scrollbar.getCurrentValue(); @@ -152,9 +146,9 @@ ChatWidgetView::paintEvent(QPaintEvent *) (fmod(this->scrollbar.getCurrentValue(), 1))); for (int i = start; i < messages.getLength(); ++i) { - messages::Message *message = messages[i].get(); + messages::MessageRef *messageRef = messages[i].get(); - for (messages::WordPart const &wordPart : message->getWordParts()) { + for (messages::WordPart const &wordPart : messageRef->getWordParts()) { painter.setPen(QColor(255, 0, 0)); painter.drawRect(wordPart.getX(), wordPart.getY() + y, wordPart.getWidth(), wordPart.getHeight()); @@ -188,7 +182,7 @@ ChatWidgetView::paintEvent(QPaintEvent *) } } - y += message->getHeight(); + y += messageRef->getHeight(); if (y > height()) { break; diff --git a/widgets/chatwidgetview.h b/widgets/chatwidgetview.h index f2e57820a..086a12f80 100644 --- a/widgets/chatwidgetview.h +++ b/widgets/chatwidgetview.h @@ -2,6 +2,7 @@ #define CHATVIEW_H #include "channel.h" +#include "messages/messageref.h" #include "messages/word.h" #include "widgets/scrollbar.h"