[EDHRec] New layout for commander details (#6405)

* Stuff

Took 22 minutes

* New layout for commander details.

Took 1 hour 18 minutes

* Update plate to encompass everything, update font sizes.

Took 10 minutes

* Include map.

Took 2 minutes

* Include QSet

Took 5 minutes

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
BruebachL 2025-12-23 16:00:07 +01:00 committed by GitHub
parent 01e8e4d589
commit e7af1bbec9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 336 additions and 127 deletions

View file

@ -287,6 +287,10 @@ set(cockatrice_SOURCES
src/interface/widgets/tabs/visual_deck_storage/tab_deck_storage_visual.cpp
src/interface/key_signals.cpp
src/interface/logger.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_budget_navigation_widget.cpp
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.h
)
add_subdirectory(sounds)

View file

@ -19,17 +19,17 @@ EdhrecApiResponseCardDetailsDisplayWidget::EdhrecApiResponseCardDetailsDisplayWi
nameLabel = new QLabel(this);
nameLabel->setText(toDisplay.name);
nameLabel->setAlignment(Qt::AlignHCenter);
nameLabel->setStyleSheet("font-size: 20px; font-weight: bold");
inclusionDisplayWidget = new EdhrecApiResponseCardInclusionDisplayWidget(this, toDisplay);
synergyDisplayWidget = new EdhrecApiResponseCardSynergyDisplayWidget(this, toDisplay);
layout->addWidget(nameLabel);
layout->addWidget(cardPictureWidget);
backgroundPlateWidget = new BackgroundPlateWidget(this);
auto plateLayout = new QVBoxLayout(backgroundPlateWidget);
plateLayout->addWidget(nameLabel);
plateLayout->addWidget(cardPictureWidget);
plateLayout->addWidget(inclusionDisplayWidget);
plateLayout->addWidget(synergyDisplayWidget);

View file

@ -3,6 +3,7 @@
#include "../../../../../cards/card_info_picture_widget.h"
#include "../../tab_edhrec_main.h"
#include "../card_prices/edhrec_api_response_card_prices_display_widget.h"
#include "edhrec_commander_api_response_bracket_navigation_widget.h"
#include <libcockatrice/card/database/card_database_manager.h>
@ -12,9 +13,14 @@ EdhrecCommanderResponseCommanderDetailsDisplayWidget::EdhrecCommanderResponseCom
QString baseUrl)
: QWidget(parent), commanderDetails(_commanderDetails)
{
layout = new QVBoxLayout(this);
layout = new QHBoxLayout(this);
setLayout(layout);
commanderLayout = new QHBoxLayout();
commanderDetailsLayout = new QVBoxLayout();
commanderDetailsLayout->setAlignment(Qt::AlignCenter);
navigationAndPricesLayout = new QVBoxLayout();
commanderPicture = new CardInfoPictureWidget(this);
commanderPicture->setCard(CardDatabaseManager::query()->getCard({commanderDetails.getName()}));
@ -36,20 +42,35 @@ EdhrecCommanderResponseCommanderDetailsDisplayWidget::EdhrecCommanderResponseCom
commanderDetails.debugPrint();
commanderName = new QLabel(this);
commanderName->setText(commanderDetails.getName());
commanderName->setAlignment(Qt::AlignCenter);
commanderName->setStyleSheet("font-size: 28px; font-weight: bold");
label = new QLabel(this);
label->setAlignment(Qt::AlignCenter);
label->setStyleSheet("font-size: 16px");
salt = new QLabel(this);
salt->setAlignment(Qt::AlignCenter);
salt->setStyleSheet("font-size: 16px");
cardPricesDisplayWidget = new EdhrecApiResponseCardPricesDisplayWidget(this, commanderDetails.getPrices());
navigationWidget = new EdhrecCommanderApiResponseNavigationWidget(this, commanderDetails, baseUrl);
layout->addWidget(commanderPicture);
layout->addWidget(label);
layout->addWidget(salt);
layout->addWidget(cardPricesDisplayWidget);
layout->addWidget(navigationWidget);
commanderLayout->addWidget(commanderPicture);
commanderDetailsLayout->addWidget(commanderName);
commanderDetailsLayout->addSpacing(1);
commanderDetailsLayout->addWidget(label);
commanderDetailsLayout->addWidget(salt);
commanderDetailsLayout->addWidget(cardPricesDisplayWidget);
commanderLayout->addLayout(commanderDetailsLayout);
navigationAndPricesLayout->addWidget(navigationWidget);
// navigationAndPricesLayout->addWidget(cardPricesDisplayWidget);
layout->addLayout(commanderLayout);
layout->addLayout(navigationAndPricesLayout);
retranslateUi();
}

