mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
refactored message drawing
This commit is contained in:
parent
c6776cb76e
commit
8b40393023
2 changed files with 152 additions and 50 deletions
|
@ -25,6 +25,10 @@ ChatWidgetView::ChatWidgetView(ChatWidget *_chatWidget)
|
||||||
, chatWidget(_chatWidget)
|
, chatWidget(_chatWidget)
|
||||||
, scrollBar(this)
|
, scrollBar(this)
|
||||||
, userPopupWidget(_chatWidget->getChannelRef())
|
, userPopupWidget(_chatWidget->getChannelRef())
|
||||||
|
, selectionStart(0, 0)
|
||||||
|
, selectionEnd(0, 0)
|
||||||
|
, selectionMin(0, 0)
|
||||||
|
, selectionMax(0, 0)
|
||||||
{
|
{
|
||||||
#ifndef Q_OS_MAC
|
#ifndef Q_OS_MAC
|
||||||
this->setAttribute(Qt::WA_OpaquePaintEvent);
|
this->setAttribute(Qt::WA_OpaquePaintEvent);
|
||||||
|
@ -147,21 +151,41 @@ void ChatWidgetView::resizeEvent(QResizeEvent *)
|
||||||
this->update();
|
this->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChatWidgetView::setSelection(SelectionItem start, SelectionItem end)
|
||||||
|
{
|
||||||
|
// selections
|
||||||
|
SelectionItem min = selectionStart;
|
||||||
|
SelectionItem max = selectionEnd;
|
||||||
|
|
||||||
|
if (max.isSmallerThan(min)) {
|
||||||
|
std::swap(min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->selectionStart = start;
|
||||||
|
this->selectionEnd = end;
|
||||||
|
|
||||||
|
this->selectionMin = min;
|
||||||
|
this->selectionMax = max;
|
||||||
|
|
||||||
|
qDebug() << min.messageIndex << ":" << min.charIndex << " " << max.messageIndex << ":"
|
||||||
|
<< max.charIndex;
|
||||||
|
}
|
||||||
|
|
||||||
void ChatWidgetView::paintEvent(QPaintEvent * /*event*/)
|
void ChatWidgetView::paintEvent(QPaintEvent * /*event*/)
|
||||||
{
|
{
|
||||||
QPainter _painter(this);
|
QPainter painter(this);
|
||||||
|
|
||||||
_painter.setRenderHint(QPainter::SmoothPixmapTransform);
|
painter.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||||
|
|
||||||
// only update gif emotes
|
// only update gif emotes
|
||||||
#ifndef Q_OS_MAC
|
#ifndef Q_OS_MAC
|
||||||
if (this->onlyUpdateEmotes) {
|
if (this->onlyUpdateEmotes) {
|
||||||
this->onlyUpdateEmotes = false;
|
this->onlyUpdateEmotes = false;
|
||||||
|
|
||||||
for (const GifEmoteData &item : this->gifEmotes) {
|
for (const GifEmoteData &item : this->gifEmotes) {
|
||||||
_painter.fillRect(item.rect, this->colorScheme.ChatBackground);
|
painter.fillRect(item.rect, this->colorScheme.ChatBackground);
|
||||||
|
|
||||||
_painter.drawPixmap(item.rect, *item.image->getPixmap());
|
painter.drawPixmap(item.rect, *item.image->getPixmap());
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -171,8 +195,21 @@ void ChatWidgetView::paintEvent(QPaintEvent * /*event*/)
|
||||||
// update all messages
|
// update all messages
|
||||||
this->gifEmotes.clear();
|
this->gifEmotes.clear();
|
||||||
|
|
||||||
_painter.fillRect(rect(), this->colorScheme.ChatBackground);
|
painter.fillRect(rect(), this->colorScheme.ChatBackground);
|
||||||
|
|
||||||
|
// draw messages
|
||||||
|
this->drawMessages(painter);
|
||||||
|
|
||||||
|
// draw gif emotes
|
||||||
|
for (GifEmoteData &item : this->gifEmotes) {
|
||||||
|
painter.fillRect(item.rect, this->colorScheme.ChatBackground);
|
||||||
|
|
||||||
|
painter.drawPixmap(item.rect, *item.image->getPixmap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatWidgetView::drawMessages(QPainter &painter)
|
||||||
|
{
|
||||||
auto messages = this->chatWidget->getMessagesSnapshot();
|
auto messages = this->chatWidget->getMessagesSnapshot();
|
||||||
|
|
||||||
int start = this->scrollBar.getCurrentValue();
|
int start = this->scrollBar.getCurrentValue();
|
||||||
|
@ -183,7 +220,7 @@ void ChatWidgetView::paintEvent(QPaintEvent * /*event*/)
|
||||||
|
|
||||||
int y = -(messages[start].get()->getHeight() * (fmod(this->scrollBar.getCurrentValue(), 1)));
|
int y = -(messages[start].get()->getHeight() * (fmod(this->scrollBar.getCurrentValue(), 1)));
|
||||||
|
|
||||||
for (int i = start; i < messages.getLength(); ++i) {
|
for (size_t i = start; i < messages.getLength(); ++i) {
|
||||||
messages::MessageRef *messageRef = messages[i].get();
|
messages::MessageRef *messageRef = messages[i].get();
|
||||||
|
|
||||||
std::shared_ptr<QPixmap> bufferPtr = messageRef->buffer;
|
std::shared_ptr<QPixmap> bufferPtr = messageRef->buffer;
|
||||||
|
@ -199,38 +236,7 @@ void ChatWidgetView::paintEvent(QPaintEvent * /*event*/)
|
||||||
|
|
||||||
// update messages that have been changed
|
// update messages that have been changed
|
||||||
if (updateBuffer) {
|
if (updateBuffer) {
|
||||||
QPainter painter(buffer);
|
this->updateMessageBuffer(messageRef, buffer, i);
|
||||||
painter.fillRect(buffer->rect(), (messageRef->getMessage()->getCanHighlightTab())
|
|
||||||
? this->colorScheme.ChatBackgroundHighlighted
|
|
||||||
: this->colorScheme.ChatBackground);
|
|
||||||
for (messages::WordPart const &wordPart : messageRef->getWordParts()) {
|
|
||||||
// image
|
|
||||||
if (wordPart.getWord().isImage()) {
|
|
||||||
messages::LazyLoadedImage &lli = wordPart.getWord().getImage();
|
|
||||||
|
|
||||||
const QPixmap *image = lli.getPixmap();
|
|
||||||
|
|
||||||
if (image != nullptr) {
|
|
||||||
painter.drawPixmap(QRect(wordPart.getX(), wordPart.getY(),
|
|
||||||
wordPart.getWidth(), wordPart.getHeight()),
|
|
||||||
*image);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// text
|
|
||||||
else {
|
|
||||||
QColor color = wordPart.getWord().getColor();
|
|
||||||
|
|
||||||
this->colorScheme.normalizeColor(color);
|
|
||||||
|
|
||||||
painter.setPen(color);
|
|
||||||
painter.setFont(wordPart.getWord().getFont());
|
|
||||||
|
|
||||||
painter.drawText(QRectF(wordPart.getX(), wordPart.getY(), 10000, 10000),
|
|
||||||
wordPart.getText(), QTextOption(Qt::AlignLeft | Qt::AlignTop));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
messageRef->updateBuffer = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// get gif emotes
|
// get gif emotes
|
||||||
|
@ -253,7 +259,7 @@ void ChatWidgetView::paintEvent(QPaintEvent * /*event*/)
|
||||||
|
|
||||||
messageRef->buffer = bufferPtr;
|
messageRef->buffer = bufferPtr;
|
||||||
|
|
||||||
_painter.drawPixmap(0, y, *buffer);
|
painter.drawPixmap(0, y, *buffer);
|
||||||
|
|
||||||
y += messageRef->getHeight();
|
y += messageRef->getHeight();
|
||||||
|
|
||||||
|
@ -261,12 +267,53 @@ void ChatWidgetView::paintEvent(QPaintEvent * /*event*/)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (GifEmoteData &item : this->gifEmotes) {
|
void ChatWidgetView::updateMessageBuffer(messages::MessageRef *messageRef, QPixmap *buffer,
|
||||||
_painter.fillRect(item.rect, this->colorScheme.ChatBackground);
|
int messageIndex)
|
||||||
|
{
|
||||||
|
QPainter painter(buffer);
|
||||||
|
|
||||||
_painter.drawPixmap(item.rect, *item.image->getPixmap());
|
// draw background
|
||||||
|
// if (this->selectionMin.messageIndex <= messageIndex &&
|
||||||
|
// this->selectionMax.messageIndex >= messageIndex) {
|
||||||
|
// painter.fillRect(buffer->rect(), QColor(24, 55, 25));
|
||||||
|
//} else {
|
||||||
|
painter.fillRect(buffer->rect(),
|
||||||
|
(messageRef->getMessage()->getCanHighlightTab())
|
||||||
|
? this->colorScheme.ChatBackgroundHighlighted
|
||||||
|
: this->colorScheme.ChatBackground);
|
||||||
|
//}
|
||||||
|
|
||||||
|
// draw messages
|
||||||
|
for (messages::WordPart const &wordPart : messageRef->getWordParts()) {
|
||||||
|
// image
|
||||||
|
if (wordPart.getWord().isImage()) {
|
||||||
|
messages::LazyLoadedImage &lli = wordPart.getWord().getImage();
|
||||||
|
|
||||||
|
const QPixmap *image = lli.getPixmap();
|
||||||
|
|
||||||
|
if (image != nullptr) {
|
||||||
|
painter.drawPixmap(QRect(wordPart.getX(), wordPart.getY(), wordPart.getWidth(),
|
||||||
|
wordPart.getHeight()),
|
||||||
|
*image);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// text
|
||||||
|
else {
|
||||||
|
QColor color = wordPart.getWord().getColor();
|
||||||
|
|
||||||
|
this->colorScheme.normalizeColor(color);
|
||||||
|
|
||||||
|
painter.setPen(color);
|
||||||
|
painter.setFont(wordPart.getWord().getFont());
|
||||||
|
|
||||||
|
painter.drawText(QRectF(wordPart.getX(), wordPart.getY(), 10000, 10000),
|
||||||
|
wordPart.getText(), QTextOption(Qt::AlignLeft | Qt::AlignTop));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
messageRef->updateBuffer = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatWidgetView::wheelEvent(QWheelEvent *event)
|
void ChatWidgetView::wheelEvent(QWheelEvent *event)
|
||||||
|
@ -283,14 +330,20 @@ void ChatWidgetView::mouseMoveEvent(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
std::shared_ptr<messages::MessageRef> message;
|
std::shared_ptr<messages::MessageRef> message;
|
||||||
QPoint relativePos;
|
QPoint relativePos;
|
||||||
|
int messageIndex;
|
||||||
|
|
||||||
if (!tryGetMessageAt(event->pos(), message, relativePos)) {
|
if (!tryGetMessageAt(event->pos(), message, relativePos, messageIndex)) {
|
||||||
setCursor(Qt::ArrowCursor);
|
setCursor(Qt::ArrowCursor);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// int index = message->getSelectionIndex(relativePos);
|
if (this->selecting) {
|
||||||
// qDebug() << index;
|
int index = message->getSelectionIndex(relativePos);
|
||||||
|
|
||||||
|
this->setSelection(this->selectionStart, SelectionItem(messageIndex, index));
|
||||||
|
|
||||||
|
this->repaint();
|
||||||
|
}
|
||||||
|
|
||||||
messages::Word hoverWord;
|
messages::Word hoverWord;
|
||||||
if (!message->tryGetWordPart(relativePos, hoverWord)) {
|
if (!message->tryGetWordPart(relativePos, hoverWord)) {
|
||||||
|
@ -307,10 +360,29 @@ void ChatWidgetView::mouseMoveEvent(QMouseEvent *event)
|
||||||
|
|
||||||
void ChatWidgetView::mousePressEvent(QMouseEvent *event)
|
void ChatWidgetView::mousePressEvent(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
|
this->chatWidget->giveFocus(Qt::MouseFocusReason);
|
||||||
|
|
||||||
this->isMouseDown = true;
|
this->isMouseDown = true;
|
||||||
|
|
||||||
this->lastPressPosition = event->screenPos();
|
this->lastPressPosition = event->screenPos();
|
||||||
|
|
||||||
this->chatWidget->giveFocus(Qt::MouseFocusReason);
|
std::shared_ptr<messages::MessageRef> message;
|
||||||
|
QPoint relativePos;
|
||||||
|
int messageIndex;
|
||||||
|
|
||||||
|
if (!tryGetMessageAt(event->pos(), message, relativePos, messageIndex)) {
|
||||||
|
setCursor(Qt::ArrowCursor);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = message->getSelectionIndex(relativePos);
|
||||||
|
|
||||||
|
auto selectionItem = SelectionItem(messageIndex, index);
|
||||||
|
this->setSelection(selectionItem, selectionItem);
|
||||||
|
this->selecting = true;
|
||||||
|
|
||||||
|
this->repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatWidgetView::mouseReleaseEvent(QMouseEvent *event)
|
void ChatWidgetView::mouseReleaseEvent(QMouseEvent *event)
|
||||||
|
@ -322,6 +394,7 @@ void ChatWidgetView::mouseReleaseEvent(QMouseEvent *event)
|
||||||
}
|
}
|
||||||
|
|
||||||
this->isMouseDown = false;
|
this->isMouseDown = false;
|
||||||
|
this->selecting = false;
|
||||||
|
|
||||||
float distance = util::distanceBetweenPoints(this->lastPressPosition, event->screenPos());
|
float distance = util::distanceBetweenPoints(this->lastPressPosition, event->screenPos());
|
||||||
|
|
||||||
|
@ -339,8 +412,9 @@ void ChatWidgetView::mouseReleaseEvent(QMouseEvent *event)
|
||||||
|
|
||||||
std::shared_ptr<messages::MessageRef> message;
|
std::shared_ptr<messages::MessageRef> message;
|
||||||
QPoint relativePos;
|
QPoint relativePos;
|
||||||
|
int messageIndex;
|
||||||
|
|
||||||
if (!tryGetMessageAt(event->pos(), message, relativePos)) {
|
if (!tryGetMessageAt(event->pos(), message, relativePos, messageIndex)) {
|
||||||
// No message at clicked position
|
// No message at clicked position
|
||||||
this->userPopupWidget.hide();
|
this->userPopupWidget.hide();
|
||||||
return;
|
return;
|
||||||
|
@ -373,7 +447,7 @@ void ChatWidgetView::mouseReleaseEvent(QMouseEvent *event)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChatWidgetView::tryGetMessageAt(QPoint p, std::shared_ptr<messages::MessageRef> &_message,
|
bool ChatWidgetView::tryGetMessageAt(QPoint p, std::shared_ptr<messages::MessageRef> &_message,
|
||||||
QPoint &relativePos)
|
QPoint &relativePos, int &index)
|
||||||
{
|
{
|
||||||
auto messages = this->chatWidget->getMessagesSnapshot();
|
auto messages = this->chatWidget->getMessagesSnapshot();
|
||||||
|
|
||||||
|
@ -391,6 +465,7 @@ bool ChatWidgetView::tryGetMessageAt(QPoint p, std::shared_ptr<messages::Message
|
||||||
if (p.y() < y + message->getHeight()) {
|
if (p.y() < y + message->getHeight()) {
|
||||||
relativePos = QPoint(p.x(), p.y() - y);
|
relativePos = QPoint(p.x(), p.y() - y);
|
||||||
_message = message;
|
_message = message;
|
||||||
|
index = i;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,23 @@
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
namespace widgets {
|
namespace widgets {
|
||||||
|
|
||||||
|
struct SelectionItem {
|
||||||
|
int messageIndex;
|
||||||
|
int charIndex;
|
||||||
|
|
||||||
|
SelectionItem(int _messageIndex, int _charIndex)
|
||||||
|
{
|
||||||
|
this->messageIndex = _messageIndex;
|
||||||
|
this->charIndex = _charIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isSmallerThan(SelectionItem &other)
|
||||||
|
{
|
||||||
|
return messageIndex < other.messageIndex ||
|
||||||
|
(messageIndex == other.messageIndex && charIndex < other.charIndex);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class ChatWidget;
|
class ChatWidget;
|
||||||
|
|
||||||
class ChatWidgetView : public BaseWidget
|
class ChatWidgetView : public BaseWidget
|
||||||
|
@ -40,7 +57,7 @@ protected:
|
||||||
virtual void mouseReleaseEvent(QMouseEvent *event) override;
|
virtual void mouseReleaseEvent(QMouseEvent *event) override;
|
||||||
|
|
||||||
bool tryGetMessageAt(QPoint p, std::shared_ptr<messages::MessageRef> &message,
|
bool tryGetMessageAt(QPoint p, std::shared_ptr<messages::MessageRef> &message,
|
||||||
QPoint &relativePos);
|
QPoint &relativePos, int &index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct GifEmoteData {
|
struct GifEmoteData {
|
||||||
|
@ -48,6 +65,10 @@ private:
|
||||||
QRect rect;
|
QRect rect;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void drawMessages(QPainter &painter);
|
||||||
|
void updateMessageBuffer(messages::MessageRef *messageRef, QPixmap *buffer, int messageIndex);
|
||||||
|
void setSelection(SelectionItem start, SelectionItem end);
|
||||||
|
|
||||||
std::vector<GifEmoteData> gifEmotes;
|
std::vector<GifEmoteData> gifEmotes;
|
||||||
|
|
||||||
ChatWidget *const chatWidget;
|
ChatWidget *const chatWidget;
|
||||||
|
@ -65,6 +86,12 @@ private:
|
||||||
bool isMouseDown = false;
|
bool isMouseDown = false;
|
||||||
QPointF lastPressPosition;
|
QPointF lastPressPosition;
|
||||||
|
|
||||||
|
SelectionItem selectionStart;
|
||||||
|
SelectionItem selectionEnd;
|
||||||
|
SelectionItem selectionMin;
|
||||||
|
SelectionItem selectionMax;
|
||||||
|
bool selecting = false;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void wordTypeMaskChanged()
|
void wordTypeMaskChanged()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue