mirror-chatterino2/src/messages/MessageElement.cpp

266 lines
8.2 KiB
C++
Raw Normal View History

2018-06-26 14:09:39 +02:00
#include "messages/MessageElement.hpp"
#include "Application.hpp"
2018-06-26 17:20:03 +02:00
#include "common/Emotemap.hpp"
#include "controllers/moderationactions/ModerationActions.hpp"
2018-06-26 17:20:03 +02:00
#include "debug/Benchmark.hpp"
2018-06-26 14:09:39 +02:00
#include "messages/layouts/MessageLayoutContainer.hpp"
#include "messages/layouts/MessageLayoutElement.hpp"
2018-06-28 19:46:45 +02:00
#include "singletons/Settings.hpp"
namespace chatterino {
2018-07-06 19:23:47 +02:00
MessageElement::MessageElement(Flags flags)
: flags_(flags)
{
2018-06-26 17:06:17 +02:00
DebugCount::increase("message elements");
2018-04-06 16:37:30 +02:00
}
MessageElement::~MessageElement()
{
2018-06-26 17:06:17 +02:00
DebugCount::decrease("message elements");
}
2018-07-06 19:23:47 +02:00
MessageElement *MessageElement::setLink(const Link &link)
{
2018-07-06 19:23:47 +02:00
this->link_ = link;
return this;
}
2018-07-06 19:23:47 +02:00
MessageElement *MessageElement::setTooltip(const QString &tooltip)
{
2018-07-06 19:23:47 +02:00
this->tooltip_ = tooltip;
return this;
}
MessageElement *MessageElement::setTrailingSpace(bool value)
{
this->trailingSpace = value;
return this;
}
const QString &MessageElement::getTooltip() const
{
2018-07-06 19:23:47 +02:00
return this->tooltip_;
}
const Link &MessageElement::getLink() const
{
2018-07-06 19:23:47 +02:00
return this->link_;
}
bool MessageElement::hasTrailingSpace() const
{
return this->trailingSpace;
}
MessageElement::Flags MessageElement::getFlags() const
{
2018-07-06 19:23:47 +02:00
return this->flags_;
}
// IMAGE
2018-07-06 19:23:47 +02:00
ImageElement::ImageElement(Image *image, MessageElement::Flags flags)
: MessageElement(flags)
2018-07-06 19:23:47 +02:00
, image_(image)
{
2018-07-06 19:23:47 +02:00
this->setTooltip(image->getTooltip());
}
2018-07-06 19:23:47 +02:00
void ImageElement::addToContainer(MessageLayoutContainer &container, MessageElement::Flags flags)
{
2018-07-06 19:23:47 +02:00
if (flags & this->getFlags()) {
QSize size(this->image_->getScaledWidth() * container.getScale(),
this->image_->getScaledHeight() * container.getScale());
2018-01-22 22:38:44 +01:00
container.addElement(
2018-07-06 19:23:47 +02:00
(new ImageLayoutElement(*this, this->image_, size))->setLink(this->getLink()));
2018-01-22 22:38:44 +01:00
}
}
// EMOTE
2018-07-06 19:23:47 +02:00
EmoteElement::EmoteElement(const EmoteData &data, MessageElement::Flags flags)
: MessageElement(flags)
2018-07-06 19:23:47 +02:00
, data(data)
{
2018-07-06 19:23:47 +02:00
if (data.isValid()) {
this->setTooltip(data.image1x->getTooltip());
2018-07-06 19:23:47 +02:00
this->textElement_.reset(
new TextElement(data.image1x->getCopyString(), MessageElement::Misc));
}
2018-01-22 22:38:44 +01:00
}
2018-07-06 19:23:47 +02:00
void EmoteElement::addToContainer(MessageLayoutContainer &container, MessageElement::Flags flags)
2018-01-22 22:38:44 +01:00
{
2018-07-06 19:23:47 +02:00
if (flags & this->getFlags()) {
if (flags & MessageElement::EmoteImages) {
2018-01-22 22:38:44 +01:00
if (!this->data.isValid()) {
return;
}
2018-07-06 19:23:47 +02:00
Image *image = this->data.getImage(container.getScale());
2018-07-06 19:23:47 +02:00
QSize size(int(container.getScale() * image->getScaledWidth()),
int(container.getScale() * image->getScaledHeight()));
2018-01-22 22:38:44 +01:00
container.addElement(
2018-07-06 19:23:47 +02:00
(new ImageLayoutElement(*this, image, size))->setLink(this->getLink()));
2018-01-22 22:38:44 +01:00
} else {
2018-07-06 19:23:47 +02:00
if (this->textElement_) {
this->textElement_->addToContainer(container, MessageElement::Misc);
2018-01-22 22:38:44 +01:00
}
}
}
}
// TEXT
TextElement::TextElement(const QString &text, MessageElement::Flags flags,
2018-07-06 19:23:47 +02:00
const MessageColor &color, FontStyle style)
: MessageElement(flags)
2018-07-06 19:23:47 +02:00
, color_(color)
, style_(style)
{
for (QString word : text.split(' ')) {
2018-07-06 19:23:47 +02:00
this->words_.push_back({word, -1});
// fourtf: add logic to store multiple spaces after message
}
}
2018-07-06 19:23:47 +02:00
void TextElement::addToContainer(MessageLayoutContainer &container, MessageElement::Flags flags)
{
auto app = getApp();
2018-07-06 19:23:47 +02:00
if (flags & this->getFlags()) {
QFontMetrics metrics = app->fonts->getFontMetrics(this->style_, container.getScale());
2018-01-22 22:38:44 +01:00
2018-07-06 19:23:47 +02:00
for (Word &word : this->words_) {
2018-01-22 22:38:44 +01:00
auto getTextLayoutElement = [&](QString text, int width, bool trailingSpace) {
2018-07-06 19:23:47 +02:00
QColor color = this->color_.getColor(*app->themes);
app->themes->normalizeColor(color);
2018-01-22 22:38:44 +01:00
auto e = (new TextLayoutElement(*this, text, QSize(width, metrics.height()), color,
2018-07-06 19:23:47 +02:00
this->style_, container.getScale()))
2018-01-22 22:38:44 +01:00
->setLink(this->getLink());
e->setTrailingSpace(trailingSpace);
return e;
};
// fourtf: add again
// if (word.width == -1) {
word.width = metrics.width(word.text);
// }
2018-01-22 22:38:44 +01:00
// see if the text fits in the current line
if (container.fitsInLine(word.width)) {
2018-01-16 00:56:17 +01:00
container.addElementNoLineBreak(
getTextLayoutElement(word.text, word.width, this->hasTrailingSpace()));
continue;
}
2018-01-22 22:38:44 +01:00
// see if the text fits in the next line
if (!container.atStartOfLine()) {
container.breakLine();
2018-01-22 22:38:44 +01:00
if (container.fitsInLine(word.width)) {
container.addElementNoLineBreak(
getTextLayoutElement(word.text, word.width, this->hasTrailingSpace()));
continue;
2018-01-16 00:56:17 +01:00
}
}
2018-01-22 22:38:44 +01:00
// we done goofed, we need to wrap the text
QString text = word.text;
int textLength = text.length();
int wordStart = 0;
int width = metrics.width(text[0]);
int lastWidth = 0;
for (int i = 1; i < textLength; i++) {
int charWidth = metrics.width(text[i]);
if (!container.fitsInLine(width + charWidth)) {
2018-04-10 02:42:41 +02:00
container.addElementNoLineBreak(
getTextLayoutElement(text.mid(wordStart, i - wordStart), width, false));
2018-01-22 22:38:44 +01:00
container.breakLine();
wordStart = i;
lastWidth = width;
width = 0;
if (textLength > i + 2) {
width += metrics.width(text[i]);
width += metrics.width(text[i + 1]);
i += 1;
}
continue;
}
width += charWidth;
}
UNUSED(lastWidth); // XXX: What should this be used for (if anything)? KKona
container.addElement(
getTextLayoutElement(text.mid(wordStart), width, this->hasTrailingSpace()));
2018-01-22 22:38:44 +01:00
container.breakLine();
}
}
}
// TIMESTAMP
2018-07-06 19:23:47 +02:00
TimestampElement::TimestampElement(QTime time)
: MessageElement(MessageElement::Timestamp)
2018-07-06 19:23:47 +02:00
, time_(time)
, element_(this->formatTime(time))
{
2018-07-06 19:23:47 +02:00
assert(this->element_ != nullptr);
}
void TimestampElement::addToContainer(MessageLayoutContainer &container,
2018-07-06 19:23:47 +02:00
MessageElement::Flags flags)
{
2018-07-06 19:23:47 +02:00
if (flags & this->getFlags()) {
auto app = getApp();
2018-07-06 19:23:47 +02:00
if (app->settings->timestampFormat != this->format_) {
this->format_ = app->settings->timestampFormat.getValue();
this->element_.reset(this->formatTime(this->time_));
2018-01-22 22:38:44 +01:00
}
2018-01-12 23:09:05 +01:00
2018-07-06 19:23:47 +02:00
this->element_->addToContainer(container, flags);
2018-01-22 22:38:44 +01:00
}
}
TextElement *TimestampElement::formatTime(const QTime &time)
{
2018-01-17 18:36:12 +01:00
static QLocale locale("en_US");
QString format = locale.toString(time, getApp()->settings->timestampFormat);
2018-05-23 04:22:17 +02:00
return new TextElement(format, Flags::Timestamp, MessageColor::System, FontStyle::ChatMedium);
}
// TWITCH MODERATION
TwitchModerationElement::TwitchModerationElement()
: MessageElement(MessageElement::ModeratorTools)
{
}
void TwitchModerationElement::addToContainer(MessageLayoutContainer &container,
2018-07-06 19:23:47 +02:00
MessageElement::Flags flags)
{
2018-07-06 19:23:47 +02:00
if (flags & MessageElement::ModeratorTools) {
QSize size(int(container.getScale() * 16), int(container.getScale() * 16));
2018-01-17 16:52:51 +01:00
for (const ModerationAction &m : getApp()->moderationActions->items.getVector()) {
2018-01-17 16:52:51 +01:00
if (m.isImage()) {
container.addElement((new ImageLayoutElement(*this, m.getImage(), size))
->setLink(Link(Link::UserAction, m.getAction())));
} else {
container.addElement((new TextIconLayoutElement(*this, m.getLine1(), m.getLine2(),
2018-01-28 16:29:47 +01:00
container.getScale(), size))
2018-01-17 16:52:51 +01:00
->setLink(Link(Link::UserAction, m.getAction())));
}
2018-01-17 14:14:31 +01:00
}
}
}
} // namespace chatterino