Added support for Twitch's Chat Replies (#3722)
Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
This commit is contained in:
@@ -55,6 +55,11 @@ const Message *MessageLayout::getMessage()
|
||||
return this->message_.get();
|
||||
}
|
||||
|
||||
const MessagePtr &MessageLayout::getMessagePtr() const
|
||||
{
|
||||
return this->message_;
|
||||
}
|
||||
|
||||
// Height
|
||||
int MessageLayout::getHeight() const
|
||||
{
|
||||
@@ -147,6 +152,12 @@ void MessageLayout::actuallyLayout(int width, MessageElementFlags flags)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!this->renderReplies_ &&
|
||||
element->getFlags().has(MessageElementFlag::RepliedMessage))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
element->addToContainer(*this->container_, flags);
|
||||
}
|
||||
|
||||
@@ -414,4 +425,26 @@ void MessageLayout::addSelectionText(QString &str, int from, int to,
|
||||
this->container_->addSelectionText(str, from, to, copymode);
|
||||
}
|
||||
|
||||
bool MessageLayout::isReplyable() const
|
||||
{
|
||||
if (this->message_->loginName.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->message_->flags.hasAny(
|
||||
{MessageFlag::System, MessageFlag::Subscription,
|
||||
MessageFlag::Timeout, MessageFlag::Whisper}))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MessageLayout::setRenderReplies(bool render)
|
||||
{
|
||||
this->renderReplies_ = render;
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -37,6 +37,7 @@ public:
|
||||
~MessageLayout();
|
||||
|
||||
const Message *getMessage();
|
||||
const MessagePtr &getMessagePtr() const;
|
||||
|
||||
int getHeight() const;
|
||||
|
||||
@@ -62,6 +63,8 @@ public:
|
||||
|
||||
// Misc
|
||||
bool isDisabled() const;
|
||||
bool isReplyable() const;
|
||||
void setRenderReplies(bool render);
|
||||
|
||||
private:
|
||||
// variables
|
||||
@@ -69,6 +72,7 @@ private:
|
||||
std::shared_ptr<MessageLayoutContainer> container_;
|
||||
std::shared_ptr<QPixmap> buffer_{};
|
||||
bool bufferValid_ = false;
|
||||
bool renderReplies_ = true;
|
||||
|
||||
int height_ = 0;
|
||||
|
||||
|
||||
@@ -661,6 +661,14 @@ void MessageLayoutContainer::addSelectionText(QString &str, int from, int to,
|
||||
|
||||
for (auto &element : this->elements_)
|
||||
{
|
||||
if (copymode != CopyMode::Everything &&
|
||||
element->getCreator().getFlags().has(
|
||||
MessageElementFlag::RepliedMessage))
|
||||
{
|
||||
// Don't include the message being replied to
|
||||
continue;
|
||||
}
|
||||
|
||||
if (copymode == CopyMode::OnlyTextAndEmotes)
|
||||
{
|
||||
if (element->getCreator().getFlags().hasAny(
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <QDebug>
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
@@ -205,6 +206,44 @@ void ImageWithBackgroundLayoutElement::paint(QPainter &painter)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// IMAGE WITH CIRCLE BACKGROUND
|
||||
//
|
||||
ImageWithCircleBackgroundLayoutElement::ImageWithCircleBackgroundLayoutElement(
|
||||
MessageElement &creator, ImagePtr image, const QSize &imageSize,
|
||||
QColor color, int padding)
|
||||
: ImageLayoutElement(creator, image,
|
||||
imageSize + QSize(padding, padding) * 2)
|
||||
, color_(color)
|
||||
, imageSize_(imageSize)
|
||||
, padding_(padding)
|
||||
{
|
||||
}
|
||||
|
||||
void ImageWithCircleBackgroundLayoutElement::paint(QPainter &painter)
|
||||
{
|
||||
if (this->image_ == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto pixmap = this->image_->pixmapOrLoad();
|
||||
if (pixmap && !this->image_->animated())
|
||||
{
|
||||
QRectF boxRect(this->getRect());
|
||||
painter.setPen(Qt::NoPen);
|
||||
painter.setBrush(QBrush(this->color_, Qt::SolidPattern));
|
||||
painter.drawEllipse(boxRect);
|
||||
|
||||
QRectF imgRect;
|
||||
imgRect.setTopLeft(boxRect.topLeft());
|
||||
imgRect.setSize(this->imageSize_);
|
||||
imgRect.translate(this->padding_, this->padding_);
|
||||
|
||||
painter.drawPixmap(imgRect, *pixmap, QRectF());
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// TEXT
|
||||
//
|
||||
@@ -402,4 +441,67 @@ int TextIconLayoutElement::getXFromIndex(int index)
|
||||
}
|
||||
}
|
||||
|
||||
ReplyCurveLayoutElement::ReplyCurveLayoutElement(MessageElement &creator,
|
||||
const QSize &size,
|
||||
float thickness,
|
||||
float neededMargin)
|
||||
: MessageLayoutElement(creator, size)
|
||||
, pen_(QColor("#888"), thickness, Qt::SolidLine, Qt::RoundCap)
|
||||
, neededMargin_(neededMargin)
|
||||
{
|
||||
}
|
||||
|
||||
void ReplyCurveLayoutElement::paint(QPainter &painter)
|
||||
{
|
||||
QRectF paintRect(this->getRect());
|
||||
QPainterPath bezierPath;
|
||||
|
||||
qreal top = paintRect.top() + paintRect.height() * 0.25; // 25% from top
|
||||
qreal left = paintRect.left() + this->neededMargin_;
|
||||
qreal bottom = paintRect.bottom() - this->neededMargin_;
|
||||
QPointF startPoint(left, bottom);
|
||||
QPointF controlPoint(left, top);
|
||||
QPointF endPoint(paintRect.right(), top);
|
||||
|
||||
// Create curve path
|
||||
bezierPath.moveTo(startPoint);
|
||||
bezierPath.quadTo(controlPoint, endPoint);
|
||||
|
||||
// Render curve
|
||||
painter.setPen(this->pen_);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
painter.drawPath(bezierPath);
|
||||
}
|
||||
|
||||
void ReplyCurveLayoutElement::paintAnimated(QPainter &painter, int yOffset)
|
||||
{
|
||||
}
|
||||
|
||||
int ReplyCurveLayoutElement::getMouseOverIndex(const QPoint &abs) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ReplyCurveLayoutElement::getXFromIndex(int index)
|
||||
{
|
||||
if (index <= 0)
|
||||
{
|
||||
return this->getRect().left();
|
||||
}
|
||||
else
|
||||
{
|
||||
return this->getRect().right();
|
||||
}
|
||||
}
|
||||
|
||||
void ReplyCurveLayoutElement::addCopyTextToString(QString &str, int from,
|
||||
int to) const
|
||||
{
|
||||
}
|
||||
|
||||
int ReplyCurveLayoutElement::getSelectionIndexCount() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <QPen>
|
||||
#include <QPoint>
|
||||
#include <QRect>
|
||||
#include <QString>
|
||||
@@ -93,6 +94,23 @@ private:
|
||||
QColor color_;
|
||||
};
|
||||
|
||||
class ImageWithCircleBackgroundLayoutElement : public ImageLayoutElement
|
||||
{
|
||||
public:
|
||||
ImageWithCircleBackgroundLayoutElement(MessageElement &creator,
|
||||
ImagePtr image,
|
||||
const QSize &imageSize, QColor color,
|
||||
int padding);
|
||||
|
||||
protected:
|
||||
void paint(QPainter &painter) override;
|
||||
|
||||
private:
|
||||
const QColor color_;
|
||||
const QSize imageSize_;
|
||||
const int padding_;
|
||||
};
|
||||
|
||||
// TEXT
|
||||
class TextLayoutElement : public MessageLayoutElement
|
||||
{
|
||||
@@ -142,4 +160,24 @@ private:
|
||||
QString line2;
|
||||
};
|
||||
|
||||
class ReplyCurveLayoutElement : public MessageLayoutElement
|
||||
{
|
||||
public:
|
||||
ReplyCurveLayoutElement(MessageElement &creator, const QSize &size,
|
||||
float thickness, float lMargin);
|
||||
|
||||
protected:
|
||||
void paint(QPainter &painter) override;
|
||||
void paintAnimated(QPainter &painter, int yOffset) override;
|
||||
int getMouseOverIndex(const QPoint &abs) const override;
|
||||
int getXFromIndex(int index) override;
|
||||
void addCopyTextToString(QString &str, int from = 0,
|
||||
int to = INT_MAX) const override;
|
||||
int getSelectionIndexCount() const override;
|
||||
|
||||
private:
|
||||
const QPen pen_;
|
||||
const float neededMargin_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
Reference in New Issue
Block a user