added spicy new segfaults

This commit is contained in:
fourtf 2017-01-11 01:08:20 +01:00
parent a8c2b1151f
commit 580a411e9d
22 changed files with 472 additions and 111 deletions

BIN
.vs/chatterino/v14/.suo Normal file

Binary file not shown.

View file

@ -11,6 +11,17 @@ public:
}
static bool isIgnoredEmote(const QString& emote);
static qreal emoteScale() {
return 1;
}
static qreal badgeScale() {
return 1;
}
static bool scaleEmotesByLineHeight() {
return false;
}
private:
AppSettings();

View file

@ -1,8 +1,10 @@
#include "channel.h"
#include "message.h"
Channel Channel::whispers = Channel(QString("/whispers"));
Channel Channel::mentions = Channel(QString("/mentions"));
#include <memory>
Channel Channel::whispers(QString("/whispers"));
Channel Channel::mentions(QString("/mentions"));
QMap<QString, Channel*> Channel::channels = QMap<QString, Channel*>();
@ -30,7 +32,7 @@ Channel* Channel::addChannel(const QString &channel)
return c;
}
c->referenceCount++;
c->m_referenceCount++;
return c;
}
@ -60,25 +62,26 @@ void Channel::removeChannel(const QString &channel)
if (c == NULL) return;
c->referenceCount--;
c->m_referenceCount--;
if (c->referenceCount == 0) {
if (c->m_referenceCount == 0) {
channels.remove(channel);
delete c;
}
}
QVector<Message*> Channel::getMessagesClone()
QVector<std::shared_ptr<Message>> Channel::getMessagesClone()
{
m_messageMutex.lock();
QVector M = QVector<Message*>(*m_messages);
QVector<std::shared_ptr<Message>> M(m_messages);
M.detach();
m_messageMutex.unlock();
return M;
}
void Channel::addMessage(Message *message)
void Channel::addMessage(std::shared_ptr<Message> message)
{
m_messageMutex.lock();
// messages
m_messages.append(message);
m_messageMutex.unlock();
}

View file

@ -8,6 +8,7 @@
#include <QMap>
#include <QMutex>
#include <QVector>
#include <memory>
class Message;
@ -48,9 +49,9 @@ public:
const QString& streamGame() const { return m_streamGame; }
// methods
void addMessage(Message* message);
void addMessage(std::shared_ptr<Message> message);
QVector<Message*> getMessagesClone();
QVector<std::shared_ptr<Message>> getMessagesClone();
private:
Channel(QString channel);
@ -61,7 +62,7 @@ private:
int m_referenceCount = 0;
QVector<Message*> m_messages;
QVector<std::shared_ptr<Message>> m_messages;
QString m_name;
int m_roomID;

View file

@ -56,7 +56,8 @@ SOURCES += main.cpp\
link.cpp \
fonts.cpp \
appsettings.cpp \
emojis.cpp
emojis.cpp \
wordpart.cpp
HEADERS += mainwindow.h \
chatwidget.h \
@ -87,11 +88,12 @@ HEADERS += mainwindow.h \
word.h \
link.h \
fonts.h \
common.h \
appsettings.h \
emojis.h
emojis.h \
wordpart.h \
common.h
PRECOMPILED_HEADER = common.h
PRECOMPILED_HEADER =
FORMS += \
dialog.ui

View file

@ -1,6 +1,10 @@
#include "chatwidgetview.h"
#include "QScroller"
#include "QPainter"
#include "word.h"
#include "wordpart.h"
#include "message.h"
#include <QScroller>
#include <QPainter>
ChatWidgetView::ChatWidgetView()
: QWidget(),
@ -18,6 +22,17 @@ void ChatWidgetView::resizeEvent(QResizeEvent *)
{
scrollbar.resize(scrollbar.width(), height());
scrollbar.move(width() - scrollbar.width(), 0);
auto c = channel();
if (c == NULL) return;
auto messages = c->getMessagesClone();
for (std::shared_ptr<Message>& message : messages)
{
message.get()->layout(width(), true);
}
}
void ChatWidgetView::paintEvent(QPaintEvent *)
@ -28,7 +43,34 @@ void ChatWidgetView::paintEvent(QPaintEvent *)
if (c == NULL) return;
auto M = c->getMessagesClone();
auto messages = c->getMessagesClone();
int y = 0;
for (std::shared_ptr<Message> const& message : messages)
{
for (WordPart const& wordPart : message.get()->wordParts())
{
// image
if (wordPart.word().isImage())
{
LazyLoadedImage& lli = wordPart.word().getImage();
const QImage* image = lli.image();
if (image != NULL)
{
painter.drawImage(QRect(wordPart.x(), wordPart.y() + y, wordPart.width(), wordPart.height()), *image);
}
}
// text
else
{
painter.drawText(wordPart.x(), wordPart.y() + y, wordPart.getText());
}
}
y += message.get()->height();
}
}

