mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-01-19 16:20:50 -08:00
[DeckAnalytics] Enforce WUBRGC ordering for analytics. (#6509)
* [DeckAnalytics] Enforce WUBRGC ordering for analytics. Took 6 minutes Took 7 seconds * Include QSet Took 51 seconds * Move include out of namespace. Took 6 minutes --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <QDialog>
|
||||
#include <QListWidget>
|
||||
#include <libcockatrice/utility/color.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -71,14 +72,16 @@ void ManaBaseWidget::updateDisplay()
|
||||
|
||||
// Choose display mode
|
||||
if (config.displayType == "bar") {
|
||||
QHash<QString, QColor> colors = {{"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)}};
|
||||
const QList<QPair<QString, int>> sortedColors = GameSpecificColors::MTG::sortManaMapWUBRGCFirst(mapSorted);
|
||||
static const QHash<QString, QColor> colorMap = {
|
||||
{"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 color : manaMap.keys()) {
|
||||
QString label = QString("%1 %2 (%3)").arg(color).arg(manaMap[color]).arg(cardCount.value(color));
|
||||
for (const auto &[color, count] : sortedColors) {
|
||||
QString label = QString("%1 %2 (%3)").arg(color).arg(count).arg(cardCount.value(color));
|
||||
|
||||
BarWidget *bar = new BarWidget(label, manaMap[color], highest, colors.value(color, Qt::gray), this);
|
||||
BarWidget *bar = new BarWidget(label, count, highest, colorMap.value(color, Qt::gray), this);
|
||||
|
||||
barLayout->addWidget(bar);
|
||||
}
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
#include "color_bar.h"
|
||||
|
||||
#include "libcockatrice/utility/color.h"
|
||||
|
||||
#include <QLinearGradient>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QToolTip>
|
||||
|
||||
ColorBar::ColorBar(const QMap<QString, int> &_colors, QWidget *parent) : QWidget(parent), colors(_colors)
|
||||
ColorBar::ColorBar(const QMap<QString, int> &_colors, QWidget *parent)
|
||||
: QWidget(parent), colors(GameSpecificColors::MTG::sortManaMapWUBRGCFirst(_colors))
|
||||
{
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
void ColorBar::setColors(const QMap<QString, int> &_colors)
|
||||
{
|
||||
colors = _colors;
|
||||
colors = GameSpecificColors::MTG::sortManaMapWUBRGCFirst(_colors);
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -27,8 +30,8 @@ void ColorBar::paintEvent(QPaintEvent *)
|
||||
return;
|
||||
|
||||
int total = 0;
|
||||
for (int v : colors.values())
|
||||
total += v;
|
||||
for (const auto &pair : colors)
|
||||
total += pair.second;
|
||||
|
||||
// Prevent divide-by-zero
|
||||
if (total == 0)
|
||||
@@ -50,15 +53,9 @@ void ColorBar::paintEvent(QPaintEvent *)
|
||||
// Clip to inside the border
|
||||
p.setClipRect(bounds.adjusted(2, 2, -2, -2));
|
||||
|
||||
// Ensure predictable order
|
||||
QList<QString> sortedKeys = colors.keys();
|
||||
std::sort(sortedKeys.begin(), sortedKeys.end()); // Sort alphabetically
|
||||
|
||||
// Draw each color segment in the sorted order
|
||||
for (const QString &key : sortedKeys) {
|
||||
int value = colors[key];
|
||||
double ratio = double(value) / total;
|
||||
|
||||
// Draw segments IN ORDER
|
||||
for (const auto &[key, value] : colors) {
|
||||
const double ratio = double(value) / total;
|
||||
if (ratio <= minRatioThreshold) {
|
||||
continue;
|
||||
}
|
||||
@@ -122,20 +119,21 @@ void ColorBar::mouseMoveEvent(QMouseEvent *event)
|
||||
QString ColorBar::tooltipForPosition(int x) const
|
||||
{
|
||||
int total = 0;
|
||||
for (int v : colors.values())
|
||||
total += v;
|
||||
for (const auto &pair : colors)
|
||||
total += pair.second;
|
||||
|
||||
if (total == 0)
|
||||
return {};
|
||||
|
||||
int pos = 0;
|
||||
for (auto it = colors.cbegin(); it != colors.cend(); ++it) {
|
||||
const double ratio = double(it.value()) / total;
|
||||
|
||||
for (const auto &[key, value] : colors) {
|
||||
const double ratio = double(value) / total;
|
||||
const int segmentWidth = int(ratio * width());
|
||||
|
||||
if (x >= pos && x < pos + segmentWidth) {
|
||||
const double percent = (100.0 * it.value()) / total;
|
||||
return QString("%1: %2 cards (%3%)").arg(it.key()).arg(it.value()).arg(QString::number(percent, 'f', 1));
|
||||
const double percent = (100.0 * value) / total;
|
||||
return QString("%1: %2 cards (%3%)").arg(key).arg(value).arg(QString::number(percent, 'f', 1));
|
||||
}
|
||||
|
||||
pos += segmentWidth;
|
||||
|
||||
@@ -100,7 +100,7 @@ protected:
|
||||
|
||||
private:
|
||||
/// Map of color keys to counts used for rendering.
|
||||
QMap<QString, int> colors;
|
||||
QList<QPair<QString, int>> colors;
|
||||
|
||||
/// True if the mouse is currently inside the widget.
|
||||
bool isHovered = false;
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
#include "color_pie.h"
|
||||
|
||||
#include "libcockatrice/utility/color.h"
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QToolTip>
|
||||
#include <QtMath>
|
||||
|
||||
ColorPie::ColorPie(const QMap<QString, int> &_colors, QWidget *parent) : QWidget(parent), colors(_colors)
|
||||
ColorPie::ColorPie(const QMap<QString, int> &_colors, QWidget *parent)
|
||||
: QWidget(parent), colors(GameSpecificColors::MTG::sortManaMapWUBRGCFirst(_colors))
|
||||
{
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
void ColorPie::setColors(const QMap<QString, int> &_colors)
|
||||
{
|
||||
colors = _colors;
|
||||
colors = GameSpecificColors::MTG::sortManaMapWUBRGCFirst(_colors);
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -28,8 +31,8 @@ void ColorPie::paintEvent(QPaintEvent *)
|
||||
}
|
||||
|
||||
int total = 0;
|
||||
for (int v : colors.values()) {
|
||||
total += v;
|
||||
for (const auto &pair : colors) {
|
||||
total += pair.second;
|
||||
}
|
||||
|
||||
if (total == 0) {
|
||||
@@ -41,24 +44,18 @@ void ColorPie::paintEvent(QPaintEvent *)
|
||||
|
||||
int w = width();
|
||||
int h = height();
|
||||
int size = qMin(w, h) - 40; // leave space for labels
|
||||
int size = qMin(w, h) - 40;
|
||||
QRectF rect((w - size) / 2.0, (h - size) / 2.0, size, size);
|
||||
|
||||
// Draw border
|
||||
// Border
|
||||
p.setPen(QPen(Qt::black, 1));
|
||||
p.setBrush(Qt::NoBrush);
|
||||
p.drawEllipse(rect);
|
||||
|
||||
// Sorted keys for predictable order
|
||||
QList<QString> sortedKeys = colors.keys();
|
||||
std::sort(sortedKeys.begin(), sortedKeys.end());
|
||||
|
||||
double startAngle = 0.0;
|
||||
|
||||
for (const QString &key : sortedKeys) {
|
||||
int value = colors[key];
|
||||
for (const auto &[key, value] : colors) {
|
||||
double ratio = double(value) / total;
|
||||
|
||||
if (ratio <= minRatioThreshold) {
|
||||
continue;
|
||||
}
|
||||
@@ -67,20 +64,18 @@ void ColorPie::paintEvent(QPaintEvent *)
|
||||
|
||||
QColor base = colorFromName(key);
|
||||
|
||||
// Gradient
|
||||
QRadialGradient grad(rect.center(), size / 2);
|
||||
grad.setColorAt(0, base.lighter(130));
|
||||
grad.setColorAt(1, base.darker(130));
|
||||
|
||||
p.setBrush(grad);
|
||||
p.setPen(Qt::NoPen);
|
||||
|
||||
// Draw slice
|
||||
p.drawPie(rect, int(startAngle * 16), int(spanAngle * 16));
|
||||
|
||||
// Draw percent label
|
||||
double midAngle = startAngle + spanAngle / 2;
|
||||
// Percent label
|
||||
double midAngle = startAngle + spanAngle / 2.0;
|
||||
double rad = qDegreesToRadians(midAngle);
|
||||
double labelRadius = size / 2 + 15; // slightly outside the pie
|
||||
double labelRadius = size / 2 + 15;
|
||||
QPointF center = rect.center();
|
||||
QPointF labelPos(center.x() + labelRadius * qCos(rad), center.y() - labelRadius * qSin(rad));
|
||||
|
||||
@@ -147,10 +142,13 @@ QString ColorPie::tooltipForPoint(const QPoint &pt) const
|
||||
}
|
||||
|
||||
int total = 0;
|
||||
for (int v : colors.values())
|
||||
total += v;
|
||||
if (total == 0)
|
||||
for (const auto &pair : colors) {
|
||||
total += pair.second;
|
||||
}
|
||||
|
||||
if (total == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
int w = width();
|
||||
int h = height();
|
||||
@@ -158,9 +156,9 @@ QString ColorPie::tooltipForPoint(const QPoint &pt) const
|
||||
QPointF center(w / 2.0, h / 2.0);
|
||||
|
||||
QPointF v = pt - center;
|
||||
double distance = std::sqrt(v.x() * v.x() + v.y() * v.y());
|
||||
double distance = std::hypot(v.x(), v.y());
|
||||
if (distance > size / 2.0)
|
||||
return {}; // outside pie
|
||||
return {};
|
||||
|
||||
double angle = std::atan2(-v.y(), v.x()) * 180.0 / M_PI;
|
||||
if (angle < 0) {
|
||||
@@ -169,16 +167,19 @@ QString ColorPie::tooltipForPoint(const QPoint &pt) const
|
||||
|
||||
double acc = 0.0;
|
||||
|
||||
QList<QString> keys = colors.keys();
|
||||
std::sort(keys.begin(), keys.end());
|
||||
for (const auto &[key, value] : colors) {
|
||||
double ratio = double(value) / total;
|
||||
if (ratio <= minRatioThreshold) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const QString &key : keys) {
|
||||
double span = (double(colors[key]) / total) * 360.0;
|
||||
double span = ratio * 360.0;
|
||||
|
||||
if (angle >= acc && angle < acc + span) {
|
||||
double percent = (100.0 * colors[key]) / total;
|
||||
return QString("%1: %2 cards (%3%)").arg(key).arg(colors[key]).arg(QString::number(percent, 'f', 1));
|
||||
double percent = (100.0 * value) / total;
|
||||
return QString("%1: %2 cards (%3%)").arg(key).arg(value).arg(QString::number(percent, 'f', 1));
|
||||
}
|
||||
|
||||
acc += span;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ protected:
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
|
||||
private:
|
||||
QMap<QString, int> colors;
|
||||
QList<QPair<QString, int>> colors;
|
||||
bool isHovered = false;
|
||||
const double minRatioThreshold = 0.01; // skip tiny slices
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@ inline color convertQColorToColor(const QColor &c)
|
||||
return result;
|
||||
}
|
||||
|
||||
#include <QSet>
|
||||
|
||||
namespace GameSpecificColors
|
||||
{
|
||||
namespace MTG
|
||||
@@ -56,6 +58,32 @@ inline QColor colorHelper(const QString &name)
|
||||
|
||||
return QColor(r, g, b);
|
||||
}
|
||||
|
||||
inline QList<QPair<QString, int>> sortManaMapWUBRGCFirst(const QMap<QString, int> &input)
|
||||
{
|
||||
static const QStringList priorityOrder = {"W", "U", "B", "R", "G", "C"};
|
||||
|
||||
QList<QPair<QString, int>> result;
|
||||
QSet<QString> consumed;
|
||||
|
||||
// 1. Add priority colors in fixed order
|
||||
for (const QString &key : priorityOrder) {
|
||||
auto it = input.find(key);
|
||||
if (it != input.end()) {
|
||||
result.append({it.key(), it.value()});
|
||||
consumed.insert(it.key());
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Add remaining keys (QMap iteration is already sorted)
|
||||
for (auto it = input.begin(); it != input.end(); ++it) {
|
||||
if (!consumed.contains(it.key())) {
|
||||
result.append({it.key(), it.value()});
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
} // namespace MTG
|
||||
} // namespace GameSpecificColors
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user