diff --git a/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.cpp b/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.cpp index dd4d1c1f6..e42e93444 100644 --- a/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.cpp +++ b/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.cpp @@ -20,12 +20,17 @@ ManaSymbolWidget::ManaSymbolWidget(QWidget *parent, QString _symbol, bool _isAct &ManaSymbolWidget::updateOpacity); } +void ManaSymbolWidget::toggleSymbol() +{ + setColorActive(!isActive); + emit colorToggled(getSymbolChar(), isActive); +} + void ManaSymbolWidget::setColorActive(bool active) { if (isActive != active) { isActive = active; updateOpacity(); - emit colorToggled(getSymbolChar(), isActive); } } @@ -46,9 +51,7 @@ void ManaSymbolWidget::mousePressEvent(QMouseEvent *event) { Q_UNUSED(event); if (mayBeToggled) { - isActive = !isActive; - updateOpacity(); - emit colorToggled(getSymbolChar(), isActive); + toggleSymbol(); } } diff --git a/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.h b/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.h index 6ecf54b34..02aaf6087 100644 --- a/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.h +++ b/cockatrice/src/client/ui/widgets/cards/additional_info/mana_symbol_widget.h @@ -11,9 +11,13 @@ class ManaSymbolWidget : public QLabel public: ManaSymbolWidget(QWidget *parent, QString symbol, bool isActive = true, bool mayBeToggled = false); + void toggleSymbol(); void setColorActive(bool active); void updateOpacity(); - bool isColorActive() const; + bool isColorActive() const + { + return isActive; + }; QString getSymbol() const { return symbol; diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp index e7dfd6f43..681282fc4 100644 --- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp +++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.cpp @@ -27,9 +27,6 @@ VisualDatabaseDisplayColorFilterWidget::VisualDatabaseDisplayColorFilterWidget(Q layout->addWidget(manaSymbol); - // Initialize the activeColors map - activeColors[color] = false; - // Connect the color toggled signal connect(manaSymbol, &ManaSymbolWidget::colorToggled, this, &VisualDatabaseDisplayColorFilterWidget::handleColorToggled); @@ -41,16 +38,8 @@ VisualDatabaseDisplayColorFilterWidget::VisualDatabaseDisplayColorFilterWidget(Q // Connect the button's toggled signal connect(toggleButton, &QPushButton::toggled, this, &VisualDatabaseDisplayColorFilterWidget::updateFilterMode); - connect(this, &VisualDatabaseDisplayColorFilterWidget::activeColorsChanged, this, - &VisualDatabaseDisplayColorFilterWidget::updateColorFilter); - connect(this, &VisualDatabaseDisplayColorFilterWidget::filterModeChanged, this, - &VisualDatabaseDisplayColorFilterWidget::updateColorFilter); - connect(filterModel, &FilterTreeModel::layoutChanged, this, [this]() { - if (blockSync) { - return; // Skip sync if we're blocking it - } - QTimer::singleShot(100, this, &VisualDatabaseDisplayColorFilterWidget::syncWithFilterModel); - }); + connect(filterModel, &FilterTreeModel::layoutChanged, this, + [this]() { QTimer::singleShot(100, this, &VisualDatabaseDisplayColorFilterWidget::syncWithFilterModel); }); // Call retranslateUi to set the initial text retranslateUi(); @@ -73,91 +62,88 @@ void VisualDatabaseDisplayColorFilterWidget::retranslateUi() void VisualDatabaseDisplayColorFilterWidget::handleColorToggled(QChar color, bool active) { - activeColors[color] = active; - emit activeColorsChanged(); // Notify listeners that the active colors have changed + if (active) { + addFilter(color); + } else { + removeFilter(color); + } } -void VisualDatabaseDisplayColorFilterWidget::updateColorFilter() +void VisualDatabaseDisplayColorFilterWidget::addFilter(QChar color) { - blockSync = true; + QString colorString = color; + QString typeStr; - // Clear previous filters - filterModel->blockSignals(true); - filterModel->filterTree()->blockSignals(true); - filterModel->clearFiltersOfType(CardFilter::Attr::AttrColor); + // Remove previous filters - QSet selectedColors; - QSet excludedColors; + QList allColorFilters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor); + QList matchingFilters; - // Collect active colors in the selected and excluded sets - for (const auto &color : activeColors.keys()) { - if (activeColors[color]) { - selectedColors.insert(color); // Include this color - } else { - excludedColors.insert(color); // Exclude this color + 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: - // Exact Match Mode: Only selected colors are allowed - if (!selectedColors.isEmpty()) { - // Require all selected colors (TypeAnd) - for (const auto &color : selectedColors) { - QString colorString = color; - filterModel->addFilter( - new CardFilter(colorString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrColor)); - } - - // Exclude all other colors - QStringList allPossibleColors = {"W", "U", "B", "R", "G"}; - for (const auto &color : allPossibleColors) { - if (!selectedColors.contains(color)) { - QString colorString = color; - filterModel->addFilter( - new CardFilter(colorString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColor)); - } - } - } + filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrColor)); break; case FilterMode::Includes: - // Includes Mode: Just include selected colors without restrictions - for (const auto &color : selectedColors) { - QString colorString = color; - filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeOr, - CardFilter::Attr::AttrColor)); // OR for selected colors - } + filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeOr, CardFilter::Attr::AttrColor)); break; case FilterMode::IncludeExclude: - // Include/Exclude Mode: Include selected colors and exclude unselected colors - for (const auto &color : selectedColors) { - QString colorString = color; - filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeOr, - CardFilter::Attr::AttrColor)); // OR for selected colors - } - for (const auto &color : excludedColors) { - QString colorString = color; - filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeAndNot, - CardFilter::Attr::AttrColor)); // AND NOT for excluded colors - } + filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeOr, CardFilter::Attr::AttrColor)); break; } +} - filterModel->blockSignals(false); - filterModel->filterTree()->blockSignals(false); +void VisualDatabaseDisplayColorFilterWidget::removeFilter(QChar color) +{ + QString colorString = color; - emit filterModel->filterTree()->changed(); - emit filterModel->layoutChanged(); + // Remove inclusion filters + QList allColorFilters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor); + QList matchingFilters; - blockSync = false; + 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; + } } void VisualDatabaseDisplayColorFilterWidget::updateFilterMode() { - blockSync = true; - switch (currentMode) { case FilterMode::ExactMatch: currentMode = FilterMode::Includes; // Switch to Includes @@ -170,59 +156,100 @@ void VisualDatabaseDisplayColorFilterWidget::updateFilterMode() break; } - retranslateUi(); // Update button text based on the mode - emit filterModeChanged(currentMode); // Signal mode change - updateColorFilter(); // Reapply the filter based on the new mode + filterModel->blockSignals(true); + filterModel->filterTree()->blockSignals(true); - blockSync = false; -} - -void VisualDatabaseDisplayColorFilterWidget::syncWithFilterModel() -{ - blockSync = true; - QSet currentFilters; - - // Get current filters of type color - for (const auto &filter : filterModel->getFiltersOfType(CardFilter::Attr::AttrColor)) { - if (filter->type() == CardFilter::Type::TypeAnd || filter->type() == CardFilter::Type::TypeOr) { - currentFilters.insert(filter->term()); - } - } - - QSet activeFilterList; - - // Iterate over the activeColors map and collect the active colors as strings - for (auto it = activeColors.constBegin(); it != activeColors.constEnd(); ++it) { - if (it.value()) { // Only add active colors - activeFilterList.insert(QString(it.key())); - } - } - - // Check if the filters in the model match the active filters - if (currentFilters == activeFilterList) { - return; - } - - // Remove filters that are in the UI but not in the model - for (const auto &color : activeFilterList) { - if (!currentFilters.contains(color)) { - activeColors[color[0]] = false; // Disable the color - } - } - - // Add filters that are in the model but not in the UI - for (const auto &color : currentFilters) { - if (!activeFilterList.contains(color)) { - activeColors[color[0]] = true; // Enable the color - } - } + filterModel->clearFiltersOfType(CardFilter::Attr::AttrColor); QList manaSymbolWidgets = findChildren(); for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) { - manaSymbolWidget->setColorActive(activeColors[manaSymbolWidget->getSymbolChar()]); + handleColorToggled(manaSymbolWidget->getSymbolChar(), manaSymbolWidget->isColorActive()); } - updateColorFilter(); - blockSync = false; -} \ No newline at end of file + filterModel->blockSignals(false); + filterModel->filterTree()->blockSignals(false); + + emit filterModel->filterTree()->changed(); + emit filterModel->layoutChanged(); + + retranslateUi(); // Update button text based on the mode + emit filterModeChanged(currentMode); // Signal mode change +} + +void VisualDatabaseDisplayColorFilterWidget::setManaSymbolActive(QChar color, bool active) +{ + QList manaSymbolWidgets = findChildren(); + + for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) { + if (manaSymbolWidget->getSymbolChar() == color) { + manaSymbolWidget->setColorActive(active); + } + } +} + +QList VisualDatabaseDisplayColorFilterWidget::getActiveColors() +{ + QList activeColors; + QList manaSymbolWidgets = findChildren(); + + for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) { + if (manaSymbolWidget->isColorActive()) { + activeColors.append(manaSymbolWidget->getSymbolChar()); + } + } + + return activeColors; +} + +void VisualDatabaseDisplayColorFilterWidget::syncWithFilterModel() +{ + QList allColorFilters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor); + + QList manaSymbolWidgets = findChildren(); + + 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; + } + } + + if (!found) { + setManaSymbolActive(manaSymbolWidget->getSymbolChar(), false); + } + } +} diff --git a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.h b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.h index 191d00eee..3936c8843 100644 --- a/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.h +++ b/cockatrice/src/client/ui/widgets/visual_database_display/visual_database_display_color_filter_widget.h @@ -43,21 +43,21 @@ public: signals: void filterModeChanged(FilterMode filterMode); - void activeColorsChanged(); private slots: void handleColorToggled(QChar color, bool active); - void updateColorFilter(); + void addFilter(QChar color); + void removeFilter(QChar color); void updateFilterMode(); + void setManaSymbolActive(QChar color, bool active); + QList getActiveColors(); void syncWithFilterModel(); private: FilterTreeModel *filterModel; QHBoxLayout *layout; QPushButton *toggleButton; - QMap activeColors; FilterMode currentMode = FilterMode::Includes; // Default mode - bool blockSync = false; }; #endif // VISUAL_DATABASE_DISPLAY_COLOR_FILTER_WIDGET_H diff --git a/cockatrice/src/game/filters/filter_tree.cpp b/cockatrice/src/game/filters/filter_tree.cpp index 170fb35d8..4e65fc06e 100644 --- a/cockatrice/src/game/filters/filter_tree.cpp +++ b/cockatrice/src/game/filters/filter_tree.cpp @@ -531,6 +531,31 @@ void FilterTree::removeFiltersByAttr(CardFilter::Attr filterType) } } +void FilterTree::removeFilter(const CardFilter *toRemove) +{ + for (int i = childNodes.size() - 1; i >= 0; --i) { + auto *logicMap = dynamic_cast(childNodes.at(i)); + if (!logicMap || logicMap->attr != toRemove->attr()) + continue; + + FilterItemList *typeList = logicMap->typeList(toRemove->type()); + if (!typeList) + continue; + + int termIdx = typeList->termIndex(toRemove->term()); + if (termIdx != -1) { + typeList->deleteAt(termIdx); + emit typeList->nodeChanged(); + if (typeList->childCount() == 0) { + int logicIndex = logicMap->childIndex(typeList); + if (logicIndex != -1) { + logicMap->deleteAt(logicIndex); + } + } + } + } +} + void FilterTree::clear() { while (childCount() > 0) { diff --git a/cockatrice/src/game/filters/filter_tree.h b/cockatrice/src/game/filters/filter_tree.h index 895e1c1f7..394e98e7b 100644 --- a/cockatrice/src/game/filters/filter_tree.h +++ b/cockatrice/src/game/filters/filter_tree.h @@ -270,6 +270,7 @@ public: bool acceptsCard(CardInfoPtr info) const; void removeFiltersByAttr(CardFilter::Attr filterType); + void removeFilter(const CardFilter *toRemove); void clear(); }; diff --git a/cockatrice/src/game/filters/filter_tree_model.cpp b/cockatrice/src/game/filters/filter_tree_model.cpp index ec98f7c98..c4ce3aa35 100644 --- a/cockatrice/src/game/filters/filter_tree_model.cpp +++ b/cockatrice/src/game/filters/filter_tree_model.cpp @@ -78,6 +78,13 @@ void FilterTreeModel::addFilter(const CardFilter *f) emit layoutChanged(); } +void FilterTreeModel::removeFilter(const CardFilter *f) +{ + emit layoutAboutToBeChanged(); + fTree->removeFilter(f); + emit layoutChanged(); +} + void FilterTreeModel::clearFiltersOfType(CardFilter::Attr filterType) { emit layoutAboutToBeChanged(); diff --git a/cockatrice/src/game/filters/filter_tree_model.h b/cockatrice/src/game/filters/filter_tree_model.h index 4e98aa02a..89547e7a2 100644 --- a/cockatrice/src/game/filters/filter_tree_model.h +++ b/cockatrice/src/game/filters/filter_tree_model.h @@ -17,6 +17,7 @@ private: public slots: void addFilter(const CardFilter *f); + void removeFilter(const CardFilter *f); void clearFiltersOfType(CardFilter::Attr filterType); QList getFiltersOfType(CardFilter::Attr filterType) const; QList allFilters() const;