16
common.h.cpp Normal file
View file

@ -0,0 +1,16 @@
/*--------------------------------------------------------------------
* Precompiled header source file used by Visual Studio.NET to generate
* the .pch file.
*
* Due to issues with the dependencies checker within the IDE, it
* sometimes fails to recompile the PCH file, if we force the IDE to
* create the PCH file directly from the header file.
*
* This file is auto-generated by qmake since no PRECOMPILED_SOURCE was
* specified, and is used as the common stdafx.cpp. The file is only
* generated when creating .vcxproj project files, and is not used for
* command line compilations by nmake.
*
* WARNING: All changes made in this file will be lost.
--------------------------------------------------------------------*/
#include "common.h"

View file

@ -14,7 +14,7 @@ public:
map = new QMap<TKey, TValue>();
}
bool tryGet(const TKey &name, TValue& value) {
bool tryGet(const TKey &name, TValue& value) const {
mutex->lock();
auto a = map->find(name);
if (a == map->end()) {

View file

@ -15,7 +15,7 @@ ConcurrentMap<QString, LazyLoadedImage*>* Emojis::imageCache = new ConcurrentMap
QString Emojis::replaceShortCodes(const QString &text)
{
#warning "xD"
#pragma message WARN("xD")
return text;
}

View file

@ -23,14 +23,14 @@ Emotes::Emotes()
LazyLoadedImage* Emotes::getTwitchEmoteById(const QString &name, long id)
{
#warning "xD"
#pragma message WARN("xD")
return new LazyLoadedImage(NULL);
// return m_twitchEmoteFromCache->getOrAdd()
}
LazyLoadedImage* Emotes::getCheerImage(long long amount, bool animated)
{
#warning "xD"
#pragma message WARN("xD")
return getCheerBadge(amount);
}

View file

@ -9,6 +9,13 @@ QFont* Fonts::small = new QFont(DEFAULT_FONT);
QFont* Fonts::large = new QFont(DEFAULT_FONT);
QFont* Fonts::veryLarge = new QFont(DEFAULT_FONT);
QFontMetrics* Fonts::metricsMedium = new QFontMetrics(*medium );
QFontMetrics* Fonts::metricsMediumBold = new QFontMetrics(*mediumBold );
QFontMetrics* Fonts::metricsMediumItalic = new QFontMetrics(*mediumItalic);
QFontMetrics* Fonts::metricsSmall = new QFontMetrics(*small );
QFontMetrics* Fonts::metricsLarge = new QFontMetrics(*large );
QFontMetrics* Fonts::metricsVeryLarge = new QFontMetrics(*veryLarge );
Fonts::Fonts()
{
@ -25,3 +32,15 @@ QFont& Fonts::getFont(Type type)
return *medium;
}
QFontMetrics& Fonts::getFontMetrics(Type type)
{
if (type == Medium ) return *metricsMedium ;
if (type == MediumBold ) return *metricsMediumBold ;
if (type == MediumItalic) return *metricsMediumItalic;
if (type == Small ) return *metricsSmall ;
if (type == Large ) return *metricsLarge ;
if (type == VeryLarge ) return *metricsVeryLarge ;
return *metricsMedium;
}

11
fonts.h
View file

@ -1,7 +1,8 @@
#ifndef FONTS_H
#define FONTS_H
#include "QFont"
#include <QFont>
#include <QFontMetrics>
class Fonts
{
@ -16,6 +17,7 @@ public:
};
static QFont& getFont(Type type);
static QFontMetrics& getFontMetrics(Type type);
private:
Fonts();
@ -26,6 +28,13 @@ private:
static QFont* small;
static QFont* large;
static QFont* veryLarge;
static QFontMetrics* metricsMedium;
static QFontMetrics* metricsMediumBold;
static QFontMetrics* metricsMediumItalic;
static QFontMetrics* metricsSmall;
static QFontMetrics* metricsLarge;
static QFontMetrics* metricsVeryLarge;
};
#endif // FONTS_H

View file

@ -22,7 +22,7 @@ QMutex* IrcManager::twitchBlockedUsersMutex = new QMutex();
IrcManager::IrcManager()
{
// account = Account::anon();
}
void IrcManager::connect()
@ -160,7 +160,7 @@ void IrcManager::privateMessageReceived(IrcPrivateMessage *message)
auto c = Channel::getChannel(message->target().mid(1));
if (c != NULL) {
c->addMessage(new Message(*message, *c));
c->addMessage(std::shared_ptr<Message>(new Message(*message, *c)));
}
}

View file

@ -1,7 +1,8 @@
#include "lazyloadedimage.h"
LazyLoadedImage::LazyLoadedImage(const QString& url, qreal scale, const QString& name, const QString& tooltip, const QMargins& margin, bool isHat)
: m_url(url)
: m_image(NULL)
, m_url(url)
, m_name(name)
, m_tooltip(tooltip)
, m_animated(false)

View file

@ -25,8 +25,22 @@ public:
bool animated() const { return m_animated; }
bool isHat() const { return m_ishat; }
const long width() const {
if (m_image == NULL) {
return 16;
}
return m_image->width();
}
const long height() const {
if (m_image == NULL) {
return 16;
}
return m_image->height();
}
private:
QImage* m_image = NULL;
QImage* m_image;
qreal m_scale;
QString m_url;

View file

@ -1,8 +1,9 @@
#include <QApplication>
#include "mainwindow.h"
#include "colorscheme.h"
#include "ircmanager.h"
#include "emojis.h"
#include <QApplication>
#include <QClipboard>
int main(int argc, char *argv[])

View file

@ -6,11 +6,18 @@
#include "link.h"
#include "appsettings.h"
#include "ircmanager.h"
#include "fonts.h"
#include <ctime>
#include <tuple>
#include <list>
#include <QStringList>
#define MARGIN_LEFT 8
#define MARGIN_RIGHT 8
#define MARGIN_TOP 8
#define MARGIN_BOTTOM 8
LazyLoadedImage* Message::badgeStaff = new LazyLoadedImage(new QImage(":/images/staff_bg.png"));
LazyLoadedImage* Message::badgeAdmin = new LazyLoadedImage(new QImage(":/images/admin_bg.png"));
LazyLoadedImage* Message::badgeModerator = new LazyLoadedImage(new QImage(":/images/moderator_bg.png"));
@ -22,29 +29,33 @@ LazyLoadedImage* Message::badgePremium = new LazyLoadedImage(new QImage(":/i
QRegularExpression* Message::cheerRegex = new QRegularExpression("cheer[1-9][0-9]*");
Message::Message(const QString &text)
: m_wordParts(new std::list<WordPart>())
{
}
Message::Message(const IrcPrivateMessage& ircMessage, const Channel& channel, bool enablePingSound,
bool isReceivedWhisper, bool isSentWhisper, bool includeChannel )
: m_wordParts(new std::list<WordPart>())
{
m_parseTime = std::chrono::system_clock::now();
auto words = new QList<Word>();
auto words = std::vector<Word>();
auto iterator = ircMessage.tags().find("id");
auto tags = ircMessage.tags();
if (iterator != ircMessage.tags().end())
auto iterator = tags.find("id");
if (iterator != tags.end())
{
m_id = iterator.value().toString();
}
// timestamps
iterator = ircMessage.tags().find("tmi-sent-ts");
iterator = tags.find("tmi-sent-ts");
std::time_t time = std::time(NULL);
if (iterator != ircMessage.tags().end())
if (iterator != tags.end())
{
time = strtoll(iterator.value().toString().toStdString().c_str(), NULL, 10);
}
@ -57,13 +68,13 @@ Message::Message(const IrcPrivateMessage& ircMessage, const Channel& channel, bo
strftime(timeStampBuffer, 69, "%H:%M:%S", localtime(&time));
QString timestampWithSeconds = QString(timeStampBuffer);
words->append(Word(timestamp, Word::TimestampNoSeconds, ColorScheme::instance().SystemMessageColor, QString(), QString()));
words->append(Word(timestampWithSeconds, Word::TimestampWithSeconds, ColorScheme::instance().SystemMessageColor, QString(), QString()));
words.push_back(Word(timestamp, Word::TimestampNoSeconds, ColorScheme::instance().SystemMessageColor, QString(), QString()));
words.push_back(Word(timestampWithSeconds, Word::TimestampWithSeconds, ColorScheme::instance().SystemMessageColor, QString(), QString()));
// badges
iterator = ircMessage.tags().find("badges");
iterator = tags.find("badges");
if (iterator != ircMessage.tags().end())
if (iterator != tags.end())
{
auto badges = iterator.value().toString().split(',');
@ -72,36 +83,36 @@ Message::Message(const IrcPrivateMessage& ircMessage, const Channel& channel, bo
if (badge.startsWith("bits/"))
{
long long int cheer = strtoll(badge.mid(5).toStdString().c_str(), NULL, 10);
words->append(Word(Emotes::getCheerBadge(cheer), Word::BadgeCheer, QString(), QString("Twitch Cheer" + QString::number(cheer))));
words.push_back(Word(Emotes::getCheerBadge(cheer), Word::BadgeCheer, QString(), QString("Twitch Cheer" + QString::number(cheer))));
}
else if (badge == "staff/1")
{
words->append(Word(badgeStaff, Word::BadgeStaff, QString(), QString("Twitch Staff")));
words.push_back(Word(badgeStaff, Word::BadgeStaff, QString(), QString("Twitch Staff")));
}
else if (badge == "admin/1")
{
words->append(Word(badgeAdmin, Word::BadgeAdmin, QString(), QString("Twitch Admin")));
words.push_back(Word(badgeAdmin, Word::BadgeAdmin, QString(), QString("Twitch Admin")));
}
else if (badge == "global_mod/1")
{
words->append(Word(badgeGlobalmod, Word::BadgeGlobalMod, QString(), QString("Global Moderator")));
words.push_back(Word(badgeGlobalmod, Word::BadgeGlobalMod, QString(), QString("Global Moderator")));
}
else if (badge == "moderator/1")
{
#warning "xD"
words->append(Word(badgeTurbo, Word::BadgeModerator, QString(), QString("Channel Moderator"))); // custom badge
#pragma message WARN("xD")
words.push_back(Word(badgeTurbo, Word::BadgeModerator, QString(), QString("Channel Moderator"))); // custom badge
}
else if (badge == "turbo/1")
{
words->append(Word(badgeStaff, Word::BadgeTurbo, QString(), QString("Turbo Subscriber")));
words.push_back(Word(badgeStaff, Word::BadgeTurbo, QString(), QString("Turbo Subscriber")));
}
else if (badge == "broadcaster/1")
{
words->append(Word(badgeBroadcaster, Word::BadgeBroadcaster, QString(), QString("Channel Broadcaster")));
words.push_back(Word(badgeBroadcaster, Word::BadgeBroadcaster, QString(), QString("Channel Broadcaster")));
}
else if (badge == "premium/1")
{
words->append(Word(badgePremium, Word::BadgePremium, QString(), QString("Twitch Prime")));
words.push_back(Word(badgePremium, Word::BadgePremium, QString(), QString("Twitch Prime")));
}
}
}
@ -109,8 +120,8 @@ Message::Message(const IrcPrivateMessage& ircMessage, const Channel& channel, bo
// color
QColor usernameColor = ColorScheme::instance().SystemMessageColor;
iterator = ircMessage.tags().find("color");
if (iterator != ircMessage.tags().end())
iterator = tags.find("color");
if (iterator != tags.end())
{
usernameColor = QColor(iterator.value().toString());
}
@ -119,7 +130,7 @@ Message::Message(const IrcPrivateMessage& ircMessage, const Channel& channel, bo
if (includeChannel)
{
QString channelName("#" + channel.name());
words->append(Word(channelName, Word::Misc, ColorScheme::instance().SystemMessageColor, QString(channelName), QString(), Link(Link::Url, channel.name() + "\n" + m_id)));
words.push_back(Word(channelName, Word::Misc, ColorScheme::instance().SystemMessageColor, QString(channelName), QString(), Link(Link::Url, channel.name() + "\n" + m_id)));
}
// username
@ -127,9 +138,9 @@ Message::Message(const IrcPrivateMessage& ircMessage, const Channel& channel, bo
if (m_userName.isEmpty())
{
auto iterator = ircMessage.tags().find("login");
auto iterator = tags.find("login");
if (iterator != ircMessage.tags().end())
if (iterator != tags.end())
{
m_userName = iterator.value().toString();
}
@ -137,8 +148,8 @@ Message::Message(const IrcPrivateMessage& ircMessage, const Channel& channel, bo
QString displayName;
iterator = ircMessage.tags().find("display-name");
if (iterator == ircMessage.tags().end()) {
iterator = tags.find("display-name");
if (iterator == tags.end()) {
displayName = ircMessage.account();
}
else {
@ -163,7 +174,7 @@ Message::Message(const IrcPrivateMessage& ircMessage, const Channel& channel, bo
userDisplayString += ": ";
}
words->append(Word(userDisplayString, Word::Username, usernameColor, userDisplayString, QString()));
words.push_back(Word(userDisplayString, Word::Username, usernameColor, userDisplayString, QString()));
// highlights
#pragma message WARN("xD")
@ -171,18 +182,18 @@ Message::Message(const IrcPrivateMessage& ircMessage, const Channel& channel, bo
// bits
QString bits = "";
iterator = ircMessage.tags().find("bits");
if (iterator != ircMessage.tags().end())
iterator = tags.find("bits");
if (iterator != tags.end())
{
bits = iterator.value().toString();
}
// twitch emotes
QVector<std::pair<long int, LazyLoadedImage*>> twitchEmotes;
std::vector<std::pair<long int, LazyLoadedImage*>> twitchEmotes;
iterator = ircMessage.tags().find("emotes");
iterator = tags.find("emotes");
if (iterator != ircMessage.tags().end())
if (iterator != tags.end())
{
auto emotes = iterator.value().toString().split('/');
@ -211,7 +222,7 @@ Message::Message(const IrcPrivateMessage& ircMessage, const Channel& channel, bo
QString name = ircMessage.content().mid(start, end - start);
twitchEmotes.append(std::pair<long int, LazyLoadedImage*>(start, Emotes::getTwitchEmoteById(name, id)));
twitchEmotes.push_back(std::pair<long int, LazyLoadedImage*>(start, Emotes::getTwitchEmoteById(name, id)));
}
}
@ -234,8 +245,8 @@ Message::Message(const IrcPrivateMessage& ircMessage, const Channel& channel, bo
if (currentTwitchEmote->first == i)
{
words->append(Word(currentTwitchEmote->second, Word::TwitchEmoteImage, currentTwitchEmote->second->name(), currentTwitchEmote->second->name() + QString("\nTwitch Emote")));
words->append(Word(currentTwitchEmote->second->name(), Word::TwitchEmoteText, textColor, currentTwitchEmote->second->name(), currentTwitchEmote->second->name() + QString("\nTwitch Emote")));
words.push_back(Word(currentTwitchEmote->second, Word::TwitchEmoteImage, currentTwitchEmote->second->name(), currentTwitchEmote->second->name() + QString("\nTwitch Emote")));
words.push_back(Word(currentTwitchEmote->second->name(), Word::TwitchEmoteText, textColor, currentTwitchEmote->second->name(), currentTwitchEmote->second->name() + QString("\nTwitch Emote")));
i += split.length() + 1;
currentTwitchEmote = std::next(currentTwitchEmote);
@ -296,26 +307,26 @@ Message::Message(const IrcPrivateMessage& ircMessage, const Channel& channel, bo
LazyLoadedImage* imageAnimated = Emotes::miscImageFromCache().getOrAdd(bitsLinkAnimated, [&bitsLinkAnimated]{ return new LazyLoadedImage(bitsLinkAnimated); });
LazyLoadedImage* image = Emotes::miscImageFromCache().getOrAdd(bitsLink, [&bitsLink]{ return new LazyLoadedImage(bitsLink); });
words->append(Word(imageAnimated, Word::BitsAnimated, QString("cheer"), QString("Twitch Cheer"), Link(Link::Url, QString("https://blog.twitch.tv/introducing-cheering-celebrate-together-da62af41fac6"))));
words->append(Word(image, Word::Bits, QString("cheer"), QString("Twitch Cheer"), Link(Link::Url, QString("https://blog.twitch.tv/introducing-cheering-celebrate-together-da62af41fac6"))));
words.push_back(Word(imageAnimated, Word::BitsAnimated, QString("cheer"), QString("Twitch Cheer"), Link(Link::Url, QString("https://blog.twitch.tv/introducing-cheering-celebrate-together-da62af41fac6"))));
words.push_back(Word(image, Word::Bits, QString("cheer"), QString("Twitch Cheer"), Link(Link::Url, QString("https://blog.twitch.tv/introducing-cheering-celebrate-together-da62af41fac6"))));
words->append(Word(QString("x" + string.mid(5)), Word::BitsAmount, bitsColor, QString(string.mid(5)), QString("Twitch Cheer"), Link(Link::Url, QString("https://blog.twitch.tv/introducing-cheering-celebrate-together-da62af41fac6"))));
words.push_back(Word(QString("x" + string.mid(5)), Word::BitsAmount, bitsColor, QString(string.mid(5)), QString("Twitch Cheer"), Link(Link::Url, QString("https://blog.twitch.tv/introducing-cheering-celebrate-together-da62af41fac6"))));
continue;
}
continue;
// bttv / ffz emotes
LazyLoadedImage* bttvEmote;
#pragma message WARN( "xD ignored emotes")
if (
#warning "xD ignored emotes"
Emotes::bttvEmotes().tryGet(string, bttvEmote) ||
channel.bttvChannelEmotes().tryGet(string, bttvEmote) ||
Emotes::ffzEmotes().tryGet(string, bttvEmote) ||
channel.ffzChannelEmotes().tryGet(string, bttvEmote) ||
Emotes::chatterinoEmotes().tryGet(string, bttvEmote))
{
words->append(Word(bttvEmote, Word::BttvEmoteImage, bttvEmote->name(), bttvEmote->tooltip(), Link(Link::Url, bttvEmote->url())));
words.push_back(Word(bttvEmote, Word::BttvEmoteImage, bttvEmote->name(), bttvEmote->tooltip(), Link(Link::Url, bttvEmote->url())));
continue;
}
@ -323,22 +334,131 @@ Message::Message(const IrcPrivateMessage& ircMessage, const Channel& channel, bo
// actually just a word
QString link = matchLink(string);
words->append(Word(string, Word::Text, textColor, string, QString(), link.isEmpty() ? Link() : Link(Link::Url, link)));
words.push_back(Word(string, Word::Text, textColor, string, QString(), link.isEmpty() ? Link() : Link(Link::Url, link)));
}
}
i += split.length() + 1;
}
this->words() = words;
this->m_words = words;
#warning "xD"
#pragma message WARN("xD")
// if (!isReceivedWhisper && AppSettings.HighlightIgnoredUsers.ContainsKey(Username))
// {
// HighlightTab = false;
// }
}
//static void normalize
bool Message::layout(int width, bool enableEmoteMargins)
{
width = width - (width % 2);
int mediumTextLineHeight = Fonts::getFontMetrics(Fonts::Medium).height();
bool redraw = width != m_currentLayoutWidth || m_relayoutRequested;
if (m_recalculateImages || m_recalculateText)
{
redraw = true;
for (auto& word : m_words)
{
if (word.isImage())
{
if (m_recalculateImages)
{
auto& image = word.getImage();
qreal w = image.width();
qreal h = image.height();
if (AppSettings::scaleEmotesByLineHeight())
{
word.setSize(w * mediumTextLineHeight / h * AppSettings::emoteScale(), mediumTextLineHeight * AppSettings::emoteScale());
}
else
{
word.setSize(w * image.scale() * AppSettings::emoteScale(), h * image.scale() * AppSettings::emoteScale());
}
}
}
else
{
if (m_recalculateText)
{
QFontMetrics& metrics = word.getFontMetrics();
word.setSize(metrics.width(word.getText()), metrics.height());
}
}
}
m_recalculateImages = false;
m_recalculateText = false;
}
if (redraw)
{
int x = MARGIN_LEFT;
int y = MARGIN_TOP;
int right = width - MARGIN_RIGHT;
std::list<WordPart>* parts;
auto lineStart = m_wordParts->begin();
int lineHeight = 0;
for (auto it = m_words.begin(); it != m_words.end(); ++it)
{
Word& word = *it;
int xOffset = 0, yOffset = 0;
if (enableEmoteMargins)
{
if (word.isImage() && word.getImage().isHat())
{
xOffset = -word.width() + 2;
}
else
{
xOffset = word.xOffset();
yOffset = word.yOffset();
}
lineHeight = std::max(word.height(), lineHeight);
}
if (x + word.width() + xOffset <= right)
{
parts->push_back(WordPart(word, x, y, QStringRef(&word.copyText())));
x += word.width() + xOffset;
}
// else if (word.isText() && word.getText().length() > 2)
// {
// }
else
{
parts->push_back(WordPart(word, x, y, QStringRef(&word.copyText())));
lineHeight = std::max(word.height(), lineHeight);
}
}
auto tmp = m_wordParts;
m_wordParts = parts;
delete tmp;
m_height = y + lineHeight;
}
return redraw;
}
bool Message::sortTwitchEmotes(const std::pair<long int, LazyLoadedImage*>& a, const std::pair<long int, LazyLoadedImage*>& b)
{
return a.first < b.first;
@ -346,6 +466,6 @@ bool Message::sortTwitchEmotes(const std::pair<long int, LazyLoadedImage*>& a, c
QString Message::matchLink(const QString &string)
{
#warning "xD"
#pragma message WARN("xD")
return QString();
}

View file

@ -1,29 +1,27 @@
#ifndef MESSAGE_H
#define MESSAGE_H
#include "IrcMessage"
#include "word.h"
#include "chrono"
#include "wordpart.h"
#include "channel.h"
#include <IrcMessage>
#include <QVector>
#include <chrono>
class Message
{
public:
// enum Badges : char {
// None = 0,
// Mod = 1,
// Turbo = 2,
// Sub = 4,
// Staff = 8,
// GlobalMod = 16,
// Admin = 32,
// Broadcaster = 64,
// };
Message(const QString& text);
Message(const IrcPrivateMessage& ircMessage, const Channel& Channel, bool enablePingSound = true,
bool isReceivedWhisper = false, bool isSentWhisper = false, bool includeChannel = false);
~Message() {
if (m_wordParts != NULL) {
delete m_wordParts;
}
}
bool canHighlightTab() const {
return m_highlightTab;
}
@ -44,10 +42,14 @@ public:
return m_displayName;
}
QList<Word> words() const {
const std::vector<Word> words() const {
return m_words;
}
const std::list<WordPart> wordParts() const {
return *m_wordParts;
}
bool disabled() const {
return m_disabled;
}
@ -56,6 +58,16 @@ public:
return m_id;
}
int height() const {
return m_height;
}
bool layout(int width, bool enableEmoteMargins = true);
void requestRelayout() { m_relayoutRequested = true; }
void requestTextRecalculation() { m_recalculateText = true; }
void requestImageRecalculation() { m_recalculateImages = true; }
private:
static LazyLoadedImage* badgeStaff;
static LazyLoadedImage* badgeAdmin;
@ -77,7 +89,15 @@ private:
QString m_displayName = "";
QString m_id = "";
QList<Word> m_words;
int m_height = 0;
std::vector<Word> m_words;
std::list<WordPart>* m_wordParts;
long m_currentLayoutWidth = -1;
bool m_relayoutRequested = true;
bool m_recalculateText = true;
bool m_recalculateImages = true;
static QString matchLink(const QString& string);

View file

@ -11,13 +11,14 @@ Word::Word(LazyLoadedImage* image, Type type, const QString& copytext, const QSt
, m_color()
, m_link(link)
{
image->width(); // professional segfault test
}
// Text word
Word::Word(const QString& text, Type type, const QColor& color, const QString& copytext, const QString& tooltip, const Link& link)
: m_image(nullptr)
: m_image(NULL)
, m_text(text)
, m_isImage(true)
, m_isImage(false)
, m_type(type)
, m_copyText(copytext)
, m_tooltip(tooltip)

49
word.h
View file

@ -27,6 +27,7 @@ public:
BttvGifEmoteText = 0x200,
FfzEmoteImage = 0x400,
FfzEmoteText = 0x800,
EmoteImages = TwitchEmoteImage | BttvEmoteImage | BttvGifEmoteImage | FfzEmoteImage,
Bits = 0x1000,
BitsAnimated = 0x2000,
@ -75,30 +76,19 @@ public:
return m_height;
}
int x() const {
return m_x;
}
int y() const {
return m_y;
}
int right() const {
return m_x + m_width;
}
int bottom() const {
return m_y + m_height;
}
QRect rect() const {
return QRect(m_x, m_y, m_width, m_height);
void setSize(int width, int height) {
m_width = width;
m_height = height;
}
bool isImage() const {
return m_isImage;
}
bool isText() const {
return !m_isImage;
}
const QString& copyText() const {
return m_copyText;
}
@ -111,6 +101,10 @@ public:
return Fonts::getFont(m_font);
}
QFontMetrics& getFontMetrics() const {
return Fonts::getFontMetrics(m_font);
}
Type type() const {
return m_type;
}
@ -127,6 +121,19 @@ public:
return m_link;
}
int xOffset() const {
return m_xOffset;
}
int yOffset() const {
return m_yOffset;
}
void setOffset(int xOffset, int yOffset) {
m_xOffset = std::max(0, xOffset);
m_yOffset = std::max(0, yOffset);
}
private:
LazyLoadedImage* m_image;
QString m_text;
@ -136,10 +143,12 @@ private:
Type m_type;
QString m_copyText;
QString m_tooltip;
int m_x;
int m_y;
int m_width;
int m_height;
int m_xOffset;
int m_yOffset;
bool m_hasTrailingSpace;
Fonts::Type m_font = Fonts::Medium;
Link m_link;

18
wordpart.cpp Normal file
View file

@ -0,0 +1,18 @@
#include "wordpart.h"
#include "word.h"
WordPart::WordPart(Word& word, int x, int y, const QStringRef& copyText, bool allowTrailingSpace)
: m_word(word)
, m_copyText(copyText)
, m_x(x)
, m_y(y)
, m_width(word.width())
, m_height(word.height())
, m_trailingSpace(word.hasTrailingSpace() & allowTrailingSpace)
{
}
const QString& WordPart::getText() const
{
return m_word.getText();
}

74
wordpart.h Normal file
View file

@ -0,0 +1,74 @@
#ifndef WORDPART_H
#define WORDPART_H
#include <QRect>
#include <QStringRef>
class Word;
class WordPart
{
public:
WordPart(Word& word, int x, int y, const QStringRef& copyText, bool allowTrailingSpace = true);
const Word& word() const {
return m_word;
}
int width() const {
return m_width;
}
int height() const {
return m_height;
}
int x() const {
return m_x;
}
int y() const {
return m_y;
}
void setPosition(int x, int y) {
m_x = x;
m_y = y;
}
int right() const {
return m_x + m_width;
}
int bottom() const {
return m_y + m_height;
}
QRect rect() const {
return QRect(m_x, m_y, m_width, m_height);
}
const QStringRef copyText() const {
return m_copyText;
}
int hasTrailingSpace() const {
return m_trailingSpace;
}
const QString& getText() const;
private:
Word& m_word;
QStringRef m_copyText;
int m_x;
int m_y;
int m_width;
int m_height;
bool m_trailingSpace;
};
#endif // WORDPART_H