New utility display widgets.

This commit is contained in:
Brübach, Lukas 2025-11-25 09:37:37 +01:00
parent 2867fbabe6
commit 45c599cae9
9 changed files with 364 additions and 0 deletions

View file

@ -153,11 +153,14 @@ set(cockatrice_SOURCES
src/interface/widgets/deck_editor/deck_editor_printing_selector_dock_widget.cpp src/interface/widgets/deck_editor/deck_editor_printing_selector_dock_widget.cpp
src/interface/widgets/deck_editor/deck_list_style_proxy.cpp src/interface/widgets/deck_editor/deck_list_style_proxy.cpp
src/interface/widgets/general/background_sources.cpp src/interface/widgets/general/background_sources.cpp
src/interface/widgets/general/display/background_plate_widget.cpp
src/interface/widgets/general/display/banner_widget.cpp src/interface/widgets/general/display/banner_widget.cpp
src/interface/widgets/general/display/bar_widget.cpp src/interface/widgets/general/display/bar_widget.cpp
src/interface/widgets/general/display/color_bar.cpp
src/interface/widgets/general/display/dynamic_font_size_label.cpp src/interface/widgets/general/display/dynamic_font_size_label.cpp
src/interface/widgets/general/display/dynamic_font_size_push_button.cpp src/interface/widgets/general/display/dynamic_font_size_push_button.cpp
src/interface/widgets/general/display/labeled_input.cpp src/interface/widgets/general/display/labeled_input.cpp
src/interface/widgets/general/display/overlay_label.cpp
src/interface/widgets/general/display/percent_bar_widget.cpp src/interface/widgets/general/display/percent_bar_widget.cpp
src/interface/widgets/general/display/shadow_background_label.cpp src/interface/widgets/general/display/shadow_background_label.cpp
src/interface/widgets/general/home_styled_button.cpp src/interface/widgets/general/home_styled_button.cpp
@ -232,6 +235,7 @@ set(cockatrice_SOURCES
src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.cpp src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.cpp
src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_entry_display_widget.cpp src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_entry_display_widget.cpp
src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_listings_display_widget.cpp src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_listings_display_widget.cpp
src/interface/widgets/tabs/api/archidekt/display/archidekt_deck_preview_image_display_widget.cpp
src/interface/widgets/tabs/api/edhrec/api_response/archidekt_links/edhrec_api_response_archidekt_links.cpp src/interface/widgets/tabs/api/edhrec/api_response/archidekt_links/edhrec_api_response_archidekt_links.cpp
src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_average_deck_api_response.cpp src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_average_deck_api_response.cpp
src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_deck_api_response.cpp src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_deck_api_response.cpp

View file

@ -0,0 +1,23 @@
#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)
{
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
painter.setBrush(QColor(0, 0, 0, 140)); // semi-transparent black
painter.drawRoundedRect(rect, 6, 6); // rounded corners
}

View file

@ -0,0 +1,21 @@
//
// Created by Ascor on 25-Nov-25.
//
#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);
protected:
void paintEvent(QPaintEvent *event) override;
};
#endif // COCKATRICE_BACKGROUND_PLATE_WIDGET_H

View file

@ -0,0 +1,147 @@
#include "color_bar.h"
#include <QLinearGradient>
#include <QMouseEvent>
#include <QPainter>
#include <QToolTip>
ColorBar::ColorBar(const QMap<QString, int> &colors, QWidget *parent) : QWidget(parent), m_colors(colors)
{
setMouseTracking(true);
}
void ColorBar::setColors(const QMap<QString, int> &colors)
{
m_colors = colors;
update();
}
QSize ColorBar::minimumSizeHint() const
{
return QSize(200, 22); // Slightly taller for rounded look
}
//-------------------------------------------
// Painting
//-------------------------------------------
void ColorBar::paintEvent(QPaintEvent *)
{
if (m_colors.isEmpty())
return;
int total = 0;
for (int v : m_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 of the border
p.setClipRect(bounds.adjusted(2, 2, -2, -2));
// Sort colors by key (this ensures a predictable order)
QList<QString> sortedKeys = m_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 = m_colors[key];
double ratio = double(value) / total;
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;
}
}
//-------------------------------------------
// Hover + Tooltips
//-------------------------------------------
void ColorBar::enterEvent(QEnterEvent *)
{
m_hover = true;
}
void ColorBar::leaveEvent(QEvent *)
{
m_hover = false;
}
void ColorBar::mouseMoveEvent(QMouseEvent *event)
{
if (!m_hover || m_colors.isEmpty())
return;
QString text = tooltipForPosition(event->position().x());
if (!text.isEmpty())
QToolTip::showText(event->globalPosition().toPoint(), text, this);
}
QString ColorBar::tooltipForPosition(int x) const
{
int total = 0;
for (int v : m_colors.values())
total += v;
int pos = 0;
for (auto it = m_colors.begin(); it != m_colors.end(); ++it) {
double ratio = double(it.value()) / total;
int segmentWidth = int(ratio * width());
if (x >= pos && x < pos + segmentWidth) {
double percent = (100.0 * it.value()) / total;
return QString("%1: %2 cards (%.1f%)").arg(it.key()).arg(it.value()).arg(percent);
}
pos += segmentWidth;
}
return {};
}
//-------------------------------------------
// Color name mapping (expandable)
//-------------------------------------------
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;
}

