From 37fd1499c3001eab886d6950515695ee4d4d3509 Mon Sep 17 00:00:00 2001 From: RickyRister Date: Fri, 19 Jun 2026 02:56:16 -0700 Subject: [PATCH] [Game] Refactor subtype tally code to be more generic --- cockatrice/CMakeLists.txt | 3 +- cockatrice/src/game/selection_subtype_tally.h | 36 ----------- cockatrice/src/game_graphics/game_view.cpp | 64 ++++++++++--------- cockatrice/src/game_graphics/game_view.h | 12 ++-- .../tally/subtype_tally.cpp} | 24 +++++-- .../src/game_graphics/tally/subtype_tally.h | 26 ++++++++ cockatrice/src/game_graphics/tally/tally.cpp | 15 +++++ cockatrice/src/game_graphics/tally/tally.h | 40 ++++++++++++ 8 files changed, 140 insertions(+), 80 deletions(-) delete mode 100644 cockatrice/src/game/selection_subtype_tally.h rename cockatrice/src/{game/selection_subtype_tally.cpp => game_graphics/tally/subtype_tally.cpp} (72%) create mode 100644 cockatrice/src/game_graphics/tally/subtype_tally.h create mode 100644 cockatrice/src/game_graphics/tally/tally.cpp create mode 100644 cockatrice/src/game_graphics/tally/tally.h diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt index 166b807d9..60ba06593 100644 --- a/cockatrice/CMakeLists.txt +++ b/cockatrice/CMakeLists.txt @@ -83,7 +83,6 @@ set(cockatrice_SOURCES src/game/game_state.cpp src/game_graphics/game_view.cpp src/game_graphics/hand_counter.cpp - src/game/selection_subtype_tally.cpp src/game_graphics/log/message_log_widget.cpp src/game/phase.cpp src/game_graphics/phases_toolbar.cpp @@ -99,6 +98,8 @@ set(cockatrice_SOURCES src/game_graphics/player/menu/say_menu.cpp src/game_graphics/player/menu/sideboard_menu.cpp src/game_graphics/player/menu/utility_menu.cpp + src/game_graphics/tally/subtype_tally.cpp + src/game_graphics/tally/tally.cpp src/game/player/player_actions.cpp src/game_graphics/player/player_area.cpp src/game_graphics/player/player_dialogs.cpp diff --git a/cockatrice/src/game/selection_subtype_tally.h b/cockatrice/src/game/selection_subtype_tally.h deleted file mode 100644 index 9038653f6..000000000 --- a/cockatrice/src/game/selection_subtype_tally.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef SELECTION_SUBTYPE_TALLY_H -#define SELECTION_SUBTYPE_TALLY_H - -#include -#include - -class CardItem; - -/** @brief A single subtype (e.g., "Goblin", "Warrior") with its occurrence count. */ -struct SubtypeEntry -{ - QString name; ///< The subtype name - int count; ///< Number of selected cards with this subtype - - bool operator==(const SubtypeEntry &other) const - { - return name == other.name && count == other.count; - } -}; - -/** - * @brief Extracts and tallies subtypes from selected cards. - */ -namespace SelectionSubtypeTally -{ -/** - * @brief Parses card type lines and counts each subtype occurrence. - * - * Skips face-down cards and cards without type info. - * @param cards The list of selected card items to analyze. - * @return Entries sorted by count ascending, then alphabetically. - */ -QList countSubtypes(const QList &cards); -} // namespace SelectionSubtypeTally - -#endif diff --git a/cockatrice/src/game_graphics/game_view.cpp b/cockatrice/src/game_graphics/game_view.cpp index c2d9b2b3b..f6114aeaf 100644 --- a/cockatrice/src/game_graphics/game_view.cpp +++ b/cockatrice/src/game_graphics/game_view.cpp @@ -1,7 +1,6 @@ #include "game_view.h" #include "../client/settings/cache_settings.h" -#include "../game/selection_subtype_tally.h" #include "game_scene.h" #include @@ -79,12 +78,12 @@ GameView::GameView(GameScene *scene, QWidget *parent) : QGraphicsView(scene, par totalCountLabel->setStyleSheet(totalCountLabelStyle); totalCountLabel->hide(); - subtypeTallyContainer = new QWidget(this); - subtypeTallyContainer->setStyleSheet(subtypeTallyLabelStyle); - subtypeTallyLayout = new QGridLayout(subtypeTallyContainer); - subtypeTallyLayout->setContentsMargins(2, 2, 2, 2); - subtypeTallyLayout->setSpacing(2); - subtypeTallyContainer->hide(); + tallyContainer = new QWidget(this); + tallyContainer->setStyleSheet(subtypeTallyLabelStyle); + tallyLayout = new QGridLayout(tallyContainer); + tallyLayout->setContentsMargins(2, 2, 2, 2); + tallyLayout->setSpacing(2); + tallyContainer->hide(); } void GameView::resizeEvent(QResizeEvent *event) @@ -177,14 +176,14 @@ void GameView::refreshShortcuts() SettingsCache::instance().shortcuts().getShortcut("Player/aCloseMostRecentZoneView")); } -void GameView::clearSubtypeLabels() +void GameView::clearTallyLabels() { - QtUtils::clearLayoutRec(subtypeTallyLayout); + QtUtils::clearLayoutRec(tallyLayout); } -QSize GameView::rebuildSubtypeLabels(const QList &entries) +QSize GameView::rebuildTallyLabels(const QList &entries) { - clearSubtypeLabels(); + clearTallyLabels(); const QString nameStyle = QStringLiteral("color: white; font-size: 12px; background: transparent;"); const QString countStyle = @@ -195,16 +194,16 @@ QSize GameView::rebuildSubtypeLabels(const QList &entries) int maxCountWidth = 0; int row = 0; - for (const SubtypeEntry &entry : entries) { - auto *nameLabel = new QLabel(entry.name, subtypeTallyContainer); + for (const TallyRow &entry : entries) { + auto *nameLabel = new QLabel(entry.name, tallyContainer); nameLabel->setStyleSheet(nameStyle); nameLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); - subtypeTallyLayout->addWidget(nameLabel, row, 0); + tallyLayout->addWidget(nameLabel, row, 0); - auto *countLabel = new QLabel(QString::number(entry.count), subtypeTallyContainer); + auto *countLabel = new QLabel(entry.value, tallyContainer); countLabel->setStyleSheet(countStyle); countLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); - subtypeTallyLayout->addWidget(countLabel, row, 1); + tallyLayout->addWidget(countLabel, row, 1); QSize nameSize = nameLabel->sizeHint(); QSize countSize = countLabel->sizeHint(); @@ -215,9 +214,9 @@ QSize GameView::rebuildSubtypeLabels(const QList &entries) ++row; } - int spacing = subtypeTallyLayout->spacing(); - int margins = subtypeTallyLayout->contentsMargins().left() + subtypeTallyLayout->contentsMargins().right(); - int verticalMargins = subtypeTallyLayout->contentsMargins().top() + subtypeTallyLayout->contentsMargins().bottom(); + int spacing = tallyLayout->spacing(); + int margins = tallyLayout->contentsMargins().left() + tallyLayout->contentsMargins().right(); + int verticalMargins = tallyLayout->contentsMargins().top() + tallyLayout->contentsMargins().bottom(); int width = maxNameWidth + spacing + maxCountWidth + margins; int height = totalHeight + (row - 1) * spacing + verticalMargins; @@ -248,28 +247,31 @@ void GameView::updateTotalSelectionCount(const QSize &viewSize) } if (!SettingsCache::instance().getShowSubtypeSelectionTally() || count <= 1) { - subtypeTallyContainer->hide(); - cachedSubtypeEntries.clear(); + tallyContainer->hide(); + cachedTallyRows.clear(); return; } + TallyType tallyType = + SettingsCache::instance().getShowSubtypeSelectionTally() ? TallyType::Subtypes : TallyType::None; + GameScene *gameScene = static_cast(scene()); - QList entries = SelectionSubtypeTally::countSubtypes(gameScene->selectedCards()); + QList entries = Tally::compute(gameScene->selectedCards(), tallyType); if (entries.isEmpty()) { - subtypeTallyContainer->hide(); - cachedSubtypeEntries.clear(); + tallyContainer->hide(); + cachedTallyRows.clear(); return; } // Only rebuild labels if entries changed QSize containerSize; - if (entries != cachedSubtypeEntries) { - cachedSubtypeEntries = entries; - containerSize = rebuildSubtypeLabels(entries); - subtypeTallyContainer->resize(containerSize); + if (entries != cachedTallyRows) { + cachedTallyRows = entries; + containerSize = rebuildTallyLabels(entries); + tallyContainer->resize(containerSize); } else { - containerSize = subtypeTallyContainer->size(); + containerSize = tallyContainer->size(); } int x = availableWidth - containerSize.width() - kMarginInPixels; @@ -283,8 +285,8 @@ void GameView::updateTotalSelectionCount(const QSize &viewSize) y = qMax(kMarginInPixels, y); - subtypeTallyContainer->move(x, y); - subtypeTallyContainer->show(); + tallyContainer->move(x, y); + tallyContainer->show(); } /** diff --git a/cockatrice/src/game_graphics/game_view.h b/cockatrice/src/game_graphics/game_view.h index 4047c87ab..3f6b60dbc 100644 --- a/cockatrice/src/game_graphics/game_view.h +++ b/cockatrice/src/game_graphics/game_view.h @@ -7,7 +7,7 @@ #ifndef GAMEVIEW_H #define GAMEVIEW_H -#include "../game/selection_subtype_tally.h" +#include "tally/tally.h" #include @@ -24,13 +24,13 @@ private: QRubberBand *rubberBand; QLabel *dragCountLabel; QLabel *totalCountLabel; - QWidget *subtypeTallyContainer; - QGridLayout *subtypeTallyLayout; + QWidget *tallyContainer; + QGridLayout *tallyLayout; QPointF selectionOrigin; - QList cachedSubtypeEntries; ///< Cached entries to avoid redundant rebuilds + QList cachedTallyRows; ///< Cached entries to avoid redundant rebuilds - QSize rebuildSubtypeLabels(const QList &entries); - void clearSubtypeLabels(); + QSize rebuildTallyLabels(const QList &entries); + void clearTallyLabels(); protected: void resizeEvent(QResizeEvent *event) override; diff --git a/cockatrice/src/game/selection_subtype_tally.cpp b/cockatrice/src/game_graphics/tally/subtype_tally.cpp similarity index 72% rename from cockatrice/src/game/selection_subtype_tally.cpp rename to cockatrice/src/game_graphics/tally/subtype_tally.cpp index e9f87fab9..5d34f6874 100644 --- a/cockatrice/src/game/selection_subtype_tally.cpp +++ b/cockatrice/src/game_graphics/tally/subtype_tally.cpp @@ -1,6 +1,6 @@ -#include "selection_subtype_tally.h" +#include "subtype_tally.h" -#include "../game_graphics/board/card_item.h" +#include "../board/card_item.h" #include #include @@ -19,12 +19,19 @@ QStringList extractSubtypesFromFace(const QString &faceType) return {}; } +/** @brief A single subtype (e.g., "Goblin", "Warrior") with its occurrence count. */ +struct SubtypeEntry +{ + QString name; + int count; +}; + } // anonymous namespace -namespace SelectionSubtypeTally +namespace SubtypeTally { -QList countSubtypes(const QList &cards) +QList countSubtypes(const QList &cards) { QMap subtypeCounts; @@ -58,7 +65,12 @@ QList countSubtypes(const QList &cards) return a.name < b.name; }); - return entries; + // convert entries into TallyRows + QList rows = QList(entries.size()); + std::transform(entries.begin(), entries.end(), rows.begin(), + [](const SubtypeEntry &e) { return TallyRow{e.name, QString::number(e.count)}; }); + + return rows; } -} // namespace SelectionSubtypeTally +} // namespace SubtypeTally diff --git a/cockatrice/src/game_graphics/tally/subtype_tally.h b/cockatrice/src/game_graphics/tally/subtype_tally.h new file mode 100644 index 000000000..82aecff97 --- /dev/null +++ b/cockatrice/src/game_graphics/tally/subtype_tally.h @@ -0,0 +1,26 @@ +#ifndef SELECTION_SUBTYPE_TALLY_H +#define SELECTION_SUBTYPE_TALLY_H + +#include "tally.h" + +#include +#include + +class CardItem; + +/** + * @brief Extracts and tallies subtypes from selected cards. + */ +namespace SubtypeTally +{ +/** + * @brief Parses card type lines and counts each subtype occurrence. + * + * Skips face-down cards and cards without type info. + * @param cards The list of selected card items to analyze. + * @return Entries sorted by count ascending, then alphabetically. + */ +QList countSubtypes(const QList &cards); +} // namespace SubtypeTally + +#endif diff --git a/cockatrice/src/game_graphics/tally/tally.cpp b/cockatrice/src/game_graphics/tally/tally.cpp new file mode 100644 index 000000000..6f6cd57db --- /dev/null +++ b/cockatrice/src/game_graphics/tally/tally.cpp @@ -0,0 +1,15 @@ +#include "tally.h" + +#include "subtype_tally.h" + +QList Tally::compute(const QList &cards, const TallyType type) +{ + switch (type) { + case TallyType::None: + return {}; + case TallyType::Subtypes: + return SubtypeTally::countSubtypes(cards); + default: + return {}; + } +} \ No newline at end of file diff --git a/cockatrice/src/game_graphics/tally/tally.h b/cockatrice/src/game_graphics/tally/tally.h new file mode 100644 index 000000000..1ccb7939f --- /dev/null +++ b/cockatrice/src/game_graphics/tally/tally.h @@ -0,0 +1,40 @@ +#ifndef COCKATRICE_TALLY_H +#define COCKATRICE_TALLY_H +#include + +class CardItem; + +/** @brief A single row of the tally output. */ +struct TallyRow +{ + QString name; ///< The row name (displayed on the left) + QString value; ///< Value for the row (displayed on the right) + + bool operator==(const TallyRow &) const = default; +}; + +/** + * The tally type + */ +enum class TallyType +{ + None, + Subtypes, +}; + +namespace Tally +{ + +/** + * @brief Analyzes the selected cards according to the tally type and builds the resulting tally rows. + * This forwards the cards to the code for that tally type. + * + * @param cards The list of selected card items to analyze. + * @param type The type of tally to do + * @return Rows sorted in top-to-bottom display order + */ +QList compute(const QList &cards, TallyType type); + +} // namespace Tally + +#endif // COCKATRICE_TALLY_H