mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
fixed ctrl+c to copy text
This commit is contained in:
parent
9d671ac873
commit
ab641abd9c
9 changed files with 66 additions and 17 deletions
|
@ -141,13 +141,16 @@ bool MessageRef::layout(int width, bool enableEmoteMargins)
|
||||||
int width = 0;
|
int width = 0;
|
||||||
|
|
||||||
std::vector<short> &charWidths = word.getCharacterWidthCache();
|
std::vector<short> &charWidths = word.getCharacterWidthCache();
|
||||||
|
int charOffset = 0;
|
||||||
|
|
||||||
for (int i = 2; i <= text.length(); i++) {
|
for (int i = 2; i <= text.length(); i++) {
|
||||||
if ((width = width + charWidths[i - 1]) + MARGIN_LEFT > right) {
|
if ((width = width + charWidths[i - 1]) + MARGIN_LEFT > right) {
|
||||||
QString mid = text.mid(start, i - start - 1);
|
QString mid = text.mid(start, i - start - 1);
|
||||||
|
|
||||||
_wordParts.push_back(WordPart(word, MARGIN_LEFT, y, width, word.getHeight(),
|
_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();
|
y += metrics.height();
|
||||||
|
|
||||||
|
@ -162,7 +165,7 @@ bool MessageRef::layout(int width, bool enableEmoteMargins)
|
||||||
width = metrics.width(mid);
|
width = metrics.width(mid);
|
||||||
|
|
||||||
_wordParts.push_back(WordPart(word, MARGIN_LEFT, y - word.getHeight(), width,
|
_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;
|
x = width + MARGIN_LEFT + spaceWidth;
|
||||||
|
|
||||||
lineHeight = word.getHeight();
|
lineHeight = word.getHeight();
|
||||||
|
|
|
@ -15,11 +15,13 @@ WordPart::WordPart(Word &word, int x, int y, int lineNumber, const QString ©
|
||||||
, _height(word.getHeight())
|
, _height(word.getHeight())
|
||||||
, _lineNumber(lineNumber)
|
, _lineNumber(lineNumber)
|
||||||
, _trailingSpace(!word.getCopyText().isEmpty() && word.hasTrailingSpace() & allowTrailingSpace)
|
, _trailingSpace(!word.getCopyText().isEmpty() && word.hasTrailingSpace() & allowTrailingSpace)
|
||||||
|
, wordCharOffset(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
WordPart::WordPart(Word &word, int x, int y, int width, int height, int lineNumber,
|
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)
|
: _word(word)
|
||||||
, _copyText(copyText)
|
, _copyText(copyText)
|
||||||
, _text(customText)
|
, _text(customText)
|
||||||
|
@ -29,6 +31,7 @@ WordPart::WordPart(Word &word, int x, int y, int width, int height, int lineNumb
|
||||||
, _height(height)
|
, _height(height)
|
||||||
, _lineNumber(lineNumber)
|
, _lineNumber(lineNumber)
|
||||||
, _trailingSpace(!word.getCopyText().isEmpty() && word.hasTrailingSpace() & allowTrailingSpace)
|
, _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;
|
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 messages
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
|
|
@ -15,7 +15,8 @@ public:
|
||||||
bool allowTrailingSpace = true);
|
bool allowTrailingSpace = true);
|
||||||
|
|
||||||
WordPart(Word &getWord, int getX, int getY, int getWidth, int getHeight, int _lineNumber,
|
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;
|
const Word &getWord() const;
|
||||||
int getWidth() const;
|
int getWidth() const;
|
||||||
|
@ -32,6 +33,7 @@ public:
|
||||||
const QString &getText() const;
|
const QString &getText() const;
|
||||||
int getLineNumber() const;
|
int getLineNumber() const;
|
||||||
int getCharacterLength() const;
|
int getCharacterLength() const;
|
||||||
|
short getCharacterWidth(int index) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Word &_word;
|
Word &_word;
|
||||||
|
@ -47,6 +49,7 @@ private:
|
||||||
int _lineNumber;
|
int _lineNumber;
|
||||||
|
|
||||||
bool _trailingSpace;
|
bool _trailingSpace;
|
||||||
|
int wordCharOffset;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace messages
|
} // namespace messages
|
||||||
|
|
|
@ -258,6 +258,18 @@ QString ChannelView::getSelectedText()
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ChannelView::hasSelection()
|
||||||
|
{
|
||||||
|
return !this->selection.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelView::clearSelection()
|
||||||
|
{
|
||||||
|
this->selection = Selection();
|
||||||
|
layoutMessages();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
messages::LimitedQueueSnapshot<SharedMessageRef> ChannelView::getMessagesSnapshot()
|
messages::LimitedQueueSnapshot<SharedMessageRef> ChannelView::getMessagesSnapshot()
|
||||||
{
|
{
|
||||||
return this->messages.getSnapshot();
|
return this->messages.getSnapshot();
|
||||||
|
@ -338,6 +350,8 @@ void ChannelView::setSelection(const SelectionItem &start, const SelectionItem &
|
||||||
// selections
|
// selections
|
||||||
this->selection = Selection(start, end);
|
this->selection = Selection(start, end);
|
||||||
|
|
||||||
|
this->selectionChanged();
|
||||||
|
|
||||||
// qDebug() << min.messageIndex << ":" << min.charIndex << " " << max.messageIndex << ":"
|
// qDebug() << min.messageIndex << ":" << min.charIndex << " " << max.messageIndex << ":"
|
||||||
// << max.charIndex;
|
// << max.charIndex;
|
||||||
}
|
}
|
||||||
|
@ -552,10 +566,8 @@ void ChannelView::drawMessageSelection(QPainter &painter, messages::MessageRef *
|
||||||
if (part.getWord().isText()) {
|
if (part.getWord().isText()) {
|
||||||
int offset = this->selection.min.charIndex - charIndex;
|
int offset = this->selection.min.charIndex - charIndex;
|
||||||
|
|
||||||
std::vector<short> &characterWidth = part.getWord().getCharacterWidthCache();
|
|
||||||
|
|
||||||
for (int j = 0; j < offset; j++) {
|
for (int j = 0; j < offset; j++) {
|
||||||
rect.setLeft(rect.left() + characterWidth[j]);
|
rect.setLeft(rect.left() + part.getCharacterWidth(j));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isSingleWord) {
|
if (isSingleWord) {
|
||||||
|
@ -564,7 +576,7 @@ void ChannelView::drawMessageSelection(QPainter &painter, messages::MessageRef *
|
||||||
rect.setRight(part.getX());
|
rect.setRight(part.getX());
|
||||||
|
|
||||||
for (int j = 0; j < offset + length; j++) {
|
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);
|
painter.fillRect(rect, selectionColor);
|
||||||
|
@ -616,14 +628,12 @@ void ChannelView::drawMessageSelection(QPainter &painter, messages::MessageRef *
|
||||||
if (part.getWord().isText()) {
|
if (part.getWord().isText()) {
|
||||||
int offset = this->selection.min.charIndex - charIndex;
|
int offset = this->selection.min.charIndex - charIndex;
|
||||||
|
|
||||||
std::vector<short> &characterWidth = part.getWord().getCharacterWidthCache();
|
|
||||||
|
|
||||||
int length = (this->selection.max.charIndex - charIndex) - offset;
|
int length = (this->selection.max.charIndex - charIndex) - offset;
|
||||||
|
|
||||||
rect.setRight(part.getX());
|
rect.setRight(part.getX());
|
||||||
|
|
||||||
for (int j = 0; j < offset + length; j++) {
|
for (int j = 0; j < offset + length; j++) {
|
||||||
rect.setRight(rect.right() + characterWidth[j]);
|
rect.setRight(rect.right() + part.getCharacterWidth(j));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (this->selection.max.charIndex == charIndex) {
|
if (this->selection.max.charIndex == charIndex) {
|
||||||
|
|
|
@ -89,6 +89,8 @@ public:
|
||||||
void updateGifEmotes();
|
void updateGifEmotes();
|
||||||
ScrollBar &getScrollBar();
|
ScrollBar &getScrollBar();
|
||||||
QString getSelectedText();
|
QString getSelectedText();
|
||||||
|
bool hasSelection();
|
||||||
|
void clearSelection();
|
||||||
|
|
||||||
void setChannel(std::shared_ptr<Channel> channel);
|
void setChannel(std::shared_ptr<Channel> channel);
|
||||||
messages::LimitedQueueSnapshot<messages::SharedMessageRef> getMessagesSnapshot();
|
messages::LimitedQueueSnapshot<messages::SharedMessageRef> getMessagesSnapshot();
|
||||||
|
@ -97,6 +99,7 @@ public:
|
||||||
void clearMessages();
|
void clearMessages();
|
||||||
|
|
||||||
boost::signals2::signal<void(QMouseEvent *)> mouseDown;
|
boost::signals2::signal<void(QMouseEvent *)> mouseDown;
|
||||||
|
boost::signals2::signal<void()> selectionChanged;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void resizeEvent(QResizeEvent *) override;
|
virtual void resizeEvent(QResizeEvent *) override;
|
||||||
|
|
|
@ -74,9 +74,6 @@ ChatWidget::ChatWidget(ChannelManager &_channelManager, NotebookPage *parent)
|
||||||
// CTRL+R: Change Channel
|
// CTRL+R: Change Channel
|
||||||
ezShortcut(this, "CTRL+R", &ChatWidget::doChangeChannel);
|
ezShortcut(this, "CTRL+R", &ChatWidget::doChangeChannel);
|
||||||
|
|
||||||
// CTRL+C: Copy
|
|
||||||
// ezShortcut(this, "CTRL+B", &ChatWidget::doCopy);
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
// F12: Toggle message spawning
|
// F12: Toggle message spawning
|
||||||
ezShortcut(this, "ALT+Q", &ChatWidget::doToggleMessageSpawning);
|
ezShortcut(this, "ALT+Q", &ChatWidget::doToggleMessageSpawning);
|
||||||
|
@ -90,6 +87,11 @@ ChatWidget::ChatWidget(ChannelManager &_channelManager, NotebookPage *parent)
|
||||||
this->input.textInput.installEventFilter(parent);
|
this->input.textInput.installEventFilter(parent);
|
||||||
|
|
||||||
this->view.mouseDown.connect([this](QMouseEvent *) { this->giveFocus(Qt::MouseFocusReason); });
|
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);
|
QTimer *timer = new QTimer(this);
|
||||||
connect(timer, &QTimer::timeout, this, &ChatWidget::test);
|
connect(timer, &QTimer::timeout, this, &ChatWidget::test);
|
||||||
|
|
|
@ -39,6 +39,8 @@ class NotebookPage;
|
||||||
// Each sub-element has a reference to the parent Chat Widget
|
// Each sub-element has a reference to the parent Chat Widget
|
||||||
class ChatWidget : public BaseWidget
|
class ChatWidget : public BaseWidget
|
||||||
{
|
{
|
||||||
|
friend class ChatWidgetInput;
|
||||||
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -161,15 +161,22 @@ ChatWidgetInput::ChatWidgetInput(ChatWidget *_chatWidget, EmoteManager &emoteMan
|
||||||
notebook->previousTab();
|
notebook->previousTab();
|
||||||
}
|
}
|
||||||
} else if (event->key() == Qt::Key_C && event->modifiers() == Qt::ControlModifier) {
|
} else if (event->key() == Qt::Key_C && event->modifiers() == Qt::ControlModifier) {
|
||||||
event->accept();
|
if (this->chatWidget->view.hasSelection()) {
|
||||||
|
this->chatWidget->doCopy();
|
||||||
this->chatWidget->doCopy();
|
event->accept();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this->textLengthVisibleChangedConnection =
|
this->textLengthVisibleChangedConnection =
|
||||||
SettingsManager::getInstance().showMessageLength.valueChanged.connect(
|
SettingsManager::getInstance().showMessageLength.valueChanged.connect(
|
||||||
[this](const bool &value) { this->textLengthLabel.setHidden(!value); });
|
[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()
|
ChatWidgetInput::~ChatWidgetInput()
|
||||||
|
@ -177,6 +184,16 @@ ChatWidgetInput::~ChatWidgetInput()
|
||||||
this->textLengthVisibleChangedConnection.disconnect();
|
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()
|
void ChatWidgetInput::refreshTheme()
|
||||||
{
|
{
|
||||||
QPalette palette;
|
QPalette palette;
|
||||||
|
|
|
@ -29,6 +29,8 @@ public:
|
||||||
ChatWidgetInput(ChatWidget *_chatWidget, EmoteManager &, WindowManager &);
|
ChatWidgetInput(ChatWidget *_chatWidget, EmoteManager &, WindowManager &);
|
||||||
~ChatWidgetInput();
|
~ChatWidgetInput();
|
||||||
|
|
||||||
|
void clearSelection();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void paintEvent(QPaintEvent *) override;
|
virtual void paintEvent(QPaintEvent *) override;
|
||||||
virtual void resizeEvent(QResizeEvent *) override;
|
virtual void resizeEvent(QResizeEvent *) override;
|
||||||
|
|
Loading…
Reference in a new issue