* move message_log_widget to game

* move files

* update headers

* fix cmakelists

* oracle fixes

* split implementation out to cpp

* fix recursive import

* fix main file

* format
This commit is contained in:
ebbit1q 2025-09-20 14:35:52 +02:00 committed by GitHub
parent f484c98152
commit 17dcaf9afa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
337 changed files with 728 additions and 721 deletions

View file

@ -0,0 +1,36 @@
#include "deck_analytics_widget.h"
DeckAnalyticsWidget::DeckAnalyticsWidget(QWidget *parent, DeckListModel *_deckListModel)
: QWidget(parent), deckListModel(_deckListModel)
{
mainLayout = new QVBoxLayout();
setLayout(mainLayout);
scrollArea = new QScrollArea(this);
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
scrollArea->setWidgetResizable(true);
mainLayout->addWidget(scrollArea);
container = new QWidget(scrollArea);
containerLayout = new QVBoxLayout(container);
container->setLayout(containerLayout);
scrollArea->setWidget(container);
manaCurveWidget = new ManaCurveWidget(this, deckListModel);
containerLayout->addWidget(manaCurveWidget);
manaDevotionWidget = new ManaDevotionWidget(this, deckListModel);
containerLayout->addWidget(manaDevotionWidget);
manaBaseWidget = new ManaBaseWidget(this, deckListModel);
containerLayout->addWidget(manaBaseWidget);
}
void DeckAnalyticsWidget::refreshDisplays(DeckListModel *_deckModel)
{
deckListModel = _deckModel;
manaCurveWidget->setDeckModel(_deckModel);
manaDevotionWidget->setDeckModel(_deckModel);
manaBaseWidget->setDeckModel(_deckModel);
}

View file

@ -0,0 +1,40 @@
#ifndef DECK_ANALYTICS_WIDGET_H
#define DECK_ANALYTICS_WIDGET_H
#include "../../../deck/deck_list_model.h"
#include "../general/layout_containers/flow_widget.h"
#include "mana_base_widget.h"
#include "mana_curve_widget.h"
#include "mana_devotion_widget.h"
#include <QHBoxLayout>
#include <QScrollArea>
#include <QVBoxLayout>
#include <QWidget>
#include <deck_list.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;
QWidget *container;
QVBoxLayout *containerLayout;
QScrollArea *scrollArea;
ManaCurveWidget *manaCurveWidget;
ManaDevotionWidget *manaDevotionWidget;
ManaBaseWidget *manaBaseWidget;
};
#endif // DECK_ANALYTICS_WIDGET_H

View file

@ -0,0 +1,135 @@
#include "mana_base_widget.h"
#include "../../../database/card_database.h"
#include "../../../database/card_database_manager.h"
#include "../../../deck/deck_loader.h"
#include "../general/display/banner_widget.h"
#include "../general/display/bar_widget.h"
#include <QHash>
#include <QRegularExpression>
#include <deck_list.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()->getCardInfo(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();
}
}

View file

@ -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 <deck_list.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

View file

@ -0,0 +1,99 @@
#include "mana_curve_widget.h"
#include "../../../database/card_database.h"
#include "../../../database/card_database_manager.h"
#include "../../../deck/deck_loader.h"
#include "../../../main.h"
#include "../general/display/banner_widget.h"
#include "../general/display/bar_widget.h"
#include <deck_list.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()->getCardInfo(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(122, 122, 122), this);
barLayout->addWidget(barWidget);
}
update(); // Update the widget display
}

View file

@ -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

View file

@ -0,0 +1,146 @@
#include "mana_devotion_widget.h"
#include "../../../database/card_database.h"
#include "../../../database/card_database_manager.h"
#include "../../../deck/deck_loader.h"
#include "../../../main.h"
#include "../general/display/banner_widget.h"
#include "../general/display/bar_widget.h"
#include <deck_list.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()->getCardInfo(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
}
}

View file

@ -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 <deck_list.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