diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt index 66d4d4675..fc4142e19 100644 --- a/cockatrice/CMakeLists.txt +++ b/cockatrice/CMakeLists.txt @@ -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_list_style_proxy.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/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_push_button.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/shadow_background_label.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_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_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/average_deck/edhrec_average_deck_api_response.cpp src/interface/widgets/tabs/api/edhrec/api_response/average_deck/edhrec_deck_api_response.cpp diff --git a/cockatrice/src/interface/widgets/general/display/background_plate_widget.cpp b/cockatrice/src/interface/widgets/general/display/background_plate_widget.cpp new file mode 100644 index 000000000..dbd5bc0d0 --- /dev/null +++ b/cockatrice/src/interface/widgets/general/display/background_plate_widget.cpp @@ -0,0 +1,23 @@ +#include "background_plate_widget.h" + +#include +#include +#include +#include + +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 +} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/general/display/background_plate_widget.h b/cockatrice/src/interface/widgets/general/display/background_plate_widget.h new file mode 100644 index 000000000..31586cbe6 --- /dev/null +++ b/cockatrice/src/interface/widgets/general/display/background_plate_widget.h @@ -0,0 +1,21 @@ +// +// Created by Ascor on 25-Nov-25. +// + +#ifndef COCKATRICE_BACKGROUND_PLATE_WIDGET_H +#define COCKATRICE_BACKGROUND_PLATE_WIDGET_H + +#include + +class BackgroundPlateWidget : public QWidget +{ + Q_OBJECT + +public: + explicit BackgroundPlateWidget(QWidget *parent = nullptr); + +protected: + void paintEvent(QPaintEvent *event) override; +}; + +#endif // COCKATRICE_BACKGROUND_PLATE_WIDGET_H diff --git a/cockatrice/src/interface/widgets/general/display/color_bar.cpp b/cockatrice/src/interface/widgets/general/display/color_bar.cpp new file mode 100644 index 000000000..62efe6b81 --- /dev/null +++ b/cockatrice/src/interface/widgets/general/display/color_bar.cpp @@ -0,0 +1,147 @@ + +#include "color_bar.h" + +#include +#include +#include +#include + +ColorBar::ColorBar(const QMap &colors, QWidget *parent) : QWidget(parent), m_colors(colors) +{ + setMouseTracking(true); +} + +void ColorBar::setColors(const QMap &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 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 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; +} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/general/display/color_bar.h b/cockatrice/src/interface/widgets/general/display/color_bar.h new file mode 100644 index 000000000..bdb7eb4d4 --- /dev/null +++ b/cockatrice/src/interface/widgets/general/display/color_bar.h @@ -0,0 +1,37 @@ +// +// Created by Ascor on 25-Nov-25. +// + +#ifndef COCKATRICE_COLOR_BAR_H +#define COCKATRICE_COLOR_BAR_H + +#include +#include +#include +#include + +class ColorBar : public QWidget +{ + Q_OBJECT + +public: + explicit ColorBar(const QMap &colors, QWidget *parent = nullptr); + + void setColors(const QMap &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 m_colors; + bool m_hover = false; + + QColor colorFromName(const QString &name) const; + QString tooltipForPosition(int x) const; +}; + +#endif // COCKATRICE_COLOR_BAR_H diff --git a/cockatrice/src/interface/widgets/general/display/overlay_label.cpp b/cockatrice/src/interface/widgets/general/display/overlay_label.cpp new file mode 100644 index 000000000..479615c61 --- /dev/null +++ b/cockatrice/src/interface/widgets/general/display/overlay_label.cpp @@ -0,0 +1,22 @@ +#include "overlay_label.h" + +#include + +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); +} diff --git a/cockatrice/src/interface/widgets/general/display/overlay_label.h b/cockatrice/src/interface/widgets/general/display/overlay_label.h new file mode 100644 index 000000000..88e435f07 --- /dev/null +++ b/cockatrice/src/interface/widgets/general/display/overlay_label.h @@ -0,0 +1,16 @@ +#ifndef COCKATRICE_OVERLAY_LABEL_H +#define COCKATRICE_OVERLAY_LABEL_H + +#include + +class OverlayLabel : public QLabel +{ + Q_OBJECT +public: + explicit OverlayLabel(QWidget *parent = nullptr); + +protected: + void paintEvent(QPaintEvent *event) override; +}; + +#endif // COCKATRICE_OVERLAY_LABEL_H diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_deck_preview_image_display_widget.cpp b/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_deck_preview_image_display_widget.cpp new file mode 100644 index 000000000..94b484df1 --- /dev/null +++ b/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_deck_preview_image_display_widget.cpp @@ -0,0 +1,65 @@ +#include "archidekt_deck_preview_image_display_widget.h" + +#include +#include + +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(); +} diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_deck_preview_image_display_widget.h b/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_deck_preview_image_display_widget.h new file mode 100644 index 000000000..ad04090b0 --- /dev/null +++ b/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_deck_preview_image_display_widget.h @@ -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 +#include + +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