Use shared multi-select Essence dropdown in Visual Database filters

This commit is contained in:
Christian Daniel Jensen 2026-11-03 12:14:26 -07:00
parent 39eb983fe9
commit abe4dc2b8f

View file

@ -1,27 +1,17 @@
#include "visual_database_display_color_filter_widget.h" #include "visual_database_display_color_filter_widget.h"
#include "../cards/additional_info/mana_symbol_widget.h" #include "../cards/additional_info/essence_filter_picker.h"
#include "filter_tree_model.h" #include "filter_tree_model.h"
#include "libcockatrice/filters/filter_card.h" #include "libcockatrice/filters/filter_card.h"
#include <libcockatrice/card/essence_types.h>
#include <QAbstractItemModel>
#include <QComboBox> #include <QComboBox>
#include <QDebug>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QPersistentModelIndex>
#include <QSharedPointer> #include <QSharedPointer>
#include <QString> #include <QString>
#include <QVariant> #include <QVariant>
#include <QtGlobal> #include <libcockatrice/card/essence_types.h>
#include <libcockatrice/filters/filter_tree.h> #include <libcockatrice/filters/filter_tree.h>
/**
* This widget provides a graphical control element for the CardFilter::Attr::AttrColor filters applied to the filter
* model.
* @param parent The Qt Widget that this widget will parent to
* @param _filterModel The filter model that this widget will manipulate
*/
VisualDatabaseDisplayColorFilterWidget::VisualDatabaseDisplayColorFilterWidget(QWidget *parent, VisualDatabaseDisplayColorFilterWidget::VisualDatabaseDisplayColorFilterWidget(QWidget *parent,
FilterTreeModel *_filterModel) FilterTreeModel *_filterModel)
: QWidget(parent), filterModel(_filterModel), layout(new QHBoxLayout(this)) : QWidget(parent), filterModel(_filterModel), layout(new QHBoxLayout(this))
@ -30,20 +20,13 @@ VisualDatabaseDisplayColorFilterWidget::VisualDatabaseDisplayColorFilterWidget(Q
layout->setSpacing(3); layout->setSpacing(3);
layout->setContentsMargins(0, 0, 0, 0); layout->setContentsMargins(0, 0, 0, 0);
// All fifteen Continuum Universes Essence types are filterable. // Share the same compact Essence selection UI as Visual Deck Storage.
// Never fall back to MTG's five-color WUBRG control. N is colorless. // A 15-icon horizontal row cannot fit the database filter toolbar.
for (const QChar essence : Essence::symbols()) { essencePicker = new EssenceFilterPicker(this);
auto *manaSymbol = new ManaSymbolWidget(this, QString(essence), false, true); layout->addWidget(essencePicker);
manaSymbol->setFixedSize(22, 22);
manaSymbol->setToolTip(essence == QChar('N') ? tr("N — Colorless Essence")
: tr("Essence %1").arg(essence));
layout->addWidget(manaSymbol); connect(essencePicker, &EssenceFilterPicker::essenceToggled, this,
&VisualDatabaseDisplayColorFilterWidget::handleColorToggled);
// Connect the color toggled signal
connect(manaSymbol, &ManaSymbolWidget::colorToggled, this,
&VisualDatabaseDisplayColorFilterWidget::handleColorToggled);
}
modeComboBox = new QComboBox(this); modeComboBox = new QComboBox(this);
layout->addWidget(modeComboBox); layout->addWidget(modeComboBox);
@ -54,108 +37,77 @@ VisualDatabaseDisplayColorFilterWidget::VisualDatabaseDisplayColorFilterWidget(Q
connect(filterModel, &FilterTreeModel::layoutChanged, this, connect(filterModel, &FilterTreeModel::layoutChanged, this,
[this]() { syncDebouncer.call([this] { syncWithFilterModel(); }); }); [this]() { syncDebouncer.call([this] { syncWithFilterModel(); }); });
// Call retranslateUi to set the initial text
retranslateUi(); retranslateUi();
syncWithFilterModel();
} }
void VisualDatabaseDisplayColorFilterWidget::retranslateUi() void VisualDatabaseDisplayColorFilterWidget::retranslateUi()
{ {
essencePicker->retranslateUi();
modeComboBox->blockSignals(true); modeComboBox->blockSignals(true);
modeComboBox->clear(); modeComboBox->clear();
modeComboBox->addItem(tr("Exact match"), QVariant::fromValue(FilterMode::ExactMatch)); modeComboBox->addItem(tr("Exact match"), QVariant::fromValue(FilterMode::ExactMatch));
modeComboBox->addItem(tr("Includes"), QVariant::fromValue(FilterMode::Includes)); modeComboBox->addItem(tr("Includes"), QVariant::fromValue(FilterMode::Includes));
modeComboBox->addItem(tr("Include / Exclude"), QVariant::fromValue(FilterMode::IncludeExclude)); modeComboBox->addItem(tr("Include / Exclude"), QVariant::fromValue(FilterMode::IncludeExclude));
modeComboBox->setToolTip(tr("How selected and unselected Essence types are combined in the filter")); modeComboBox->setToolTip(tr("How selected and unselected Essence types are combined in the filter"));
// Restore current mode
const int index = modeComboBox->findData(QVariant::fromValue(currentMode)); const int index = modeComboBox->findData(QVariant::fromValue(currentMode));
if (index >= 0) { if (index >= 0) {
modeComboBox->setCurrentIndex(index); modeComboBox->setCurrentIndex(index);
} }
modeComboBox->blockSignals(false); modeComboBox->blockSignals(false);
} }
void VisualDatabaseDisplayColorFilterWidget::handleColorToggled(QChar color, bool active) void VisualDatabaseDisplayColorFilterWidget::handleColorToggled(QChar essence, bool active)
{ {
if (active) { if (active) {
addFilter(color); addFilter(essence);
} else { } else {
removeFilter(color); removeFilter(essence);
} }
} }
void VisualDatabaseDisplayColorFilterWidget::addFilter(QChar color) void VisualDatabaseDisplayColorFilterWidget::addFilter(QChar essence)
{ {
QString colorString = color; const QString essenceString(essence);
QString typeStr; const QList<const CardFilter *> filters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor);
for (const CardFilter *filter : filters) {
// Remove previous filters if (filter->term() == essenceString) {
filterModel->removeFilter(filter);
QList<const CardFilter *> allColorFilters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor);
QList<const CardFilter *> matchingFilters;
for (const CardFilter *filter : allColorFilters) {
if (filter->term() == color) {
matchingFilters.append(filter);
} }
} }
for (const CardFilter *filter : matchingFilters) {
filterModel->removeFilter(filter);
}
// Add actual filter
switch (currentMode) { switch (currentMode) {
case FilterMode::ExactMatch: case FilterMode::ExactMatch:
filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrColor)); filterModel->addFilter(
new CardFilter(essenceString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrColor));
break; break;
case FilterMode::Includes: case FilterMode::Includes:
filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeOr, CardFilter::Attr::AttrColor));
break;
case FilterMode::IncludeExclude: case FilterMode::IncludeExclude:
filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeOr, CardFilter::Attr::AttrColor)); filterModel->addFilter(
new CardFilter(essenceString, CardFilter::Type::TypeOr, CardFilter::Attr::AttrColor));
break; break;
} }
} }
void VisualDatabaseDisplayColorFilterWidget::removeFilter(QChar color) void VisualDatabaseDisplayColorFilterWidget::removeFilter(QChar essence)
{ {
QString colorString = color; const QString essenceString(essence);
const QList<const CardFilter *> filters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor);
// Remove inclusion filters for (const CardFilter *filter : filters) {
QList<const CardFilter *> allColorFilters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor); if (filter->term() == essenceString) {
QList<const CardFilter *> matchingFilters; filterModel->removeFilter(filter);
for (const CardFilter *filter : allColorFilters) {
if (filter->term() == color) {
matchingFilters.append(filter);
} }
} }
for (const CardFilter *filter : matchingFilters) {
filterModel->removeFilter(filter);
}
// Add exclusion filters if the mode demands it
switch (currentMode) { switch (currentMode) {
case FilterMode::ExactMatch: case FilterMode::ExactMatch:
filterModel->addFilter(
new CardFilter(colorString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColor));
break;
case FilterMode::IncludeExclude: case FilterMode::IncludeExclude:
filterModel->addFilter( filterModel->addFilter(
new CardFilter(colorString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColor)); new CardFilter(essenceString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColor));
break; break;
case FilterMode::Includes: case FilterMode::Includes:
// No exclusion in Includes mode
break; break;
} }
} }
@ -174,10 +126,9 @@ void VisualDatabaseDisplayColorFilterWidget::updateFilterMode()
filterModel->clearFiltersOfType(CardFilter::Attr::AttrColor); filterModel->clearFiltersOfType(CardFilter::Attr::AttrColor);
const QList<ManaSymbolWidget *> manaSymbolWidgets = findChildren<ManaSymbolWidget *>(); const QSet<QChar> selected = essencePicker->activeEssences();
for (const QChar essence : Essence::symbols()) {
for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) { handleColorToggled(essence, selected.contains(essence));
handleColorToggled(manaSymbolWidget->getSymbolChar(), manaSymbolWidget->isColorActive());
} }
filterModel->blockSignals(false); filterModel->blockSignals(false);
@ -188,79 +139,44 @@ void VisualDatabaseDisplayColorFilterWidget::updateFilterMode()
emit filterModeChanged(currentMode); emit filterModeChanged(currentMode);
} }
void VisualDatabaseDisplayColorFilterWidget::setManaSymbolActive(QChar color, bool active) void VisualDatabaseDisplayColorFilterWidget::setEssenceActive(QChar essence, bool active)
{ {
QList<ManaSymbolWidget *> manaSymbolWidgets = findChildren<ManaSymbolWidget *>(); essencePicker->setEssenceActive(essence, active);
for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) {
if (manaSymbolWidget->getSymbolChar() == color) {
manaSymbolWidget->setColorActive(active);
}
}
} }
QList<QChar> VisualDatabaseDisplayColorFilterWidget::getActiveColors() QList<QChar> VisualDatabaseDisplayColorFilterWidget::getActiveColors()
{ {
QList<QChar> activeColors; QList<QChar> result;
QList<ManaSymbolWidget *> manaSymbolWidgets = findChildren<ManaSymbolWidget *>(); const QSet<QChar> selected = essencePicker->activeEssences();
for (const QChar essence : Essence::symbols()) {
for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) { if (selected.contains(essence)) {
if (manaSymbolWidget->isColorActive()) { result.append(essence);
activeColors.append(manaSymbolWidget->getSymbolChar());
} }
} }
return result;
return activeColors;
} }
void VisualDatabaseDisplayColorFilterWidget::syncWithFilterModel() void VisualDatabaseDisplayColorFilterWidget::syncWithFilterModel()
{ {
QList<const CardFilter *> allColorFilters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor); const QList<const CardFilter *> filters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor);
QList<ManaSymbolWidget *> manaSymbolWidgets = findChildren<ManaSymbolWidget *>(); for (const QChar essence : Essence::symbols()) {
bool selected = false;
for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) { for (const CardFilter *filter : filters) {
bool found = false; if (filter->term() != QString(essence)) {
for (const CardFilter *filter : allColorFilters) { continue;
if (manaSymbolWidget->getSymbolChar() == filter->term()) { }
switch (currentMode) { if (currentMode == FilterMode::ExactMatch) {
case FilterMode::ExactMatch: selected = filter->type() == CardFilter::Type::TypeAnd;
switch (filter->type()) { } else {
case CardFilter::Type::TypeAnd: selected = filter->type() == CardFilter::Type::TypeOr;
setManaSymbolActive(filter->term().at(0), true); }
break; if (selected) {
default: break;
setManaSymbolActive(filter->term().at(0), false);
break;
}
break;
case FilterMode::Includes:
switch (filter->type()) {
case CardFilter::Type::TypeOr:
setManaSymbolActive(filter->term().at(0), true);
break;
default:
setManaSymbolActive(filter->term().at(0), false);
break;
}
break;
case FilterMode::IncludeExclude:
switch (filter->type()) {
case CardFilter::Type::TypeOr:
setManaSymbolActive(filter->term().at(0), true);
break;
default:
setManaSymbolActive(filter->term().at(0), false);
break;
}
break;
}
found = true;
} }
} }
// Signals are blocked inside the picker; loading saved filters must
if (!found) { // not mutate the FilterTreeModel again.
setManaSymbolActive(manaSymbolWidget->getSymbolChar(), false); setEssenceActive(essence, selected);
}
} }
} }