Convert json data holder to structs, rename variables, extract widget

- Extract bracket estimation UI from DeckEditorDeckDockWidget into a
  new CommanderBracketWidget
- Move CommanderSpellbook integration settings from CardsDisplaySettings
  to DeckEditorSettings (matching the settings refactor on master)
- Rename CommanderSpellbook integration variables to drop the redundant
  'DeckEditor' prefix

Took 4 minutes

# Commit time for manual adjustment:
# Took 6 minutes

# Commit time for manual adjustment:
# Took 8 minutes
This commit is contained in:
Lukas Brübach 2026-08-08 23:19:58 +02:00
parent b0035d41cb
commit 375898c565
30 changed files with 575 additions and 568 deletions

View file

@ -372,6 +372,7 @@ set(cockatrice_SOURCES
src/interface/key_signals.cpp src/interface/key_signals.cpp
src/interface/logger.cpp src/interface/logger.cpp
src/interface/widgets/tabs/api/commander_spellbook/commander_bracket_service.cpp src/interface/widgets/tabs/api/commander_spellbook/commander_bracket_service.cpp
src/interface/widgets/tabs/api/commander_spellbook/commander_bracket_widget.cpp
src/interface/widgets/tabs/api/commander_spellbook/handle_commander_brackets.cpp src/interface/widgets/tabs/api/commander_spellbook/handle_commander_brackets.cpp
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_bracket_navigation_widget.cpp src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_bracket_navigation_widget.cpp
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_bracket_navigation_widget.h src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_bracket_navigation_widget.h

View file

@ -3,19 +3,14 @@
#include "../../../client/settings/cache_settings.h" #include "../../../client/settings/cache_settings.h"
#include "../../../client/settings/shortcuts_settings.h" #include "../../../client/settings/shortcuts_settings.h"
#include "../settings_page/user_interface_settings_page.h" #include "../settings_page/user_interface_settings_page.h"
#include "../tabs/api/commander_spellbook/commander_bracket_service.h" #include "../tabs/api/commander_spellbook/commander_bracket_widget.h"
#include "../tabs/api/commander_spellbook/commander_spellbook_api_accessor.h"
#include "../tabs/api/commander_spellbook/commander_spellbook_bracket_explainer.h"
#include "deck_list_style_proxy.h" #include "deck_list_style_proxy.h"
#include "deck_state_manager.h" #include "deck_state_manager.h"
#include <QComboBox> #include <QComboBox>
#include <QDialogButtonBox>
#include <QDockWidget> #include <QDockWidget>
#include <QFormLayout>
#include <QHeaderView> #include <QHeaderView>
#include <QLabel> #include <QLabel>
#include <QMessageBox>
#include <QSplitter> #include <QSplitter>
#include <QTextEdit> #include <QTextEdit>
#include <libcockatrice/card/database/card_database_manager.h> #include <libcockatrice/card/database/card_database_manager.h>
@ -141,40 +136,7 @@ void DeckEditorDeckDockWidget::createDeckDock()
formatComboBox->addItem(tr("Loading Database...")); formatComboBox->addItem(tr("Loading Database..."));
formatComboBox->setEnabled(false); // Disable until loaded formatComboBox->setEnabled(false); // Disable until loaded
// --- Commander bracket row (hidden, unless format is 'commander') --- commanderBracketWidget = new CommanderBracketWidget(this);
bracketLabel = new QLabel(tr("Bracket:"), this);
bracketValueLabel = new QLabel(this);
bracketValueLabel->setText("-");
bracketValueLabel->setObjectName("bracketValueLabel");
bracketInfoButton = new QToolButton(this);
bracketInfoButton->setText("?");
bracketInfoButton->setAutoRaise(true);
bracketInfoButton->setEnabled(false);
bracketRefreshButton = new QToolButton(this);
bracketRefreshButton->setIcon(QPixmap("theme:icons/reload"));
bracketRefreshButton->setAutoRaise(true);
connect(bracketRefreshButton, &QToolButton::clicked, this, &DeckEditorDeckDockWidget::requestBracketEstimate);
if (SettingsCache::instance().cardsDisplay().getDeckEditorCommanderSpellbookIntegrationEnabled() !=
deckEditorCommanderSpellbookIntegrationEnabledIndexUnprompted) {
connect(&SettingsCache::instance().cardsDisplay(),
&CardsDisplaySettings::deckEditorCommanderSpellbookIntegrationEnabledChanged, this,
&DeckEditorDeckDockWidget::maybeAutoEstimateBracket);
connect(&SettingsCache::instance().cardsDisplay(),
&CardsDisplaySettings::deckEditorCommanderSpellbookIntegrationUseOfficialBracketNamesChanged, this,
&DeckEditorDeckDockWidget::maybeAutoEstimateBracket);
}
bracketLabel->setVisible(false);
bracketValueLabel->setVisible(false);
bracketInfoButton->setVisible(false);
bracketRefreshButton->setVisible(false);
connect(&CommanderBracketService::instance(), &CommanderBracketService::estimateFinished, this,
&DeckEditorDeckDockWidget::onEstimateBracketFinished);
commentsLabel = new QLabel(); commentsLabel = new QLabel();
commentsLabel->setObjectName("commentsLabel"); commentsLabel->setObjectName("commentsLabel");
@ -261,15 +223,7 @@ void DeckEditorDeckDockWidget::createDeckDock()
upperLayout->addWidget(formatLabel, 2, 0); upperLayout->addWidget(formatLabel, 2, 0);
upperLayout->addWidget(formatComboBox, 2, 1); upperLayout->addWidget(formatComboBox, 2, 1);
upperLayout->addWidget(bracketLabel, 3, 0); upperLayout->addWidget(commanderBracketWidget, 3, 0, 1, 2);
auto *bracketRow = new QHBoxLayout;
bracketRow->addWidget(bracketValueLabel);
bracketRow->addWidget(bracketInfoButton);
bracketRow->addWidget(bracketRefreshButton);
bracketRow->addStretch();
upperLayout->addLayout(bracketRow, 3, 1);
upperLayout->addWidget(bannerCardLabel, 4, 0); upperLayout->addWidget(bannerCardLabel, 4, 0);
upperLayout->addWidget(bannerCardComboBox, 4, 1); upperLayout->addWidget(bannerCardComboBox, 4, 1);
@ -335,151 +289,6 @@ void DeckEditorDeckDockWidget::createDeckDock()
} }
} }
bool DeckEditorDeckDockWidget::promptCommanderSpellbookIntegration()
{
QDialog dialog(this);
dialog.setWindowTitle(tr("CommanderSpellbook integration"));
auto *mainLayout = new QVBoxLayout(&dialog);
// Main text
auto *label = new QLabel(tr("CommanderSpellbook can analyze your deck and estimate its Commander bracket.\n\n"
"This sends your deck list to an external service.\n\n"
"CommanderSpellbook uses its own bracket naming system based on their own algorithm. "
"These names can be mapped to the official Commander brackets, but the mapping "
"is only an approximation."));
label->setWordWrap(true);
mainLayout->addWidget(label);
// Naming selector
auto *formLayout = new QFormLayout;
auto *namingCombo = new QComboBox(&dialog);
namingCombo->addItem(tr("CommanderSpellbook bracket names"));
namingCombo->addItem(tr("Official Commander bracket names (approximate)"));
namingCombo->setCurrentIndex(
SettingsCache::instance().cardsDisplay().getDeckEditorCommanderSpellbookIntegrationUseOfficialBracketNames()
? 1
: 0);
// Create label + explainer button
auto *labelWidget = new QWidget(&dialog);
auto *labelLayout = new QHBoxLayout(labelWidget);
labelLayout->setContentsMargins(0, 0, 0, 0);
auto *namingLabel = new QLabel(tr("Bracket naming:"), labelWidget);
auto *explainerButton = new QToolButton(labelWidget);
explainerButton->setText("?");
explainerButton->setAutoRaise(true);
explainerButton->setEnabled(false);
explainerButton->setToolTip(CommanderBracketNames::Explainer);
labelLayout->addWidget(namingLabel);
labelLayout->addWidget(explainerButton);
labelLayout->addStretch(); // push the button next to label, combo stays aligned
// Add row with the custom label widget
formLayout->addRow(labelWidget, namingCombo);
mainLayout->addLayout(formLayout);
// Buttons
auto *buttonBox = new QDialogButtonBox(&dialog);
auto *enableBtn = buttonBox->addButton(tr("Enable"), QDialogButtonBox::AcceptRole);
auto *automaticBtn = buttonBox->addButton(tr("Automatic"), QDialogButtonBox::ApplyRole);
auto *disableBtn = buttonBox->addButton(tr("Disable"), QDialogButtonBox::RejectRole);
mainLayout->addWidget(buttonBox);
// Track which button was clicked
QAbstractButton *clickedButton = nullptr;
QObject::connect(buttonBox, &QDialogButtonBox::clicked, &dialog, [&](QAbstractButton *btn) {
clickedButton = btn;
dialog.accept();
});
dialog.exec();
// Persist naming choice (if not disabled)
if (clickedButton != disableBtn) {
bool useOfficial = namingCombo->currentIndex() == 1;
SettingsCache::instance().cardsDisplay().setDeckEditorCommanderSpellbookIntegrationUseOfficialBracketNames(
useOfficial);
}
connect(&SettingsCache::instance().cardsDisplay(),
&CardsDisplaySettings::deckEditorCommanderSpellbookIntegrationEnabledChanged, this,
&DeckEditorDeckDockWidget::maybeAutoEstimateBracket);
connect(&SettingsCache::instance().cardsDisplay(),
&CardsDisplaySettings::deckEditorCommanderSpellbookIntegrationUseOfficialBracketNamesChanged, this,
&DeckEditorDeckDockWidget::maybeAutoEstimateBracket);
// Persist integration mode
if (clickedButton == disableBtn) {
SettingsCache::instance().cardsDisplay().setDeckEditorCommanderSpellbookIntegrationEnabled(
deckEditorCommanderSpellbookIntegrationEnabledIndexDisabled);
return false;
}
if (clickedButton == enableBtn) {
SettingsCache::instance().cardsDisplay().setDeckEditorCommanderSpellbookIntegrationEnabled(
deckEditorCommanderSpellbookIntegrationEnabledIndexEnabled);
return true;
}
if (clickedButton == automaticBtn) {
SettingsCache::instance().cardsDisplay().setDeckEditorCommanderSpellbookIntegrationEnabled(
deckEditorCommanderSpellbookIntegrationEnabledIndexAutomatic);
return true;
}
return false;
}
void DeckEditorDeckDockWidget::updateBracketVisibility(bool visible)
{
bracketLabel->setVisible(visible);
bracketValueLabel->setVisible(visible);
bracketInfoButton->setVisible(visible);
bracketRefreshButton->setVisible(visible);
}
void DeckEditorDeckDockWidget::requestBracketEstimate()
{
bracketRefreshButton->setEnabled(false);
bracketInfoButton->setEnabled(false);
bracketValueLabel->setText(tr("Calculating…"));
requestId = CommanderBracketService::instance().estimateBracket(deckStateManager->getDeckList(), this);
}
void DeckEditorDeckDockWidget::onEstimateBracketFinished(quint64 id,
QObject *requester,
const CommanderBracketEstimate &result)
{
if (requester != this || id != requestId) {
return;
}
BracketExplainer explainer;
lastBracketExplanation = explainer.explain(result.rawResult);
// Display bracket
bracketValueLabel->setText(
SettingsCache::instance().cardsDisplay().getDeckEditorCommanderSpellbookIntegrationUseOfficialBracketNames()
? result.officialName
: result.displayName);
bracketRefreshButton->setEnabled(true);
// Build tooltip
QString tooltip;
for (const auto &section : lastBracketExplanation.sections) {
tooltip += "<b>" + section.title + "</b><br>";
for (const auto &line : section.bulletPoints) {
tooltip += "• " + line + "<br>";
}
tooltip += "<br>";
}
bracketInfoButton->setToolTip(tooltip);
bracketInfoButton->setEnabled(!tooltip.isEmpty());
}
void DeckEditorDeckDockWidget::initializeFormats() void DeckEditorDeckDockWidget::initializeFormats()
{ {
QStringList allFormats = CardDatabaseManager::query()->getAllFormatsWithCount().keys(); QStringList allFormats = CardDatabaseManager::query()->getAllFormatsWithCount().keys();
@ -509,61 +318,10 @@ void DeckEditorDeckDockWidget::initializeFormats()
deckStateManager->setFormat(""); // clear format if deselected deckStateManager->setFormat(""); // clear format if deselected
} }
const bool isCommander = (formatKey.compare("commander", Qt::CaseInsensitive) == 0); commanderBracketWidget->setDeck(deckStateManager->getDeckListShared());
const bool commanderSpellbookIntegrationEnabled =
SettingsCache::instance().cardsDisplay().getDeckEditorCommanderSpellbookIntegrationEnabled() !=
deckEditorCommanderSpellbookIntegrationEnabledIndexDisabled;
const bool bracketVisible = isCommander && commanderSpellbookIntegrationEnabled;
updateBracketVisibility(bracketVisible);
if (!isCommander) {
bracketValueLabel->setText("-");
bracketInfoButton->setToolTip({});
bracketInfoButton->setEnabled(false);
bracketRefreshButton->setEnabled(false);
} else {
bracketRefreshButton->setEnabled(true);
maybeAutoEstimateBracket();
}
}); });
maybeAutoEstimateBracket(); commanderBracketWidget->setDeck(deckStateManager->getDeckListShared());
}
void DeckEditorDeckDockWidget::maybeAutoEstimateBracket()
{
const QString formatKey = deckStateManager->getDeckList().getGameFormat();
const bool isCommander = (formatKey.compare("commander", Qt::CaseInsensitive) == 0);
int mode = SettingsCache::instance().cardsDisplay().getDeckEditorCommanderSpellbookIntegrationEnabled();
if (!isCommander || mode == deckEditorCommanderSpellbookIntegrationEnabledIndexDisabled) {
updateBracketVisibility(false);
return;
}
if (mode == deckEditorCommanderSpellbookIntegrationEnabledIndexUnprompted) {
if (!promptCommanderSpellbookIntegration()) {
updateBracketVisibility(false);
return;
}
}
updateBracketVisibility(true);
mode = SettingsCache::instance().cardsDisplay().getDeckEditorCommanderSpellbookIntegrationEnabled();
if (mode != deckEditorCommanderSpellbookIntegrationEnabledIndexAutomatic) {
return;
}
// Avoid firing if we already have a result or a request in flight
if (!bracketRefreshButton->isEnabled()) {
return;
}
// Defer to avoid races during init / model rebuild
QTimer::singleShot(0, this, &DeckEditorDeckDockWidget::requestBracketEstimate);
} }
ExactCard DeckEditorDeckDockWidget::getCurrentCard() ExactCard DeckEditorDeckDockWidget::getCurrentCard()
@ -745,6 +503,8 @@ void DeckEditorDeckDockWidget::syncDisplayWidgetsToModel()
formatComboBox->setCurrentIndex(formatComboBox->findData(deckStateManager->getMetadata().gameFormat)); formatComboBox->setCurrentIndex(formatComboBox->findData(deckStateManager->getMetadata().gameFormat));
formatComboBox->blockSignals(false); formatComboBox->blockSignals(false);
commanderBracketWidget->setDeck(deckStateManager->getDeckListShared());
deckTagsDisplayWidget->blockSignals(true); deckTagsDisplayWidget->blockSignals(true);
deckTagsDisplayWidget->setTags(deckStateManager->getMetadata().tags); deckTagsDisplayWidget->setTags(deckStateManager->getMetadata().tags);
deckTagsDisplayWidget->blockSignals(false); deckTagsDisplayWidget->blockSignals(false);
@ -998,8 +758,7 @@ void DeckEditorDeckDockWidget::retranslateUi()
commentsLabel->setText(tr("&Comments:")); commentsLabel->setText(tr("&Comments:"));
activeGroupCriteriaLabel->setText(tr("Group by:")); activeGroupCriteriaLabel->setText(tr("Group by:"));
formatLabel->setText(tr("Format:")); formatLabel->setText(tr("Format:"));
bracketInfoButton->setToolTip(tr("Why this bracket?")); commanderBracketWidget->retranslateUi();
bracketRefreshButton->setToolTip(tr("Recalculate bracket"));
hashLabel1->setText(tr("Hash:")); hashLabel1->setText(tr("Hash:"));

