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"
|
2018-06-28 19:38:57 +02:00
|
|
|
#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"
|
2018-01-11 20:16:25 +01:00
|
|
|
|
|
|
|
namespace chatterino {
|
|
|
|
|
2018-07-06 19:23:47 +02:00
|
|
|
MessageElement::MessageElement(Flags flags)
|
|
|
|
: flags_(flags)
|
2018-01-11 20:16:25 +01:00
|
|
|
{
|
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-01-11 20:16:25 +01:00
|
|
|
}
|
|
|
|
|
2018-07-06 19:23:47 +02:00
|
|
|
MessageElement *MessageElement::setLink(const Link &link)
|
2018-01-11 20:16:25 +01:00
|
|
|
{
|
2018-07-06 19:23:47 +02:00
|
|
|
this->link_ = link;
|
2018-01-11 20:16:25 +01:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2018-07-06 19:23:47 +02:00
|
|
|
MessageElement *MessageElement::setTooltip(const QString &tooltip)
|
2018-01-11 20:16:25 +01:00
|
|
|
{
|
2018-07-06 19:23:47 +02:00
|
|
|
this->tooltip_ = tooltip;
|
2018-01-11 20:16:25 +01:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
MessageElement *MessageElement::setTrailingSpace(bool value)
|
|
|
|
{
|
|
|
|
this->trailingSpace = value;
|
2018-01-12 18:42:13 +01:00
|
|
|
return this;
|
2018-01-11 20:16:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const QString &MessageElement::getTooltip() const
|
|
|
|
{
|
2018-07-06 19:23:47 +02:00
|
|
|
return this->tooltip_;
|
2018-01-11 20:16:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const Link &MessageElement::getLink() const
|
|
|
|
{
|
2018-07-06 19:23:47 +02:00
|
|
|
return this->link_;
|
2018-01-11 20:16:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool MessageElement::hasTrailingSpace() const
|
|
|
|
{
|
|
|
|
return this->trailingSpace;
|
|
|
|
}
|
|
|
|
|
|
|
|
MessageElement::Flags MessageElement::getFlags() const
|
|
|
|
{
|
2018-07-06 19:23:47 +02:00
|
|
|
return this->flags_;
|
2018-01-11 20:16:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// IMAGE
|
2018-08-02 14:23:27 +02:00
|
|
|
ImageElement::ImageElement(ImagePtr image, MessageElement::Flags flags)
|
2018-01-11 20:16:25 +01:00
|
|
|
: MessageElement(flags)
|
2018-07-06 19:23:47 +02:00
|
|
|
, image_(image)
|
2018-01-11 20:16:25 +01:00
|
|
|
{
|
2018-08-02 14:23:27 +02:00
|
|
|
// this->setTooltip(image->getTooltip());
|
2018-01-11 20:16:25 +01:00
|
|
|
}
|
|
|
|
|
2018-08-06 21:17:03 +02:00
|
|
|
void ImageElement::addToContainer(MessageLayoutContainer &container,
|
|
|
|
MessageElement::Flags flags)
|
2018-01-11 20:16:25 +01:00
|
|
|
{
|
2018-07-06 19:23:47 +02:00
|
|
|
if (flags & this->getFlags()) {
|
2018-08-06 18:25:47 +02:00
|
|
|
auto size = QSize(this->image_->width() * container.getScale(),
|
|
|
|
this->image_->height() * container.getScale());
|
2018-01-11 20:16:25 +01:00
|
|
|
|
2018-08-06 21:17:03 +02:00
|
|
|
container.addElement((new ImageLayoutElement(*this, this->image_, size))
|
|
|
|
->setLink(this->getLink()));
|
2018-01-22 22:38:44 +01:00
|
|
|
}
|
2018-01-11 20:16:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// EMOTE
|
2018-08-02 14:23:27 +02:00
|
|
|
EmoteElement::EmoteElement(const EmotePtr &emote, MessageElement::Flags flags)
|
2018-01-11 20:16:25 +01:00
|
|
|
: MessageElement(flags)
|
2018-08-02 14:23:27 +02:00
|
|
|
, emote_(emote)
|
2018-01-11 20:16:25 +01:00
|
|
|
{
|
2018-08-06 21:17:03 +02:00
|
|
|
this->textElement_.reset(
|
|
|
|
new TextElement(emote->getCopyString(), MessageElement::Misc));
|
2018-08-02 14:23:27 +02:00
|
|
|
|
|
|
|
this->setTooltip(emote->tooltip.string);
|
|
|
|
}
|
|
|
|
|
|
|
|
EmotePtr EmoteElement::getEmote() const
|
|
|
|
{
|
|
|
|
return this->emote_;
|
2018-01-22 22:38:44 +01:00
|
|
|
}
|
2018-01-11 20:16:25 +01:00
|
|
|
|
2018-08-06 21:17:03 +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-08-02 14:23:27 +02:00
|
|
|
auto image = this->emote_->images.getImage(container.getScale());
|
2018-08-06 18:25:47 +02:00
|
|
|
if (image->empty()) return;
|
2018-01-11 20:16:25 +01:00
|
|
|
|
2018-08-06 18:25:47 +02:00
|
|
|
auto size = QSize(int(container.getScale() * image->width()),
|
|
|
|
int(container.getScale() * image->height()));
|
2018-01-22 22:38:44 +01:00
|
|
|
|
2018-08-06 21:17:03 +02:00
|
|
|
container.addElement((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_) {
|
2018-08-06 21:17:03 +02:00
|
|
|
this->textElement_->addToContainer(container,
|
|
|
|
MessageElement::Misc);
|
2018-01-22 22:38:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-01-11 20:16:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// TEXT
|
|
|
|
TextElement::TextElement(const QString &text, MessageElement::Flags flags,
|
2018-07-06 19:23:47 +02:00
|
|
|
const MessageColor &color, FontStyle style)
|
2018-01-11 20:16:25 +01:00
|
|
|
: MessageElement(flags)
|
2018-07-06 19:23:47 +02:00
|
|
|
, color_(color)
|
|
|
|
, style_(style)
|
2018-01-11 20:16:25 +01:00
|
|
|
{
|
2018-08-06 18:25:47 +02:00
|
|
|
for (const auto &word : text.split(' ')) {
|
2018-07-06 19:23:47 +02:00
|
|
|
this->words_.push_back({word, -1});
|
2018-04-03 02:55:32 +02:00
|
|
|
// fourtf: add logic to store multiple spaces after message
|
2018-01-11 20:16:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-06 21:17:03 +02:00
|
|
|
void TextElement::addToContainer(MessageLayoutContainer &container,
|
|
|
|
MessageElement::Flags flags)
|
2018-01-11 20:16:25 +01:00
|
|
|
{
|
2018-04-27 22:11:19 +02:00
|
|
|
auto app = getApp();
|
|
|
|
|
2018-07-06 19:23:47 +02:00
|
|
|
if (flags & this->getFlags()) {
|
2018-08-06 21:17:03 +02:00
|
|
|
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-08-06 21:17:03 +02:00
|
|
|
auto getTextLayoutElement = [&](QString text, int width,
|
|
|
|
bool trailingSpace) {
|
2018-07-06 19:23:47 +02:00
|
|
|
QColor color = this->color_.getColor(*app->themes);
|
2018-04-27 22:11:19 +02:00
|
|
|
app->themes->normalizeColor(color);
|
2018-01-22 22:38:44 +01:00
|
|
|
|
2018-08-06 21:17:03 +02:00
|
|
|
auto e = (new TextLayoutElement(
|
|
|
|
*this, text, QSize(width, metrics.height()),
|
|
|
|
color, this->style_, container.getScale()))
|
2018-01-22 22:38:44 +01:00
|
|
|
->setLink(this->getLink());
|
|
|
|
e->setTrailingSpace(trailingSpace);
|
|
|
|
return e;
|
|
|
|
};
|
|
|
|
|
2018-01-23 22:00:58 +01:00
|
|
|
// fourtf: add again
|
|
|
|
// if (word.width == -1) {
|
|
|
|
word.width = metrics.width(word.text);
|
|
|
|
// }
|
2018-01-11 20:16:25 +01:00
|
|
|
|
2018-01-22 22:38:44 +01:00
|
|
|
// see if the text fits in the current line
|
2018-01-11 20:16:25 +01:00
|
|
|
if (container.fitsInLine(word.width)) {
|
2018-08-06 21:17:03 +02:00
|
|
|
container.addElementNoLineBreak(getTextLayoutElement(
|
|
|
|
word.text, word.width, this->hasTrailingSpace()));
|
2018-01-11 20:16:25 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-01-22 22:38:44 +01:00
|
|
|
// see if the text fits in the next line
|
|
|
|
if (!container.atStartOfLine()) {
|
2018-01-11 20:16:25 +01:00
|
|
|
container.breakLine();
|
|
|
|
|
2018-01-22 22:38:44 +01:00
|
|
|
if (container.fitsInLine(word.width)) {
|
2018-08-06 21:17:03 +02:00
|
|
|
container.addElementNoLineBreak(getTextLayoutElement(
|
|
|
|
word.text, word.width, this->hasTrailingSpace()));
|
2018-01-22 22:38:44 +01:00
|
|
|
continue;
|
2018-01-16 00:56:17 +01:00
|
|
|
}
|
2018-01-11 20:16:25 +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]);
|
|
|
|
|
|
|
|
for (int i = 1; i < textLength; i++) {
|
|
|
|
int charWidth = metrics.width(text[i]);
|
|
|
|
|
|
|
|
if (!container.fitsInLine(width + charWidth)) {
|
2018-08-06 21:17:03 +02:00
|
|
|
container.addElementNoLineBreak(getTextLayoutElement(
|
|
|
|
text.mid(wordStart, i - wordStart), width, false));
|
2018-01-22 22:38:44 +01:00
|
|
|
container.breakLine();
|
|
|
|
|
|
|
|
wordStart = i;
|
|
|
|
width = 0;
|
|
|
|
if (textLength > i + 2) {
|
|
|
|
width += metrics.width(text[i]);
|
|
|
|
width += metrics.width(text[i + 1]);
|
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
width += charWidth;
|
|
|
|
}
|
|
|
|
|
2018-08-06 21:17:03 +02:00
|
|
|
container.addElement(getTextLayoutElement(
|
|
|
|
text.mid(wordStart), width, this->hasTrailingSpace()));
|
2018-01-22 22:38:44 +01:00
|
|
|
container.breakLine();
|
|
|
|
}
|
2018-01-11 20:16:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TIMESTAMP
|
2018-07-06 19:23:47 +02:00
|
|
|
TimestampElement::TimestampElement(QTime time)
|
2018-01-11 20:16:25 +01:00
|
|
|
: MessageElement(MessageElement::Timestamp)
|
2018-07-06 19:23:47 +02:00
|
|
|
, time_(time)
|
|
|
|
, element_(this->formatTime(time))
|
2018-01-11 20:16:25 +01:00
|
|
|
{
|
2018-07-06 19:23:47 +02:00
|
|
|
assert(this->element_ != nullptr);
|
2018-01-11 20:16:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void TimestampElement::addToContainer(MessageLayoutContainer &container,
|
2018-07-06 19:23:47 +02:00
|
|
|
MessageElement::Flags flags)
|
2018-01-11 20:16:25 +01:00
|
|
|
{
|
2018-07-06 19:23:47 +02:00
|
|
|
if (flags & this->getFlags()) {
|
2018-04-27 22:11:19 +02:00
|
|
|
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
|
|
|
}
|
2018-01-11 20:16:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
TextElement *TimestampElement::formatTime(const QTime &time)
|
|
|
|
{
|
2018-01-17 18:36:12 +01:00
|
|
|
static QLocale locale("en_US");
|
|
|
|
|
2018-04-27 22:11:19 +02:00
|
|
|
QString format = locale.toString(time, getApp()->settings->timestampFormat);
|
2018-01-11 20:16:25 +01:00
|
|
|
|
2018-08-06 21:17:03 +02:00
|
|
|
return new TextElement(format, Flags::Timestamp, MessageColor::System,
|
|
|
|
FontStyle::ChatMedium);
|
2018-01-11 20:16:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// TWITCH MODERATION
|
|
|
|
TwitchModerationElement::TwitchModerationElement()
|
|
|
|
: MessageElement(MessageElement::ModeratorTools)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void TwitchModerationElement::addToContainer(MessageLayoutContainer &container,
|
2018-07-06 19:23:47 +02:00
|
|
|
MessageElement::Flags flags)
|
2018-01-11 20:16:25 +01:00
|
|
|
{
|
2018-07-06 19:23:47 +02:00
|
|
|
if (flags & MessageElement::ModeratorTools) {
|
2018-08-06 21:17:03 +02:00
|
|
|
QSize size(int(container.getScale() * 16),
|
|
|
|
int(container.getScale() * 16));
|
2018-01-17 16:52:51 +01:00
|
|
|
|
2018-08-06 21:17:03 +02:00
|
|
|
for (const auto &action :
|
|
|
|
getApp()->moderationActions->items.getVector()) {
|
2018-08-02 14:23:27 +02:00
|
|
|
if (auto image = action.getImage()) {
|
2018-08-06 21:17:03 +02:00
|
|
|
container.addElement(
|
|
|
|
(new ImageLayoutElement(*this, image.get(), size))
|
|
|
|
->setLink(Link(Link::UserAction, action.getAction())));
|
2018-01-17 16:52:51 +01:00
|
|
|
} else {
|
2018-08-02 14:23:27 +02:00
|
|
|
container.addElement(
|
2018-08-06 21:17:03 +02:00
|
|
|
(new TextIconLayoutElement(*this, action.getLine1(),
|
|
|
|
action.getLine2(),
|
2018-08-02 14:23:27 +02:00
|
|
|
container.getScale(), size))
|
|
|
|
->setLink(Link(Link::UserAction, action.getAction())));
|
2018-01-17 16:52:51 +01:00
|
|
|
}
|
2018-01-17 14:14:31 +01:00
|
|
|
}
|
|
|
|
}
|
2018-01-11 20:16:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace chatterino
|