mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-12 13:00:01 -08:00
Merge e540126056 into df74917cb0
This commit is contained in:
commit
a37a494ce7
12 changed files with 464 additions and 131 deletions
|
|
@ -15,9 +15,58 @@
|
|||
#include <QtGlobal>
|
||||
#include <libcockatrice/filters/filter_tree.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
/**
|
||||
* This widget provides a graphical control element for the CardFilter::Attr::AttrColor filters applied to the filter
|
||||
* model.
|
||||
* @brief Information about the behaviour of a filter mode.
|
||||
*/
|
||||
struct FilterModeInfo
|
||||
{
|
||||
// When a color symbol is enabled, add filters of this type. Skipped if equal to CardFilter::Type::TypeEnd.
|
||||
CardFilter::Type includeType;
|
||||
|
||||
// When a color symbol is disabled, add filters of this type. Skipped if equal to CardFilter::Type::TypeEnd.
|
||||
CardFilter::Type excludeType;
|
||||
|
||||
// The attribute to filter for when adding the filters.
|
||||
CardFilter::Attr attr;
|
||||
};
|
||||
|
||||
/** @brief Return information about the given filter mode. */
|
||||
static FilterModeInfo getFilterModeInfo(FilterMode filterMode)
|
||||
{
|
||||
switch (filterMode) {
|
||||
case FilterMode::Includes:
|
||||
return {CardFilter::Type::TypeOr, CardFilter::Type::TypeEnd, CardFilter::Attr::AttrColor};
|
||||
case FilterMode::Excludes:
|
||||
return {CardFilter::Type::TypeAndNot, CardFilter::Type::TypeEnd, CardFilter::Attr::AttrColor};
|
||||
case FilterMode::IncludeExclude:
|
||||
return {CardFilter::Type::TypeOr, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColor};
|
||||
case FilterMode::ExactMatch:
|
||||
return {CardFilter::Type::TypeAnd, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColor};
|
||||
case FilterMode::ColorIdentity:
|
||||
return {CardFilter::Type::TypeEnd, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColorIdentity};
|
||||
case FilterMode::Custom:
|
||||
case FilterMode::End:
|
||||
break;
|
||||
}
|
||||
return {CardFilter::Type::TypeEnd, CardFilter::Type::TypeEnd, CardFilter::Attr::AttrEnd};
|
||||
}
|
||||
|
||||
/** @brief Remove the filters that apply to the given color and attribute from the given model. */
|
||||
static void removeFilters(FilterTreeModel *filterModel, QChar color, CardFilter::Attr attr)
|
||||
{
|
||||
for (const CardFilter *filter : filterModel->getFiltersOfType(attr)) {
|
||||
if (filter->term() == color) {
|
||||
filterModel->removeFilter(filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
/**
|
||||
* This widget provides a graphical control element for the CardFilter::Attr::AttrColor and
|
||||
* CardFilter::Attr::AttrColorIdentity 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
|
||||
*/
|
||||
|
|
@ -59,11 +108,25 @@ 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 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);
|
||||
|
||||
if (currentMode == FilterMode::Custom) {
|
||||
addCustomFilterModeItem();
|
||||
}
|
||||
|
||||
modeComboBox->setToolTip(tr("How selected and unselected colors are combined in the filter"));
|
||||
modeComboBox->setAccessibleName(tr("Color filter mode"));
|
||||
|
||||
// Restore current mode
|
||||
const int index = modeComboBox->findData(QVariant::fromValue(currentMode));
|
||||
|
|
@ -74,6 +137,28 @@ void VisualDatabaseDisplayColorFilterWidget::retranslateUi()
|
|||
modeComboBox->blockSignals(false);
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayColorFilterWidget::setFilterMode(FilterMode filterMode)
|
||||
{
|
||||
int index = modeComboBox->findData(QVariant::fromValue(filterMode));
|
||||
|
||||
if (index < 0 && filterMode == FilterMode::Custom) {
|
||||
index = modeComboBox->count();
|
||||
addCustomFilterModeItem();
|
||||
}
|
||||
|
||||
if (index >= 0) {
|
||||
modeComboBox->setCurrentIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayColorFilterWidget::addCustomFilterModeItem()
|
||||
{
|
||||
int 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);
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayColorFilterWidget::handleColorToggled(QChar color, bool active)
|
||||
{
|
||||
if (active) {
|
||||
|
|
@ -85,74 +170,24 @@ void VisualDatabaseDisplayColorFilterWidget::handleColorToggled(QChar color, boo
|
|||
|
||||
void VisualDatabaseDisplayColorFilterWidget::addFilter(QChar color)
|
||||
{
|
||||
QString colorString = color;
|
||||
QString typeStr;
|
||||
FilterModeInfo info = getFilterModeInfo(currentMode);
|
||||
|
||||
// Remove previous filters
|
||||
removeFilters(filterModel, color, info.attr);
|
||||
|
||||
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) {
|
||||
case FilterMode::ExactMatch:
|
||||
filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrColor));
|
||||
break;
|
||||
|
||||
case FilterMode::Includes:
|
||||
filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeOr, CardFilter::Attr::AttrColor));
|
||||
break;
|
||||
|
||||
case FilterMode::IncludeExclude:
|
||||
filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeOr, CardFilter::Attr::AttrColor));
|
||||
break;
|
||||
if (info.includeType != CardFilter::Type::TypeEnd) {
|
||||
filterModel->addFilter(new CardFilter(color, info.includeType, info.attr));
|
||||
}
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayColorFilterWidget::removeFilter(QChar color)
|
||||
{
|
||||
QString colorString = color;
|
||||
FilterModeInfo info = getFilterModeInfo(currentMode);
|
||||
|
||||
// Remove inclusion filters
|
||||
QList<const CardFilter *> allColorFilters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor);
|
||||
QList<const CardFilter *> matchingFilters;
|
||||
removeFilters(filterModel, color, info.attr);
|
||||
|
||||
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) {
|
||||
case FilterMode::ExactMatch:
|
||||
filterModel->addFilter(
|
||||
new CardFilter(colorString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColor));
|
||||
break;
|
||||
|
||||
case FilterMode::IncludeExclude:
|
||||
filterModel->addFilter(
|
||||
new CardFilter(colorString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColor));
|
||||
break;
|
||||
|
||||
case FilterMode::Includes:
|
||||
// No exclusion in Includes mode
|
||||
break;
|
||||
// Add exclusion filters if the mode demands it.
|
||||
if (info.excludeType != CardFilter::Type::TypeEnd) {
|
||||
filterModel->addFilter(new CardFilter(color, info.excludeType, info.attr));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -169,6 +204,7 @@ void VisualDatabaseDisplayColorFilterWidget::updateFilterMode()
|
|||
filterModel->filterTree()->blockSignals(true);
|
||||
|
||||
filterModel->clearFiltersOfType(CardFilter::Attr::AttrColor);
|
||||
filterModel->clearFiltersOfType(CardFilter::Attr::AttrColorIdentity);
|
||||
|
||||
const QList<ManaSymbolWidget *> manaSymbolWidgets = findChildren<ManaSymbolWidget *>();
|
||||
|
||||
|
|
@ -211,52 +247,94 @@ QList<QChar> VisualDatabaseDisplayColorFilterWidget::getActiveColors()
|
|||
|
||||
void VisualDatabaseDisplayColorFilterWidget::syncWithFilterModel()
|
||||
{
|
||||
QList<const CardFilter *> allColorFilters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor);
|
||||
// Determine the correct currentMode from the filter model by finding which modes
|
||||
// are not possible due to the model containing (a combination of) filters that
|
||||
// that mode cannot add.
|
||||
constexpr int modeCount = static_cast<int>(FilterMode::End);
|
||||
bool modeImpossible[modeCount] = {};
|
||||
|
||||
QList<ManaSymbolWidget *> manaSymbolWidgets = findChildren<ManaSymbolWidget *>();
|
||||
QList<const CardFilter *> filters;
|
||||
filters.append(filterModel->getFiltersOfType(CardFilter::Attr::AttrColor));
|
||||
filters.append(filterModel->getFiltersOfType(CardFilter::Attr::AttrColorIdentity));
|
||||
|
||||
for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) {
|
||||
bool found = false;
|
||||
for (const CardFilter *filter : allColorFilters) {
|
||||
if (manaSymbolWidget->getSymbolChar() == filter->term()) {
|
||||
switch (currentMode) {
|
||||
case FilterMode::ExactMatch:
|
||||
switch (filter->type()) {
|
||||
case CardFilter::Type::TypeAnd:
|
||||
setManaSymbolActive(filter->term().at(0), true);
|
||||
break;
|
||||
default:
|
||||
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;
|
||||
for (int i = 0; i < modeCount; ++i) {
|
||||
FilterModeInfo modeInfo = getFilterModeInfo(static_cast<FilterMode>(i));
|
||||
|
||||
// Remove the modes that cannot create one of the filters.
|
||||
for (const CardFilter *filter : filters) {
|
||||
if (filter->attr() != modeInfo.attr ||
|
||||
(filter->type() != modeInfo.includeType && filter->type() != modeInfo.excludeType)) {
|
||||
modeImpossible[i] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
setManaSymbolActive(manaSymbolWidget->getSymbolChar(), false);
|
||||
// Modes that have both an include and exclude filter should always have a filter for each color.
|
||||
if (modeInfo.includeType != CardFilter::Type::TypeEnd && modeInfo.excludeType != CardFilter::Type::TypeEnd &&
|
||||
!modeImpossible[i]) {
|
||||
for (const QChar &color : QString("WUBRG")) {
|
||||
int count = 0;
|
||||
for (const CardFilter *filter : filters) {
|
||||
count += filter->term() == color;
|
||||
}
|
||||
if (count != 1) {
|
||||
modeImpossible[i] = true;
|
||||
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();
|
||||
addCustomFilterModeItem();
|
||||
}
|
||||
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::Type::TypeEnd && modeInfo.excludeType != CardFilter::Type::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;
|
||||
}
|
||||
}
|
||||
|
||||
manaSymbolWidget->setColorActive(useExclude ? !found : found);
|
||||
manaSymbolWidget->setDisabled(currentMode == FilterMode::Custom);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,9 +40,14 @@ private:
|
|||
|
||||
enum class FilterMode
|
||||
{
|
||||
ExactMatch, // Only selected colors are included, all others are excluded.
|
||||
Includes, // Include selected colors (OR condition).
|
||||
IncludeExclude // Include selected colors (OR) and exclude unselected colors (AND NOT).
|
||||
Includes = 0, // Include selected colors (OR condition).
|
||||
Excludes, // Exclude selected colors (AND NOT).
|
||||
IncludeExclude, // Include selected colors (OR) and exclude unselected colors (AND NOT).
|
||||
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 AND NOT for each
|
||||
// unselected color).
|
||||
Custom, // The color filters do not match any of the above modes. Not included in the combo box.
|
||||
End
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(FilterMode)
|
||||
|
|
@ -54,11 +59,13 @@ class VisualDatabaseDisplayColorFilterWidget : public QWidget
|
|||
public:
|
||||
explicit VisualDatabaseDisplayColorFilterWidget(QWidget *parent, FilterTreeModel *filterModel);
|
||||
void retranslateUi();
|
||||
void setFilterMode(FilterMode filterMode);
|
||||
|
||||
signals:
|
||||
void filterModeChanged(FilterMode filterMode);
|
||||
|
||||
private slots:
|
||||
void addCustomFilterModeItem();
|
||||
void handleColorToggled(QChar color, bool active);
|
||||
void addFilter(QChar color);
|
||||
void removeFilter(QChar color);
|
||||
|
|
|
|||
|
|
@ -160,6 +160,7 @@ VisualDatabaseDisplayWidget::VisualDatabaseDisplayWidget(QWidget *parent,
|
|||
connect(clearFilterWidget, &QToolButton::clicked, this, [this] {
|
||||
filterModel->blockSignals(true);
|
||||
filterModel->filterTree()->blockSignals(true);
|
||||
colorFilterWidget->setFilterMode(FilterMode::Includes);
|
||||
filterModel->clear();
|
||||
filterModel->blockSignals(false);
|
||||
filterModel->filterTree()->blockSignals(false);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue