started adding text selection

This commit is contained in:
fourtf 2017-02-17 23:51:35 +01:00
parent bfd57121b8
commit 181fb69a44
12 changed files with 238 additions and 29 deletions

View file

@ -5,6 +5,6 @@ before_install:
- sudo apt-get install qt5-default qttools5-dev-tools - sudo apt-get install qt5-default qttools5-dev-tools
script: script:
- qmake -project - qmake -qt=qt5 -v
- qmake Ultron.pro - qmake -qt=qt5
- make - make

View file

@ -24,19 +24,19 @@ public:
Link(Type getType, const QString &getValue); Link(Type getType, const QString &getValue);
bool bool
getIsValid() getIsValid() const
{ {
return type == None; return type == None;
} }
Type Type
getType() getType() const
{ {
return type; return type;
} }
const QString & const QString &
getValue() getValue() const
{ {
return value; return value;
} }

View file

@ -9,6 +9,7 @@
#include "resources.h" #include "resources.h"
#include "settings.h" #include "settings.h"
#include <QObjectUserData>
#include <QStringList> #include <QStringList>
#include <ctime> #include <ctime>
#include <list> #include <list>
@ -144,7 +145,7 @@ Message::Message(const IrcPrivateMessage &ircMessage, Channel &channel,
} }
// username // username
this->userName = ircMessage.account(); this->userName = ircMessage.nick();
if (this->userName.isEmpty()) { if (this->userName.isEmpty()) {
auto iterator = tags.find("login"); auto iterator = tags.find("login");
@ -230,7 +231,7 @@ Message::Message(const IrcPrivateMessage &ircMessage, Channel &channel,
end > ircMessage.content().length()) end > ircMessage.content().length())
continue; 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 *>( twitchEmotes.push_back(std::pair<long int, LazyLoadedImage *>(
start, Emotes::getTwitchEmoteById(name, id))); start, Emotes::getTwitchEmoteById(name, id)));

View file

@ -36,11 +36,13 @@ MessageRef::layout(int width, bool enableEmoteMargins)
bool recalculateImages = bool recalculateImages =
this->emoteGeneration != Emotes::getGeneration(); this->emoteGeneration != Emotes::getGeneration();
bool recalculateText = this->fontGeneration != Fonts::getGeneration(); bool recalculateText = this->fontGeneration != Fonts::getGeneration();
bool newWordTypes =
this->currentWordTypes != Settings::getInstance().getWordTypeMask();
qreal emoteScale = settings.emoteScale.get(); qreal emoteScale = settings.emoteScale.get();
bool scaleEmotesByLineHeight = settings.scaleEmotesByLineHeight.get(); bool scaleEmotesByLineHeight = settings.scaleEmotesByLineHeight.get();
if (recalculateImages || recalculateText) { if (recalculateImages || recalculateText || newWordTypes) {
this->emoteGeneration = Emotes::getGeneration(); this->emoteGeneration = Emotes::getGeneration();
this->fontGeneration = Fonts::getGeneration(); this->fontGeneration = Fonts::getGeneration();
@ -72,6 +74,10 @@ MessageRef::layout(int width, bool enableEmoteMargins)
} }
} }
} }
if (newWordTypes) {
this->currentWordTypes = Settings::getInstance().getWordTypeMask();
}
} }
if (!redraw) { if (!redraw) {
@ -85,6 +91,7 @@ MessageRef::layout(int width, bool enableEmoteMargins)
int right = width - MARGIN_RIGHT - MARGIN_LEFT; int right = width - MARGIN_RIGHT - MARGIN_LEFT;
int lineNumber = 0;
int lineStart = 0; int lineStart = 0;
int lineHeight = 0; int lineHeight = 0;
bool first = true; bool first = true;
@ -139,22 +146,23 @@ MessageRef::layout(int width, bool enableEmoteMargins)
this->wordParts.push_back(WordPart(word, MARGIN_LEFT, y, this->wordParts.push_back(WordPart(word, MARGIN_LEFT, y,
width, word.getHeight(), width, word.getHeight(),
mid, mid)); lineNumber, mid, mid));
y += metrics.height(); y += metrics.height();
start = i - 1; start = i - 1;
width = 0; width = 0;
lineNumber++;
} }
} }
QString mid(text.mid(start)); QString mid(text.mid(start));
width = metrics.width(mid); width = metrics.width(mid);
this->wordParts.push_back(WordPart(word, MARGIN_LEFT, this->wordParts.push_back(
y - word.getHeight(), width, WordPart(word, MARGIN_LEFT, y - word.getHeight(), width,
word.getHeight(), mid, mid)); word.getHeight(), lineNumber, mid, mid));
x = width + MARGIN_LEFT + spaceWidth; x = width + MARGIN_LEFT + spaceWidth;
lineHeight = word.getHeight(); lineHeight = word.getHeight();
@ -164,8 +172,8 @@ MessageRef::layout(int width, bool enableEmoteMargins)
first = false; first = false;
} else if (first || x + word.getWidth() + xOffset <= right) { } else if (first || x + word.getWidth() + xOffset <= right) {
// fits in the line // fits in the line
this->wordParts.push_back( this->wordParts.push_back(WordPart(word, x, y - word.getHeight(),
WordPart(word, x, y - word.getHeight(), word.getCopyText())); lineNumber, word.getCopyText()));
x += word.getWidth() + xOffset; x += word.getWidth() + xOffset;
x += spaceWidth; x += spaceWidth;
@ -179,8 +187,9 @@ MessageRef::layout(int width, bool enableEmoteMargins)
y += lineHeight; y += lineHeight;
this->wordParts.push_back(WordPart( this->wordParts.push_back(WordPart(word, MARGIN_LEFT,
word, MARGIN_LEFT, y - word.getHeight(), word.getCopyText())); y - word.getHeight(), lineNumber,
word.getCopyText()));
lineStart = this->wordParts.size() - 1; lineStart = this->wordParts.size() - 1;
@ -188,6 +197,8 @@ MessageRef::layout(int width, bool enableEmoteMargins)
x = word.getWidth() + MARGIN_LEFT; x = word.getWidth() + MARGIN_LEFT;
x += spaceWidth; x += spaceWidth;
lineNumber++;
} }
} }
@ -216,5 +227,112 @@ MessageRef::alignWordParts(int lineStart, int lineHeight)
wordPart2.setY(wordPart2.getY() + 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;
// }
// }
}
} }
} }

