mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
started adding text selection
This commit is contained in:
parent
bfd57121b8
commit
181fb69a44
12 changed files with 238 additions and 29 deletions
|
@ -5,6 +5,6 @@ before_install:
|
|||
- sudo apt-get install qt5-default qttools5-dev-tools
|
||||
|
||||
script:
|
||||
- qmake -project
|
||||
- qmake Ultron.pro
|
||||
- qmake -qt=qt5 -v
|
||||
- qmake -qt=qt5
|
||||
- make
|
|
@ -24,19 +24,19 @@ public:
|
|||
Link(Type getType, const QString &getValue);
|
||||
|
||||
bool
|
||||
getIsValid()
|
||||
getIsValid() const
|
||||
{
|
||||
return type == None;
|
||||
}
|
||||
|
||||
Type
|
||||
getType()
|
||||
getType() const
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
const QString &
|
||||
getValue()
|
||||
getValue() const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "resources.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <QObjectUserData>
|
||||
#include <QStringList>
|
||||
#include <ctime>
|
||||
#include <list>
|
||||
|
@ -144,7 +145,7 @@ Message::Message(const IrcPrivateMessage &ircMessage, Channel &channel,
|
|||
}
|
||||
|
||||
// username
|
||||
this->userName = ircMessage.account();
|
||||
this->userName = ircMessage.nick();
|
||||
|
||||
if (this->userName.isEmpty()) {
|
||||
auto iterator = tags.find("login");
|
||||
|
@ -230,7 +231,7 @@ Message::Message(const IrcPrivateMessage &ircMessage, Channel &channel,
|
|||
end > ircMessage.content().length())
|
||||
continue;
|
||||
|
||||
QString name = ircMessage.content().mid(start, end - start);
|
||||
QString name = ircMessage.content().mid(start, end - start + 1);
|
||||
|
||||
twitchEmotes.push_back(std::pair<long int, LazyLoadedImage *>(
|
||||
start, Emotes::getTwitchEmoteById(name, id)));
|
||||
|
|
|
@ -36,11 +36,13 @@ MessageRef::layout(int width, bool enableEmoteMargins)
|
|||
bool recalculateImages =
|
||||
this->emoteGeneration != Emotes::getGeneration();
|
||||
bool recalculateText = this->fontGeneration != Fonts::getGeneration();
|
||||
bool newWordTypes =
|
||||
this->currentWordTypes != Settings::getInstance().getWordTypeMask();
|
||||
|
||||
qreal emoteScale = settings.emoteScale.get();
|
||||
bool scaleEmotesByLineHeight = settings.scaleEmotesByLineHeight.get();
|
||||
|
||||
if (recalculateImages || recalculateText) {
|
||||
if (recalculateImages || recalculateText || newWordTypes) {
|
||||
this->emoteGeneration = Emotes::getGeneration();
|
||||
this->fontGeneration = Fonts::getGeneration();
|
||||
|
||||
|
@ -72,6 +74,10 @@ MessageRef::layout(int width, bool enableEmoteMargins)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newWordTypes) {
|
||||
this->currentWordTypes = Settings::getInstance().getWordTypeMask();
|
||||
}
|
||||
}
|
||||
|
||||
if (!redraw) {
|
||||
|
@ -85,6 +91,7 @@ MessageRef::layout(int width, bool enableEmoteMargins)
|
|||
|
||||
int right = width - MARGIN_RIGHT - MARGIN_LEFT;
|
||||
|
||||
int lineNumber = 0;
|
||||
int lineStart = 0;
|
||||
int lineHeight = 0;
|
||||
bool first = true;
|
||||
|
@ -139,22 +146,23 @@ MessageRef::layout(int width, bool enableEmoteMargins)
|
|||
|
||||
this->wordParts.push_back(WordPart(word, MARGIN_LEFT, y,
|
||||
width, word.getHeight(),
|
||||
mid, mid));
|
||||
lineNumber, mid, mid));
|
||||
|
||||
y += metrics.height();
|
||||
|
||||
start = i - 1;
|
||||
|
||||
width = 0;
|
||||
lineNumber++;
|
||||
}
|
||||
}
|
||||
|
||||
QString mid(text.mid(start));
|
||||
width = metrics.width(mid);
|
||||
|
||||
this->wordParts.push_back(WordPart(word, MARGIN_LEFT,
|
||||
y - word.getHeight(), width,
|
||||
word.getHeight(), mid, mid));
|
||||
this->wordParts.push_back(
|
||||
WordPart(word, MARGIN_LEFT, y - word.getHeight(), width,
|
||||
word.getHeight(), lineNumber, mid, mid));
|
||||
x = width + MARGIN_LEFT + spaceWidth;
|
||||
|
||||
lineHeight = word.getHeight();
|
||||
|
@ -164,8 +172,8 @@ MessageRef::layout(int width, bool enableEmoteMargins)
|
|||
first = false;
|
||||
} else if (first || x + word.getWidth() + xOffset <= right) {
|
||||
// fits in the line
|
||||
this->wordParts.push_back(
|
||||
WordPart(word, x, y - word.getHeight(), word.getCopyText()));
|
||||
this->wordParts.push_back(WordPart(word, x, y - word.getHeight(),
|
||||
lineNumber, word.getCopyText()));
|
||||
|
||||
x += word.getWidth() + xOffset;
|
||||
x += spaceWidth;
|
||||
|
@ -179,8 +187,9 @@ MessageRef::layout(int width, bool enableEmoteMargins)
|
|||
|
||||
y += lineHeight;
|
||||
|
||||
this->wordParts.push_back(WordPart(
|
||||
word, MARGIN_LEFT, y - word.getHeight(), word.getCopyText()));
|
||||
this->wordParts.push_back(WordPart(word, MARGIN_LEFT,
|
||||
y - word.getHeight(), lineNumber,
|
||||
word.getCopyText()));
|
||||
|
||||
lineStart = this->wordParts.size() - 1;
|
||||
|
||||
|
@ -188,6 +197,8 @@ MessageRef::layout(int width, bool enableEmoteMargins)
|
|||
|
||||
x = word.getWidth() + MARGIN_LEFT;
|
||||
x += spaceWidth;
|
||||
|
||||
lineNumber++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -216,5 +227,112 @@ MessageRef::alignWordParts(int lineStart, int lineHeight)
|
|||
wordPart2.setY(wordPart2.getY() + lineHeight);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MessageRef::tryGetWordPart(QPoint point, messages::Word &word)
|
||||
{
|
||||
for (messages::WordPart &wordPart : this->wordParts) {
|
||||
if (wordPart.getRect().contains(point)) {
|
||||
word = wordPart.getWord();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int
|
||||
MessageRef::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 (int i = 0; i < this->wordParts.size(); i++) {
|
||||
WordPart &part = this->wordParts[i];
|
||||
|
||||
// return if curser under the word
|
||||
if (position.y() >= part.getBottom()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (part.getLineNumber() != lineNumber) {
|
||||
lineStart = i;
|
||||
lineNumber = part.getLineNumber();
|
||||
}
|
||||
|
||||
lineEnd = i;
|
||||
}
|
||||
|
||||
// count up to the cursor
|
||||
int index = 0;
|
||||
|
||||
for (int i = 0; i < lineStart; i++) {
|
||||
WordPart &part = this->wordParts[i];
|
||||
|
||||
index += part.getWord().isImage() ? 2 : part.getText().length() + 1;
|
||||
}
|
||||
|
||||
for (int i = lineStart; i < lineEnd; i++) {
|
||||
WordPart &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()) {
|
||||
index += part.getWord().isImage() ? 2 : part.getText().length() + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// cursor is over the word part
|
||||
if (part.getWord().isImage()) {
|
||||
index++;
|
||||
} else {
|
||||
auto text = part.getWord().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().width(text, j + 1);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return index;
|
||||
|
||||
// go through all the wordparts
|
||||
// for (int i = 0; i < this->wordParts; i < this->wordParts.size()) {
|
||||
|
||||
// WordPart &part = this->wordParts[i];
|
||||
|
||||
// // return if curser under the word
|
||||
// if (position.y() >= part.getBottom()) {
|
||||
// break;
|
||||
// }
|
||||
|
||||
// // increment index and continue if the curser x is bigger than the
|
||||
// words
|
||||
// // right edge
|
||||
// if (position.x() > part.getRight()) {
|
||||
// index += part.getWord().isImage() ? 2 +
|
||||
// part.getText().length() + 1;
|
||||
// continue;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,10 @@ public:
|
|||
std::shared_ptr<QPixmap> buffer = nullptr;
|
||||
bool updateBuffer = false;
|
||||
|
||||
bool tryGetWordPart(QPoint point, messages::Word &word);
|
||||
|
||||
int getSelectionIndex(QPoint position);
|
||||
|
||||
private:
|
||||
Message *message;
|
||||
std::shared_ptr<Message> messagePtr;
|
||||
|
@ -48,6 +52,7 @@ private:
|
|||
int currentLayoutWidth = -1;
|
||||
int fontGeneration = -1;
|
||||
int emoteGeneration = -1;
|
||||
Word::Type currentWordTypes = Word::None;
|
||||
|
||||
void alignWordParts(int lineStart, int lineHeight);
|
||||
};
|
||||
|
|
|
@ -65,6 +65,9 @@ public:
|
|||
ButtonTimeout
|
||||
};
|
||||
|
||||
Word()
|
||||
{
|
||||
}
|
||||
explicit Word(LazyLoadedImage *image, Type getType, const QString ©text,
|
||||
const QString &getTooltip, const Link &getLink = Link());
|
||||
explicit Word(const QString &text, Type getType, const QColor &getColor,
|
||||
|
@ -182,7 +185,7 @@ public:
|
|||
}
|
||||
|
||||
std::vector<short> &
|
||||
getCharacterWidthCache()
|
||||
getCharacterWidthCache() const
|
||||
{
|
||||
return this->characterWidthCache;
|
||||
}
|
||||
|
@ -206,7 +209,7 @@ private:
|
|||
Fonts::Type font = Fonts::Medium;
|
||||
Link link;
|
||||
|
||||
std::vector<short> characterWidthCache;
|
||||
mutable std::vector<short> characterWidthCache;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
namespace chatterino {
|
||||
namespace messages {
|
||||
|
||||
WordPart::WordPart(Word &word, int x, int y, const QString ©Text,
|
||||
bool allowTrailingSpace)
|
||||
WordPart::WordPart(Word &word, int x, int y, int lineNumber,
|
||||
const QString ©Text, bool allowTrailingSpace)
|
||||
: m_word(word)
|
||||
, copyText(copyText)
|
||||
, text(word.isText() ? m_word.getText() : QString())
|
||||
|
@ -13,13 +13,14 @@ WordPart::WordPart(Word &word, int x, int y, const QString ©Text,
|
|||
, y(y)
|
||||
, width(word.getWidth())
|
||||
, height(word.getHeight())
|
||||
, lineNumber(lineNumber)
|
||||
, _trailingSpace(word.hasTrailingSpace() & allowTrailingSpace)
|
||||
{
|
||||
}
|
||||
|
||||
WordPart::WordPart(Word &word, int x, int y, int width, int height,
|
||||
const QString ©Text, const QString &customText,
|
||||
bool allowTrailingSpace)
|
||||
int lineNumber, const QString ©Text,
|
||||
const QString &customText, bool allowTrailingSpace)
|
||||
: m_word(word)
|
||||
, copyText(copyText)
|
||||
, text(customText)
|
||||
|
@ -27,6 +28,7 @@ WordPart::WordPart(Word &word, int x, int y, int width, int height,
|
|||
, y(y)
|
||||
, width(width)
|
||||
, height(height)
|
||||
, lineNumber(lineNumber)
|
||||
, _trailingSpace(word.hasTrailingSpace() & allowTrailingSpace)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -12,12 +12,12 @@ class Word;
|
|||
class WordPart
|
||||
{
|
||||
public:
|
||||
WordPart(Word &getWord, int getX, int getY, const QString &getCopyText,
|
||||
bool allowTrailingSpace = true);
|
||||
WordPart(Word &getWord, int getX, int getY, int lineNumber,
|
||||
const QString &getCopyText, bool allowTrailingSpace = true);
|
||||
|
||||
WordPart(Word &getWord, int getX, int getY, int getWidth, int getHeight,
|
||||
const QString &getCopyText, const QString &customText,
|
||||
bool allowTrailingSpace = true);
|
||||
int lineNumber, const QString &getCopyText,
|
||||
const QString &customText, bool allowTrailingSpace = true);
|
||||
|
||||
const Word &
|
||||
getWord() const
|
||||
|
@ -98,6 +98,12 @@ public:
|
|||
return this->text;
|
||||
}
|
||||
|
||||
int
|
||||
getLineNumber()
|
||||
{
|
||||
return this->lineNumber;
|
||||
}
|
||||
|
||||
private:
|
||||
Word &m_word;
|
||||
|
||||
|
@ -109,6 +115,8 @@ private:
|
|||
int width;
|
||||
int height;
|
||||
|
||||
int lineNumber;
|
||||
|
||||
bool _trailingSpace;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -76,8 +76,6 @@ ChatWidget::setChannelName(const QString &name)
|
|||
|
||||
auto messageRef = new messages::MessageRef(message);
|
||||
|
||||
qDebug() << "xD";
|
||||
|
||||
this->messages.appendItem(
|
||||
std::shared_ptr<messages::MessageRef>(messageRef), deleted);
|
||||
});
|
||||
|
|
|
@ -24,6 +24,7 @@ ChatWidgetView::ChatWidgetView(ChatWidget *parent)
|
|||
{
|
||||
this->setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
this->scrollbar.setSmallChange(5);
|
||||
this->setMouseTracking(true);
|
||||
|
||||
QObject::connect(&Settings::getInstance(), &Settings::wordTypeMaskChanged,
|
||||
this, &ChatWidgetView::wordTypeMaskChanged);
|
||||
|
@ -286,5 +287,70 @@ ChatWidgetView::wheelEvent(QWheelEvent *event)
|
|||
true);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ChatWidgetView::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
std::shared_ptr<messages::MessageRef> message;
|
||||
QPoint relativePos;
|
||||
|
||||
if (!tryGetMessageAt(event->pos(), message, relativePos)) {
|
||||
this->setCursor(Qt::ArrowCursor);
|
||||
return;
|
||||
}
|
||||
|
||||
auto _message = message->getMessage();
|
||||
auto user = _message->getUserName();
|
||||
|
||||
messages::Word hoverWord;
|
||||
|
||||
if (!message->tryGetWordPart(relativePos, hoverWord)) {
|
||||
this->setCursor(Qt::ArrowCursor);
|
||||
return;
|
||||
}
|
||||
|
||||
int index = message->getSelectionIndex(relativePos);
|
||||
|
||||
qDebug() << index;
|
||||
|
||||
if (hoverWord.getLink().getIsValid()) {
|
||||
this->setCursor(Qt::PointingHandCursor);
|
||||
qDebug() << hoverWord.getLink().getValue();
|
||||
} else {
|
||||
this->setCursor(Qt::ArrowCursor);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ChatWidgetView::tryGetMessageAt(QPoint p,
|
||||
std::shared_ptr<messages::MessageRef> &_message,
|
||||
QPoint &relativePos)
|
||||
{
|
||||
auto messages = chatWidget->getMessagesSnapshot();
|
||||
|
||||
int start = this->scrollbar.getCurrentValue();
|
||||
|
||||
if (start >= messages.getLength()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int y = -(messages[start].get()->getHeight() *
|
||||
(fmod(this->scrollbar.getCurrentValue(), 1))) +
|
||||
12;
|
||||
|
||||
for (int i = start; i < messages.getLength(); ++i) {
|
||||
auto message = messages[i];
|
||||
|
||||
y += message->getHeight();
|
||||
|
||||
if (p.y() < y) {
|
||||
relativePos = QPoint(p.x(), y - p.y());
|
||||
_message = message;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,12 @@ protected:
|
|||
void paintEvent(QPaintEvent *);
|
||||
void wheelEvent(QWheelEvent *event);
|
||||
|
||||
void mouseMoveEvent(QMouseEvent *event);
|
||||
|
||||
bool tryGetMessageAt(QPoint p,
|
||||
std::shared_ptr<messages::MessageRef> &message,
|
||||
QPoint &relativePos);
|
||||
|
||||
private:
|
||||
struct GifEmoteData {
|
||||
messages::LazyLoadedImage *image;
|
||||
|
@ -56,6 +62,7 @@ private slots:
|
|||
void
|
||||
wordTypeMaskChanged()
|
||||
{
|
||||
layoutMessages();
|
||||
update();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -152,6 +152,7 @@ Notebook::performLayout(bool animated)
|
|||
if (Settings::getInstance().hideUserButton.get()) {
|
||||
userButton.hide();
|
||||
} else {
|
||||
userButton.move(x, 0);
|
||||
userButton.show();
|
||||
x += 24;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue