From bbe438b09a59172589c9a747cf8ead4913471c59 Mon Sep 17 00:00:00 2001 From: BruebachL <44814898+BruebachL@users.noreply.github.com> Date: Fri, 16 Oct 2026 19:01:38 +0200 Subject: [PATCH] [Completer] Highlight popup rows without rewriting the line edit (#7502) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [Completer] Highlight popup rows without rewriting the line edit Selecting a popup row with ClearAndSelect emits selectionChanged, which QCompleter turns into highlighted() and QLineEdit turns into setText(). Since be2c16eca5 (#7466) that rewrites the typed text on every completion reset / arrow-key press (e.g. typing "A" becomes "Axe" and cannot be edited), regressing the 514014dc00 (#7447) fix that used NoUpdate. Add selectWithoutRewrite(), which blocks the selection-model signals while applying ClearAndSelect so the highlight stays visible without touching the line edit, then syncs the preview manually. Route both the above-popup auto-select and Up/Down navigation through it, and handle Up/Down for below-popups too instead of falling through to Qt's rewriting default. Enter/click acceptance via activated() is unchanged. * [Completer] Repaint popup highlight after silent selection change Blocking the selection model's signals also suppresses the view's own selectionChanged/currentChanged repaints, so force a viewport update after restoring signals. Use EnsureVisible to match Qt's normal scroll behaviour. --------- Co-authored-by: Lukas BrĂ¼bach --- .../widgets/utility/card_completer_styler.cpp | 61 ++++++++++++++----- .../widgets/utility/card_completer_styler.h | 1 + 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/cockatrice/src/interface/widgets/utility/card_completer_styler.cpp b/cockatrice/src/interface/widgets/utility/card_completer_styler.cpp index 8aa32556f..5b33303a0 100644 --- a/cockatrice/src/interface/widgets/utility/card_completer_styler.cpp +++ b/cockatrice/src/interface/widgets/utility/card_completer_styler.cpp @@ -133,29 +133,33 @@ bool CardCompleterStyler::handlePopupKeyPress(QKeyEvent *event) return false; } - if (!above) { - return false; - } - auto *popup = completer->popup(); const int rowCount = completer->completionModel()->rowCount(); if (rowCount == 0) { return true; } + // Handle navigation ourselves so arrow keys move the highlight without + // rewriting the line edit. QCompleter's default handling selects with a + // selection change that QLineEdit turns into setText(), which fights the + // user while typing (e.g. typing "A" becomes "Axe" and cannot be edited). // With the popup above the text edit the rows are shown in reverse order and // the closest match is in the bottom-most row. The up arrow then advances // through the list (towards its end at the top of the popup). - const int currentRow = popup->currentIndex().row(); - const int step = (key == Qt::Key_Up) ? -1 : 1; - const int newRow = qBound(0, currentRow + step, rowCount - 1); - - if (newRow != currentRow) { - const QModelIndex newIndex = completer->completionModel()->index(newRow, completer->completionColumn()); - popup->selectionModel()->setCurrentIndex(newIndex, - QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); + const QModelIndex current = popup->currentIndex(); + int newRow; + if (!current.isValid()) { + newRow = (key == Qt::Key_Down) ? 0 : rowCount - 1; + } else { + const int step = (key == Qt::Key_Up) ? -1 : 1; + newRow = qBound(0, current.row() + step, rowCount - 1); + if (newRow == current.row()) { + return true; + } } + selectWithoutRewrite(completer->completionModel()->index(newRow, completer->completionColumn())); + return true; } @@ -218,8 +222,37 @@ void CardCompleterStyler::ensureClosestSelected() const int closestRow = rowCount - 1; if (currentRow != closestRow) { - popup->selectionModel()->setCurrentIndex(completionModel->index(closestRow, completer->completionColumn()), - QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); + selectWithoutRewrite(completionModel->index(closestRow, completer->completionColumn())); + } +} + +// --------------------------------------------------------------------------- + +void CardCompleterStyler::selectWithoutRewrite(const QModelIndex &index) +{ + auto *popup = completer->popup(); + auto *selectionModel = popup->selectionModel(); + + // Changing the popup selection emits selectionChanged, which QCompleter + // turns into highlighted() and QLineEdit turns into setText(). That + // rewrites what the user typed (e.g. "A" becomes "Axe") and fights further + // typing. Block the signals so the highlight and preview move without + // touching the line edit; Enter/click still activates via activated(). + const bool wasBlocked = selectionModel->blockSignals(true); + if (!index.isValid()) { + selectionModel->clear(); + } else { + selectionModel->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); + } + selectionModel->blockSignals(wasBlocked); + popup->viewport()->update(); + + // currentRowChanged was suppressed above, so sync the preview manually. + updatePreview(index); + if (index.isValid()) { + popup->scrollTo(index, QAbstractItemView::EnsureVisible); + } else { + popup->scrollToTop(); } } diff --git a/cockatrice/src/interface/widgets/utility/card_completer_styler.h b/cockatrice/src/interface/widgets/utility/card_completer_styler.h index 2912f7312..04310e676 100644 --- a/cockatrice/src/interface/widgets/utility/card_completer_styler.h +++ b/cockatrice/src/interface/widgets/utility/card_completer_styler.h @@ -55,6 +55,7 @@ private: void applyPopupWidth(); void updateOrientation(); void ensureClosestSelected(); + void selectWithoutRewrite(const QModelIndex &index); bool handlePopupKeyPress(QKeyEvent *event); bool isPopupAboveWidget() const;