View file

@ -37,6 +37,10 @@ public:
std::shared_ptr<QPixmap> buffer = nullptr; std::shared_ptr<QPixmap> buffer = nullptr;
bool updateBuffer = false; bool updateBuffer = false;
bool tryGetWordPart(QPoint point, messages::Word &word);
int getSelectionIndex(QPoint position);
private: private:
Message *message; Message *message;
std::shared_ptr<Message> messagePtr; std::shared_ptr<Message> messagePtr;
@ -48,6 +52,7 @@ private:
int currentLayoutWidth = -1; int currentLayoutWidth = -1;
int fontGeneration = -1; int fontGeneration = -1;
int emoteGeneration = -1; int emoteGeneration = -1;
Word::Type currentWordTypes = Word::None;
void alignWordParts(int lineStart, int lineHeight); void alignWordParts(int lineStart, int lineHeight);
}; };

View file

@ -65,6 +65,9 @@ public:
ButtonTimeout ButtonTimeout
}; };
Word()
{
}
explicit Word(LazyLoadedImage *image, Type getType, const QString &copytext, explicit Word(LazyLoadedImage *image, Type getType, const QString &copytext,
const QString &getTooltip, const Link &getLink = Link()); const QString &getTooltip, const Link &getLink = Link());
explicit Word(const QString &text, Type getType, const QColor &getColor, explicit Word(const QString &text, Type getType, const QColor &getColor,
@ -182,7 +185,7 @@ public:
} }
std::vector<short> & std::vector<short> &
getCharacterWidthCache() getCharacterWidthCache() const
{ {
return this->characterWidthCache; return this->characterWidthCache;
} }
@ -206,7 +209,7 @@ private:
Fonts::Type font = Fonts::Medium; Fonts::Type font = Fonts::Medium;
Link link; Link link;
std::vector<short> characterWidthCache; mutable std::vector<short> characterWidthCache;
}; };
} }
} }

View file