View file

@ -10,7 +10,6 @@
#include "../../../interface/widgets/tabs/abstract_tab_deck_editor.h" #include "../../../interface/widgets/tabs/abstract_tab_deck_editor.h"
#include "../../key_signals.h" #include "../../key_signals.h"
#include "../tabs/api/commander_spellbook/commander_spellbook_bracket_explainer.h"
#include "../utility/custom_line_edit.h" #include "../utility/custom_line_edit.h"
#include "../visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h" #include "../visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h"
#include "deck_list_history_manager_widget.h" #include "deck_list_history_manager_widget.h"
@ -22,7 +21,7 @@
#include <QTreeView> #include <QTreeView>
#include <libcockatrice/card/card_info.h> #include <libcockatrice/card/card_info.h>
struct CommanderBracketEstimate; class CommanderBracketWidget;
class DeckListModel; class DeckListModel;
class AbstractTabDeckEditor; class AbstractTabDeckEditor;
class DeckEditorDeckDockWidget : public QDockWidget class DeckEditorDeckDockWidget : public QDockWidget
@ -35,9 +34,6 @@ public:
QTreeView *deckView; QTreeView *deckView;
QComboBox *bannerCardComboBox; QComboBox *bannerCardComboBox;
void createDeckDock(); void createDeckDock();
bool promptCommanderSpellbookIntegration();
void updateBracketVisibility(bool visible);
void requestBracketEstimate();
ExactCard getCurrentCard(); ExactCard getCurrentCard();
void retranslateUi(); void retranslateUi();
@ -64,8 +60,6 @@ public slots:
void actSwapSelection(); void actSwapSelection();
void actRemoveCard(); void actRemoveCard();
void initializeFormats(); void initializeFormats();
void maybeAutoEstimateBracket();
void onEstimateBracketFinished(quint64 id, QObject *requester, const CommanderBracketEstimate &result);
signals: signals:
void selectedCardChanged(const ExactCard &card); void selectedCardChanged(const ExactCard &card);
@ -96,14 +90,7 @@ private:
QAction *aRemoveCard, *aIncrement, *aDecrement, *aSwapCard; QAction *aRemoveCard, *aIncrement, *aDecrement, *aSwapCard;
QLabel *bracketLabel; CommanderBracketWidget *commanderBracketWidget;
QLabel *bracketValueLabel;
QToolButton *bracketInfoButton;
QToolButton *bracketRefreshButton;
BracketExplanation lastBracketExplanation;
quint64 requestId;
DeckListModel *getModel() const; DeckListModel *getModel() const;
[[nodiscard]] QModelIndexList getSelectedCardNodeSourceIndices() const; [[nodiscard]] QModelIndexList getSelectedCardNodeSourceIndices() const;

View file

