added another level of unneeded abstraction

This commit is contained in:
fourtf 2017-02-02 22:15:09 +01:00
parent 93660233fd
commit c6c90d9f50
10 changed files with 330 additions and 237 deletions

View file

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

View file

@ -24,7 +24,18 @@ public:
, limit(limit)
, buffer(buffer)
{
;
}
void
clear()
{
std::lock_guard<std::mutex> lock(this->mutex);
this->vector = new std::vector<T>(this->limit + this->buffer);
this->vectorPtr = std::shared_ptr<std::vector<T>>(this->vector);
this->offset = 0;
this->length = 0;
}
// return true if an item was deleted

View file

@ -14,11 +14,6 @@
#include <list>
#include <tuple>
#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<short> &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)
{

View file

@ -54,18 +54,12 @@ public:
return displayName;
}
const std::vector<Word> &
getWords() const
std::vector<Word> &
getWords()
{
return words;
}
const std::vector<WordPart> &
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<Word> words;
std::vector<WordPart> 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);

202
messages/messageref.cpp Normal file
View file

@ -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(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<short> &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);
}
}
}
}

59
messages/messageref.h Normal file
View file

@ -0,0 +1,59 @@
#ifndef MESSAGEREF_H
#define MESSAGEREF_H
#include <memory>
#include "messages/message.h"
namespace chatterino {
namespace messages {
class MessageRef
{
public:
MessageRef(std::shared_ptr<Message> 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<WordPart> &
getWordParts() const
{
return wordParts;
}
private:
Message *message;
std::shared_ptr<Message> messagePtr;
std::vector<messages::WordPart> 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

View file

@ -8,12 +8,14 @@
#include <QFontDatabase>
#include <QPainter>
#include <QVBoxLayout>
#include <boost/signals2.hpp>
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<messages::Message> &message) {
std::shared_ptr<messages::MessageRef> deleted;
auto messageRef = new messages::MessageRef(message);
this->messages.appendItem(
std::shared_ptr<messages::MessageRef>(messageRef), deleted);
});
messageRemovedConnection =
this->channel.get()->messageRemovedFromStart.connect(
[this](std::shared_ptr<messages::Message> &message) {});
}
this->view.layoutMessages();

View file

@ -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 <QVBoxLayout>
#include <QWidget>
#include <boost/property_tree/ptree.hpp>
#include <boost/signals2/connection.hpp>
namespace chatterino {
namespace widgets {
@ -45,10 +49,18 @@ public:
void showChangeChannelPopup();
messages::LimitedQueueSnapshot<std::shared_ptr<messages::MessageRef>>
getMessagesSnapshot()
{
return messages.getSnapshot();
}
protected:
void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE;
private:
messages::LimitedQueue<std::shared_ptr<messages::MessageRef>> messages;
std::shared_ptr<Channel> 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();

View file

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

View file

@ -2,6 +2,7 @@
#define CHATVIEW_H
#include "channel.h"
#include "messages/messageref.h"
#include "messages/word.h"
#include "widgets/scrollbar.h"