View file

@ -29,8 +29,12 @@ public:
private:
EdhrecCommanderApiResponseCommanderDetails commanderDetails;
QVBoxLayout *layout;
QHBoxLayout *layout;
QHBoxLayout *commanderLayout;
QVBoxLayout *commanderDetailsLayout;
QVBoxLayout *navigationAndPricesLayout;
CardInfoPictureWidget *commanderPicture;
QLabel *commanderName;
QLabel *label;
QLabel *salt;
EdhrecApiResponseCardPricesDisplayWidget *cardPricesDisplayWidget;

View file

@ -0,0 +1,99 @@
#include "edhrec_commander_api_response_bracket_navigation_widget.h"
#include <QSet>
EdhrecCommanderApiResponseBracketNavigationWidget::EdhrecCommanderApiResponseBracketNavigationWidget(
QWidget *parent,
const QString &baseUrl)
: QWidget(parent)
{
layout = new QGridLayout(this);
setLayout(layout);
gameChangerLabel = new QLabel(this);
layout->addWidget(gameChangerLabel, 1, 0, 1, 2);
for (int i = 0; i < gameChangerOptions.length(); i++) {
QString option = gameChangerOptions.at(i);
QString label = option.isEmpty() ? "All" : option.at(0).toUpper() + option.mid(1);
QPushButton *optionButton = new QPushButton(label, this);
optionButton->setMinimumHeight(84);
optionButton->setStyleSheet("font-size: 24px");
gameChangerButtons[option] = optionButton;
layout->addWidget(optionButton, 2, i);
connect(optionButton, &QPushButton::clicked, this, [=, this]() {
selectedGameChanger = option;
updateOptionButtonSelection(gameChangerButtons, option);
emit requestNavigation();
});
}
updateOptionButtonSelection(gameChangerButtons, "");
retranslateUi();
applyOptionsFromUrl(baseUrl);
}
void EdhrecCommanderApiResponseBracketNavigationWidget::retranslateUi()
{
gameChangerLabel->setText(tr("Game Changers"));
}
void EdhrecCommanderApiResponseBracketNavigationWidget::applyOptionsFromUrl(const QString &url)
{
QString cleanedUrl = url;
// Remove base and file extension
if (cleanedUrl.startsWith("https://json.edhrec.com/pages/")) {
cleanedUrl = cleanedUrl.mid(QString("https://json.edhrec.com/pages/").length());
}
if (cleanedUrl.endsWith(".json")) {
cleanedUrl.chop(5);
}
// Expecting something like: "commanders/the-ur-dragon/core/expensive"
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
QStringList parts = cleanedUrl.split('/', Qt::SkipEmptyParts);
#else
QStringList parts = cleanedUrl.split('/', QString::SkipEmptyParts);
#endif
if (parts.size() < 2) {
return;
}
QString commanderName = parts[1];
QString gameChangerOpt;
// Define valid sets
QSet<QString> validGameChangers = {"exhibition", "core", "upgraded", "optimized", "cedh"};
// Check remaining parts after commander
for (int i = 2; i < parts.size(); ++i) {
QString part = parts[i].toLower();
if (validGameChangers.contains(part)) {
gameChangerOpt = part;
}
}
// Validate and apply
if (!gameChangerButtons.contains(gameChangerOpt)) {
gameChangerOpt.clear();
}
selectedGameChanger = gameChangerOpt;
updateOptionButtonSelection(gameChangerButtons, selectedGameChanger);
}
void EdhrecCommanderApiResponseBracketNavigationWidget::updateOptionButtonSelection(
QMap<QString, QPushButton *> &buttons,
const QString &selectedKey)
{
for (auto it = buttons.begin(); it != buttons.end(); ++it) {
it.value()->setStyleSheet(it.key() == selectedKey
? "background-color: lightblue; font-weight: bold; font-size: 24px;"
: "font-size: 24px");
}
}

View file

