Add FilterComboBox

This helper class is based on QComboBox, which has filtering of items
enabled by default.
It is intended to be used in places where QComboBoxes have a lot of
entries.
For example, the condition, action, or macro selection widgets.
This commit is contained in:
WarmUpTill 2023-07-12 21:10:34 +02:00 committed by WarmUpTill
parent 72a11eedfc
commit 0b2e1b88cc
3 changed files with 114 additions and 0 deletions

View File

@ -257,6 +257,8 @@ target_sources(
src/utils/log-helper.hpp
src/utils/file-selection.cpp
src/utils/file-selection.hpp
src/utils/filter-combo-box.cpp
src/utils/filter-combo-box.hpp
src/utils/filter-selection.cpp
src/utils/filter-selection.hpp
src/utils/macro-list.cpp

View File

@ -0,0 +1,87 @@
#include "filter-combo-box.hpp"
#include "utility.hpp"
#include <QCompleter>
#include <QLineEdit>
#include <QFocusEvent>
namespace advss {
FilterComboBox::FilterComboBox(QWidget *parent, const QString &placehodler)
: QComboBox(parent)
{
// Allow edit for completer but don't add new entries on pressing enter
setEditable(true);
setInsertPolicy(InsertPolicy::NoInsert);
if (!placehodler.isEmpty()) {
lineEdit()->setPlaceholderText(placehodler);
}
setMaxVisibleItems(30);
auto c = completer();
c->setCaseSensitivity(Qt::CaseInsensitive);
c->setFilterMode(Qt::MatchContains);
c->setCompletionMode(QCompleter::PopupCompletion);
connect(c, QOverload<const QModelIndex &>::of(&QCompleter::highlighted),
this, &FilterComboBox::CompleterHighlightChanged);
connect(lineEdit(), &QLineEdit::textChanged, this,
&FilterComboBox::TextChagned);
}
void FilterComboBox::focusOutEvent(QFocusEvent *event)
{
// Reset on invalid selection
if (findText(currentText()) == -1) {
setCurrentIndex(-1);
emit currentIndexChanged(-1);
emit currentTextChanged("");
}
QComboBox::focusOutEvent(event);
_lastCompleterHighlightRow = -1;
}
static int findXthOccurance(QComboBox *list, int count, const QString &value)
{
if (value.isEmpty() || count < 1) {
return -1;
}
const auto size = list->count();
int idx = FindIdxInRagne(list, 0, size, value.toStdString(),
Qt::MatchContains | Qt::MatchFixedString);
if (count == 1) {
return idx;
}
for (int i = 1; i < count; i++) {
idx = FindIdxInRagne(list, idx, size, value.toStdString(),
Qt::MatchContains | Qt::MatchFixedString);
}
return idx;
}
void FilterComboBox::CompleterHighlightChanged(const QModelIndex &index)
{
_lastCompleterHighlightRow = index.row();
const auto text = currentText();
int idx = findXthOccurance(this, _lastCompleterHighlightRow, text);
emit currentIndexChanged(idx);
emit currentTextChanged(text);
}
void FilterComboBox::TextChagned(const QString &text)
{
auto c = completer();
const bool completerActive = c->completionCount() > 0;
int count = completerActive ? _lastCompleterHighlightRow + 1 : 1;
int idx = findXthOccurance(this, count, text);
emit currentIndexChanged(idx);
emit currentTextChanged(text);
}
} // namespace advss

View File

@ -0,0 +1,25 @@
#pragma once
#include <QComboBox>
namespace advss {
// Helper class which enables user to filter possible selections by typing
class FilterComboBox : public QComboBox {
Q_OBJECT
public:
FilterComboBox(QWidget *parent = nullptr,
const QString &placehodler = "");
protected:
void focusOutEvent(QFocusEvent *event) override;
private slots:
void CompleterHighlightChanged(const QModelIndex &);
void TextChagned(const QString &);
private:
int _lastCompleterHighlightRow = -1;
};
} // namespace advss