From 2425ddbd2c3069ba1f4b2f7506f71711a87a8c74 Mon Sep 17 00:00:00 2001 From: hemirt Date: Sun, 9 Jul 2017 00:09:02 +0200 Subject: [PATCH] Implement basic tab autocomplete (#75) --- chatterino.pro | 3 +- src/widgets/chatwidgetinput.cpp | 13 ++-- src/widgets/chatwidgetinput.hpp | 2 +- src/widgets/resizingtextedit.cpp | 113 +++++++++++++++++++++++++++++++ src/widgets/resizingtextedit.hpp | 48 ++++--------- 5 files changed, 138 insertions(+), 41 deletions(-) create mode 100644 src/widgets/resizingtextedit.cpp diff --git a/chatterino.pro b/chatterino.pro index 22922e9b2..69691f24c 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -94,7 +94,8 @@ SOURCES += \ src/ircaccount.cpp \ src/widgets/accountpopup.cpp \ src/messagefactory.cpp \ - src/widgets/basewidget.cpp + src/widgets/basewidget.cpp \ + src/widgets/resizingtextedit.cpp HEADERS += \ src/asyncexec.hpp \ diff --git a/src/widgets/chatwidgetinput.cpp b/src/widgets/chatwidgetinput.cpp index 5cb34fb52..3cb52312c 100644 --- a/src/widgets/chatwidgetinput.cpp +++ b/src/widgets/chatwidgetinput.cpp @@ -43,17 +43,18 @@ ChatWidgetInput::ChatWidgetInput(ChatWidget *_chatWidget) connect(&textInput, &ResizingTextEdit::textChanged, this, &ChatWidgetInput::editTextChanged); this->refreshTheme(); - this->setMessageLengthVisisble(SettingsManager::getInstance().showMessageLength.get()); + this->setMessageLengthVisible(SettingsManager::getInstance().showMessageLength.get()); QStringList list; - list.append("asd"); + /*list.append("asd"); list.append("asdf"); list.append("asdg"); list.append("asdh"); - +*/ + list << "Kappa" << "asd" << "asdf" << "asdg"; QCompleter *completer = new QCompleter(list, &this->textInput); - completer->setWidget(&textInput); + this->textInput.setCompleter(completer); this->textInput.keyPressed.connect([this /*, completer*/](QKeyEvent *event) { if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) { @@ -76,7 +77,7 @@ ChatWidgetInput::ChatWidgetInput(ChatWidget *_chatWidget) /* XXX(pajlada): FIX THIS QObject::connect(&Settings::getInstance().showMessageLength, &BoolSetting::valueChanged, this, - &ChatWidgetInput::setMessageLengthVisisble); + &ChatWidgetInput::setMessageLengthVisible); */ } @@ -86,7 +87,7 @@ ChatWidgetInput::~ChatWidgetInput() QObject::disconnect( &Settings::getInstance().getShowMessageLength(), &BoolSetting::valueChanged, this, - &ChatWidgetInput::setMessageLengthVisisble); + &ChatWidgetInput::setMessageLengthVisible); */ } diff --git a/src/widgets/chatwidgetinput.hpp b/src/widgets/chatwidgetinput.hpp index f7fb9e5de..2d0a3e389 100644 --- a/src/widgets/chatwidgetinput.hpp +++ b/src/widgets/chatwidgetinput.hpp @@ -42,7 +42,7 @@ private: virtual void refreshTheme() override; private slots: - void setMessageLengthVisisble(bool value) + void setMessageLengthVisible(bool value) { textLengthLabel.setHidden(!value); } diff --git a/src/widgets/resizingtextedit.cpp b/src/widgets/resizingtextedit.cpp new file mode 100644 index 000000000..deb008fa3 --- /dev/null +++ b/src/widgets/resizingtextedit.cpp @@ -0,0 +1,113 @@ +#include "widgets/resizingtextedit.hpp" + +ResizingTextEdit::ResizingTextEdit() + : keyPressed() +{ + auto sizePolicy = this->sizePolicy(); + sizePolicy.setHeightForWidth(true); + sizePolicy.setVerticalPolicy(QSizePolicy::Preferred); + this->setSizePolicy(sizePolicy); + + QObject::connect(this, &QTextEdit::textChanged, this, &QWidget::updateGeometry); +} + +QSize ResizingTextEdit::sizeHint() const +{ + return QSize(this->width(), this->heightForWidth(this->width())); +} + +bool ResizingTextEdit::hasHeightForWidth() const +{ + return true; +} + +int ResizingTextEdit::heightForWidth(int) const +{ + auto margins = this->contentsMargins(); + + return margins.top() + document()->size().height() + margins.bottom() + 5; +} + +QString ResizingTextEdit::textUnderCursor() const +{ + QTextCursor tc = textCursor(); + tc.select(QTextCursor::WordUnderCursor); + return tc.selectedText(); +} + +void ResizingTextEdit::keyPressEvent(QKeyEvent *event) +{ + event->ignore(); + + keyPressed(event); + + if (event->key() == Qt::Key_Tab) { + QString currentCompletionPrefix = this->textUnderCursor(); + if (!currentCompletionPrefix.size()) { + return; + } + if (!this->nextCompletion) { + // first selection + this->completer->setCompletionPrefix(currentCompletionPrefix); + this->nextCompletion = true; + this->completer->complete(); + return; + } + + // scrolling through selections + if (!this->completer->setCurrentRow(this->completer->currentRow() + 1)) { + // wrap over and start again + this->completer->setCurrentRow(0); + } + this->completer->complete(); + return; + } + // (hemirt) + // this resets the selection in the completion list, it should probably only trigger on actual + // chat input (space, character) and not on every key input (pressing alt for example) + this->nextCompletion = false; + + if (!event->isAccepted()) { + QTextEdit::keyPressEvent(event); + } +} + +void ResizingTextEdit::setCompleter(QCompleter *c) +{ + if (this->completer) { + QObject::disconnect(this->completer, 0, this, 0); + } + + this->completer = c; + + if (!this->completer) { + return; + } + + this->completer->setWidget(this); + this->completer->setCompletionMode(QCompleter::InlineCompletion); + this->completer->setCaseSensitivity(Qt::CaseInsensitive); + /*QObject::connect(this->completer, SIGNAL(highlighted(QString)), this, + SLOT(insertCompletion(QString))); +*/ + QObject::connect(completer, + static_cast(&QCompleter::highlighted), + this, &ResizingTextEdit::insertCompletion); +} + +void ResizingTextEdit::insertCompletion(const QString &completion) +{ + if (this->completer->widget() != this) { + return; + } + + QTextCursor tc = this->textCursor(); + tc.select(QTextCursor::SelectionType::WordUnderCursor); + tc.insertText(completion); + this->setTextCursor(tc); +} + +QCompleter *ResizingTextEdit::getCompleter() const +{ + return this->completer; +} diff --git a/src/widgets/resizingtextedit.hpp b/src/widgets/resizingtextedit.hpp index 24279c0c8..a786a356a 100644 --- a/src/widgets/resizingtextedit.hpp +++ b/src/widgets/resizingtextedit.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -7,45 +8,26 @@ class ResizingTextEdit : public QTextEdit { public: - ResizingTextEdit() - : keyPressed() - { - auto sizePolicy = this->sizePolicy(); - sizePolicy.setHeightForWidth(true); - sizePolicy.setVerticalPolicy(QSizePolicy::Preferred); - this->setSizePolicy(sizePolicy); + ResizingTextEdit(); - QObject::connect(this, &QTextEdit::textChanged, this, &QWidget::updateGeometry); - } + QSize sizeHint() const override; - QSize sizeHint() const override - { - return QSize(this->width(), this->heightForWidth(this->width())); - } - - bool hasHeightForWidth() const override - { - return true; - } + bool hasHeightForWidth() const override; boost::signals2::signal keyPressed; + void setCompleter(QCompleter *c); + QCompleter *getCompleter() const; + protected: - int heightForWidth(int) const override - { - auto margins = this->contentsMargins(); + int heightForWidth(int) const override; + void keyPressEvent(QKeyEvent *event) override; - return margins.top() + document()->size().height() + margins.bottom() + 5; - } +private: + QCompleter *completer = nullptr; + QString textUnderCursor() const; + bool nextCompletion = false; - void keyPressEvent(QKeyEvent *event) override - { - event->ignore(); - - keyPressed(event); - - if (!event->isAccepted()) { - QTextEdit::keyPressEvent(event); - } - } +private slots: + void insertCompletion(const QString &completion); };