From f2e4aa3c3432a468c76d4948884a8361fac69a43 Mon Sep 17 00:00:00 2001 From: Jurriaan van den Berg Date: Mon, 2 Nov 2026 14:20:04 +0100 Subject: [PATCH] Rederive the mode from saved filters, added Custom mode --- ...l_database_display_color_filter_widget.cpp | 204 +++++++++++------- ...ual_database_display_color_filter_widget.h | 9 +- 2 files changed, 130 insertions(+), 83 deletions(-) diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp index ccc65078d..2fb328bf0 100644 --- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp +++ b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp @@ -15,6 +15,39 @@ #include #include +/** + * @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 * model. @@ -59,16 +92,17 @@ void VisualDatabaseDisplayColorFilterWidget::retranslateUi() modeComboBox->blockSignals(true); modeComboBox->clear(); - modeComboBox->addItem(tr("Exact match"), QVariant::fromValue(FilterMode::ExactMatch)); modeComboBox->addItem(tr("Includes"), QVariant::fromValue(FilterMode::Includes)); modeComboBox->addItem(tr("Excludes"), QVariant::fromValue(FilterMode::Excludes)); 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->setItemData(0, tr("Cards being exactly of the selected colors"), Qt::ToolTipRole); - modeComboBox->setItemData(1, tr("Cards containing any of the selected colors"), Qt::ToolTipRole); - modeComboBox->setItemData(2, tr("Cards containing none of the selected colors"), Qt::ToolTipRole); - modeComboBox->setItemData(3, tr("Cards containing any of the selected colors and none of the unselected colors"), Qt::ToolTipRole); + modeComboBox->setItemData(0, 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 any of the selected colors and none of the unselected colors"), + 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->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) { for (const CardFilter *filter : filterModel->getFiltersOfType(attr)) { @@ -102,59 +137,24 @@ static void removeFilters(FilterTreeModel *filterModel, QChar color, CardFilter: void VisualDatabaseDisplayColorFilterWidget::addFilter(QChar color) { - switch (currentMode) { - case FilterMode::ExactMatch: - removeFilters(filterModel, color, CardFilter::Attr::AttrColor); - filterModel->addFilter(new CardFilter(color, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrColor)); - break; + FilterModeInfo info = getFilterModeInfo(currentMode); - case FilterMode::Includes: - removeFilters(filterModel, color, CardFilter::Attr::AttrColor); - filterModel->addFilter(new CardFilter(color, CardFilter::Type::TypeOr, CardFilter::Attr::AttrColor)); - break; + removeFilters(filterModel, color, info.attr); - case FilterMode::Excludes: - removeFilters(filterModel, color, CardFilter::Attr::AttrColor); - 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; + if (info.includeType != CardFilter::TypeEnd) { + filterModel->addFilter(new CardFilter(color, info.includeType, info.attr)); } } void VisualDatabaseDisplayColorFilterWidget::removeFilter(QChar color) { - // Add exclusion filters if the mode demands it - switch (currentMode) { - case FilterMode::ExactMatch: - removeFilters(filterModel, color, CardFilter::Attr::AttrColor); - filterModel->addFilter(new CardFilter(color, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColor)); - break; + FilterModeInfo info = getFilterModeInfo(currentMode); - case FilterMode::Includes: - removeFilters(filterModel, color, CardFilter::Attr::AttrColor); - break; + removeFilters(filterModel, color, info.attr); - case FilterMode::Excludes: - removeFilters(filterModel, color, CardFilter::Attr::AttrColor); - break; - - 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; + // Add exclusion filters if the mode demands it. + if (info.excludeType != CardFilter::TypeEnd) { + filterModel->addFilter(new CardFilter(color, info.excludeType, info.attr)); } } @@ -214,42 +214,86 @@ QList VisualDatabaseDisplayColorFilterWidget::getActiveColors() void VisualDatabaseDisplayColorFilterWidget::syncWithFilterModel() { - QList allColorFilters = filterModel->getFiltersOfType( - currentMode == FilterMode::ColorIdentity - ? CardFilter::Attr::AttrColorIdentity - : CardFilter::Attr::AttrColor); + // Determine the correct currentMode from the filter model by finding which modes + // are not possible due to the model containing filters that that mode cannot add. + constexpr int modeCount = static_cast(FilterMode::End); + bool modeImpossible[modeCount] = {}; - QList manaSymbolWidgets = findChildren(); + QList filters; + filters.append(filterModel->getFiltersOfType(CardFilter::AttrColor)); + filters.append(filterModel->getFiltersOfType(CardFilter::AttrColorIdentity)); - for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) { - QChar symbol = manaSymbolWidget->getSymbolChar(); - bool found = currentMode == FilterMode::ColorIdentity; - for (const CardFilter *filter : allColorFilters) { - if (symbol == filter->term()) { - switch (currentMode) { - case FilterMode::ExactMatch: - if (filter->type() == CardFilter::Type::TypeAnd) - found = true; - break; - case FilterMode::Includes: - case FilterMode::IncludeExclude: - if (filter->type() == CardFilter::Type::TypeOr) - found = true; - break; - case FilterMode::Excludes: - if (filter->type() == CardFilter::Type::TypeAndNot) - found = true; - break; - case FilterMode::ColorIdentity: - if (filter->type() == CardFilter::Type::TypeAndNot) - found = false; - break; + if (filters.empty()) { + // Remove the modes that should always contain filters. + for (int i = 0; i < modeCount; ++i) { + FilterModeInfo modeInfo = getFilterModeInfo(static_cast(i)); + if (modeInfo.includeType != CardFilter::TypeEnd && modeInfo.excludeType != CardFilter::TypeEnd) { + modeImpossible[i] = true; + } + } + } else { + // Remove the modes that cannot create one of the filters. + for (const CardFilter *filter : filters) { + for (int i = 0; i < modeCount; ++i) { + FilterModeInfo modeInfo = getFilterModeInfo(static_cast(i)); + if (filter->attr() != modeInfo.attr || + (filter->type() != modeInfo.includeType && filter->type() != modeInfo.excludeType)) { + modeImpossible[i] = true; } - 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(currentMode)] || currentMode == FilterMode::Custom) { + for (int i = 0; i < modeCount; ++i) { + if (!modeImpossible[i] || i == static_cast(FilterMode::Custom)) { + currentMode = static_cast(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()) { + 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); } } diff --git a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_color_filter_widget.h b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_color_filter_widget.h index fa9c32204..68012d6e8 100644 --- a/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_color_filter_widget.h +++ b/cockatrice/src/interface/widgets/visual_database_display/visual_database_display_color_filter_widget.h @@ -40,11 +40,14 @@ private: enum class FilterMode { - ExactMatch, // Only selected colors are included, all others are excluded. - Includes, // Include selected colors (OR condition). + Includes = 0, // Include selected colors (OR condition). Excludes, // Exclude selected 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)