Refactor Card Info Widgets (#5176)

* Refactor CardInfo Widgets to reside in their appropriate folder and to have a clearer naming structure.

* Add optional HoverToZoom functionality to CardInfoPictureWidget (default: disabled) and utility class to display text over a CardInfoPictureWidget.

* Patch CardInfoWidgets to use the new CardDatabaseManager.

* Add HoverToZoom to CardInfoPictureWithTextOverlayWidget

* Refactors and new signals for CardInfoPictureWidgets.

* Address pull request comments (nullptr checks and additional comments, mostly.)

* Reformat code so the linter will stop yelling at me.

* Linting.

* Fix the build.

* Fix warnings.

* Formatting, const qualifiers.

* Sensibly call the base class's (QWidget) paint event.

* Address PR comments (card picture).

* QT Version check because enterEvent signature changed.

* Linting.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
BruebachL 2024-11-17 16:49:22 +01:00 committed by GitHub
parent c2fe3cda35
commit c8336df49d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 785 additions and 177 deletions

View file

@ -1,124 +0,0 @@
#include "card_frame.h"
#include "../../main.h"
#include "../../settings/cache_settings.h"
#include "card_database_manager.h"
#include "card_info_picture.h"
#include "card_info_text.h"
#include "card_item.h"
#include <QSplitter>
#include <QVBoxLayout>
#include <utility>
CardFrame::CardFrame(const QString &cardName, QWidget *parent) : QTabWidget(parent), info(nullptr), cardTextOnly(false)
{
setContentsMargins(3, 3, 3, 3);
pic = new CardInfoPicture();
pic->setObjectName("pic");
text = new CardInfoText();
text->setObjectName("text");
connect(text, SIGNAL(linkActivated(const QString &)), this, SLOT(setCard(const QString &)));
tab1 = new QWidget(this);
tab2 = new QWidget(this);
tab3 = new QWidget(this);
tab1->setObjectName("tab1");
tab2->setObjectName("tab2");
tab3->setObjectName("tab3");
insertTab(ImageOnlyView, tab1, QString());
insertTab(TextOnlyView, tab2, QString());
insertTab(ImageAndTextView, tab3, QString());
connect(this, SIGNAL(currentChanged(int)), this, SLOT(setViewMode(int)));
tab1Layout = new QVBoxLayout();
tab1Layout->setObjectName("tab1Layout");
tab1Layout->setContentsMargins(0, 0, 0, 0);
tab1Layout->setSpacing(0);
tab1->setLayout(tab1Layout);
tab2Layout = new QVBoxLayout();
tab2Layout->setObjectName("tab2Layout");
tab2Layout->setContentsMargins(0, 0, 0, 0);
tab2Layout->setSpacing(0);
tab2->setLayout(tab2Layout);
splitter = new QSplitter();
splitter->setObjectName("splitter");
splitter->setOrientation(Qt::Vertical);
tab3Layout = new QVBoxLayout();
tab3Layout->setObjectName("tab3Layout");
tab3Layout->setContentsMargins(0, 0, 0, 0);
tab3Layout->setSpacing(0);
tab3Layout->addWidget(splitter);
tab3->setLayout(tab3Layout);
setViewMode(SettingsCache::instance().getCardInfoViewMode());
setCard(CardDatabaseManager::getInstance()->getCard(cardName));
}
void CardFrame::retranslateUi()
{
setTabText(ImageOnlyView, tr("Image"));
setTabText(TextOnlyView, tr("Description"));
setTabText(ImageAndTextView, tr("Both"));
}
void CardFrame::setViewMode(int mode)
{
if (currentIndex() != mode)
setCurrentIndex(mode);
switch (mode) {
case ImageOnlyView:
case TextOnlyView:
tab1Layout->addWidget(pic);
tab2Layout->addWidget(text);
break;
case ImageAndTextView:
splitter->addWidget(pic);
splitter->addWidget(text);
break;
default:
break;
}
SettingsCache::instance().setCardInfoViewMode(mode);
}
void CardFrame::setCard(CardInfoPtr card)
{
if (info) {
disconnect(info.data(), nullptr, this, nullptr);
}
info = std::move(card);
if (info) {
connect(info.data(), SIGNAL(destroyed()), this, SLOT(clearCard()));
}
text->setCard(info);
pic->setCard(info);
}
void CardFrame::setCard(const QString &cardName)
{
setCard(CardDatabaseManager::getInstance()->guessCard(cardName));
}
void CardFrame::setCard(AbstractCardItem *card)
{
if (card) {
setCard(card->getInfo());
}
}
void CardFrame::clearCard()
{
setCard((CardInfoPtr) nullptr);
}

View file

@ -1,44 +0,0 @@
#ifndef CARDFRAME_H
#define CARDFRAME_H
#include "card_database.h"
#include <QTabWidget>
class AbstractCardItem;
class CardInfoPicture;
class CardInfoText;
class QVBoxLayout;
class QSplitter;
class CardFrame : public QTabWidget
{
Q_OBJECT
private:
CardInfoPtr info;
CardInfoPicture *pic;
CardInfoText *text;
bool cardTextOnly;
QWidget *tab1, *tab2, *tab3;
QVBoxLayout *tab1Layout, *tab2Layout, *tab3Layout;
QSplitter *splitter;
public:
enum ViewMode
{
ImageOnlyView,
TextOnlyView,
ImageAndTextView
};
explicit CardFrame(const QString &cardName = QString(), QWidget *parent = nullptr);
void retranslateUi();
public slots:
void setCard(CardInfoPtr card);
void setCard(const QString &cardName);
void setCard(AbstractCardItem *card);
void clearCard();
void setViewMode(int mode);
};
#endif

View file

@ -1,66 +0,0 @@
#include "card_info_picture.h"
#include "../../client/ui/picture_loader.h"
#include "../../main.h"
#include "card_item.h"
#include <QStylePainter>
#include <QWidget>
CardInfoPicture::CardInfoPicture(QWidget *parent) : QWidget(parent), info(nullptr), pixmapDirty(true)
{
setMinimumHeight(100);
}
void CardInfoPicture::setCard(CardInfoPtr card)
{
if (info) {
disconnect(info.data(), nullptr, this, nullptr);
}
info = card;
if (info) {
connect(info.data(), SIGNAL(pixmapUpdated()), this, SLOT(updatePixmap()));
}
updatePixmap();
}
void CardInfoPicture::resizeEvent(QResizeEvent *)
{
updatePixmap();
}
void CardInfoPicture::updatePixmap()
{
pixmapDirty = true;
update();
}
void CardInfoPicture::loadPixmap()
{
if (info)
PictureLoader::getPixmap(resizedPixmap, info, size());
else
PictureLoader::getCardBackPixmap(resizedPixmap, size());
}
void CardInfoPicture::paintEvent(QPaintEvent *)
{
if (width() == 0 || height() == 0)
return;
if (pixmapDirty)
loadPixmap();
QSize scaledSize = resizedPixmap.size().scaled(size(), Qt::KeepAspectRatio);
QPoint topLeft{(width() - scaledSize.width()) / 2, (height() - scaledSize.height()) / 2};
qreal radius = 0.05 * scaledSize.width();
QStylePainter painter(this);
QPainterPath shape;
shape.addRoundedRect(QRect(topLeft, scaledSize), radius, radius);
painter.setClipPath(shape);
painter.drawItemPixmap(QRect(topLeft, scaledSize), Qt::AlignCenter, resizedPixmap);
}

View file

@ -1,31 +0,0 @@
#ifndef CARDINFOPICTURE_H
#define CARDINFOPICTURE_H
#include "card_database.h"
#include <QWidget>
class AbstractCardItem;
class CardInfoPicture : public QWidget
{
Q_OBJECT
private:
CardInfoPtr info;
QPixmap resizedPixmap;
bool pixmapDirty;
public:
CardInfoPicture(QWidget *parent = nullptr);
protected:
void resizeEvent(QResizeEvent *event);
void paintEvent(QPaintEvent *);
void loadPixmap();
public slots:
void setCard(CardInfoPtr card);
void updatePixmap();
};
#endif

View file

@ -1,81 +0,0 @@
#include "card_info_text.h"
#include "../../game/game_specific_terms.h"
#include "../../main.h"
#include "card_item.h"
#include <QGridLayout>
#include <QLabel>
#include <QTextEdit>
CardInfoText::CardInfoText(QWidget *parent) : QFrame(parent), info(nullptr)
{
nameLabel = new QLabel;
nameLabel->setOpenExternalLinks(false);
nameLabel->setWordWrap(true);
connect(nameLabel, SIGNAL(linkActivated(const QString &)), this, SIGNAL(linkActivated(const QString &)));
textLabel = new QTextEdit();
textLabel->setReadOnly(true);
auto *grid = new QGridLayout(this);
grid->addWidget(nameLabel, 0, 0);
grid->addWidget(textLabel, 1, 0, -1, 2);
grid->setRowStretch(1, 1);
grid->setColumnStretch(1, 1);
retranslateUi();
}
void CardInfoText::setCard(CardInfoPtr card)
{
if (card == nullptr) {
nameLabel->setText("");
textLabel->setText("");
return;
}
QString text = "<table width=\"100%\" border=0 cellspacing=0 cellpadding=0>";
text += QString("<tr><td>%1</td><td width=\"5\"></td><td>%2</td></tr>")
.arg(tr("Name:"), card->getName().toHtmlEscaped());
QStringList cardProps = card->getProperties();
for (const QString &key : cardProps) {
if (key.contains("-"))
continue;
QString keyText = Mtg::getNicePropertyName(key).toHtmlEscaped() + ":";
text +=
QString("<tr><td>%1</td><td></td><td>%2</td></tr>").arg(keyText, card->getProperty(key).toHtmlEscaped());
}
auto relatedCards = card->getAllRelatedCards();
if (!relatedCards.empty()) {
text += QString("<tr><td>%1</td><td width=\"5\"></td><td>").arg(tr("Related cards:"));
for (auto *relatedCard : relatedCards) {
QString tmp = relatedCard->getName().toHtmlEscaped();
text += "<a href=\"" + tmp + "\">" + tmp + "</a><br>";
}
text += "</td></tr>";
}
text += "</table>";
nameLabel->setText(text);
textLabel->setText(card->getText());
}
void CardInfoText::setInvalidCardName(const QString &cardName)
{
nameLabel->setText(tr("Unknown card:") + " " + cardName);
textLabel->setText("");
}
void CardInfoText::retranslateUi()
{
/*
* There's no way we can really translate the text currently being rendered.
* The best we can do is invalidate the current text.
*/
setInvalidCardName("");
}

View file

@ -1,30 +0,0 @@
#ifndef CARDINFOTEXT_H
#define CARDINFOTEXT_H
#include "card_database.h"
#include <QFrame>
class QLabel;
class QTextEdit;
class CardInfoText : public QFrame
{
Q_OBJECT
private:
QLabel *nameLabel;
QTextEdit *textLabel;
CardInfoPtr info;
public:
explicit CardInfoText(QWidget *parent = nullptr);
void retranslateUi();
void setInvalidCardName(const QString &cardName);
signals:
void linkActivated(const QString &link);
public slots:
void setCard(CardInfoPtr card);
};
#endif

View file

@ -1,74 +0,0 @@
#include "card_info_widget.h"
#include "../../main.h"
#include "card_database_manager.h"
#include "card_info_picture.h"
#include "card_info_text.h"
#include "card_item.h"
#include <QApplication>
#include <QScreen>
#include <QVBoxLayout>
#include <utility>
CardInfoWidget::CardInfoWidget(const QString &cardName, QWidget *parent, Qt::WindowFlags flags)
: QFrame(parent, flags), aspectRatio((qreal)CARD_HEIGHT / (qreal)CARD_WIDTH), info(nullptr)
{
setContentsMargins(3, 3, 3, 3);
pic = new CardInfoPicture();
pic->setObjectName("pic");
text = new CardInfoText();
text->setObjectName("text");
connect(text, SIGNAL(linkActivated(const QString &)), this, SLOT(setCard(const QString &)));
auto *layout = new QVBoxLayout();
layout->setObjectName("layout");
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);
layout->addWidget(pic, 0, Qt::AlignCenter);
layout->addWidget(text, 0, Qt::AlignCenter);
setLayout(layout);
setFrameStyle(QFrame::Panel | QFrame::Raised);
int pixmapHeight = QGuiApplication::primaryScreen()->geometry().height() / 3;
int pixmapWidth = static_cast<int>(pixmapHeight / aspectRatio);
pic->setFixedWidth(pixmapWidth);
pic->setFixedHeight(pixmapHeight);
setFixedWidth(pixmapWidth + 150);
setCard(cardName);
// ensure our parent gets a valid size to position us correctly
resize(width(), sizeHint().height());
}
void CardInfoWidget::setCard(CardInfoPtr card)
{
if (info)
disconnect(info.data(), nullptr, this, nullptr);
info = std::move(card);
if (info)
connect(info.data(), SIGNAL(destroyed()), this, SLOT(clear()));
text->setCard(info);
pic->setCard(info);
}
void CardInfoWidget::setCard(const QString &cardName)
{
setCard(CardDatabaseManager::getInstance()->guessCard(cardName));
if (info == nullptr) {
text->setInvalidCardName(cardName);
}
}
void CardInfoWidget::setCard(AbstractCardItem *card)
{
setCard(card->getInfo());
}
void CardInfoWidget::clear()
{
setCard((CardInfoPtr) nullptr);
}

View file

@ -1,36 +0,0 @@
#ifndef CARDINFOWIDGET_H
#define CARDINFOWIDGET_H
#include "card_database.h"
#include <QComboBox>
#include <QFrame>
#include <QStringList>
class CardInfoPicture;
class CardInfoText;
class AbstractCardItem;
class CardInfoWidget : public QFrame
{
Q_OBJECT
private:
qreal aspectRatio;
CardInfoPtr info;
CardInfoPicture *pic;
CardInfoText *text;
public:
explicit CardInfoWidget(const QString &cardName, QWidget *parent = nullptr, Qt::WindowFlags f = {});
public slots:
void setCard(CardInfoPtr card);
void setCard(const QString &cardName);
void setCard(AbstractCardItem *card);
private slots:
void clear();
};
#endif