Rederive the mode from saved filters, added Custom mode

This commit is contained in:
Jurriaan van den Berg 2026-11-02 14:20:04 +01:00
parent e85e81ce85
commit f2e4aa3c34
2 changed files with 130 additions and 83 deletions

View file

@ -15,6 +15,39 @@
#include <QtGlobal> #include <QtGlobal>
#include <libcockatrice/filters/filter_tree.h> #include <libcockatrice/filters/filter_tree.h>
/**
* @brief Information about the filter mode.
*/
struct FilterModeInfo
{
CardFilter::Type includeType;
CardFilter::Type excludeType;
CardFilter::Attr attr;
};
/**
* @brief Return information about the filter mode.
*/
static FilterModeInfo getFilterModeInfo(FilterMode filterMode)
{
switch (filterMode) {
case FilterMode::Includes:
return {CardFilter::TypeOr, CardFilter::TypeEnd, CardFilter::AttrColor};
case FilterMode::Excludes:
return {CardFilter::TypeAndNot, CardFilter::TypeEnd, CardFilter::AttrColor};
case FilterMode::IncludeExclude:
return {CardFilter::TypeOr, CardFilter::TypeAndNot, CardFilter::AttrColor};
case FilterMode::ExactMatch:
return {CardFilter::TypeAnd, CardFilter::TypeAndNot, CardFilter::AttrColor};
case FilterMode::ColorIdentity:
return {CardFilter::TypeEnd, CardFilter::TypeAndNot, CardFilter::AttrColorIdentity};
case FilterMode::Custom:
case FilterMode::End:
break;
}
return {CardFilter::TypeEnd, CardFilter::TypeEnd, CardFilter::AttrEnd};
}
/** /**
* This widget provides a graphical control element for the CardFilter::Attr::AttrColor filters applied to the filter * This widget provides a graphical control element for the CardFilter::Attr::AttrColor filters applied to the filter
* model. * model.
@ -59,16 +92,17 @@ void VisualDatabaseDisplayColorFilterWidget::retranslateUi()
modeComboBox->blockSignals(true); modeComboBox->blockSignals(true);
modeComboBox->clear(); modeComboBox->clear();
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("Excludes"), QVariant::fromValue(FilterMode::Excludes)); modeComboBox->addItem(tr("Excludes"), QVariant::fromValue(FilterMode::Excludes));
modeComboBox->addItem(tr("Include / Exclude"), QVariant::fromValue(FilterMode::IncludeExclude)); modeComboBox->addItem(tr("Include / Exclude"), QVariant::fromValue(FilterMode::IncludeExclude));
modeComboBox->addItem(tr("Exact match"), QVariant::fromValue(FilterMode::ExactMatch));
modeComboBox->addItem(tr("Color identity"), QVariant::fromValue(FilterMode::ColorIdentity)); modeComboBox->addItem(tr("Color identity"), QVariant::fromValue(FilterMode::ColorIdentity));
modeComboBox->setItemData(0, tr("Cards being exactly of the selected colors"), Qt::ToolTipRole); modeComboBox->setItemData(0, tr("Cards containing any of the selected colors"), Qt::ToolTipRole);
modeComboBox->setItemData(1, tr("Cards containing any of the selected colors"), Qt::ToolTipRole); modeComboBox->setItemData(1, tr("Cards containing none of the selected colors"), Qt::ToolTipRole);
modeComboBox->setItemData(2, tr("Cards containing none of the selected colors"), Qt::ToolTipRole); modeComboBox->setItemData(2, tr("Cards containing any of the selected colors and none of the unselected colors"),
modeComboBox->setItemData(3, tr("Cards containing any of the selected colors and none of the unselected colors"), Qt::ToolTipRole); Qt::ToolTipRole);
modeComboBox->setItemData(3, tr("Cards being exactly of the selected colors"), Qt::ToolTipRole);
modeComboBox->setItemData(4, tr("Cards whose color identity fits within the selected colors"), Qt::ToolTipRole); modeComboBox->setItemData(4, tr("Cards whose color identity fits within the selected colors"), Qt::ToolTipRole);
modeComboBox->setToolTip(tr("How selected and unselected colors are combined in the filter")); modeComboBox->setToolTip(tr("How selected and unselected colors are combined in the filter"));
@ -91,6 +125,7 @@ void VisualDatabaseDisplayColorFilterWidget::handleColorToggled(QChar color, boo
} }
} }
/** @brief TODO */
static void removeFilters(FilterTreeModel *filterModel, QChar color, CardFilter::Attr attr) static void removeFilters(FilterTreeModel *filterModel, QChar color, CardFilter::Attr attr)
{ {
for (const CardFilter *filter : filterModel->getFiltersOfType(attr)) { for (const CardFilter *filter : filterModel->getFiltersOfType(attr)) {
@ -102,59 +137,24 @@ static void removeFilters(FilterTreeModel *filterModel, QChar color, CardFilter:
void VisualDatabaseDisplayColorFilterWidget::addFilter(QChar color) void VisualDatabaseDisplayColorFilterWidget::addFilter(QChar color)
{ {
switch (currentMode) { FilterModeInfo info = getFilterModeInfo(currentMode);
case FilterMode::ExactMatch:
removeFilters(filterModel, color, CardFilter::Attr::AttrColor);
filterModel->addFilter(new CardFilter(color, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrColor));
break;
case FilterMode::Includes: removeFilters(filterModel, color, info.attr);
removeFilters(filterModel, color, CardFilter::Attr::AttrColor);
filterModel->addFilter(new CardFilter(color, CardFilter::Type::TypeOr, CardFilter::Attr::AttrColor));
break;
case FilterMode::Excludes: if (info.includeType != CardFilter::TypeEnd) {
removeFilters(filterModel, color, CardFilter::Attr::AttrColor); filterModel->addFilter(new CardFilter(color, info.includeType, info.attr));
filterModel->addFilter(new CardFilter(color, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColor));
break;
case FilterMode::IncludeExclude:
removeFilters(filterModel, color, CardFilter::Attr::AttrColor);
filterModel->addFilter(new CardFilter(color, CardFilter::Type::TypeOr, CardFilter::Attr::AttrColor));
break;
case FilterMode::ColorIdentity:
removeFilters(filterModel, color, CardFilter::Attr::AttrColorIdentity);
break;
} }
} }
void VisualDatabaseDisplayColorFilterWidget::removeFilter(QChar color) void VisualDatabaseDisplayColorFilterWidget::removeFilter(QChar color)
{ {
// Add exclusion filters if the mode demands it FilterModeInfo info = getFilterModeInfo(currentMode);
switch (currentMode) {
case FilterMode::ExactMatch:
removeFilters(filterModel, color, CardFilter::Attr::AttrColor);
filterModel->addFilter(new CardFilter(color, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColor));
break;
case FilterMode::Includes: removeFilters(filterModel, color, info.attr);
removeFilters(filterModel, color, CardFilter::Attr::AttrColor);
break;
case FilterMode::Excludes: // Add exclusion filters if the mode demands it.
removeFilters(filterModel, color, CardFilter::Attr::AttrColor); if (info.excludeType != CardFilter::TypeEnd) {
break; filterModel->addFilter(new CardFilter(color, info.excludeType, info.attr));
case FilterMode::IncludeExclude:
removeFilters(filterModel, color, CardFilter::Attr::AttrColor);
filterModel->addFilter(new CardFilter(color, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColor));
break;
case FilterMode::ColorIdentity:
removeFilters(filterModel, color, CardFilter::Attr::AttrColorIdentity);
filterModel->addFilter(new CardFilter(color, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColorIdentity));
break;
} }
} }
@ -214,42 +214,86 @@ QList<QChar> VisualDatabaseDisplayColorFilterWidget::getActiveColors()
void VisualDatabaseDisplayColorFilterWidget::syncWithFilterModel() void VisualDatabaseDisplayColorFilterWidget::syncWithFilterModel()
{ {
QList<const CardFilter *> allColorFilters = filterModel->getFiltersOfType( // Determine the correct currentMode from the filter model by finding which modes
currentMode == FilterMode::ColorIdentity // are not possible due to the model containing filters that that mode cannot add.
? CardFilter::Attr::AttrColorIdentity constexpr int modeCount = static_cast<int>(FilterMode::End);
: CardFilter::Attr::AttrColor); bool modeImpossible[modeCount] = {};
QList<ManaSymbolWidget *> manaSymbolWidgets = findChildren<ManaSymbolWidget *>(); QList<const CardFilter *> filters;
filters.append(filterModel->getFiltersOfType(CardFilter::AttrColor));
filters.append(filterModel->getFiltersOfType(CardFilter::AttrColorIdentity));
for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) { if (filters.empty()) {
QChar symbol = manaSymbolWidget->getSymbolChar(); // Remove the modes that should always contain filters.
bool found = currentMode == FilterMode::ColorIdentity; for (int i = 0; i < modeCount; ++i) {
for (const CardFilter *filter : allColorFilters) { FilterModeInfo modeInfo = getFilterModeInfo(static_cast<FilterMode>(i));
if (symbol == filter->term()) { if (modeInfo.includeType != CardFilter::TypeEnd && modeInfo.excludeType != CardFilter::TypeEnd) {
switch (currentMode) { modeImpossible[i] = true;
case FilterMode::ExactMatch: }
if (filter->type() == CardFilter::Type::TypeAnd) }
found = true; } else {
break; // Remove the modes that cannot create one of the filters.
case FilterMode::Includes: for (const CardFilter *filter : filters) {
case FilterMode::IncludeExclude: for (int i = 0; i < modeCount; ++i) {
if (filter->type() == CardFilter::Type::TypeOr) FilterModeInfo modeInfo = getFilterModeInfo(static_cast<FilterMode>(i));
found = true; if (filter->attr() != modeInfo.attr ||
break; (filter->type() != modeInfo.includeType && filter->type() != modeInfo.excludeType)) {
case FilterMode::Excludes: modeImpossible[i] = true;
if (filter->type() == CardFilter::Type::TypeAndNot)
found = true;
break;
case FilterMode::ColorIdentity:
if (filter->type() == CardFilter::Type::TypeAndNot)
found = false;
break;
} }
if (found) }
break; }
}
// If the current mode is not possible with the current filters, set it to the first
// one that is. Switching to and from the custom mode is always possible.
if (modeImpossible[static_cast<int>(currentMode)] || currentMode == FilterMode::Custom) {
for (int i = 0; i < modeCount; ++i) {
if (!modeImpossible[i] || i == static_cast<int>(FilterMode::Custom)) {
currentMode = static_cast<FilterMode>(i);
break;
}
}
}
// Update the combobox. Add a Custom item only if we have a custom filter mode.
int customIndex = modeComboBox->findData(QVariant::fromValue(FilterMode::Custom));
modeComboBox->blockSignals(true);
if (currentMode == FilterMode::Custom) {
if (customIndex < 0) {
customIndex = modeComboBox->count();
modeComboBox->addItem(tr("Custom"), QVariant::fromValue(FilterMode::Custom));
modeComboBox->setItemData(customIndex, tr("Cards matching an unknown combination of color filters"),
Qt::ToolTipRole);
}
modeComboBox->setCurrentIndex(customIndex);
} else {
if (customIndex >= 0) {
modeComboBox->removeItem(customIndex);
}
int index = modeComboBox->findData(QVariant::fromValue(currentMode));
if (index >= 0) {
modeComboBox->setCurrentIndex(index);
}
}
modeComboBox->blockSignals(false);
// Update the mana symbol widgets by looking for the current mode's include or exclude filters.
const FilterModeInfo modeInfo = getFilterModeInfo(currentMode);
const bool useExclude = modeInfo.includeType == CardFilter::TypeEnd && modeInfo.excludeType != CardFilter::TypeEnd;
const CardFilter::Type filterType = useExclude ? modeInfo.excludeType : modeInfo.includeType;
filters = filterModel->getFiltersOfType(modeInfo.attr);
for (ManaSymbolWidget *manaSymbolWidget : findChildren<ManaSymbolWidget *>()) {
bool found = false;
for (const CardFilter *filter : filters) {
if (filter->type() == filterType && manaSymbolWidget->getSymbolChar() == filter->term()) {
found = true;
break;
} }
} }
setManaSymbolActive(manaSymbolWidget->getSymbolChar(), found); manaSymbolWidget->setColorActive(useExclude ? !found : found);
} }
} }

View file

@ -40,11 +40,14 @@ private:
enum class FilterMode enum class FilterMode
{ {
ExactMatch, // Only selected colors are included, all others are excluded. Includes = 0, // Include selected colors (OR condition).
Includes, // Include selected colors (OR condition).
Excludes, // Exclude selected colors (AND NOT). Excludes, // Exclude selected colors (AND NOT).
IncludeExclude, // Include selected colors (OR) and exclude unselected colors (AND NOT). IncludeExclude, // Include selected colors (OR) and exclude unselected colors (AND NOT).
ColorIdentity // Keep cards whose color identity is a subset of the selected colors (stored as ANDNOT for each unselected color). ExactMatch, // Only selected colors are included, all others are excluded.
ColorIdentity, // Keep cards whose color identity is a subset of the selected colors (stored as ANDNOT for each
// unselected color).
Custom, // The filters do not match any of the modes. Not included in the combo box.
End
}; };
Q_DECLARE_METATYPE(FilterMode) Q_DECLARE_METATYPE(FilterMode)