mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-06-11 00:24:47 -07:00
Implement deck analytics widgets. (#5837)
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
parent
67db245aea
commit
854208ea0a
16 changed files with 782 additions and 1 deletions
|
|
@ -74,13 +74,17 @@ set(cockatrice_SOURCES
|
|||
src/client/ui/widgets/cards/card_size_widget.cpp
|
||||
src/client/ui/widgets/cards/deck_card_zone_display_widget.cpp
|
||||
src/client/ui/widgets/cards/deck_preview_card_picture_widget.cpp
|
||||
src/client/ui/widgets/deck_analytics/deck_analytics_widget.cpp
|
||||
src/client/ui/widgets/deck_analytics/mana_base_widget.cpp
|
||||
src/client/ui/widgets/deck_analytics/mana_curve_widget.cpp
|
||||
src/client/ui/widgets/deck_analytics/mana_devotion_widget.cpp
|
||||
src/client/ui/widgets/deck_editor/deck_editor_card_info_dock_widget.cpp
|
||||
src/client/ui/widgets/deck_editor/deck_editor_database_display_widget.cpp
|
||||
src/client/ui/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
|
||||
src/client/ui/widgets/deck_editor/deck_editor_filter_dock_widget.cpp
|
||||
src/client/ui/widgets/deck_editor/deck_editor_printing_selector_dock_widget.cpp
|
||||
src/client/ui/widgets/general/display/banner_widget.cpp
|
||||
src/client/ui/widgets/general/display/banner_widget.cpp
|
||||
src/client/ui/widgets/general/display/bar_widget.cpp
|
||||
src/client/ui/widgets/general/display/dynamic_font_size_label.cpp
|
||||
src/client/ui/widgets/general/display/dynamic_font_size_push_button.cpp
|
||||
src/client/ui/widgets/general/display/labeled_input.cpp
|
||||
|
|
@ -108,6 +112,7 @@ set(cockatrice_SOURCES
|
|||
src/client/ui/widgets/visual_database_display/visual_database_display_filter_save_load_widget.cpp
|
||||
src/client/ui/widgets/visual_database_display/visual_database_filter_display_widget.cpp
|
||||
src/client/ui/widgets/visual_deck_editor/visual_deck_editor_widget.cpp
|
||||
src/client/ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.cpp
|
||||
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.cpp
|
||||
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.cpp
|
||||
src/client/ui/widgets/visual_deck_storage/deck_preview/deck_preview_tag_addition_widget.cpp
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include "../../../settings/cache_settings.h"
|
||||
#include "../../ui/pixel_map_generator.h"
|
||||
#include "../../ui/widgets/cards/card_info_frame_widget.h"
|
||||
#include "../../ui/widgets/deck_analytics/deck_analytics_widget.h"
|
||||
#include "../../ui/widgets/visual_deck_editor/visual_deck_editor_widget.h"
|
||||
#include "../tab_deck_editor.h"
|
||||
#include "../tab_supervisor.h"
|
||||
|
|
@ -81,6 +82,8 @@ void TabDeckEditorVisual::onDeckChanged()
|
|||
{
|
||||
AbstractTabDeckEditor::onDeckChanged();
|
||||
tabContainer->visualDeckView->decklistDataChanged(QModelIndex(), QModelIndex());
|
||||
tabContainer->deckAnalytics->refreshDisplays(deckDockWidget->deckModel);
|
||||
tabContainer->sampleHandWidget->setDeckModel(deckDockWidget->deckModel);
|
||||
}
|
||||
|
||||
void TabDeckEditorVisual::createMenus()
|
||||
|
|
|
|||
|
|
@ -35,8 +35,15 @@ TabDeckEditorVisualTabWidget::TabDeckEditorVisualTabWidget(QWidget *parent,
|
|||
connect(visualDatabaseDisplay, &VisualDatabaseDisplayWidget::cardClickedDatabaseDisplay, this,
|
||||
&TabDeckEditorVisualTabWidget::onCardClickedDatabaseDisplay);
|
||||
|
||||
deckAnalytics = new DeckAnalyticsWidget(this, deckModel);
|
||||
deckAnalytics->setObjectName("deckAnalytics");
|
||||
|
||||
sampleHandWidget = new VisualDeckEditorSampleHandWidget(this, deckModel);
|
||||
|
||||
this->addNewTab(visualDeckView, tr("Visual Deck View"));
|
||||
this->addNewTab(visualDatabaseDisplay, tr("Visual Database Display"));
|
||||
this->addNewTab(deckAnalytics, tr("Deck Analytics"));
|
||||
this->addNewTab(sampleHandWidget, tr("Sample Hand"));
|
||||
}
|
||||
|
||||
void TabDeckEditorVisualTabWidget::onCardChanged(CardInfoPtr activeCard)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
#ifndef TAB_DECK_EDITOR_VISUAL_TAB_WIDGET_H
|
||||
#define TAB_DECK_EDITOR_VISUAL_TAB_WIDGET_H
|
||||
|
||||
#include "../../ui/widgets/deck_analytics/deck_analytics_widget.h"
|
||||
#include "../../ui/widgets/printing_selector/printing_selector.h"
|
||||
#include "../../ui/widgets/visual_database_display/visual_database_display_widget.h"
|
||||
#include "../../ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.h"
|
||||
#include "../../ui/widgets/visual_deck_editor/visual_deck_editor_widget.h"
|
||||
#include "../abstract_tab_deck_editor.h"
|
||||
|
||||
|
|
@ -29,8 +31,10 @@ public:
|
|||
int getTabCount() const;
|
||||
|
||||
VisualDeckEditorWidget *visualDeckView;
|
||||
DeckAnalyticsWidget *deckAnalytics;
|
||||
VisualDatabaseDisplayWidget *visualDatabaseDisplay;
|
||||
PrintingSelector *printingSelector;
|
||||
VisualDeckEditorSampleHandWidget *sampleHandWidget;
|
||||
|
||||
public slots:
|
||||
void onCardChanged(CardInfoPtr activeCard);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
#include "deck_analytics_widget.h"
|
||||
|
||||
DeckAnalyticsWidget::DeckAnalyticsWidget(QWidget *parent, DeckListModel *_deckListModel)
|
||||
: QWidget(parent), deckListModel(_deckListModel)
|
||||
{
|
||||
mainLayout = new QVBoxLayout();
|
||||
setLayout(mainLayout);
|
||||
|
||||
manaCurveWidget = new ManaCurveWidget(this, deckListModel);
|
||||
mainLayout->addWidget(manaCurveWidget);
|
||||
|
||||
manaDevotionWidget = new ManaDevotionWidget(this, deckListModel);
|
||||
mainLayout->addWidget(manaDevotionWidget);
|
||||
|
||||
manaBaseWidget = new ManaBaseWidget(this, deckListModel);
|
||||
mainLayout->addWidget(manaBaseWidget);
|
||||
}
|
||||
|
||||
void DeckAnalyticsWidget::refreshDisplays(DeckListModel *_deckModel)
|
||||
{
|
||||
deckListModel = _deckModel;
|
||||
manaCurveWidget->setDeckModel(_deckModel);
|
||||
manaDevotionWidget->setDeckModel(_deckModel);
|
||||
manaBaseWidget->setDeckModel(_deckModel);
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef DECK_ANALYTICS_WIDGET_H
|
||||
#define DECK_ANALYTICS_WIDGET_H
|
||||
|
||||
#include "../../../../deck/deck_list_model.h"
|
||||
#include "../../../ui/widgets/general/layout_containers/flow_widget.h"
|
||||
#include "mana_base_widget.h"
|
||||
#include "mana_curve_widget.h"
|
||||
#include "mana_devotion_widget.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QWidget>
|
||||
#include <decklist.h>
|
||||
#include <qscrollarea.h>
|
||||
|
||||
class DeckAnalyticsWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DeckAnalyticsWidget(QWidget *parent, DeckListModel *deckListModel);
|
||||
void setDeckList(const DeckList &_deckListModel);
|
||||
std::map<int, int> analyzeManaCurve();
|
||||
void refreshDisplays(DeckListModel *_deckListModel);
|
||||
|
||||
private:
|
||||
DeckListModel *deckListModel;
|
||||
QVBoxLayout *mainLayout;
|
||||
|
||||
ManaCurveWidget *manaCurveWidget;
|
||||
ManaDevotionWidget *manaDevotionWidget;
|
||||
ManaBaseWidget *manaBaseWidget;
|
||||
};
|
||||
|
||||
#endif // DECK_ANALYTICS_WIDGET_H
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
#include "mana_base_widget.h"
|
||||
|
||||
#include "../../../../deck/deck_loader.h"
|
||||
#include "../../../../game/cards/card_database.h"
|
||||
#include "../../../../game/cards/card_database_manager.h"
|
||||
#include "../general/display/banner_widget.h"
|
||||
#include "../general/display/bar_widget.h"
|
||||
|
||||
#include <QHash>
|
||||
#include <QRegularExpression>
|
||||
#include <decklist.h>
|
||||
|
||||
ManaBaseWidget::ManaBaseWidget(QWidget *parent, DeckListModel *_deckListModel)
|
||||
: QWidget(parent), deckListModel(_deckListModel)
|
||||
{
|
||||
layout = new QVBoxLayout(this);
|
||||
setLayout(layout);
|
||||
|
||||
bannerWidget = new BannerWidget(this, tr("Mana Base"), Qt::Vertical, 100);
|
||||
bannerWidget->setMaximumHeight(100);
|
||||
layout->addWidget(bannerWidget);
|
||||
|
||||
barContainer = new QWidget(this);
|
||||
barLayout = new QHBoxLayout(barContainer);
|
||||
layout->addWidget(barContainer);
|
||||
|
||||
connect(deckListModel, &DeckListModel::dataChanged, this, &ManaBaseWidget::analyzeManaBase);
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void ManaBaseWidget::retranslateUi()
|
||||
{
|
||||
bannerWidget->setText(tr("Mana Base"));
|
||||
}
|
||||
|
||||
void ManaBaseWidget::setDeckModel(DeckListModel *deckModel)
|
||||
{
|
||||
deckListModel = deckModel;
|
||||
connect(deckListModel, &DeckListModel::dataChanged, this, &ManaBaseWidget::analyzeManaBase);
|
||||
analyzeManaBase();
|
||||
}
|
||||
|
||||
void ManaBaseWidget::updateDisplay()
|
||||
{
|
||||
// Clear the layout first
|
||||
QLayoutItem *item;
|
||||
while ((item = barLayout->takeAt(0)) != nullptr) {
|
||||
item->widget()->deleteLater();
|
||||
delete item;
|
||||
}
|
||||
|
||||
int highestEntry = 0;
|
||||
for (auto entry : manaBaseMap) {
|
||||
if (entry > highestEntry) {
|
||||
highestEntry = entry;
|
||||
}
|
||||
}
|
||||
|
||||
// Define color mapping for mana types
|
||||
QHash<QString, QColor> manaColors;
|
||||
manaColors.insert("W", QColor(248, 231, 185));
|
||||
manaColors.insert("U", QColor(14, 104, 171));
|
||||
manaColors.insert("B", QColor(21, 11, 0));
|
||||
manaColors.insert("R", QColor(211, 32, 42));
|
||||
manaColors.insert("G", QColor(0, 115, 62));
|
||||
manaColors.insert("C", QColor(150, 150, 150));
|
||||
|
||||
for (auto manaColor : manaBaseMap.keys()) {
|
||||
QColor barColor = manaColors.value(manaColor, Qt::gray);
|
||||
BarWidget *barWidget = new BarWidget(QString(manaColor), manaBaseMap[manaColor], highestEntry, barColor, this);
|
||||
barLayout->addWidget(barWidget);
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
QHash<QString, int> ManaBaseWidget::analyzeManaBase()
|
||||
{
|
||||
manaBaseMap.clear();
|
||||
InnerDecklistNode *listRoot = deckListModel->getDeckList()->getRoot();
|
||||
for (int i = 0; i < listRoot->size(); i++) {
|
||||
InnerDecklistNode *currentZone = dynamic_cast<InnerDecklistNode *>(listRoot->at(i));
|
||||
for (int j = 0; j < currentZone->size(); j++) {
|
||||
DecklistCardNode *currentCard = dynamic_cast<DecklistCardNode *>(currentZone->at(j));
|
||||
if (!currentCard)
|
||||
continue;
|
||||
|
||||
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
||||
CardInfoPtr info = CardDatabaseManager::getInstance()->getCard(currentCard->getName());
|
||||
if (info) {
|
||||
auto devotion = determineManaProduction(info->getText());
|
||||
mergeManaCounts(manaBaseMap, devotion);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateDisplay();
|
||||
return manaBaseMap;
|
||||
}
|
||||
|
||||
QHash<QString, int> ManaBaseWidget::determineManaProduction(const QString &rulesText)
|
||||
{
|
||||
QHash<QString, int> manaCounts = {{"W", 0}, {"U", 0}, {"B", 0}, {"R", 0}, {"G", 0}, {"C", 0}};
|
||||
|
||||
QString text = rulesText.toLower(); // Normalize case for matching
|
||||
|
||||
// Quick keyword-based checks for any color and colorless mana
|
||||
if (text.contains("{t}: add one mana of any color") || text.contains("add one mana of any color")) {
|
||||
for (const auto &color : {QStringLiteral("W"), QStringLiteral("U"), QStringLiteral("B"), QStringLiteral("R"),
|
||||
QStringLiteral("G")}) {
|
||||
manaCounts[color]++;
|
||||
}
|
||||
}
|
||||
if (text.contains("{t}: add {c}") || text.contains("add one colorless mana")) {
|
||||
manaCounts["C"]++;
|
||||
}
|
||||
|
||||
// Optimized regex for specific mana symbols
|
||||
static const QRegularExpression specificColorRegex(R"(\{T\}:\s*Add\s*\{([WUBRG])\})");
|
||||
QRegularExpressionMatch match = specificColorRegex.match(rulesText);
|
||||
if (match.hasMatch()) {
|
||||
manaCounts[match.captured(1)]++;
|
||||
}
|
||||
|
||||
return manaCounts;
|
||||
}
|
||||
|
||||
void ManaBaseWidget::mergeManaCounts(QHash<QString, int> &manaCounts1, const QHash<QString, int> &manaCounts2)
|
||||
{
|
||||
for (auto it = manaCounts2.constBegin(); it != manaCounts2.constEnd(); ++it) {
|
||||
manaCounts1[it.key()] += it.value();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef MANA_BASE_WIDGET_H
|
||||
#define MANA_BASE_WIDGET_H
|
||||
|
||||
#include "../../../../deck/deck_list_model.h"
|
||||
#include "../general/display/banner_widget.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QWidget>
|
||||
#include <decklist.h>
|
||||
#include <utility>
|
||||
|
||||
class ManaBaseWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ManaBaseWidget(QWidget *parent, DeckListModel *deckListModel);
|
||||
QHash<QString, int> analyzeManaBase();
|
||||
void updateDisplay();
|
||||
|
||||
QHash<QString, int> determineManaProduction(const QString &manaString);
|
||||
void mergeManaCounts(QHash<QString, int> &manaCounts1, const QHash<QString, int> &manaCounts2);
|
||||
|
||||
public slots:
|
||||
void setDeckModel(DeckListModel *deckModel);
|
||||
void retranslateUi();
|
||||
|
||||
private:
|
||||
DeckListModel *deckListModel;
|
||||
BannerWidget *bannerWidget;
|
||||
QHash<QString, int> manaBaseMap;
|
||||
QVBoxLayout *layout;
|
||||
QWidget *barContainer;
|
||||
QHBoxLayout *barLayout;
|
||||
};
|
||||
|
||||
#endif // MANA_BASE_WIDGET_H
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
#include "mana_curve_widget.h"
|
||||
|
||||
#include "../../../../deck/deck_loader.h"
|
||||
#include "../../../../game/cards/card_database.h"
|
||||
#include "../../../../game/cards/card_database_manager.h"
|
||||
#include "../../../../main.h"
|
||||
#include "../general/display/banner_widget.h"
|
||||
#include "../general/display/bar_widget.h"
|
||||
|
||||
#include <decklist.h>
|
||||
#include <unordered_map>
|
||||
|
||||
ManaCurveWidget::ManaCurveWidget(QWidget *parent, DeckListModel *_deckListModel)
|
||||
: QWidget(parent), deckListModel(_deckListModel)
|
||||
{
|
||||
layout = new QVBoxLayout(this);
|
||||
setLayout(layout);
|
||||
|
||||
bannerWidget = new BannerWidget(this, tr("Mana Curve"), Qt::Vertical, 100);
|
||||
bannerWidget->setMaximumHeight(100);
|
||||
layout->addWidget(bannerWidget);
|
||||
|
||||
barContainer = new QWidget(this);
|
||||
barLayout = new QHBoxLayout(barContainer);
|
||||
layout->addWidget(barContainer);
|
||||
|
||||
connect(deckListModel, &DeckListModel::dataChanged, this, &ManaCurveWidget::analyzeManaCurve);
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void ManaCurveWidget::retranslateUi()
|
||||
{
|
||||
bannerWidget->setText(tr("Mana Curve"));
|
||||
}
|
||||
|
||||
void ManaCurveWidget::setDeckModel(DeckListModel *deckModel)
|
||||
{
|
||||
deckListModel = deckModel;
|
||||
connect(deckListModel, &DeckListModel::dataChanged, this, &ManaCurveWidget::analyzeManaCurve);
|
||||
analyzeManaCurve();
|
||||
}
|
||||
|
||||
std::unordered_map<int, int> ManaCurveWidget::analyzeManaCurve()
|
||||
{
|
||||
manaCurveMap.clear();
|
||||
InnerDecklistNode *listRoot = deckListModel->getDeckList()->getRoot();
|
||||
for (int i = 0; i < listRoot->size(); i++) {
|
||||
InnerDecklistNode *currentZone = dynamic_cast<InnerDecklistNode *>(listRoot->at(i));
|
||||
for (int j = 0; j < currentZone->size(); j++) {
|
||||
DecklistCardNode *currentCard = dynamic_cast<DecklistCardNode *>(currentZone->at(j));
|
||||
if (!currentCard)
|
||||
continue;
|
||||
|
||||
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
||||
CardInfoPtr info = CardDatabaseManager::getInstance()->getCard(currentCard->getName());
|
||||
if (info) {
|
||||
int cmc = info->getCmc().toInt();
|
||||
manaCurveMap[cmc]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateDisplay();
|
||||
|
||||
return manaCurveMap;
|
||||
}
|
||||
|
||||
void ManaCurveWidget::updateDisplay()
|
||||
{
|
||||
// Clear the layout first
|
||||
if (barLayout != nullptr) {
|
||||
QLayoutItem *item;
|
||||
while ((item = barLayout->takeAt(0)) != nullptr) {
|
||||
item->widget()->deleteLater();
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
|
||||
int highestEntry = 0;
|
||||
for (const auto &entry : manaCurveMap) {
|
||||
if (entry.second > highestEntry) {
|
||||
highestEntry = entry.second;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert unordered_map to ordered map to ensure sorting by CMC
|
||||
std::map<int, int> sortedManaCurve(manaCurveMap.begin(), manaCurveMap.end());
|
||||
|
||||
// Add new widgets to the layout in sorted order
|
||||
for (const auto &entry : sortedManaCurve) {
|
||||
BarWidget *barWidget =
|
||||
new BarWidget(QString::number(entry.first), entry.second, highestEntry, QColor(11, 11, 11), this);
|
||||
barLayout->addWidget(barWidget);
|
||||
}
|
||||
|
||||
update(); // Update the widget display
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef MANA_CURVE_WIDGET_H
|
||||
#define MANA_CURVE_WIDGET_H
|
||||
|
||||
#include "../../../../deck/deck_list_model.h"
|
||||
#include "../general/display/banner_widget.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QWidget>
|
||||
#include <unordered_map>
|
||||
|
||||
class ManaCurveWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ManaCurveWidget(QWidget *parent, DeckListModel *deckListModel);
|
||||
void updateDisplay();
|
||||
|
||||
public slots:
|
||||
void setDeckModel(DeckListModel *deckModel);
|
||||
std::unordered_map<int, int> analyzeManaCurve();
|
||||
void retranslateUi();
|
||||
|
||||
private:
|
||||
DeckListModel *deckListModel;
|
||||
std::unordered_map<int, int> manaCurveMap;
|
||||
QVBoxLayout *layout;
|
||||
BannerWidget *bannerWidget;
|
||||
QWidget *barContainer;
|
||||
QHBoxLayout *barLayout;
|
||||
};
|
||||
|
||||
#endif // MANA_CURVE_WIDGET_H
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
#include "mana_devotion_widget.h"
|
||||
|
||||
#include "../../../../deck/deck_loader.h"
|
||||
#include "../../../../game/cards/card_database.h"
|
||||
#include "../../../../game/cards/card_database_manager.h"
|
||||
#include "../../../../main.h"
|
||||
#include "../general/display/banner_widget.h"
|
||||
#include "../general/display/bar_widget.h"
|
||||
|
||||
#include <decklist.h>
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
ManaDevotionWidget::ManaDevotionWidget(QWidget *parent, DeckListModel *_deckListModel)
|
||||
: QWidget(parent), deckListModel(_deckListModel)
|
||||
{
|
||||
layout = new QVBoxLayout(this);
|
||||
setLayout(layout);
|
||||
|
||||
bannerWidget = new BannerWidget(this, tr("Mana Devotion"), Qt::Vertical, 100);
|
||||
bannerWidget->setMaximumHeight(100);
|
||||
layout->addWidget(bannerWidget);
|
||||
|
||||
barLayout = new QHBoxLayout();
|
||||
layout->addLayout(barLayout);
|
||||
|
||||
connect(deckListModel, &DeckListModel::dataChanged, this, &ManaDevotionWidget::analyzeManaDevotion);
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void ManaDevotionWidget::retranslateUi()
|
||||
{
|
||||
bannerWidget->setText(tr("Mana Devotion"));
|
||||
}
|
||||
|
||||
void ManaDevotionWidget::setDeckModel(DeckListModel *deckModel)
|
||||
{
|
||||
deckListModel = deckModel;
|
||||
connect(deckListModel, &DeckListModel::dataChanged, this, &ManaDevotionWidget::analyzeManaDevotion);
|
||||
analyzeManaDevotion();
|
||||
}
|
||||
|
||||
std::unordered_map<char, int> ManaDevotionWidget::analyzeManaDevotion()
|
||||
{
|
||||
manaDevotionMap.clear();
|
||||
InnerDecklistNode *listRoot = deckListModel->getDeckList()->getRoot();
|
||||
for (int i = 0; i < listRoot->size(); i++) {
|
||||
InnerDecklistNode *currentZone = dynamic_cast<InnerDecklistNode *>(listRoot->at(i));
|
||||
for (int j = 0; j < currentZone->size(); j++) {
|
||||
DecklistCardNode *currentCard = dynamic_cast<DecklistCardNode *>(currentZone->at(j));
|
||||
if (!currentCard)
|
||||
continue;
|
||||
|
||||
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
||||
CardInfoPtr info = CardDatabaseManager::getInstance()->getCard(currentCard->getName());
|
||||
if (info) {
|
||||
auto devotion = countManaSymbols(info->getManaCost());
|
||||
mergeManaCounts(manaDevotionMap, devotion);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateDisplay();
|
||||
return manaDevotionMap;
|
||||
}
|
||||
|
||||
void ManaDevotionWidget::updateDisplay()
|
||||
{
|
||||
// Clear the layout first
|
||||
QLayoutItem *item;
|
||||
while ((item = barLayout->takeAt(0)) != nullptr) {
|
||||
item->widget()->deleteLater();
|
||||
delete item;
|
||||
}
|
||||
|
||||
int highestEntry = 0;
|
||||
for (auto entry : manaDevotionMap) {
|
||||
if (highestEntry < entry.second) {
|
||||
highestEntry = entry.second;
|
||||
}
|
||||
}
|
||||
|
||||
// Define color mapping for devotion bars
|
||||
std::unordered_map<char, QColor> manaColors = {{'W', QColor(248, 231, 185)}, {'U', QColor(14, 104, 171)},
|
||||
{'B', QColor(21, 11, 0)}, {'R', QColor(211, 32, 42)},
|
||||
{'G', QColor(0, 115, 62)}, {'C', QColor(150, 150, 150)}};
|
||||
|
||||
for (auto entry : manaDevotionMap) {
|
||||
QColor barColor = manaColors.count(entry.first) ? manaColors[entry.first] : Qt::gray;
|
||||
BarWidget *barWidget = new BarWidget(QString(entry.first), entry.second, highestEntry, barColor, this);
|
||||
barLayout->addWidget(barWidget);
|
||||
}
|
||||
|
||||
update(); // Update the widget display
|
||||
}
|
||||
|
||||
std::unordered_map<char, int> ManaDevotionWidget::countManaSymbols(const QString &manaString)
|
||||
{
|
||||
std::unordered_map<char, int> manaCounts = {{'W', 0}, {'U', 0}, {'B', 0}, {'R', 0}, {'G', 0}};
|
||||
|
||||
int len = manaString.length();
|
||||
for (int i = 0; i < len; ++i) {
|
||||
if (manaString[i] == '{') {
|
||||
++i; // Move past '{'
|
||||
if (i < len && manaCounts.find(manaString[i].toLatin1()) != manaCounts.end()) {
|
||||
char mana1 = manaString[i].toLatin1();
|
||||
++i; // Move to next character
|
||||
if (i < len && manaString[i] == '/') {
|
||||
++i; // Move past '/'
|
||||
if (i < len && manaCounts.find(manaString[i].toLatin1()) != manaCounts.end()) {
|
||||
char mana2 = manaString[i].toLatin1();
|
||||
manaCounts[mana1]++;
|
||||
manaCounts[mana2]++;
|
||||
} else {
|
||||
// Handle cases like "{W/}" where second part is invalid
|
||||
manaCounts[mana1]++;
|
||||
}
|
||||
} else {
|
||||
manaCounts[mana1]++;
|
||||
}
|
||||
}
|
||||
// Ensure we always skip to the closing '}'
|
||||
while (i < len && manaString[i] != '}') {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
// Check if the character is a standalone mana symbol (not inside {})
|
||||
else if (manaCounts.find(manaString[i].toLatin1()) != manaCounts.end()) {
|
||||
manaCounts[manaString[i].toLatin1()]++;
|
||||
}
|
||||
}
|
||||
|
||||
return manaCounts;
|
||||
}
|
||||
|
||||
void ManaDevotionWidget::mergeManaCounts(std::unordered_map<char, int> &manaCounts1,
|
||||
const std::unordered_map<char, int> &manaCounts2)
|
||||
{
|
||||
for (const auto &pair : manaCounts2) {
|
||||
manaCounts1[pair.first] += pair.second; // Add values for matching keys
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef MANA_DEVOTION_WIDGET_H
|
||||
#define MANA_DEVOTION_WIDGET_H
|
||||
|
||||
#include "../../../../deck/deck_list_model.h"
|
||||
#include "../general/display/banner_widget.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QWidget>
|
||||
#include <decklist.h>
|
||||
#include <utility>
|
||||
|
||||
class ManaDevotionWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ManaDevotionWidget(QWidget *parent, DeckListModel *deckListModel);
|
||||
void updateDisplay();
|
||||
|
||||
std::unordered_map<char, int> countManaSymbols(const QString &manaString);
|
||||
void mergeManaCounts(std::unordered_map<char, int> &manaCounts1, const std::unordered_map<char, int> &manaCounts2);
|
||||
|
||||
public slots:
|
||||
void setDeckModel(DeckListModel *deckModel);
|
||||
std::unordered_map<char, int> analyzeManaDevotion();
|
||||
void retranslateUi();
|
||||
|
||||
private:
|
||||
DeckListModel *deckListModel;
|
||||
BannerWidget *bannerWidget;
|
||||
std::unordered_map<char, int> manaDevotionMap;
|
||||
QVBoxLayout *layout;
|
||||
QHBoxLayout *barLayout;
|
||||
};
|
||||
|
||||
#endif // MANA_DEVOTION_WIDGET_H
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
#include "bar_widget.h"
|
||||
|
||||
#include <QFontMetrics>
|
||||
#include <QPainter>
|
||||
|
||||
BarWidget::BarWidget(QString label, int value, int total, QColor barColor, QWidget *parent)
|
||||
: QWidget(parent), label(std::move(label)), value(value), total(total), barColor(barColor)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
}
|
||||
|
||||
QSize BarWidget::sizeHint() const
|
||||
{
|
||||
QFontMetrics metrics(font());
|
||||
int labelHeight = metrics.height();
|
||||
int valueHeight = metrics.height();
|
||||
|
||||
// Calculate the height dynamically based on the total
|
||||
int barHeight = (total > 0) ? (value * 200 / total) : 20; // Scale height proportionally
|
||||
int totalHeight = barHeight + labelHeight + valueHeight + 30; // Extra space for text
|
||||
return QSize(60, totalHeight); // Allow width to expand
|
||||
}
|
||||
|
||||
void BarWidget::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
int widgetWidth = width();
|
||||
int widgetHeight = height();
|
||||
|
||||
// Calculate bar dimensions
|
||||
int barWidth = widgetWidth * 0.8; // Use 80% of the available width
|
||||
int fullBarHeight = widgetHeight - 40; // Leave space for labels
|
||||
int valueBarHeight = (total > 0) ? (value * fullBarHeight / total) : 0;
|
||||
|
||||
// Draw full bar background (gray)
|
||||
painter.setBrush(QColor(200, 200, 200));
|
||||
painter.drawRect((widgetWidth - barWidth) / 2, 10, barWidth, fullBarHeight);
|
||||
|
||||
// Draw the value-specific bar using the assigned color
|
||||
painter.setBrush(barColor);
|
||||
painter.drawRect((widgetWidth - barWidth) / 2, 10 + fullBarHeight - valueBarHeight, barWidth, valueBarHeight);
|
||||
|
||||
// Draw the CMC label
|
||||
painter.setPen(Qt::white);
|
||||
QRect textRect(0, widgetHeight - 30, widgetWidth, 20);
|
||||
painter.drawText(textRect, Qt::AlignCenter, label);
|
||||
|
||||
// Draw the value count
|
||||
painter.setPen(Qt::black);
|
||||
QRect valueRect(0, 10, widgetWidth, 20);
|
||||
painter.drawText(valueRect, Qt::AlignCenter, QString::number(value));
|
||||
|
||||
(void)event; // Suppress unused parameter warning
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef BAR_WIDGET_H
|
||||
#define BAR_WIDGET_H
|
||||
|
||||
#include <QColor>
|
||||
#include <QString>
|
||||
#include <QWidget>
|
||||
|
||||
class BarWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit BarWidget(QString label, int value, int total, QColor barColor = Qt::blue, QWidget *parent = nullptr);
|
||||
|
||||
QSize sizeHint() const override;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private:
|
||||
QString label;
|
||||
int value;
|
||||
int total;
|
||||
QColor barColor; // Store the bar color
|
||||
};
|
||||
|
||||
#endif // BAR_WIDGET_H
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
#include "visual_deck_editor_sample_hand_widget.h"
|
||||
|
||||
#include "../../../../deck/deck_loader.h"
|
||||
#include "../../../../game/cards/card_database_manager.h"
|
||||
#include "../cards/card_info_picture_widget.h"
|
||||
|
||||
#include <random>
|
||||
|
||||
VisualDeckEditorSampleHandWidget::VisualDeckEditorSampleHandWidget(QWidget *parent, DeckListModel *_deckListModel)
|
||||
: QWidget(parent), deckListModel(_deckListModel)
|
||||
{
|
||||
layout = new QVBoxLayout(this);
|
||||
setLayout(layout);
|
||||
|
||||
resetButton = new QPushButton(this);
|
||||
connect(resetButton, SIGNAL(clicked()), this, SLOT(updateDisplay()));
|
||||
layout->addWidget(resetButton);
|
||||
|
||||
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAlwaysOff);
|
||||
layout->addWidget(flowWidget);
|
||||
|
||||
for (CardInfoPtr card : getRandomCards(7)) {
|
||||
auto displayWidget = new CardInfoPictureWidget(this);
|
||||
displayWidget->setCard(card);
|
||||
flowWidget->addWidget(displayWidget);
|
||||
}
|
||||
}
|
||||
|
||||
void VisualDeckEditorSampleHandWidget::retranslateUi()
|
||||
{
|
||||
resetButton->setText(tr("Reset"));
|
||||
}
|
||||
|
||||
void VisualDeckEditorSampleHandWidget::setDeckModel(DeckListModel *deckModel)
|
||||
{
|
||||
deckListModel = deckModel;
|
||||
// connect(deckListModel, &DeckListModel::dataChanged, this, &VisualDeckEditorSampleHandWidget::updateDisplay);
|
||||
updateDisplay();
|
||||
}
|
||||
|
||||
void VisualDeckEditorSampleHandWidget::updateDisplay()
|
||||
{
|
||||
flowWidget->clearLayout();
|
||||
for (CardInfoPtr card : getRandomCards(7)) {
|
||||
auto displayWidget = new CardInfoPictureWidget(this);
|
||||
displayWidget->setCard(card);
|
||||
flowWidget->addWidget(displayWidget);
|
||||
}
|
||||
}
|
||||
|
||||
QList<CardInfoPtr> VisualDeckEditorSampleHandWidget::getRandomCards(int amountToGet)
|
||||
{
|
||||
QList<CardInfoPtr> mainDeckCards;
|
||||
QList<CardInfoPtr> randomCards;
|
||||
if (!deckListModel)
|
||||
return randomCards;
|
||||
DeckList *decklist = deckListModel->getDeckList();
|
||||
if (!decklist)
|
||||
return randomCards;
|
||||
InnerDecklistNode *listRoot = decklist->getRoot();
|
||||
if (!listRoot)
|
||||
return randomCards;
|
||||
|
||||
// Collect all cards in the main deck, allowing duplicates based on their count
|
||||
for (int i = 0; i < listRoot->size(); i++) {
|
||||
InnerDecklistNode *currentZone = dynamic_cast<InnerDecklistNode *>(listRoot->at(i));
|
||||
if (!currentZone)
|
||||
continue;
|
||||
if (currentZone->getName() != DECK_ZONE_MAIN)
|
||||
continue; // Only process the main deck
|
||||
|
||||
for (int j = 0; j < currentZone->size(); j++) {
|
||||
DecklistCardNode *currentCard = dynamic_cast<DecklistCardNode *>(currentZone->at(j));
|
||||
if (!currentCard)
|
||||
continue;
|
||||
|
||||
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
||||
CardInfoPtr info = CardDatabaseManager::getInstance()->getCardByNameAndProviderId(
|
||||
currentCard->getName(), currentCard->getCardProviderId());
|
||||
if (info) {
|
||||
mainDeckCards.append(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mainDeckCards.isEmpty())
|
||||
return randomCards;
|
||||
|
||||
// Shuffle the deck
|
||||
std::random_device rd;
|
||||
std::mt19937 rng(rd());
|
||||
std::shuffle(mainDeckCards.begin(), mainDeckCards.end(), rng);
|
||||
|
||||
// Select amountToGet cards
|
||||
|
||||
for (int i = 0; i < qMin(amountToGet, mainDeckCards.size()); ++i) {
|
||||
randomCards.append(mainDeckCards.at(i));
|
||||
}
|
||||
|
||||
std::sort(randomCards.begin(), randomCards.end(),
|
||||
[](const CardInfoPtr &a, const CardInfoPtr &b) { return a->getCmc() < b->getCmc(); });
|
||||
|
||||
return randomCards;
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef VISUAL_DECK_EDITOR_SAMPLE_HAND_WIDGET_H
|
||||
#define VISUAL_DECK_EDITOR_SAMPLE_HAND_WIDGET_H
|
||||
|
||||
#include "../../../../deck/deck_list_model.h"
|
||||
#include "../general/layout_containers/flow_widget.h"
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QWidget>
|
||||
|
||||
class VisualDeckEditorSampleHandWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
VisualDeckEditorSampleHandWidget(QWidget *parent, DeckListModel *deckListModel);
|
||||
QList<CardInfoPtr> getRandomCards(int amountToGet);
|
||||
|
||||
public slots:
|
||||
void updateDisplay();
|
||||
void setDeckModel(DeckListModel *deckModel);
|
||||
void retranslateUi();
|
||||
|
||||
private:
|
||||
DeckListModel *deckListModel;
|
||||
QVBoxLayout *layout;
|
||||
QPushButton *resetButton;
|
||||
FlowWidget *flowWidget;
|
||||
};
|
||||
|
||||
#endif // VISUAL_DECK_EDITOR_SAMPLE_HAND_WIDGET_H
|
||||
Loading…
Add table
Add a link
Reference in a new issue