From 3cdd3df666c9c18a183e0771e50668c14ed2ac98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Br=C3=BCbach?= Date: Thu, 10 Jul 2025 15:55:51 +0200 Subject: [PATCH] Rotate random art crop. Took 3 hours 34 minutes Took 9 seconds --- cockatrice/CMakeLists.txt | 1 + .../card_info_picture_art_crop_widget.cpp | 41 +++++++++++++ .../cards/card_info_picture_art_crop_widget.h | 17 ++++++ .../ui/widgets/general/home_styled_button.cpp | 6 ++ .../ui/widgets/general/home_styled_button.h | 1 + .../client/ui/widgets/general/home_widget.cpp | 60 +++++++++++++++++-- .../client/ui/widgets/general/home_widget.h | 6 ++ cockatrice/src/game/cards/card_database.cpp | 12 ++++ cockatrice/src/game/cards/card_database.h | 2 + 9 files changed, 140 insertions(+), 6 deletions(-) create mode 100644 cockatrice/src/client/ui/widgets/cards/card_info_picture_art_crop_widget.cpp create mode 100644 cockatrice/src/client/ui/widgets/cards/card_info_picture_art_crop_widget.h diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt index 0aba9e226..f34cac6cd 100644 --- a/cockatrice/CMakeLists.txt +++ b/cockatrice/CMakeLists.txt @@ -85,6 +85,7 @@ set(cockatrice_SOURCES src/client/ui/widgets/cards/card_group_display_widgets/overlapped_card_group_display_widget.cpp src/client/ui/widgets/cards/card_info_display_widget.cpp src/client/ui/widgets/cards/card_info_frame_widget.cpp + src/client/ui/widgets/cards/card_info_picture_art_crop_widget.cpp src/client/ui/widgets/cards/card_info_picture_enlarged_widget.cpp src/client/ui/widgets/cards/card_info_picture_widget.cpp src/client/ui/widgets/cards/card_info_picture_with_text_overlay_widget.cpp diff --git a/cockatrice/src/client/ui/widgets/cards/card_info_picture_art_crop_widget.cpp b/cockatrice/src/client/ui/widgets/cards/card_info_picture_art_crop_widget.cpp new file mode 100644 index 000000000..63cab97e6 --- /dev/null +++ b/cockatrice/src/client/ui/widgets/cards/card_info_picture_art_crop_widget.cpp @@ -0,0 +1,41 @@ +#include "card_info_picture_art_crop_widget.h" + +#include "../../picture_loader/picture_loader.h" + +CardInfoPictureArtCropWidget::CardInfoPictureArtCropWidget(QWidget *parent) + : CardInfoPictureWidget(parent, false, false) +{ + hide(); +} + +QPixmap CardInfoPictureArtCropWidget::getProcessedBackground(const QSize &targetSize) +{ + // Load the full-resolution card image, not a pre-scaled one + QPixmap fullResPixmap; + if (getInfo()) { + PictureLoader::getPixmap(fullResPixmap, getInfo(), QSize(745, 1040)); // or a high default size + } else { + PictureLoader::getCardBackPixmap(fullResPixmap, QSize(745, 1040)); + } + + // Fail-safe if loading failed + if (fullResPixmap.isNull()) { + return QPixmap(targetSize); + } + + const QSize sz = fullResPixmap.size(); + + int marginX = sz.width() * 0.07; + int topMargin = sz.height() * 0.11; + int bottomMargin = sz.height() * 0.45; + + QRect foilRect(marginX, topMargin, sz.width() - 2 * marginX, sz.height() - topMargin - bottomMargin); + + foilRect = foilRect.intersected(fullResPixmap.rect()); // always clamp to source bounds + + // Crop first, then scale for best quality + QPixmap cropped = fullResPixmap.copy(foilRect); + QPixmap scaled = cropped.scaled(targetSize, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); + + return scaled; +} diff --git a/cockatrice/src/client/ui/widgets/cards/card_info_picture_art_crop_widget.h b/cockatrice/src/client/ui/widgets/cards/card_info_picture_art_crop_widget.h new file mode 100644 index 000000000..8b25af5a8 --- /dev/null +++ b/cockatrice/src/client/ui/widgets/cards/card_info_picture_art_crop_widget.h @@ -0,0 +1,17 @@ +#ifndef CARD_INFO_PICTURE_ART_CROP_WIDGET_H +#define CARD_INFO_PICTURE_ART_CROP_WIDGET_H + +#include "card_info_picture_widget.h" + +class CardInfoPictureArtCropWidget : public CardInfoPictureWidget +{ + Q_OBJECT + +public: + explicit CardInfoPictureArtCropWidget(QWidget *parent = nullptr); + + // Returns a processed (cropped & scaled) version of the pixmap + QPixmap getProcessedBackground(const QSize &targetSize); +}; + +#endif // CARD_INFO_PICTURE_ART_CROP_WIDGET_H diff --git a/cockatrice/src/client/ui/widgets/general/home_styled_button.cpp b/cockatrice/src/client/ui/widgets/general/home_styled_button.cpp index e9a29c3ad..796712fb4 100644 --- a/cockatrice/src/client/ui/widgets/general/home_styled_button.cpp +++ b/cockatrice/src/client/ui/widgets/general/home_styled_button.cpp @@ -12,6 +12,12 @@ HomeStyledButton::HomeStyledButton(const QString &text, QPair _g setStyleSheet(generateButtonStylesheet(gradientColors)); } +void HomeStyledButton::updateStylesheet(const QPair &colors) +{ + gradientColors = colors; + setStyleSheet(generateButtonStylesheet(gradientColors)); +} + QString HomeStyledButton::generateButtonStylesheet(const QPair &colors) { QColor base1 = colors.first; diff --git a/cockatrice/src/client/ui/widgets/general/home_styled_button.h b/cockatrice/src/client/ui/widgets/general/home_styled_button.h index 2b71dbe7f..2ff30fc81 100644 --- a/cockatrice/src/client/ui/widgets/general/home_styled_button.h +++ b/cockatrice/src/client/ui/widgets/general/home_styled_button.h @@ -11,6 +11,7 @@ class HomeStyledButton : public QPushButton Q_OBJECT public: HomeStyledButton(const QString &text, QPair gradientColors, QWidget *parent = nullptr); + void updateStylesheet(const QPair &colors); QString generateButtonStylesheet(const QPair &colors); public slots: void paintEvent(QPaintEvent *event) override; diff --git a/cockatrice/src/client/ui/widgets/general/home_widget.cpp b/cockatrice/src/client/ui/widgets/general/home_widget.cpp index 5791a590a..3a7e0a28e 100644 --- a/cockatrice/src/client/ui/widgets/general/home_widget.cpp +++ b/cockatrice/src/client/ui/widgets/general/home_widget.cpp @@ -1,5 +1,6 @@ #include "home_widget.h" +#include "../../../../game/cards/card_database_manager.h" #include "../../../tabs/tab_supervisor.h" #include "home_styled_button.h" @@ -11,8 +12,15 @@ HomeWidget::HomeWidget(QWidget *parent, TabSupervisor *_tabSupervisor) : QWidget(parent), tabSupervisor(_tabSupervisor), background("theme:backgrounds/home"), overlay("theme:cockatrice") { + setAttribute(Qt::WA_OpaquePaintEvent); layout = new QGridLayout(this); + backgroundSource = new CardInfoPictureArtCropWidget(this); + + backgroundSource->setCard(CardDatabaseManager::getInstance()->getRandomCard()); + + background = backgroundSource->getProcessedBackground(size()); + gradientColors = extractDominantColors(background); layout->addWidget(createSettingsButtonGroup("Settings"), 0, 0, Qt::AlignTop | Qt::AlignLeft); @@ -26,6 +34,42 @@ HomeWidget::HomeWidget(QWidget *parent, TabSupervisor *_tabSupervisor) layout->setColumnStretch(2, 1); setLayout(layout); + + connect(CardDatabaseManager::getInstance(), &CardDatabase::cardDatabaseLoadingFinished, this, + &HomeWidget::startCardShuffleTimer); + + if (CardDatabaseManager::getInstance()->getLoadStatus() == LoadStatus::Ok) { + startCardShuffleTimer(); + } +} + +void HomeWidget::startCardShuffleTimer() +{ + cardChangeTimer = new QTimer(this); + connect(cardChangeTimer, &QTimer::timeout, this, &HomeWidget::updateRandomCard); + cardChangeTimer->start(5000); // 20 seconds +} + +void HomeWidget::updateRandomCard() +{ + CardInfoPtr newCard = CardDatabaseManager::getInstance()->getRandomCard(); + if (!newCard) + return; + + connect(newCard.data(), &CardInfo::pixmapUpdated, this, &HomeWidget::updateBackgroundProperties); + backgroundSource->setCard(newCard); +} + +void HomeWidget::updateBackgroundProperties() +{ + background = backgroundSource->getProcessedBackground(size()); + + gradientColors = extractDominantColors(background); + for (HomeStyledButton *button : findChildren()) { + button->updateStylesheet(gradientColors); + button->update(); + } + update(); // Triggers repaint } QGroupBox *HomeWidget::createSettingsButtonGroup(const QString &title) @@ -197,13 +241,17 @@ void HomeWidget::paintEvent(QPaintEvent *event) { QPainter painter(this); - // Draw zoomed background + // Update background if we have a source + if (backgroundSource) { + background = backgroundSource->getProcessedBackground(size()); + } + + // Draw already-scaled background centered QSize widgetSize = size(); QSize bgSize = background.size(); - QSize scaledSize = bgSize.scaled(widgetSize, Qt::KeepAspectRatioByExpanding); - QPoint topLeft((widgetSize.width() - scaledSize.width()) / 2, (widgetSize.height() - scaledSize.height()) / 2); - painter.drawPixmap(topLeft, - background.scaled(scaledSize, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation)); + QPoint topLeft((widgetSize.width() - bgSize.width()) / 2, (widgetSize.height() - bgSize.height()) / 2); + + painter.drawPixmap(topLeft, background); // Draw translucent black overlay with rounded corners QRectF overlayRect(5, 5, width() - 10, height() - 10); // 5px inset @@ -220,4 +268,4 @@ void HomeWidget::paintEvent(QPaintEvent *event) painter.drawPixmap(center, overlay); QWidget::paintEvent(event); -} \ No newline at end of file +} diff --git a/cockatrice/src/client/ui/widgets/general/home_widget.h b/cockatrice/src/client/ui/widgets/general/home_widget.h index 048605b7c..b3a5c8ee6 100644 --- a/cockatrice/src/client/ui/widgets/general/home_widget.h +++ b/cockatrice/src/client/ui/widgets/general/home_widget.h @@ -1,6 +1,7 @@ #ifndef HOME_WIDGET_H #define HOME_WIDGET_H #include "../../../tabs/tab_supervisor.h" +#include "../cards/card_info_picture_art_crop_widget.h" #include #include @@ -13,6 +14,8 @@ class HomeWidget : public QWidget public: HomeWidget(QWidget *parent, TabSupervisor *tabSupervisor); + void startCardShuffleTimer(); + void updateRandomCard(); QGroupBox *createSettingsButtonGroup(const QString &title); QGroupBox *createUpdatesButtonGroup(const QString &title); QGroupBox *createNavigationButtonGroup(const QString &title); @@ -21,11 +24,14 @@ public: public slots: void paintEvent(QPaintEvent *event) override; + void updateBackgroundProperties(); private: QGridLayout *layout; + QTimer *cardChangeTimer; TabSupervisor *tabSupervisor; QPixmap background; + CardInfoPictureArtCropWidget *backgroundSource = nullptr; QPixmap overlay; QPair gradientColors; }; diff --git a/cockatrice/src/game/cards/card_database.cpp b/cockatrice/src/game/cards/card_database.cpp index e32519de1..83ee5814c 100644 --- a/cockatrice/src/game/cards/card_database.cpp +++ b/cockatrice/src/game/cards/card_database.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include CardDatabase::CardDatabase(QObject *parent) : QObject(parent), loadStatus(NotLoaded) @@ -213,6 +214,17 @@ ExactCard CardDatabase::guessCard(const CardRef &cardRef) const return ExactCard(temp, findPrintingWithId(temp, cardRef.providerId)); } +CardInfoPtr CardDatabase::getRandomCard() +{ + if (cards.isEmpty()) return nullptr; + + const auto keys = cards.keys(); + int randomIndex = QRandomGenerator::global()->bounded(keys.size()); + const QString &randomKey = keys.at(randomIndex); + + return getCardFromMap(cards, randomKey); +} + CardSetPtr CardDatabase::getSet(const QString &setName) { if (sets.contains(setName)) { diff --git a/cockatrice/src/game/cards/card_database.h b/cockatrice/src/game/cards/card_database.h index 0654c7494..989812047 100644 --- a/cockatrice/src/game/cards/card_database.h +++ b/cockatrice/src/game/cards/card_database.h @@ -53,6 +53,7 @@ protected: QVector availableParsers; private: + CardInfoPtr getCardFromMap(const CardNameMap &cardMap, const QString &cardName) const; void checkUnknownSets(); void refreshCachedReverseRelatedCards(); @@ -85,6 +86,7 @@ public: ExactCard getCardFromSameSet(const QString &cardName, const PrintingInfo &otherPrinting) const; [[nodiscard]] ExactCard guessCard(const CardRef &cardRef) const; + [[nodiscard]] ExactCard getRandomCard(); /* * Get a card by its simple name. The name will be simplified in this