@ -57,6 +57,14 @@ public:
*/ */
const DeckList &getDeckList() const; const DeckList &getDeckList() const;
/**
* @brief Gets the underlying DeckList.
*/
QSharedPointer<DeckList> getDeckListShared() const
{
return deckList;
}
/** /**
* @brief Creates a LoadedDeck containing the contents of the current deck and the current LoadInfo. * @brief Creates a LoadedDeck containing the contents of the current deck and the current LoadInfo.
* *

View file

@ -2,6 +2,7 @@
#include "../../../client/settings/cache_settings.h" #include "../../../client/settings/cache_settings.h"
#include "../interface/widgets/tabs/tab_supervisor.h" #include "../interface/widgets/tabs/tab_supervisor.h"
#include "../tabs/api/commander_spellbook/commander_spellbook_bracket_explainer.h"
#include <QGridLayout> #include <QGridLayout>
#include <libcockatrice/settings/cards_display_settings.h> #include <libcockatrice/settings/cards_display_settings.h>
@ -161,56 +162,53 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage()
connect(&defaultDeckEditorTypeSelector, QOverload<int>::of(&QComboBox::currentIndexChanged), connect(&defaultDeckEditorTypeSelector, QOverload<int>::of(&QComboBox::currentIndexChanged),
&SettingsCache::instance().deckEditor(), &DeckEditorSettings::setDefaultDeckEditorType); &SettingsCache::instance().deckEditor(), &DeckEditorSettings::setDefaultDeckEditorType);
deckEditorCommanderSpellBookIntegrationUseOfficialBracketNamesExplainer.setText("?"); commanderSpellbookIntegrationUseOfficialBracketNamesExplainer.setText("?");
deckEditorCommanderSpellBookIntegrationUseOfficialBracketNamesExplainer.setAutoRaise(true); commanderSpellbookIntegrationUseOfficialBracketNamesExplainer.setAutoRaise(true);
deckEditorCommanderSpellBookIntegrationUseOfficialBracketNamesExplainer.setEnabled(false); commanderSpellbookIntegrationUseOfficialBracketNamesExplainer.setEnabled(false);
// Add items with userData = internal enum // Add items with userData = internal enum
deckEditorCommanderSpellbookIntegrationEnabledSelector.addItem( commanderSpellbookIntegrationEnabledSelector.addItem(tr("Disabled"),
tr("Disabled"), deckEditorCommanderSpellbookIntegrationEnabledIndexDisabled); commanderSpellbookIntegrationEnabledIndexDisabled);
deckEditorCommanderSpellbookIntegrationEnabledSelector.addItem( commanderSpellbookIntegrationEnabledSelector.addItem(tr("Enabled"),
tr("Enabled"), deckEditorCommanderSpellbookIntegrationEnabledIndexEnabled); commanderSpellbookIntegrationEnabledIndexEnabled);
deckEditorCommanderSpellbookIntegrationEnabledSelector.addItem( commanderSpellbookIntegrationEnabledSelector.addItem(tr("Automatic"),
tr("Automatic"), deckEditorCommanderSpellbookIntegrationEnabledIndexAutomatic); commanderSpellbookIntegrationEnabledIndexAutomatic);
int storedMode = SettingsCache::instance().cardsDisplay().getDeckEditorCommanderSpellbookIntegrationEnabled(); int storedMode = SettingsCache::instance().deckEditor().getCommanderSpellbookIntegrationEnabled();
for (int i = 0; i < deckEditorCommanderSpellbookIntegrationEnabledSelector.count(); ++i) { for (int i = 0; i < commanderSpellbookIntegrationEnabledSelector.count(); ++i) {
if (deckEditorCommanderSpellbookIntegrationEnabledSelector.itemData(i).toInt() == storedMode) { if (commanderSpellbookIntegrationEnabledSelector.itemData(i).toInt() == storedMode) {
deckEditorCommanderSpellbookIntegrationEnabledSelector.setCurrentIndex(i); commanderSpellbookIntegrationEnabledSelector.setCurrentIndex(i);
break; break;
} }
} }
connect(&deckEditorCommanderSpellbookIntegrationEnabledSelector, connect(&commanderSpellbookIntegrationEnabledSelector, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int index) { [this](int index) {
int mode = deckEditorCommanderSpellbookIntegrationEnabledSelector.itemData(index).toInt(); int mode = commanderSpellbookIntegrationEnabledSelector.itemData(index).toInt();
SettingsCache::instance().cardsDisplay().setDeckEditorCommanderSpellbookIntegrationEnabled(mode); SettingsCache::instance().deckEditor().setCommanderSpellbookIntegrationEnabled(mode);
updateCommanderSpellbookUiState(); updateCommanderSpellbookUiState();
}); });
deckEditorCommanderSpellbookIntegrationBracketNamingSelector.addItem( commanderSpellbookIntegrationBracketNamingSelector.addItem(
tr("CommanderSpellbook bracket names")); // index 0 = false tr("CommanderSpellbook bracket names")); // index 0 = false
deckEditorCommanderSpellbookIntegrationBracketNamingSelector.addItem( commanderSpellbookIntegrationBracketNamingSelector.addItem(
tr("Official Commander bracket names (approximate)")); // index 1 = true tr("Official Commander bracket names (approximate)")); // index 1 = true
deckEditorCommanderSpellbookIntegrationBracketNamingSelector.setCurrentIndex( commanderSpellbookIntegrationBracketNamingSelector.setCurrentIndex(
SettingsCache::instance().cardsDisplay().getDeckEditorCommanderSpellbookIntegrationUseOfficialBracketNames() SettingsCache::instance().deckEditor().getCommanderSpellbookIntegrationUseOfficialBracketNames() ? 1 : 0);
? 1
: 0);
connect( connect(&commanderSpellbookIntegrationBracketNamingSelector, QOverload<int>::of(&QComboBox::currentIndexChanged),
&deckEditorCommanderSpellbookIntegrationBracketNamingSelector, &SettingsCache::instance(), [](int index) {
QOverload<int>::of(&QComboBox::currentIndexChanged), &SettingsCache::instance(), [](int index) { SettingsCache::instance().deckEditor().setCommanderSpellbookIntegrationUseOfficialBracketNames(index ==
SettingsCache::instance().cardsDisplay().setDeckEditorCommanderSpellbookIntegrationUseOfficialBracketNames( 1);
index == 1); });
});
updateCommanderSpellbookUiState(); updateCommanderSpellbookUiState();
auto *labelLayout = new QHBoxLayout; auto *labelLayout = new QHBoxLayout;
labelLayout->setContentsMargins(0, 0, 0, 0); labelLayout->setContentsMargins(0, 0, 0, 0);
labelLayout->addWidget(&deckEditorCommanderSpellbookIntegrationUseOfficialBracketNamesLabel); labelLayout->addWidget(&commanderSpellbookIntegrationUseOfficialBracketNamesLabel);
labelLayout->addWidget(&deckEditorCommanderSpellBookIntegrationUseOfficialBracketNamesExplainer); labelLayout->addWidget(&commanderSpellbookIntegrationUseOfficialBracketNamesExplainer);
auto *labelWidget = new QWidget; auto *labelWidget = new QWidget;
labelWidget->setLayout(labelLayout); labelWidget->setLayout(labelLayout);
@ -223,10 +221,10 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage()
deckEditorGrid->addWidget(&visualDeckStoragePromptForConversionSelector, 3, 1); deckEditorGrid->addWidget(&visualDeckStoragePromptForConversionSelector, 3, 1);
deckEditorGrid->addWidget(&defaultDeckEditorTypeLabel, 4, 0); deckEditorGrid->addWidget(&defaultDeckEditorTypeLabel, 4, 0);
deckEditorGrid->addWidget(&defaultDeckEditorTypeSelector, 4, 1); deckEditorGrid->addWidget(&defaultDeckEditorTypeSelector, 4, 1);
deckEditorGrid->addWidget(&deckEditorCommanderSpellbookIntegrationEnabledLabel, 5, 0); deckEditorGrid->addWidget(&commanderSpellbookIntegrationEnabledLabel, 5, 0);
deckEditorGrid->addWidget(&deckEditorCommanderSpellbookIntegrationEnabledSelector, 5, 1); deckEditorGrid->addWidget(&commanderSpellbookIntegrationEnabledSelector, 5, 1);
deckEditorGrid->addWidget(labelWidget, 6, 0); deckEditorGrid->addWidget(labelWidget, 6, 0);
deckEditorGrid->addWidget(&deckEditorCommanderSpellbookIntegrationBracketNamingSelector); deckEditorGrid->addWidget(&commanderSpellbookIntegrationBracketNamingSelector, 6, 1);
deckEditorGroupBox = new QGroupBox; deckEditorGroupBox = new QGroupBox;
deckEditorGroupBox->setLayout(deckEditorGrid); deckEditorGroupBox->setLayout(deckEditorGrid);
@ -272,23 +270,22 @@ void UserInterfaceSettingsPage::setNotificationEnabled(QT_STATE_CHANGED_T i)
void UserInterfaceSettingsPage::updateCommanderSpellbookUiState() void UserInterfaceSettingsPage::updateCommanderSpellbookUiState()
{ {
const int mode = SettingsCache::instance().cardsDisplay().getDeckEditorCommanderSpellbookIntegrationEnabled(); const int mode = SettingsCache::instance().deckEditor().getCommanderSpellbookIntegrationEnabled();
const bool enabled = mode != deckEditorCommanderSpellbookIntegrationEnabledIndexDisabled && const bool enabled = mode != commanderSpellbookIntegrationEnabledIndexDisabled &&
mode != deckEditorCommanderSpellbookIntegrationEnabledIndexUnprompted; mode != commanderSpellbookIntegrationEnabledIndexUnprompted;
deckEditorCommanderSpellbookIntegrationBracketNamingSelector.setEnabled(enabled); commanderSpellbookIntegrationBracketNamingSelector.setEnabled(enabled);
deckEditorCommanderSpellBookIntegrationUseOfficialBracketNamesExplainer.setEnabled(enabled); commanderSpellbookIntegrationUseOfficialBracketNamesExplainer.setEnabled(enabled);
deckEditorCommanderSpellbookIntegrationUseOfficialBracketNamesLabel.setVisible(enabled); commanderSpellbookIntegrationUseOfficialBracketNamesLabel.setVisible(enabled);
deckEditorCommanderSpellBookIntegrationUseOfficialBracketNamesExplainer.setVisible(enabled); commanderSpellbookIntegrationUseOfficialBracketNamesExplainer.setVisible(enabled);
deckEditorCommanderSpellbookIntegrationBracketNamingSelector.setVisible(enabled); commanderSpellbookIntegrationBracketNamingSelector.setVisible(enabled);
if (enabled) { if (enabled) {
// Sync selector with the current stored bool // Sync selector with the current stored bool
const bool useOfficial = SettingsCache::instance() const bool useOfficial =
.cardsDisplay() SettingsCache::instance().deckEditor().getCommanderSpellbookIntegrationUseOfficialBracketNames();
.getDeckEditorCommanderSpellbookIntegrationUseOfficialBracketNames(); commanderSpellbookIntegrationBracketNamingSelector.setCurrentIndex(useOfficial ? 1 : 0);
deckEditorCommanderSpellbookIntegrationBracketNamingSelector.setCurrentIndex(useOfficial ? 1 : 0);
} }
} }
@ -330,22 +327,21 @@ void UserInterfaceSettingsPage::retranslateUi()
defaultDeckEditorTypeSelector.setItemText(TabSupervisor::ClassicDeckEditor, tr("Classic Deck Editor")); defaultDeckEditorTypeSelector.setItemText(TabSupervisor::ClassicDeckEditor, tr("Classic Deck Editor"));
defaultDeckEditorTypeSelector.setItemText(TabSupervisor::VisualDeckEditor, tr("Visual Deck Editor")); defaultDeckEditorTypeSelector.setItemText(TabSupervisor::VisualDeckEditor, tr("Visual Deck Editor"));
deckEditorCommanderSpellbookIntegrationEnabledLabel.setText( commanderSpellbookIntegrationEnabledLabel.setText(
tr("CommanderSpellbook integration to estimate commander bracket")); tr("CommanderSpellbook integration to estimate commander bracket"));
deckEditorCommanderSpellbookIntegrationEnabledSelector.setItemText( commanderSpellbookIntegrationEnabledSelector.setItemText(commanderSpellbookIntegrationEnabledIndexDisabled,
deckEditorCommanderSpellbookIntegrationEnabledIndexDisabled, tr("Disabled")); tr("Disabled"));
deckEditorCommanderSpellbookIntegrationEnabledSelector.setItemText( commanderSpellbookIntegrationEnabledSelector.setItemText(commanderSpellbookIntegrationEnabledIndexEnabled,
deckEditorCommanderSpellbookIntegrationEnabledIndexEnabled, tr("Enabled")); tr("Enabled"));
deckEditorCommanderSpellbookIntegrationEnabledSelector.setItemText( commanderSpellbookIntegrationEnabledSelector.setItemText(commanderSpellbookIntegrationEnabledIndexAutomatic,
deckEditorCommanderSpellbookIntegrationEnabledIndexAutomatic, tr("Automatic")); tr("Automatic"));
deckEditorCommanderSpellbookIntegrationUseOfficialBracketNamesLabel.setText(tr("Bracket naming")); commanderSpellbookIntegrationUseOfficialBracketNamesLabel.setText(tr("Bracket naming"));
deckEditorCommanderSpellbookIntegrationBracketNamingSelector.setItemText( commanderSpellbookIntegrationBracketNamingSelector.setItemText(
0, CommanderBracketNames::CommanderSpellbookBracketNames); 0, CommanderBracketNames::CommanderSpellbookBracketNames);
deckEditorCommanderSpellbookIntegrationBracketNamingSelector.setItemText( commanderSpellbookIntegrationBracketNamingSelector.setItemText(
1, CommanderBracketNames::OfficialCommanderBracketNames); 1, CommanderBracketNames::OfficialCommanderBracketNames);
deckEditorCommanderSpellBookIntegrationUseOfficialBracketNamesExplainer.setToolTip( commanderSpellbookIntegrationUseOfficialBracketNamesExplainer.setToolTip(CommanderBracketNames::Explainer);
CommanderBracketNames::Explainer);
replayGroupBox->setTitle(tr("Replay settings")); replayGroupBox->setTitle(tr("Replay settings"));
rewindBufferingMsLabel.setText(tr("Buffer time for backwards skip via shortcut:")); rewindBufferingMsLabel.setText(tr("Buffer time for backwards skip via shortcut:"));
rewindBufferingMsBox.setSuffix(" ms"); rewindBufferingMsBox.setSuffix(" ms");

View file

@ -12,21 +12,6 @@
#include <libcockatrice/settings/cards_display_settings.h> #include <libcockatrice/settings/cards_display_settings.h>
#include <libcockatrice/utility/macros.h> #include <libcockatrice/utility/macros.h>
namespace CommanderBracketNames
{
inline const char *CommanderSpellbookBracketNames = QT_TR_NOOP("CommanderSpellbook");
inline const char *OfficialCommanderBracketNames = QT_TR_NOOP("Official (approximate)");
inline const char *Explainer = QT_TR_NOOP(
"The bracket system combines both objective data, as well as subjective play experience to estimate a "
"bracket for a deck.\nCommanderSpellbook's estimation is algorithmical, which means that it can only operate "
"on the objective data, not the subjective intent. \nThey have chosen to represent this by defining their "
"own bracket system which matches their algorithm.\n"
"This custom bracket system maps loosely to the standard system. \nYou may choose to use these mapped "
"standardized names if these are more familiar to you, however, you should keep in mind that these are just "
"rough estimations.\n\nAlways consider the subjective factors of the bracket system when determing a deck's "
"final bracket!");
} // namespace CommanderBracketNames
class UserInterfaceSettingsPage : public AbstractSettingsPage class UserInterfaceSettingsPage : public AbstractSettingsPage
{ {
Q_OBJECT Q_OBJECT
@ -57,11 +42,11 @@ private:
QCheckBox visualDeckStorageSelectionAnimationCheckBox; QCheckBox visualDeckStorageSelectionAnimationCheckBox;
QLabel defaultDeckEditorTypeLabel; QLabel defaultDeckEditorTypeLabel;
QComboBox defaultDeckEditorTypeSelector; QComboBox defaultDeckEditorTypeSelector;
QLabel deckEditorCommanderSpellbookIntegrationEnabledLabel; QLabel commanderSpellbookIntegrationEnabledLabel;
QComboBox deckEditorCommanderSpellbookIntegrationEnabledSelector; QComboBox commanderSpellbookIntegrationEnabledSelector;
QLabel deckEditorCommanderSpellbookIntegrationUseOfficialBracketNamesLabel; QLabel commanderSpellbookIntegrationUseOfficialBracketNamesLabel;
QToolButton deckEditorCommanderSpellBookIntegrationUseOfficialBracketNamesExplainer; QToolButton commanderSpellbookIntegrationUseOfficialBracketNamesExplainer;
QComboBox deckEditorCommanderSpellbookIntegrationBracketNamingSelector; QComboBox commanderSpellbookIntegrationBracketNamingSelector;
QLabel rewindBufferingMsLabel; QLabel rewindBufferingMsLabel;
QSpinBox rewindBufferingMsBox; QSpinBox rewindBufferingMsBox;
QGroupBox *generalGroupBox; QGroupBox *generalGroupBox;

View file

@ -1,9 +1,11 @@
#include "card_in_deck_request.h" #include "card_in_deck_request.h"
void CardInDeckRequest::fromJson(const QJsonObject &json) CardInDeckRequest CardInDeckRequest::fromJson(const QJsonObject &json)
{ {
card = json.value("card").toString(); CardInDeckRequest request;
quantity = json.value("quantity").toInt(); request.card = json.value("card").toString();
request.quantity = json.value("quantity").toInt();
return request;
} }
QJsonObject CardInDeckRequest::toJson() const QJsonObject CardInDeckRequest::toJson() const
@ -13,9 +15,3 @@ QJsonObject CardInDeckRequest::toJson() const
json.insert("quantity", quantity); json.insert("quantity", quantity);
return json; return json;
} }
void CardInDeckRequest::debugPrint() const
{
qDebug() << "Card:" << card;
qDebug() << "Quantity:" << quantity;
}

View file

@ -2,20 +2,11 @@
#define COCKATRICE_CARD_IN_DECK_REQUEST_H #define COCKATRICE_CARD_IN_DECK_REQUEST_H
#include <QJsonObject> #include <QJsonObject>
class CardInDeckRequest struct CardInDeckRequest
{ {
public: static CardInDeckRequest fromJson(const QJsonObject &json);
// Constructor
CardInDeckRequest() = default;
// Parse deck-related data from JSON
void fromJson(const QJsonObject &json);
QJsonObject toJson() const; QJsonObject toJson() const;
// Debug method for logging
void debugPrint() const;
private:
QString card; QString card;
int quantity; int quantity;
}; };

View file

@ -1,22 +1,26 @@
#include "commander_spellbook_card_result.h" #include "commander_spellbook_card_result.h"
void CommanderSpellbookCardResult::fromJson(const QJsonObject &json) CommanderSpellbookCardResult CommanderSpellbookCardResult::fromJson(const QJsonObject &json)
{ {
id = json.value("id").toString(); CommanderSpellbookCardResult result;
name = json.value("name").toString();
oracleId = json.value("oracleId").toString();
spoiler = json.value("spoiler").toBool();
typeLine = json.value("typeLine").toString();
imageUriFrontPng = json.value("imageUriFrontPng").toString(); result.id = json.value("id").toString();
imageUriFrontLarge = json.value("imageUriFrontLarge").toString(); result.name = json.value("name").toString();
imageUriFrontNormal = json.value("imageUriFrontNormal").toString(); result.oracleId = json.value("oracleId").toString();
imageUriFrontSmall = json.value("imageUriFrontSmall").toString(); result.spoiler = json.value("spoiler").toBool();
imageUriFrontArtCrop = json.value("imageUriFrontArtCrop").toString(); result.typeLine = json.value("typeLine").toString();
imageUriBackPng = json.value("imageUriBackPng").toString(); result.imageUriFrontPng = json.value("imageUriFrontPng").toString();
imageUriBackLarge = json.value("imageUriBackLarge").toString(); result.imageUriFrontLarge = json.value("imageUriFrontLarge").toString();
imageUriBackNormal = json.value("imageUriBackNormal").toString(); result.imageUriFrontNormal = json.value("imageUriFrontNormal").toString();
imageUriBackSmall = json.value("imageUriBackSmall").toString(); result.imageUriFrontSmall = json.value("imageUriFrontSmall").toString();
imageUriBackArtCrop = json.value("imageUriBackArtCrop").toString(); result.imageUriFrontArtCrop = json.value("imageUriFrontArtCrop").toString();
result.imageUriBackPng = json.value("imageUriBackPng").toString();
result.imageUriBackLarge = json.value("imageUriBackLarge").toString();
result.imageUriBackNormal = json.value("imageUriBackNormal").toString();
result.imageUriBackSmall = json.value("imageUriBackSmall").toString();
result.imageUriBackArtCrop = json.value("imageUriBackArtCrop").toString();
return result;
} }

View file

@ -3,10 +3,9 @@
#include <QJsonObject> #include <QJsonObject>
#include <QString> #include <QString>
class CommanderSpellbookCardResult struct CommanderSpellbookCardResult
{ {
public: static CommanderSpellbookCardResult fromJson(const QJsonObject &json);
void fromJson(const QJsonObject &json);
QString id; QString id;
QString name; QString name;

View file

@ -1,14 +1,11 @@
#include "commander_spellbook_deck_request.h" #include "commander_spellbook_deck_request.h"
#include <QDebug>
#include <QJsonArray> #include <QJsonArray>
#include <libcockatrice/deck_list/deck_list.h>
#include <libcockatrice/deck_list/tree/deck_list_card_node.h> #include <libcockatrice/deck_list/tree/deck_list_card_node.h>
void CommanderSpellbookDeckRequest::fromJson(const QJsonObject &json) CommanderSpellbookDeckRequest CommanderSpellbookDeckRequest::fromJson(const QJsonObject &json)
{ {
mainDeck.clear(); CommanderSpellbookDeckRequest request;
commanderDeck.clear();
// Main deck // Main deck
const QJsonArray mainArray = json.value("main").toArray(); const QJsonArray mainArray = json.value("main").toArray();
@ -17,12 +14,10 @@ void CommanderSpellbookDeckRequest::fromJson(const QJsonObject &json)
continue; continue;
} }
CardInDeckRequest card; request.mainDeck.append(CardInDeckRequest::fromJson(value.toObject()));
card.fromJson(value.toObject());
mainDeck.append(card);
// Max size allowed by commanderspellbook // Max size allowed by commanderspellbook
if (mainDeck.size() >= 600) { if (request.mainDeck.size() >= 600) {
break; break;
} }
} }
@ -34,15 +29,15 @@ void CommanderSpellbookDeckRequest::fromJson(const QJsonObject &json)
continue; continue;
} }
CardInDeckRequest card; request.commanderDeck.append(CardInDeckRequest::fromJson(value.toObject()));
card.fromJson(value.toObject());
commanderDeck.append(card);
// Max size allowed by commanderspellbook // Max size allowed by commanderspellbook
if (commanderDeck.size() >= 12) { if (request.commanderDeck.size() >= 12) {
break; break;
} }
} }
return request;
} }
QJsonObject CommanderSpellbookDeckRequest::toJson() const QJsonObject CommanderSpellbookDeckRequest::toJson() const
@ -65,10 +60,9 @@ QJsonObject CommanderSpellbookDeckRequest::toJson() const
return json; return json;
} }
void CommanderSpellbookDeckRequest::fromDeckList(const DeckList &deck) CommanderSpellbookDeckRequest CommanderSpellbookDeckRequest::fromDeckList(const DeckList &deck)
{ {
mainDeck.clear(); CommanderSpellbookDeckRequest request;
commanderDeck.clear();
// --- Mainboard --- // --- Mainboard ---
const auto mainCards = deck.getCardNodes({DECK_ZONE_MAIN}); const auto mainCards = deck.getCardNodes({DECK_ZONE_MAIN});
@ -77,16 +71,13 @@ void CommanderSpellbookDeckRequest::fromDeckList(const DeckList &deck)
continue; continue;
} }
CardInDeckRequest req;
QJsonObject json; QJsonObject json;
json.insert("card", node->getName()); json.insert("card", node->getName());
json.insert("quantity", node->getNumber()); json.insert("quantity", node->getNumber());
req.fromJson(json); request.mainDeck.append(CardInDeckRequest::fromJson(json));
mainDeck.append(req);
// Max size allowed by commanderspellbook // Max size allowed by commanderspellbook
if (mainDeck.size() >= 600) { if (request.mainDeck.size() >= 600) {
break; break;
} }
} }
@ -94,25 +85,11 @@ void CommanderSpellbookDeckRequest::fromDeckList(const DeckList &deck)
// --- Commander (bannerCard) --- // --- Commander (bannerCard) ---
const auto &metadata = deck.getMetadata(); const auto &metadata = deck.getMetadata();
if (!metadata.bannerCard.name.isEmpty()) { if (!metadata.bannerCard.name.isEmpty()) {
CardInDeckRequest commander;
QJsonObject json; QJsonObject json;
json.insert("card", metadata.bannerCard.name); json.insert("card", metadata.bannerCard.name);
json.insert("quantity", 1); json.insert("quantity", 1);
commander.fromJson(json); request.commanderDeck.append(CardInDeckRequest::fromJson(json));
commanderDeck.append(commander);
}
}
void CommanderSpellbookDeckRequest::debugPrint() const
{
qDebug() << "Main deck:";
for (const CardInDeckRequest &card : mainDeck) {
card.debugPrint();
}
qDebug() << "Commanders:";
for (const CardInDeckRequest &card : commanderDeck) {
card.debugPrint();
} }
return request;
} }

View file

@ -4,31 +4,16 @@
#include "libcockatrice/deck_list/deck_list.h" #include "libcockatrice/deck_list/deck_list.h"
#include <QJsonObject> #include <QJsonObject>
#include <QVector> #include <QList>
class CommanderSpellbookDeckRequest struct CommanderSpellbookDeckRequest
{ {
public: static CommanderSpellbookDeckRequest fromJson(const QJsonObject &json);
CommanderSpellbookDeckRequest() = default; static CommanderSpellbookDeckRequest fromDeckList(const DeckList &deck);
void fromJson(const QJsonObject &json);
QJsonObject toJson() const; QJsonObject toJson() const;
void fromDeckList(const DeckList &deck);
void debugPrint() const; QList<CardInDeckRequest> mainDeck; // maxItems: 600
QList<CardInDeckRequest> commanderDeck; // maxItems: 12
const QVector<CardInDeckRequest> &main() const
{
return mainDeck;
}
const QVector<CardInDeckRequest> &commanders() const
{
return commanderDeck;
}
private:
QVector<CardInDeckRequest> mainDeck; // maxItems: 600
QVector<CardInDeckRequest> commanderDeck; // maxItems: 12
}; };
#endif // COCKATRICE_COMMANDER_SPELLBOOK_DECK_REQUEST_H #endif // COCKATRICE_COMMANDER_SPELLBOOK_DECK_REQUEST_H

View file

@ -1,23 +1,10 @@
#include "commander_spellbook_estimate_bracket_result.h" #include "commander_spellbook_estimate_bracket_result.h"
void EstimateBracketResult::fromJson(const QJsonObject &json) EstimateBracketResult EstimateBracketResult::fromJson(const QJsonObject &json)
{ {
bracketTag = json.value("bracketTag").toString(); EstimateBracketResult result;
gameChangerCards.clear(); result.bracketTag = json.value("bracketTag").toString();
massLandDenialCards.clear();
extraTurnCards.clear();
massLandDenialTemplates.clear();
extraTurnTemplates.clear();
massLandDenialCombos.clear();
extraTurnCombos.clear();
lockCombos.clear();
skipTurnsCombos.clear();
definitelyTwoCardCombos.clear();
arguablyTwoCardCombos.clear();
// //
// Cards // Cards
@ -29,19 +16,18 @@ void EstimateBracketResult::fromJson(const QJsonObject &json)
const QJsonObject obj = value.toObject(); const QJsonObject obj = value.toObject();
CommanderSpellbookCardResult card; CommanderSpellbookCardResult card = CommanderSpellbookCardResult::fromJson(obj.value("card").toObject());
card.fromJson(obj.value("card").toObject());
if (obj.value("gameChanger").toBool()) { if (obj.value("gameChanger").toBool()) {
gameChangerCards.append(card); result.gameChangerCards.append(card);
} }
if (obj.value("massLandDenial").toBool()) { if (obj.value("massLandDenial").toBool()) {
massLandDenialCards.append(card); result.massLandDenialCards.append(card);
} }
if (obj.value("extraTurn").toBool()) { if (obj.value("extraTurn").toBool()) {
extraTurnCards.append(card); result.extraTurnCards.append(card);
} }
} }
@ -55,15 +41,14 @@ void EstimateBracketResult::fromJson(const QJsonObject &json)
const QJsonObject obj = value.toObject(); const QJsonObject obj = value.toObject();
CommanderSpellbookVariantResult variant; CommanderSpellbookVariantResult variant = CommanderSpellbookVariantResult::fromJson(obj);
variant.fromJson(obj);
if (obj.value("massLandDenial").toBool()) { if (obj.value("massLandDenial").toBool()) {
massLandDenialTemplates.append(variant); result.massLandDenialTemplates.append(variant);
} }
if (obj.value("extraTurn").toBool()) { if (obj.value("extraTurn").toBool()) {
extraTurnTemplates.append(variant); result.extraTurnTemplates.append(variant);
} }
} }
@ -77,31 +62,32 @@ void EstimateBracketResult::fromJson(const QJsonObject &json)
const QJsonObject obj = value.toObject(); const QJsonObject obj = value.toObject();
CommanderSpellbookVariantResult combo; CommanderSpellbookVariantResult combo = CommanderSpellbookVariantResult::fromJson(obj);
combo.fromJson(obj);
if (obj.value("massLandDenial").toBool()) { if (obj.value("massLandDenial").toBool()) {
massLandDenialCombos.append(combo); result.massLandDenialCombos.append(combo);
} }
if (obj.value("extraTurn").toBool()) { if (obj.value("extraTurn").toBool()) {
extraTurnCombos.append(combo); result.extraTurnCombos.append(combo);
} }
if (obj.value("lock").toBool()) { if (obj.value("lock").toBool()) {
lockCombos.append(combo); result.lockCombos.append(combo);
} }
if (obj.value("skipTurns").toBool()) { if (obj.value("skipTurns").toBool()) {
skipTurnsCombos.append(combo); result.skipTurnsCombos.append(combo);
} }
if (obj.value("definitelyTwoCard").toBool()) { if (obj.value("definitelyTwoCard").toBool()) {
definitelyTwoCardCombos.append(combo); result.definitelyTwoCardCombos.append(combo);
} }
if (obj.value("arguablyTwoCard").toBool()) { if (obj.value("arguablyTwoCard").toBool()) {
arguablyTwoCardCombos.append(combo); result.arguablyTwoCardCombos.append(combo);
} }
} }
return result;
} }

View file

@ -4,29 +4,29 @@
#include "commander_spellbook_card_result.h" #include "commander_spellbook_card_result.h"
#include "commander_spellbook_variant_result.h" #include "commander_spellbook_variant_result.h"
#include <QVector> #include <QJsonObject>
#include <QList>
class EstimateBracketResult struct EstimateBracketResult
{ {
public: static EstimateBracketResult fromJson(const QJsonObject &json);
void fromJson(const QJsonObject &json);
QString bracketTag; QString bracketTag;
QVector<CommanderSpellbookCardResult> gameChangerCards; QList<CommanderSpellbookCardResult> gameChangerCards;
QVector<CommanderSpellbookCardResult> massLandDenialCards; QList<CommanderSpellbookCardResult> massLandDenialCards;
QVector<CommanderSpellbookCardResult> extraTurnCards; QList<CommanderSpellbookCardResult> extraTurnCards;
QVector<CommanderSpellbookVariantResult> massLandDenialTemplates; QList<CommanderSpellbookVariantResult> massLandDenialTemplates;
QVector<CommanderSpellbookVariantResult> extraTurnTemplates; QList<CommanderSpellbookVariantResult> extraTurnTemplates;
QVector<CommanderSpellbookVariantResult> massLandDenialCombos; QList<CommanderSpellbookVariantResult> massLandDenialCombos;
QVector<CommanderSpellbookVariantResult> extraTurnCombos; QList<CommanderSpellbookVariantResult> extraTurnCombos;
QVector<CommanderSpellbookVariantResult> lockCombos; QList<CommanderSpellbookVariantResult> lockCombos;
QVector<CommanderSpellbookVariantResult> skipTurnsCombos; QList<CommanderSpellbookVariantResult> skipTurnsCombos;
QVector<CommanderSpellbookVariantResult> definitelyTwoCardCombos; QList<CommanderSpellbookVariantResult> definitelyTwoCardCombos;
QVector<CommanderSpellbookVariantResult> arguablyTwoCardCombos; QList<CommanderSpellbookVariantResult> arguablyTwoCardCombos;
}; };
#endif #endif // COCKATRICE_COMMANDER_SPELLBOOK_ESTIMATE_BRACKET_RESULT_H

View file

@ -1,31 +1,35 @@
#include "commander_spellbook_variant_result.h" #include "commander_spellbook_variant_result.h"
void CommanderSpellbookVariantResult::fromJson(const QJsonObject &json) CommanderSpellbookVariantResult CommanderSpellbookVariantResult::fromJson(const QJsonObject &json)
{ {
id = json.value("id").toString(); CommanderSpellbookVariantResult result;
status = json.value("status").toString();
uses = json.value("uses").toArray(); result.id = json.value("id").toString();
cardRequires = json.value("requires").toArray(); result.status = json.value("status").toString();
produces = json.value("produces").toArray();
of = json.value("of").toArray();
includes = json.value("includes").toArray();
manaNeeded = json.value("manaNeeded").toArray(); result.uses = json.value("uses").toArray();
manaValueNeeded = json.value("manaValueNeeded").toArray(); result.cardRequires = json.value("requires").toArray();
result.produces = json.value("produces").toArray();
result.of = json.value("of").toArray();
result.includes = json.value("includes").toArray();
easyPrerequisites = json.value("easyPrerequisites").toArray(); result.manaNeeded = json.value("manaNeeded").toArray();
notablePrerequisites = json.value("notablePrerequisites").toArray(); result.manaValueNeeded = json.value("manaValueNeeded").toArray();
description = json.value("description").toString(); result.easyPrerequisites = json.value("easyPrerequisites").toArray();
notes = json.value("notes").toString(); result.notablePrerequisites = json.value("notablePrerequisites").toArray();
popularity = json.value("popularity").toDouble();
spoiler = json.value("spoiler").toBool(); result.description = json.value("description").toString();
bracketTag = json.value("bracketTag").toString(); result.notes = json.value("notes").toString();
result.popularity = json.value("popularity").toDouble();
legalities = json.value("legalities").toObject(); result.spoiler = json.value("spoiler").toBool();
prices = json.value("prices").toObject(); result.bracketTag = json.value("bracketTag").toString();
variantCount = json.value("variantCount").toInt(); result.legalities = json.value("legalities").toObject();
result.prices = json.value("prices").toObject();
result.variantCount = json.value("variantCount").toInt();
return result;
} }

View file

@ -4,10 +4,9 @@
#include <QJsonArray> #include <QJsonArray>
#include <QJsonObject> #include <QJsonObject>
class CommanderSpellbookVariantResult struct CommanderSpellbookVariantResult
{ {
public: static CommanderSpellbookVariantResult fromJson(const QJsonObject &json);
void fromJson(const QJsonObject &json);
QString id; QString id;
QString status; QString status;

View file

@ -0,0 +1,269 @@
#include "commander_bracket_widget.h"
#include "../../../../../client/settings/cache_settings.h"
#include "commander_bracket_service.h"
#include <QComboBox>
#include <QDialog>
#include <QDialogButtonBox>
#include <QFormLayout>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QTimer>
#include <QToolButton>
#include <QVBoxLayout>
#include <libcockatrice/settings/deck_editor_settings.h>
CommanderBracketWidget::CommanderBracketWidget(QWidget *parent) : QWidget(parent)
{
bracketLabel = new QLabel(tr("Bracket:"), this);
bracketValueLabel = new QLabel(this);
bracketValueLabel->setText("-");
bracketValueLabel->setObjectName("bracketValueLabel");
bracketInfoButton = new QToolButton(this);
bracketInfoButton->setText("?");
bracketInfoButton->setAutoRaise(true);
bracketInfoButton->setEnabled(false);
bracketRefreshButton = new QToolButton(this);
bracketRefreshButton->setIcon(QPixmap("theme:icons/reload"));
bracketRefreshButton->setAutoRaise(true);
connect(bracketRefreshButton, &QToolButton::clicked, this, &CommanderBracketWidget::requestBracketEstimate);
auto *layout = new QGridLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(bracketLabel, 0, 0);
auto *bracketRow = new QHBoxLayout;
bracketRow->addWidget(bracketValueLabel);
bracketRow->addWidget(bracketInfoButton);
bracketRow->addWidget(bracketRefreshButton);
bracketRow->addStretch();
layout->addLayout(bracketRow, 0, 1);
connect(&CommanderBracketService::instance(), &CommanderBracketService::estimateFinished, this,
&CommanderBracketWidget::onEstimateBracketFinished);
connect(&CommanderBracketService::instance(), &CommanderBracketService::estimateError, this,
&CommanderBracketWidget::onEstimateBracketError);
connect(&SettingsCache::instance().deckEditor(), &DeckEditorSettings::commanderSpellbookIntegrationEnabledChanged,
this, &CommanderBracketWidget::maybeAutoEstimateBracket);
connect(&SettingsCache::instance().deckEditor(),
&DeckEditorSettings::commanderSpellbookIntegrationUseOfficialBracketNamesChanged, this,
&CommanderBracketWidget::maybeAutoEstimateBracket);
setVisible(false);
}
void CommanderBracketWidget::setDeck(const QSharedPointer<DeckList> &_deck)
{
deck = _deck;
requestId = 0; // invalidate any in-flight estimate for the previous deck
// Reset the displayed bracket
bracketValueLabel->setText("-");
bracketInfoButton->setToolTip({});
bracketInfoButton->setEnabled(false);
bracketRefreshButton->setEnabled(true);
maybeAutoEstimateBracket();
}
bool CommanderBracketWidget::promptCommanderSpellbookIntegration()
{
QDialog dialog(this);
dialog.setWindowTitle(tr("CommanderSpellbook integration"));
auto *mainLayout = new QVBoxLayout(&dialog);
// Main text
auto *label = new QLabel(tr("CommanderSpellbook can analyze your deck and estimate its Commander bracket.\n\n"
"This sends your deck list to an external service.\n\n"
"CommanderSpellbook uses its own bracket naming system based on their own algorithm. "
"These names can be mapped to the official Commander brackets, but the mapping "
"is only an approximation."));
label->setWordWrap(true);
mainLayout->addWidget(label);
// Naming selector
auto *formLayout = new QFormLayout;
auto *namingCombo = new QComboBox(&dialog);
namingCombo->addItem(tr("CommanderSpellbook bracket names"));
namingCombo->addItem(tr("Official Commander bracket names (approximate)"));
namingCombo->setCurrentIndex(
SettingsCache::instance().deckEditor().getCommanderSpellbookIntegrationUseOfficialBracketNames() ? 1 : 0);
// Create label + explainer button
auto *labelWidget = new QWidget(&dialog);
auto *labelLayout = new QHBoxLayout(labelWidget);
labelLayout->setContentsMargins(0, 0, 0, 0);
auto *namingLabel = new QLabel(tr("Bracket naming:"), labelWidget);
auto *explainerButton = new QToolButton(labelWidget);
explainerButton->setText("?");
explainerButton->setAutoRaise(true);
explainerButton->setEnabled(false);
explainerButton->setToolTip(CommanderBracketNames::Explainer);
labelLayout->addWidget(namingLabel);
labelLayout->addWidget(explainerButton);
labelLayout->addStretch(); // push the button next to label, combo stays aligned
// Add row with the custom label widget
formLayout->addRow(labelWidget, namingCombo);
mainLayout->addLayout(formLayout);
// Buttons
auto *buttonBox = new QDialogButtonBox(&dialog);
auto *enableBtn = buttonBox->addButton(tr("Enable"), QDialogButtonBox::AcceptRole);
auto *automaticBtn = buttonBox->addButton(tr("Automatic"), QDialogButtonBox::ApplyRole);
auto *disableBtn = buttonBox->addButton(tr("Disable"), QDialogButtonBox::RejectRole);
mainLayout->addWidget(buttonBox);
// Track which button was clicked
QAbstractButton *clickedButton = nullptr;
QObject::connect(buttonBox, &QDialogButtonBox::clicked, &dialog, [&](QAbstractButton *btn) {
clickedButton = btn;
dialog.accept();
});
dialog.exec();
// Persist naming choice (if not disabled)
if (clickedButton != disableBtn) {
bool useOfficial = namingCombo->currentIndex() == 1;
SettingsCache::instance().deckEditor().setCommanderSpellbookIntegrationUseOfficialBracketNames(useOfficial);
}
// Persist integration mode
if (clickedButton == disableBtn) {
SettingsCache::instance().deckEditor().setCommanderSpellbookIntegrationEnabled(
commanderSpellbookIntegrationEnabledIndexDisabled);
return false;
}
if (clickedButton == enableBtn) {
SettingsCache::instance().deckEditor().setCommanderSpellbookIntegrationEnabled(
commanderSpellbookIntegrationEnabledIndexEnabled);
return true;
}
if (clickedButton == automaticBtn) {
SettingsCache::instance().deckEditor().setCommanderSpellbookIntegrationEnabled(
commanderSpellbookIntegrationEnabledIndexAutomatic);
return true;
}
return false;
}
void CommanderBracketWidget::updateBracketVisibility(bool visible)
{
setVisible(visible);
}
void CommanderBracketWidget::requestBracketEstimate()
{
bracketRefreshButton->setEnabled(false);
bracketInfoButton->setEnabled(false);
bracketValueLabel->setText(tr("Calculating…"));
requestId = CommanderBracketService::instance().estimateBracket(*deck, this);
}
void CommanderBracketWidget::onEstimateBracketFinished(quint64 id,
QObject *requester,
const CommanderBracketEstimate &result)
{
if (requester != this || id != requestId) {
return;
}
BracketExplainer explainer;
lastBracketExplanation = explainer.explain(result.rawResult);
// Display bracket
bracketValueLabel->setText(
SettingsCache::instance().deckEditor().getCommanderSpellbookIntegrationUseOfficialBracketNames()
? result.officialName
: result.displayName);
bracketRefreshButton->setEnabled(true);
// Build tooltip
QString tooltip;
for (const auto &section : lastBracketExplanation.sections) {
tooltip += "<b>" + section.title + "</b><br>";
for (const auto &line : section.bulletPoints) {
tooltip += "• " + line + "<br>";
}
tooltip += "<br>";
}
bracketInfoButton->setToolTip(tooltip);
bracketInfoButton->setEnabled(!tooltip.isEmpty());
}
void CommanderBracketWidget::onEstimateBracketError(quint64 id, QObject *requester, const QString & /*error*/)
{
if (requester != this || id != requestId) {
return;
}
bracketValueLabel->setText("-");
bracketRefreshButton->setEnabled(true);
bracketInfoButton->setToolTip({});
bracketInfoButton->setEnabled(false);
}
void CommanderBracketWidget::maybeAutoEstimateBracket()
{
const QString formatKey = deck->getGameFormat();
const bool isCommander = (formatKey.compare("commander", Qt::CaseInsensitive) == 0);
int mode = SettingsCache::instance().deckEditor().getCommanderSpellbookIntegrationEnabled();
if (!isCommander || mode == commanderSpellbookIntegrationEnabledIndexDisabled) {
updateBracketVisibility(false);
return;
}
if (mode == commanderSpellbookIntegrationEnabledIndexUnprompted) {
if (prompting) {
return;
}
prompting = true;
const bool accepted = promptCommanderSpellbookIntegration();
prompting = false;
if (!accepted) {
updateBracketVisibility(false);
return;
}
}
updateBracketVisibility(true);
mode = SettingsCache::instance().deckEditor().getCommanderSpellbookIntegrationEnabled();
if (mode != commanderSpellbookIntegrationEnabledIndexAutomatic) {
return;
}
// Avoid firing if we already have a result or a request in flight
if (!bracketRefreshButton->isEnabled()) {
return;
}
// Defer to avoid races during init / model rebuild
QTimer::singleShot(0, this, &CommanderBracketWidget::requestBracketEstimate);
}
void CommanderBracketWidget::retranslateUi()
{
bracketLabel->setText(tr("Bracket:"));
bracketInfoButton->setToolTip(tr("Why this bracket?"));
bracketRefreshButton->setToolTip(tr("Recalculate bracket"));
}

