diff --git a/src/messages/messageref.cpp b/src/messages/messageref.cpp index f75d72a3e..d692d5d45 100644 --- a/src/messages/messageref.cpp +++ b/src/messages/messageref.cpp @@ -141,13 +141,16 @@ bool MessageRef::layout(int width, bool enableEmoteMargins) int width = 0; std::vector &charWidths = word.getCharacterWidthCache(); + int charOffset = 0; for (int i = 2; i <= text.length(); i++) { if ((width = width + charWidths[i - 1]) + MARGIN_LEFT > right) { QString mid = text.mid(start, i - start - 1); _wordParts.push_back(WordPart(word, MARGIN_LEFT, y, width, word.getHeight(), - lineNumber, mid, mid, false)); + lineNumber, mid, mid, false, charOffset)); + + charOffset = i; y += metrics.height(); @@ -162,7 +165,7 @@ bool MessageRef::layout(int width, bool enableEmoteMargins) width = metrics.width(mid); _wordParts.push_back(WordPart(word, MARGIN_LEFT, y - word.getHeight(), width, - word.getHeight(), lineNumber, mid, mid)); + word.getHeight(), lineNumber, mid, mid, charOffset)); x = width + MARGIN_LEFT + spaceWidth; lineHeight = word.getHeight(); diff --git a/src/messages/wordpart.cpp b/src/messages/wordpart.cpp index c19bb94be..96fb25fda 100644 --- a/src/messages/wordpart.cpp +++ b/src/messages/wordpart.cpp @@ -15,11 +15,13 @@ WordPart::WordPart(Word &word, int x, int y, int lineNumber, const QString © , _height(word.getHeight()) , _lineNumber(lineNumber) , _trailingSpace(!word.getCopyText().isEmpty() && word.hasTrailingSpace() & allowTrailingSpace) + , wordCharOffset(0) { } WordPart::WordPart(Word &word, int x, int y, int width, int height, int lineNumber, - const QString ©Text, const QString &customText, bool allowTrailingSpace) + const QString ©Text, const QString &customText, bool allowTrailingSpace, + int wordCharOffset) : _word(word) , _copyText(copyText) , _text(customText) @@ -29,6 +31,7 @@ WordPart::WordPart(Word &word, int x, int y, int width, int height, int lineNumb , _height(height) , _lineNumber(lineNumber) , _trailingSpace(!word.getCopyText().isEmpty() && word.hasTrailingSpace() & allowTrailingSpace) + , wordCharOffset(wordCharOffset) { } @@ -110,5 +113,9 @@ int WordPart::getCharacterLength() const return this->getWord().isImage() ? 2 : this->getText().length() + 1; } +short WordPart::getCharacterWidth(int index) const +{ + return this->getWord().getCharacterWidthCache().at(index + this->wordCharOffset); +} } // namespace messages } // namespace chatterino diff --git a/src/messages/wordpart.hpp b/src/messages/wordpart.hpp index bdf3375d6..85776a60d 100644 --- a/src/messages/wordpart.hpp +++ b/src/messages/wordpart.hpp @@ -15,7 +15,8 @@ public: bool allowTrailingSpace = true); WordPart(Word &getWord, int getX, int getY, int getWidth, int getHeight, int _lineNumber, - const QString &getCopyText, const QString &customText, bool allowTrailingSpace = true); + const QString &getCopyText, const QString &customText, bool allowTrailingSpace = true, + int wordCharOffset = 0); const Word &getWord() const; int getWidth() const; @@ -32,6 +33,7 @@ public: const QString &getText() const; int getLineNumber() const; int getCharacterLength() const; + short getCharacterWidth(int index) const; private: Word &_word; @@ -47,6 +49,7 @@ private: int _lineNumber; bool _trailingSpace; + int wordCharOffset; }; } // namespace messages diff --git a/src/widgets/channelview.cpp b/src/widgets/channelview.cpp index b73750cac..8e9f4f58c 100644 --- a/src/widgets/channelview.cpp +++ b/src/widgets/channelview.cpp @@ -258,6 +258,18 @@ QString ChannelView::getSelectedText() return text; } +bool ChannelView::hasSelection() +{ + return !this->selection.isEmpty(); +} + +void ChannelView::clearSelection() +{ + this->selection = Selection(); + layoutMessages(); + update(); +} + messages::LimitedQueueSnapshot ChannelView::getMessagesSnapshot() { return this->messages.getSnapshot(); @@ -338,6 +350,8 @@ void ChannelView::setSelection(const SelectionItem &start, const SelectionItem & // selections this->selection = Selection(start, end); + this->selectionChanged(); + // qDebug() << min.messageIndex << ":" << min.charIndex << " " << max.messageIndex << ":" // << max.charIndex; } @@ -552,10 +566,8 @@ void ChannelView::drawMessageSelection(QPainter &painter, messages::MessageRef * if (part.getWord().isText()) { int offset = this->selection.min.charIndex - charIndex; - std::vector &characterWidth = part.getWord().getCharacterWidthCache(); - for (int j = 0; j < offset; j++) { - rect.setLeft(rect.left() + characterWidth[j]); + rect.setLeft(rect.left() + part.getCharacterWidth(j)); } if (isSingleWord) { @@ -564,7 +576,7 @@ void ChannelView::drawMessageSelection(QPainter &painter, messages::MessageRef * rect.setRight(part.getX()); for (int j = 0; j < offset + length; j++) { - rect.setRight(rect.right() + characterWidth[j]); + rect.setRight(rect.right() + part.getCharacterWidth(j)); } painter.fillRect(rect, selectionColor); @@ -616,14 +628,12 @@ void ChannelView::drawMessageSelection(QPainter &painter, messages::MessageRef * if (part.getWord().isText()) { int offset = this->selection.min.charIndex - charIndex; - std::vector &characterWidth = part.getWord().getCharacterWidthCache(); - int length = (this->selection.max.charIndex - charIndex) - offset; rect.setRight(part.getX()); for (int j = 0; j < offset + length; j++) { - rect.setRight(rect.right() + characterWidth[j]); + rect.setRight(rect.right() + part.getCharacterWidth(j)); } } else { if (this->selection.max.charIndex == charIndex) { diff --git a/src/widgets/channelview.hpp b/src/widgets/channelview.hpp index 1ce7780bc..c472dc1bf 100644 --- a/src/widgets/channelview.hpp +++ b/src/widgets/channelview.hpp @@ -89,6 +89,8 @@ public: void updateGifEmotes(); ScrollBar &getScrollBar(); QString getSelectedText(); + bool hasSelection(); + void clearSelection(); void setChannel(std::shared_ptr channel); messages::LimitedQueueSnapshot getMessagesSnapshot(); @@ -97,6 +99,7 @@ public: void clearMessages(); boost::signals2::signal mouseDown; + boost::signals2::signal selectionChanged; protected: virtual void resizeEvent(QResizeEvent *) override; diff --git a/src/widgets/chatwidget.cpp b/src/widgets/chatwidget.cpp index d5afe70f2..d9ed67163 100644 --- a/src/widgets/chatwidget.cpp +++ b/src/widgets/chatwidget.cpp @@ -74,9 +74,6 @@ ChatWidget::ChatWidget(ChannelManager &_channelManager, NotebookPage *parent) // CTRL+R: Change Channel ezShortcut(this, "CTRL+R", &ChatWidget::doChangeChannel); -// CTRL+C: Copy -// ezShortcut(this, "CTRL+B", &ChatWidget::doCopy); - #ifndef NDEBUG // F12: Toggle message spawning ezShortcut(this, "ALT+Q", &ChatWidget::doToggleMessageSpawning); @@ -90,6 +87,11 @@ ChatWidget::ChatWidget(ChannelManager &_channelManager, NotebookPage *parent) this->input.textInput.installEventFilter(parent); this->view.mouseDown.connect([this](QMouseEvent *) { this->giveFocus(Qt::MouseFocusReason); }); + this->view.selectionChanged.connect([this]() { + if (view.hasSelection()) { + this->input.clearSelection(); + } + }); QTimer *timer = new QTimer(this); connect(timer, &QTimer::timeout, this, &ChatWidget::test); diff --git a/src/widgets/chatwidget.hpp b/src/widgets/chatwidget.hpp index 93edee5f4..b468520d5 100644 --- a/src/widgets/chatwidget.hpp +++ b/src/widgets/chatwidget.hpp @@ -39,6 +39,8 @@ class NotebookPage; // Each sub-element has a reference to the parent Chat Widget class ChatWidget : public BaseWidget { + friend class ChatWidgetInput; + Q_OBJECT public: diff --git a/src/widgets/chatwidgetinput.cpp b/src/widgets/chatwidgetinput.cpp index b752111d7..8c782d20a 100644 --- a/src/widgets/chatwidgetinput.cpp +++ b/src/widgets/chatwidgetinput.cpp @@ -161,15 +161,22 @@ ChatWidgetInput::ChatWidgetInput(ChatWidget *_chatWidget, EmoteManager &emoteMan notebook->previousTab(); } } else if (event->key() == Qt::Key_C && event->modifiers() == Qt::ControlModifier) { - event->accept(); - - this->chatWidget->doCopy(); + if (this->chatWidget->view.hasSelection()) { + this->chatWidget->doCopy(); + event->accept(); + } } }); this->textLengthVisibleChangedConnection = SettingsManager::getInstance().showMessageLength.valueChanged.connect( [this](const bool &value) { this->textLengthLabel.setHidden(!value); }); + + QObject::connect(&this->textInput, &QTextEdit::copyAvailable, [this](bool available) { + if (available) { + this->chatWidget->view.clearSelection(); + } + }); } ChatWidgetInput::~ChatWidgetInput() @@ -177,6 +184,16 @@ ChatWidgetInput::~ChatWidgetInput() this->textLengthVisibleChangedConnection.disconnect(); } +void ChatWidgetInput::clearSelection() +{ + QTextCursor c = this->textInput.textCursor(); + + c.setPosition(c.position()); + c.setPosition(c.position(), QTextCursor::KeepAnchor); + + this->textInput.setTextCursor(c); +} + void ChatWidgetInput::refreshTheme() { QPalette palette; diff --git a/src/widgets/chatwidgetinput.hpp b/src/widgets/chatwidgetinput.hpp index ebf5b7637..bad7b590f 100644 --- a/src/widgets/chatwidgetinput.hpp +++ b/src/widgets/chatwidgetinput.hpp @@ -29,6 +29,8 @@ public: ChatWidgetInput(ChatWidget *_chatWidget, EmoteManager &, WindowManager &); ~ChatWidgetInput(); + void clearSelection(); + protected: virtual void paintEvent(QPaintEvent *) override; virtual void resizeEvent(QResizeEvent *) override;