View file

@ -0,0 +1,37 @@
//
// Created by Ascor on 25-Nov-25.
//
#ifndef COCKATRICE_COLOR_BAR_H
#define COCKATRICE_COLOR_BAR_H
#include <QColor>
#include <QMap>
#include <QString>
#include <QWidget>
class ColorBar : public QWidget
{
Q_OBJECT
public:
explicit ColorBar(const QMap<QString, int> &colors, QWidget *parent = nullptr);
void setColors(const QMap<QString, int> &colors);
QSize minimumSizeHint() const override;
protected:
void paintEvent(QPaintEvent *event) override;
void enterEvent(QEnterEvent *event) override;
void leaveEvent(QEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
private:
QMap<QString, int> m_colors;
bool m_hover = false;
QColor colorFromName(const QString &name) const;
QString tooltipForPosition(int x) const;
};
#endif // COCKATRICE_COLOR_BAR_H

View file

@ -0,0 +1,22 @@
#include "overlay_label.h"
#include <QPainter>
OverlayLabel::OverlayLabel(QWidget *parent) : QLabel(parent)
{
setAttribute(Qt::WA_TranslucentBackground);
}
void OverlayLabel::paintEvent(QPaintEvent *event)
{
QPainter p(this);
p.setRenderHint(QPainter::Antialiasing, true);
QRect r = rect().adjusted(0, 0, -1, -1);
p.setBrush(QColor(0, 0, 0, 140));
p.setPen(Qt::NoPen);
p.drawRoundedRect(r, 6, 6);
QLabel::paintEvent(event);
}

View file

@ -0,0 +1,16 @@
#ifndef COCKATRICE_OVERLAY_LABEL_H
#define COCKATRICE_OVERLAY_LABEL_H
#include <QLabel>
class OverlayLabel : public QLabel
{
Q_OBJECT
public:
explicit OverlayLabel(QWidget *parent = nullptr);
protected:
void paintEvent(QPaintEvent *event) override;
};
#endif // COCKATRICE_OVERLAY_LABEL_H

View file

@ -0,0 +1,65 @@
#include "archidekt_deck_preview_image_display_widget.h"
#include <QFontMetrics>
#include <QPainter>
ArchidektDeckPreviewImageDisplayWidget::ArchidektDeckPreviewImageDisplayWidget(QWidget *parent) : QWidget(parent)
{
imageLabel = new QLabel(this);
imageLabel->setAlignment(Qt::AlignCenter);
topLeftLabel = new OverlayLabel(this);
topRightLabel = new OverlayLabel(this);
bottomLeftLabel = new OverlayLabel(this);
bottomRightLabel = new OverlayLabel(this);
QFont f;
f.setBold(true);
topLeftLabel->setFont(f);
topRightLabel->setFont(f);
bottomLeftLabel->setFont(f);
bottomRightLabel->setFont(f);
// Raise so labels appear above image
topLeftLabel->raise();
topRightLabel->raise();
bottomLeftLabel->raise();
bottomRightLabel->raise();
}
void ArchidektDeckPreviewImageDisplayWidget::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
// Full size for the image
imageLabel->setGeometry(rect());
topLeftLabel->adjustSize();
topRightLabel->adjustSize();
bottomLeftLabel->adjustSize();
bottomRightLabel->adjustSize();
// Padding settings
const int horizontalPadding = 8;
const int topPadding = 6;
const int bottomPadding = 6;
// Left-aligned, top-aligned (Deck Name)
topLeftLabel->move(horizontalPadding, topPadding);
// Right-aligned, top-aligned (Card Count)
topRightLabel->move(width() - topRightLabel->width() - horizontalPadding, topPadding);
// Bottom-left, bottom-aligned (EDH bracket)
bottomLeftLabel->move(horizontalPadding, height() - bottomLeftLabel->height() - bottomPadding);
// Bottom-right, bottom-aligned (views)
bottomRightLabel->move(width() - bottomRightLabel->width() - horizontalPadding,
height() - bottomRightLabel->height() - bottomPadding);
// Ensure labels stay above image
topLeftLabel->raise();
topRightLabel->raise();
bottomLeftLabel->raise();
bottomRightLabel->raise();
}

View file

@ -0,0 +1,29 @@
//
// Created by Ascor on 25-Nov-25.
//
#ifndef COCKATRICE_ARCHIDEKT_DECK_PREVIEW_IMAGE_DISPLAY_WIDGET_H
#define COCKATRICE_ARCHIDEKT_DECK_PREVIEW_IMAGE_DISPLAY_WIDGET_H
#include "../../../../general/display/overlay_label.h"
#include <QLabel>
#include <QWidget>
class ArchidektDeckPreviewImageDisplayWidget : public QWidget
{
Q_OBJECT
public:
explicit ArchidektDeckPreviewImageDisplayWidget(QWidget *parent = nullptr);
QLabel *imageLabel;
OverlayLabel *topLeftLabel;
OverlayLabel *topRightLabel;
OverlayLabel *bottomLeftLabel;
OverlayLabel *bottomRightLabel;
protected:
void resizeEvent(QResizeEvent *event) override;
};
#endif // COCKATRICE_ARCHIDEKT_DECK_PREVIEW_IMAGE_DISPLAY_WIDGET_H