View file

@ -0,0 +1,46 @@
#ifndef COCKATRICE_COMMANDER_BRACKET_WIDGET_H
#define COCKATRICE_COMMANDER_BRACKET_WIDGET_H
#include "commander_spellbook_bracket_explainer.h"
#include <QSharedPointer>
#include <QWidget>
#include <libcockatrice/deck_list/deck_list.h>
class QLabel;
class QToolButton;
struct CommanderBracketEstimate;
class CommanderBracketWidget : public QWidget
{
Q_OBJECT
public:
explicit CommanderBracketWidget(QWidget *parent = nullptr);
void setDeck(const QSharedPointer<DeckList> &_deck);
void retranslateUi();
private slots:
void requestBracketEstimate();
void onEstimateBracketFinished(quint64 id, QObject *requester, const CommanderBracketEstimate &result);
void onEstimateBracketError(quint64 id, QObject *requester, const QString &error);
void maybeAutoEstimateBracket();
private:
bool promptCommanderSpellbookIntegration();
void updateBracketVisibility(bool visible);
QSharedPointer<DeckList> deck;
bool prompting = false;
quint64 requestId = 0;
QLabel *bracketLabel;
QLabel *bracketValueLabel;
QToolButton *bracketInfoButton;
QToolButton *bracketRefreshButton;
BracketExplanation lastBracketExplanation;
};
#endif // COCKATRICE_COMMANDER_BRACKET_WIDGET_H

