I BROKE EVERYTHING
refactored the rendering process
This commit is contained in:
@@ -0,0 +1,345 @@
|
||||
#include "messages/layouts/messagelayout.hpp"
|
||||
#include "singletons/emotemanager.hpp"
|
||||
#include "singletons/settingsmanager.hpp"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include <QPainter>
|
||||
#include <QThread>
|
||||
#include <QtGlobal>
|
||||
|
||||
#define MARGIN_LEFT (int)(8 * this->scale)
|
||||
#define MARGIN_RIGHT (int)(8 * this->scale)
|
||||
#define MARGIN_TOP (int)(4 * this->scale)
|
||||
#define MARGIN_BOTTOM (int)(4 * this->scale)
|
||||
#define COMPACT_EMOTES_OFFSET 6
|
||||
|
||||
namespace chatterino {
|
||||
namespace messages {
|
||||
namespace layouts {
|
||||
|
||||
MessageLayout::MessageLayout(MessagePtr _message)
|
||||
: message(_message)
|
||||
, buffer(nullptr)
|
||||
{
|
||||
if (_message->hasFlags(Message::Collapsed)) {
|
||||
this->addFlags(MessageLayout::Collapsed);
|
||||
}
|
||||
}
|
||||
|
||||
Message *MessageLayout::getMessage()
|
||||
{
|
||||
return this->message.get();
|
||||
}
|
||||
|
||||
// Height
|
||||
int MessageLayout::getHeight() const
|
||||
{
|
||||
return container.getHeight();
|
||||
}
|
||||
|
||||
// Flags
|
||||
MessageLayout::Flags MessageLayout::getFlags() const
|
||||
{
|
||||
return this->flags;
|
||||
}
|
||||
|
||||
bool MessageLayout::hasFlags(Flags _flags) const
|
||||
{
|
||||
return this->flags & _flags;
|
||||
}
|
||||
|
||||
void MessageLayout::addFlags(Flags _flags)
|
||||
{
|
||||
this->flags = (Flags)((MessageLayoutFlagsType)this->flags | (MessageLayoutFlagsType)_flags);
|
||||
}
|
||||
|
||||
void MessageLayout::removeFlags(Flags _flags)
|
||||
{
|
||||
this->flags = (Flags)((MessageLayoutFlagsType)this->flags & ~((MessageLayoutFlagsType)_flags));
|
||||
}
|
||||
|
||||
// Layout
|
||||
// return true if redraw is required
|
||||
bool MessageLayout::layout(int width, float scale)
|
||||
{
|
||||
auto &emoteManager = singletons::EmoteManager::getInstance();
|
||||
|
||||
bool layoutRequired = false;
|
||||
|
||||
// check if width changed
|
||||
bool widthChanged = width != this->currentLayoutWidth;
|
||||
layoutRequired |= widthChanged;
|
||||
this->currentLayoutWidth = width;
|
||||
|
||||
// check if emotes changed
|
||||
bool imagesChanged = this->emoteGeneration != emoteManager.getGeneration();
|
||||
layoutRequired |= imagesChanged;
|
||||
this->emoteGeneration = emoteManager.getGeneration();
|
||||
|
||||
// check if text changed
|
||||
bool textChanged =
|
||||
this->fontGeneration != singletons::FontManager::getInstance().getGeneration();
|
||||
layoutRequired |= textChanged;
|
||||
this->fontGeneration = singletons::FontManager::getInstance().getGeneration();
|
||||
|
||||
// check if work mask changed
|
||||
bool wordMaskChanged =
|
||||
this->currentWordTypes != singletons::SettingManager::getInstance().getWordTypeMask();
|
||||
layoutRequired |= wordMaskChanged;
|
||||
this->currentWordTypes = singletons::SettingManager::getInstance().getWordTypeMask();
|
||||
|
||||
// check if dpi changed
|
||||
bool scaleChanged = this->scale != scale;
|
||||
layoutRequired |= scaleChanged;
|
||||
this->scale = scale;
|
||||
imagesChanged |= scaleChanged;
|
||||
textChanged |= scaleChanged;
|
||||
|
||||
// update word sizes if needed
|
||||
if (imagesChanged) {
|
||||
// fourtf: update images
|
||||
this->addFlags(MessageLayout::RequiresBufferUpdate);
|
||||
}
|
||||
if (textChanged) {
|
||||
// fourtf: update text
|
||||
this->addFlags(MessageLayout::RequiresBufferUpdate);
|
||||
}
|
||||
if (widthChanged || wordMaskChanged) {
|
||||
this->deleteBuffer();
|
||||
}
|
||||
|
||||
// return if no layout is required
|
||||
if (!layoutRequired) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this->actuallyLayout(width);
|
||||
this->invalidateBuffer();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MessageLayout::actuallyLayout(int width)
|
||||
{
|
||||
this->container.clear();
|
||||
this->container.width = width;
|
||||
this->container.scale = this->scale;
|
||||
|
||||
for (const std::unique_ptr<MessageElement> &element : this->message->getElements()) {
|
||||
element->addToContainer(this->container, MessageElement::Default);
|
||||
}
|
||||
|
||||
if (this->height != this->container.getHeight()) {
|
||||
this->deleteBuffer();
|
||||
}
|
||||
|
||||
this->container.finish();
|
||||
this->height = this->container.getHeight();
|
||||
}
|
||||
|
||||
// Painting
|
||||
void MessageLayout::paint(QPainter &painter, int y, int messageIndex, Selection &selection)
|
||||
{
|
||||
QPixmap *pixmap = this->buffer.get();
|
||||
|
||||
// create new buffer if required
|
||||
if (!pixmap) {
|
||||
#ifdef Q_OS_MACOS
|
||||
|
||||
pixmap =
|
||||
new QPixmap((int)(this->container.getWidth() * painter.device()->devicePixelRatioF()),
|
||||
(int)(this->container.getHeight() * painter.device()->devicePixelRatioF()));
|
||||
pixmap->setDevicePixelRatio(painter.device()->devicePixelRatioF());
|
||||
#else
|
||||
pixmap = new QPixmap(this->container.width, std::max(16, this->container.getHeight()));
|
||||
#endif
|
||||
|
||||
this->buffer = std::shared_ptr<QPixmap>(pixmap);
|
||||
this->bufferValid = false;
|
||||
}
|
||||
|
||||
if (!this->bufferValid) {
|
||||
this->updateBuffer(pixmap, messageIndex, selection);
|
||||
}
|
||||
|
||||
// draw on buffer
|
||||
painter.drawPixmap(0, y, pixmap->width(), pixmap->height(), *pixmap);
|
||||
|
||||
this->bufferValid = true;
|
||||
}
|
||||
|
||||
void MessageLayout::updateBuffer(QPixmap *buffer, int messageIndex, Selection &selection)
|
||||
{
|
||||
singletons::ThemeManager &themeManager = singletons::ThemeManager::getInstance();
|
||||
|
||||
QPainter painter(buffer);
|
||||
|
||||
painter.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||
|
||||
// draw background
|
||||
painter.fillRect(buffer->rect(),
|
||||
this->message->hasFlags(Message::Highlighted)
|
||||
? themeManager.messages.backgrounds.highlighted
|
||||
: themeManager.messages.backgrounds.regular);
|
||||
|
||||
// draw selection
|
||||
if (!selection.isEmpty()) {
|
||||
this->container.paintSelection(painter, messageIndex, selection);
|
||||
}
|
||||
|
||||
// draw message
|
||||
this->container.paintElements(painter);
|
||||
|
||||
// debug
|
||||
painter.setPen(QColor(255, 0, 0));
|
||||
painter.drawRect(buffer->rect().x(), buffer->rect().y(), buffer->rect().width() - 1,
|
||||
buffer->rect().height() - 1);
|
||||
|
||||
QTextOption option;
|
||||
option.setAlignment(Qt::AlignRight | Qt::AlignTop);
|
||||
|
||||
painter.drawText(QRectF(1, 1, this->container.width - 3, 1000),
|
||||
QString::number(++this->bufferUpdatedCount), option);
|
||||
}
|
||||
|
||||
void MessageLayout::invalidateBuffer()
|
||||
{
|
||||
this->bufferValid = false;
|
||||
}
|
||||
|
||||
void MessageLayout::deleteBuffer()
|
||||
{
|
||||
this->buffer = nullptr;
|
||||
}
|
||||
|
||||
// Elements
|
||||
// assert(QThread::currentThread() == QApplication::instance()->thread());
|
||||
|
||||
// returns nullptr if none was found
|
||||
|
||||
// fourtf: this should return a MessageLayoutItem
|
||||
const MessageLayoutElement *MessageLayout::getElementAt(QPoint point)
|
||||
{
|
||||
// go through all words and return the first one that contains the point.
|
||||
return this->container.getElementAt(point);
|
||||
}
|
||||
|
||||
// XXX(pajlada): This is probably not the optimal way to calculate this
|
||||
int MessageLayout::getLastCharacterIndex() const
|
||||
{
|
||||
// fourtf: xD
|
||||
// // find out in which line the cursor is
|
||||
// int lineNumber = 0, lineStart = 0, lineEnd = 0;
|
||||
|
||||
// for (size_t i = 0; i < this->wordParts.size(); i++) {
|
||||
// const LayoutItem &part = this->wordParts[i];
|
||||
|
||||
// if (part.getLineNumber() != lineNumber) {
|
||||
// lineStart = i;
|
||||
// lineNumber = part.getLineNumber();
|
||||
// }
|
||||
|
||||
// lineEnd = i + 1;
|
||||
// }
|
||||
|
||||
// // count up to the cursor
|
||||
// int index = 0;
|
||||
|
||||
// for (int i = 0; i < lineStart; i++) {
|
||||
// const LayoutItem &part = this->wordParts[i];
|
||||
|
||||
// index += part.getWord().isImage() ? 2 : part.getText().length() + 1;
|
||||
// }
|
||||
|
||||
// for (int i = lineStart; i < lineEnd; i++) {
|
||||
// const LayoutItem &part = this->wordParts[i];
|
||||
|
||||
// index += part.getCharacterLength();
|
||||
// }
|
||||
|
||||
// return index;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MessageLayout::getSelectionIndex(QPoint position)
|
||||
{
|
||||
// if (this->wordParts.size() == 0) {
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// // find out in which line the cursor is
|
||||
// int lineNumber = 0, lineStart = 0, lineEnd = 0;
|
||||
|
||||
// for (size_t i = 0; i < this->wordParts.size(); i++) {
|
||||
// LayoutItem &part = this->wordParts[i];
|
||||
|
||||
// if (part.getLineNumber() != 0 && position.y() < part.getY()) {
|
||||
// break;
|
||||
// }
|
||||
|
||||
// if (part.getLineNumber() != lineNumber) {
|
||||
// lineStart = i;
|
||||
// lineNumber = part.getLineNumber();
|
||||
// }
|
||||
|
||||
// lineEnd = i + 1;
|
||||
// }
|
||||
|
||||
// // count up to the cursor
|
||||
// int index = 0;
|
||||
|
||||
// for (int i = 0; i < lineStart; i++) {
|
||||
// LayoutItem &part = this->wordParts[i];
|
||||
|
||||
// index += part.getWord().isImage() ? 2 : part.getText().length() + 1;
|
||||
// }
|
||||
|
||||
// for (int i = lineStart; i < lineEnd; i++) {
|
||||
// LayoutItem &part = this->wordParts[i];
|
||||
|
||||
// // curser is left of the word part
|
||||
// if (position.x() < part.getX()) {
|
||||
// break;
|
||||
// }
|
||||
|
||||
// // cursor is right of the word part
|
||||
// if (position.x() > part.getX() + part.getWidth()) {
|
||||
// index += part.getCharacterLength();
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// // cursor is over the word part
|
||||
// if (part.getWord().isImage()) {
|
||||
// if (position.x() - part.getX() > part.getWidth() / 2) {
|
||||
// index++;
|
||||
// }
|
||||
// } else {
|
||||
// // TODO: use word.getCharacterWidthCache();
|
||||
|
||||
// auto text = part.getText();
|
||||
|
||||
// int x = part.getX();
|
||||
|
||||
// for (int j = 0; j < text.length(); j++) {
|
||||
// if (x > position.x()) {
|
||||
// break;
|
||||
// }
|
||||
|
||||
// index++;
|
||||
// x = part.getX() + part.getWord().getFontMetrics(this->scale).width(text, j +
|
||||
// 1);
|
||||
// }
|
||||
// }
|
||||
|
||||
// break;
|
||||
// }
|
||||
|
||||
// return index;
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace layouts
|
||||
} // namespace messages
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,83 @@
|
||||
#pragma once
|
||||
|
||||
#include "messages/layouts/messagelayoutcontainer.hpp"
|
||||
#include "messages/layouts/messagelayoutelement.hpp"
|
||||
#include "messages/message.hpp"
|
||||
#include "messages/selection.hpp"
|
||||
|
||||
#include <QPixmap>
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <cinttypes>
|
||||
#include <memory>
|
||||
|
||||
namespace chatterino {
|
||||
namespace messages {
|
||||
namespace layouts {
|
||||
|
||||
class MessageLayout;
|
||||
typedef std::shared_ptr<MessageLayout> MessageLayoutPtr;
|
||||
typedef uint8_t MessageLayoutFlagsType;
|
||||
|
||||
class MessageLayout : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
enum Flags : MessageLayoutFlagsType { Collapsed, RequiresBufferUpdate, RequiresLayout };
|
||||
|
||||
MessageLayout(MessagePtr message);
|
||||
|
||||
Message *getMessage();
|
||||
|
||||
// Height
|
||||
int getHeight() const;
|
||||
|
||||
// Flags
|
||||
Flags getFlags() const;
|
||||
bool hasFlags(Flags flags) const;
|
||||
void addFlags(Flags flags);
|
||||
void removeFlags(Flags flags);
|
||||
|
||||
// Layout
|
||||
bool layout(int width, float scale);
|
||||
|
||||
// Painting
|
||||
void paint(QPainter &painter, int y, int messageIndex, Selection &selection);
|
||||
void invalidateBuffer();
|
||||
void deleteBuffer();
|
||||
|
||||
// Elements
|
||||
const MessageLayoutElement *getElementAt(QPoint point);
|
||||
int getLastCharacterIndex() const;
|
||||
int getSelectionIndex(QPoint position);
|
||||
|
||||
// Misc
|
||||
bool isDisabled() const;
|
||||
|
||||
private:
|
||||
// variables
|
||||
MessagePtr message;
|
||||
MessageLayoutContainer container;
|
||||
std::shared_ptr<QPixmap> buffer = nullptr;
|
||||
bool bufferValid = false;
|
||||
Flags flags;
|
||||
|
||||
int height = 0;
|
||||
|
||||
int currentLayoutWidth = -1;
|
||||
int fontGeneration = -1;
|
||||
int emoteGeneration = -1;
|
||||
float scale = -1;
|
||||
unsigned int bufferUpdatedCount = 0;
|
||||
|
||||
MessageElement::Flags currentWordTypes = MessageElement::None;
|
||||
|
||||
int collapsedHeight = 32;
|
||||
|
||||
// methods
|
||||
void actuallyLayout(int width);
|
||||
void updateBuffer(QPixmap *pixmap, int messageIndex, Selection &selection);
|
||||
};
|
||||
|
||||
} // namespace layouts
|
||||
} // namespace messages
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,157 @@
|
||||
#include "messagelayoutcontainer.hpp"
|
||||
|
||||
#include "messagelayoutelement.hpp"
|
||||
#include "messages/selection.hpp"
|
||||
#include "singletons/settingsmanager.hpp"
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
#define COMPACT_EMOTES_OFFSET 6
|
||||
|
||||
namespace chatterino {
|
||||
namespace messages {
|
||||
namespace layouts {
|
||||
MessageLayoutContainer::MessageLayoutContainer()
|
||||
: scale(1)
|
||||
, margin(4, 8, 4, 8)
|
||||
, centered(false)
|
||||
{
|
||||
this->clear();
|
||||
}
|
||||
|
||||
int MessageLayoutContainer::getHeight() const
|
||||
{
|
||||
return this->height;
|
||||
}
|
||||
|
||||
// methods
|
||||
void MessageLayoutContainer::clear()
|
||||
{
|
||||
this->elements.clear();
|
||||
|
||||
this->height = 0;
|
||||
this->line = 0;
|
||||
this->currentX = 0;
|
||||
this->currentY = 0;
|
||||
this->lineStart = 0;
|
||||
this->lineHeight = 0;
|
||||
}
|
||||
|
||||
void MessageLayoutContainer::addElement(MessageLayoutElement *element)
|
||||
{
|
||||
if (!this->fitsInLine(element->getRect().width())) {
|
||||
this->breakLine();
|
||||
}
|
||||
|
||||
this->_addElement(element);
|
||||
}
|
||||
|
||||
void MessageLayoutContainer::addElementNoLineBreak(MessageLayoutElement *element)
|
||||
{
|
||||
this->_addElement(element);
|
||||
}
|
||||
|
||||
void MessageLayoutContainer::_addElement(MessageLayoutElement *element)
|
||||
{
|
||||
if (this->elements.size() == 0) {
|
||||
this->currentY = this->margin.top * this->scale;
|
||||
}
|
||||
|
||||
int newLineHeight = element->getRect().height();
|
||||
|
||||
// fourtf: xD
|
||||
// bool compactEmotes = true;
|
||||
// if (compactEmotes && element->word.isImage() && word.getFlags() &
|
||||
// MessageElement::EmoteImages) {
|
||||
// newLineHeight -= COMPACT_EMOTES_OFFSET * this->scale;
|
||||
// }
|
||||
|
||||
this->lineHeight = std::max(this->lineHeight, newLineHeight);
|
||||
|
||||
element->setPosition(QPoint(this->currentX, this->currentY - element->getRect().height()));
|
||||
this->elements.push_back(std::unique_ptr<MessageLayoutElement>(element));
|
||||
|
||||
this->currentX += element->getRect().width();
|
||||
|
||||
if (element->hasTrailingSpace()) {
|
||||
this->currentX += this->spaceWidth;
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLayoutContainer::breakLine()
|
||||
{
|
||||
int xOffset = 0;
|
||||
|
||||
if (this->centered && this->elements.size() > 0) {
|
||||
xOffset = (width - this->elements.at(this->elements.size() - 1)->getRect().right()) / 2;
|
||||
}
|
||||
|
||||
for (size_t i = lineStart; i < this->elements.size(); i++) {
|
||||
MessageLayoutElement *element = this->elements.at(i).get();
|
||||
|
||||
bool isCompactEmote = false;
|
||||
|
||||
// fourtf: xD
|
||||
// this->enableCompactEmotes && element->getWord().isImage() &&
|
||||
// element->getWord().getFlags() &
|
||||
// MessageElement::EmoteImages;
|
||||
|
||||
int yExtra = 0;
|
||||
if (isCompactEmote) {
|
||||
yExtra = (COMPACT_EMOTES_OFFSET / 2) * this->scale;
|
||||
}
|
||||
|
||||
element->setPosition(QPoint(element->getRect().x() + xOffset + this->margin.left,
|
||||
element->getRect().y() + this->lineHeight + yExtra));
|
||||
}
|
||||
|
||||
this->lineStart = this->elements.size();
|
||||
this->currentX = 0;
|
||||
this->currentY += this->lineHeight;
|
||||
this->height = this->currentY + (this->margin.bottom * this->scale);
|
||||
this->lineHeight = 0;
|
||||
}
|
||||
|
||||
bool MessageLayoutContainer::atStartOfLine()
|
||||
{
|
||||
return this->lineStart == this->elements.size();
|
||||
}
|
||||
|
||||
bool MessageLayoutContainer::fitsInLine(int _width)
|
||||
{
|
||||
return this->currentX + _width <= this->width - this->margin.left - this->margin.right;
|
||||
}
|
||||
|
||||
void MessageLayoutContainer::finish()
|
||||
{
|
||||
if (!this->atStartOfLine()) {
|
||||
this->breakLine();
|
||||
}
|
||||
}
|
||||
|
||||
MessageLayoutElement *MessageLayoutContainer::getElementAt(QPoint point)
|
||||
{
|
||||
for (std::unique_ptr<MessageLayoutElement> &element : this->elements) {
|
||||
if (element->getRect().contains(point)) {
|
||||
return element.get();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// painting
|
||||
void MessageLayoutContainer::paintElements(QPainter &painter)
|
||||
{
|
||||
for (const std::unique_ptr<MessageLayoutElement> &element : this->elements) {
|
||||
element->paint(painter);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLayoutContainer::paintSelection(QPainter &painter, int messageIndex,
|
||||
Selection &selection)
|
||||
{
|
||||
}
|
||||
} // namespace layouts
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <QPoint>
|
||||
|
||||
class QPainter;
|
||||
|
||||
namespace chatterino {
|
||||
namespace messages {
|
||||
class Selection;
|
||||
|
||||
namespace layouts {
|
||||
class MessageLayoutElement;
|
||||
|
||||
struct Margin {
|
||||
int top;
|
||||
int right;
|
||||
int bottom;
|
||||
int left;
|
||||
|
||||
Margin()
|
||||
: Margin(0)
|
||||
{
|
||||
}
|
||||
|
||||
Margin(int value)
|
||||
: Margin(value, value, value, value)
|
||||
{
|
||||
}
|
||||
|
||||
Margin(int _top, int _right, int _bottom, int _left)
|
||||
: top(_top)
|
||||
, right(_right)
|
||||
, bottom(_bottom)
|
||||
, left(_left)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class MessageLayoutContainer
|
||||
{
|
||||
public:
|
||||
MessageLayoutContainer();
|
||||
|
||||
float scale;
|
||||
Margin margin;
|
||||
bool centered;
|
||||
bool enableCompactEmotes;
|
||||
int width;
|
||||
|
||||
int getHeight() const;
|
||||
|
||||
// methods
|
||||
void clear();
|
||||
void addElement(MessageLayoutElement *element);
|
||||
void addElementNoLineBreak(MessageLayoutElement *element);
|
||||
void breakLine();
|
||||
bool atStartOfLine();
|
||||
bool fitsInLine(int width);
|
||||
void finish();
|
||||
MessageLayoutElement *getElementAt(QPoint point);
|
||||
|
||||
// painting
|
||||
void paintElements(QPainter &painter);
|
||||
void paintSelection(QPainter &painter, int messageIndex, Selection &selection);
|
||||
|
||||
private:
|
||||
// helpers
|
||||
void _addElement(MessageLayoutElement *element);
|
||||
|
||||
// variables
|
||||
int line;
|
||||
int height;
|
||||
int currentX, currentY;
|
||||
size_t lineStart = 0;
|
||||
int lineHeight = 0;
|
||||
int spaceWidth = 4;
|
||||
std::vector<std::unique_ptr<MessageLayoutElement>> elements;
|
||||
};
|
||||
} // namespace layouts
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
#include "messages/layouts/messagelayoutelement.hpp"
|
||||
#include "messages/messageelement.hpp"
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
namespace chatterino {
|
||||
namespace messages {
|
||||
namespace layouts {
|
||||
|
||||
const QRect &MessageLayoutElement::getRect() const
|
||||
{
|
||||
return this->rect;
|
||||
}
|
||||
|
||||
MessageLayoutElement::MessageLayoutElement(MessageElement &_creator, const QSize &size)
|
||||
: creator(_creator)
|
||||
{
|
||||
this->rect.setSize(size);
|
||||
}
|
||||
|
||||
MessageElement &MessageLayoutElement::getCreator() const
|
||||
{
|
||||
return this->creator;
|
||||
}
|
||||
|
||||
void MessageLayoutElement::setPosition(QPoint point)
|
||||
{
|
||||
this->rect.moveTopLeft(point);
|
||||
}
|
||||
|
||||
bool MessageLayoutElement::hasTrailingSpace() const
|
||||
{
|
||||
return this->trailingSpace;
|
||||
}
|
||||
|
||||
MessageLayoutElement *MessageLayoutElement::setTrailingSpace(bool value)
|
||||
{
|
||||
this->trailingSpace = value;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
//
|
||||
// IMAGE
|
||||
//
|
||||
|
||||
ImageLayoutElement::ImageLayoutElement(MessageElement &_creator, Image &_image, QSize _size)
|
||||
: MessageLayoutElement(_creator, _size)
|
||||
, image(_image)
|
||||
{
|
||||
this->trailingSpace = _creator.hasTrailingSpace();
|
||||
}
|
||||
|
||||
void ImageLayoutElement::addCopyTextToString(QString &str, int from, int to) const
|
||||
{
|
||||
str += "<image>";
|
||||
}
|
||||
|
||||
int ImageLayoutElement::getSelectionIndexCount()
|
||||
{
|
||||
return this->trailingSpace ? 2 : 1;
|
||||
}
|
||||
|
||||
void ImageLayoutElement::paint(QPainter &painter)
|
||||
{
|
||||
const QPixmap *pixmap = this->image.getPixmap();
|
||||
|
||||
if (pixmap != nullptr && !this->image.isAnimated()) {
|
||||
// fourtf: make it use qreal values
|
||||
painter.drawPixmap(QRectF(this->getRect()), *pixmap, QRectF());
|
||||
}
|
||||
}
|
||||
|
||||
void ImageLayoutElement::paintAnimated(QPainter &painter)
|
||||
{
|
||||
if (this->image.isAnimated()) {
|
||||
if (this->image.getPixmap() != nullptr) {
|
||||
// fourtf: make it use qreal values
|
||||
painter.drawPixmap(QRectF(this->getRect()), *this->image.getPixmap(), QRectF());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ImageLayoutElement::getMouseOverIndex(const QPoint &abs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// TEXT
|
||||
//
|
||||
|
||||
TextLayoutElement::TextLayoutElement(MessageElement &_creator, QString &_text, QSize _size,
|
||||
QColor _color, FontStyle _style, float _scale)
|
||||
: MessageLayoutElement(_creator, _size)
|
||||
, text(_text)
|
||||
, color(_color)
|
||||
, style(_style)
|
||||
, scale(_scale)
|
||||
{
|
||||
}
|
||||
|
||||
void TextLayoutElement::addCopyTextToString(QString &str, int from, int to) const
|
||||
{
|
||||
}
|
||||
|
||||
int TextLayoutElement::getSelectionIndexCount()
|
||||
{
|
||||
return this->text.length() + (this->trailingSpace ? 1 : 0);
|
||||
}
|
||||
|
||||
void TextLayoutElement::paint(QPainter &painter)
|
||||
{
|
||||
painter.setPen(this->color);
|
||||
|
||||
painter.setFont(singletons::FontManager::getInstance().getFont(this->style, this->scale));
|
||||
|
||||
painter.drawText(QRectF(this->getRect().x(), this->getRect().y(), 10000, 10000), this->text,
|
||||
QTextOption(Qt::AlignLeft | Qt::AlignTop));
|
||||
}
|
||||
|
||||
void TextLayoutElement::paintAnimated(QPainter &painter)
|
||||
{
|
||||
}
|
||||
|
||||
int TextLayoutElement::getMouseOverIndex(const QPoint &abs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
} // namespace layouts
|
||||
} // namespace messages
|
||||
} // namespace chatterino
|
||||
@@ -0,0 +1,88 @@
|
||||
#pragma once
|
||||
|
||||
#include <QPoint>
|
||||
#include <QRect>
|
||||
#include <QString>
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <climits>
|
||||
|
||||
#include "messages/messagecolor.hpp"
|
||||
#include "singletons/fontmanager.hpp"
|
||||
|
||||
class QPainter;
|
||||
|
||||
namespace chatterino {
|
||||
namespace messages {
|
||||
class MessageElement;
|
||||
class Image;
|
||||
|
||||
namespace layouts {
|
||||
|
||||
class MessageLayoutElement : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
MessageLayoutElement(MessageElement &creator, const QSize &size);
|
||||
|
||||
const QRect &getRect() const;
|
||||
MessageElement &getCreator() const;
|
||||
void setPosition(QPoint point);
|
||||
bool hasTrailingSpace() const;
|
||||
|
||||
MessageLayoutElement *setTrailingSpace(bool value);
|
||||
|
||||
virtual void addCopyTextToString(QString &str, int from = 0, int to = INT_MAX) const = 0;
|
||||
virtual int getSelectionIndexCount() = 0;
|
||||
virtual void paint(QPainter &painter) = 0;
|
||||
virtual void paintAnimated(QPainter &painter) = 0;
|
||||
virtual int getMouseOverIndex(const QPoint &abs) = 0;
|
||||
|
||||
protected:
|
||||
bool trailingSpace = true;
|
||||
|
||||
private:
|
||||
QRect rect;
|
||||
// bool isInNewLine;
|
||||
MessageElement &creator;
|
||||
};
|
||||
|
||||
// IMAGE
|
||||
class ImageLayoutElement : public MessageLayoutElement
|
||||
{
|
||||
public:
|
||||
ImageLayoutElement(MessageElement &creator, Image &image, QSize size);
|
||||
|
||||
protected:
|
||||
virtual void addCopyTextToString(QString &str, int from = 0, int to = INT_MAX) const override;
|
||||
virtual int getSelectionIndexCount() override;
|
||||
virtual void paint(QPainter &painter) override;
|
||||
virtual void paintAnimated(QPainter &painter) override;
|
||||
virtual int getMouseOverIndex(const QPoint &abs) override;
|
||||
|
||||
private:
|
||||
Image ℑ
|
||||
};
|
||||
|
||||
// TEXT
|
||||
class TextLayoutElement : public MessageLayoutElement
|
||||
{
|
||||
public:
|
||||
TextLayoutElement(MessageElement &creator, QString &text, QSize size, QColor color,
|
||||
FontStyle style, float scale);
|
||||
|
||||
protected:
|
||||
virtual void addCopyTextToString(QString &str, int from = 0, int to = INT_MAX) const override;
|
||||
virtual int getSelectionIndexCount() override;
|
||||
virtual void paint(QPainter &painter) override;
|
||||
virtual void paintAnimated(QPainter &painter) override;
|
||||
virtual int getMouseOverIndex(const QPoint &abs) override;
|
||||
|
||||
private:
|
||||
QString text;
|
||||
QColor color;
|
||||
FontStyle style;
|
||||
float scale;
|
||||
};
|
||||
} // namespace layouts
|
||||
} // namespace messages
|
||||
} // namespace chatterino
|
||||
Reference in New Issue
Block a user