@ -0,0 +1,37 @@
#ifndef COCKATRICE_EDHREC_COMMANDER_API_RESPONSE_BRACKET_NAVIGATION_WIDGET_H
#define COCKATRICE_EDHREC_COMMANDER_API_RESPONSE_BRACKET_NAVIGATION_WIDGET_H
#include <QGridLayout>
#include <QLabel>
#include <QMap>
#include <QPushButton>
#include <QWidget>
class EdhrecCommanderApiResponseBracketNavigationWidget : public QWidget
{
Q_OBJECT
public:
explicit EdhrecCommanderApiResponseBracketNavigationWidget(QWidget *parent, const QString &baseUrl);
void retranslateUi();
void applyOptionsFromUrl(const QString &url);
QString getSelectedGameChanger() const
{
return selectedGameChanger;
}
signals:
void requestNavigation();
private:
QGridLayout *layout;
QLabel *gameChangerLabel;
QStringList gameChangerOptions = {"", "exhibition", "core", "upgraded", "optimized", "cedh"};
QString selectedGameChanger;
QMap<QString, QPushButton *> gameChangerButtons;
void updateOptionButtonSelection(QMap<QString, QPushButton *> &buttons, const QString &selectedKey);
};
#endif // COCKATRICE_EDHREC_COMMANDER_API_RESPONSE_BRACKET_NAVIGATION_WIDGET_H

View file

@ -0,0 +1,101 @@
#include "edhrec_commander_api_response_budget_navigation_widget.h"
#include <QSet>
EdhrecCommanderApiResponseBudgetNavigationWidget::EdhrecCommanderApiResponseBudgetNavigationWidget(
QWidget *parent,
const QString &baseUrl)
: QWidget(parent)
{
layout = new QGridLayout(this);
setLayout(layout);
budgetLabel = new QLabel(this);
layout->addWidget(budgetLabel, 3, 0, 1, 2);
for (int i = 0; i < budgetOptions.length(); i++) {
QString option = budgetOptions.at(i);
QString label = option.isEmpty() ? "Any" : option.at(0).toUpper() + option.mid(1);
QPushButton *btn = new QPushButton(label, this);
btn->setMinimumHeight(84);
btn->setStyleSheet("font-size: 24px");
budgetButtons[option] = btn;
layout->addWidget(btn, 4, i);
connect(btn, &QPushButton::clicked, this, [=, this]() {
selectedBudget = option;
updateOptionButtonSelection(budgetButtons, option);
emit requestNavigation();
});
}
updateOptionButtonSelection(budgetButtons, "");
retranslateUi();
applyOptionsFromUrl(baseUrl);
}
void EdhrecCommanderApiResponseBudgetNavigationWidget::retranslateUi()
{
budgetLabel->setText(tr("Budget"));
}
void EdhrecCommanderApiResponseBudgetNavigationWidget::applyOptionsFromUrl(const QString &url)
{
QString cleanedUrl = url;
// Remove base and file extension
if (cleanedUrl.startsWith("https://json.edhrec.com/pages/")) {
cleanedUrl = cleanedUrl.mid(QString("https://json.edhrec.com/pages/").length());
}
if (cleanedUrl.endsWith(".json")) {
cleanedUrl.chop(5);
}
// Expecting something like: "commanders/the-ur-dragon/core/expensive"
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
QStringList parts = cleanedUrl.split('/', Qt::SkipEmptyParts);
#else
QStringList parts = cleanedUrl.split('/', QString::SkipEmptyParts);
#endif
if (parts.size() < 2) {
return;
}
QString commanderName = parts[1];
QString gameChangerOpt, budgetOpt;
// Define valid sets
QSet<QString> validGameChangers = {"exhibition", "core", "upgraded", "optimized", "cedh"};
QSet<QString> validBudgets = {"budget", "expensive"};
// Check remaining parts after commander
for (int i = 2; i < parts.size(); ++i) {
QString part = parts[i].toLower();
if (validGameChangers.contains(part)) {
gameChangerOpt = part;
} else if (validBudgets.contains(part)) {
budgetOpt = part;
}
}
if (!budgetButtons.contains(budgetOpt)) {
budgetOpt.clear();
}
selectedBudget = budgetOpt;
updateOptionButtonSelection(budgetButtons, selectedBudget);
}
void EdhrecCommanderApiResponseBudgetNavigationWidget::updateOptionButtonSelection(
QMap<QString, QPushButton *> &buttons,
const QString &selectedKey)
{
for (auto it = buttons.begin(); it != buttons.end(); ++it) {
it.value()->setStyleSheet(it.key() == selectedKey
? "background-color: lightblue; font-weight: bold; font-size: 24px;"
: "font-size: 24px");
}
}

View file