View file

@ -23,8 +23,7 @@ CommanderSpellbookApiAccessor::CommanderSpellbookApiAccessor(QObject *parent) :
CommanderSpellbookApiAccessor::RequestId CommanderSpellbookApiAccessor::estimateBracket(const DeckList &deck, CommanderSpellbookApiAccessor::RequestId CommanderSpellbookApiAccessor::estimateBracket(const DeckList &deck,
QObject *requester) QObject *requester)
{ {
CommanderSpellbookDeckRequest deckRequest; CommanderSpellbookDeckRequest deckRequest = CommanderSpellbookDeckRequest::fromDeckList(deck);
deckRequest.fromDeckList(deck);
QJsonDocument doc(deckRequest.toJson()); QJsonDocument doc(deckRequest.toJson());
QByteArray body = doc.toJson(QJsonDocument::Compact); QByteArray body = doc.toJson(QJsonDocument::Compact);
@ -70,8 +69,7 @@ void CommanderSpellbookApiAccessor::onEstimateReplyFinished(QNetworkReply *reply
return; return;
} }
EstimateBracketResult result; EstimateBracketResult result = EstimateBracketResult::fromJson(doc.object());
result.fromJson(doc.object());
emit estimateBracketFinished(id, requester, result); emit estimateBracketFinished(id, requester, result);
} }

