From 430fc117b4251fc722100282f7b86a984ec5d14e Mon Sep 17 00:00:00 2001 From: RickyRister <42636155+RickyRister@users.noreply.github.com> Date: Sun, 5 Jul 2026 18:24:52 -0700 Subject: [PATCH 1/5] [UserContextMenu] Refactor: Consolidate actions (#7022) --- .../widgets/server/user/user_context_menu.cpp | 122 ++++++------------ .../widgets/server/user/user_context_menu.h | 4 +- .../widgets/server/user/user_list_widget.cpp | 8 +- 3 files changed, 45 insertions(+), 89 deletions(-) diff --git a/cockatrice/src/interface/widgets/server/user/user_context_menu.cpp b/cockatrice/src/interface/widgets/server/user/user_context_menu.cpp index 11fd02d80..5c4a88974 100644 --- a/cockatrice/src/interface/widgets/server/user/user_context_menu.cpp +++ b/cockatrice/src/interface/widgets/server/user/user_context_menu.cpp @@ -436,103 +436,35 @@ void UserContextMenu::showContextMenu(const QPoint &pos, QAction *actionClicked = menu->exec(pos); if (actionClicked == nullptr) { } else if (actionClicked == aDetails) { - auto *infoWidget = - new UserInfoBox(client, false, static_cast(parent()), - Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint); - infoWidget->setAttribute(Qt::WA_DeleteOnClose); - infoWidget->updateInfo(userName); + execDetails(userName); } else if (actionClicked == aChat) { - emit openMessageDialog(userName, true); + execChat(userName); } else if (actionClicked == aShowGames) { - Command_GetGamesOfUser cmd; - cmd.set_user_name(userName.toStdString()); - - PendingCommand *pend = client->prepareSessionCommand(cmd); - connect(pend, &PendingCommand::finished, this, &UserContextMenu::gamesOfUserReceived); - - client->sendCommand(pend); + execShowGames(userName); } else if (actionClicked == aAddToBuddyList) { - Command_AddToList cmd; - cmd.set_list("buddy"); - cmd.set_user_name(userName.toStdString()); - - client->sendCommand(client->prepareSessionCommand(cmd)); + execAddToBuddy(userName); } else if (actionClicked == aRemoveFromBuddyList) { - Command_RemoveFromList cmd; - cmd.set_list("buddy"); - cmd.set_user_name(userName.toStdString()); - - client->sendCommand(client->prepareSessionCommand(cmd)); + execRemoveFromBuddy(userName); } else if (actionClicked == aAddToIgnoreList) { - Command_AddToList cmd; - cmd.set_list("ignore"); - cmd.set_user_name(userName.toStdString()); - - client->sendCommand(client->prepareSessionCommand(cmd)); + execAddToIgnore(userName); } else if (actionClicked == aRemoveFromIgnoreList) { - Command_RemoveFromList cmd; - cmd.set_list("ignore"); - cmd.set_user_name(userName.toStdString()); - - client->sendCommand(client->prepareSessionCommand(cmd)); + execRemoveFromIgnore(userName); } else if (actionClicked == aKick) { - auto result = QMessageBox::question(static_cast(parent()), tr("Kick Player"), - tr("Are you sure you want to kick this player from the game?"), - QMessageBox::Yes | QMessageBox::No, QMessageBox::No); - if (result == QMessageBox::Yes) { - Command_KickFromGame cmd; - cmd.set_player_id(playerId); - - game->getGameEventHandler()->sendGameCommand(cmd); - } + execKick(playerId); } else if (actionClicked == aBan) { - Command_GetUserInfo cmd; - cmd.set_user_name(userName.toStdString()); - - PendingCommand *pend = client->prepareSessionCommand(cmd); - connect(pend, &PendingCommand::finished, this, &UserContextMenu::banUser_processUserInfoResponse); - client->sendCommand(pend); + execBan(userName); } else if (actionClicked == aPromoteToMod || actionClicked == aDemoteFromMod) { - Command_AdjustMod cmd; - cmd.set_user_name(userName.toStdString()); - cmd.set_should_be_mod(actionClicked == aPromoteToMod); - - PendingCommand *pend = client->prepareAdminCommand(cmd); - connect(pend, &PendingCommand::finished, this, &UserContextMenu::adjustMod_processUserResponse); - client->sendCommand(pend); + execAdjustMod(userName, actionClicked == aPromoteToMod); } else if (actionClicked == aPromoteToJudge || actionClicked == aDemoteFromJudge) { - Command_AdjustMod cmd; - cmd.set_user_name(userName.toStdString()); - cmd.set_should_be_judge(actionClicked == aPromoteToJudge); - - PendingCommand *pend = client->prepareAdminCommand(cmd); - connect(pend, &PendingCommand::finished, this, &UserContextMenu::adjustMod_processUserResponse); - client->sendCommand(pend); + execAdjustJudge(userName, actionClicked == aPromoteToJudge); } else if (actionClicked == aBanHistory) { - Command_GetBanHistory cmd; - cmd.set_user_name(userName.toStdString()); - PendingCommand *pend = client->prepareModeratorCommand(cmd); - connect(pend, &PendingCommand::finished, this, &UserContextMenu::banUserHistory_processResponse); - client->sendCommand(pend); + execBanHistory(userName); } else if (actionClicked == aWarnUser) { - Command_GetUserInfo cmd; - cmd.set_user_name(userName.toStdString()); - PendingCommand *pend = client->prepareSessionCommand(cmd); - connect(pend, &PendingCommand::finished, this, &UserContextMenu::warnUser_processUserInfoResponse); - client->sendCommand(pend); + execWarn(userName); } else if (actionClicked == aWarnHistory) { - Command_GetWarnHistory cmd; - cmd.set_user_name(userName.toStdString()); - PendingCommand *pend = client->prepareModeratorCommand(cmd); - connect(pend, &PendingCommand::finished, this, &UserContextMenu::warnUserHistory_processResponse); - client->sendCommand(pend); + execWarnHistory(userName); } else if (actionClicked == aGetAdminNotes) { - Command_GetAdminNotes cmd; - cmd.set_user_name(userName.toStdString()); - auto *pend = client->prepareModeratorCommand(cmd); - connect(pend, &PendingCommand::finished, this, &UserContextMenu::getAdminNotes_processResponse); - client->sendCommand(pend); - + execAdminNotes(userName); } else if (actionClicked == aCopyToClipBoard) { QClipboard *clipboard = QGuiApplication::clipboard(); clipboard->setText(deckHash); @@ -597,6 +529,19 @@ void UserContextMenu::execRemoveFromIgnore(const QString &userName) client->sendCommand(client->prepareSessionCommand(cmd)); } +void UserContextMenu::execKick(int playerId) +{ + auto result = QMessageBox::question(static_cast(parent()), tr("Kick Player"), + tr("Are you sure you want to kick this player from the game?"), + QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + if (result == QMessageBox::Yes) { + Command_KickFromGame cmd; + cmd.set_player_id(playerId); + + game->getGameEventHandler()->sendGameCommand(cmd); + } +} + void UserContextMenu::execBan(const QString &userName) { Command_GetUserInfo cmd; @@ -642,11 +587,20 @@ void UserContextMenu::execAdminNotes(const QString &userName) client->sendCommand(pend); } -void UserContextMenu::execAdjustMod(const QString &userName, bool shouldBeMod, bool shouldBeJudge) +void UserContextMenu::execAdjustMod(const QString &userName, bool shouldBeMod) { Command_AdjustMod cmd; cmd.set_user_name(userName.toStdString()); cmd.set_should_be_mod(shouldBeMod); + PendingCommand *pend = client->prepareAdminCommand(cmd); + connect(pend, &PendingCommand::finished, this, &UserContextMenu::adjustMod_processUserResponse); + client->sendCommand(pend); +} + +void UserContextMenu::execAdjustJudge(const QString &userName, bool shouldBeJudge) +{ + Command_AdjustMod cmd; + cmd.set_user_name(userName.toStdString()); cmd.set_should_be_judge(shouldBeJudge); PendingCommand *pend = client->prepareAdminCommand(cmd); connect(pend, &PendingCommand::finished, this, &UserContextMenu::adjustMod_processUserResponse); diff --git a/cockatrice/src/interface/widgets/server/user/user_context_menu.h b/cockatrice/src/interface/widgets/server/user/user_context_menu.h index 28173bfbc..00fdc51fe 100644 --- a/cockatrice/src/interface/widgets/server/user/user_context_menu.h +++ b/cockatrice/src/interface/widgets/server/user/user_context_menu.h @@ -89,12 +89,14 @@ public: void execRemoveFromBuddy(const QString &userName); void execAddToIgnore(const QString &userName); void execRemoveFromIgnore(const QString &userName); + void execKick(int playerId); void execBan(const QString &userName); void execWarn(const QString &userName); void execBanHistory(const QString &userName); void execWarnHistory(const QString &userName); void execAdminNotes(const QString &userName); - void execAdjustMod(const QString &userName, bool shouldBeMod, bool shouldBeJudge); + void execAdjustMod(const QString &userName, bool shouldBeMod); + void execAdjustJudge(const QString &userName, bool shouldBeJudge); }; #endif diff --git a/cockatrice/src/interface/widgets/server/user/user_list_widget.cpp b/cockatrice/src/interface/widgets/server/user/user_list_widget.cpp index 32f46a79f..09480b1a1 100644 --- a/cockatrice/src/interface/widgets/server/user/user_list_widget.cpp +++ b/cockatrice/src/interface/widgets/server/user/user_list_widget.cpp @@ -707,13 +707,13 @@ void UserListWidget::connectPopupSignals() connect(m_userInfoPopup, &UserInfoPopup::warnHistoryRequested, userContextMenu, &UserContextMenu::execWarnHistory); connect(m_userInfoPopup, &UserInfoPopup::adminNotesRequested, userContextMenu, &UserContextMenu::execAdminNotes); connect(m_userInfoPopup, &UserInfoPopup::promoteToModRequested, this, - [this](const QString &n) { userContextMenu->execAdjustMod(n, true, false); }); + [this](const QString &n) { userContextMenu->execAdjustMod(n, true); }); connect(m_userInfoPopup, &UserInfoPopup::demoteFromModRequested, this, - [this](const QString &n) { userContextMenu->execAdjustMod(n, false, false); }); + [this](const QString &n) { userContextMenu->execAdjustMod(n, false); }); connect(m_userInfoPopup, &UserInfoPopup::promoteToJudgeRequested, this, - [this](const QString &n) { userContextMenu->execAdjustMod(n, false, true); }); + [this](const QString &n) { userContextMenu->execAdjustJudge(n, true); }); connect(m_userInfoPopup, &UserInfoPopup::demoteFromJudgeRequested, this, - [this](const QString &n) { userContextMenu->execAdjustMod(n, false, false); }); + [this](const QString &n) { userContextMenu->execAdjustJudge(n, false); }); } bool UserListWidget::eventFilter(QObject *obj, QEvent *event) From c5b37cdffeb40e34d7123b76bcb595119b7eeae1 Mon Sep 17 00:00:00 2001 From: RickyRister <42636155+RickyRister@users.noreply.github.com> Date: Sun, 5 Jul 2026 19:11:08 -0700 Subject: [PATCH 2/5] [Game] Refactor subtype tally code to be more generic (#7021) * [Game] Refactor subtype tally code to be more generic * remove default case * consolidate empty check * fix include guard * backwards compatibility with qt5 --- cockatrice/CMakeLists.txt | 3 +- cockatrice/src/game/selection_subtype_tally.h | 36 ---------- cockatrice/src/game_graphics/game_view.cpp | 66 +++++++++---------- cockatrice/src/game_graphics/game_view.h | 12 ++-- .../tally/subtype_tally.cpp} | 25 +++++-- .../src/game_graphics/tally/subtype_tally.h | 26 ++++++++ cockatrice/src/game_graphics/tally/tally.cpp | 14 ++++ cockatrice/src/game_graphics/tally/tally.h | 40 +++++++++++ 8 files changed, 138 insertions(+), 84 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} (71%) 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..db17aaead 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; @@ -247,29 +246,26 @@ void GameView::updateTotalSelectionCount(const QSize &viewSize) totalCountLabel->show(); } - if (!SettingsCache::instance().getShowSubtypeSelectionTally() || count <= 1) { - subtypeTallyContainer->hide(); - cachedSubtypeEntries.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(); + if (entries.isEmpty() || count <= 1) { + 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 +279,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 71% rename from cockatrice/src/game/selection_subtype_tally.cpp rename to cockatrice/src/game_graphics/tally/subtype_tally.cpp index e9f87fab9..804443b15 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,13 @@ QList countSubtypes(const QList &cards) return a.name < b.name; }); - return entries; + // convert entries into TallyRows + QList rows; + rows.reserve(entries.size()); // for backwards compatibility with Qt5 + std::transform(entries.begin(), entries.end(), std::back_inserter(rows), + [](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..9926528e0 --- /dev/null +++ b/cockatrice/src/game_graphics/tally/subtype_tally.h @@ -0,0 +1,26 @@ +#ifndef COCKATRICE_SUBTYPE_TALLY_H +#define COCKATRICE_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..521417ae6 --- /dev/null +++ b/cockatrice/src/game_graphics/tally/tally.cpp @@ -0,0 +1,14 @@ +#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); + } + return {}; +} 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 From 808d99148903281c7f1c29fad99c10815b995e13 Mon Sep 17 00:00:00 2001 From: tooomm Date: Mon, 6 Jul 2026 07:00:03 +0200 Subject: [PATCH 3/5] Delete .codacy.yml (#6957) --- .codacy.yml | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .codacy.yml diff --git a/.codacy.yml b/.codacy.yml deleted file mode 100644 index f9482da2f..000000000 --- a/.codacy.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -exclude_paths: - - '**/translations/*.ts' - -# codacy config documentation: https://support.codacy.com/hc/en-us/articles/115002130625-Codacy-Configuration-File From f3b41432cb823f84791a85810b0bc9504beada77 Mon Sep 17 00:00:00 2001 From: tooomm Date: Mon, 6 Jul 2026 07:01:12 +0200 Subject: [PATCH 4/5] CI: Fix login+push for publishing Servatrice Docker images (#7023) --- .github/workflows/docker-release.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml index b479322d0..5384c9e64 100644 --- a/.github/workflows/docker-release.yml +++ b/.github/workflows/docker-release.yml @@ -56,8 +56,9 @@ jobs: - name: "Set up Docker buildx" uses: docker/setup-buildx-action@v4 - - name: "Login to GitHub Container Registry" - if: contains(github.event.release.tag_name, 'Release') && github.event.release.target_commitish == 'master' + - name: "Login to GitHub Container Registry (GHCR)" + if: github.event_name == 'release' && github.event.release.prerelease == false + id: login uses: docker/login-action@v4 with: password: ${{ github.token }} @@ -73,5 +74,5 @@ jobs: context: . labels: ${{ steps.metadata.outputs.labels }} platforms: linux/amd64,linux/arm64 - push: ${{ github.ref_type == 'tag' }} + push: ${{ steps.login.outcome == 'success' }} tags: ${{ steps.metadata.outputs.tags }} From 6c960fdf31c12372abc7f39a0df7273b9ec35a43 Mon Sep 17 00:00:00 2001 From: tooomm Date: Mon, 6 Jul 2026 11:24:11 +0200 Subject: [PATCH 5/5] Use default values (#7017) --- .github/workflows/desktop-build.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml index a6b9d5340..f1846ecf6 100644 --- a/.github/workflows/desktop-build.yml +++ b/.github/workflows/desktop-build.yml @@ -271,7 +271,6 @@ jobs: override_target: 13 package_suffix: "-macOS13_Intel" qt_version: 6.11.0 - qt_arch: clang_64 qt_modules: qtimageformats qtmultimedia qtwebsockets soc: Intel type: Release @@ -287,7 +286,6 @@ jobs: make_package: 1 package_suffix: "-macOS14" qt_version: 6.11.0 - qt_arch: clang_64 qt_modules: qtimageformats qtmultimedia qtwebsockets soc: Apple type: Release @@ -303,7 +301,6 @@ jobs: make_package: 1 package_suffix: "-macOS15" qt_version: 6.11.0 - qt_arch: clang_64 qt_modules: qtimageformats qtmultimedia qtwebsockets soc: Apple type: Release @@ -317,7 +314,6 @@ jobs: ccache_eviction_age: 7d cmake_generator: Ninja qt_version: 6.11.0 - qt_arch: clang_64 qt_modules: qtimageformats qtmultimedia qtwebsockets soc: Apple type: Debug @@ -333,7 +329,6 @@ jobs: make_package: 1 package_suffix: "-Win10" qt_version: 6.11.0 - qt_arch: win64_msvc2022_64 qt_modules: qtimageformats qtmultimedia qtwebsockets type: Release @@ -398,7 +393,6 @@ jobs: if: matrix.os == 'macOS' && steps.restore_qt.outputs.cache-hit != 'true' uses: jurplel/install-qt-action@v4 with: - arch: ${{ matrix.qt_arch }} cache: false dir: ${{ github.workspace }} modules: ${{ matrix.qt_modules }} @@ -421,7 +415,6 @@ jobs: with: # Qt 6.11.0 only works with aqtinstall directly from git until aqtinstall 3.4 is released aqtsource: git+https://github.com/miurahr/aqtinstall.git - arch: ${{ matrix.qt_arch }} cache: true modules: ${{ matrix.qt_modules }} version: ${{ steps.resolve_qt_version.outputs.version }}