mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-06-14 19:18:55 -07:00
* move message_log_widget to game * move files * update headers * fix cmakelists * oracle fixes * split implementation out to cpp * fix recursive import * fix main file * format
This commit is contained in:
parent
f484c98152
commit
17dcaf9afa
337 changed files with 728 additions and 721 deletions
|
|
@ -0,0 +1,125 @@
|
|||
#include "color_identity_widget.h"
|
||||
|
||||
#include "../../../../settings/cache_settings.h"
|
||||
#include "mana_symbol_widget.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QPixmap>
|
||||
#include <QRegularExpression>
|
||||
#include <QResizeEvent>
|
||||
#include <QSize>
|
||||
|
||||
ColorIdentityWidget::ColorIdentityWidget(QWidget *parent, CardInfoPtr _card) : QWidget(parent), card(_card)
|
||||
{
|
||||
layout = new QHBoxLayout(this);
|
||||
layout->setSpacing(5); // Small spacing between icons
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setAlignment(Qt::AlignCenter); // Ensure icons are centered
|
||||
setLayout(layout);
|
||||
|
||||
// Define the full WUBRG set (White, Blue, Black, Red, Green)
|
||||
QString fullColorIdentity = "WUBRG";
|
||||
|
||||
if (card) {
|
||||
manaCost = card->getColors(); // Get mana cost string
|
||||
QStringList symbols = parseColorIdentity(manaCost); // Parse mana cost string
|
||||
|
||||
populateManaSymbolWidgets();
|
||||
}
|
||||
connect(&SettingsCache::instance(), &SettingsCache::visualDeckStorageDrawUnusedColorIdentitiesChanged, this,
|
||||
&ColorIdentityWidget::toggleUnusedVisibility);
|
||||
}
|
||||
|
||||
ColorIdentityWidget::ColorIdentityWidget(QWidget *parent, QString _manaCost)
|
||||
: QWidget(parent), card(nullptr), manaCost(_manaCost)
|
||||
{
|
||||
layout = new QHBoxLayout(this);
|
||||
layout->setSpacing(5); // Small spacing between icons
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setAlignment(Qt::AlignCenter); // Ensure icons are centered
|
||||
setLayout(layout);
|
||||
|
||||
populateManaSymbolWidgets();
|
||||
|
||||
connect(&SettingsCache::instance(), &SettingsCache::visualDeckStorageDrawUnusedColorIdentitiesChanged, this,
|
||||
&ColorIdentityWidget::toggleUnusedVisibility);
|
||||
}
|
||||
|
||||
void ColorIdentityWidget::populateManaSymbolWidgets()
|
||||
{
|
||||
// Define the full WUBRG set (White, Blue, Black, Red, Green)
|
||||
QString fullColorIdentity = "WUBRG";
|
||||
QStringList symbols = parseColorIdentity(manaCost); // Parse mana cost string
|
||||
|
||||
if (SettingsCache::instance().getVisualDeckStorageDrawUnusedColorIdentities()) {
|
||||
for (const QString symbol : fullColorIdentity) {
|
||||
auto *manaSymbol = new ManaSymbolWidget(this, symbol, symbols.contains(symbol));
|
||||
layout->addWidget(manaSymbol);
|
||||
}
|
||||
} else {
|
||||
for (const QString &symbol : symbols) {
|
||||
auto *manaSymbol = new ManaSymbolWidget(this, symbol, symbols.contains(symbol));
|
||||
layout->addWidget(manaSymbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ColorIdentityWidget::toggleUnusedVisibility()
|
||||
{
|
||||
if (layout != nullptr) {
|
||||
QLayoutItem *item;
|
||||
while ((item = layout->takeAt(0)) != nullptr) {
|
||||
item->widget()->deleteLater(); // Delete the widget
|
||||
delete item; // Delete the layout item
|
||||
}
|
||||
}
|
||||
populateManaSymbolWidgets();
|
||||
}
|
||||
|
||||
void ColorIdentityWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
QList<ManaSymbolWidget *> manaSymbols = findChildren<ManaSymbolWidget *>();
|
||||
|
||||
if (!manaSymbols.isEmpty()) {
|
||||
int totalWidth = event->size().width();
|
||||
int totalHeight = totalWidth / 6; // Set height to 1/4 of the width
|
||||
setFixedHeight(totalHeight);
|
||||
|
||||
int spacing = layout->spacing();
|
||||
int count = manaSymbols.size();
|
||||
int availableWidth = totalWidth - (spacing * (count - 1));
|
||||
int iconSize = qMin(availableWidth / count, totalHeight); // Ensure icons fit within the new height
|
||||
|
||||
for (ManaSymbolWidget *manaSymbol : manaSymbols) {
|
||||
manaSymbol->setFixedSize(iconSize, iconSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QStringList ColorIdentityWidget::parseColorIdentity(const QString &cmc)
|
||||
{
|
||||
QStringList symbols;
|
||||
|
||||
// Handle split costs (e.g., "3U // 4UU")
|
||||
QStringList splitCosts = cmc.split(" // ");
|
||||
for (const QString &part : splitCosts) {
|
||||
QRegularExpression regex(R"(\{([^}]+)\}|(\d+)|([WUBRGCSPX]))");
|
||||
QRegularExpressionMatchIterator matches = regex.globalMatch(part);
|
||||
while (matches.hasNext()) {
|
||||
QRegularExpressionMatch match = matches.next();
|
||||
if (match.captured(1).isEmpty()) { // If no `{}` group was captured, check other groups
|
||||
if (!match.captured(2).isEmpty()) {
|
||||
symbols.append(match.captured(2)); // Number match
|
||||
} else {
|
||||
symbols.append(match.captured(3)); // Single mana letter match
|
||||
}
|
||||
} else {
|
||||
symbols.append(match.captured(1)); // `{}` enclosed match
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return symbols;
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef COLOR_IDENTITY_WIDGET_H
|
||||
#define COLOR_IDENTITY_WIDGET_H
|
||||
|
||||
#include "../../../../card/card_info.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
class ColorIdentityWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ColorIdentityWidget(QWidget *parent, CardInfoPtr card);
|
||||
explicit ColorIdentityWidget(QWidget *parent, QString manaCost);
|
||||
void populateManaSymbolWidgets();
|
||||
|
||||
QStringList parseColorIdentity(const QString &manaString);
|
||||
|
||||
public slots:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
void toggleUnusedVisibility();
|
||||
|
||||
private:
|
||||
CardInfoPtr card;
|
||||
QString manaCost;
|
||||
QHBoxLayout *layout;
|
||||
};
|
||||
|
||||
#endif // COLOR_IDENTITY_WIDGET_H
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
#include "mana_cost_widget.h"
|
||||
|
||||
#include "mana_symbol_widget.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QPixmap>
|
||||
#include <QResizeEvent>
|
||||
#include <QSize>
|
||||
#include <qregularexpression.h>
|
||||
|
||||
ManaCostWidget::ManaCostWidget(QWidget *parent, CardInfoPtr _card) : QWidget(parent), card(_card)
|
||||
{
|
||||
layout = new QHBoxLayout(this);
|
||||
layout->setSpacing(5); // Small spacing between icons
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
setLayout(layout);
|
||||
|
||||
setFixedHeight(50); // Fixed height
|
||||
|
||||
if (card) {
|
||||
QString manaCost = card->getManaCost(); // Get mana cost string
|
||||
QStringList symbols = parseManaCost(manaCost); // Parse mana cost string
|
||||
|
||||
for (const QString &symbol : symbols) {
|
||||
ManaSymbolWidget *manaSymbol = new ManaSymbolWidget(this, symbol, true, false);
|
||||
layout->addWidget(manaSymbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ManaCostWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
QList<ManaSymbolWidget *> manaSymbols = findChildren<ManaSymbolWidget *>();
|
||||
|
||||
if (!manaSymbols.isEmpty()) {
|
||||
int totalWidth = event->size().width();
|
||||
int spacing = layout->spacing();
|
||||
int count = manaSymbols.size();
|
||||
|
||||
// Available width minus total spacing
|
||||
int availableWidth = totalWidth - (spacing * (count - 1));
|
||||
int iconSize = qMin(50, availableWidth / count);
|
||||
|
||||
for (ManaSymbolWidget *manaSymbol : manaSymbols) {
|
||||
manaSymbol->setFixedSize(iconSize, iconSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QStringList ManaCostWidget::parseManaCost(const QString &cmc)
|
||||
{
|
||||
QStringList symbols;
|
||||
|
||||
// Handle split costs (e.g., "3U // 4UU")
|
||||
QStringList splitCosts = cmc.split(" // ");
|
||||
for (const QString &part : splitCosts) {
|
||||
QRegularExpression regex(R"(\{([^}]+)\}|(\d+)|([WUBRGCSPX]))");
|
||||
QRegularExpressionMatchIterator matches = regex.globalMatch(part);
|
||||
while (matches.hasNext()) {
|
||||
QRegularExpressionMatch match = matches.next();
|
||||
if (match.captured(1).isEmpty()) { // If no `{}` group was captured, check other groups
|
||||
if (!match.captured(2).isEmpty()) {
|
||||
symbols.append(match.captured(2)); // Number match
|
||||
} else {
|
||||
symbols.append(match.captured(3)); // Single mana letter match
|
||||
}
|
||||
} else {
|
||||
symbols.append(match.captured(1)); // `{}` enclosed match
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return symbols;
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef MANA_COST_WIDGET_H
|
||||
#define MANA_COST_WIDGET_H
|
||||
|
||||
#include "../../../../card/card_info.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
class ManaCostWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ManaCostWidget(QWidget *parent, CardInfoPtr card);
|
||||
|
||||
QStringList parseManaCost(const QString &manaString);
|
||||
public slots:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
private:
|
||||
CardInfoPtr card;
|
||||
QHBoxLayout *layout;
|
||||
};
|
||||
|
||||
#endif // MANA_COST_WIDGET_H
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
#include "mana_symbol_widget.h"
|
||||
|
||||
#include "../../../../settings/cache_settings.h"
|
||||
|
||||
#include <QResizeEvent>
|
||||
|
||||
ManaSymbolWidget::ManaSymbolWidget(QWidget *parent, QString _symbol, bool _isActive, bool _mayBeToggled)
|
||||
: QLabel(parent), symbol(_symbol), isActive(_isActive), mayBeToggled(_mayBeToggled)
|
||||
{
|
||||
loadManaIcon();
|
||||
setPixmap(manaIcon.scaled(50, 50, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
setMaximumWidth(50);
|
||||
|
||||
// Initialize opacity effect
|
||||
opacityEffect = new QGraphicsOpacityEffect(this);
|
||||
setGraphicsEffect(opacityEffect);
|
||||
updateOpacity();
|
||||
|
||||
connect(&SettingsCache::instance(), &SettingsCache::visualDeckStorageUnusedColorIdentitiesOpacityChanged, this,
|
||||
&ManaSymbolWidget::updateOpacity);
|
||||
}
|
||||
|
||||
void ManaSymbolWidget::toggleSymbol()
|
||||
{
|
||||
setColorActive(!isActive);
|
||||
emit colorToggled(getSymbolChar(), isActive);
|
||||
}
|
||||
|
||||
void ManaSymbolWidget::setColorActive(bool active)
|
||||
{
|
||||
if (isActive != active) {
|
||||
isActive = active;
|
||||
updateOpacity();
|
||||
}
|
||||
}
|
||||
|
||||
void ManaSymbolWidget::updateOpacity()
|
||||
{
|
||||
qreal opacity;
|
||||
if (mayBeToggled) {
|
||||
// UI elements that users can click on shouldn't be transparent.
|
||||
opacity = isActive ? 1.0 : 0.5;
|
||||
} else {
|
||||
// It's just for display, they can do whatever they want.
|
||||
opacity = isActive ? 1.0 : SettingsCache::instance().getVisualDeckStorageUnusedColorIdentitiesOpacity() / 100.0;
|
||||
}
|
||||
opacityEffect->setOpacity(opacity);
|
||||
}
|
||||
|
||||
void ManaSymbolWidget::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
if (mayBeToggled) {
|
||||
toggleSymbol();
|
||||
}
|
||||
}
|
||||
|
||||
void ManaSymbolWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QLabel::resizeEvent(event);
|
||||
setPixmap(manaIcon.scaled(event->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
}
|
||||
|
||||
void ManaSymbolWidget::loadManaIcon()
|
||||
{
|
||||
QString filename = "theme:icons/mana/";
|
||||
|
||||
if (symbol == "W" || symbol == "U" || symbol == "B" || symbol == "R" || symbol == "G") {
|
||||
filename += symbol;
|
||||
}
|
||||
|
||||
manaIcon = QPixmap(filename);
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef MANA_SYMBOL_WIDGET_H
|
||||
#define MANA_SYMBOL_WIDGET_H
|
||||
|
||||
#include <QGraphicsOpacityEffect>
|
||||
#include <QLabel>
|
||||
|
||||
class ManaSymbolWidget : public QLabel
|
||||
{
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ManaSymbolWidget(QWidget *parent, QString symbol, bool isActive = true, bool mayBeToggled = false);
|
||||
void toggleSymbol();
|
||||
void setColorActive(bool active);
|
||||
void updateOpacity();
|
||||
bool isColorActive() const
|
||||
{
|
||||
return isActive;
|
||||
};
|
||||
QString getSymbol() const
|
||||
{
|
||||
return symbol;
|
||||
};
|
||||
QChar getSymbolChar() const
|
||||
{
|
||||
return symbol[0];
|
||||
};
|
||||
|
||||
void loadManaIcon();
|
||||
|
||||
public slots:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
|
||||
signals:
|
||||
void colorToggled(QChar symbol, bool isActive);
|
||||
|
||||
private:
|
||||
QString symbol;
|
||||
QPixmap manaIcon;
|
||||
bool isActive;
|
||||
bool mayBeToggled;
|
||||
QGraphicsOpacityEffect *opacityEffect;
|
||||
};
|
||||
|
||||
#endif // MANA_SYMBOL_WIDGET_H
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
#include "card_group_display_widget.h"
|
||||
|
||||
#include "../../../../database/card_database_manager.h"
|
||||
#include "../../../../deck/deck_list_model.h"
|
||||
#include "../../../../utility/card_info_comparator.h"
|
||||
#include "../../../../utility/deck_list_sort_filter_proxy_model.h"
|
||||
#include "../card_info_picture_with_text_overlay_widget.h"
|
||||
|
||||
#include <QResizeEvent>
|
||||
|
||||
CardGroupDisplayWidget::CardGroupDisplayWidget(QWidget *parent,
|
||||
DeckListModel *_deckListModel,
|
||||
QPersistentModelIndex _trackedIndex,
|
||||
QString _zoneName,
|
||||
QString _cardGroupCategory,
|
||||
QString _activeGroupCriteria,
|
||||
QStringList _activeSortCriteria,
|
||||
int bannerOpacity,
|
||||
CardSizeWidget *_cardSizeWidget)
|
||||
: QWidget(parent), deckListModel(_deckListModel), trackedIndex(_trackedIndex), zoneName(_zoneName),
|
||||
cardGroupCategory(_cardGroupCategory), activeGroupCriteria(_activeGroupCriteria),
|
||||
activeSortCriteria(_activeSortCriteria), cardSizeWidget(_cardSizeWidget)
|
||||
{
|
||||
layout = new QVBoxLayout(this);
|
||||
setLayout(layout);
|
||||
setMinimumSize(QSize(0, 0));
|
||||
|
||||
banner = new BannerWidget(this, cardGroupCategory, Qt::Orientation::Vertical, bannerOpacity);
|
||||
|
||||
layout->addWidget(banner);
|
||||
|
||||
CardGroupDisplayWidget::updateCardDisplays();
|
||||
|
||||
connect(deckListModel, &QAbstractItemModel::rowsInserted, this, &CardGroupDisplayWidget::onCardAddition);
|
||||
connect(deckListModel, &QAbstractItemModel::rowsRemoved, this, &CardGroupDisplayWidget::onCardRemoval);
|
||||
}
|
||||
|
||||
void CardGroupDisplayWidget::clearAllDisplayWidgets()
|
||||
{
|
||||
for (auto idx : indexToWidgetMap.keys()) {
|
||||
auto displayWidget = indexToWidgetMap.value(idx);
|
||||
removeFromLayout(displayWidget);
|
||||
indexToWidgetMap.remove(idx);
|
||||
delete displayWidget;
|
||||
}
|
||||
}
|
||||
|
||||
QWidget *CardGroupDisplayWidget::constructWidgetForIndex(QPersistentModelIndex index)
|
||||
{
|
||||
if (indexToWidgetMap.contains(index)) {
|
||||
return indexToWidgetMap[index];
|
||||
}
|
||||
auto cardName = deckListModel->data(index.sibling(index.row(), 1), Qt::EditRole).toString();
|
||||
auto cardProviderId = deckListModel->data(index.sibling(index.row(), 4), Qt::EditRole).toString();
|
||||
|
||||
auto widget = new CardInfoPictureWithTextOverlayWidget(getLayoutParent(), true);
|
||||
widget->setScaleFactor(cardSizeWidget->getSlider()->value());
|
||||
widget->setCard(CardDatabaseManager::getInstance()->getCard({cardName, cardProviderId}));
|
||||
|
||||
connect(widget, &CardInfoPictureWithTextOverlayWidget::imageClicked, this, &CardGroupDisplayWidget::onClick);
|
||||
connect(widget, &CardInfoPictureWithTextOverlayWidget::hoveredOnCard, this, &CardGroupDisplayWidget::onHover);
|
||||
connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, widget, &CardInfoPictureWidget::setScaleFactor);
|
||||
|
||||
indexToWidgetMap.insert(index, widget);
|
||||
return widget;
|
||||
}
|
||||
|
||||
void CardGroupDisplayWidget::updateCardDisplays()
|
||||
{
|
||||
DeckListSortFilterProxyModel proxy;
|
||||
proxy.setSourceModel(deckListModel);
|
||||
proxy.setSortCriteria(activeSortCriteria);
|
||||
|
||||
// This doesn't really matter since overwrite the whole lessThan function to just compare dynamically anyway.
|
||||
proxy.setSortRole(Qt::EditRole);
|
||||
proxy.sort(1, Qt::AscendingOrder);
|
||||
|
||||
// 1. trackedIndex is a source index → map it to proxy space
|
||||
QModelIndex proxyParent = proxy.mapFromSource(trackedIndex);
|
||||
|
||||
// 2. iterate children under the proxy parent
|
||||
for (int i = 0; i < proxy.rowCount(proxyParent); ++i) {
|
||||
QModelIndex proxyIndex = proxy.index(i, 0, proxyParent);
|
||||
|
||||
// 3. map back to source
|
||||
QModelIndex sourceIndex = proxy.mapToSource(proxyIndex);
|
||||
|
||||
// 4. persist the source index
|
||||
QPersistentModelIndex persistent(sourceIndex);
|
||||
|
||||
addToLayout(constructWidgetForIndex(persistent));
|
||||
}
|
||||
}
|
||||
|
||||
void CardGroupDisplayWidget::onCardAddition(const QModelIndex &parent, int first, int last)
|
||||
{
|
||||
if (!trackedIndex.isValid()) {
|
||||
emit cleanupRequested(this);
|
||||
return;
|
||||
}
|
||||
|
||||
if (parent == trackedIndex) {
|
||||
for (int row = first; row <= last; ++row) {
|
||||
QModelIndex child = deckListModel->index(row, 0, parent);
|
||||
|
||||
// Persist the index
|
||||
QPersistentModelIndex persistent(child);
|
||||
|
||||
insertIntoLayout(constructWidgetForIndex(persistent), row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CardGroupDisplayWidget::onCardRemoval(const QModelIndex &parent, int first, int last)
|
||||
{
|
||||
Q_UNUSED(first);
|
||||
Q_UNUSED(last);
|
||||
if (parent == trackedIndex) {
|
||||
for (const QPersistentModelIndex &idx : indexToWidgetMap.keys()) {
|
||||
if (!idx.isValid()) {
|
||||
removeFromLayout(indexToWidgetMap.value(idx));
|
||||
indexToWidgetMap.value(idx)->deleteLater();
|
||||
indexToWidgetMap.remove(idx);
|
||||
}
|
||||
}
|
||||
|
||||
if (!trackedIndex.isValid()) {
|
||||
emit cleanupRequested(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CardGroupDisplayWidget::onActiveSortCriteriaChanged(QStringList _activeSortCriteria)
|
||||
{
|
||||
activeSortCriteria = std::move(_activeSortCriteria);
|
||||
|
||||
clearAllDisplayWidgets();
|
||||
updateCardDisplays();
|
||||
}
|
||||
|
||||
void CardGroupDisplayWidget::onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card)
|
||||
{
|
||||
emit cardClicked(event, card);
|
||||
}
|
||||
|
||||
void CardGroupDisplayWidget::onHover(const ExactCard &card)
|
||||
{
|
||||
emit cardHovered(card);
|
||||
}
|
||||
|
||||
void CardGroupDisplayWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
#ifndef CARD_GROUP_DISPLAY_WIDGET_H
|
||||
#define CARD_GROUP_DISPLAY_WIDGET_H
|
||||
|
||||
#include "../../../../card/card_info.h"
|
||||
#include "../../../../deck/deck_list_model.h"
|
||||
#include "../../general/display/banner_widget.h"
|
||||
#include "../card_info_picture_with_text_overlay_widget.h"
|
||||
#include "../card_size_widget.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
class CardGroupDisplayWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CardGroupDisplayWidget(QWidget *parent,
|
||||
DeckListModel *deckListModel,
|
||||
QPersistentModelIndex trackedIndex,
|
||||
QString zoneName,
|
||||
QString cardGroupCategory,
|
||||
QString activeGroupCriteria,
|
||||
QStringList activeSortCriteria,
|
||||
int bannerOpacity,
|
||||
CardSizeWidget *cardSizeWidget);
|
||||
void clearAllDisplayWidgets();
|
||||
|
||||
DeckListModel *deckListModel;
|
||||
QPersistentModelIndex trackedIndex;
|
||||
QHash<QPersistentModelIndex, QWidget *> indexToWidgetMap;
|
||||
QString zoneName;
|
||||
QString cardGroupCategory;
|
||||
QString activeGroupCriteria;
|
||||
QStringList activeSortCriteria;
|
||||
CardSizeWidget *cardSizeWidget;
|
||||
|
||||
public slots:
|
||||
void onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card);
|
||||
void onHover(const ExactCard &card);
|
||||
virtual QWidget *constructWidgetForIndex(QPersistentModelIndex index);
|
||||
virtual void updateCardDisplays();
|
||||
virtual void onCardAddition(const QModelIndex &parent, int first, int last);
|
||||
virtual void onCardRemoval(const QModelIndex &parent, int first, int last);
|
||||
void onActiveSortCriteriaChanged(QStringList activeSortCriteria);
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
signals:
|
||||
void cardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card);
|
||||
void cardHovered(const ExactCard &card);
|
||||
void cleanupRequested(CardGroupDisplayWidget *cardGroupDisplayWidget);
|
||||
|
||||
protected:
|
||||
QVBoxLayout *layout;
|
||||
BannerWidget *banner;
|
||||
|
||||
virtual QWidget *getLayoutParent()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
virtual void addToLayout(QWidget *toAdd)
|
||||
{
|
||||
layout->addWidget(toAdd);
|
||||
}
|
||||
|
||||
virtual void insertIntoLayout(QWidget *toInsert, int insertAt)
|
||||
{
|
||||
layout->insertWidget(insertAt, toInsert);
|
||||
}
|
||||
|
||||
virtual void removeFromLayout(QWidget *toRemove)
|
||||
{
|
||||
layout->removeWidget(toRemove);
|
||||
}
|
||||
};
|
||||
#endif // CARD_GROUP_DISPLAY_WIDGET_H
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
#include "flat_card_group_display_widget.h"
|
||||
|
||||
#include "../../../../database/card_database_manager.h"
|
||||
#include "../../../../deck/deck_list_model.h"
|
||||
#include "../../../../utility/card_info_comparator.h"
|
||||
#include "../card_info_picture_with_text_overlay_widget.h"
|
||||
|
||||
#include <QResizeEvent>
|
||||
#include <utility>
|
||||
|
||||
FlatCardGroupDisplayWidget::FlatCardGroupDisplayWidget(QWidget *parent,
|
||||
DeckListModel *_deckListModel,
|
||||
QPersistentModelIndex _trackedIndex,
|
||||
QString _zoneName,
|
||||
QString _cardGroupCategory,
|
||||
QString _activeGroupCriteria,
|
||||
QStringList _activeSortCriteria,
|
||||
int bannerOpacity,
|
||||
CardSizeWidget *_cardSizeWidget)
|
||||
: CardGroupDisplayWidget(parent,
|
||||
_deckListModel,
|
||||
std::move(_trackedIndex),
|
||||
_zoneName,
|
||||
_cardGroupCategory,
|
||||
_activeGroupCriteria,
|
||||
_activeSortCriteria,
|
||||
bannerOpacity,
|
||||
_cardSizeWidget)
|
||||
{
|
||||
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAlwaysOff);
|
||||
banner->setBuddy(flowWidget);
|
||||
|
||||
layout->addWidget(flowWidget);
|
||||
|
||||
for (const QPersistentModelIndex &idx : indexToWidgetMap.keys()) {
|
||||
FlatCardGroupDisplayWidget::removeFromLayout(indexToWidgetMap.value(idx));
|
||||
indexToWidgetMap.value(idx)->deleteLater();
|
||||
indexToWidgetMap.remove(idx);
|
||||
}
|
||||
|
||||
FlatCardGroupDisplayWidget::updateCardDisplays();
|
||||
disconnect(deckListModel, &QAbstractItemModel::rowsInserted, this, &CardGroupDisplayWidget::onCardAddition);
|
||||
disconnect(deckListModel, &QAbstractItemModel::rowsRemoved, this, &CardGroupDisplayWidget::onCardRemoval);
|
||||
|
||||
connect(deckListModel, &QAbstractItemModel::rowsInserted, this, &FlatCardGroupDisplayWidget::onCardAddition);
|
||||
connect(deckListModel, &QAbstractItemModel::rowsRemoved, this, &FlatCardGroupDisplayWidget::onCardRemoval);
|
||||
}
|
||||
|
||||
void FlatCardGroupDisplayWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
#ifndef FLAT_CARD_GROUP_DISPLAY_WIDGET_H
|
||||
#define FLAT_CARD_GROUP_DISPLAY_WIDGET_H
|
||||
|
||||
#include "../../general/layout_containers/flow_widget.h"
|
||||
#include "card_group_display_widget.h"
|
||||
|
||||
class FlatCardGroupDisplayWidget : public CardGroupDisplayWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FlatCardGroupDisplayWidget(QWidget *parent,
|
||||
DeckListModel *deckListModel,
|
||||
QPersistentModelIndex trackedIndex,
|
||||
QString zoneName,
|
||||
QString cardGroupCategory,
|
||||
QString activeGroupCriteria,
|
||||
QStringList activeSortCriteria,
|
||||
int bannerOpacity,
|
||||
CardSizeWidget *cardSizeWidget);
|
||||
|
||||
public slots:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
private:
|
||||
FlowWidget *flowWidget;
|
||||
|
||||
QWidget *getLayoutParent() override
|
||||
{
|
||||
return flowWidget;
|
||||
}
|
||||
|
||||
void addToLayout(QWidget *toAdd) override
|
||||
{
|
||||
flowWidget->addWidget(toAdd);
|
||||
}
|
||||
|
||||
void insertIntoLayout(QWidget *toInsert, int insertAt) override
|
||||
{
|
||||
flowWidget->insertWidgetAtIndex(toInsert, insertAt);
|
||||
}
|
||||
|
||||
void removeFromLayout(QWidget *toRemove) override
|
||||
{
|
||||
flowWidget->removeWidget(toRemove);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // FLAT_CARD_GROUP_DISPLAY_WIDGET_H
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
#include "overlapped_card_group_display_widget.h"
|
||||
|
||||
#include "../../../../database/card_database_manager.h"
|
||||
#include "../../../../deck/deck_list_model.h"
|
||||
#include "../../../../utility/card_info_comparator.h"
|
||||
#include "../card_info_picture_with_text_overlay_widget.h"
|
||||
|
||||
#include <QResizeEvent>
|
||||
|
||||
OverlappedCardGroupDisplayWidget::OverlappedCardGroupDisplayWidget(QWidget *parent,
|
||||
DeckListModel *_deckListModel,
|
||||
QPersistentModelIndex _trackedIndex,
|
||||
QString _zoneName,
|
||||
QString _cardGroupCategory,
|
||||
QString _activeGroupCriteria,
|
||||
QStringList _activeSortCriteria,
|
||||
int bannerOpacity,
|
||||
CardSizeWidget *_cardSizeWidget)
|
||||
: CardGroupDisplayWidget(parent,
|
||||
_deckListModel,
|
||||
_trackedIndex,
|
||||
_zoneName,
|
||||
_cardGroupCategory,
|
||||
_activeGroupCriteria,
|
||||
_activeSortCriteria,
|
||||
bannerOpacity,
|
||||
_cardSizeWidget)
|
||||
{
|
||||
overlapWidget = new OverlapWidget(this, 80, 1, 1, Qt::Vertical, true);
|
||||
banner->setBuddy(overlapWidget);
|
||||
|
||||
layout->addWidget(overlapWidget);
|
||||
|
||||
for (const QPersistentModelIndex &idx : indexToWidgetMap.keys()) {
|
||||
OverlappedCardGroupDisplayWidget::removeFromLayout(indexToWidgetMap.value(idx));
|
||||
indexToWidgetMap.value(idx)->deleteLater();
|
||||
indexToWidgetMap.remove(idx);
|
||||
}
|
||||
|
||||
OverlappedCardGroupDisplayWidget::updateCardDisplays();
|
||||
|
||||
connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, this,
|
||||
[this]() { overlapWidget->adjustMaxColumnsAndRows(); });
|
||||
|
||||
disconnect(deckListModel, &QAbstractItemModel::rowsInserted, this, &CardGroupDisplayWidget::onCardAddition);
|
||||
disconnect(deckListModel, &QAbstractItemModel::rowsRemoved, this, &CardGroupDisplayWidget::onCardRemoval);
|
||||
|
||||
connect(deckListModel, &QAbstractItemModel::rowsInserted, this, &OverlappedCardGroupDisplayWidget::onCardAddition);
|
||||
connect(deckListModel, &QAbstractItemModel::rowsRemoved, this, &OverlappedCardGroupDisplayWidget::onCardRemoval);
|
||||
}
|
||||
|
||||
void OverlappedCardGroupDisplayWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
|
||||
overlapWidget->resize(event->size());
|
||||
overlapWidget->adjustMaxColumnsAndRows();
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
#ifndef OVERLAPPED_CARD_GROUP_DISPLAY_WIDGET_H
|
||||
#define OVERLAPPED_CARD_GROUP_DISPLAY_WIDGET_H
|
||||
|
||||
#include "../../general/layout_containers/overlap_widget.h"
|
||||
#include "card_group_display_widget.h"
|
||||
|
||||
class OverlappedCardGroupDisplayWidget : public CardGroupDisplayWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
OverlappedCardGroupDisplayWidget(QWidget *parent,
|
||||
DeckListModel *deckListModel,
|
||||
QPersistentModelIndex trackedIndex,
|
||||
QString zoneName,
|
||||
QString cardGroupCategory,
|
||||
QString activeGroupCriteria,
|
||||
QStringList activeSortCriteria,
|
||||
int bannerOpacity,
|
||||
CardSizeWidget *cardSizeWidget);
|
||||
|
||||
public slots:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
private:
|
||||
OverlapWidget *overlapWidget;
|
||||
|
||||
QWidget *getLayoutParent() override
|
||||
{
|
||||
return overlapWidget;
|
||||
}
|
||||
|
||||
void addToLayout(QWidget *toAdd) override
|
||||
{
|
||||
overlapWidget->addWidget(toAdd);
|
||||
}
|
||||
|
||||
void insertIntoLayout(QWidget *toInsert, int insertAt) override
|
||||
{
|
||||
overlapWidget->insertWidgetAtIndex(toInsert, insertAt);
|
||||
}
|
||||
|
||||
void removeFromLayout(QWidget *toRemove) override
|
||||
{
|
||||
overlapWidget->removeWidget(toRemove);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // OVERLAPPED_CARD_GROUP_DISPLAY_WIDGET_H
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
#include "card_info_display_widget.h"
|
||||
|
||||
#include "../../../database/card_database_manager.h"
|
||||
#include "../../../game/board/card_item.h"
|
||||
#include "../../../main.h"
|
||||
#include "card_info_picture_widget.h"
|
||||
#include "card_info_text_widget.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QScreen>
|
||||
#include <QVBoxLayout>
|
||||
#include <utility>
|
||||
|
||||
CardInfoDisplayWidget::CardInfoDisplayWidget(const CardRef &cardRef, QWidget *parent, Qt::WindowFlags flags)
|
||||
: QFrame(parent, flags), aspectRatio((qreal)CARD_HEIGHT / (qreal)CARD_WIDTH)
|
||||
{
|
||||
setContentsMargins(3, 3, 3, 3);
|
||||
pic = new CardInfoPictureWidget();
|
||||
pic->setObjectName("pic");
|
||||
text = new CardInfoTextWidget();
|
||||
text->setObjectName("text");
|
||||
connect(text, &CardInfoTextWidget::linkActivated, this, [this](const QString &card) { setCard({card}); });
|
||||
|
||||
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(cardRef);
|
||||
|
||||
// ensure our parent gets a valid size to position us correctly
|
||||
resize(width(), sizeHint().height());
|
||||
}
|
||||
|
||||
void CardInfoDisplayWidget::setCard(const ExactCard &card)
|
||||
{
|
||||
if (exactCard)
|
||||
disconnect(exactCard.getCardPtr().data(), nullptr, this, nullptr);
|
||||
exactCard = card;
|
||||
if (exactCard)
|
||||
connect(exactCard.getCardPtr().data(), &QObject::destroyed, this, &CardInfoDisplayWidget::clear);
|
||||
|
||||
text->setCard(exactCard.getCardPtr());
|
||||
pic->setCard(exactCard);
|
||||
}
|
||||
|
||||
void CardInfoDisplayWidget::setCard(const CardRef &cardRef)
|
||||
{
|
||||
setCard(CardDatabaseManager::getInstance()->guessCard(cardRef));
|
||||
if (exactCard.isEmpty()) {
|
||||
text->setInvalidCardName(cardRef.name);
|
||||
}
|
||||
}
|
||||
|
||||
void CardInfoDisplayWidget::setCard(AbstractCardItem *card)
|
||||
{
|
||||
setCard(card->getCard());
|
||||
}
|
||||
|
||||
void CardInfoDisplayWidget::clear()
|
||||
{
|
||||
setCard(ExactCard());
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef CARDINFOWIDGET_H
|
||||
#define CARDINFOWIDGET_H
|
||||
|
||||
#include "../../../card/exact_card.h"
|
||||
#include "card_ref.h"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QFrame>
|
||||
#include <QStringList>
|
||||
|
||||
class CardInfoPictureWidget;
|
||||
class CardInfoTextWidget;
|
||||
class AbstractCardItem;
|
||||
|
||||
class CardInfoDisplayWidget : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
qreal aspectRatio;
|
||||
ExactCard exactCard;
|
||||
CardInfoPictureWidget *pic;
|
||||
CardInfoTextWidget *text;
|
||||
|
||||
public:
|
||||
explicit CardInfoDisplayWidget(const CardRef &cardRef, QWidget *parent = nullptr, Qt::WindowFlags f = {});
|
||||
|
||||
public slots:
|
||||
void setCard(const ExactCard &card);
|
||||
void setCard(const CardRef &cardRef);
|
||||
void setCard(AbstractCardItem *card);
|
||||
|
||||
private slots:
|
||||
void clear();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
#include "card_info_frame_widget.h"
|
||||
|
||||
#include "../../../database/card_database_manager.h"
|
||||
#include "../../../game/board/card_item.h"
|
||||
#include "../../../settings/cache_settings.h"
|
||||
#include "card_info_display_widget.h"
|
||||
#include "card_info_picture_widget.h"
|
||||
#include "card_info_text_widget.h"
|
||||
|
||||
#include <QSplitter>
|
||||
#include <QVBoxLayout>
|
||||
#include <utility>
|
||||
|
||||
CardInfoFrameWidget::CardInfoFrameWidget(QWidget *parent)
|
||||
: QTabWidget(parent), viewTransformationButton(nullptr), cardTextOnly(false)
|
||||
{
|
||||
setContentsMargins(3, 3, 3, 3);
|
||||
pic = new CardInfoPictureWidget();
|
||||
pic->setObjectName("pic");
|
||||
connect(pic, &CardInfoPictureWidget::cardChanged, this,
|
||||
qOverload<const ExactCard &>(&CardInfoFrameWidget::setCard));
|
||||
|
||||
text = new CardInfoTextWidget();
|
||||
text->setObjectName("text");
|
||||
connect(text, &CardInfoTextWidget::linkActivated, this, qOverload<const QString &>(&CardInfoFrameWidget::setCard));
|
||||
|
||||
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, &CardInfoFrameWidget::currentChanged, this, &CardInfoFrameWidget::setViewMode);
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
void CardInfoFrameWidget::retranslateUi()
|
||||
{
|
||||
setTabText(ImageOnlyView, tr("Image"));
|
||||
setTabText(TextOnlyView, tr("Description"));
|
||||
setTabText(ImageAndTextView, tr("Both"));
|
||||
|
||||
if (viewTransformationButton) {
|
||||
viewTransformationButton->setText(tr("View transformation"));
|
||||
}
|
||||
}
|
||||
|
||||
void CardInfoFrameWidget::setViewTransformationButtonVisibility(bool visible)
|
||||
{
|
||||
if (!viewTransformationButton && visible) {
|
||||
viewTransformationButton = new QPushButton();
|
||||
viewTransformationButton->setObjectName("viewTransformationButton");
|
||||
connect(viewTransformationButton, &QPushButton::clicked, this, &CardInfoFrameWidget::viewTransformation);
|
||||
refreshLayout();
|
||||
} else if (viewTransformationButton && !visible) {
|
||||
// Deleting a widget automatically removes it from its parent
|
||||
viewTransformationButton->deleteLater();
|
||||
viewTransformationButton = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the widgets to the layouts that are relevant to the currently active tab.
|
||||
*
|
||||
* QWidgets can only have one parent, so we need to re-parent the shared widgets whenever we switch tabs.
|
||||
*/
|
||||
void CardInfoFrameWidget::refreshLayout()
|
||||
{
|
||||
switch (currentIndex()) {
|
||||
case ImageOnlyView:
|
||||
case TextOnlyView:
|
||||
// We need to always parent all widgets, even the ones that aren't visible,
|
||||
// since an unparented widget becomes free-floating.
|
||||
tab1Layout->addWidget(pic);
|
||||
if (viewTransformationButton) {
|
||||
tab1Layout->addWidget(viewTransformationButton);
|
||||
}
|
||||
tab2Layout->addWidget(text);
|
||||
break;
|
||||
case ImageAndTextView:
|
||||
splitter->addWidget(pic);
|
||||
if (viewTransformationButton) {
|
||||
splitter->addWidget(viewTransformationButton);
|
||||
}
|
||||
splitter->addWidget(text);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void CardInfoFrameWidget::setViewMode(int mode)
|
||||
{
|
||||
if (currentIndex() != mode) {
|
||||
setCurrentIndex(mode);
|
||||
}
|
||||
|
||||
refreshLayout();
|
||||
|
||||
SettingsCache::instance().setCardInfoViewMode(mode);
|
||||
}
|
||||
|
||||
static bool hasTransformation(const CardInfo &info)
|
||||
{
|
||||
for (const auto &cardRelation : info.getAllRelatedCards()) {
|
||||
if (cardRelation->getDoesTransform()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CardInfoFrameWidget::setCard(const ExactCard &card)
|
||||
{
|
||||
if (exactCard) {
|
||||
disconnect(exactCard.getCardPtr().data(), nullptr, this, nullptr);
|
||||
}
|
||||
|
||||
exactCard = card;
|
||||
|
||||
if (exactCard) {
|
||||
connect(exactCard.getCardPtr().data(), &QObject::destroyed, this, &CardInfoFrameWidget::clearCard);
|
||||
}
|
||||
|
||||
setViewTransformationButtonVisibility(hasTransformation(exactCard.getInfo()));
|
||||
|
||||
text->setCard(exactCard.getCardPtr());
|
||||
pic->setCard(exactCard);
|
||||
}
|
||||
|
||||
void CardInfoFrameWidget::setCard(const QString &cardName)
|
||||
{
|
||||
setCard(CardDatabaseManager::getInstance()->guessCard({cardName}));
|
||||
}
|
||||
|
||||
void CardInfoFrameWidget::setCard(const CardRef &cardRef)
|
||||
{
|
||||
setCard(CardDatabaseManager::getInstance()->getCard(cardRef));
|
||||
}
|
||||
|
||||
void CardInfoFrameWidget::setCard(AbstractCardItem *card)
|
||||
{
|
||||
if (card) {
|
||||
setCard(card->getCard());
|
||||
}
|
||||
}
|
||||
|
||||
void CardInfoFrameWidget::viewTransformation()
|
||||
{
|
||||
if (exactCard) {
|
||||
const auto &cardRelations = exactCard.getInfo().getAllRelatedCards();
|
||||
for (const auto &cardRelation : cardRelations) {
|
||||
if (cardRelation->getDoesTransform()) {
|
||||
setCard(cardRelation->getName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CardInfoFrameWidget::clearCard()
|
||||
{
|
||||
setCard(ExactCard());
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
#ifndef CARDFRAME_H
|
||||
#define CARDFRAME_H
|
||||
|
||||
#include "../../../card/exact_card.h"
|
||||
#include "card_ref.h"
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QTabWidget>
|
||||
|
||||
class AbstractCardItem;
|
||||
class CardInfoPictureWidget;
|
||||
class CardInfoTextWidget;
|
||||
class QVBoxLayout;
|
||||
class QSplitter;
|
||||
|
||||
class CardInfoFrameWidget : public QTabWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
ExactCard exactCard;
|
||||
CardInfoPictureWidget *pic;
|
||||
CardInfoTextWidget *text;
|
||||
QPushButton *viewTransformationButton;
|
||||
bool cardTextOnly;
|
||||
QWidget *tab1, *tab2, *tab3;
|
||||
QVBoxLayout *tab1Layout, *tab2Layout, *tab3Layout;
|
||||
QSplitter *splitter;
|
||||
|
||||
void setViewTransformationButtonVisibility(bool visible);
|
||||
void refreshLayout();
|
||||
|
||||
public:
|
||||
enum ViewMode
|
||||
{
|
||||
ImageOnlyView,
|
||||
TextOnlyView,
|
||||
ImageAndTextView
|
||||
};
|
||||
|
||||
explicit CardInfoFrameWidget(QWidget *parent = nullptr);
|
||||
ExactCard getCard()
|
||||
{
|
||||
return exactCard;
|
||||
}
|
||||
void retranslateUi();
|
||||
|
||||
public slots:
|
||||
void setCard(const ExactCard &card);
|
||||
void setCard(const QString &cardName);
|
||||
void setCard(const CardRef &cardRef);
|
||||
void setCard(AbstractCardItem *card);
|
||||
void viewTransformation();
|
||||
void clearCard();
|
||||
void setViewMode(int mode);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -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 (getCard()) {
|
||||
PictureLoader::getPixmap(fullResPixmap, getCard(), 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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
#include "card_info_picture_enlarged_widget.h"
|
||||
|
||||
#include "../../../picture_loader/picture_loader.h"
|
||||
#include "../../../settings/cache_settings.h"
|
||||
|
||||
#include <QPainterPath>
|
||||
#include <QStylePainter>
|
||||
#include <utility>
|
||||
|
||||
/**
|
||||
* @brief Constructs a CardPictureEnlargedWidget.
|
||||
* @param parent The parent widget.
|
||||
*
|
||||
* Sets the widget's window flags to keep it displayed as a tooltip overlay.
|
||||
*/
|
||||
CardInfoPictureEnlargedWidget::CardInfoPictureEnlargedWidget(QWidget *parent) : QWidget(parent), pixmapDirty(true)
|
||||
{
|
||||
setWindowFlags(Qt::ToolTip); // Keeps this widget on top of everything
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
|
||||
connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
|
||||
Q_UNUSED(_roundCardCorners);
|
||||
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Loads the pixmap based on the given size and card information.
|
||||
* @param size The desired size for the loaded pixmap.
|
||||
*
|
||||
* If card information is available, it loads the card's specific pixmap. Otherwise, it loads a default card back
|
||||
* pixmap.
|
||||
*/
|
||||
void CardInfoPictureEnlargedWidget::loadPixmap(const QSize &size)
|
||||
{
|
||||
if (card) {
|
||||
PictureLoader::getPixmap(enlargedPixmap, card, size);
|
||||
} else {
|
||||
PictureLoader::getCardBackPixmap(enlargedPixmap, size);
|
||||
}
|
||||
pixmapDirty = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the pixmap for the widget based on a provided card.
|
||||
* @param _card The card information to load.
|
||||
* @param size The desired size for the pixmap.
|
||||
*
|
||||
* Sets the widget's pixmap to the card image and resizes the widget to match the specified size. Triggers a repaint.
|
||||
*/
|
||||
void CardInfoPictureEnlargedWidget::setCardPixmap(const ExactCard &_card, const QSize size)
|
||||
{
|
||||
card = _card;
|
||||
loadPixmap(size);
|
||||
|
||||
setFixedSize(size); // Set the widget size to the enlarged size
|
||||
|
||||
update(); // Trigger a repaint
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Custom paint event that draws the enlarged card image with rounded corners.
|
||||
* @param event The paint event (unused).
|
||||
*
|
||||
* Checks if the pixmap is valid. Then, calculates the size and position for centering the
|
||||
* scaled pixmap within the widget, applies rounded corners, and draws the pixmap.
|
||||
*/
|
||||
void CardInfoPictureEnlargedWidget::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
if (width() == 0 || height() == 0 || enlargedPixmap.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pixmapDirty) {
|
||||
loadPixmap(size());
|
||||
}
|
||||
|
||||
// Scale the size of the pixmap to fit the widget while maintaining the aspect ratio
|
||||
QSize scaledSize = enlargedPixmap.size().scaled(size().width(), size().height(), Qt::KeepAspectRatio);
|
||||
|
||||
// Calculate the position to center the scaled pixmap
|
||||
QPoint topLeft{(width() - scaledSize.width()) / 2, (height() - scaledSize.height()) / 2};
|
||||
|
||||
// Define the radius for rounded corners
|
||||
// Adjust the radius as needed for rounded corners
|
||||
qreal radius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * scaledSize.width() : 0.;
|
||||
|
||||
QStylePainter painter(this);
|
||||
// Fill the background with transparent color to ensure rounded corners are rendered properly
|
||||
painter.fillRect(rect(), Qt::transparent); // Use the transparent background
|
||||
|
||||
QPainterPath shape;
|
||||
shape.addRoundedRect(QRect(topLeft, scaledSize), radius, radius);
|
||||
painter.setClipPath(shape); // Set the clipping path
|
||||
|
||||
// Draw the pixmap scaled to the calculated size
|
||||
painter.drawItemPixmap(QRect(topLeft, scaledSize), Qt::AlignCenter,
|
||||
enlargedPixmap.scaled(scaledSize, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
#ifndef CARD_PICTURE_ENLARGED_WIDGET_H
|
||||
#define CARD_PICTURE_ENLARGED_WIDGET_H
|
||||
|
||||
#include "../../../card/exact_card.h"
|
||||
|
||||
#include <QPixmap>
|
||||
#include <QWidget>
|
||||
|
||||
class CardInfoPictureEnlargedWidget final : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
explicit CardInfoPictureEnlargedWidget(QWidget *parent = nullptr);
|
||||
|
||||
// Sets the card pixmap to display
|
||||
void setCardPixmap(const ExactCard &_card, QSize size);
|
||||
|
||||
protected:
|
||||
// Handles the painting event for the enlarged card
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private:
|
||||
// Cached pixmap for the enlarged card
|
||||
QPixmap enlargedPixmap;
|
||||
|
||||
// Tracks if the pixmap needs to be refreshed/redrawn
|
||||
bool pixmapDirty;
|
||||
|
||||
// Card information
|
||||
ExactCard card;
|
||||
|
||||
// Loads the enlarged card pixmap
|
||||
void loadPixmap(const QSize &size);
|
||||
};
|
||||
|
||||
#endif // CARD_PICTURE_ENLARGED_WIDGET_H
|
||||
|
|
@ -0,0 +1,473 @@
|
|||
#include "card_info_picture_widget.h"
|
||||
|
||||
#include "../../../database/card_database_manager.h"
|
||||
#include "../../../game/board/card_item.h"
|
||||
#include "../../../picture_loader/picture_loader.h"
|
||||
#include "../../../settings/cache_settings.h"
|
||||
#include "../../../tabs/tab_supervisor.h"
|
||||
#include "../../window_main.h"
|
||||
|
||||
#include <QMenu>
|
||||
#include <QMouseEvent>
|
||||
#include <QScreen>
|
||||
#include <QStylePainter>
|
||||
#include <QWidget>
|
||||
#include <utility>
|
||||
|
||||
/**
|
||||
* @class CardInfoPictureWidget
|
||||
* @brief Widget that displays an enlarged image of a card, loading the image based on the card's info or showing a
|
||||
* default image.
|
||||
*
|
||||
* This widget can optionally display a larger version of the card's image when hovered over,
|
||||
* depending on the `hoverToZoomEnabled` parameter.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Constructs a CardInfoPictureWidget.
|
||||
* @param parent The parent widget, if any.
|
||||
* @param hoverToZoomEnabled If this widget will spawn a larger widget when hovered over.
|
||||
*
|
||||
* Initializes the widget with a minimum height and sets the pixmap to a dirty state for initial loading.
|
||||
*/
|
||||
CardInfoPictureWidget::CardInfoPictureWidget(QWidget *parent, const bool _hoverToZoomEnabled, const bool _raiseOnEnter)
|
||||
: QWidget(parent), pixmapDirty(true), hoverToZoomEnabled(_hoverToZoomEnabled), raiseOnEnter(_raiseOnEnter)
|
||||
{
|
||||
setMinimumHeight(baseHeight);
|
||||
if (hoverToZoomEnabled) {
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
enlargedPixmapWidget = new CardInfoPictureEnlargedWidget(this->window());
|
||||
enlargedPixmapWidget->hide();
|
||||
connect(this, &QObject::destroyed, enlargedPixmapWidget, &CardInfoPictureEnlargedWidget::deleteLater);
|
||||
|
||||
hoverTimer = new QTimer(this);
|
||||
hoverTimer->setSingleShot(true);
|
||||
connect(hoverTimer, &QTimer::timeout, this, &CardInfoPictureWidget::showEnlargedPixmap);
|
||||
|
||||
// Store the widget's original position
|
||||
originalPos = this->pos();
|
||||
|
||||
// Create the animation
|
||||
animation = new QPropertyAnimation(this, "pos");
|
||||
animation->setDuration(200); // 200ms animation duration
|
||||
animation->setEasingCurve(QEasingCurve::OutQuad);
|
||||
|
||||
animation->setStartValue(originalPos);
|
||||
animation->setEndValue(originalPos - QPoint(0, animationOffset));
|
||||
|
||||
connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
|
||||
Q_UNUSED(_roundCardCorners);
|
||||
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the card to be displayed and updates the pixmap.
|
||||
* @param card A shared pointer to the card information (CardInfoPtr).
|
||||
*
|
||||
* Disconnects any existing signal connections from the previous card info and connects to the `pixmapUpdated`
|
||||
* signal of the new card to automatically update the pixmap when the card image changes.
|
||||
*/
|
||||
void CardInfoPictureWidget::setCard(const ExactCard &card)
|
||||
{
|
||||
if (exactCard.getCardPtr()) {
|
||||
disconnect(exactCard.getCardPtr().data(), nullptr, this, nullptr);
|
||||
}
|
||||
|
||||
exactCard = card;
|
||||
|
||||
if (exactCard.getCardPtr()) {
|
||||
connect(exactCard.getCardPtr().data(), &CardInfo::pixmapUpdated, this, &CardInfoPictureWidget::updatePixmap);
|
||||
}
|
||||
|
||||
updatePixmap();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the hover to zoom feature.
|
||||
* @param enabled If true, enables the hover-to-zoom functionality; otherwise, disables it.
|
||||
*/
|
||||
void CardInfoPictureWidget::setHoverToZoomEnabled(const bool enabled)
|
||||
{
|
||||
hoverToZoomEnabled = enabled;
|
||||
setMouseTracking(enabled);
|
||||
}
|
||||
|
||||
void CardInfoPictureWidget::setRaiseOnEnterEnabled(const bool enabled)
|
||||
{
|
||||
raiseOnEnter = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handles widget resizing by updating the pixmap size.
|
||||
* @param event The resize event (unused).
|
||||
*
|
||||
* Calls `updatePixmap()` to ensure the image scales appropriately when the widget is resized.
|
||||
*/
|
||||
void CardInfoPictureWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
originalPos = pos(); // Update the baseline position
|
||||
updatePixmap();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the scale factor for the widget.
|
||||
* @param scale The scale factor to apply.
|
||||
*
|
||||
* Adjusts the widget's size according to the scale factor and updates the pixmap.
|
||||
*/
|
||||
void CardInfoPictureWidget::setScaleFactor(const int scale)
|
||||
{
|
||||
const int newWidth = baseWidth * scale / 100;
|
||||
const int newHeight = static_cast<int>(newWidth * aspectRatio);
|
||||
|
||||
scaleFactor = scale;
|
||||
|
||||
setFixedSize(newWidth, newHeight);
|
||||
updatePixmap();
|
||||
|
||||
emit cardScaleFactorChanged(scale);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Marks the pixmap as dirty and triggers a widget repaint.
|
||||
*
|
||||
* Sets `pixmapDirty` to true, indicating that the pixmap needs to be reloaded before the next display.
|
||||
*/
|
||||
void CardInfoPictureWidget::updatePixmap()
|
||||
{
|
||||
pixmapDirty = true;
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Loads the appropriate pixmap based on the current card info.
|
||||
*
|
||||
* If `info` is valid, loads the card's image. Otherwise, loads a default card back image.
|
||||
*/
|
||||
void CardInfoPictureWidget::loadPixmap()
|
||||
{
|
||||
PictureLoader::getCardBackLoadingInProgressPixmap(resizedPixmap, size());
|
||||
if (exactCard) {
|
||||
PictureLoader::getPixmap(resizedPixmap, exactCard, size());
|
||||
} else {
|
||||
PictureLoader::getCardBackLoadingFailedPixmap(resizedPixmap, size());
|
||||
}
|
||||
|
||||
pixmapDirty = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Custom paint event that draws the card image with rounded corners.
|
||||
* @param event The paint event (unused).
|
||||
*
|
||||
* Checks if the pixmap needs to be reloaded. Then, calculates the size and position for centering the
|
||||
* scaled pixmap within the widget, applies rounded corners, and draws the pixmap.
|
||||
*/
|
||||
void CardInfoPictureWidget::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
QWidget::paintEvent(event);
|
||||
|
||||
if (width() == 0 || height() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pixmapDirty) {
|
||||
loadPixmap();
|
||||
}
|
||||
|
||||
QPixmap transformedPixmap = resizedPixmap; // Default pixmap
|
||||
if (SettingsCache::instance().getAutoRotateSidewaysLayoutCards()) {
|
||||
if (exactCard.getInfo().getLandscapeOrientation()) {
|
||||
// Rotate pixmap 90 degrees to the left
|
||||
QTransform transform;
|
||||
transform.rotate(90);
|
||||
transformedPixmap = resizedPixmap.transformed(transform, Qt::SmoothTransformation);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle DPI scaling
|
||||
qreal dpr = devicePixelRatio(); // Get the actual scaling factor
|
||||
QSize availableSize = size() * dpr; // Convert to physical pixel size
|
||||
|
||||
// Compute final scaled size
|
||||
QSize pixmapSize = transformedPixmap.size();
|
||||
QSize scaledSize = pixmapSize.scaled(availableSize, Qt::KeepAspectRatio);
|
||||
|
||||
// Pre-scale the pixmap once before drawing
|
||||
QPixmap finalPixmap = transformedPixmap.scaled(scaledSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
finalPixmap.setDevicePixelRatio(dpr); // Ensure correct display on high-DPI screens
|
||||
|
||||
// Compute target rectangle with explicit integer conversion
|
||||
int targetX = static_cast<int>((availableSize.width() - scaledSize.width()) / (2 * dpr));
|
||||
int targetY = static_cast<int>((availableSize.height() - scaledSize.height()) / (2 * dpr));
|
||||
int targetW = static_cast<int>(scaledSize.width() / dpr);
|
||||
int targetH = static_cast<int>(scaledSize.height() / dpr);
|
||||
QRect targetRect{targetX, targetY, targetW, targetH};
|
||||
|
||||
// Compute rounded corner radius
|
||||
// Ensure consistent rounding
|
||||
qreal radius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * static_cast<qreal>(targetRect.width()) : 0.;
|
||||
|
||||
// Draw the pixmap with rounded corners
|
||||
QStylePainter painter(this);
|
||||
QPainterPath shape;
|
||||
shape.addRoundedRect(targetRect, radius, radius);
|
||||
painter.setClipPath(shape);
|
||||
|
||||
// Draw the pre-scaled pixmap directly
|
||||
painter.drawPixmap(targetRect, finalPixmap);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Provides the recommended size for the widget based on the scale factor.
|
||||
* @return The recommended widget size.
|
||||
*/
|
||||
QSize CardInfoPictureWidget::sizeHint() const
|
||||
{
|
||||
return {static_cast<int>(baseWidth * scaleFactor / 100.0),
|
||||
static_cast<int>(baseWidth * scaleFactor / 100.0 * aspectRatio)};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts the hover timer to show the enlarged pixmap on hover.
|
||||
* @param event The enter event.
|
||||
*/
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
void CardInfoPictureWidget::enterEvent(QEnterEvent *event)
|
||||
#else
|
||||
void CardInfoPictureWidget::enterEvent(QEvent *event)
|
||||
#endif
|
||||
{
|
||||
QWidget::enterEvent(event); // Call the base class implementation
|
||||
|
||||
// If hover-to-zoom is enabled, start the hover timer
|
||||
if (hoverToZoomEnabled) {
|
||||
hoverTimer->start(hoverActivateThresholdInMs);
|
||||
}
|
||||
|
||||
// Emit signal indicating a card is being hovered on
|
||||
emit hoveredOnCard(exactCard);
|
||||
|
||||
if (raiseOnEnter) {
|
||||
if (animation->state() == QAbstractAnimation::Running) {
|
||||
animation->pause(); // Pause current animation
|
||||
} else {
|
||||
originalPos = this->pos(); // Update the baseline position
|
||||
animation->setStartValue(originalPos);
|
||||
animation->setEndValue(originalPos - QPoint(0, animationOffset));
|
||||
}
|
||||
animation->setDirection(QAbstractAnimation::Forward);
|
||||
animation->start();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stops the hover timer and hides the enlarged pixmap when the mouse leaves.
|
||||
* @param event The leave event.
|
||||
*/
|
||||
void CardInfoPictureWidget::leaveEvent(QEvent *event)
|
||||
{
|
||||
QWidget::leaveEvent(event);
|
||||
|
||||
if (hoverToZoomEnabled) {
|
||||
hoverTimer->stop();
|
||||
enlargedPixmapWidget->hide();
|
||||
}
|
||||
|
||||
if (raiseOnEnter) {
|
||||
if (animation->state() == QAbstractAnimation::Running) {
|
||||
animation->pause(); // Pause current animation
|
||||
}
|
||||
animation->setDirection(QAbstractAnimation::Backward);
|
||||
animation->start();
|
||||
}
|
||||
}
|
||||
|
||||
void CardInfoPictureWidget::moveEvent(QMoveEvent *event)
|
||||
{
|
||||
QWidget::moveEvent(event);
|
||||
|
||||
hoverTimer->stop();
|
||||
enlargedPixmapWidget->hide();
|
||||
|
||||
if (animation->state() == QAbstractAnimation::Running) {
|
||||
return;
|
||||
}
|
||||
originalPos = this->pos(); // Update the baseline position
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Moves the enlarged pixmap widget to follow the mouse cursor.
|
||||
* @param event The mouse move event.
|
||||
*/
|
||||
void CardInfoPictureWidget::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
QWidget::mouseMoveEvent(event);
|
||||
|
||||
if (hoverToZoomEnabled && enlargedPixmapWidget->isVisible()) {
|
||||
const QPoint cursorPos = QCursor::pos();
|
||||
const QRect screenGeometry = QGuiApplication::screenAt(cursorPos)->geometry();
|
||||
const QSize widgetSize = enlargedPixmapWidget->size();
|
||||
|
||||
int newX = cursorPos.x() + enlargedPixmapOffset;
|
||||
int newY = cursorPos.y() + enlargedPixmapOffset;
|
||||
|
||||
// Adjust if out of bounds
|
||||
if (newX + widgetSize.width() > screenGeometry.right()) {
|
||||
newX = cursorPos.x() - widgetSize.width() - enlargedPixmapOffset;
|
||||
}
|
||||
if (newY + widgetSize.height() > screenGeometry.bottom()) {
|
||||
newY = cursorPos.y() - widgetSize.height() - enlargedPixmapOffset;
|
||||
}
|
||||
|
||||
enlargedPixmapWidget->move(newX, newY);
|
||||
}
|
||||
}
|
||||
|
||||
void CardInfoPictureWidget::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
QWidget::mousePressEvent(event);
|
||||
if (event->button() == Qt::RightButton) {
|
||||
createRightClickMenu()->popup(QCursor::pos());
|
||||
} else {
|
||||
emit cardClicked();
|
||||
}
|
||||
|
||||
emit cardClicked();
|
||||
}
|
||||
|
||||
void CardInfoPictureWidget::hideEvent(QHideEvent *event)
|
||||
{
|
||||
enlargedPixmapWidget->hide();
|
||||
QWidget::hideEvent(event);
|
||||
}
|
||||
|
||||
QMenu *CardInfoPictureWidget::createRightClickMenu()
|
||||
{
|
||||
auto *cardMenu = new QMenu(this);
|
||||
|
||||
if (!exactCard) {
|
||||
return cardMenu;
|
||||
}
|
||||
|
||||
cardMenu->addMenu(createViewRelatedCardsMenu());
|
||||
cardMenu->addMenu(createAddToOpenDeckMenu());
|
||||
|
||||
return cardMenu;
|
||||
}
|
||||
|
||||
QMenu *CardInfoPictureWidget::createViewRelatedCardsMenu()
|
||||
{
|
||||
auto viewRelatedCards = new QMenu(tr("View related cards"));
|
||||
|
||||
QList<CardRelation *> relatedCards = exactCard.getInfo().getAllRelatedCards();
|
||||
|
||||
auto relatedCardExists = [](const CardRelation *cardRelation) {
|
||||
return CardDatabaseManager::getInstance()->getCardInfo(cardRelation->getName()) != nullptr;
|
||||
};
|
||||
|
||||
bool atLeastOneGoodRelationFound = std::any_of(relatedCards.begin(), relatedCards.end(), relatedCardExists);
|
||||
|
||||
if (!atLeastOneGoodRelationFound) {
|
||||
viewRelatedCards->setEnabled(false);
|
||||
return viewRelatedCards;
|
||||
}
|
||||
|
||||
for (const auto &relatedCard : relatedCards) {
|
||||
const auto &relatedCardName = relatedCard->getName();
|
||||
QAction *viewCard = viewRelatedCards->addAction(relatedCardName);
|
||||
connect(viewCard, &QAction::triggered, this, [this, &relatedCardName] {
|
||||
emit cardChanged(
|
||||
CardDatabaseManager::getInstance()->getCard({relatedCardName, exactCard.getPrinting().getUuid()}));
|
||||
});
|
||||
viewRelatedCards->addAction(viewCard);
|
||||
}
|
||||
|
||||
return viewRelatedCards;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the single instance of the MainWindow in this application.
|
||||
*/
|
||||
static MainWindow *findMainWindow()
|
||||
{
|
||||
for (auto widget : QApplication::topLevelWidgets()) {
|
||||
if (auto mainWindow = qobject_cast<MainWindow *>(widget)) {
|
||||
return mainWindow;
|
||||
}
|
||||
}
|
||||
// This code should be unreachable
|
||||
qCritical() << "Could not find MainWindow in QApplication::topLevelWidgets";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QMenu *CardInfoPictureWidget::createAddToOpenDeckMenu()
|
||||
{
|
||||
auto addToOpenDeckMenu = new QMenu(tr("Add card to deck"));
|
||||
|
||||
auto mainWindow = findMainWindow();
|
||||
QList<AbstractTabDeckEditor *> deckEditorTabs = mainWindow->getTabSupervisor()->getDeckEditorTabs();
|
||||
|
||||
if (deckEditorTabs.isEmpty()) {
|
||||
addToOpenDeckMenu->setEnabled(false);
|
||||
return addToOpenDeckMenu;
|
||||
}
|
||||
|
||||
for (auto &deckEditorTab : deckEditorTabs) {
|
||||
auto *addCardMenu = addToOpenDeckMenu->addMenu(deckEditorTab->getTabText());
|
||||
|
||||
QAction *addCard = addCardMenu->addAction(tr("Mainboard"));
|
||||
connect(addCard, &QAction::triggered, this, [this, deckEditorTab] {
|
||||
deckEditorTab->updateCard(exactCard);
|
||||
deckEditorTab->actAddCard(exactCard);
|
||||
});
|
||||
|
||||
QAction *addCardSideboard = addCardMenu->addAction(tr("Sideboard"));
|
||||
connect(addCardSideboard, &QAction::triggered, this, [this, deckEditorTab] {
|
||||
deckEditorTab->updateCard(exactCard);
|
||||
deckEditorTab->actAddCardToSideboard(exactCard);
|
||||
});
|
||||
}
|
||||
|
||||
return addToOpenDeckMenu;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Displays the enlarged version of the card's pixmap near the cursor.
|
||||
*
|
||||
* If card information is available, the enlarged pixmap is loaded, positioned near the cursor,
|
||||
* and displayed.
|
||||
*/
|
||||
void CardInfoPictureWidget::showEnlargedPixmap() const
|
||||
{
|
||||
if (!exactCard) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QSize enlargedSize(static_cast<int>(size().width() * 2), static_cast<int>(size().width() * aspectRatio * 2));
|
||||
enlargedPixmapWidget->setCardPixmap(exactCard, enlargedSize);
|
||||
|
||||
const QPoint cursorPos = QCursor::pos();
|
||||
const QRect screenGeometry = QGuiApplication::screenAt(cursorPos)->geometry();
|
||||
const QSize widgetSize = enlargedPixmapWidget->size();
|
||||
|
||||
int newX = cursorPos.x() + enlargedPixmapOffset;
|
||||
int newY = cursorPos.y() + enlargedPixmapOffset;
|
||||
|
||||
// Adjust if out of bounds
|
||||
if (newX + widgetSize.width() > screenGeometry.right()) {
|
||||
newX = cursorPos.x() - widgetSize.width() - enlargedPixmapOffset;
|
||||
}
|
||||
if (newY + widgetSize.height() > screenGeometry.bottom()) {
|
||||
newY = cursorPos.y() - widgetSize.height() - enlargedPixmapOffset;
|
||||
}
|
||||
|
||||
enlargedPixmapWidget->move(newX, newY);
|
||||
|
||||
enlargedPixmapWidget->show();
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
#ifndef CARD_INFO_PICTURE_H
|
||||
#define CARD_INFO_PICTURE_H
|
||||
|
||||
#include "../../../card/exact_card.h"
|
||||
#include "card_info_picture_enlarged_widget.h"
|
||||
|
||||
#include <QPropertyAnimation>
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
||||
inline Q_LOGGING_CATEGORY(CardInfoPictureWidgetLog, "card_info_picture_widget");
|
||||
|
||||
class AbstractCardItem;
|
||||
class QMenu;
|
||||
|
||||
class CardInfoPictureWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CardInfoPictureWidget(QWidget *parent = nullptr,
|
||||
bool hoverToZoomEnabled = false,
|
||||
bool raiseOnEnter = false);
|
||||
ExactCard getCard()
|
||||
{
|
||||
return exactCard;
|
||||
}
|
||||
[[nodiscard]] QSize sizeHint() const override;
|
||||
|
||||
public slots:
|
||||
void setCard(const ExactCard &card);
|
||||
void setScaleFactor(int scale); // New slot for scaling
|
||||
void setHoverToZoomEnabled(bool enabled);
|
||||
void setRaiseOnEnterEnabled(bool enabled);
|
||||
void updatePixmap();
|
||||
|
||||
signals:
|
||||
void hoveredOnCard(const ExactCard &hoveredCard);
|
||||
void cardScaleFactorChanged(int _scale);
|
||||
void cardChanged(const ExactCard &card);
|
||||
void cardClicked();
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
void paintEvent(QPaintEvent *) override;
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
void enterEvent(QEnterEvent *event) override; // Qt6 signature
|
||||
#else
|
||||
void enterEvent(QEvent *event) override; // Qt5 signature
|
||||
#endif
|
||||
void leaveEvent(QEvent *event) override;
|
||||
void moveEvent(QMoveEvent *event) override;
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void hideEvent(QHideEvent *event) override;
|
||||
void loadPixmap();
|
||||
[[nodiscard]] const QPixmap &getResizedPixmap() const
|
||||
{
|
||||
return resizedPixmap;
|
||||
}
|
||||
void showEnlargedPixmap() const;
|
||||
|
||||
private:
|
||||
ExactCard exactCard;
|
||||
qreal magicTheGatheringCardAspectRatio = 1.396;
|
||||
qreal yuGiOhCardAspectRatio = 1.457;
|
||||
qreal aspectRatio = magicTheGatheringCardAspectRatio;
|
||||
int baseWidth = 200;
|
||||
int baseHeight = 200;
|
||||
double scaleFactor = 100;
|
||||
QPixmap resizedPixmap;
|
||||
bool pixmapDirty;
|
||||
bool hoverToZoomEnabled;
|
||||
bool raiseOnEnter;
|
||||
int hoverActivateThresholdInMs = 500;
|
||||
CardInfoPictureEnlargedWidget *enlargedPixmapWidget = nullptr;
|
||||
int enlargedPixmapOffset = 10;
|
||||
QTimer *hoverTimer;
|
||||
QPropertyAnimation *animation;
|
||||
QPoint originalPos; // Store the original position
|
||||
const int animationOffset = 10; // Adjust this for how much the widget moves up
|
||||
|
||||
QMenu *createRightClickMenu();
|
||||
QMenu *createViewRelatedCardsMenu();
|
||||
QMenu *createAddToOpenDeckMenu();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,245 @@
|
|||
#include "card_info_picture_with_text_overlay_widget.h"
|
||||
|
||||
#include <QFontMetrics>
|
||||
#include <QPainterPath>
|
||||
#include <QStylePainter>
|
||||
#include <QTextOption>
|
||||
|
||||
/**
|
||||
* @brief Constructs a CardPictureWithTextOverlay widget.
|
||||
* @param parent The parent widget.
|
||||
* @param hoverToZoomEnabled If this widget will spawn a larger widget when hovered over.
|
||||
* @param raiseOnEnter If this widget will raise slightly when entered.
|
||||
* @param textColor The color of the overlay text.
|
||||
* @param outlineColor The color of the outline around the text.
|
||||
* @param fontSize The font size of the overlay text.
|
||||
* @param alignment The alignment of the text within the overlay.
|
||||
*
|
||||
* Sets the widget's size policy and default border style.
|
||||
*/
|
||||
CardInfoPictureWithTextOverlayWidget::CardInfoPictureWithTextOverlayWidget(QWidget *parent,
|
||||
const bool hoverToZoomEnabled,
|
||||
const bool raiseOnEnter,
|
||||
const QColor &textColor,
|
||||
const QColor &outlineColor,
|
||||
const int fontSize,
|
||||
const Qt::Alignment alignment)
|
||||
: CardInfoPictureWidget(parent, hoverToZoomEnabled, raiseOnEnter), textColor(textColor), outlineColor(outlineColor),
|
||||
fontSize(fontSize), textAlignment(alignment)
|
||||
{
|
||||
this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the overlay text to be displayed on the card.
|
||||
* @param text The text to overlay.
|
||||
*
|
||||
* Updates the widget to display the new overlay text.
|
||||
*/
|
||||
void CardInfoPictureWithTextOverlayWidget::setOverlayText(const QString &text)
|
||||
{
|
||||
overlayText = text;
|
||||
update(); // Trigger a redraw to display the updated text
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the color of the overlay text.
|
||||
* @param color The new text color.
|
||||
*/
|
||||
void CardInfoPictureWithTextOverlayWidget::setTextColor(const QColor &color)
|
||||
{
|
||||
textColor = color;
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the outline color around the overlay text.
|
||||
* @param color The new outline color.
|
||||
*/
|
||||
void CardInfoPictureWithTextOverlayWidget::setOutlineColor(const QColor &color)
|
||||
{
|
||||
outlineColor = color;
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the font size for the overlay text.
|
||||
* @param size The new font size.
|
||||
*/
|
||||
void CardInfoPictureWithTextOverlayWidget::setFontSize(const int size)
|
||||
{
|
||||
fontSize = size > 0 ? size : 1;
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the alignment of the overlay text within the widget.
|
||||
* @param alignment The new text alignment.
|
||||
*/
|
||||
void CardInfoPictureWithTextOverlayWidget::setTextAlignment(const Qt::Alignment alignment)
|
||||
{
|
||||
textAlignment = alignment;
|
||||
update();
|
||||
}
|
||||
|
||||
void CardInfoPictureWithTextOverlayWidget::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
emit imageClicked(event, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Paints the widget, including both the card image and the text overlay.
|
||||
* @param event The paint event.
|
||||
*
|
||||
* Draws the card image first, then overlays text on top. The text is wrapped and centered within the image.
|
||||
*/
|
||||
void CardInfoPictureWithTextOverlayWidget::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
// Call the base class's paintEvent to draw the card image
|
||||
CardInfoPictureWidget::paintEvent(event);
|
||||
|
||||
// If no overlay text, skip drawing the text
|
||||
if (overlayText.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QStylePainter painter(this);
|
||||
|
||||
// Get the pixmap from the base class using the getter
|
||||
const QPixmap &pixmap = getResizedPixmap();
|
||||
if (pixmap.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate size and position for drawing
|
||||
const QSize scaledSize = pixmap.size().scaled(size(), Qt::KeepAspectRatio);
|
||||
const QPoint topLeft{(width() - scaledSize.width()) / 2, (height() - scaledSize.height()) / 2};
|
||||
const QRect pixmapRect(topLeft, scaledSize);
|
||||
|
||||
// Calculate the optimal font size
|
||||
QFont font = painter.font();
|
||||
int optimalFontSize = fontSize; // Start with the user-defined font size
|
||||
const QFontMetrics baseMetrics(font);
|
||||
int textWidth = pixmapRect.width();
|
||||
|
||||
// Reduce the font size until the text fits within the pixmap's width
|
||||
do {
|
||||
font.setPointSize(optimalFontSize);
|
||||
QFontMetrics fm(font);
|
||||
int currentWidth = 0;
|
||||
for (const QString &word : overlayText.split(' ')) {
|
||||
currentWidth = std::max(currentWidth, fm.horizontalAdvance(word));
|
||||
}
|
||||
|
||||
if (currentWidth <= textWidth) {
|
||||
break;
|
||||
}
|
||||
|
||||
--optimalFontSize;
|
||||
} while (optimalFontSize > 1);
|
||||
|
||||
// Apply the calculated font size
|
||||
painter.setFont(font);
|
||||
|
||||
// Wrap the text to fit within the pixmap width
|
||||
const QFontMetrics fontMetrics(font);
|
||||
QString wrappedText;
|
||||
QString currentLine;
|
||||
QStringList words = overlayText.split(' ');
|
||||
for (const QString &word : words) {
|
||||
if (fontMetrics.horizontalAdvance(currentLine + " " + word) > textWidth) {
|
||||
wrappedText += currentLine + '\n';
|
||||
currentLine = word;
|
||||
} else {
|
||||
if (!currentLine.isEmpty()) {
|
||||
currentLine += " ";
|
||||
}
|
||||
currentLine += word;
|
||||
}
|
||||
}
|
||||
wrappedText += currentLine;
|
||||
|
||||
// Calculate total text block height
|
||||
int totalTextHeight = wrappedText.count('\n') * fontMetrics.height() + fontMetrics.height();
|
||||
|
||||
// Adjust font size if the total text height exceeds the pixmap height
|
||||
while (totalTextHeight > pixmapRect.height() && optimalFontSize > 1) {
|
||||
--optimalFontSize;
|
||||
font.setPointSize(optimalFontSize);
|
||||
painter.setFont(font);
|
||||
const QFontMetrics newMetrics(font);
|
||||
totalTextHeight = wrappedText.count('\n') * newMetrics.height() + newMetrics.height();
|
||||
}
|
||||
|
||||
// Set up the text layout options
|
||||
QTextOption textOption;
|
||||
textOption.setAlignment(textAlignment);
|
||||
|
||||
// Create a text rectangle centered vertically within the pixmap rect
|
||||
auto textRect = QRect(pixmapRect.left(), pixmapRect.top(), pixmapRect.width(), totalTextHeight);
|
||||
textRect.moveTop((pixmapRect.height() - totalTextHeight) / 2 + pixmapRect.top());
|
||||
|
||||
// Draw the outlined text
|
||||
drawOutlinedText(painter, textRect, wrappedText, textOption);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Draws text with an outline for visibility.
|
||||
* @param painter The painter to draw the text.
|
||||
* @param textRect The rectangle area to draw the text in.
|
||||
* @param text The text to display.
|
||||
* @param textOption The text layout options, such as alignment.
|
||||
*
|
||||
* Draws an outline around the text to enhance readability before drawing the main text.
|
||||
*/
|
||||
void CardInfoPictureWithTextOverlayWidget::drawOutlinedText(QPainter &painter,
|
||||
const QRect &textRect,
|
||||
const QString &text,
|
||||
const QTextOption &textOption) const
|
||||
{
|
||||
painter.setPen(outlineColor);
|
||||
for (int dx = -1; dx <= 1; ++dx) {
|
||||
for (int dy = -1; dy <= 1; ++dy) {
|
||||
if (dx != 0 || dy != 0) {
|
||||
QRect shiftedTextRect = textRect.translated(dx, dy);
|
||||
painter.drawText(shiftedTextRect, text, textOption);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the main text
|
||||
painter.setPen(textColor);
|
||||
painter.drawText(textRect, text, textOption);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Provides the recommended size for this widget.
|
||||
* @return The suggested widget size.
|
||||
*/
|
||||
QSize CardInfoPictureWithTextOverlayWidget::sizeHint() const
|
||||
{
|
||||
return CardInfoPictureWidget::sizeHint();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Provides the minimum recommended size for this widget.
|
||||
* @return The minimum widget size.
|
||||
*/
|
||||
QSize CardInfoPictureWithTextOverlayWidget::minimumSizeHint() const
|
||||
{
|
||||
// Same as sizeHint, but ensure that there is at least some space for the pixmap
|
||||
const QPixmap &pixmap = getResizedPixmap();
|
||||
const QSize pixmapSize = pixmap.isNull() ? QSize(0, 0) : pixmap.size();
|
||||
|
||||
// Get the font metrics for the overlay text
|
||||
QFont font;
|
||||
font.setPointSize(fontSize);
|
||||
const QFontMetrics fontMetrics(font);
|
||||
|
||||
// Calculate the height required for the text
|
||||
const QStringList lines = overlayText.split('\n');
|
||||
const int totalTextHeight = static_cast<int>(lines.size()) * fontMetrics.height();
|
||||
|
||||
// Return the maximum width and combined height
|
||||
return {pixmapSize.width(), pixmapSize.height() + totalTextHeight};
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
#ifndef CARD_PICTURE_WITH_TEXT_OVERLAY_H
|
||||
#define CARD_PICTURE_WITH_TEXT_OVERLAY_H
|
||||
|
||||
#include "card_info_picture_widget.h"
|
||||
|
||||
#include <QColor>
|
||||
#include <QSize>
|
||||
#include <QTextOption>
|
||||
|
||||
class CardInfoPictureWithTextOverlayWidget : public CardInfoPictureWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CardInfoPictureWithTextOverlayWidget(QWidget *parent = nullptr,
|
||||
bool hoverToZoomEnabled = false,
|
||||
bool raiseOnEnter = false,
|
||||
const QColor &textColor = Qt::white,
|
||||
const QColor &outlineColor = Qt::black,
|
||||
int fontSize = 12,
|
||||
Qt::Alignment alignment = Qt::AlignCenter);
|
||||
|
||||
void setOverlayText(const QString &text);
|
||||
void setTextColor(const QColor &color);
|
||||
void setOutlineColor(const QColor &color);
|
||||
void setFontSize(int size);
|
||||
void setTextAlignment(Qt::Alignment alignment);
|
||||
|
||||
[[nodiscard]] QSize sizeHint() const override;
|
||||
signals:
|
||||
void imageClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
[[nodiscard]] QSize minimumSizeHint() const override;
|
||||
|
||||
private:
|
||||
void drawOutlinedText(QPainter &painter,
|
||||
const QRect &textRect,
|
||||
const QString &text,
|
||||
const QTextOption &textOption) const;
|
||||
|
||||
QString overlayText;
|
||||
QColor textColor;
|
||||
QColor outlineColor;
|
||||
int fontSize;
|
||||
Qt::Alignment textAlignment;
|
||||
};
|
||||
|
||||
#endif // CARD_PICTURE_WITH_TEXT_OVERLAY_H
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
#include "card_info_text_widget.h"
|
||||
|
||||
#include "../../../card/game_specific_terms.h"
|
||||
#include "../../../game/board/card_item.h"
|
||||
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
#include <QTextEdit>
|
||||
|
||||
CardInfoTextWidget::CardInfoTextWidget(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 CardInfoTextWidget::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 CardInfoTextWidget::setInvalidCardName(const QString &cardName)
|
||||
{
|
||||
nameLabel->setText(tr("Unknown card:") + " " + cardName);
|
||||
textLabel->setText("");
|
||||
}
|
||||
|
||||
void CardInfoTextWidget::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("");
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef CARDINFOTEXT_H
|
||||
#define CARDINFOTEXT_H
|
||||
|
||||
#include "../../../card/card_info.h"
|
||||
|
||||
#include <QFrame>
|
||||
class QLabel;
|
||||
class QTextEdit;
|
||||
|
||||
class CardInfoTextWidget : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
QLabel *nameLabel;
|
||||
QTextEdit *textLabel;
|
||||
CardInfoPtr info;
|
||||
|
||||
public:
|
||||
explicit CardInfoTextWidget(QWidget *parent = nullptr);
|
||||
void retranslateUi();
|
||||
void setInvalidCardName(const QString &cardName);
|
||||
|
||||
signals:
|
||||
void linkActivated(const QString &link);
|
||||
public slots:
|
||||
void setCard(CardInfoPtr card);
|
||||
};
|
||||
|
||||
#endif
|
||||
61
cockatrice/src/interface/widgets/cards/card_size_widget.cpp
Normal file
61
cockatrice/src/interface/widgets/cards/card_size_widget.cpp
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
#include "card_size_widget.h"
|
||||
|
||||
#include "../../../settings/cache_settings.h"
|
||||
#include "../printing_selector/printing_selector.h"
|
||||
#include "../visual_deck_storage/visual_deck_storage_widget.h"
|
||||
|
||||
/**
|
||||
* @class CardSizeWidget
|
||||
* @brief A widget for adjusting card sizes using a slider.
|
||||
*
|
||||
* This widget allows users to dynamically change the card size in a linked FlowWidget
|
||||
* and updates the application's settings accordingly.
|
||||
*/
|
||||
CardSizeWidget::CardSizeWidget(QWidget *parent, FlowWidget *_flowWidget, int defaultValue)
|
||||
: parent(parent), flowWidget(_flowWidget)
|
||||
{
|
||||
cardSizeLayout = new QHBoxLayout(this);
|
||||
cardSizeLayout->setContentsMargins(9, 0, 9, 0);
|
||||
setLayout(cardSizeLayout);
|
||||
|
||||
cardSizeLabel = new QLabel(tr("Card Size"), this);
|
||||
cardSizeLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
|
||||
cardSizeSlider = new QSlider(Qt::Horizontal, this);
|
||||
cardSizeSlider->setRange(50, 250); ///< Slider range for card size adjustment.
|
||||
cardSizeSlider->setValue(defaultValue); ///< Initial slider value.
|
||||
|
||||
cardSizeLayout->addWidget(cardSizeLabel);
|
||||
cardSizeLayout->addWidget(cardSizeSlider);
|
||||
|
||||
if (flowWidget != nullptr) {
|
||||
connect(cardSizeSlider, &QSlider::valueChanged, flowWidget, &FlowWidget::setMinimumSizeToMaxSizeHint);
|
||||
}
|
||||
|
||||
// Debounce setup
|
||||
debounceTimer.setSingleShot(true);
|
||||
connect(&debounceTimer, &QTimer::timeout, this, [this] { emit cardSizeSettingUpdated(pendingValue); });
|
||||
|
||||
connect(cardSizeSlider, &QSlider::valueChanged, this, &CardSizeWidget::updateCardSizeSetting);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Updates the card size setting in the application's cache.
|
||||
*
|
||||
* @param newValue The new card size value set by the slider.
|
||||
*/
|
||||
void CardSizeWidget::updateCardSizeSetting(int newValue)
|
||||
{
|
||||
pendingValue = newValue;
|
||||
debounceTimer.start(300); // 300ms debounce time
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the slider widget used for adjusting the card size.
|
||||
*
|
||||
* @return A pointer to the QSlider object.
|
||||
*/
|
||||
QSlider *CardSizeWidget::getSlider() const
|
||||
{
|
||||
return cardSizeSlider;
|
||||
}
|
||||
41
cockatrice/src/interface/widgets/cards/card_size_widget.h
Normal file
41
cockatrice/src/interface/widgets/cards/card_size_widget.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#ifndef CARD_SIZE_WIDGET_H
|
||||
#define CARD_SIZE_WIDGET_H
|
||||
|
||||
#include "../general/layout_containers/flow_widget.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QSlider>
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
||||
class CardSizeWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CardSizeWidget(QWidget *parent, FlowWidget *flowWidget = nullptr, int defaultValue = 100);
|
||||
[[nodiscard]] QSlider *getSlider() const;
|
||||
|
||||
private slots:
|
||||
void updateCardSizeSetting(int newValue);
|
||||
|
||||
signals:
|
||||
/**
|
||||
* Emitted when the slider value changes, but on a debounce timer.
|
||||
* Any parents that care about saving the value to settings should use this signal to indicate when to save the new
|
||||
* value to settings.
|
||||
*/
|
||||
void cardSizeSettingUpdated(int newValue);
|
||||
|
||||
private:
|
||||
QWidget *parent;
|
||||
FlowWidget *flowWidget;
|
||||
QHBoxLayout *cardSizeLayout;
|
||||
QLabel *cardSizeLabel;
|
||||
QSlider *cardSizeSlider;
|
||||
QTimer debounceTimer; // Debounce timer
|
||||
int pendingValue; // Stores the latest slider value
|
||||
};
|
||||
|
||||
#endif // CARD_SIZE_WIDGET_H
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
#include "deck_card_zone_display_widget.h"
|
||||
|
||||
#include "../../../deck/deck_list_model.h"
|
||||
#include "../../../utility/card_info_comparator.h"
|
||||
#include "card_group_display_widgets/flat_card_group_display_widget.h"
|
||||
#include "card_group_display_widgets/overlapped_card_group_display_widget.h"
|
||||
|
||||
#include <QResizeEvent>
|
||||
|
||||
DeckCardZoneDisplayWidget::DeckCardZoneDisplayWidget(QWidget *parent,
|
||||
DeckListModel *_deckListModel,
|
||||
QPersistentModelIndex _trackedIndex,
|
||||
QString _zoneName,
|
||||
QString _activeGroupCriteria,
|
||||
QStringList _activeSortCriteria,
|
||||
DisplayType _displayType,
|
||||
int bannerOpacity,
|
||||
int subBannerOpacity,
|
||||
CardSizeWidget *_cardSizeWidget)
|
||||
: QWidget(parent), deckListModel(_deckListModel), trackedIndex(_trackedIndex), zoneName(_zoneName),
|
||||
activeGroupCriteria(_activeGroupCriteria), activeSortCriteria(_activeSortCriteria), displayType(_displayType),
|
||||
bannerOpacity(bannerOpacity), subBannerOpacity(subBannerOpacity), cardSizeWidget(_cardSizeWidget)
|
||||
{
|
||||
layout = new QVBoxLayout(this);
|
||||
setLayout(layout);
|
||||
|
||||
banner = new BannerWidget(this, zoneName, Qt::Orientation::Vertical, bannerOpacity);
|
||||
layout->addWidget(banner);
|
||||
|
||||
cardGroupContainer = new QWidget(this);
|
||||
cardGroupLayout = new QVBoxLayout(cardGroupContainer);
|
||||
cardGroupContainer->setLayout(cardGroupLayout);
|
||||
layout->addWidget(cardGroupContainer);
|
||||
|
||||
banner->setBuddy(cardGroupContainer);
|
||||
|
||||
displayCards();
|
||||
|
||||
connect(deckListModel, &QAbstractItemModel::rowsInserted, this, &DeckCardZoneDisplayWidget::onCategoryAddition);
|
||||
connect(deckListModel, &QAbstractItemModel::rowsRemoved, this, &DeckCardZoneDisplayWidget::onCategoryRemoval);
|
||||
}
|
||||
|
||||
void DeckCardZoneDisplayWidget::cleanupInvalidCardGroup(CardGroupDisplayWidget *displayWidget)
|
||||
{
|
||||
cardGroupLayout->removeWidget(displayWidget);
|
||||
displayWidget->setParent(nullptr);
|
||||
for (auto idx : indexToWidgetMap.keys()) {
|
||||
if (!idx.isValid()) {
|
||||
indexToWidgetMap.remove(idx);
|
||||
}
|
||||
}
|
||||
delete displayWidget;
|
||||
}
|
||||
|
||||
void DeckCardZoneDisplayWidget::constructAppropriateWidget(QPersistentModelIndex index)
|
||||
{
|
||||
auto categoryName = deckListModel->data(index.sibling(index.row(), 1), Qt::EditRole).toString();
|
||||
if (indexToWidgetMap.contains(index)) {
|
||||
return;
|
||||
}
|
||||
if (displayType == DisplayType::Overlap) {
|
||||
auto *displayWidget = new OverlappedCardGroupDisplayWidget(
|
||||
cardGroupContainer, deckListModel, index, zoneName, categoryName, activeGroupCriteria, activeSortCriteria,
|
||||
subBannerOpacity, cardSizeWidget);
|
||||
connect(displayWidget, &OverlappedCardGroupDisplayWidget::cardClicked, this,
|
||||
&DeckCardZoneDisplayWidget::onClick);
|
||||
connect(displayWidget, &OverlappedCardGroupDisplayWidget::cardHovered, this,
|
||||
&DeckCardZoneDisplayWidget::onHover);
|
||||
connect(displayWidget, &CardGroupDisplayWidget::cleanupRequested, this,
|
||||
&DeckCardZoneDisplayWidget::cleanupInvalidCardGroup);
|
||||
connect(this, &DeckCardZoneDisplayWidget::activeSortCriteriaChanged, displayWidget,
|
||||
&CardGroupDisplayWidget::onActiveSortCriteriaChanged);
|
||||
cardGroupLayout->addWidget(displayWidget);
|
||||
indexToWidgetMap.insert(index, displayWidget);
|
||||
} else if (displayType == DisplayType::Flat) {
|
||||
auto *displayWidget =
|
||||
new FlatCardGroupDisplayWidget(cardGroupContainer, deckListModel, index, zoneName, categoryName,
|
||||
activeGroupCriteria, activeSortCriteria, subBannerOpacity, cardSizeWidget);
|
||||
connect(displayWidget, &FlatCardGroupDisplayWidget::cardClicked, this, &DeckCardZoneDisplayWidget::onClick);
|
||||
connect(displayWidget, &FlatCardGroupDisplayWidget::cardHovered, this, &DeckCardZoneDisplayWidget::onHover);
|
||||
connect(displayWidget, &CardGroupDisplayWidget::cleanupRequested, this,
|
||||
&DeckCardZoneDisplayWidget::cleanupInvalidCardGroup);
|
||||
connect(this, &DeckCardZoneDisplayWidget::activeSortCriteriaChanged, displayWidget,
|
||||
&CardGroupDisplayWidget::onActiveSortCriteriaChanged);
|
||||
cardGroupLayout->addWidget(displayWidget);
|
||||
indexToWidgetMap.insert(index, displayWidget);
|
||||
}
|
||||
}
|
||||
|
||||
void DeckCardZoneDisplayWidget::displayCards()
|
||||
{
|
||||
QSortFilterProxyModel proxy;
|
||||
proxy.setSourceModel(deckListModel);
|
||||
proxy.setSortRole(Qt::EditRole);
|
||||
proxy.sort(1, Qt::AscendingOrder);
|
||||
|
||||
// 1. trackedIndex is a source index → map it to proxy space
|
||||
QModelIndex proxyParent = proxy.mapFromSource(trackedIndex);
|
||||
|
||||
// 2. iterate children under the proxy parent
|
||||
for (int i = 0; i < proxy.rowCount(proxyParent); ++i) {
|
||||
QModelIndex proxyIndex = proxy.index(i, 0, proxyParent);
|
||||
|
||||
// 3. map back to source
|
||||
QModelIndex sourceIndex = proxy.mapToSource(proxyIndex);
|
||||
|
||||
// 4. persist the source index
|
||||
QPersistentModelIndex persistent(sourceIndex);
|
||||
|
||||
constructAppropriateWidget(persistent);
|
||||
}
|
||||
}
|
||||
|
||||
void DeckCardZoneDisplayWidget::onCategoryAddition(const QModelIndex &parent, int first, int last)
|
||||
{
|
||||
if (!trackedIndex.isValid()) {
|
||||
emit requestCleanup(this);
|
||||
return;
|
||||
}
|
||||
if (parent == trackedIndex) {
|
||||
for (int i = first; i <= last; i++) {
|
||||
QPersistentModelIndex index = QPersistentModelIndex(deckListModel->index(i, 0, trackedIndex));
|
||||
|
||||
constructAppropriateWidget(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DeckCardZoneDisplayWidget::onCategoryRemoval(const QModelIndex &parent, int first, int last)
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
Q_UNUSED(first);
|
||||
Q_UNUSED(last);
|
||||
for (const QPersistentModelIndex &idx : indexToWidgetMap.keys()) {
|
||||
if (!idx.isValid()) {
|
||||
cardGroupLayout->removeWidget(indexToWidgetMap.value(idx));
|
||||
indexToWidgetMap.value(idx)->deleteLater();
|
||||
indexToWidgetMap.remove(idx);
|
||||
}
|
||||
}
|
||||
if (!trackedIndex.isValid()) {
|
||||
emit requestCleanup(this);
|
||||
}
|
||||
}
|
||||
|
||||
void DeckCardZoneDisplayWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
for (QObject *child : layout->children()) {
|
||||
QWidget *widget = qobject_cast<QWidget *>(child);
|
||||
if (widget) {
|
||||
widget->setMaximumWidth(width());
|
||||
}
|
||||
}
|
||||
}
|
||||
void DeckCardZoneDisplayWidget::onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card)
|
||||
{
|
||||
emit cardClicked(event, card, zoneName);
|
||||
}
|
||||
void DeckCardZoneDisplayWidget::onHover(const ExactCard &card)
|
||||
{
|
||||
emit cardHovered(card);
|
||||
}
|
||||
|
||||
void DeckCardZoneDisplayWidget::refreshDisplayType(const DisplayType &_displayType)
|
||||
{
|
||||
displayType = _displayType;
|
||||
QLayoutItem *item;
|
||||
while ((item = cardGroupLayout->takeAt(0)) != nullptr) {
|
||||
if (item->widget()) {
|
||||
item->widget()->deleteLater();
|
||||
} else if (item->layout()) {
|
||||
item->layout()->deleteLater();
|
||||
}
|
||||
delete item;
|
||||
}
|
||||
|
||||
indexToWidgetMap.clear();
|
||||
|
||||
// We gotta wait for all the deleteLater's to finish so we fire after the next event cycle
|
||||
|
||||
auto timer = new QTimer(this);
|
||||
timer->setSingleShot(true);
|
||||
connect(timer, &QTimer::timeout, this, [this]() { displayCards(); });
|
||||
timer->start();
|
||||
}
|
||||
|
||||
void DeckCardZoneDisplayWidget::onActiveGroupCriteriaChanged(QString _activeGroupCriteria)
|
||||
{
|
||||
activeGroupCriteria = _activeGroupCriteria;
|
||||
displayCards();
|
||||
}
|
||||
|
||||
void DeckCardZoneDisplayWidget::onActiveSortCriteriaChanged(QStringList _activeSortCriteria)
|
||||
{
|
||||
activeSortCriteria = _activeSortCriteria;
|
||||
emit activeSortCriteriaChanged(activeSortCriteria);
|
||||
}
|
||||
|
||||
QList<QString> DeckCardZoneDisplayWidget::getGroupCriteriaValueList()
|
||||
{
|
||||
QList<QString> groupCriteriaValues;
|
||||
|
||||
QList<ExactCard> cardsInZone = deckListModel->getCardsForZone(zoneName);
|
||||
|
||||
for (const ExactCard &cardInZone : cardsInZone) {
|
||||
groupCriteriaValues.append(cardInZone.getInfo().getProperty(activeGroupCriteria));
|
||||
}
|
||||
|
||||
groupCriteriaValues.removeDuplicates();
|
||||
groupCriteriaValues.sort();
|
||||
|
||||
return groupCriteriaValues;
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
#ifndef DECK_CARD_ZONE_DISPLAY_WIDGET_H
|
||||
#define DECK_CARD_ZONE_DISPLAY_WIDGET_H
|
||||
|
||||
#include "../../../card/card_info.h"
|
||||
#include "../../../deck/deck_list_model.h"
|
||||
#include "../general/display/banner_widget.h"
|
||||
#include "../general/layout_containers/overlap_widget.h"
|
||||
#include "../visual_deck_editor/visual_deck_editor_widget.h"
|
||||
#include "card_group_display_widgets/card_group_display_widget.h"
|
||||
#include "card_info_picture_with_text_overlay_widget.h"
|
||||
#include "card_size_widget.h"
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
class DeckCardZoneDisplayWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DeckCardZoneDisplayWidget(QWidget *parent,
|
||||
DeckListModel *deckListModel,
|
||||
QPersistentModelIndex trackedIndex,
|
||||
QString zoneName,
|
||||
QString activeGroupCriteria,
|
||||
QStringList activeSortCriteria,
|
||||
DisplayType displayType,
|
||||
int bannerOpacity,
|
||||
int subBannerOpacity,
|
||||
CardSizeWidget *_cardSizeWidget);
|
||||
DeckListModel *deckListModel;
|
||||
QPersistentModelIndex trackedIndex;
|
||||
QString zoneName;
|
||||
void addCardsToOverlapWidget();
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
public slots:
|
||||
void onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card);
|
||||
void onHover(const ExactCard &card);
|
||||
void cleanupInvalidCardGroup(CardGroupDisplayWidget *displayWidget);
|
||||
void constructAppropriateWidget(QPersistentModelIndex index);
|
||||
void displayCards();
|
||||
void refreshDisplayType(const DisplayType &displayType);
|
||||
void onActiveGroupCriteriaChanged(QString activeGroupCriteria);
|
||||
void onActiveSortCriteriaChanged(QStringList activeSortCriteria);
|
||||
QList<QString> getGroupCriteriaValueList();
|
||||
void onCategoryAddition(const QModelIndex &parent, int first, int last);
|
||||
void onCategoryRemoval(const QModelIndex &parent, int first, int last);
|
||||
|
||||
signals:
|
||||
void cardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card, QString zoneName);
|
||||
void cardHovered(const ExactCard &card);
|
||||
void activeSortCriteriaChanged(QStringList activeSortCriteria);
|
||||
void requestCleanup(DeckCardZoneDisplayWidget *displayWidget);
|
||||
|
||||
private:
|
||||
QString activeGroupCriteria;
|
||||
QStringList activeSortCriteria;
|
||||
DisplayType displayType = DisplayType::Overlap;
|
||||
int bannerOpacity = 20;
|
||||
int subBannerOpacity = 10;
|
||||
CardSizeWidget *cardSizeWidget;
|
||||
QVBoxLayout *layout;
|
||||
BannerWidget *banner;
|
||||
QWidget *cardGroupContainer;
|
||||
QVBoxLayout *cardGroupLayout;
|
||||
OverlapWidget *overlapWidget;
|
||||
QHash<QPersistentModelIndex, QWidget *> indexToWidgetMap;
|
||||
};
|
||||
|
||||
#endif // DECK_CARD_ZONE_DISPLAY_WIDGET_H
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
#include "deck_preview_card_picture_widget.h"
|
||||
|
||||
#include "../../../settings/cache_settings.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QFileInfo>
|
||||
#include <QFontMetrics>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainterPath>
|
||||
#include <QStylePainter>
|
||||
#include <QTextOption>
|
||||
|
||||
/**
|
||||
* @brief Constructs a CardPictureWithTextOverlay widget.
|
||||
* @param parent The parent widget.
|
||||
* @param hoverToZoomEnabled If this widget will spawn a larger widget when hovered over.
|
||||
* @param textColor The color of the overlay text.
|
||||
* @param outlineColor The color of the outline around the text.
|
||||
* @param fontSize The font size of the overlay text.
|
||||
* @param alignment The alignment of the text within the overlay.
|
||||
* @param _deckLoader The Deck Loader holding the Deck associated with this preview.
|
||||
*
|
||||
* Sets the widget's size policy and default border style.
|
||||
*/
|
||||
DeckPreviewCardPictureWidget::DeckPreviewCardPictureWidget(QWidget *parent,
|
||||
const bool hoverToZoomEnabled,
|
||||
const bool raiseOnEnter,
|
||||
const QColor &textColor,
|
||||
const QColor &outlineColor,
|
||||
const int fontSize,
|
||||
const Qt::Alignment alignment)
|
||||
: CardInfoPictureWithTextOverlayWidget(parent,
|
||||
hoverToZoomEnabled,
|
||||
raiseOnEnter,
|
||||
textColor,
|
||||
outlineColor,
|
||||
fontSize,
|
||||
alignment)
|
||||
{
|
||||
singleClickTimer = new QTimer(this);
|
||||
singleClickTimer->setSingleShot(true);
|
||||
connect(singleClickTimer, &QTimer::timeout, this, [this]() { emit imageClicked(lastMouseEvent, this); });
|
||||
connect(&SettingsCache::instance(), &SettingsCache::visualDeckStorageSelectionAnimationChanged, this,
|
||||
&CardInfoPictureWidget::setRaiseOnEnterEnabled);
|
||||
}
|
||||
|
||||
void DeckPreviewCardPictureWidget::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
lastMouseEvent = event;
|
||||
singleClickTimer->start(QApplication::doubleClickInterval());
|
||||
} else {
|
||||
emit imageClicked(event, this);
|
||||
event->accept();
|
||||
}
|
||||
}
|
||||
|
||||
void DeckPreviewCardPictureWidget::mouseDoubleClickEvent(QMouseEvent *event)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
singleClickTimer->stop(); // Prevent single-click logic
|
||||
emit imageDoubleClicked(lastMouseEvent, this);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef DECK_PREVIEW_CARD_PICTURE_WIDGET_H
|
||||
#define DECK_PREVIEW_CARD_PICTURE_WIDGET_H
|
||||
|
||||
#include "card_info_picture_with_text_overlay_widget.h"
|
||||
|
||||
#include <QColor>
|
||||
#include <QSize>
|
||||
#include <QTextOption>
|
||||
|
||||
class DeckPreviewCardPictureWidget final : public CardInfoPictureWithTextOverlayWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DeckPreviewCardPictureWidget(QWidget *parent,
|
||||
bool hoverToZoomEnabled = false,
|
||||
bool raiseOnEnter = false,
|
||||
const QColor &textColor = Qt::white,
|
||||
const QColor &outlineColor = Qt::black,
|
||||
int fontSize = 12,
|
||||
Qt::Alignment alignment = Qt::AlignCenter);
|
||||
|
||||
signals:
|
||||
void imageClicked(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
|
||||
void imageDoubleClicked(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
|
||||
|
||||
private:
|
||||
QTimer *singleClickTimer;
|
||||
QMouseEvent *lastMouseEvent = nullptr; // Store the last mouse event
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mouseDoubleClickEvent(QMouseEvent *event) override;
|
||||
};
|
||||
|
||||
#endif // DECK_PREVIEW_CARD_PICTURE_WIDGET_H
|
||||
Loading…
Add table
Add a link
Reference in a new issue