View file

@ -1,6 +1,6 @@
#include "commander_spellbook_bracket_explainer.h" #include "commander_spellbook_bracket_explainer.h"
static QString cardList(const QVector<CommanderSpellbookCardResult> &cards, int max = 5) static QString cardList(const QList<CommanderSpellbookCardResult> &cards, int max = 5)
{ {
QStringList names; QStringList names;
for (int i = 0; i < cards.size() && i < max; ++i) { for (int i = 0; i < cards.size() && i < max; ++i) {
@ -14,7 +14,7 @@ static QString cardList(const QVector<CommanderSpellbookCardResult> &cards, int
return names.join(", "); return names.join(", ");
} }
static QString comboCount(const QVector<CommanderSpellbookVariantResult> &variants) static QString comboCount(const QList<CommanderSpellbookVariantResult> &variants)
{ {
return QString::number(variants.size()); return QString::number(variants.size());
} }

View file

@ -2,6 +2,21 @@
#define COCKATRICE_COMMANDER_SPELLBOOK_BRACKET_EXPLAINER_H #define COCKATRICE_COMMANDER_SPELLBOOK_BRACKET_EXPLAINER_H
#include "api_response/commander_spellbook_estimate_bracket_result.h" #include "api_response/commander_spellbook_estimate_bracket_result.h"
namespace CommanderBracketNames
{
inline const char *CommanderSpellbookBracketNames = QT_TR_NOOP("CommanderSpellbook");
inline const char *OfficialCommanderBracketNames = QT_TR_NOOP("Official (approximate)");
inline const char *Explainer = QT_TR_NOOP(
"The bracket system combines both objective data, as well as subjective play experience to estimate a "
"bracket for a deck.\nCommanderSpellbook's estimation is algorithmical, which means that it can only operate "
"on the objective data, not the subjective intent. \nThey have chosen to represent this by defining their "
"own bracket system which matches their algorithm.\n"
"This custom bracket system maps loosely to the standard system. \nYou may choose to use these mapped "
"standardized names if these are more familiar to you, however, you should keep in mind that these are just "
"rough estimations.\n\nAlways consider the subjective factors of the bracket system when determing a deck's "
"final bracket!");
} // namespace CommanderBracketNames
struct BracketExplanationSection struct BracketExplanationSection
{ {
QString title; QString title;

View file

@ -7,7 +7,7 @@
#include <QUrl> #include <QUrl>
#include <libcockatrice/settings/commander_bracket_settings.h> #include <libcockatrice/settings/commander_bracket_settings.h>
#define COMMANDER_BRACKET_JSON "https://cockatrice.github.io/commander-brackets.json" static const QUrl COMMANDER_BRACKET_JSON_URL(QStringLiteral("https://cockatrice.github.io/commander-brackets.json"));
HandleCommanderBrackets::HandleCommanderBrackets(QObject *parent) HandleCommanderBrackets::HandleCommanderBrackets(QObject *parent)
: QObject(parent), nam(new QNetworkAccessManager(this)), reply(nullptr) : QObject(parent), nam(new QNetworkAccessManager(this)), reply(nullptr)
@ -16,7 +16,11 @@ HandleCommanderBrackets::HandleCommanderBrackets(QObject *parent)
void HandleCommanderBrackets::downloadBracketDefinitions() void HandleCommanderBrackets::downloadBracketDefinitions()
{ {
reply = nam->get(QNetworkRequest(QUrl(COMMANDER_BRACKET_JSON))); if (reply) {
return;
}
reply = nam->get(QNetworkRequest(COMMANDER_BRACKET_JSON_URL));
connect(reply, &QNetworkReply::finished, this, &HandleCommanderBrackets::actFinishParsingDownloadedData); connect(reply, &QNetworkReply::finished, this, &HandleCommanderBrackets::actFinishParsingDownloadedData);
} }

View file

@ -560,6 +560,8 @@ void MainWindow::startupConfigCheck()
actCheckClientUpdates(); actCheckClientUpdates();
} }
actCheckCommanderBracketDefinitionUpdates();
if (SettingsCache::instance().network().getClientVersion() == CLIENT_INFO_NOT_SET) { if (SettingsCache::instance().network().getClientVersion() == CLIENT_INFO_NOT_SET) {
// no config found, 99% new clean install // no config found, 99% new clean install
qCInfo(WindowMainStartupVersionLog) qCInfo(WindowMainStartupVersionLog)

View file

@ -214,29 +214,3 @@ void CardsDisplaySettings::setSampleHandSize(int _sampleHandSize)
setValue(_sampleHandSize, "sampleHandSize", "cards", "cardSize"); setValue(_sampleHandSize, "sampleHandSize", "cards", "cardSize");
emit sampleHandSizeChanged(_sampleHandSize); emit sampleHandSizeChanged(_sampleHandSize);
} }
int CardsDisplaySettings::getDeckEditorCommanderSpellbookIntegrationEnabled() const
{
return getValue("deckeditorcommanderspellbookintegrationenabled", "interface", QString(),
deckEditorCommanderSpellbookIntegrationEnabledIndexUnprompted)
.toInt();
}
bool CardsDisplaySettings::getDeckEditorCommanderSpellbookIntegrationUseOfficialBracketNames() const
{
return getValue("deckeditorcommanderspellbookintegrationuseofficialbracketnames", "interface", QString(), false)
.toBool();
}
void CardsDisplaySettings::setDeckEditorCommanderSpellbookIntegrationEnabled(int _enabled)
{
setValue(_enabled, "deckeditorcommanderspellbookintegrationenabled", "interface");
emit deckEditorCommanderSpellbookIntegrationEnabledChanged(_enabled);
}
void CardsDisplaySettings::setDeckEditorCommanderSpellbookIntegrationUseOfficialBracketNames(
bool _useOfficialBracketNames)
{
setValue(_useOfficialBracketNames, "deckeditorcommanderspellbookintegrationuseofficialbracketnames", "interface");
emit deckEditorCommanderSpellbookIntegrationUseOfficialBracketNamesChanged(_useOfficialBracketNames);
}

View file

@ -5,14 +5,6 @@
#include <libcockatrice/interfaces/interface_cards_display_settings_provider.h> #include <libcockatrice/interfaces/interface_cards_display_settings_provider.h>
enum deckEditorCommanderSpellbookIntegrationEnabledIndex
{
deckEditorCommanderSpellbookIntegrationEnabledIndexDisabled,
deckEditorCommanderSpellbookIntegrationEnabledIndexEnabled,
deckEditorCommanderSpellbookIntegrationEnabledIndexAutomatic,
deckEditorCommanderSpellbookIntegrationEnabledIndexUnprompted,
};
class CardsDisplaySettings : public SettingsManager, public ICardsDisplaySettingsProvider class CardsDisplaySettings : public SettingsManager, public ICardsDisplaySettingsProvider
{ {
Q_OBJECT Q_OBJECT
@ -39,12 +31,6 @@ public:
[[nodiscard]] int getArchidektPreviewSize() const override; [[nodiscard]] int getArchidektPreviewSize() const override;
[[nodiscard]] int getSampleHandSize() const override; [[nodiscard]] int getSampleHandSize() const override;
[[nodiscard]] int getDeckEditorCommanderSpellbookIntegrationEnabled() const;
[[nodiscard]] bool getDeckEditorCommanderSpellbookIntegrationUseOfficialBracketNames() const;
void setDeckEditorCommanderSpellbookIntegrationEnabled(int _deckEditorCommanderSpellbookIntegrationEnabled);
void setDeckEditorCommanderSpellbookIntegrationUseOfficialBracketNames(
bool _deckEditorCommanderSpellbookIntegrationUseOfficialBracketNames);
void setDisplayCardNames(bool _displayCardNames); void setDisplayCardNames(bool _displayCardNames);
void setRoundCardCorners(bool _roundCardCorners); void setRoundCardCorners(bool _roundCardCorners);
void setOverrideAllCardArtWithPersonalPreference(bool _overrideAllCardArt); void setOverrideAllCardArtWithPersonalPreference(bool _overrideAllCardArt);
@ -80,8 +66,6 @@ signals:
void edhRecCardSizeChanged(); void edhRecCardSizeChanged();
void archidektPreviewSizeChanged(); void archidektPreviewSizeChanged();
void sampleHandSizeChanged(int amount); void sampleHandSizeChanged(int amount);
void deckEditorCommanderSpellbookIntegrationEnabledChanged(int _enabled);
void deckEditorCommanderSpellbookIntegrationUseOfficialBracketNamesChanged(bool _useOfficialBracketNames);
public: public:
explicit CardsDisplaySettings(const QString &settingPath, QObject *parent = nullptr); explicit CardsDisplaySettings(const QString &settingPath, QObject *parent = nullptr);

View file

@ -46,3 +46,27 @@ void DeckEditorSettings::setDefaultDeckEditorType(int _defaultDeckEditorType)
{ {
setValue(_defaultDeckEditorType, "defaultDeckEditorType"); setValue(_defaultDeckEditorType, "defaultDeckEditorType");
} }
int DeckEditorSettings::getCommanderSpellbookIntegrationEnabled() const
{
return getValue("commanderspellbookintegrationenabled", QString(), QString(),
commanderSpellbookIntegrationEnabledIndexUnprompted)
.toInt();
}
bool DeckEditorSettings::getCommanderSpellbookIntegrationUseOfficialBracketNames() const
{
return getValue("commanderspellbookintegrationuseofficialbracketnames", QString(), QString(), false).toBool();
}
void DeckEditorSettings::setCommanderSpellbookIntegrationEnabled(int _commanderSpellbookIntegrationEnabled)
{
setValue(_commanderSpellbookIntegrationEnabled, "commanderspellbookintegrationenabled");
emit commanderSpellbookIntegrationEnabledChanged(_commanderSpellbookIntegrationEnabled);
}
void DeckEditorSettings::setCommanderSpellbookIntegrationUseOfficialBracketNames(bool _useOfficialBracketNames)
{
setValue(_useOfficialBracketNames, "commanderspellbookintegrationuseofficialbracketnames");
emit commanderSpellbookIntegrationUseOfficialBracketNamesChanged(_useOfficialBracketNames);
}

View file

@ -5,6 +5,14 @@
#include <libcockatrice/interfaces/interface_deck_editor_settings_provider.h> #include <libcockatrice/interfaces/interface_deck_editor_settings_provider.h>
enum commanderSpellbookIntegrationEnabledIndex
{
commanderSpellbookIntegrationEnabledIndexDisabled,
commanderSpellbookIntegrationEnabledIndexEnabled,
commanderSpellbookIntegrationEnabledIndexAutomatic,
commanderSpellbookIntegrationEnabledIndexUnprompted,
};
class DeckEditorSettings : public SettingsManager, public IDeckEditorSettingsProvider class DeckEditorSettings : public SettingsManager, public IDeckEditorSettingsProvider
{ {
Q_OBJECT Q_OBJECT
@ -15,15 +23,21 @@ public:
[[nodiscard]] bool getBannerCardComboBoxVisible() const override; [[nodiscard]] bool getBannerCardComboBoxVisible() const override;
[[nodiscard]] bool getTagsWidgetVisible() const override; [[nodiscard]] bool getTagsWidgetVisible() const override;
[[nodiscard]] int getDefaultDeckEditorType() const override; [[nodiscard]] int getDefaultDeckEditorType() const override;
[[nodiscard]] int getCommanderSpellbookIntegrationEnabled() const;
[[nodiscard]] bool getCommanderSpellbookIntegrationUseOfficialBracketNames() const;
void setOpenDeckInNewTab(bool _openDeckInNewTab); void setOpenDeckInNewTab(bool _openDeckInNewTab);
void setBannerCardComboBoxVisible(bool _bannerCardComboBoxVisible); void setBannerCardComboBoxVisible(bool _bannerCardComboBoxVisible);
void setTagsWidgetVisible(bool _tagsWidgetVisible); void setTagsWidgetVisible(bool _tagsWidgetVisible);
void setDefaultDeckEditorType(int _defaultDeckEditorType); void setDefaultDeckEditorType(int _defaultDeckEditorType);
void setCommanderSpellbookIntegrationEnabled(int _commanderSpellbookIntegrationEnabled);
void setCommanderSpellbookIntegrationUseOfficialBracketNames(bool _useOfficialBracketNames);
signals: signals:
void bannerCardComboBoxVisibleChanged(bool visible); void bannerCardComboBoxVisibleChanged(bool visible);
void tagsWidgetVisibleChanged(bool visible); void tagsWidgetVisibleChanged(bool visible);
void commanderSpellbookIntegrationEnabledChanged(int enabled);
void commanderSpellbookIntegrationUseOfficialBracketNamesChanged(bool useOfficialBracketNames);
public: public:
explicit DeckEditorSettings(const QString &settingPath, QObject *parent = nullptr); explicit DeckEditorSettings(const QString &settingPath, QObject *parent = nullptr);