2018-06-26 14:09:39 +02:00
|
|
|
#include "MessageLayoutContainer.hpp"
|
2018-01-11 20:16:25 +01:00
|
|
|
|
2018-06-26 14:09:39 +02:00
|
|
|
#include "Application.hpp"
|
2018-08-11 22:23:06 +02:00
|
|
|
#include "messages/Message.hpp"
|
|
|
|
#include "messages/MessageElement.hpp"
|
2018-06-26 14:09:39 +02:00
|
|
|
#include "messages/Selection.hpp"
|
2018-08-11 22:23:06 +02:00
|
|
|
#include "messages/layouts/MessageLayoutElement.hpp"
|
|
|
|
#include "singletons/Fonts.hpp"
|
2018-06-28 19:46:45 +02:00
|
|
|
#include "singletons/Settings.hpp"
|
2018-08-11 22:23:06 +02:00
|
|
|
#include "singletons/Theme.hpp"
|
2018-01-11 20:16:25 +01:00
|
|
|
|
2018-01-15 04:08:48 +01:00
|
|
|
#include <QDebug>
|
2018-01-11 20:16:25 +01:00
|
|
|
#include <QPainter>
|
|
|
|
|
|
|
|
#define COMPACT_EMOTES_OFFSET 6
|
2018-08-06 21:17:03 +02:00
|
|
|
#define MAX_UNCOLLAPSED_LINES \
|
2018-08-12 12:56:28 +02:00
|
|
|
(getSettings()->collpseMessagesMinLines.getValue())
|
2018-01-11 20:16:25 +01:00
|
|
|
|
|
|
|
namespace chatterino {
|
|
|
|
|
|
|
|
int MessageLayoutContainer::getHeight() const
|
|
|
|
{
|
2018-07-06 19:23:47 +02:00
|
|
|
return this->height_;
|
2018-01-11 20:16:25 +01:00
|
|
|
}
|
|
|
|
|
2018-01-28 16:29:47 +01:00
|
|
|
int MessageLayoutContainer::getWidth() const
|
|
|
|
{
|
2018-07-06 19:23:47 +02:00
|
|
|
return this->width_;
|
2018-01-28 16:29:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
float MessageLayoutContainer::getScale() const
|
|
|
|
{
|
2018-07-06 19:23:47 +02:00
|
|
|
return this->scale_;
|
2018-01-28 16:29:47 +01:00
|
|
|
}
|
|
|
|
|
2018-01-11 20:16:25 +01:00
|
|
|
// methods
|
2018-08-07 07:55:31 +02:00
|
|
|
void MessageLayoutContainer::begin(int width, float scale, MessageFlags flags)
|
2018-01-28 16:29:47 +01:00
|
|
|
{
|
|
|
|
this->clear();
|
2018-07-06 19:23:47 +02:00
|
|
|
this->width_ = width;
|
|
|
|
this->scale_ = scale;
|
|
|
|
this->flags_ = flags;
|
2018-08-06 21:17:03 +02:00
|
|
|
auto mediumFontMetrics =
|
|
|
|
getApp()->fonts->getFontMetrics(FontStyle::ChatMedium, scale);
|
2018-07-06 19:23:47 +02:00
|
|
|
this->textLineHeight_ = mediumFontMetrics.height();
|
|
|
|
this->spaceWidth_ = mediumFontMetrics.width(' ');
|
|
|
|
this->dotdotdotWidth_ = mediumFontMetrics.width("...");
|
|
|
|
this->canAddMessages_ = true;
|
|
|
|
this->isCollapsed_ = false;
|
2018-01-28 16:29:47 +01:00
|
|
|
}
|
|
|
|
|
2018-01-11 20:16:25 +01:00
|
|
|
void MessageLayoutContainer::clear()
|
|
|
|
{
|
2018-07-06 19:23:47 +02:00
|
|
|
this->elements_.clear();
|
|
|
|
this->lines_.clear();
|
|
|
|
|
|
|
|
this->height_ = 0;
|
|
|
|
this->line_ = 0;
|
|
|
|
this->currentX_ = 0;
|
|
|
|
this->currentY_ = 0;
|
|
|
|
this->lineStart_ = 0;
|
|
|
|
this->lineHeight_ = 0;
|
|
|
|
this->charIndex_ = 0;
|
2018-01-11 20:16:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void MessageLayoutContainer::addElement(MessageLayoutElement *element)
|
|
|
|
{
|
|
|
|
if (!this->fitsInLine(element->getRect().width())) {
|
|
|
|
this->breakLine();
|
|
|
|
}
|
|
|
|
|
|
|
|
this->_addElement(element);
|
|
|
|
}
|
|
|
|
|
2018-08-06 21:17:03 +02:00
|
|
|
void MessageLayoutContainer::addElementNoLineBreak(
|
|
|
|
MessageLayoutElement *element)
|
2018-01-11 20:16:25 +01:00
|
|
|
{
|
|
|
|
this->_addElement(element);
|
|
|
|
}
|
|
|
|
|
2018-04-18 09:12:29 +02:00
|
|
|
bool MessageLayoutContainer::canAddElements()
|
|
|
|
{
|
2018-07-06 19:23:47 +02:00
|
|
|
return this->canAddMessages_;
|
2018-04-18 09:12:29 +02:00
|
|
|
}
|
|
|
|
|
2018-08-06 21:17:03 +02:00
|
|
|
void MessageLayoutContainer::_addElement(MessageLayoutElement *element,
|
|
|
|
bool forceAdd)
|
2018-01-11 20:16:25 +01:00
|
|
|
{
|
2018-05-24 11:35:50 +02:00
|
|
|
if (!this->canAddElements() && !forceAdd) {
|
2018-04-18 09:12:29 +02:00
|
|
|
delete element;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-01-28 16:29:47 +01:00
|
|
|
// top margin
|
2018-07-06 19:23:47 +02:00
|
|
|
if (this->elements_.size() == 0) {
|
|
|
|
this->currentY_ = this->margin.top * this->scale_;
|
2018-01-11 20:16:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int newLineHeight = element->getRect().height();
|
|
|
|
|
2018-01-28 16:29:47 +01:00
|
|
|
// compact emote offset
|
2018-08-06 21:17:03 +02:00
|
|
|
bool isCompactEmote =
|
2018-08-07 07:55:31 +02:00
|
|
|
!this->flags_.has(MessageFlag::DisableCompactEmotes) &&
|
|
|
|
element->getCreator().getFlags().has(MessageElementFlag::EmoteImages);
|
2018-01-11 20:16:25 +01:00
|
|
|
|
2018-01-28 16:29:47 +01:00
|
|
|
if (isCompactEmote) {
|
2018-07-06 19:23:47 +02:00
|
|
|
newLineHeight -= COMPACT_EMOTES_OFFSET * this->scale_;
|
2018-01-28 16:29:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// update line height
|
2018-07-06 19:23:47 +02:00
|
|
|
this->lineHeight_ = std::max(this->lineHeight_, newLineHeight);
|
2018-01-11 20:16:25 +01:00
|
|
|
|
2018-01-28 16:29:47 +01:00
|
|
|
// set move element
|
2018-08-06 21:17:03 +02:00
|
|
|
element->setPosition(
|
|
|
|
QPoint(this->currentX_, this->currentY_ - element->getRect().height()));
|
2018-01-28 16:29:47 +01:00
|
|
|
|
|
|
|
// add element
|
2018-07-06 19:23:47 +02:00
|
|
|
this->elements_.push_back(std::unique_ptr<MessageLayoutElement>(element));
|
2018-01-11 20:16:25 +01:00
|
|
|
|
2018-01-28 16:29:47 +01:00
|
|
|
// set current x
|
2018-07-06 19:23:47 +02:00
|
|
|
this->currentX_ += element->getRect().width();
|
2018-01-11 20:16:25 +01:00
|
|
|
|
|
|
|
if (element->hasTrailingSpace()) {
|
2018-07-06 19:23:47 +02:00
|
|
|
this->currentX_ += this->spaceWidth_;
|
2018-01-11 20:16:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MessageLayoutContainer::breakLine()
|
|
|
|
{
|
|
|
|
int xOffset = 0;
|
|
|
|
|
2018-08-07 07:55:31 +02:00
|
|
|
if (this->flags_.has(MessageFlag::Centered) && this->elements_.size() > 0) {
|
2018-08-11 14:20:53 +02:00
|
|
|
xOffset = (width_ - this->elements_.at(0)->getRect().left() -
|
|
|
|
this->elements_.at(this->elements_.size() - 1)
|
|
|
|
->getRect()
|
|
|
|
.right()) /
|
2018-08-06 21:17:03 +02:00
|
|
|
2;
|
2018-01-11 20:16:25 +01:00
|
|
|
}
|
|
|
|
|
2018-07-06 19:23:47 +02:00
|
|
|
for (size_t i = lineStart_; i < this->elements_.size(); i++) {
|
|
|
|
MessageLayoutElement *element = this->elements_.at(i).get();
|
2018-01-11 20:16:25 +01:00
|
|
|
|
2018-08-06 21:17:03 +02:00
|
|
|
bool isCompactEmote =
|
2018-08-07 07:55:31 +02:00
|
|
|
!this->flags_.has(MessageFlag::DisableCompactEmotes) &&
|
|
|
|
element->getCreator().getFlags().has(
|
|
|
|
MessageElementFlag::EmoteImages);
|
2018-01-11 20:16:25 +01:00
|
|
|
|
|
|
|
int yExtra = 0;
|
|
|
|
if (isCompactEmote) {
|
2018-07-06 19:23:47 +02:00
|
|
|
yExtra = (COMPACT_EMOTES_OFFSET / 2) * this->scale_;
|
2018-01-11 20:16:25 +01:00
|
|
|
}
|
|
|
|
|
2018-08-07 07:55:31 +02:00
|
|
|
// if (element->getCreator().getFlags() &
|
|
|
|
// MessageElementFlag::Badges)
|
2018-08-06 21:17:03 +02:00
|
|
|
// {
|
2018-07-06 19:23:47 +02:00
|
|
|
if (element->getRect().height() < this->textLineHeight_) {
|
|
|
|
yExtra -= (this->textLineHeight_ - element->getRect().height()) / 2;
|
2018-05-23 13:31:55 +02:00
|
|
|
}
|
|
|
|
|
2018-08-06 21:17:03 +02:00
|
|
|
element->setPosition(
|
|
|
|
QPoint(element->getRect().x() + xOffset + this->margin.left,
|
|
|
|
element->getRect().y() + this->lineHeight_ + yExtra));
|
2018-01-11 20:16:25 +01:00
|
|
|
}
|
|
|
|
|
2018-07-06 19:23:47 +02:00
|
|
|
if (this->lines_.size() != 0) {
|
|
|
|
this->lines_.back().endIndex = this->lineStart_;
|
|
|
|
this->lines_.back().endCharIndex = this->charIndex_;
|
2018-01-16 00:26:04 +01:00
|
|
|
}
|
2018-08-06 21:17:03 +02:00
|
|
|
this->lines_.push_back(
|
|
|
|
{(int)lineStart_, 0, this->charIndex_, 0,
|
|
|
|
QRect(-100000, this->currentY_, 200000, lineHeight_)});
|
2018-01-16 00:26:04 +01:00
|
|
|
|
2018-07-06 19:23:47 +02:00
|
|
|
for (int i = this->lineStart_; i < this->elements_.size(); i++) {
|
|
|
|
this->charIndex_ += this->elements_[i]->getSelectionIndexCount();
|
2018-01-16 00:26:04 +01:00
|
|
|
}
|
2018-01-15 04:08:48 +01:00
|
|
|
|
2018-07-06 19:23:47 +02:00
|
|
|
this->lineStart_ = this->elements_.size();
|
2018-04-10 15:48:56 +02:00
|
|
|
// this->currentX = (int)(this->scale * 8);
|
2018-05-24 11:35:50 +02:00
|
|
|
|
2018-07-06 19:23:47 +02:00
|
|
|
if (this->canCollapse() && line_ + 1 >= MAX_UNCOLLAPSED_LINES) {
|
|
|
|
this->canAddMessages_ = false;
|
2018-05-24 11:35:50 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-07-06 19:23:47 +02:00
|
|
|
this->currentX_ = 0;
|
|
|
|
this->currentY_ += this->lineHeight_;
|
|
|
|
this->height_ = this->currentY_ + (this->margin.bottom * this->scale_);
|
|
|
|
this->lineHeight_ = 0;
|
|
|
|
this->line_++;
|
2018-05-24 11:35:50 +02:00
|
|
|
}
|
2018-01-11 20:16:25 +01:00
|
|
|
|
|
|
|
bool MessageLayoutContainer::atStartOfLine()
|
|
|
|
{
|
2018-07-06 19:23:47 +02:00
|
|
|
return this->lineStart_ == this->elements_.size();
|
2018-01-11 20:16:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool MessageLayoutContainer::fitsInLine(int _width)
|
|
|
|
{
|
2018-07-06 19:23:47 +02:00
|
|
|
return this->currentX_ + _width <=
|
|
|
|
(this->width_ - this->margin.left - this->margin.right -
|
2018-08-06 21:17:03 +02:00
|
|
|
(this->line_ + 1 == MAX_UNCOLLAPSED_LINES ? this->dotdotdotWidth_
|
|
|
|
: 0));
|
2018-01-11 20:16:25 +01:00
|
|
|
}
|
|
|
|
|
2018-04-01 16:41:32 +02:00
|
|
|
void MessageLayoutContainer::end()
|
2018-01-11 20:16:25 +01:00
|
|
|
{
|
2018-05-24 11:35:50 +02:00
|
|
|
if (!this->canAddElements()) {
|
2018-08-07 07:55:31 +02:00
|
|
|
static TextElement dotdotdot("...", MessageElementFlag::Collapsed,
|
2018-08-06 21:17:03 +02:00
|
|
|
MessageColor::Link);
|
2018-05-24 11:35:50 +02:00
|
|
|
static QString dotdotdotText("...");
|
|
|
|
|
|
|
|
auto *element = new TextLayoutElement(
|
2018-08-06 21:17:03 +02:00
|
|
|
dotdotdot, dotdotdotText,
|
|
|
|
QSize(this->dotdotdotWidth_, this->textLineHeight_),
|
2018-07-06 19:23:47 +02:00
|
|
|
QColor("#00D80A"), FontStyle::ChatMediumBold, this->scale_);
|
2018-05-24 11:35:50 +02:00
|
|
|
|
|
|
|
// getApp()->themes->messages.textColors.system
|
|
|
|
this->_addElement(element, true);
|
2018-07-06 19:23:47 +02:00
|
|
|
this->isCollapsed_ = true;
|
2018-05-24 11:35:50 +02:00
|
|
|
}
|
|
|
|
|
2018-01-11 20:16:25 +01:00
|
|
|
if (!this->atStartOfLine()) {
|
|
|
|
this->breakLine();
|
|
|
|
}
|
2018-01-15 04:08:48 +01:00
|
|
|
|
2018-07-06 19:23:47 +02:00
|
|
|
this->height_ += this->lineHeight_;
|
2018-05-24 11:35:50 +02:00
|
|
|
|
2018-07-06 19:23:47 +02:00
|
|
|
if (this->lines_.size() != 0) {
|
|
|
|
this->lines_[0].rect.setTop(-100000);
|
|
|
|
this->lines_.back().rect.setBottom(100000);
|
|
|
|
this->lines_.back().endIndex = this->elements_.size();
|
|
|
|
this->lines_.back().endCharIndex = this->charIndex_;
|
2018-01-15 04:08:48 +01:00
|
|
|
}
|
2018-01-11 20:16:25 +01:00
|
|
|
}
|
|
|
|
|
2018-05-24 11:35:50 +02:00
|
|
|
bool MessageLayoutContainer::canCollapse()
|
|
|
|
{
|
2018-08-12 12:56:28 +02:00
|
|
|
return getSettings()->collpseMessagesMinLines.getValue() > 0 &&
|
2018-08-07 07:55:31 +02:00
|
|
|
this->flags_.has(MessageFlag::Collapsed);
|
2018-05-24 11:35:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool MessageLayoutContainer::isCollapsed()
|
|
|
|
{
|
2018-07-06 19:23:47 +02:00
|
|
|
return this->isCollapsed_;
|
2018-05-24 11:35:50 +02:00
|
|
|
}
|
|
|
|
|
2018-01-11 20:16:25 +01:00
|
|
|
MessageLayoutElement *MessageLayoutContainer::getElementAt(QPoint point)
|
|
|
|
{
|
2018-07-06 19:23:47 +02:00
|
|
|
for (std::unique_ptr<MessageLayoutElement> &element : this->elements_) {
|
2018-01-11 20:16:25 +01:00
|
|
|
if (element->getRect().contains(point)) {
|
|
|
|
return element.get();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// painting
|
|
|
|
void MessageLayoutContainer::paintElements(QPainter &painter)
|
|
|
|
{
|
2018-08-06 21:17:03 +02:00
|
|
|
for (const std::unique_ptr<MessageLayoutElement> &element :
|
|
|
|
this->elements_) {
|
2018-04-25 14:49:30 +02:00
|
|
|
#ifdef FOURTF
|
2018-04-10 02:42:41 +02:00
|
|
|
painter.setPen(QColor(0, 255, 0));
|
|
|
|
painter.drawRect(element->getRect());
|
|
|
|
#endif
|
|
|
|
|
2018-01-11 20:16:25 +01:00
|
|
|
element->paint(painter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-06 21:17:03 +02:00
|
|
|
void MessageLayoutContainer::paintAnimatedElements(QPainter &painter,
|
|
|
|
int yOffset)
|
2018-01-13 02:13:59 +01:00
|
|
|
{
|
2018-08-06 21:17:03 +02:00
|
|
|
for (const std::unique_ptr<MessageLayoutElement> &element :
|
|
|
|
this->elements_) {
|
2018-01-13 02:13:59 +01:00
|
|
|
element->paintAnimated(painter, yOffset);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-11 20:16:25 +01:00
|
|
|
void MessageLayoutContainer::paintSelection(QPainter &painter, int messageIndex,
|
2018-04-10 03:29:00 +02:00
|
|
|
Selection &selection, int yOffset)
|
2018-01-11 20:16:25 +01:00
|
|
|
{
|
2018-04-27 22:11:19 +02:00
|
|
|
auto app = getApp();
|
|
|
|
QColor selectionColor = app->themes->messages.selection;
|
2018-01-16 00:34:32 +01:00
|
|
|
|
2018-01-16 00:26:04 +01:00
|
|
|
// don't draw anything
|
2018-04-25 14:49:30 +02:00
|
|
|
if (selection.selectionMin.messageIndex > messageIndex ||
|
|
|
|
selection.selectionMax.messageIndex < messageIndex) {
|
2018-01-16 00:26:04 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// fully selected
|
2018-04-25 14:49:30 +02:00
|
|
|
if (selection.selectionMin.messageIndex < messageIndex &&
|
|
|
|
selection.selectionMax.messageIndex > messageIndex) {
|
2018-07-06 19:23:47 +02:00
|
|
|
for (Line &line : this->lines_) {
|
2018-01-16 00:26:04 +01:00
|
|
|
QRect rect = line.rect;
|
|
|
|
|
2018-04-10 03:29:00 +02:00
|
|
|
rect.setTop(std::max(0, rect.top()) + yOffset);
|
2018-07-06 19:23:47 +02:00
|
|
|
rect.setBottom(std::min(this->height_, rect.bottom()) + yOffset);
|
|
|
|
rect.setLeft(this->elements_[line.startIndex]->getRect().left());
|
2018-08-06 21:17:03 +02:00
|
|
|
rect.setRight(
|
|
|
|
this->elements_[line.endIndex - 1]->getRect().right());
|
2018-01-16 00:26:04 +01:00
|
|
|
|
2018-01-16 00:34:32 +01:00
|
|
|
painter.fillRect(rect, selectionColor);
|
2018-01-16 00:26:04 +01:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int lineIndex = 0;
|
|
|
|
int index = 0;
|
|
|
|
|
|
|
|
// start in this message
|
2018-04-15 15:09:31 +02:00
|
|
|
if (selection.selectionMin.messageIndex == messageIndex) {
|
2018-07-06 19:23:47 +02:00
|
|
|
for (; lineIndex < this->lines_.size(); lineIndex++) {
|
|
|
|
Line &line = this->lines_[lineIndex];
|
2018-01-16 00:26:04 +01:00
|
|
|
index = line.startCharIndex;
|
|
|
|
|
|
|
|
bool returnAfter = false;
|
|
|
|
bool breakAfter = false;
|
2018-07-06 19:23:47 +02:00
|
|
|
int x = this->elements_[line.startIndex]->getRect().left();
|
|
|
|
int r = this->elements_[line.endIndex - 1]->getRect().right();
|
2018-01-16 00:26:04 +01:00
|
|
|
|
2018-09-30 20:02:07 +02:00
|
|
|
if (line.endCharIndex <= selection.selectionMin.charIndex) {
|
2018-01-16 00:26:04 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = line.startIndex; i < line.endIndex; i++) {
|
2018-07-06 19:23:47 +02:00
|
|
|
int c = this->elements_[i]->getSelectionIndexCount();
|
2018-01-16 00:26:04 +01:00
|
|
|
|
2018-04-15 15:09:31 +02:00
|
|
|
if (index + c > selection.selectionMin.charIndex) {
|
2018-08-06 21:17:03 +02:00
|
|
|
x = this->elements_[i]->getXFromIndex(
|
|
|
|
selection.selectionMin.charIndex - index);
|
2018-01-16 00:26:04 +01:00
|
|
|
|
|
|
|
// ends in same line
|
2018-04-15 15:09:31 +02:00
|
|
|
if (selection.selectionMax.messageIndex == messageIndex &&
|
2018-08-06 21:17:03 +02:00
|
|
|
line.endCharIndex >
|
|
|
|
/*=*/selection.selectionMax.charIndex) //
|
2018-01-16 00:26:04 +01:00
|
|
|
{
|
|
|
|
returnAfter = true;
|
|
|
|
index = line.startCharIndex;
|
|
|
|
for (int i = line.startIndex; i < line.endIndex; i++) {
|
2018-08-06 21:17:03 +02:00
|
|
|
int c =
|
|
|
|
this->elements_[i]->getSelectionIndexCount();
|
2018-01-16 00:26:04 +01:00
|
|
|
|
2018-04-15 15:09:31 +02:00
|
|
|
if (index + c > selection.selectionMax.charIndex) {
|
2018-07-06 19:23:47 +02:00
|
|
|
r = this->elements_[i]->getXFromIndex(
|
2018-04-25 14:49:30 +02:00
|
|
|
selection.selectionMax.charIndex - index);
|
2018-01-16 00:26:04 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
index += c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// ends in same line end
|
|
|
|
|
2018-04-15 15:09:31 +02:00
|
|
|
if (selection.selectionMax.messageIndex != messageIndex) {
|
2018-01-16 00:26:04 +01:00
|
|
|
int lineIndex2 = lineIndex + 1;
|
2018-07-06 19:23:47 +02:00
|
|
|
for (; lineIndex2 < this->lines_.size(); lineIndex2++) {
|
|
|
|
Line &line = this->lines_[lineIndex2];
|
2018-01-16 00:26:04 +01:00
|
|
|
QRect rect = line.rect;
|
|
|
|
|
2018-04-10 03:29:00 +02:00
|
|
|
rect.setTop(std::max(0, rect.top()) + yOffset);
|
2018-08-06 21:17:03 +02:00
|
|
|
rect.setBottom(
|
|
|
|
std::min(this->height_, rect.bottom()) +
|
|
|
|
yOffset);
|
|
|
|
rect.setLeft(this->elements_[line.startIndex]
|
|
|
|
->getRect()
|
|
|
|
.left());
|
|
|
|
rect.setRight(this->elements_[line.endIndex - 1]
|
|
|
|
->getRect()
|
|
|
|
.right());
|
2018-01-16 00:26:04 +01:00
|
|
|
|
2018-01-16 00:34:32 +01:00
|
|
|
painter.fillRect(rect, selectionColor);
|
2018-01-16 00:26:04 +01:00
|
|
|
}
|
|
|
|
returnAfter = true;
|
|
|
|
} else {
|
|
|
|
lineIndex++;
|
|
|
|
breakAfter = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
index += c;
|
|
|
|
}
|
|
|
|
|
|
|
|
QRect rect = line.rect;
|
|
|
|
|
2018-04-10 03:29:00 +02:00
|
|
|
rect.setTop(std::max(0, rect.top()) + yOffset);
|
2018-07-06 19:23:47 +02:00
|
|
|
rect.setBottom(std::min(this->height_, rect.bottom()) + yOffset);
|
2018-01-16 00:26:04 +01:00
|
|
|
rect.setLeft(x);
|
|
|
|
rect.setRight(r);
|
|
|
|
|
2018-01-16 00:34:32 +01:00
|
|
|
painter.fillRect(rect, selectionColor);
|
2018-01-16 00:26:04 +01:00
|
|
|
|
|
|
|
if (returnAfter) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (breakAfter) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// start in this message
|
2018-07-06 19:23:47 +02:00
|
|
|
for (; lineIndex < this->lines_.size(); lineIndex++) {
|
|
|
|
Line &line = this->lines_[lineIndex];
|
2018-01-16 00:26:04 +01:00
|
|
|
index = line.startCharIndex;
|
|
|
|
|
|
|
|
// just draw the garbage
|
2018-04-15 15:09:31 +02:00
|
|
|
if (line.endCharIndex < /*=*/selection.selectionMax.charIndex) {
|
2018-01-16 00:26:04 +01:00
|
|
|
QRect rect = line.rect;
|
|
|
|
|
2018-04-10 03:29:00 +02:00
|
|
|
rect.setTop(std::max(0, rect.top()) + yOffset);
|
2018-07-06 19:23:47 +02:00
|
|
|
rect.setBottom(std::min(this->height_, rect.bottom()) + yOffset);
|
|
|
|
rect.setLeft(this->elements_[line.startIndex]->getRect().left());
|
2018-08-06 21:17:03 +02:00
|
|
|
rect.setRight(
|
|
|
|
this->elements_[line.endIndex - 1]->getRect().right());
|
2018-01-16 00:26:04 +01:00
|
|
|
|
2018-01-16 00:34:32 +01:00
|
|
|
painter.fillRect(rect, selectionColor);
|
2018-01-16 00:26:04 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-07-06 19:23:47 +02:00
|
|
|
int r = this->elements_[line.endIndex - 1]->getRect().right();
|
2018-01-16 00:26:04 +01:00
|
|
|
|
|
|
|
for (int i = line.startIndex; i < line.endIndex; i++) {
|
2018-07-06 19:23:47 +02:00
|
|
|
int c = this->elements_[i]->getSelectionIndexCount();
|
2018-01-16 00:26:04 +01:00
|
|
|
|
2018-04-15 15:09:31 +02:00
|
|
|
if (index + c > selection.selectionMax.charIndex) {
|
2018-08-06 21:17:03 +02:00
|
|
|
r = this->elements_[i]->getXFromIndex(
|
|
|
|
selection.selectionMax.charIndex - index);
|
2018-01-16 00:26:04 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
index += c;
|
|
|
|
}
|
|
|
|
|
|
|
|
QRect rect = line.rect;
|
|
|
|
|
2018-04-10 03:29:00 +02:00
|
|
|
rect.setTop(std::max(0, rect.top()) + yOffset);
|
2018-07-06 19:23:47 +02:00
|
|
|
rect.setBottom(std::min(this->height_, rect.bottom()) + yOffset);
|
|
|
|
rect.setLeft(this->elements_[line.startIndex]->getRect().left());
|
2018-01-16 00:26:04 +01:00
|
|
|
rect.setRight(r);
|
|
|
|
|
2018-01-16 00:34:32 +01:00
|
|
|
painter.fillRect(rect, selectionColor);
|
2018-01-16 00:26:04 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-15 04:08:48 +01:00
|
|
|
// selection
|
|
|
|
int MessageLayoutContainer::getSelectionIndex(QPoint point)
|
|
|
|
{
|
2018-07-06 19:23:47 +02:00
|
|
|
if (this->elements_.size() == 0) {
|
2018-01-15 04:08:48 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-07-06 19:23:47 +02:00
|
|
|
auto line = this->lines_.begin();
|
2018-01-15 04:08:48 +01:00
|
|
|
|
2018-07-06 19:23:47 +02:00
|
|
|
for (; line != this->lines_.end(); line++) {
|
2018-01-15 04:08:48 +01:00
|
|
|
if (line->rect.contains(point)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-06 21:17:03 +02:00
|
|
|
int lineStart = line == this->lines_.end() ? this->lines_.back().startIndex
|
|
|
|
: line->startIndex;
|
2018-07-06 19:23:47 +02:00
|
|
|
if (line != this->lines_.end()) {
|
2018-01-16 00:26:04 +01:00
|
|
|
line++;
|
|
|
|
}
|
2018-08-06 21:17:03 +02:00
|
|
|
int lineEnd =
|
|
|
|
line == this->lines_.end() ? this->elements_.size() : line->startIndex;
|
2018-01-15 04:08:48 +01:00
|
|
|
|
|
|
|
int index = 0;
|
|
|
|
|
|
|
|
for (int i = 0; i < lineEnd; i++) {
|
|
|
|
// end of line
|
|
|
|
if (i == lineEnd) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// before line
|
|
|
|
if (i < lineStart) {
|
2018-07-06 19:23:47 +02:00
|
|
|
index += this->elements_[i]->getSelectionIndexCount();
|
2018-01-15 04:08:48 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// this is the word
|
2018-07-06 19:23:47 +02:00
|
|
|
if (point.x() < this->elements_[i]->getRect().right()) {
|
|
|
|
index += this->elements_[i]->getMouseOverIndex(point);
|
2018-01-15 04:08:48 +01:00
|
|
|
break;
|
|
|
|
}
|
2018-01-16 00:26:04 +01:00
|
|
|
|
2018-07-06 19:23:47 +02:00
|
|
|
index += this->elements_[i]->getSelectionIndexCount();
|
2018-01-15 04:08:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return index;
|
|
|
|
}
|
2018-01-16 02:39:31 +01:00
|
|
|
|
|
|
|
// fourtf: no idea if this is acurate LOL
|
|
|
|
int MessageLayoutContainer::getLastCharacterIndex() const
|
|
|
|
{
|
2018-07-06 19:23:47 +02:00
|
|
|
if (this->lines_.size() == 0) {
|
2018-01-16 02:39:31 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2018-07-06 19:23:47 +02:00
|
|
|
return this->lines_.back().endCharIndex;
|
2018-01-16 02:39:31 +01:00
|
|
|
}
|
|
|
|
|
2018-10-02 12:56:10 +02:00
|
|
|
int MessageLayoutContainer::getFirstMessageCharacterIndex() const
|
|
|
|
{
|
|
|
|
static FlagsEnum<MessageElementFlag> flags;
|
|
|
|
flags.set(MessageElementFlag::Username);
|
|
|
|
flags.set(MessageElementFlag::Timestamp);
|
|
|
|
flags.set(MessageElementFlag::Badges);
|
|
|
|
|
|
|
|
// Get the index of the first character of the real message
|
|
|
|
// (no badges/timestamps/username)
|
|
|
|
int index = 0;
|
|
|
|
for (auto &element : this->elements_) {
|
|
|
|
if (element.get()->getFlags().hasAny(flags)) {
|
|
|
|
index += element.get()->getSelectionIndexCount();
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
2018-08-16 00:16:33 +02:00
|
|
|
void MessageLayoutContainer::addSelectionText(QString &str, int from, int to,
|
|
|
|
CopyMode copymode)
|
2018-01-16 02:39:31 +01:00
|
|
|
{
|
|
|
|
int index = 0;
|
2018-04-10 15:48:56 +02:00
|
|
|
bool first = true;
|
2018-01-16 02:39:31 +01:00
|
|
|
|
2018-08-16 00:16:33 +02:00
|
|
|
for (auto &element : this->elements_) {
|
|
|
|
if (copymode == CopyMode::OnlyTextAndEmotes) {
|
|
|
|
if (element->getCreator().getFlags().hasAny(
|
|
|
|
{MessageElementFlag::Timestamp,
|
|
|
|
MessageElementFlag::Username, MessageElementFlag::Badges}))
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto indexCount = element->getSelectionIndexCount();
|
2018-01-16 02:39:31 +01:00
|
|
|
|
2018-04-10 15:48:56 +02:00
|
|
|
if (first) {
|
2018-08-16 00:16:33 +02:00
|
|
|
if (index + indexCount > from) {
|
|
|
|
element->addCopyTextToString(str, from - index, to - index);
|
2018-04-10 15:48:56 +02:00
|
|
|
first = false;
|
2018-04-10 15:52:47 +02:00
|
|
|
|
2018-08-16 00:16:33 +02:00
|
|
|
if (index + indexCount > to) {
|
2018-04-10 15:52:47 +02:00
|
|
|
break;
|
|
|
|
}
|
2018-01-16 02:39:31 +01:00
|
|
|
}
|
|
|
|
} else {
|
2018-08-16 00:16:33 +02:00
|
|
|
if (index + indexCount > to) {
|
|
|
|
element->addCopyTextToString(str, 0, to - index);
|
2018-01-16 02:39:31 +01:00
|
|
|
break;
|
|
|
|
} else {
|
2018-08-16 00:16:33 +02:00
|
|
|
element->addCopyTextToString(str);
|
2018-01-16 02:39:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-16 00:16:33 +02:00
|
|
|
index += indexCount;
|
2018-01-16 02:39:31 +01:00
|
|
|
}
|
|
|
|
}
|
2018-04-01 16:43:30 +02:00
|
|
|
|
2018-01-13 02:13:59 +01:00
|
|
|
} // namespace chatterino
|