@ -4,8 +4,8 @@
namespace chatterino { namespace chatterino {
namespace messages { namespace messages {
WordPart::WordPart(Word &word, int x, int y, const QString &copyText, WordPart::WordPart(Word &word, int x, int y, int lineNumber,
bool allowTrailingSpace) const QString &copyText, bool allowTrailingSpace)
: m_word(word) : m_word(word)
, copyText(copyText) , copyText(copyText)
, text(word.isText() ? m_word.getText() : QString()) , text(word.isText() ? m_word.getText() : QString())
@ -13,13 +13,14 @@ WordPart::WordPart(Word &word, int x, int y, const QString &copyText,
, y(y) , y(y)
, width(word.getWidth()) , width(word.getWidth())
, height(word.getHeight()) , height(word.getHeight())
, lineNumber(lineNumber)
, _trailingSpace(word.hasTrailingSpace() & allowTrailingSpace) , _trailingSpace(word.hasTrailingSpace() & allowTrailingSpace)
{ {
} }
WordPart::WordPart(Word &word, int x, int y, int width, int height, WordPart::WordPart(Word &word, int x, int y, int width, int height,
const QString &copyText, const QString &customText, int lineNumber, const QString &copyText,
bool allowTrailingSpace) const QString &customText, bool allowTrailingSpace)
: m_word(word) : m_word(word)
, copyText(copyText) , copyText(copyText)
, text(customText) , text(customText)
@ -27,6 +28,7 @@ WordPart::WordPart(Word &word, int x, int y, int width, int height,
, y(y) , y(y)
, width(width) , width(width)
, height(height) , height(height)
, lineNumber(lineNumber)
, _trailingSpace(word.hasTrailingSpace() & allowTrailingSpace) , _trailingSpace(word.hasTrailingSpace() & allowTrailingSpace)
{ {
} }

View file

@ -12,12 +12,12 @@ class Word;
class WordPart class WordPart
{ {
public: public:
WordPart(Word &getWord, int getX, int getY, const QString &getCopyText, WordPart(Word &getWord, int getX, int getY, int lineNumber,
bool allowTrailingSpace = true); const QString &getCopyText, bool allowTrailingSpace = true);
WordPart(Word &getWord, int getX, int getY, int getWidth, int getHeight, WordPart(Word &getWord, int getX, int getY, int getWidth, int getHeight,
const QString &getCopyText, const QString &customText, int lineNumber, const QString &getCopyText,
bool allowTrailingSpace = true); const QString &customText, bool allowTrailingSpace = true);
const Word & const Word &
getWord() const getWord() const
@ -98,6 +98,12 @@ public:
return this->text; return this->text;
} }
int
getLineNumber()
{
return this->lineNumber;
}
private: private:
Word &m_word; Word &m_word;
@ -109,6 +115,8 @@ private:
int width; int width;
int height; int height;
int lineNumber;
bool _trailingSpace; bool _trailingSpace;
}; };
} }

View file

@ -76,8 +76,6 @@ ChatWidget::setChannelName(const QString &name)
auto messageRef = new messages::MessageRef(message); auto messageRef = new messages::MessageRef(message);
qDebug() << "xD";
this->messages.appendItem( this->messages.appendItem(
std::shared_ptr<messages::MessageRef>(messageRef), deleted); std::shared_ptr<messages::MessageRef>(messageRef), deleted);
}); });

View file

@ -24,6 +24,7 @@ ChatWidgetView::ChatWidgetView(ChatWidget *parent)
{ {
this->setAttribute(Qt::WA_OpaquePaintEvent); this->setAttribute(Qt::WA_OpaquePaintEvent);
this->scrollbar.setSmallChange(5); this->scrollbar.setSmallChange(5);
this->setMouseTracking(true);
QObject::connect(&Settings::getInstance(), &Settings::wordTypeMaskChanged, QObject::connect(&Settings::getInstance(), &Settings::wordTypeMaskChanged,
this, &ChatWidgetView::wordTypeMaskChanged); this, &ChatWidgetView::wordTypeMaskChanged);
@ -286,5 +287,70 @@ ChatWidgetView::wheelEvent(QWheelEvent *event)
true); 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;
}
} }
} }

View file

@ -39,6 +39,12 @@ protected:
void paintEvent(QPaintEvent *); void paintEvent(QPaintEvent *);
void wheelEvent(QWheelEvent *event); void wheelEvent(QWheelEvent *event);
void mouseMoveEvent(QMouseEvent *event);
bool tryGetMessageAt(QPoint p,
std::shared_ptr<messages::MessageRef> &message,
QPoint &relativePos);
private: private:
struct GifEmoteData { struct GifEmoteData {
messages::LazyLoadedImage *image; messages::LazyLoadedImage *image;
@ -56,6 +62,7 @@ private slots:
void void
wordTypeMaskChanged() wordTypeMaskChanged()
{ {
layoutMessages();
update(); update();
} }
}; };

View file

@ -152,6 +152,7 @@ Notebook::performLayout(bool animated)
if (Settings::getInstance().hideUserButton.get()) { if (Settings::getInstance().hideUserButton.get()) {
userButton.hide(); userButton.hide();
} else { } else {
userButton.move(x, 0);
userButton.show(); userButton.show();
x += 24; x += 24;
} }