@ -0,0 +1,37 @@
#ifndef COCKATRICE_EDHREC_COMMANDER_API_RESPONSE_BUDGET_NAVIGATION_WIDGET_H
#define COCKATRICE_EDHREC_COMMANDER_API_RESPONSE_BUDGET_NAVIGATION_WIDGET_H
#include <QGridLayout>
#include <QLabel>
#include <QMap>
#include <QPushButton>
#include <QWidget>
class EdhrecCommanderApiResponseBudgetNavigationWidget : public QWidget
{
Q_OBJECT
public:
explicit EdhrecCommanderApiResponseBudgetNavigationWidget(QWidget *parent, const QString &baseUrl);
void retranslateUi();
void applyOptionsFromUrl(const QString &url);
QString getSelectedBudget() const
{
return selectedBudget;
}
signals:
void requestNavigation();
private:
QGridLayout *layout;
QLabel *budgetLabel;
QStringList budgetOptions = {"", "budget", "expensive"};
QString selectedBudget;
QMap<QString, QPushButton *> budgetButtons;
void updateOptionButtonSelection(QMap<QString, QPushButton *> &buttons, const QString &selectedKey);
};
#endif // COCKATRICE_EDHREC_COMMANDER_API_RESPONSE_BUDGET_NAVIGATION_WIDGET_H

View file

