mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-06 01:53:25 -08:00
[UI] Fix auto-completion acceptance on Space/Tab/Enter (#7466)
* [UI] Fix auto-completion acceptance on Space/Tab/Enter * [UI] Accept current completion when no item selected in popup * [UI] Also accept completion on focus out when none selected * [UI] Keep focus in chat on Tab completion acceptance * [UI] Prevent Tab from moving focus when no completion popup * [UI] Refocus on Tab when completing * [UI] Let focusOut handle Tab completion acceptance * [UI] Restore Tab behavior to match original (handle in focusOut) * [UI] Defer refocus on Tab to avoid focus chain issues * [UI] Auto-select first completion match in popup * [UI] Auto-select first match when completer popup resets * Revert "[UI] Auto-select first match when completer popup resets" This reverts commitc7a3de3595. * Revert "[UI] Auto-select first completion match in popup" This reverts commitae0dfb8622. * [UI] Ensure completion selection updates on model changes * Revert "[UI] Ensure completion selection updates on model changes" This reverts commit686bbef5b2. * [UI] Highlight the selected completion in chat popups The card completer's above-variant moved the current row with NoUpdate, so the delegate never painted the selection border, and it used Select which accumulated highlights while navigating. Use ClearAndSelect so only the current row is highlighted and the old one is cleared. The mention popup opened with no current row at all, so nothing was highlighted and there was no visual hint of what Enter would insert. Select the row currentCompletion() uses, and install a delegate that mirrors the active highlight into the inactive group so the selection stays visible when the transient popup is not the active window. --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
parent
b8e8f2c738
commit
be2c16eca5
3 changed files with 128 additions and 19 deletions
|
|
@ -1,9 +1,11 @@
|
|||
#include "line_edit_completer.h"
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QAbstractItemView>
|
||||
#include <QChar>
|
||||
#include <QCompleter>
|
||||
#include <QFocusEvent>
|
||||
#include <QItemSelectionModel>
|
||||
#include <QKeyEvent>
|
||||
#include <QModelIndex>
|
||||
#include <QVariant>
|
||||
|
|
@ -48,37 +50,80 @@ void LineEditCompleter::focusOutEvent(QFocusEvent *e)
|
|||
{
|
||||
LineEditUnfocusable::focusOutEvent(e);
|
||||
|
||||
// Only commit the highlighted completion when focus moves away via Tab.
|
||||
// Commit completion when focus moves away via Tab if popup is visible.
|
||||
// Other focus losses (e.g. the unfocus shortcut / Escape) must simply close
|
||||
// the popup without inserting anything.
|
||||
if (e->reason() != Qt::TabFocusReason) {
|
||||
hideCompleterPopups();
|
||||
bool popupWasVisible = false;
|
||||
for (auto &info : completers) {
|
||||
if (info.completer->popup()->isVisible()) {
|
||||
popupWasVisible = true;
|
||||
const QModelIndex currentIndex = info.completer->popup()->currentIndex();
|
||||
QString completionText;
|
||||
if (currentIndex.isValid()) {
|
||||
completionText = currentIndex.data().toString();
|
||||
} else {
|
||||
completionText = info.completer->currentCompletion();
|
||||
}
|
||||
if (!completionText.isEmpty()) {
|
||||
insertCompletion(info.completer, completionText);
|
||||
}
|
||||
}
|
||||
}
|
||||
hideCompleterPopups();
|
||||
|
||||
if (popupWasVisible && e->reason() == Qt::TabFocusReason) {
|
||||
// Refocus the edit so Tab doesn't move focus away
|
||||
// Use a queued connection to ensure focus is restored after the focus change completes
|
||||
QMetaObject::invokeMethod(this, "setFocus", Qt::QueuedConnection);
|
||||
e->accept();
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto &info : completers) {
|
||||
if (!info.completer->popup()->isVisible()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const QModelIndex currentIndex = info.completer->popup()->currentIndex();
|
||||
if (currentIndex.isValid()) {
|
||||
insertCompletion(info.completer, currentIndex.data().toString());
|
||||
}
|
||||
if (popupWasVisible) {
|
||||
return;
|
||||
}
|
||||
|
||||
hideCompleterPopups();
|
||||
}
|
||||
|
||||
void LineEditCompleter::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
LineEditUnfocusable::keyPressEvent(event);
|
||||
|
||||
if (event->key() == Qt::Key_Escape) {
|
||||
hideCompleterPopups();
|
||||
if (hasVisibleCompleterPopup()) {
|
||||
event->ignore();
|
||||
hideCompleterPopups();
|
||||
return;
|
||||
}
|
||||
LineEditUnfocusable::keyPressEvent(event);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter || event->key() == Qt::Key_Space) {
|
||||
for (auto &info : completers) {
|
||||
if (info.completer->popup()->isVisible()) {
|
||||
event->ignore();
|
||||
const QModelIndex currentIndex = info.completer->popup()->currentIndex();
|
||||
QString completionText;
|
||||
if (currentIndex.isValid()) {
|
||||
completionText = currentIndex.data().toString();
|
||||
} else {
|
||||
completionText = info.completer->currentCompletion();
|
||||
}
|
||||
if (!completionText.isEmpty()) {
|
||||
insertCompletion(info.completer, completionText);
|
||||
}
|
||||
hideCompleterPopups();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (event->key() == Qt::Key_Tab) {
|
||||
// Let Tab proceed normally; focusOutEvent will handle completion if popup is visible
|
||||
LineEditUnfocusable::keyPressEvent(event);
|
||||
return;
|
||||
}
|
||||
|
||||
LineEditUnfocusable::keyPressEvent(event);
|
||||
|
||||
QString textValue = text();
|
||||
int cursorPos = cursorPosition();
|
||||
|
||||
|
|
@ -132,6 +177,17 @@ void LineEditCompleter::keyPressEvent(QKeyEvent *event)
|
|||
}
|
||||
|
||||
active->completer->complete();
|
||||
|
||||
// The popup opens without a current row, so nothing is highlighted and there
|
||||
// is no visual indication of what Enter will insert. Select the row that
|
||||
// currentCompletion() would use so the current mention stays visible.
|
||||
auto *completionModel = active->completer->completionModel();
|
||||
const int currentRow = active->completer->currentRow();
|
||||
if (currentRow >= 0 && currentRow < completionModel->rowCount()) {
|
||||
active->completer->popup()->selectionModel()->setCurrentIndex(
|
||||
completionModel->index(currentRow, active->completer->completionColumn()),
|
||||
QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
|
||||
}
|
||||
}
|
||||
|
||||
void LineEditCompleter::insertCompletion(const QString &completion)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue