Merge branch 'master' into tooomm-qt5

This commit is contained in:
tooomm 2026-07-03 23:02:35 +02:00
commit ae9ce701f4
290 changed files with 10683 additions and 4451 deletions

View file

@ -43,7 +43,7 @@
#include <libcockatrice/protocol/pb/command_deck_upload.pb.h>
#include <libcockatrice/protocol/pb/response.pb.h>
#include <libcockatrice/protocol/pending_command.h>
#include <libcockatrice/utility/trice_limits.h>
#include <libcockatrice/utility/string_limits.h>
/**
* @brief Constructs the AbstractTabDeckEditor.
@ -56,6 +56,9 @@ AbstractTabDeckEditor::AbstractTabDeckEditor(TabSupervisor *_tabSupervisor) : Ta
deckStateManager = new DeckStateManager(this);
databaseModel = new CardDatabaseModel(CardDatabaseManager::getInstance(), true, this);
databaseModel->setObjectName("databaseModel");
cardDatabaseDockWidget = new DeckEditorCardDatabaseDockWidget(this);
deckDockWidget = new DeckEditorDeckDockWidget(this);
cardInfoDockWidget = new DeckEditorCardInfoDockWidget(this);
@ -105,16 +108,17 @@ void AbstractTabDeckEditor::registerDockWidget(QMenu *_viewMenu, QDockWidget *wi
dockToActions.insert(widget, {menu, aVisible, aFloating, defaultSize});
}
/**
* @brief Updates the card info dock and printing selector.
* @param card The card to display.
*/
void AbstractTabDeckEditor::updateCard(const ExactCard &card)
{
cardInfoDockWidget->updateCard(card);
printingSelectorDockWidget->printingSelector->setCard(card.getCardPtr());
}
void AbstractTabDeckEditor::updateCardInfo(const ExactCard &card)
{
cardInfoDockWidget->updateCard(card);
}
/** @brief Placeholder: called when the deck changes. */
void AbstractTabDeckEditor::onDeckChanged()
{
@ -129,47 +133,14 @@ void AbstractTabDeckEditor::onDeckModified()
emit tabTextChanged(this, getTabText());
}
/**
* @brief Helper for adding a card to a deck zone.
* @param card Card to add.
* @param zoneName Zone to add the card to.
*/
void AbstractTabDeckEditor::addCardHelper(const ExactCard &card, const QString &zoneName)
void AbstractTabDeckEditor::addCard(const ExactCard &card, const QString &zoneName)
{
deckStateManager->addCard(card, zoneName);
}
/**
* @brief Adds a card to the main deck or sideboard depending on Ctrl key.
*/
void AbstractTabDeckEditor::actAddCard(const ExactCard &card)
void AbstractTabDeckEditor::decrementCard(const ExactCard &card, const QString &zoneName)
{
if (QApplication::keyboardModifiers() & Qt::ControlModifier) {
actAddCardToSideboard(card);
} else {
addCardHelper(card, DECK_ZONE_MAIN);
}
deckMenu->setSaveStatus(true);
}
/** @brief Adds a card to the sideboard explicitly. */
void AbstractTabDeckEditor::actAddCardToSideboard(const ExactCard &card)
{
addCardHelper(card, DECK_ZONE_SIDE);
deckMenu->setSaveStatus(true);
}
/** @brief Decrements a card from the main deck. */
void AbstractTabDeckEditor::actDecrementCard(const ExactCard &card)
{
deckStateManager->decrementCard(card, DECK_ZONE_MAIN);
}
/** @brief Decrements a card from the sideboard. */
void AbstractTabDeckEditor::actDecrementCardFromSideboard(const ExactCard &card)
{
deckStateManager->decrementCard(card, DECK_ZONE_SIDE);
deckStateManager->decrementCard(card, zoneName);
}
/**
@ -571,14 +542,14 @@ void AbstractTabDeckEditor::actExportDeckDecklistXyz()
/** @brief Analyzes the deck using DeckStats. */
void AbstractTabDeckEditor::actAnalyzeDeckDeckstats()
{
auto *interface = new DeckStatsInterface(*cardDatabaseDockWidget->getDatabase(), this);
auto *interface = new DeckStatsInterface(this);
interface->analyzeDeck(deckStateManager->getDeckList());
}
/** @brief Analyzes the deck using TappedOut. */
void AbstractTabDeckEditor::actAnalyzeDeckTappedout()
{
auto *interface = new TappedOutInterface(*cardDatabaseDockWidget->getDatabase(), this);
auto *interface = new TappedOutInterface(this);
interface->analyzeDeck(deckStateManager->getDeckList());
}
@ -621,3 +592,15 @@ bool AbstractTabDeckEditor::closeRequest()
}
return close();
}
void AbstractTabDeckEditor::showPrintingSelector()
{
printingSelectorDockWidget->printingSelector->setCard(cardInfoDockWidget->cardInfo->getCard().getCardPtr());
printingSelectorDockWidget->printingSelector->updateDisplay();
printingSelectorDockWidget->setVisible(true);
}
void AbstractTabDeckEditor::openEdhrecTab(const CardInfoPtr &info, bool isCommander)
{
getTabSupervisor()->addEdhrecTab(info, isCommander);
}

View file

@ -77,8 +77,8 @@ class QAction;
*
* **Key Methods:**
*
* - actAddCard(const ExactCard &card) Adds a card to the deck.
* - actDecrementCard(const ExactCard &card) Removes a single instance of a card from the deck.
* - addCard(const ExactCard &card, const QString &zoneName) Adds a card to the deck.
* - decrementCard(const ExactCard &card, const QString &zoneName) Removes a single instance of a card from the deck.
* - actRemoveCard() Removes the currently selected card from the deck.
* - actSaveDeckAs() Performs a "Save As" action for the deck.
* - updateCard(const ExactCard &card) Updates the currently displayed card info in the dock.
@ -126,6 +126,7 @@ public:
// UI Elements
DeckStateManager *deckStateManager;
CardDatabaseModel *databaseModel; ///< Card database
DeckEditorMenu *deckMenu; ///< Menu for deck operations
DeckEditorCardDatabaseDockWidget *cardDatabaseDockWidget; ///< Database dock
DeckEditorCardInfoDockWidget *cardInfoDockWidget; ///< Card info dock
@ -140,22 +141,35 @@ public slots:
/** @brief Called when the deck is modified. */
virtual void onDeckModified();
/** @brief Updates the card info panel.
* @param card The card to display.
/**
* @brief Updates the card info dock and printing selector.
* @param card The card to display.
*/
void updateCard(const ExactCard &card);
/** @brief Adds a card to the main deck or sideboard based on Ctrl key. */
void actAddCard(const ExactCard &card);
/**
* @brief Updates just the card info dock
* @param card The card to display
*/
void updateCardInfo(const ExactCard &card);
/** @brief Adds a card to the sideboard explicitly. */
void actAddCardToSideboard(const ExactCard &card);
/**
* @brief Adds a card to the given zone
* @param card Card to add.
* @param zoneName Zone to add the card to.
*/
void addCard(const ExactCard &card, const QString &zoneName);
/** @brief Decrements a card from the main deck. */
void actDecrementCard(const ExactCard &card);
/** @brief Decrements a card from the sideboard. */
void actDecrementCardFromSideboard(const ExactCard &card);
/**
* @brief Decrements a card from the given zone
*
* Use an ExactCard with empty PrintingInfo if you want to remove a card by name regardless of printing.
* Otherwise, it won't remove anything unless there's an exact printing match.
*
* @param card Card to decrement.
* @param zoneName Zone to decrement from.
*/
void decrementCard(const ExactCard &card, const QString &zoneName);
/** @brief Opens a recently opened deck file. */
void actOpenRecent(const QString &fileName);
@ -166,8 +180,15 @@ public slots:
/** @brief Requests closing the tab. */
bool closeRequest() override;
/** @brief Shows the printing selector dock. Pure virtual. */
virtual void showPrintingSelector() = 0;
/** @brief Shows the printing selector dock and updates it with the current card. */
void showPrintingSelector();
/**
* @brief Opens an EDHRec tab for the given card
* @param info The card
* @param isCommander The type of search
*/
void openEdhrecTab(const CardInfoPtr &info, bool isCommander);
signals:
/** @brief Emitted when a deck should be opened in a new editor tab. */
@ -293,9 +314,6 @@ protected:
*/
QMessageBox *createSaveConfirmationWindow();
/** @brief Helper function to add a card to a specific deck zone. */
void addCardHelper(const ExactCard &card, const QString &zoneName);
/** @brief Opens a deck from a file. */
virtual void openDeckFromFile(const QString &fileName, DeckOpenLocation deckOpenLocation);

View file

@ -17,7 +17,7 @@
#include <libcockatrice/protocol/pb/response_list_users.pb.h>
#include <libcockatrice/protocol/pb/session_commands.pb.h>
#include <libcockatrice/protocol/pending_command.h>
#include <libcockatrice/utility/trice_limits.h>
#include <libcockatrice/utility/string_limits.h>
TabAccount::TabAccount(TabSupervisor *_tabSupervisor, AbstractClient *_client, const ServerInfo_User &userInfo)
: Tab(_tabSupervisor), client(_client)

View file

@ -13,7 +13,7 @@
#include <libcockatrice/protocol/pb/event_replay_added.pb.h>
#include <libcockatrice/protocol/pb/moderator_commands.pb.h>
#include <libcockatrice/protocol/pending_command.h>
#include <libcockatrice/utility/trice_limits.h>
#include <libcockatrice/utility/string_limits.h>
ShutdownDialog::ShutdownDialog(QWidget *parent) : QDialog(parent)
{

View file

@ -0,0 +1,293 @@
#include "tab_card_art_rules.h"
#include "libcockatrice/card/database/card_database_manager.h"
#include <QCompleter>
#include <QFormLayout>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <libcockatrice/network/client/abstract/abstract_client.h>
#include <libcockatrice/protocol/pb/moderator_commands.pb.h>
#include <libcockatrice/protocol/pb/response_card_art_rule_entry.pb.h>
#include <libcockatrice/protocol/pending_command.h>
CardArtRulesModel::CardArtRulesModel(AbstractClient *client, QObject *parent)
: QAbstractTableModel(parent), client(client)
{
}
int CardArtRulesModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid()) {
return 0;
}
return static_cast<int>(entries.size());
}
int CardArtRulesModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return 4;
}
QVariant CardArtRulesModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid()) {
return {};
}
const auto &e = entries.at(index.row());
if (role == Qt::DisplayRole) {
switch (index.column()) {
case 0:
return e.cardName;
case 1:
return e.cardProviderId;
case 2:
return e.mode;
case 3:
return e.reason;
}
}
return {};
}
QVariant CardArtRulesModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation != Qt::Horizontal || role != Qt::DisplayRole) {
return {};
}
switch (section) {
case 0:
return tr("Card");
case 1:
return tr("ProviderId");
case 2:
return tr("Mode");
case 3:
return tr("Reason");
default:
return {};
}
}
void CardArtRulesModel::refresh()
{
Command_ListCardArtRules cmd;
PendingCommand *pend = client->prepareModeratorCommand(cmd);
connect(pend, &PendingCommand::finished, this, &CardArtRulesModel::onRefreshFinished);
client->sendCommand(pend);
}
void CardArtRulesModel::clear()
{
beginResetModel();
entries.clear();
endResetModel();
}
QString CardArtRulesModel::cardAt(int row) const
{
if (row < 0 || row >= static_cast<int>(entries.size())) {
return {};
}
return entries[row].cardName;
}
const CardArtRulesModel::Entry *CardArtRulesModel::entryAt(int row) const
{
if (row < 0 || row >= static_cast<int>(entries.size())) {
return nullptr;
}
return &entries[row];
}
void CardArtRulesModel::onRefreshFinished(const Response &r)
{
if (r.response_code() != Response::RespOk) {
return;
}
const auto &resp = r.GetExtension(Response_ListCardArtRules::ext);
beginResetModel();
entries.clear();
for (const auto &e : resp.entries()) {
entries.push_back({QString::fromStdString(e.card_name()), QString::fromStdString(e.card_provider_id()),
QString::fromStdString(e.mode()), QString::fromStdString(e.reason())});
}
endResetModel();
}
TabCardArtRules::TabCardArtRules(TabSupervisor *parent, AbstractClient *_client) : Tab(parent), client(_client)
{
setupUi();
refresh();
}
void TabCardArtRules::setupUi()
{
auto *central = new QWidget(this);
initSearchBar();
providerComboBox = new QComboBox;
modeBox = new QComboBox;
reasonEdit = new QLineEdit;
addBtn = new QPushButton;
removeBtn = new QPushButton;
refreshBtn = new QPushButton;
modeBox->addItems({"ALLOW", "DENY"});
tableModel = new CardArtRulesModel(client, this);
table = new QTableView;
table->setModel(tableModel);
table->setSelectionBehavior(QAbstractItemView::SelectRows);
table->setSelectionMode(QAbstractItemView::SingleSelection);
auto *form = new QFormLayout;
form->addRow(tr("Card:"), searchEdit);
form->addRow(tr("ProviderId:"), providerComboBox);
form->addRow(tr("Mode:"), modeBox);
form->addRow(tr("Reason:"), reasonEdit);
auto *buttons = new QHBoxLayout;
buttons->addWidget(addBtn);
buttons->addWidget(removeBtn);
buttons->addWidget(refreshBtn);
auto *layout = new QVBoxLayout;
layout->addLayout(form);
layout->addLayout(buttons);
layout->addWidget(table);
central->setLayout(layout);
setCentralWidget(central);
connect(addBtn, &QPushButton::clicked, this, &TabCardArtRules::addRule);
connect(removeBtn, &QPushButton::clicked, this, &TabCardArtRules::removeSelected);
connect(refreshBtn, &QPushButton::clicked, this, &TabCardArtRules::refresh);
retranslateUi();
}
void TabCardArtRules::initSearchBar()
{
searchEdit = new QLineEdit;
searchEdit->setPlaceholderText(tr("Type a card name..."));
cardDbModel = new CardDatabaseModel(CardDatabaseManager::getInstance(), false, this);
cardDbDisplayModel = new CardDatabaseDisplayModel(this);
cardDbDisplayModel->setSourceModel(cardDbModel);
cardSearchModel = new CardSearchModel(cardDbDisplayModel, this);
cardProxyModel = new CardCompleterProxyModel(this);
cardProxyModel->setSourceModel(cardSearchModel);
cardProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
searchCompleter = new QCompleter(cardProxyModel, this);
searchCompleter->setCompletionRole(Qt::DisplayRole);
searchCompleter->setCompletionMode(QCompleter::PopupCompletion);
searchCompleter->setCaseSensitivity(Qt::CaseInsensitive);
searchCompleter->setFilterMode(Qt::MatchContains);
searchCompleter->setMaxVisibleItems(15);
searchEdit->setCompleter(searchCompleter);
connect(searchEdit, &QLineEdit::textEdited, cardSearchModel, &CardSearchModel::updateSearchResults);
connect(searchEdit, &QLineEdit::textEdited, this, [this](const QString &text) {
const QString pattern = ".*" + QRegularExpression::escape(text) + ".*";
cardProxyModel->setFilterRegularExpression(
QRegularExpression(pattern, QRegularExpression::CaseInsensitiveOption));
if (!text.isEmpty()) {
searchCompleter->complete();
}
});
connect(searchCompleter, static_cast<void (QCompleter::*)(const QString &)>(&QCompleter::activated), this,
[this](const QString &name) { searchEdit->setText(name); });
connect(searchEdit, &QLineEdit::editingFinished, this,
[this]() { populateProviderCombo(searchEdit->text().trimmed()); });
}
void TabCardArtRules::populateProviderCombo(const QString &cardName)
{
providerComboBox->clear();
auto card = CardDatabaseManager::query()->getCard({cardName});
const auto &sets = card.getInfo().getSets();
for (const auto &printings : sets) {
for (const auto &p : printings) {
QString setName = p.getSet()->getLongName();
QString collector = p.getProperty("num");
QString uuid = p.getUuid();
QString label = setName;
if (!collector.isEmpty()) {
label += " #" + collector;
}
providerComboBox->addItem(label, uuid);
}
}
}
void TabCardArtRules::retranslateUi()
{
addBtn->setText(tr("Add rule"));
removeBtn->setText(tr("Remove rule"));
refreshBtn->setText(tr("Refresh"));
}
void TabCardArtRules::refresh()
{
tableModel->refresh();
}
void TabCardArtRules::addRule()
{
Command_AddCardArtRule cmd;
cmd.set_card_name(searchEdit->text().toStdString());
cmd.set_card_provider_id(providerComboBox->currentData().toString().toStdString());
cmd.set_mode(modeBox->currentText().toStdString());
cmd.set_reason(reasonEdit->text().toStdString());
client->sendCommand(client->prepareModeratorCommand(cmd));
refresh();
}
void TabCardArtRules::removeSelected()
{
QModelIndex idx = table->currentIndex();
if (!idx.isValid()) {
return;
}
Command_RemoveCardArtRule cmd;
const auto e = tableModel->entryAt(idx.row());
cmd.set_card_name(e->cardName.toStdString());
cmd.set_card_provider_id(e->cardProviderId.toStdString());
client->sendCommand(client->prepareModeratorCommand(cmd));
refresh();
}

View file

@ -0,0 +1,93 @@
#ifndef COCKATRICE_DLG_CARD_ART_RULES_H
#define COCKATRICE_DLG_CARD_ART_RULES_H
#include "card/card_search_model.h"
#include "tab_supervisor.h"
#include <QAbstractTableModel>
#include <QComboBox>
#include <QLineEdit>
#include <QPushButton>
#include <QTableView>
class AbstractClient;
class CardArtRulesModel : public QAbstractTableModel
{
Q_OBJECT
public:
struct Entry
{
QString cardName;
QString cardProviderId;
QString mode;
QString reason;
};
explicit CardArtRulesModel(AbstractClient *client, QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
void refresh();
void clear();
QString cardAt(int row) const;
const Entry *entryAt(int row) const;
private slots:
void onRefreshFinished(const Response &r);
private:
AbstractClient *client;
std::vector<Entry> entries;
};
class TabCardArtRules : public Tab
{
Q_OBJECT
public:
TabCardArtRules(TabSupervisor *parent, AbstractClient *client);
QString getTabText() const override
{
return tr("Card Art Rules");
}
void retranslateUi() override;
private:
void setupUi();
private slots:
void addRule();
void removeSelected();
void refresh();
private:
AbstractClient *client;
QLineEdit *searchEdit;
void initSearchBar();
void populateProviderCombo(const QString &cardName);
QCompleter *searchCompleter;
CardDatabaseModel *cardDbModel;
CardDatabaseDisplayModel *cardDbDisplayModel;
CardSearchModel *cardSearchModel;
CardCompleterProxyModel *cardProxyModel;
QComboBox *providerComboBox;
QComboBox *modeBox;
QLineEdit *reasonEdit;
QPushButton *addBtn;
QPushButton *removeBtn;
QPushButton *refreshBtn;
QTableView *table;
CardArtRulesModel *tableModel;
};
#endif // COCKATRICE_DLG_CARD_ART_RULES_H

View file

@ -21,7 +21,6 @@
#include <libcockatrice/models/database/card_database_model.h>
#include <libcockatrice/network/client/abstract/abstract_client.h>
#include <libcockatrice/protocol/pending_command.h>
#include <libcockatrice/utility/trice_limits.h>
/**
* @brief Constructs a new TabDeckEditor object.
@ -120,16 +119,6 @@ void TabDeckEditor::refreshShortcuts()
aResetLayout->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aResetLayout"));
}
/**
* @brief Displays the printing selector dock with the current card.
*/
void TabDeckEditor::showPrintingSelector()
{
printingSelectorDockWidget->printingSelector->setCard(cardInfoDockWidget->cardInfo->getCard().getCardPtr());
printingSelectorDockWidget->printingSelector->updateDisplay();
printingSelectorDockWidget->setVisible(true);
}
/**
* @brief Loads deck editor layout from settings or resets to default.
*/

View file

@ -83,10 +83,6 @@ public:
/** @brief Creates menus for deck editing and view options. */
void createMenus() override;
public slots:
/** @brief Shows the printing selector dock and updates it with current card. */
void showPrintingSelector() override;
};
#endif

View file