@ -11,47 +11,28 @@ EdhrecCommanderApiResponseNavigationWidget::EdhrecCommanderApiResponseNavigation
layout = new QGridLayout(this);
setLayout(layout);
gameChangerLabel = new QLabel(this);
budgetLabel = new QLabel(this);
bracketNavigationWidget = new EdhrecCommanderApiResponseBracketNavigationWidget(this, baseUrl);
connect(bracketNavigationWidget, &EdhrecCommanderApiResponseBracketNavigationWidget::requestNavigation, this,
&EdhrecCommanderApiResponseNavigationWidget::actRequestCommanderNavigation);
budgetNavigationWidget = new EdhrecCommanderApiResponseBudgetNavigationWidget(this, baseUrl);
connect(budgetNavigationWidget, &EdhrecCommanderApiResponseBudgetNavigationWidget::requestNavigation, this,
&EdhrecCommanderApiResponseNavigationWidget::actRequestCommanderNavigation);
comboPushButton = new QPushButton(this);
comboPushButton->setMinimumHeight(84);
comboPushButton->setStyleSheet("font-size: 24px");
averageDeckPushButton = new QPushButton(this);
averageDeckPushButton->setMinimumHeight(84);
averageDeckPushButton->setStyleSheet("font-size: 24px");
layout->addWidget(comboPushButton, 0, 0, 1, 1);
layout->addWidget(averageDeckPushButton, 0, 1, 1, 1);
layout->addWidget(gameChangerLabel, 1, 0, 1, 2);
for (int i = 0; i < gameChangerOptions.length(); i++) {
QString option = gameChangerOptions.at(i);
QString label = option.isEmpty() ? "All" : option.at(0).toUpper() + option.mid(1);
QPushButton *optionButton = new QPushButton(label, this);
gameChangerButtons[option] = optionButton;
layout->addWidget(optionButton, 2, i);
connect(optionButton, &QPushButton::clicked, this, [=, this]() {
selectedGameChanger = option;
updateOptionButtonSelection(gameChangerButtons, option);
actRequestCommanderNavigation();
});
}
layout->addWidget(budgetLabel, 3, 0, 1, 2);
for (int i = 0; i < budgetOptions.length(); i++) {
QString option = budgetOptions.at(i);
QString label = option.isEmpty() ? "Any" : option.at(0).toUpper() + option.mid(1);
QPushButton *btn = new QPushButton(label, this);
budgetButtons[option] = btn;
layout->addWidget(btn, 4, i);
connect(btn, &QPushButton::clicked, this, [=, this]() {
selectedBudget = option;
updateOptionButtonSelection(budgetButtons, option);
actRequestCommanderNavigation();
});
}
updateOptionButtonSelection(gameChangerButtons, "");
updateOptionButtonSelection(budgetButtons, "");
layout->addWidget(bracketNavigationWidget, 1, 0, 1, 2);
layout->addWidget(budgetNavigationWidget, 2, 0, 1, 2);
QWidget *currentParent = parentWidget();
TabEdhRecMain *parentTab = nullptr;
@ -73,87 +54,21 @@ EdhrecCommanderApiResponseNavigationWidget::EdhrecCommanderApiResponseNavigation
}
retranslateUi();
applyOptionsFromUrl(baseUrl);
}
void EdhrecCommanderApiResponseNavigationWidget::retranslateUi()
{
comboPushButton->setText(tr("Combos"));
averageDeckPushButton->setText(tr("Average Deck"));
gameChangerLabel->setText(tr("Game Changers"));
budgetLabel->setText(tr("Budget"));
}
void EdhrecCommanderApiResponseNavigationWidget::applyOptionsFromUrl(const QString &url)
{
QString cleanedUrl = url;
// Remove base and file extension
if (cleanedUrl.startsWith("https://json.edhrec.com/pages/")) {
cleanedUrl = cleanedUrl.mid(QString("https://json.edhrec.com/pages/").length());
}
if (cleanedUrl.endsWith(".json")) {
cleanedUrl.chop(5);
}
// Expecting something like: "commanders/the-ur-dragon/core/expensive"
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
QStringList parts = cleanedUrl.split('/', Qt::SkipEmptyParts);
#else
QStringList parts = cleanedUrl.split('/', QString::SkipEmptyParts);
#endif
if (parts.size() < 2) {
return;
}
QString commanderName = parts[1];
QString gameChangerOpt, budgetOpt;
// Define valid sets
QSet<QString> validGameChangers = {"core", "upgraded", "optimized"};
QSet<QString> validBudgets = {"budget", "expensive"};
// Check remaining parts after commander
for (int i = 2; i < parts.size(); ++i) {
QString part = parts[i].toLower();
if (validGameChangers.contains(part)) {
gameChangerOpt = part;
} else if (validBudgets.contains(part)) {
budgetOpt = part;
}
}
// Validate and apply
if (!gameChangerButtons.contains(gameChangerOpt)) {
gameChangerOpt.clear();
}
if (!budgetButtons.contains(budgetOpt)) {
budgetOpt.clear();
}
selectedGameChanger = gameChangerOpt;
selectedBudget = budgetOpt;
updateOptionButtonSelection(gameChangerButtons, selectedGameChanger);
updateOptionButtonSelection(budgetButtons, selectedBudget);
}
void EdhrecCommanderApiResponseNavigationWidget::updateOptionButtonSelection(QMap<QString, QPushButton *> &buttons,
const QString &selectedKey)
{
for (auto it = buttons.begin(); it != buttons.end(); ++it) {
it.value()->setStyleSheet(it.key() == selectedKey ? "background-color: lightblue; font-weight: bold;" : "");
}
}
QString EdhrecCommanderApiResponseNavigationWidget::addNavigationOptionsToUrl(QString baseUrl)
{
if (!selectedGameChanger.isEmpty()) {
baseUrl += "/" + selectedGameChanger;
if (!bracketNavigationWidget->getSelectedGameChanger().isEmpty()) {
baseUrl += "/" + bracketNavigationWidget->getSelectedGameChanger();
}
if (!selectedBudget.isEmpty()) {
baseUrl += "/" + selectedBudget;
if (!budgetNavigationWidget->getSelectedBudget().isEmpty()) {
baseUrl += "/" + budgetNavigationWidget->getSelectedBudget();
}
return baseUrl;
}

View file

@ -8,6 +8,8 @@
#define EDHREC_COMMANDER_API_RESPONSE_NAVIGATION_WIDGET_H
#include "edhrec_api_response_commander_details_display_widget.h"
#include "edhrec_commander_api_response_bracket_navigation_widget.h"
#include "edhrec_commander_api_response_budget_navigation_widget.h"
#include <QGridLayout>
#include <QLabel>
@ -23,7 +25,6 @@ public:
const EdhrecCommanderApiResponseCommanderDetails &_commanderDetails,
QString baseUrl);
void retranslateUi();
void applyOptionsFromUrl(const QString &url);
public slots:
void actRequestCommanderNavigation();
@ -35,24 +36,14 @@ signals:
private:
QGridLayout *layout;
QLabel *gameChangerLabel;
QLabel *budgetLabel;
QStringList gameChangerOptions = {"", "core", "upgraded", "optimized"};
QStringList budgetOptions = {"", "budget", "expensive"};
QString selectedGameChanger;
QString selectedBudget;
QMap<QString, QPushButton *> gameChangerButtons;
QMap<QString, QPushButton *> budgetButtons;
EdhrecCommanderApiResponseBracketNavigationWidget *bracketNavigationWidget;
EdhrecCommanderApiResponseBudgetNavigationWidget *budgetNavigationWidget;
QPushButton *comboPushButton;
QPushButton *averageDeckPushButton;
EdhrecCommanderApiResponseCommanderDetails commanderDetails;
void updateOptionButtonSelection(QMap<QString, QPushButton *> &buttons, const QString &selectedKey);
QString addNavigationOptionsToUrl(QString baseUrl);
QString buildComboUrl() const;
};