mirror-chatterino2/src/widgets/helper/resizingtextedit.cpp
Rasmus Karlsson adf3ff3075 Switch some c-style includes to c++-style includes (i.e. stdint.h to
cstdint)

Make MessageElement to a class to fit better with the derived classes.
Make MessageLayoutElement to a class to fit better with the derived
classes.

Remove virtual from override functions

Replace all instances of boost::signals2 with pajlada::Signals. This
lets us properly use clang code model to check for issues.

Add missing virtual destructor to AbstractIrcServer
Add missing virtual destructor to MessageLayoutElement

Remove unused "connectedConnection" connection in TwitchChannel

Fix typo in TrimChannelName function
Fix typo in MessageParseArgs

Replace some raw pointers with unique pointers where it made more sense.
This allowed us to remove some manually written destructors whose only
purpose was to delete that raw pointer.

Reformat: Add namespace comments
Reformat: Add empty empty lines between main namespace beginning and end
Reformat: Re-order includes
Reformat: Fix some includes that used quotes where they should use angle
brackets
Reformat: Replace some typedef's with using's

Filter out more useless warnings
2018-04-03 03:00:34 +02:00

177 lines
4.6 KiB
C++

#include "widgets/helper/resizingtextedit.hpp"
#include "common.hpp"
#include "util/completionmodel.hpp"
ResizingTextEdit::ResizingTextEdit()
{
auto sizePolicy = this->sizePolicy();
sizePolicy.setHeightForWidth(true);
sizePolicy.setVerticalPolicy(QSizePolicy::Preferred);
this->setSizePolicy(sizePolicy);
this->setAcceptRichText(false);
QObject::connect(this, &QTextEdit::textChanged, this, &QWidget::updateGeometry);
this->setFocusPolicy(Qt::ClickFocus);
}
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(bool *hadSpace) const
{
auto currentText = this->toPlainText();
QTextCursor tc = this->textCursor();
auto textUpToCursor = currentText.left(tc.selectionStart());
auto words = textUpToCursor.splitRef(' ');
if (words.size() == 0) {
return QString();
}
bool first = true;
QString lastWord;
for (auto it = words.crbegin(); it != words.crend(); ++it) {
auto word = *it;
if (first && word.isEmpty()) {
first = false;
if (hadSpace != nullptr) {
*hadSpace = true;
}
continue;
}
lastWord = word.toString();
break;
}
if (lastWord.isEmpty()) {
return QString();
}
return lastWord;
}
void ResizingTextEdit::keyPressEvent(QKeyEvent *event)
{
event->ignore();
this->keyPressed.invoke(event);
if (event->key() == Qt::Key_Backtab) {
// Ignore for now. We want to use it for autocomplete later
return;
}
bool doComplete =
event->key() == Qt::Key_Tab && (event->modifiers() & Qt::ControlModifier) == Qt::NoModifier;
if (doComplete) {
// check if there is a completer
if (!this->completer) {
return;
}
QString currentCompletionPrefix = this->textUnderCursor();
// check if there is something to complete
if (!currentCompletionPrefix.size()) {
return;
}
auto *completionModel =
static_cast<chatterino::CompletionModel *>(this->completer->model());
if (!this->completionInProgress) {
// First type pressing tab after modifying a message, we refresh our completion model
this->completer->setModel(completionModel);
completionModel->refresh();
this->completionInProgress = true;
this->completer->setCompletionPrefix(currentCompletionPrefix);
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->completionInProgress = 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(completer,
static_cast<void (QCompleter::*)(const QString &)>(&QCompleter::highlighted),
this, &ResizingTextEdit::insertCompletion);
}
void ResizingTextEdit::insertCompletion(const QString &completion)
{
if (this->completer->widget() != this) {
return;
}
bool hadSpace = false;
auto prefix = this->textUnderCursor(&hadSpace);
int prefixSize = prefix.size();
if (hadSpace) {
++prefixSize;
}
QTextCursor tc = this->textCursor();
tc.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, prefixSize);
tc.insertText(completion);
this->setTextCursor(tc);
}
QCompleter *ResizingTextEdit::getCompleter() const
{
return this->completer;
}