@ -28,6 +28,7 @@
#include <libcockatrice/protocol/pb/response_deck_download.pb.h>
#include <libcockatrice/protocol/pb/response_deck_upload.pb.h>
#include <libcockatrice/protocol/pending_command.h>
#include <libcockatrice/utility/string_limits.h>
TabDeckStorage::TabDeckStorage(TabSupervisor *_tabSupervisor,
AbstractClient *_client,

View file

@ -1,18 +1,21 @@
#include "tab_game.h"
#include "../../../client/settings/cache_settings.h"
#include "../game/board/arrow_item.h"
#include "../game/board/card_item.h"
#include "../game/deckview/deck_view_container.h"
#include "../game/deckview/tabbed_deck_view_container.h"
#include "../game/game.h"
#include "../game/game_scene.h"
#include "../game/game_view.h"
#include "../game/log/message_log_widget.h"
#include "../game/phases_toolbar.h"
#include "../game/player/player_list_widget.h"
#include "../game/player/player_logic.h"
#include "../game/replay.h"
#include "../game_graphics/board/arrow_item.h"
#include "../game_graphics/board/card_item.h"
#include "../game_graphics/deckview/deck_view_container.h"
#include "../game_graphics/deckview/tabbed_deck_view_container.h"
#include "../game_graphics/game_scene.h"
#include "../game_graphics/game_view.h"
#include "../game_graphics/log/message_log_widget.h"
#include "../game_graphics/phases_toolbar.h"
#include "../game_graphics/player/menu/card_menu.h"
#include "../game_graphics/player/menu/player_menu.h"
#include "../game_graphics/player/player_graphics_item.h"
#include "../game_graphics/player/player_list_widget.h"
#include "../interface/card_picture_loader/card_picture_loader.h"
#include "../interface/widgets/cards/card_info_frame_widget.h"
#include "../interface/widgets/dialogs/dlg_create_game.h"
@ -41,13 +44,13 @@
#include <libcockatrice/protocol/pb/game_replay.pb.h>
#include <libcockatrice/protocol/pb/serverinfo_player.pb.h>
#include <libcockatrice/protocol/pb/serverinfo_user.pb.h>
#include <libcockatrice/utility/trice_limits.h>
#include <libcockatrice/utility/string_limits.h>
TabGame::TabGame(TabSupervisor *_tabSupervisor, GameReplay *_replay)
: Tab(_tabSupervisor), sayLabel(nullptr), sayEdit(nullptr)
{
// THIS CTOR IS USED ON REPLAY
game = new Replay(this, _replay);
game = new Replay(this, _replay, tabSupervisor->getIsLocalGame());
createCardInfoDock(true);
createPlayerListDock(true);
@ -91,7 +94,7 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor,
: Tab(_tabSupervisor), userListProxy(_tabSupervisor->getUserListManager())
{
// THIS CTOR IS USED ON GAMES
game = new Game(this, _clients, event, _roomGameTypes);
game = new Game(this, tabSupervisor->getIsLocalGame(), _clients, event, _roomGameTypes);
createCardInfoDock();
createPlayerListDock();
@ -363,11 +366,10 @@ void TabGame::retranslateUi()
cardInfoFrameWidget->retranslateUi();
QMapIterator<int, PlayerLogic *> i(game->getPlayerManager()->getPlayers());
while (i.hasNext()) {
i.next().value()->getGraphicsItem()->retranslateUi();
for (auto playerView : scene->getPlayers().values()) {
playerView->retranslateUi();
}
QMapIterator<int, TabbedDeckViewContainer *> j(deckViewContainers);
while (j.hasNext()) {
j.next().value()->playerDeckView->retranslateUi();
@ -608,7 +610,7 @@ void TabGame::actRemoveLocalArrows()
{
auto *local = game->getPlayerManager()->getActiveLocalPlayer(game->getGameState()->getActivePlayer());
if (local) {
scene->requestClearArrowsForPlayer(local->getPlayerInfo()->getId());
scene->clearArrowsForPlayer(local->getPlayerInfo()->getId());
}
}
@ -654,8 +656,12 @@ PlayerLogic *TabGame::addPlayer(PlayerLogic *newPlayer)
scene->addPlayer(newPlayer);
auto *view = scene->viewForPlayer(newPlayer->getPlayerInfo()->getId());
connect(newPlayer, &PlayerLogic::newCardAdded, this, &TabGame::newCardAdded);
connect(newPlayer->getPlayerMenu(), &PlayerMenu::cardMenuUpdated, this, &TabGame::setCardMenu);
connect(newPlayer, &PlayerLogic::openDeckEditor, this, &TabGame::openDeckEditor);
connect(view->getPlayerMenu(), &PlayerMenu::cardMenuUpdated, this, &TabGame::setCardMenu);
connect(view, &PlayerGraphicsItem::cardInfoRequested, this, &TabGame::viewCardInfo);
messageLog->connectToPlayerEventHandler(newPlayer->getPlayerEventHandler());
@ -668,7 +674,7 @@ PlayerLogic *TabGame::addPlayer(PlayerLogic *newPlayer)
addLocalPlayer(newPlayer, newPlayer->getPlayerInfo()->getId());
}
gameMenu->insertMenu(playersSeparator, newPlayer->getPlayerMenu()->getPlayerMenu());
gameMenu->insertMenu(playersSeparator, view->getPlayerMenu()->getPlayerMenu());
createZoneForPlayer(newPlayer, newPlayer->getPlayerInfo()->getId());
@ -678,7 +684,7 @@ PlayerLogic *TabGame::addPlayer(PlayerLogic *newPlayer)
void TabGame::addLocalPlayer(PlayerLogic *newPlayer, int playerId)
{
if (game->getGameState()->getClients().size() == 1) {
newPlayer->getPlayerMenu()->setShortcutsActive();
scene->viewForPlayer(playerId)->getPlayerMenu()->setShortcutsActive();
}
auto *deckView = new TabbedDeckViewContainer(playerId, this);
@ -698,27 +704,24 @@ void TabGame::addLocalPlayer(PlayerLogic *newPlayer, int playerId)
void TabGame::processPlayerLeave(PlayerLogic *leavingPlayer)
{
QString playerName = "@" + leavingPlayer->getPlayerInfo()->getName();
removePlayerFromAutoCompleteList(playerName);
scene->removePlayer(leavingPlayer);
removePlayerFromAutoCompleteList("@" + leavingPlayer->getPlayerInfo()->getName());
// When we inserted the playerMenu into the gameMenu earlier, Qt wrapped the playerMenu into a QAction*, which lives
// independently and does not get cleaned up when the source menu gets destroyed. We have to manually clean here.
if (leavingPlayer->getPlayerMenu()) {
QMenu *menu = leavingPlayer->getPlayerMenu()->getPlayerMenu();
if (menu) {
// Find and remove the QAction pointing to this menu
QList<QAction *> actions = gameMenu->actions();
for (QAction *act : actions) {
if (act->menu() == menu) {
gameMenu->removeAction(act);
delete act; // deletes the QAction wrapper around the submenu
break;
}
auto *view = scene->viewForPlayer(leavingPlayer->getPlayerInfo()->getId());
if (view) {
// Find and remove the QAction pointing to this menu
QMenu *menu = view->getPlayerMenu()->getPlayerMenu();
for (QAction *act : gameMenu->actions()) {
if (act->menu() == menu) {
gameMenu->removeAction(act);
delete act;
break;
}
}
}
scene->removePlayer(leavingPlayer);
}
void TabGame::processRemotePlayerDeckSelect(QString deckList, int playerId, QString playerName)
@ -869,12 +872,12 @@ PlayerLogic *TabGame::setActivePlayer(int id)
if (i.value() == player) {
i.value()->setActive(true);
if (game->getGameState()->getClients().size() > 1) {
i.value()->getPlayerMenu()->setShortcutsActive();
scene->viewForPlayer(i.value()->getPlayerInfo()->getId())->getPlayerMenu()->setShortcutsActive();
}
} else {
i.value()->setActive(false);
if (game->getGameState()->getClients().size() > 1) {
i.value()->getPlayerMenu()->setShortcutsInactive();
scene->viewForPlayer(i.value()->getPlayerInfo()->getId())->getPlayerMenu()->setShortcutsInactive();
}
}
}
@ -890,16 +893,16 @@ void TabGame::setActivePhase(int phase)
void TabGame::newCardAdded(AbstractCardItem *card)
{
connect(card, &AbstractCardItem::rightClicked, scene, &GameScene::onCardRightClicked);
connect(card, &AbstractCardItem::playSelected, scene, &GameScene::playSelected);
connect(card, &AbstractCardItem::playSelectedFaceDown, scene, &GameScene::playSelectedFaceDown);
connect(card, &AbstractCardItem::hideSelected, scene, &GameScene::hideSelected);
connect(card, &AbstractCardItem::hovered, cardInfoFrameWidget,
qOverload<AbstractCardItem *>(&CardInfoFrameWidget::setCard));
connect(card, &AbstractCardItem::selectionChanged, scene, &GameScene::onCardSelectionChanged);
connect(card, &AbstractCardItem::showCardInfoPopup, this, &TabGame::showCardInfoPopup);
connect(card, SIGNAL(deleteCardInfoPopup(QString)), this, SLOT(deleteCardInfoPopup(QString)));
connect(card, &AbstractCardItem::cardShiftClicked, this, &TabGame::linkCardToChat);
CardItem *cardItem = qobject_cast<CardItem *>(card);
if (cardItem) {
connect(cardItem->getState(), &CardState::zoneChanged, scene,
[this, cardItem]() { scene->onCardZoneChanged(cardItem, false); });
}
}
QString TabGame::getTabText() const
@ -940,7 +943,7 @@ QString TabGame::getTabText() const
/**
* @param menu The menu to set. Pass in nullptr to set the menu to empty.
*/
void TabGame::setCardMenu(QMenu *menu)
void TabGame::setCardMenu(CardMenu *menu)
{
if (!aCardMenu) {
return;
@ -1174,6 +1177,11 @@ void TabGame::createReplayDock(GameReplay *replay)
QDockWidget::DockWidgetMovable);
replayDock->setWidget(replayManager);
replayDock->setFloating(false);
connect(replayManager, &ReplayManager::eventReplayed, game->getGameEventHandler(),
[this](const auto &event, auto options) {
game->getGameEventHandler()->processGameEventContainer(event, nullptr, options);
});
}
void TabGame::createDeckViewContainerWidget(bool bReplay)

View file

@ -10,8 +10,8 @@
#define TAB_GAME_H
#include "../game/abstract_game.h"
#include "../game/log/message_log_widget.h"
#include "../game/player/player_logic.h"
#include "../game_graphics/log/message_log_widget.h"
#include "../interface/widgets/menus/tearoff_menu.h"
#include "../interface/widgets/replay/replay_manager.h"
#include "tab.h"
@ -20,6 +20,7 @@
#include <QLoggingCategory>
#include <QMap>
class CardMenu;
class ServerInfo_PlayerProperties;
class TabbedDeckViewContainer;
inline Q_LOGGING_CATEGORY(TabGameLog, "tab_game");
@ -141,7 +142,7 @@ signals:
private slots:
void adminLockChanged(bool lock);
void newCardAdded(AbstractCardItem *card);
void setCardMenu(QMenu *menu);
void setCardMenu(CardMenu *menu);
void actGameInfo();
void actConcede();

View file

@ -17,7 +17,7 @@
#include <libcockatrice/protocol/pb/moderator_commands.pb.h>
#include <libcockatrice/protocol/pb/response_viewlog_history.pb.h>
#include <libcockatrice/protocol/pending_command.h>
#include <libcockatrice/utility/trice_limits.h>
#include <libcockatrice/utility/string_limits.h>
TabLog::TabLog(TabSupervisor *_tabSupervisor, AbstractClient *_client) : Tab(_tabSupervisor), client(_client)
{

View file

@ -17,7 +17,7 @@
#include <libcockatrice/protocol/pb/serverinfo_user.pb.h>
#include <libcockatrice/protocol/pb/session_commands.pb.h>
#include <libcockatrice/protocol/pending_command.h>
#include <libcockatrice/utility/trice_limits.h>
#include <libcockatrice/utility/string_limits.h>
TabMessage::TabMessage(TabSupervisor *_tabSupervisor,
AbstractClient *_client,

View file

@ -31,7 +31,7 @@
#include <libcockatrice/protocol/pb/room_commands.pb.h>
#include <libcockatrice/protocol/pb/serverinfo_room.pb.h>
#include <libcockatrice/protocol/pending_command.h>
#include <libcockatrice/utility/trice_limits.h>
#include <libcockatrice/utility/string_limits.h>
TabRoom::TabRoom(TabSupervisor *_tabSupervisor,
AbstractClient *_client,
@ -49,10 +49,25 @@ TabRoom::TabRoom(TabSupervisor *_tabSupervisor,
QMap<int, GameTypeMap> tempMap;
tempMap.insert(info.room_id(), gameTypes);
gameSelector = new GameSelector(client, tabSupervisor, this, QMap<int, QString>(), tempMap, true, true);
auto *tabs = new QTabWidget(this);
friendsList = new UserListWidget(tabSupervisor, client, UserListWidget::BuddyList);
friendsList->bind(tabSupervisor->getUserListManager());
userList = new UserListWidget(tabSupervisor, client, UserListWidget::RoomList);
userList->bind(tabSupervisor->getUserListManager());
ignoreList = new UserListWidget(tabSupervisor, client, UserListWidget::IgnoreList);
ignoreList->bind(tabSupervisor->getUserListManager());
connect(friendsList, SIGNAL(openMessageDialog(const QString &, bool)), this,
SIGNAL(openMessageDialog(const QString &, bool)));
connect(userList, SIGNAL(openMessageDialog(const QString &, bool)), this,
SIGNAL(openMessageDialog(const QString &, bool)));
tabs->addTab(friendsList, tr("Friends"));
tabs->addTab(userList, tr("Online"));
tabs->addTab(ignoreList, tr("Ignored"));
chatView = new ChatView(tabSupervisor, nullptr, true, this);
connect(chatView, &ChatView::showMentionPopup, this, &TabRoom::actShowMentionPopup);
connect(chatView, &ChatView::messageClickedSignal, this, &TabRoom::focusTab);
@ -101,7 +116,7 @@ TabRoom::TabRoom(TabSupervisor *_tabSupervisor,
auto *hbox = new QHBoxLayout;
hbox->addWidget(splitter, 3);
hbox->addWidget(userList, 1);
hbox->addWidget(tabs, 1);
aLeaveRoom = new QAction(this);
connect(aLeaveRoom, &QAction::triggered, this, &TabRoom::closeRequest);
@ -112,10 +127,8 @@ TabRoom::TabRoom(TabSupervisor *_tabSupervisor,
const int userListSize = info.user_list_size();
for (int i = 0; i < userListSize; ++i) {
userList->processUserInfo(info.user_list(i), true);
autocompleteUserList.append("@" + QString::fromStdString(info.user_list(i).name()));
}
userList->sortItems();
const int gameListSize = info.game_list_size();
for (int i = 0; i < gameListSize; ++i) {
@ -269,8 +282,6 @@ void TabRoom::processListGamesEvent(const Event_ListGames &event)
void TabRoom::processJoinRoomEvent(const Event_JoinRoom &event)
{
userList->processUserInfo(event.user_info(), true);
userList->sortItems();
if (!autocompleteUserList.contains("@" + QString::fromStdString(event.user_info().name()))) {
autocompleteUserList << "@" + QString::fromStdString(event.user_info().name());
sayEdit->setCompletionList(autocompleteUserList);
@ -279,7 +290,6 @@ void TabRoom::processJoinRoomEvent(const Event_JoinRoom &event)
void TabRoom::processLeaveRoomEvent(const Event_LeaveRoom &event)
{
userList->deleteUser(QString::fromStdString(event.name()));
autocompleteUserList.removeOne("@" + QString::fromStdString(event.name()));
sayEdit->setCompletionList(autocompleteUserList);
}

View file

@ -56,7 +56,9 @@ private:
QMap<int, QString> gameTypes;
GameSelector *gameSelector;
UserListWidget *friendsList;
UserListWidget *userList;
UserListWidget *ignoreList;
const UserListProxy *userListProxy;
ChatView *chatView;
QLabel *sayLabel;

View file

@ -9,6 +9,7 @@
#include "api/edhrec/tab_edhrec_main.h"
#include "tab_account.h"
#include "tab_admin.h"
#include "tab_card_art_rules.h"
#include "tab_deck_editor.h"
#include "tab_deck_storage.h"
#include "tab_game.h"
@ -157,6 +158,10 @@ TabSupervisor::TabSupervisor(AbstractClient *_client, QMenu *tabsMenu, QWidget *
aTabAdmin->setCheckable(true);
connect(aTabAdmin, &QAction::triggered, this, &TabSupervisor::actTabAdmin);
aTabCardArtRules = new QAction(this);
aTabCardArtRules->setCheckable(true);
connect(aTabCardArtRules, &QAction::triggered, this, &TabSupervisor::actTabCardArtRules);
aTabLog = new QAction(this);
aTabLog->setCheckable(true);
connect(aTabLog, &QAction::triggered, this, &TabSupervisor::actTabLog);
@ -413,6 +418,7 @@ void TabSupervisor::start(const ServerInfo_User &_userInfo)
tabsMenu->addSeparator();
tabsMenu->addAction(aTabAdmin);
tabsMenu->addAction(aTabLog);
tabsMenu->addAction(aTabCardArtRules);
if (SettingsCache::instance().getTabAdminOpen()) {
openTabAdmin();
@ -420,6 +426,7 @@ void TabSupervisor::start(const ServerInfo_User &_userInfo)
if (SettingsCache::instance().getTabLogOpen()) {
openTabLog();
}
openTabCardArtRules();
}
retranslateUi();
@ -659,6 +666,30 @@ void TabSupervisor::openTabAdmin()
aTabAdmin->setChecked(true);
}
void TabSupervisor::actTabCardArtRules(bool checked)
{
if (checked && !tabCardArtRules) {
openTabCardArtRules();
setCurrentWidget(tabCardArtRules);
} else if (!checked && tabCardArtRules) {
tabCardArtRules->closeRequest();
}
}
void TabSupervisor::openTabCardArtRules()
{
tabCardArtRules = new TabCardArtRules(this, client);
myAddTab(tabCardArtRules, aTabCardArtRules);
connect(tabCardArtRules, &QObject::destroyed, this, [this] {
tabCardArtRules = nullptr;
aTabCardArtRules->setChecked(false);
});
aTabCardArtRules->setChecked(true);
}
void TabSupervisor::actTabLog(bool checked)
{
SettingsCache::instance().setTabLogOpen(checked);
@ -997,6 +1028,12 @@ void TabSupervisor::processUserMessageEvent(const Event_UserMessage &event)
!userLevel.testFlag(ServerInfo_User::IsRegistered)) {
// Flags are additive, so reg/mod/admin are all IsRegistered
return;
} else if (SettingsCache::instance().getIgnoreNonBuddyUserMessages() &&
!userListManager->isUserBuddy(senderName) && !userLevel.testFlag(ServerInfo_User::IsModerator) &&
!userLevel.testFlag(ServerInfo_User::IsAdmin)) {
// Ignore private messages from non-buddies
// Moderator/Admin messages are exempt to ensure warnings reach users
return;
}
}
tab = addMessageTab(QString::fromStdString(event.sender_name()), false);

View file

@ -23,6 +23,7 @@
#include <QMap>
#include <QTabWidget>
class TabCardArtRules;
inline Q_LOGGING_CATEGORY(TabSupervisorLog, "tab_supervisor");
class UserListManager;
@ -91,6 +92,7 @@ private:
TabDeckStorage *tabDeckStorage;
TabReplays *tabReplays;
TabAdmin *tabAdmin;
TabCardArtRules *tabCardArtRules;
TabLog *tabLog;
QMap<int, TabRoom *> roomTabs;
QMap<int, TabGame *> gameTabs;
@ -100,7 +102,8 @@ private:
bool isLocalGame;
QAction *aTabHome, *aTabDeckEditor, *aTabVisualDeckEditor, *aTabEdhRec, *aTabArchidekt, *aTabVisualDeckStorage,
*aTabVisualDatabaseDisplay, *aTabServer, *aTabAccount, *aTabDeckStorage, *aTabReplays, *aTabAdmin, *aTabLog;
*aTabVisualDatabaseDisplay, *aTabServer, *aTabAccount, *aTabDeckStorage, *aTabReplays, *aTabAdmin,
*aTabCardArtRules, *aTabLog;
int myAddTab(Tab *tab, QAction *manager = nullptr);
void addCloseButtonToTab(Tab *tab, int tabIndex, QAction *manager);
@ -133,7 +136,7 @@ public:
return userInfo;
}
[[nodiscard]] AbstractClient *getClient() const;
[[nodiscard]] const UserListManager *getUserListManager() const
[[nodiscard]] UserListManager *getUserListManager() const
{
return userListManager;
}
@ -185,6 +188,8 @@ private slots:
void openTabDeckStorage();
void openTabReplays();
void openTabAdmin();
void actTabCardArtRules(bool checked);
void openTabCardArtRules();
void openTabLog();
void updateCurrent(int index);

View file

@ -1,14 +1,19 @@
#include "tab_visual_database_display.h"
#include "tab_deck_editor.h"
#include "tab_supervisor.h"
#include <libcockatrice/card/database/card_database_manager.h>
TabVisualDatabaseDisplay::TabVisualDatabaseDisplay(TabSupervisor *_tabSupervisor) : Tab(_tabSupervisor)
{
deckEditor = new TabDeckEditor(_tabSupervisor);
deckEditor->setHidden(true);
visualDatabaseDisplayWidget = new VisualDatabaseDisplayWidget(
this, deckEditor, deckEditor->cardDatabaseDockWidget->databaseDisplayWidget->databaseModel,
deckEditor->cardDatabaseDockWidget->databaseDisplayWidget->databaseDisplayModel);
auto databaseModel = new CardDatabaseModel(CardDatabaseManager::getInstance(), true, this);
databaseModel->setObjectName("databaseModel");
visualDatabaseDisplayWidget = new VisualDatabaseDisplayWidget(this, databaseModel);
connect(visualDatabaseDisplayWidget, &VisualDatabaseDisplayWidget::edhrecRequested, this,
&TabVisualDatabaseDisplay::openEdhrecTab);
setCentralWidget(visualDatabaseDisplayWidget);
@ -18,3 +23,8 @@ TabVisualDatabaseDisplay::TabVisualDatabaseDisplay(TabSupervisor *_tabSupervisor
void TabVisualDatabaseDisplay::retranslateUi()
{
}
void TabVisualDatabaseDisplay::openEdhrecTab(const CardInfoPtr &info, bool isCommander) const
{
getTabSupervisor()->addEdhrecTab(info, isCommander);
}

View file

@ -15,9 +15,11 @@ class TabVisualDatabaseDisplay : public Tab
Q_OBJECT
private:
TabDeckEditor *deckEditor;
VisualDatabaseDisplayWidget *visualDatabaseDisplayWidget;
private slots:
void openEdhrecTab(const CardInfoPtr &info, bool isCommander) const;
public:
TabVisualDatabaseDisplay(TabSupervisor *_tabSupervisor);
void retranslateUi() override;

View file

@ -1,6 +1,7 @@
#include "tab_deck_editor_visual.h"
#include "../../../../client/settings/cache_settings.h"
#include "../../cards/card_info_display_widget.h"
#include "../../deck_editor/deck_state_manager.h"
#include "../../filters/filter_builder.h"
#include "../../interface/pixel_map_generator.h"
@ -25,6 +26,7 @@
#include <QTimer>
#include <QTreeView>
#include <QVBoxLayout>
#include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/models/deck_list/deck_list_model.h>
#include <libcockatrice/protocol/pb/command_deck_upload.pb.h>
#include <libcockatrice/protocol/pending_command.h>
@ -63,9 +65,10 @@ void TabDeckEditorVisual::createCentralFrame()
centralFrame = new QVBoxLayout;
centralWidget->setLayout(centralFrame);
tabContainer = new TabDeckEditorVisualTabWidget(
centralWidget, this, deckStateManager->getModel(), cardDatabaseDockWidget->databaseDisplayWidget->databaseModel,
cardDatabaseDockWidget->databaseDisplayWidget->databaseDisplayModel);
auto databaseModel = new CardDatabaseModel(CardDatabaseManager::getInstance(), true, this);
databaseModel->setObjectName("databaseModel");
tabContainer = new TabDeckEditorVisualTabWidget(centralWidget, this, deckStateManager->getModel(), databaseModel);
connect(tabContainer, &TabDeckEditorVisualTabWidget::cardChanged, this,
&TabDeckEditorVisual::changeModelIndexAndCardInfo);
@ -74,7 +77,14 @@ void TabDeckEditorVisual::createCentralFrame()
connect(tabContainer, &TabDeckEditorVisualTabWidget::cardClicked, this,
&TabDeckEditorVisual::processMainboardCardClick);
connect(tabContainer, &TabDeckEditorVisualTabWidget::cardClickedDatabaseDisplay, this,
&TabDeckEditorVisual::processCardClickDatabaseDisplay);
&TabDeckEditorVisual::processDatabaseCardClick);
connect(tabContainer, &TabDeckEditorVisualTabWidget::cardAdded, this, &TabDeckEditorVisual::addCard);
connect(tabContainer, &TabDeckEditorVisualTabWidget::cardDecremented, this, &TabDeckEditorVisual::decrementCard);
connect(tabContainer, &TabDeckEditorVisualTabWidget::edhrecRequested, this, &TabDeckEditorVisual::openEdhrecTab);
connect(tabContainer, &TabDeckEditorVisualTabWidget::printingSelectorRequested, this,
&TabDeckEditorVisual::showPrintingSelector);
connect(tabContainer, &TabDeckEditorVisualTabWidget::cardInfoRequested, this, &TabDeckEditorVisual::updateCardInfo);
centralFrame->addWidget(tabContainer);
setCentralWidget(centralWidget);
@ -143,12 +153,10 @@ void TabDeckEditorVisual::changeModelIndexToCard(const ExactCard &activeCard)
}
}
void TabDeckEditorVisual::processMainboardCardClick(QMouseEvent *event,
CardInfoPictureWithTextOverlayWidget *instance,
void TabDeckEditorVisual::processMainboardCardClick(const QMouseEvent *event,
const ExactCard &card,
const QString &zoneName)
{
auto card = instance->getCard();
// Get the model index for the card
QModelIndex idx = deckStateManager->getModel()->findCard(card.getName(), zoneName);
if (!idx.isValid()) {
@ -168,22 +176,14 @@ void TabDeckEditorVisual::processMainboardCardClick(QMouseEvent *event,
// Alt + Right-click = decrement
if (event->button() == Qt::RightButton && event->modifiers().testFlag(Qt::AltModifier)) {
if (zoneName == DECK_ZONE_MAIN) {
actDecrementCard(card);
} else {
actDecrementCardFromSideboard(card);
}
decrementCard(card, zoneName);
// Keep selection intact.
return;
}
// Alt + Left click = increment
if (event->button() == Qt::LeftButton && event->modifiers().testFlag(Qt::AltModifier)) {
if (zoneName == DECK_ZONE_MAIN) {
actAddCard(card);
} else {
actAddCardToSideboard(card);
}
addCard(card, zoneName);
// Keep selection intact.
return;
}
@ -219,13 +219,16 @@ void TabDeckEditorVisual::processMainboardCardClick(QMouseEvent *event,
}
/** @brief Handles clicks on cards in the database display. */
void TabDeckEditorVisual::processCardClickDatabaseDisplay(QMouseEvent *event,
CardInfoPictureWithTextOverlayWidget *instance)
void TabDeckEditorVisual::processDatabaseCardClick(const QMouseEvent *event, const ExactCard &card)
{
if (event->button() == Qt::LeftButton) {
actAddCard(instance->getCard());
if (QApplication::keyboardModifiers() & Qt::ControlModifier) {
addCard(card, DECK_ZONE_SIDE);
} else {
addCard(card, DECK_ZONE_MAIN);
}
} else if (event->button() == Qt::RightButton) {
actDecrementCard(instance->getCard());
decrementCard(card, DECK_ZONE_MAIN);
} else if (event->button() == Qt::MiddleButton) {
deckDockWidget->actRemoveCard();
}
@ -240,14 +243,6 @@ bool TabDeckEditorVisual::actSaveDeckAs()
return result;
}
/** @brief Shows the printing selector dock and updates it with the current card. */
void TabDeckEditorVisual::showPrintingSelector()
{
printingSelectorDockWidget->printingSelector->setCard(cardInfoDockWidget->cardInfo->getCard().getCardPtr());
printingSelectorDockWidget->printingSelector->updateDisplay();
printingSelectorDockWidget->setVisible(true);
}
/** @brief Refreshes keyboard shortcuts for this tab from settings. */
void TabDeckEditorVisual::refreshShortcuts()
{

View file

@ -41,7 +41,7 @@
* - changeModelIndexAndCardInfo(const ExactCard &card) Updates deck model selection and card info.
* - changeModelIndexToCard(const ExactCard &card) Selects the card in the deck view.
* - processMainboardCardClick(QMouseEvent *event, ...) Handles clicks on mainboard cards.
* - processCardClickDatabaseDisplay(QMouseEvent *event, ...) Handles clicks on database cards.
* - processDatabaseCardClick(QMouseEvent *event, ...) Handles clicks on database cards.
* - actSaveDeckAs() Overrides save action with temporary UI adjustments.
* - showPrintingSelector() Opens the printing selector dock for the current card.
* - freeDocksSize() Frees constraints on dock widget sizes.
@ -144,27 +144,20 @@ public slots:
*/
void onDeckChanged() override;
/**
* @brief Show the printing selector dock for the currently active card.
*/
void showPrintingSelector() override;
/**
* @brief Handle card clicks in the mainboard visual deck.
* @param event Mouse event triggering the action.
* @param instance Widget representing the clicked card.
* @param card The clicked card.
* @param zoneName Deck zone of the card.
*/
void processMainboardCardClick(QMouseEvent *event,
CardInfoPictureWithTextOverlayWidget *instance,
const QString &zoneName);
void processMainboardCardClick(const QMouseEvent *event, const ExactCard &card, const QString &zoneName);
/**
* @brief Handle card clicks in the database visual display.
* @param event Mouse event triggering the action.
* @param instance Widget representing the clicked card.
* @param card The clicked card.
*/
void processCardClickDatabaseDisplay(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
void processDatabaseCardClick(const QMouseEvent *event, const ExactCard &card);
/**
* @brief Save the deck under a new name.

View file

@ -9,7 +9,6 @@
* @param _deckEditor Pointer to the associated deck editor.
* @param _deckModel Pointer to the deck list model.
* @param _cardDatabaseModel Pointer to the card database model.
* @param _cardDatabaseDisplayModel Pointer to the card database display model.
*
* Initializes all sub-widgets (visual deck view, database display, deck analytics,
* sample hand) and sets up the tab layout and signal connections.
@ -17,10 +16,8 @@
TabDeckEditorVisualTabWidget::TabDeckEditorVisualTabWidget(QWidget *parent,
AbstractTabDeckEditor *_deckEditor,
DeckListModel *_deckModel,
CardDatabaseModel *_cardDatabaseModel,
CardDatabaseDisplayModel *_cardDatabaseDisplayModel)
: QTabWidget(parent), deckEditor(_deckEditor), deckModel(_deckModel), cardDatabaseModel(_cardDatabaseModel),
cardDatabaseDisplayModel(_cardDatabaseDisplayModel)
CardDatabaseModel *_cardDatabaseModel)
: QTabWidget(parent), deckEditor(_deckEditor), deckModel(_deckModel), cardDatabaseModel(_cardDatabaseModel)
{
this->setTabsClosable(true); // Enable tab closing
connect(this, &QTabWidget::tabCloseRequested, this, &TabDeckEditorVisualTabWidget::handleTabClose);
@ -34,16 +31,25 @@ TabDeckEditorVisualTabWidget::TabDeckEditorVisualTabWidget(QWidget *parent,
&TabDeckEditorVisualTabWidget::onCardChanged);
connect(visualDeckView, &VisualDeckEditorWidget::cardClicked, this,
&TabDeckEditorVisualTabWidget::onCardClickedDeckEditor);
connect(visualDeckView, &VisualDeckEditorWidget::cardAdditionRequested, deckEditor,
&AbstractTabDeckEditor::actAddCard);
connect(visualDeckView, &VisualDeckEditorWidget::cardAdditionRequested, this,
&TabDeckEditorVisualTabWidget::actAddCard);
visualDatabaseDisplay =
new VisualDatabaseDisplayWidget(this, deckEditor, _cardDatabaseModel, _cardDatabaseDisplayModel);
visualDatabaseDisplay = new VisualDatabaseDisplayWidget(this, _cardDatabaseModel, deckModel);
visualDatabaseDisplay->setObjectName("visualDatabaseView");
connect(visualDatabaseDisplay, &VisualDatabaseDisplayWidget::cardHoveredDatabaseDisplay, this,
&TabDeckEditorVisualTabWidget::onCardChangedDatabaseDisplay);
connect(visualDatabaseDisplay, &VisualDatabaseDisplayWidget::cardClickedDatabaseDisplay, this,
&TabDeckEditorVisualTabWidget::onCardClickedDatabaseDisplay);
connect(visualDatabaseDisplay, &VisualDatabaseDisplayWidget::cardAdded, this,
&TabDeckEditorVisualTabWidget::cardAdded);
connect(visualDatabaseDisplay, &VisualDatabaseDisplayWidget::cardDecremented, this,
&TabDeckEditorVisualTabWidget::cardDecremented);
connect(visualDatabaseDisplay, &VisualDatabaseDisplayWidget::edhrecRequested, this,
&TabDeckEditorVisualTabWidget::edhrecRequested);
connect(visualDatabaseDisplay, &VisualDatabaseDisplayWidget::printingSelectorRequested, this,
&TabDeckEditorVisualTabWidget::printingSelectorRequested);
connect(visualDatabaseDisplay, &VisualDatabaseDisplayWidget::cardInfoRequested, this,
&TabDeckEditorVisualTabWidget::cardInfoRequested);
statsAnalyzer = new DeckListStatisticsAnalyzer(this, deckModel);
statsAnalyzer->analyze();
@ -82,25 +88,24 @@ void TabDeckEditorVisualTabWidget::onCardChangedDatabaseDisplay(const ExactCard
/**
* @brief Emits the cardClicked signal when a card is clicked in the visual deck view.
* @param event The mouse event.
* @param instance The widget instance of the clicked card.
* @param card The clicked card.
* @param zoneName The zone of the deck where the card is located.
*/
void TabDeckEditorVisualTabWidget::onCardClickedDeckEditor(QMouseEvent *event,
CardInfoPictureWithTextOverlayWidget *instance,
QString zoneName)
const ExactCard &card,
const QString &zoneName)
{
emit cardClicked(event, instance, zoneName);
emit cardClicked(event, card, zoneName);
}
/**
* @brief Emits the cardClickedDatabaseDisplay signal when a card is clicked in the database display.
* @param event The mouse event.
* @param instance The widget instance of the clicked card.
* @param card The clicked card.
*/
void TabDeckEditorVisualTabWidget::onCardClickedDatabaseDisplay(QMouseEvent *event,
CardInfoPictureWithTextOverlayWidget *instance)
void TabDeckEditorVisualTabWidget::onCardClickedDatabaseDisplay(QMouseEvent *event, const ExactCard &card)
{
emit cardClickedDatabaseDisplay(event, instance);
emit cardClickedDatabaseDisplay(event, card);
}
/**
@ -166,3 +171,15 @@ void TabDeckEditorVisualTabWidget::handleTabClose(int index)
this->removeTab(index);
delete tab;
}
void TabDeckEditorVisualTabWidget::actAddCard(const ExactCard &card)
{
QString zoneName;
if (QApplication::keyboardModifiers() & Qt::ControlModifier) {
zoneName = DECK_ZONE_SIDE;
} else {
zoneName = DECK_ZONE_MAIN;
}
deckEditor->addCard(card, zoneName);
}

View file

@ -55,13 +55,11 @@ public:
* @param _deckEditor Pointer to the deck editor instance.
* @param _deckModel Deck list model.
* @param _cardDatabaseModel Card database model.
* @param _cardDatabaseDisplayModel Database display model.
*/
explicit TabDeckEditorVisualTabWidget(QWidget *parent,
AbstractTabDeckEditor *_deckEditor,
DeckListModel *_deckModel,
CardDatabaseModel *_cardDatabaseModel,
CardDatabaseDisplayModel *_cardDatabaseDisplayModel);
CardDatabaseModel *_cardDatabaseModel);
/** @brief Add a new tab with a widget and title. */
void addNewTab(QWidget *widget, const QString &title);
@ -101,30 +99,35 @@ public slots:
/**
* @brief Emitted when a card is clicked in the deck view.
* @param event Mouse event.
* @param instance Widget representing the clicked card.
* @param card The clicked card.
* @param zoneName Deck zone of the card.
*/
void onCardClickedDeckEditor(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance, QString zoneName);
void onCardClickedDeckEditor(QMouseEvent *event, const ExactCard &card, const QString &zoneName);
/**
* @brief Emitted when a card is clicked in the database display.
* @param event Mouse event.
* @param instance Widget representing the clicked card.
* @param card The clicked card.
*/
void onCardClickedDatabaseDisplay(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
void onCardClickedDatabaseDisplay(QMouseEvent *event, const ExactCard &card);
signals:
void cardChanged(const ExactCard &activeCard);
void cardChangedDatabaseDisplay(const ExactCard &activeCard);
void cardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance, QString zoneName);
void cardClickedDatabaseDisplay(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
void cardClicked(QMouseEvent *event, const ExactCard &card, const QString &zoneName);
void cardClickedDatabaseDisplay(QMouseEvent *event, const ExactCard &card);
void cardAdded(const ExactCard &card, const QString &zoneName);
void cardDecremented(const ExactCard &card, const QString &zoneName);
void edhrecRequested(const CardInfoPtr &cardInfo, bool isCommander);
void printingSelectorRequested();
void cardInfoRequested(const ExactCard &cardName);
private:
QVBoxLayout *layout; ///< Layout for tabs and controls.
AbstractTabDeckEditor *deckEditor; ///< Reference to the deck editor.
DeckListModel *deckModel; ///< Deck list model.
CardDatabaseModel *cardDatabaseModel; ///< Card database model.
CardDatabaseDisplayModel *cardDatabaseDisplayModel; ///< Card database display model.
QVBoxLayout *layout; ///< Layout for tabs and controls.
AbstractTabDeckEditor *deckEditor; ///< Reference to the deck editor.
DeckListModel *deckModel; ///< Deck list model.
CardDatabaseModel *cardDatabaseModel; ///< Card database model.
private slots:
/**
@ -132,6 +135,12 @@ private slots:
* @param index Index of the tab to close.
*/
void handleTabClose(int index);
/**
* @brief Adds card to maindeck or side depending on whether ctrl is held
* @param card
*/
void actAddCard(const ExactCard &card);
};
#endif // TAB_DECK_EDITOR_VISUAL_TAB_WIDGET_H