mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-06-10 16:24:45 -07:00
[Feature] TabArchidekt and Archidekt API integration (#6348)
* TabArchidekt and Archidekt API integration. Took 37 seconds Took 4 minutes Took 40 seconds Took 4 minutes * Lint. * Lont. * Search bar, fancier display, resolve providerId * Delegate click to base. * Be explicit for pedantic compilers. * Liiint. * Leave them default I guess * Leave them default I guess * Small fixes. * New utility display widgets. * New style for deck listing. * Lint. * Lont. * Scale things. * Delegate paint to base. * Use default Archidekt preview image for decks without featured. * Consistent sizes. * Increase font size, qt version guard. * More version guards. * Clean up filter layout, use mana symbols. * Set content margins. * Refresh on filter change. * Lint. * Better elision. * Query actual new endpoints, new query parameters. * Doxygen, reorder fields in constructor, readability. * Update page size doc to min size. * Update initial min deck size value. * Add label to page selection. * Okay, so, people upload a lot of 1 card decks frequently. * Whoops. * Add a selection combobox for sorting logic. * Debounce and limit searches. * Include. * Lint. * Don't imply that Archidekt supports multiple cards/commander names. * Let's not lambda it and slot it instead. * Overload. * Add button to home tab. Took 8 minutes * Adjust to selection model change. Took 5 minutes * Cleanup auto-generated comments. Took 8 minutes * Remember card sizes. Took 1 minute * Initialize with correct size. Took 3 minutes * Use correct placeholders. Took 2 minutes * Style lint. Took 16 minutes * Parse double-faced cards correctly. * Parse double-faced cards correctly. * Allow TabArchidekt to use VDE group/sort/display buttons * Lint. * Indicate that things are clickable. * Min treshold for nicer display. * Lint. * We have good labels at home. * We do a little linting. * Qt version guards. * Qt5 is the devil. * Update comments. * Lint comments. * More doxys. * One more doxy. * Lint. * Update. * Small fixes. Took 7 minutes Took 13 seconds --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
parent
de13c22552
commit
eab4d435f8
43 changed files with 3285 additions and 141 deletions
|
|
@ -0,0 +1,34 @@
|
|||
#include "background_plate_widget.h"
|
||||
|
||||
#include <QBrush>
|
||||
#include <QColor>
|
||||
#include <QPainter>
|
||||
#include <QPen>
|
||||
|
||||
BackgroundPlateWidget::BackgroundPlateWidget(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
setAutoFillBackground(true); // For automatic background filling
|
||||
}
|
||||
|
||||
void BackgroundPlateWidget::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
QWidget::paintEvent(event);
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||
|
||||
// Set the background color to semi-transparent black with rounded corners
|
||||
QRect rect = this->rect();
|
||||
painter.setPen(Qt::NoPen); // No border
|
||||
if (focused) {
|
||||
painter.setBrush(QColor(85, 190, 75, 140));
|
||||
} else {
|
||||
painter.setBrush(QColor(0, 0, 0, 140)); // semi-transparent black
|
||||
}
|
||||
painter.drawRoundedRect(rect, 6, 6); // rounded corners
|
||||
}
|
||||
|
||||
void BackgroundPlateWidget::setFocused(bool _focused)
|
||||
{
|
||||
focused = _focused;
|
||||
update();
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef COCKATRICE_BACKGROUND_PLATE_WIDGET_H
|
||||
#define COCKATRICE_BACKGROUND_PLATE_WIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class BackgroundPlateWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit BackgroundPlateWidget(QWidget *parent = nullptr);
|
||||
|
||||
void setFocused(bool focused);
|
||||
|
||||
private:
|
||||
bool focused = false;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_BACKGROUND_PLATE_WIDGET_H
|
||||
163
cockatrice/src/interface/widgets/general/display/color_bar.cpp
Normal file
163
cockatrice/src/interface/widgets/general/display/color_bar.cpp
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
|
||||
#include "color_bar.h"
|
||||
|
||||
#include <QLinearGradient>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QToolTip>
|
||||
|
||||
ColorBar::ColorBar(const QMap<QString, int> &_colors, QWidget *parent) : QWidget(parent), colors(_colors)
|
||||
{
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
void ColorBar::setColors(const QMap<QString, int> &_colors)
|
||||
{
|
||||
colors = _colors;
|
||||
update();
|
||||
}
|
||||
|
||||
QSize ColorBar::minimumSizeHint() const
|
||||
{
|
||||
return QSize(200, 22);
|
||||
}
|
||||
|
||||
void ColorBar::paintEvent(QPaintEvent *)
|
||||
{
|
||||
if (colors.isEmpty())
|
||||
return;
|
||||
|
||||
int total = 0;
|
||||
for (int v : colors.values())
|
||||
total += v;
|
||||
|
||||
// Prevent divide-by-zero
|
||||
if (total == 0)
|
||||
return;
|
||||
|
||||
QPainter p(this);
|
||||
p.setRenderHint(QPainter::Antialiasing, true);
|
||||
|
||||
const int w = width();
|
||||
const int h = height();
|
||||
int x = 0;
|
||||
|
||||
// Draw rounded border background
|
||||
QRectF bounds(0.5, 0.5, w - 1, h - 1);
|
||||
p.setPen(QPen(Qt::black, 1));
|
||||
p.setBrush(Qt::NoBrush);
|
||||
p.drawRoundedRect(bounds, 6, 6);
|
||||
|
||||
// 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;
|
||||
|
||||
if (ratio <= minRatioThreshold) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int segmentWidth = int(ratio * w);
|
||||
|
||||
// Ensure the segment width is at least 1 to avoid degenerate rectangles
|
||||
if (segmentWidth < 1)
|
||||
segmentWidth = 1;
|
||||
|
||||
QColor base = colorFromName(key);
|
||||
|
||||
// Slight gradient for nicer look
|
||||
QLinearGradient grad(x, 0, x, h);
|
||||
grad.setColorAt(0, base.lighter(120));
|
||||
grad.setColorAt(1, base.darker(120));
|
||||
|
||||
p.fillRect(QRect(x, 0, segmentWidth, h), grad);
|
||||
|
||||
x += segmentWidth;
|
||||
}
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
void ColorBar::enterEvent(QEnterEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
isHovered = true;
|
||||
}
|
||||
#else
|
||||
void ColorBar::enterEvent(QEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
isHovered = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void ColorBar::leaveEvent(QEvent *)
|
||||
{
|
||||
isHovered = false;
|
||||
}
|
||||
|
||||
void ColorBar::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
if (!isHovered || colors.isEmpty())
|
||||
return;
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
int x = int(event->position().x());
|
||||
QPoint gp = event->globalPosition().toPoint();
|
||||
#else
|
||||
int x = event->pos().x();
|
||||
QPoint gp = event->globalPos();
|
||||
#endif
|
||||
|
||||
QString text = tooltipForPosition(x);
|
||||
if (!text.isEmpty())
|
||||
QToolTip::showText(gp, text, this);
|
||||
}
|
||||
|
||||
QString ColorBar::tooltipForPosition(int x) const
|
||||
{
|
||||
int total = 0;
|
||||
for (int v : colors.values())
|
||||
total += v;
|
||||
|
||||
if (total == 0)
|
||||
return {};
|
||||
|
||||
int pos = 0;
|
||||
for (auto it = colors.cbegin(); it != colors.cend(); ++it) {
|
||||
const double ratio = double(it.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));
|
||||
}
|
||||
|
||||
pos += segmentWidth;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
QColor ColorBar::colorFromName(const QString &name) const
|
||||
{
|
||||
static QMap<QString, QColor> map = {
|
||||
{"R", QColor(220, 30, 30)}, {"G", QColor(40, 170, 40)}, {"U", QColor(40, 90, 200)},
|
||||
{"W", QColor(235, 235, 230)}, {"B", QColor(30, 30, 30)},
|
||||
};
|
||||
|
||||
if (map.contains(name))
|
||||
return map[name];
|
||||
|
||||
QColor c(name);
|
||||
if (!c.isValid())
|
||||
c = Qt::gray;
|
||||
|
||||
return c;
|
||||
}
|
||||
128
cockatrice/src/interface/widgets/general/display/color_bar.h
Normal file
128
cockatrice/src/interface/widgets/general/display/color_bar.h
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
#ifndef COCKATRICE_COLOR_BAR_H
|
||||
#define COCKATRICE_COLOR_BAR_H
|
||||
|
||||
#include <QColor>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QWidget>
|
||||
|
||||
/**
|
||||
* @class ColorBar
|
||||
* @brief A widget for visualizing proportional color distributions as a horizontal bar.
|
||||
*
|
||||
* This widget renders a horizontal bar divided into colored segments whose widths reflect
|
||||
* the relative values associated with each color key in a `QMap<QString, int>`. The class
|
||||
* is designed as a small, lightweight, and self-contained visualization component suitable
|
||||
* for representing distributions such as color counts, mana statistics, categorical frequencies, and similar data sets.
|
||||
*
|
||||
* Key features:
|
||||
* - Filled segments for better visual clarity.
|
||||
* - Deterministic alphabetical ordering of color keys.
|
||||
* - Optional minimum percentage threshold for filtering out insignificant segments.
|
||||
* - Mouse-hover tooltips showing each segment’s key, count, and percentage of total.
|
||||
*
|
||||
* Default color mappings exist for `"R"`, `"G"`, `"U"`, `"W"`, and `"B"`, using named
|
||||
* colors, but any string recognized by `QColor` may be used. If an unknown name is provided,
|
||||
* the segment will fall back to gray.
|
||||
*
|
||||
* This component is display-only and does not interpret or mutate domain-level data.
|
||||
*/
|
||||
class ColorBar : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs a ColorBar widget.
|
||||
*
|
||||
* @param colors Map of color identifiers to integer counts.
|
||||
* @param parent Optional parent widget.
|
||||
*/
|
||||
explicit ColorBar(const QMap<QString, int> &colors, QWidget *parent = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Updates the color distribution map.
|
||||
* @param colors New color → count mapping.
|
||||
*
|
||||
* Triggers an immediate repaint.
|
||||
*/
|
||||
void setColors(const QMap<QString, int> &colors);
|
||||
|
||||
/**
|
||||
* @brief Sets a minimum percentage threshold below which segments are not drawn.
|
||||
*
|
||||
* @param treshold Percentage from 0 to 100.
|
||||
*
|
||||
* Internally converted into a ratio (0.05 = 5%).
|
||||
*/
|
||||
void setMinPercentThreshold(double treshold)
|
||||
{
|
||||
minRatioThreshold = treshold / 100.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the recommended minimum size.
|
||||
*/
|
||||
QSize minimumSizeHint() const override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Paints the color distribution bar.
|
||||
*
|
||||
* Draws:
|
||||
* - A rounded border
|
||||
* - Filled segments for each color
|
||||
* - Only segments above the minimum ratio threshold
|
||||
*/
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
/**
|
||||
* @brief Handles mouse hover entering (Qt6 version).
|
||||
*/
|
||||
void enterEvent(QEnterEvent *event) override;
|
||||
#else
|
||||
/**
|
||||
* @brief Handles mouse hover entering (Qt5 version).
|
||||
*/
|
||||
void enterEvent(QEvent *event) override;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Handles mouse hover leaving.
|
||||
*/
|
||||
void leaveEvent(QEvent *event) override;
|
||||
|
||||
/**
|
||||
* @brief Handles mouse movement to update contextual tooltips.
|
||||
*/
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
|
||||
private:
|
||||
/// Map of color keys to counts used for rendering.
|
||||
QMap<QString, int> colors;
|
||||
|
||||
/// True if the mouse is currently inside the widget.
|
||||
bool isHovered = false;
|
||||
|
||||
/// Minimum ratio a segment must exceed to be drawn.
|
||||
double minRatioThreshold = 0.0;
|
||||
|
||||
/**
|
||||
* @brief Converts a color name into a display QColor.
|
||||
*
|
||||
* Recognized special keys: `"R", "G", "U", "W", "B"`.
|
||||
* Other strings are treated as QColor names or fall back to gray.
|
||||
*/
|
||||
QColor colorFromName(const QString &name) const;
|
||||
|
||||
/**
|
||||
* @brief Returns tooltip text for a given x-coordinate in the bar.
|
||||
*
|
||||
* @param x Horizontal coordinate relative to widget.
|
||||
* @return Tooltip text or empty string if no segment applies.
|
||||
*/
|
||||
QString tooltipForPosition(int x) const;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_COLOR_BAR_H
|
||||
|
|
@ -12,12 +12,18 @@
|
|||
*/
|
||||
ShadowBackgroundLabel::ShadowBackgroundLabel(QWidget *parent, const QString &text) : QLabel(parent)
|
||||
{
|
||||
setAttribute(Qt::WA_TranslucentBackground); // Allows transparency.
|
||||
setText("<font color='white'>" + text + "</font>"); ///< Ensures the text is rendered in white.
|
||||
setAttribute(Qt::WA_TranslucentBackground); // Allows transparency.
|
||||
setLabelText(text);
|
||||
setAlignment(Qt::AlignCenter); ///< Centers the text within the label.
|
||||
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); ///< Ensures minimum size constraints.
|
||||
}
|
||||
|
||||
void ShadowBackgroundLabel::setLabelText(const QString &text)
|
||||
{
|
||||
setText("<font color='white'>" + text + "</font>"); ///< Ensures the text is rendered in white.
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handles resizing of the label.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ class ShadowBackgroundLabel : public QLabel
|
|||
|
||||
public:
|
||||
explicit ShadowBackgroundLabel(QWidget *parent, const QString &text);
|
||||
void setLabelText(const QString &text);
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
|
|
|||
|
|
@ -196,6 +196,9 @@ QGroupBox *HomeWidget::createButtons()
|
|||
auto edhrecButton = new HomeStyledButton(tr("Browse EDHRec"), gradientColors);
|
||||
connect(edhrecButton, &QPushButton::clicked, tabSupervisor, &TabSupervisor::addEdhrecMainTab);
|
||||
boxLayout->addWidget(edhrecButton);
|
||||
auto archidektButton = new HomeStyledButton(tr("Browse Archidekt"), gradientColors);
|
||||
connect(archidektButton, &QPushButton::clicked, tabSupervisor, &TabSupervisor::addArchidektTab);
|
||||
boxLayout->addWidget(archidektButton);
|
||||
auto replaybutton = new HomeStyledButton(tr("View Replays"), gradientColors);
|
||||
connect(replaybutton, &QPushButton::clicked, tabSupervisor, [this] { tabSupervisor->actTabReplays(true); });
|
||||
boxLayout->addWidget(replaybutton);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue