Don't commit on ESC, switch to enum for triggers

Took 6 seconds
This commit is contained in:
Lukas Brübach 2026-08-10 21:52:12 +02:00
parent fdf2b069d7
commit f717b8687d
5 changed files with 95 additions and 66 deletions

View file

@ -1291,13 +1291,13 @@ void TabGame::createMessageDock(bool bReplay)
connect(this, &TabGame::chatMessageSent, game->getGameEventHandler(), &GameEventHandler::handleChatMessageSent);
mentionModel = new QStringListModel(autocompleteUserList, sayEdit);
mentionCompleter = createMentionCompleter(mentionModel, sayEdit);
sayEdit->addCompleter(mentionCompleter, "@");
sayEdit->addCompleter(mentionCompleter, CompleterTrigger::Mention);
auto *cardDatabaseModel = new CardDatabaseModel(CardDatabaseManager::getInstance(), false, sayEdit);
auto *displayModel = new CardDatabaseDisplayModel(sayEdit);
displayModel->setSourceModel(cardDatabaseModel);
const CardCompleterSetup cardSetup = createCardCompleter(displayModel, sayEdit);
sayEdit->addCompleter(cardSetup.completer, "[[");
sayEdit->addCompleter(cardSetup.completer, CompleterTrigger::Card);
connect(sayEdit, &LineEditCompleter::cardPartialChanged, this, [this, cardSetup](const QString &text) {
cardSetup.searchModel->updateSearchResults(text);

View file

@ -147,13 +147,13 @@ TabRoom::TabRoom(TabSupervisor *_tabSupervisor,
mentionModel = new QStringListModel(autocompleteUserList, sayEdit);
mentionCompleter = createMentionCompleter(mentionModel, sayEdit);
sayEdit->addCompleter(mentionCompleter, "@");
sayEdit->addCompleter(mentionCompleter, CompleterTrigger::Mention);
auto *cardDatabaseModel = new CardDatabaseModel(CardDatabaseManager::getInstance(), false, sayEdit);
auto *displayModel = new CardDatabaseDisplayModel(sayEdit);
displayModel->setSourceModel(cardDatabaseModel);
const CardCompleterSetup cardSetup = createCardCompleter(displayModel, sayEdit);
sayEdit->addCompleter(cardSetup.completer, "[[");
sayEdit->addCompleter(cardSetup.completer, CompleterTrigger::Card);
connect(sayEdit, &LineEditCompleter::cardPartialChanged, this, [this, cardSetup](const QString &text) {
cardSetup.searchModel->updateSearchResults(text);

View file

@ -25,7 +25,7 @@ struct ManaColor
QColor text;
};
ManaColor manaColour(QChar symbol)
ManaColor manaColor(QChar symbol)
{
switch (symbol.unicode()) {
case 'W':
@ -74,7 +74,7 @@ QColor CardCompleterDelegate::accentForColors(const QString &colors)
return QColor(100, 115, 135);
}
return manaColour(*seen.begin()).fill;
return manaColor(*seen.begin()).fill;
}
// ---------------------------------------------------------------------------
@ -144,7 +144,7 @@ void CardCompleterDelegate::drawManaSymbol(QPainter *p, QPoint centre, const QSt
const QString label = isNumeric ? QString::number(numVal) : symbol;
const ManaColor mc =
(symbol.length() == 1 && QString("WUBRG").contains(symbol)) ? manaColour(symbol[0]) : manaColour(QChar('X'));
(symbol.length() == 1 && QString("WUBRG").contains(symbol)) ? manaColor(symbol[0]) : manaColor(QChar('X'));
QPainterPath circle;
circle.addEllipse(pip);

View file

@ -8,7 +8,7 @@ LineEditCompleter::LineEditCompleter(QWidget *parent) : LineEditUnfocusable(pare
{
}
void LineEditCompleter::addCompleter(QCompleter *c, const QString &trigger)
void LineEditCompleter::addCompleter(QCompleter *c, CompleterTrigger trigger)
{
c->setWidget(this);
c->setCompletionMode(QCompleter::PopupCompletion);
@ -40,7 +40,14 @@ void LineEditCompleter::focusOutEvent(QFocusEvent *e)
{
LineEditUnfocusable::focusOutEvent(e);
// Commit the highlighted completion so that tabbing away still applies it
// Only commit the highlighted completion when focus moves away via Tab.
// Other focus losses (e.g. the unfocus shortcut / Escape) must simply close
// the popup without inserting anything.
if (e->reason() != Qt::TabFocusReason) {
hideCompleterPopups();
return;
}
for (auto &info : completers) {
if (!info.completer->popup()->isVisible()) {
continue;
@ -71,22 +78,32 @@ void LineEditCompleter::keyPressEvent(QKeyEvent *event)
QString prefix;
for (auto &info : completers) {
if (info.trigger == "@") {
int triggerPos = textValue.lastIndexOf("@", cursorPos - 1);
if (triggerPos != -1 && (triggerPos == 0 || textValue[triggerPos - 1].isSpace())) {
active = &info;
prefix = textValue.mid(triggerPos + 1, cursorPos - (triggerPos + 1));
bool triggered = false;
switch (info.trigger) {
case CompleterTrigger::Mention: {
int triggerPos = textValue.lastIndexOf("@", cursorPos - 1);
if (triggerPos != -1 && (triggerPos == 0 || textValue[triggerPos - 1].isSpace())) {
triggered = true;
// Keep the "@" so the prefix matches the "@"-prefixed mention model entries.
prefix = textValue.mid(triggerPos, cursorPos - triggerPos);
}
break;
}
} else if (info.trigger == "[[") {
int triggerPos = textValue.lastIndexOf("[[", cursorPos - 1);
int closePos = textValue.indexOf("]]", triggerPos + 2);
if (triggerPos != -1 && (closePos == -1 || closePos >= cursorPos)) {
active = &info;
prefix = textValue.mid(triggerPos + 2, cursorPos - (triggerPos + 2));
case CompleterTrigger::Card: {
int triggerPos = textValue.lastIndexOf("[[", cursorPos - 1);
int closePos = textValue.indexOf("]]", triggerPos + 2);
if (triggerPos != -1 && (closePos == -1 || closePos >= cursorPos)) {
triggered = true;
prefix = textValue.mid(triggerPos + 2, cursorPos - (triggerPos + 2));
}
break;
}
}
if (triggered) {
active = &info;
break;
}
}
if (!active) {
@ -98,9 +115,12 @@ void LineEditCompleter::keyPressEvent(QKeyEvent *event)
active->completer->setCompletionPrefix(prefix);
if (active->trigger == "[[") {
emit cardPartialChanged(prefix);
return;
switch (active->trigger) {
case CompleterTrigger::Card:
emit cardPartialChanged(prefix);
return;
case CompleterTrigger::Mention:
break;
}
active->completer->complete();
@ -126,51 +146,54 @@ void LineEditCompleter::insertCompletion(QCompleter *completer, const QString &c
continue;
}
if (info.trigger == "[[") {
int triggerPos = t.lastIndexOf("[[", pos - 1);
if (triggerPos == -1) {
switch (info.trigger) {
case CompleterTrigger::Card: {
int triggerPos = t.lastIndexOf("[[", pos - 1);
if (triggerPos == -1) {
return;
}
// If an earlier "[[" is still open it also encloses the cursor, so
// replace from its start. Otherwise completing in text such as
// "[[Opt[[Amok" would leave a stray "[[" behind.
int startPos = triggerPos;
for (int searchFrom = triggerPos; searchFrom > 0;) {
const int earlier = t.lastIndexOf("[[", searchFrom - 1);
if (earlier == -1) {
break;
}
const int earlierClose = t.indexOf("]]", earlier + 2);
if (earlierClose != -1 && earlierClose < pos) {
break;
}
startPos = earlier;
searchFrom = earlier;
}
// If the cursor sits inside an already-closed [[...]] pair, replace
// the whole construct instead of leaving a duplicate closing bracket
// behind.
int insertEnd = pos;
const int closePos = t.indexOf("]]", startPos + 2);
if (closePos != -1 && closePos >= pos) {
insertEnd = closePos + 2;
}
QString after = t.mid(insertEnd);
QString replaced = t.left(startPos + 2) + completion + "]] ";
setText(replaced + after);
setCursorPosition(replaced.length());
return;
}
// If an earlier "[[" is still open it also encloses the cursor, so
// replace from its start. Otherwise completing in text such as
// "[[Opt[[Amok" would leave a stray "[[" behind.
int startPos = triggerPos;
for (int searchFrom = triggerPos; searchFrom > 0;) {
const int earlier = t.lastIndexOf("[[", searchFrom - 1);
if (earlier == -1) {
break;
case CompleterTrigger::Mention: {
int triggerPos = t.lastIndexOf("@", pos - 1);
if (triggerPos == -1) {
return;
}
const int earlierClose = t.indexOf("]]", earlier + 2);
if (earlierClose != -1 && earlierClose < pos) {
break;
}
startPos = earlier;
searchFrom = earlier;
setText(t.replace(triggerPos, pos - triggerPos, completion + " "));
setCursorPosition(triggerPos + completion.length() + 1);
return;
}
// If the cursor sits inside an already-closed [[...]] pair, replace
// the whole construct instead of leaving a duplicate closing bracket
// behind.
int insertEnd = pos;
const int closePos = t.indexOf("]]", startPos + 2);
if (closePos != -1 && closePos >= pos) {
insertEnd = closePos + 2;
}
QString after = t.mid(insertEnd);
QString replaced = t.left(startPos + 2) + completion + "]] ";
setText(replaced + after);
setCursorPosition(replaced.length());
return;
}
int triggerPos = t.lastIndexOf("@", pos - 1);
if (triggerPos == -1) {
return;
}
setText(t.replace(triggerPos, pos - triggerPos, completion + " "));
setCursorPosition(triggerPos + completion.length() + 1);
return;
}
}

View file

@ -17,10 +17,16 @@
#include <QString>
#include <QVector>
enum class CompleterTrigger
{
Mention, // "@" prefix, replaced in place with a trailing space.
Card // "[[" prefix, replaced with the completion plus a closing "]] ".
};
struct CompleterInfo
{
QCompleter *completer;
QString trigger; // e.g., "@" or "[["
CompleterTrigger trigger;
};
class LineEditCompleter : public LineEditUnfocusable
@ -43,7 +49,7 @@ protected:
public:
explicit LineEditCompleter(QWidget *parent = nullptr);
void addCompleter(QCompleter *c, const QString &trigger);
void addCompleter(QCompleter *c, CompleterTrigger trigger);
bool hasVisibleCompleterPopup() const;
void hideCompleterPopups();