Merge branch 'master' into mergingCheckout

This commit is contained in:
Lily 2025-04-18 11:49:56 -04:00
commit 0879bc3430
No known key found for this signature in database
GPG key ID: 57E5B0E79E93B05C
290 changed files with 50236 additions and 34560 deletions

View file

@ -3,14 +3,13 @@
#include "../../../settings/cache_settings.h"
#include "../../../settings/shortcuts_settings.h"
DeckEditorMenu::DeckEditorMenu(QWidget *parent, AbstractTabDeckEditor *_deckEditor)
: QMenu(parent), deckEditor(_deckEditor)
DeckEditorMenu::DeckEditorMenu(AbstractTabDeckEditor *parent) : QMenu(parent), deckEditor(parent)
{
aNewDeck = new QAction(QString(), this);
connect(aNewDeck, SIGNAL(triggered()), deckEditor, SLOT(actNewDeck()));
connect(aNewDeck, &QAction::triggered, deckEditor, &AbstractTabDeckEditor::actNewDeck);
aLoadDeck = new QAction(QString(), this);
connect(aLoadDeck, SIGNAL(triggered()), deckEditor, SLOT(actLoadDeck()));
connect(aLoadDeck, &QAction::triggered, deckEditor, &AbstractTabDeckEditor::actLoadDeck);
loadRecentDeckMenu = new QMenu(this);
connect(&SettingsCache::instance().recents(), &RecentsSettings::recentlyOpenedDeckPathsChanged, this,
@ -22,47 +21,50 @@ DeckEditorMenu::DeckEditorMenu(QWidget *parent, AbstractTabDeckEditor *_deckEdit
updateRecentlyOpened();
aSaveDeck = new QAction(QString(), this);
connect(aSaveDeck, SIGNAL(triggered()), deckEditor, SLOT(actSaveDeck()));
connect(aSaveDeck, &QAction::triggered, deckEditor, &AbstractTabDeckEditor::actSaveDeck);
aSaveDeckAs = new QAction(QString(), this);
connect(aSaveDeckAs, SIGNAL(triggered()), deckEditor, SLOT(actSaveDeckAs()));
connect(aSaveDeckAs, &QAction::triggered, deckEditor, &AbstractTabDeckEditor::actSaveDeckAs);
aLoadDeckFromClipboard = new QAction(QString(), this);
connect(aLoadDeckFromClipboard, SIGNAL(triggered()), deckEditor, SLOT(actLoadDeckFromClipboard()));
connect(aLoadDeckFromClipboard, &QAction::triggered, deckEditor, &AbstractTabDeckEditor::actLoadDeckFromClipboard);
aEditDeckInClipboard = new QAction(QString(), this);
connect(aEditDeckInClipboard, SIGNAL(triggered()), deckEditor, SLOT(actEditDeckInClipboard()));
connect(aEditDeckInClipboard, &QAction::triggered, deckEditor, &AbstractTabDeckEditor::actEditDeckInClipboard);
aEditDeckInClipboardRaw = new QAction(QString(), this);
connect(aEditDeckInClipboardRaw, SIGNAL(triggered()), deckEditor, SLOT(actEditDeckInClipboardRaw()));
connect(aEditDeckInClipboardRaw, &QAction::triggered, deckEditor,
&AbstractTabDeckEditor::actEditDeckInClipboardRaw);
aSaveDeckToClipboard = new QAction(QString(), this);
connect(aSaveDeckToClipboard, SIGNAL(triggered()), deckEditor, SLOT(actSaveDeckToClipboard()));
connect(aSaveDeckToClipboard, &QAction::triggered, deckEditor, &AbstractTabDeckEditor::actSaveDeckToClipboard);
aSaveDeckToClipboardNoSetInfo = new QAction(QString(), this);
connect(aSaveDeckToClipboardNoSetInfo, SIGNAL(triggered()), deckEditor, SLOT(actSaveDeckToClipboardNoSetInfo()));
connect(aSaveDeckToClipboardNoSetInfo, &QAction::triggered, deckEditor,
&AbstractTabDeckEditor::actSaveDeckToClipboardNoSetInfo);
aSaveDeckToClipboardRaw = new QAction(QString(), this);
connect(aSaveDeckToClipboardRaw, SIGNAL(triggered()), deckEditor, SLOT(actSaveDeckToClipboardRaw()));
connect(aSaveDeckToClipboardRaw, &QAction::triggered, deckEditor,
&AbstractTabDeckEditor::actSaveDeckToClipboardRaw);
aSaveDeckToClipboardRawNoSetInfo = new QAction(QString(), this);
connect(aSaveDeckToClipboardRawNoSetInfo, SIGNAL(triggered()), deckEditor,
SLOT(actSaveDeckToClipboardRawNoSetInfo()));
connect(aSaveDeckToClipboardRawNoSetInfo, &QAction::triggered, deckEditor,
&AbstractTabDeckEditor::actSaveDeckToClipboardRawNoSetInfo);
aPrintDeck = new QAction(QString(), this);
connect(aPrintDeck, SIGNAL(triggered()), deckEditor, SLOT(actPrintDeck()));
connect(aPrintDeck, &QAction::triggered, deckEditor, &AbstractTabDeckEditor::actPrintDeck);
aExportDeckDecklist = new QAction(QString(), this);
connect(aExportDeckDecklist, SIGNAL(triggered()), deckEditor, SLOT(actExportDeckDecklist()));
connect(aExportDeckDecklist, &QAction::triggered, deckEditor, &AbstractTabDeckEditor::actExportDeckDecklist);
aExportDeckDecklistXyz = new QAction(QString(), this);
connect(aExportDeckDecklistXyz, SIGNAL(triggered()), deckEditor, SLOT(actExportDeckDecklistXyz()));
connect(aExportDeckDecklistXyz, &QAction::triggered, deckEditor, &AbstractTabDeckEditor::actExportDeckDecklistXyz);
aAnalyzeDeckDeckstats = new QAction(QString(), this);
connect(aAnalyzeDeckDeckstats, SIGNAL(triggered()), deckEditor, SLOT(actAnalyzeDeckDeckstats()));
connect(aAnalyzeDeckDeckstats, &QAction::triggered, deckEditor, &AbstractTabDeckEditor::actAnalyzeDeckDeckstats);
aAnalyzeDeckTappedout = new QAction(QString(), this);
connect(aAnalyzeDeckTappedout, SIGNAL(triggered()), deckEditor, SLOT(actAnalyzeDeckTappedout()));
connect(aAnalyzeDeckTappedout, &QAction::triggered, deckEditor, &AbstractTabDeckEditor::actAnalyzeDeckTappedout);
analyzeDeckMenu = new QMenu(this);
analyzeDeckMenu->addAction(aExportDeckDecklist);
@ -103,7 +105,8 @@ DeckEditorMenu::DeckEditorMenu(QWidget *parent, AbstractTabDeckEditor *_deckEdit
addAction(aClose);
retranslateUi();
connect(&SettingsCache::instance().shortcuts(), SIGNAL(shortCutChanged()), this, SLOT(refreshShortcuts()));
connect(&SettingsCache::instance().shortcuts(), &ShortcutsSettings::shortCutChanged, this,
&DeckEditorMenu::refreshShortcuts);
refreshShortcuts();
}

View file

@ -10,7 +10,7 @@ class DeckEditorMenu : public QMenu
{
Q_OBJECT
public:
explicit DeckEditorMenu(QWidget *parent, AbstractTabDeckEditor *deckEditor);
explicit DeckEditorMenu(AbstractTabDeckEditor *parent);
AbstractTabDeckEditor *deckEditor;

View file

@ -38,7 +38,7 @@ ReleaseChannel::~ReleaseChannel()
void ReleaseChannel::checkForUpdates()
{
QString releaseChannelUrl = getReleaseChannelUrl();
qCDebug(ReleaseChannelLog) << "Searching for updates on the channel: " << releaseChannelUrl;
qCInfo(ReleaseChannelLog) << "Searching for updates on the channel: " << releaseChannelUrl;
response = netMan->get(QNetworkRequest(releaseChannelUrl));
connect(response, &QNetworkReply::finished, this, &ReleaseChannel::releaseListFinished);
}
@ -152,15 +152,15 @@ void StableReleaseChannel::releaseListFinished()
QString shortHash = lastRelease->getCommitHash().left(GIT_SHORT_HASH_LEN);
QString myHash = QString(VERSION_COMMIT);
qCDebug(ReleaseChannelLog) << "Current hash=" << myHash << "update hash=" << shortHash;
qCInfo(ReleaseChannelLog) << "Current hash=" << myHash << "update hash=" << shortHash;
qCDebug(ReleaseChannelLog) << "Got reply from release server, name=" << lastRelease->getName()
<< "desc=" << lastRelease->getDescriptionUrl()
<< "date=" << lastRelease->getPublishDate() << "url=" << lastRelease->getDownloadUrl();
qCInfo(ReleaseChannelLog) << "Got reply from release server, name=" << lastRelease->getName()
<< "desc=" << lastRelease->getDescriptionUrl() << "date=" << lastRelease->getPublishDate()
<< "url=" << lastRelease->getDownloadUrl();
const QString &tagName = resultMap["tag_name"].toString();
QString url = QString(STABLETAG_URL) + tagName;
qCDebug(ReleaseChannelLog) << "Searching for commit hash corresponding to stable channel tag: " << tagName;
qCInfo(ReleaseChannelLog) << "Searching for commit hash corresponding to stable channel tag: " << tagName;
response = netMan->get(QNetworkRequest(url));
connect(response, &QNetworkReply::finished, this, &StableReleaseChannel::tagListFinished);
}
@ -185,11 +185,11 @@ void StableReleaseChannel::tagListFinished()
}
lastRelease->setCommitHash(resultMap["object"].toMap()["sha"].toString());
qCDebug(ReleaseChannelLog) << "Got reply from tag server, commit=" << lastRelease->getCommitHash();
qCInfo(ReleaseChannelLog) << "Got reply from tag server, commit=" << lastRelease->getCommitHash();
QString shortHash = lastRelease->getCommitHash().left(GIT_SHORT_HASH_LEN);
QString myHash = QString(VERSION_COMMIT);
qCDebug(ReleaseChannelLog) << "Current hash=" << myHash << "update hash=" << shortHash;
qCInfo(ReleaseChannelLog) << "Current hash=" << myHash << "update hash=" << shortHash;
const bool needToUpdate = (QString::compare(shortHash, myHash, Qt::CaseInsensitive) != 0);
emit finishedCheck(needToUpdate, lastRelease->isCompatibleVersionFound(), lastRelease);
@ -256,13 +256,13 @@ void BetaReleaseChannel::releaseListFinished()
lastRelease->setName(QString("%1 (%2)").arg(resultMap["tag_name"].toString()).arg(shortHash));
lastRelease->setDescriptionUrl(QString(BETARELEASE_CHANGESURL).arg(VERSION_COMMIT, shortHash));
qCDebug(ReleaseChannelLog) << "Got reply from release server, size=" << resultMap.size()
<< "name=" << lastRelease->getName() << "desc=" << lastRelease->getDescriptionUrl()
<< "commit=" << lastRelease->getCommitHash() << "date=" << lastRelease->getPublishDate();
qCInfo(ReleaseChannelLog) << "Got reply from release server, size=" << resultMap.size()
<< "name=" << lastRelease->getName() << "desc=" << lastRelease->getDescriptionUrl()
<< "commit=" << lastRelease->getCommitHash() << "date=" << lastRelease->getPublishDate();
QString betaBuildDownloadUrl = resultMap["assets_url"].toString();
qCDebug(ReleaseChannelLog) << "Searching for a corresponding file on the beta channel: " << betaBuildDownloadUrl;
qCInfo(ReleaseChannelLog) << "Searching for a corresponding file on the beta channel: " << betaBuildDownloadUrl;
response = netMan->get(QNetworkRequest(betaBuildDownloadUrl));
connect(response, &QNetworkReply::finished, this, &BetaReleaseChannel::fileListFinished);
}
@ -282,7 +282,7 @@ void BetaReleaseChannel::fileListFinished()
QVariantList resultList = jsonResponse.toVariant().toList();
QString shortHash = lastRelease->getCommitHash().left(GIT_SHORT_HASH_LEN);
QString myHash = QString(VERSION_COMMIT);
qCDebug(ReleaseChannelLog) << "Current hash=" << myHash << "update hash=" << shortHash;
qCInfo(ReleaseChannelLog) << "Current hash=" << myHash << "update hash=" << shortHash;
bool needToUpdate = (QString::compare(shortHash, myHash, Qt::CaseInsensitive) != 0);
bool compatibleVersion = false;
@ -299,7 +299,7 @@ void BetaReleaseChannel::fileListFinished()
if (downloadMatchesCurrentOS(*url)) {
compatibleVersion = true;
lastRelease->setDownloadUrl(*url);
qCDebug(ReleaseChannelLog) << "Found compatible version url=" << *url;
qCInfo(ReleaseChannelLog) << "Found compatible version url=" << *url;
break;
}
}

View file

@ -28,7 +28,7 @@ SpoilerBackgroundUpdater::SpoilerBackgroundUpdater(QObject *apParent) : QObject(
// File exists means we're in spoiler season
startSpoilerDownloadProcess(SPOILERS_STATUS_URL, false);
} else {
qCDebug(SpoilerBackgroundUpdaterLog) << "Spoilers Disabled";
qCInfo(SpoilerBackgroundUpdaterLog) << "Spoilers Disabled";
}
}
@ -67,7 +67,7 @@ void SpoilerBackgroundUpdater::actDownloadFinishedSpoilersFile()
reply->deleteLater();
emit spoilerCheckerDone();
} else {
qCDebug(SpoilerBackgroundUpdaterLog) << "Error downloading spoilers file" << errorCode;
qCWarning(SpoilerBackgroundUpdaterLog) << "Error downloading spoilers file" << errorCode;
emit spoilerCheckerDone();
}
}
@ -81,11 +81,11 @@ bool SpoilerBackgroundUpdater::deleteSpoilerFile()
// Delete the spoiler.xml file
if (file.exists() && file.remove()) {
qCDebug(SpoilerBackgroundUpdaterLog) << "Deleting spoiler.xml";
qCInfo(SpoilerBackgroundUpdaterLog) << "Deleting spoiler.xml";
return true;
}
qCDebug(SpoilerBackgroundUpdaterLog) << "Error: Spoiler.xml not found or not deleted";
qCInfo(SpoilerBackgroundUpdaterLog) << "Error: Spoiler.xml not found or not deleted";
return false;
}
@ -101,24 +101,24 @@ void SpoilerBackgroundUpdater::actCheckIfSpoilerSeasonEnabled()
trayIcon->showMessage(tr("Spoilers season has ended"), tr("Deleting spoiler.xml. Please run Oracle"));
}
qCDebug(SpoilerBackgroundUpdaterLog) << "Spoiler Season Offline";
qCInfo(SpoilerBackgroundUpdaterLog) << "Spoiler Season Offline";
emit spoilerCheckerDone();
} else if (errorCode == QNetworkReply::NoError) {
qCDebug(SpoilerBackgroundUpdaterLog) << "Spoiler Service Online";
qCInfo(SpoilerBackgroundUpdaterLog) << "Spoiler Service Online";
startSpoilerDownloadProcess(SPOILERS_URL, true);
} else if (errorCode == QNetworkReply::HostNotFoundError) {
if (trayIcon) {
trayIcon->showMessage(tr("Spoilers download failed"), tr("No internet connection"));
}
qCDebug(SpoilerBackgroundUpdaterLog) << "Spoiler download failed due to no internet connection";
qCWarning(SpoilerBackgroundUpdaterLog) << "Spoiler download failed due to no internet connection";
emit spoilerCheckerDone();
} else {
if (trayIcon) {
trayIcon->showMessage(tr("Spoilers download failed"), tr("Error") + " " + (short)errorCode);
}
qCDebug(SpoilerBackgroundUpdaterLog) << "Spoiler download failed with reason" << errorCode;
qCWarning(SpoilerBackgroundUpdaterLog) << "Spoiler download failed with reason" << errorCode;
emit spoilerCheckerDone();
}
}
@ -139,19 +139,19 @@ bool SpoilerBackgroundUpdater::saveDownloadedFile(QByteArray data)
trayIcon->showMessage(tr("Spoilers already up to date"), tr("No new spoilers added"));
}
qCDebug(SpoilerBackgroundUpdaterLog) << "Spoilers Up to Date";
qCInfo(SpoilerBackgroundUpdaterLog) << "Spoilers Up to Date";
return false;
}
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly)) {
qCDebug(SpoilerBackgroundUpdaterLog) << "Spoiler Service Error: File open (w) failed for" << fileName;
qCWarning(SpoilerBackgroundUpdaterLog) << "Spoiler Service Error: File open (w) failed for" << fileName;
file.close();
return false;
}
if (file.write(data) == -1) {
qCDebug(SpoilerBackgroundUpdaterLog) << "Spoiler Service Error: File write (w) failed for" << fileName;
qCWarning(SpoilerBackgroundUpdaterLog) << "Spoiler Service Error: File write (w) failed for" << fileName;
file.close();
return false;
}
@ -159,7 +159,7 @@ bool SpoilerBackgroundUpdater::saveDownloadedFile(QByteArray data)
file.close();
// Data written, so reload the card database
qCDebug(SpoilerBackgroundUpdaterLog) << "Spoiler Service Data Written";
qCInfo(SpoilerBackgroundUpdaterLog) << "Spoiler Service Data Written";
const auto reloadOk = QtConcurrent::run([] { CardDatabaseManager::getInstance()->loadCardDatabases(); });
// If the user has notifications enabled, let them know
@ -202,12 +202,12 @@ QByteArray SpoilerBackgroundUpdater::getHash(const QString fileName)
QCryptographicHash hash(QCryptographicHash::Algorithm::Md5);
hash.addData(bytes);
qCDebug(SpoilerBackgroundUpdaterLog) << "File Hash =" << hash.result();
qCInfo(SpoilerBackgroundUpdaterLog) << "File Hash =" << hash.result();
file.close();
return hash.result();
} else {
qCDebug(SpoilerBackgroundUpdaterLog) << "getHash ReadOnly failed!";
qCWarning(SpoilerBackgroundUpdaterLog) << "getHash ReadOnly failed!";
file.close();
return QByteArray();
}
@ -221,7 +221,7 @@ QByteArray SpoilerBackgroundUpdater::getHash(QByteArray data)
QCryptographicHash hash(QCryptographicHash::Algorithm::Md5);
hash.addData(bytes);
qCDebug(SpoilerBackgroundUpdaterLog) << "Data Hash =" << hash.result();
qCInfo(SpoilerBackgroundUpdaterLog) << "Data Hash =" << hash.result();
return hash.result();
}

View file

@ -37,7 +37,7 @@ SoundEngine::~SoundEngine()
void SoundEngine::soundEnabledChanged()
{
if (SettingsCache::instance().getSoundEnabled()) {
qCDebug(SoundEngineLog) << "SoundEngine: enabling sound with" << audioData.size() << "sounds";
qCInfo(SoundEngineLog) << "SoundEngine: enabling sound with" << audioData.size() << "sounds";
if (!player) {
player = new QMediaPlayer;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
@ -46,7 +46,7 @@ void SoundEngine::soundEnabledChanged()
#endif
}
} else {
qCDebug(SoundEngineLog) << "SoundEngine: disabling sound";
qCInfo(SoundEngineLog) << "SoundEngine: disabling sound";
if (player) {
player->stop();
player->deleteLater();
@ -90,7 +90,7 @@ void SoundEngine::ensureThemeDirectoryExists()
{
if (SettingsCache::instance().getSoundThemeName().isEmpty() ||
!getAvailableThemes().contains(SettingsCache::instance().getSoundThemeName())) {
qCDebug(SoundEngineLog) << "Sounds theme name not set, setting default value";
qCInfo(SoundEngineLog) << "Sounds theme name not set, setting default value";
SettingsCache::instance().setSoundThemeName(DEFAULT_THEME_NAME);
}
}
@ -131,7 +131,7 @@ QStringMap &SoundEngine::getAvailableThemes()
void SoundEngine::themeChangedSlot()
{
QString themeName = SettingsCache::instance().getSoundThemeName();
qCDebug(SoundEngineLog) << "Sound theme changed:" << themeName;
qCInfo(SoundEngineLog) << "Sound theme changed:" << themeName;
QDir dir = getAvailableThemes().value(themeName);

View file

@ -30,6 +30,7 @@
#include <QMenuBar>
#include <QMessageBox>
#include <QPrintPreviewDialog>
#include <QPrinter>
#include <QProcessEnvironment>
#include <QPushButton>
#include <QRegularExpression>
@ -65,7 +66,8 @@ AbstractTabDeckEditor::AbstractTabDeckEditor(TabSupervisor *_tabSupervisor) : Ta
connect(filterDockWidget, &DeckEditorFilterDockWidget::clearAllDatabaseFilters, databaseDisplayDockWidget,
&DeckEditorDatabaseDisplayWidget::clearAllDatabaseFilters);
connect(&SettingsCache::instance().shortcuts(), SIGNAL(shortCutChanged()), this, SLOT(refreshShortcuts()));
connect(&SettingsCache::instance().shortcuts(), &ShortcutsSettings::shortCutChanged, this,
&AbstractTabDeckEditor::refreshShortcuts);
}
void AbstractTabDeckEditor::updateCard(CardInfoPtr _card)
@ -124,8 +126,13 @@ void AbstractTabDeckEditor::actSwapCard(CardInfoPtr info, QString zoneName)
{
QString providerId = CardDatabaseManager::getInstance()->getSetInfoForCard(info).getProperty("uuid");
QString collectorNumber = CardDatabaseManager::getInstance()->getSetInfoForCard(info).getProperty("num");
deckDockWidget->swapCard(
deckDockWidget->deckModel->findCard(info->getName(), zoneName, providerId, collectorNumber));
QModelIndex foundCard = deckDockWidget->deckModel->findCard(info->getName(), zoneName, providerId, collectorNumber);
if (!foundCard.isValid()) {
foundCard = deckDockWidget->deckModel->findCard(info->getName(), zoneName);
}
deckDockWidget->swapCard(foundCard);
}
/**
@ -332,8 +339,7 @@ bool AbstractTabDeckEditor::actSaveDeck()
cmd.set_deck_list(deckString.toStdString());
PendingCommand *pend = AbstractClient::prepareSessionCommand(cmd);
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
SLOT(saveDeckRemoteFinished(Response)));
connect(pend, &PendingCommand::finished, this, &AbstractTabDeckEditor::saveDeckRemoteFinished);
tabSupervisor->getClient()->sendCommand(pend);
return true;
@ -357,6 +363,7 @@ bool AbstractTabDeckEditor::actSaveDeckAs()
dialog.setDefaultSuffix("cod");
dialog.setNameFilters(DeckLoader::FILE_NAME_FILTERS);
dialog.selectFile(getDeckList()->getName().trimmed());
if (!dialog.exec())
return false;
@ -451,7 +458,7 @@ void AbstractTabDeckEditor::actSaveDeckToClipboardRawNoSetInfo()
void AbstractTabDeckEditor::actPrintDeck()
{
auto *dlg = new QPrintPreviewDialog(this);
connect(dlg, SIGNAL(paintRequested(QPrinter *)), deckDockWidget->deckModel, SLOT(printDeckList(QPrinter *)));
connect(dlg, &QPrintPreviewDialog::paintRequested, deckDockWidget->deckModel, &DeckListModel::printDeckList);
dlg->exec();
}

View file

@ -1,7 +1,7 @@
#ifndef TAB_GENERIC_DECK_EDITOR_H
#define TAB_GENERIC_DECK_EDITOR_H
#include "../../game/cards/card_database.h"
#include "../../game/cards/card_info.h"
#include "../menus/deck_editor/deck_editor_menu.h"
#include "../ui/widgets/deck_editor/deck_editor_card_info_dock_widget.h"
#include "../ui/widgets/deck_editor/deck_editor_database_display_widget.h"
@ -44,6 +44,8 @@ class AbstractTabDeckEditor : public Tab
{
Q_OBJECT
friend class DeckEditorMenu;
public:
explicit AbstractTabDeckEditor(TabSupervisor *_tabSupervisor);
@ -67,7 +69,7 @@ public:
DeckEditorPrintingSelectorDockWidget *printingSelectorDockWidget;
public slots:
void onDeckChanged();
virtual void onDeckChanged();
void updateCard(CardInfoPtr _card);
void actAddCard(CardInfoPtr info);
void actAddCardToSideboard(CardInfoPtr info);
@ -90,7 +92,7 @@ protected slots:
void cleanDeckAndResetModified();
virtual void actLoadDeck();
bool actSaveDeck();
bool actSaveDeckAs();
virtual bool actSaveDeckAs();
virtual void actLoadDeckFromClipboard();
void actEditDeckInClipboard();
void actEditDeckInClipboardRaw();

View file

@ -0,0 +1,47 @@
#include "edhrec_average_deck_api_response.h"
#include <QDebug>
#include <QJsonArray>
void EdhrecAverageDeckApiResponse::fromJson(const QJsonObject &json)
{
// Parse the collapsed DeckStatistics
deckStats.fromJson(json);
// Parse Archidekt section
QJsonArray archidektJson = json.value("archidekt").toArray();
archidekt.fromJson(archidektJson);
// Parse other fields
similar = json.value("similar").toObject();
header = json.value("header").toString();
panels = json.value("panels").toObject();
description = json.value("description").toString();
QJsonObject containerJson = json.value("container").toObject();
container.fromJson(containerJson);
QJsonArray cardsJson = json.value("deck").toArray();
deck.fromJson(cardsJson);
}
void EdhrecAverageDeckApiResponse::debugPrint() const
{
qDebug() << "Deck Statistics:";
qDebug() << " Creature:" << deckStats.creature;
qDebug() << " Instant:" << deckStats.instant;
qDebug() << " Sorcery:" << deckStats.sorcery;
qDebug() << " Artifact:" << deckStats.artifact;
qDebug() << " Enchantment:" << deckStats.enchantment;
qDebug() << " Battle:" << deckStats.battle;
qDebug() << " Planeswalker:" << deckStats.planeswalker;
qDebug() << " Land:" << deckStats.land;
qDebug() << " Basic:" << deckStats.basic;
qDebug() << " Nonbasic:" << deckStats.nonbasic;
archidekt.debugPrint();
qDebug() << "Similar:" << similar;
qDebug() << "Header:" << header;
qDebug() << "Panels:" << panels;
qDebug() << "Description:" << description;
container.debugPrint();
}

View file

@ -0,0 +1,30 @@
#ifndef EDHREC_AVERAGE_DECK_API_RESPONSE_H
#define EDHREC_AVERAGE_DECK_API_RESPONSE_H
#include "../commander/edhrec_commander_api_response_archidekt_links.h"
#include "../commander/edhrec_commander_api_response_average_deck_statistics.h"
#include "../commander/edhrec_commander_api_response_card_container.h"
#include "edhrec_deck_api_response.h"
#include <QDebug>
#include <QJsonObject>
#include <QString>
// Represents the main structure of the JSON
class EdhrecAverageDeckApiResponse
{
public:
EdhrecCommanderApiResponseAverageDeckStatistics deckStats;
EdhrecCommanderApiResponseArchidektLinks archidekt;
QJsonObject similar;
QString header;
QJsonObject panels;
QString description;
EdhrecCommanderApiResponseCardContainer container;
EdhrecDeckApiResponse deck;
void fromJson(const QJsonObject &json);
void debugPrint() const;
};
#endif // EDHREC_AVERAGE_DECK_API_RESPONSE_H

View file

@ -0,0 +1,27 @@
#include "edhrec_deck_api_response.h"
#include "../../../../../../deck/deck_loader.h"
#include <QApplication>
#include <QDebug>
#include <QJsonArray>
#include <QJsonObject>
#include <QMainWindow>
void EdhrecDeckApiResponse::fromJson(const QJsonArray &json)
{
QString deckList;
for (const QJsonValue &cardlistValue : json) {
deckList += cardlistValue.toString() + "\n";
}
deckLoader = new DeckLoader();
QTextStream stream(&deckList);
deckLoader->loadFromStream_Plain(stream, true);
}
void EdhrecDeckApiResponse::debugPrint() const
{
qDebug() << "Breadcrumb:";
}

View file

@ -0,0 +1,27 @@
#ifndef EDHREC_DECK_API_RESPONSE_H
#define EDHREC_DECK_API_RESPONSE_H
#include "../../../../../../deck/deck_loader.h"
#include <QDebug>
#include <QJsonArray>
#include <QJsonObject>
#include <QString>
#include <QVector>
class EdhrecDeckApiResponse
{
public:
// Constructor
EdhrecDeckApiResponse() = default;
// Parse deck-related data from JSON
void fromJson(const QJsonArray &json);
// Debug method for logging
void debugPrint() const;
DeckLoader *deckLoader;
};
#endif // EDHREC_DECK_API_RESPONSE_H

View file

@ -0,0 +1,19 @@
#include "edhrec_top_cards_api_response.h"
#include <QDebug>
#include <QJsonArray>
void EdhrecTopCardsApiResponse::fromJson(const QJsonObject &json)
{
header = json.value("header").toString();
description = json.value("description").toString();
QJsonObject containerJson = json.value("container").toObject();
container.fromJson(containerJson);
}
void EdhrecTopCardsApiResponse::debugPrint() const
{
qDebug() << "Header:" << header;
qDebug() << "Description:" << description;
container.debugPrint();
}

View file

@ -0,0 +1,22 @@
#ifndef EDHREC_TOP_CARDS_API_RESPONSE_H
#define EDHREC_TOP_CARDS_API_RESPONSE_H
#include "../commander/edhrec_commander_api_response_card_container.h"
#include <QDebug>
#include <QJsonObject>
#include <QString>
// Represents the main structure of the JSON
class EdhrecTopCardsApiResponse
{
public:
QString header;
QString description;
EdhrecCommanderApiResponseCardContainer container;
void fromJson(const QJsonObject &json);
void debugPrint() const;
};
#endif // EDHREC_TOP_CARDS_API_RESPONSE_H

View file

@ -0,0 +1,19 @@
#include "edhrec_top_commanders_api_response.h"
#include <QDebug>
#include <QJsonArray>
void EdhrecTopCommandersApiResponse::fromJson(const QJsonObject &json)
{
header = json.value("header").toString();
description = json.value("description").toString();
QJsonObject containerJson = json.value("container").toObject();
container.fromJson(containerJson);
}
void EdhrecTopCommandersApiResponse::debugPrint() const
{
qDebug() << "Header:" << header;
qDebug() << "Description:" << description;
container.debugPrint();
}

View file

@ -0,0 +1,22 @@
#ifndef EDHREC_TOP_COMMANDERS_API_RESPONSE_H
#define EDHREC_TOP_COMMANDERS_API_RESPONSE_H
#include "../commander/edhrec_commander_api_response_card_container.h"
#include <QDebug>
#include <QJsonObject>
#include <QString>
// Represents the main structure of the JSON
class EdhrecTopCommandersApiResponse
{
public:
QString header;
QString description;
EdhrecCommanderApiResponseCardContainer container;
void fromJson(const QJsonObject &json);
void debugPrint() const;
};
#endif // EDHREC_TOP_COMMANDERS_API_RESPONSE_H

View file

@ -0,0 +1,19 @@
#include "edhrec_top_tags_api_response.h"
#include <QDebug>
#include <QJsonArray>
void EdhrecTopTagsApiResponse::fromJson(const QJsonObject &json)
{
header = json.value("header").toString();
description = json.value("description").toString();
QJsonObject containerJson = json.value("container").toObject();
container.fromJson(containerJson);
}
void EdhrecTopTagsApiResponse::debugPrint() const
{
qDebug() << "Header:" << header;
qDebug() << "Description:" << description;
container.debugPrint();
}

View file

@ -0,0 +1,22 @@
#ifndef EDHREC_TOP_TAGS_API_RESPONSE_H
#define EDHREC_TOP_TAGS_API_RESPONSE_H
#include "../commander/edhrec_commander_api_response_card_container.h"
#include <QDebug>
#include <QJsonObject>
#include <QString>
// Represents the main structure of the JSON
class EdhrecTopTagsApiResponse
{
public:
QString header;
QString description;
EdhrecCommanderApiResponseCardContainer container;
void fromJson(const QJsonObject &json);
void debugPrint() const;
};
#endif // EDHREC_TOP_TAGS_API_RESPONSE_H

View file

@ -1,6 +1,7 @@
#include "edhrec_commander_api_response_card_details_display_widget.h"
#include "../../../../game/cards/card_database_manager.h"
#include "../../../../../../game/cards/card_database_manager.h"
#include "../../tab_edhrec_main.h"
EdhrecCommanderApiResponseCardDetailsDisplayWidget::EdhrecCommanderApiResponseCardDetailsDisplayWidget(
QWidget *parent,
@ -11,14 +12,17 @@ EdhrecCommanderApiResponseCardDetailsDisplayWidget::EdhrecCommanderApiResponseCa
setLayout(layout);
cardPictureWidget = new CardInfoPictureWidget(this);
cardPictureWidget->setCard(CardDatabaseManager::getInstance()->getCard(toDisplay.name));
cardPictureWidget->setCard(CardDatabaseManager::getInstance()->guessCard(toDisplay.sanitized));
label = new QLabel(this);
label->setText(toDisplay.name + "\n" + toDisplay.label);
label->setAlignment(Qt::AlignHCenter);
int inclusionRate = 0;
// Set label color based on inclusion rate
int inclusionRate = (toDisplay.numDecks * 100) / toDisplay.potentialDecks;
if (toDisplay.potentialDecks != 0) {
inclusionRate = (toDisplay.numDecks * 100) / toDisplay.potentialDecks;
}
QColor labelColor;
if (inclusionRate <= 30) {
@ -38,4 +42,26 @@ EdhrecCommanderApiResponseCardDetailsDisplayWidget::EdhrecCommanderApiResponseCa
layout->addWidget(cardPictureWidget);
layout->addWidget(label);
QWidget *currentParent = parentWidget();
TabEdhRecMain *parentTab = nullptr;
while (currentParent) {
if ((parentTab = qobject_cast<TabEdhRecMain *>(currentParent))) {
break;
}
currentParent = currentParent->parentWidget();
}
if (parentTab) {
connect(cardPictureWidget, &CardInfoPictureWidget::cardClicked, this,
&EdhrecCommanderApiResponseCardDetailsDisplayWidget::actRequestPageNavigation);
connect(this, &EdhrecCommanderApiResponseCardDetailsDisplayWidget::requestUrl, parentTab,
&TabEdhRecMain::actNavigatePage);
}
}
void EdhrecCommanderApiResponseCardDetailsDisplayWidget::actRequestPageNavigation()
{
emit requestUrl(toDisplay.url);
}

View file

@ -1,8 +1,8 @@
#ifndef EDHREC_COMMANDER_API_RESPONSE_CARD_DETAILS_DISPLAY_WIDGET_H
#define EDHREC_COMMANDER_API_RESPONSE_CARD_DETAILS_DISPLAY_WIDGET_H
#include "../../../ui/widgets/cards/card_info_picture_widget.h"
#include "api_response/edhrec_commander_api_response_card_details.h"
#include "../../../../../ui/widgets/cards/card_info_picture_widget.h"
#include "../../api_response/commander/edhrec_commander_api_response_card_details.h"
#include <QHBoxLayout>
#include <QLabel>
@ -15,6 +15,10 @@ public:
explicit EdhrecCommanderApiResponseCardDetailsDisplayWidget(
QWidget *parent,
const EdhrecCommanderApiResponseCardDetails &_toDisplay);
public slots:
void actRequestPageNavigation();
signals:
void requestUrl(QString url);
private:
EdhrecCommanderApiResponseCardDetails toDisplay;

View file

@ -1,6 +1,6 @@
#include "edhrec_commander_api_response_card_list_display_widget.h"
#include "../../../ui/widgets/general/display/banner_widget.h"
#include "../../../../../ui/widgets/general/display/banner_widget.h"
#include "edhrec_commander_api_response_card_details_display_widget.h"
#include <QLabel>

View file

@ -1,9 +1,9 @@
#ifndef EDHREC_COMMANDER_API_RESPONSE_CARD_LIST_DISPLAY_WIDGET_H
#define EDHREC_COMMANDER_API_RESPONSE_CARD_LIST_DISPLAY_WIDGET_H
#include "../../../ui/widgets/general/display/banner_widget.h"
#include "../../../ui/widgets/general/layout_containers/flow_widget.h"
#include "api_response/edhrec_commander_api_response_card_list.h"
#include "../../../../../ui/widgets/general/display/banner_widget.h"
#include "../../../../../ui/widgets/general/layout_containers/flow_widget.h"
#include "../../api_response/commander/edhrec_commander_api_response_card_list.h"
#include <QResizeEvent>
#include <QVBoxLayout>

View file

@ -0,0 +1,75 @@
#include "edhrec_commander_api_response_commander_details_display_widget.h"
#include "../../../../../../game/cards/card_database_manager.h"
#include "../../../../../ui/widgets/cards/card_info_picture_widget.h"
#include "../../tab_edhrec_main.h"
#include <QLabel>
#include <QPushButton>
EdhrecCommanderResponseCommanderDetailsDisplayWidget::EdhrecCommanderResponseCommanderDetailsDisplayWidget(
QWidget *parent,
const EdhrecCommanderApiResponseCommanderDetails &_commanderDetails)
: QWidget(parent), commanderDetails(_commanderDetails)
{
layout = new QVBoxLayout(this);
setLayout(layout);
commanderPicture = new CardInfoPictureWidget(this);
commanderPicture->setCard(CardDatabaseManager::getInstance()->getCard(commanderDetails.getName()));
commanderDetails.debugPrint();
label = new QLabel(this);
label->setAlignment(Qt::AlignCenter);
salt = new QLabel(this);
salt->setAlignment(Qt::AlignCenter);
comboPushButton = new QPushButton(this);
averageDeckPushButton = new QPushButton(this);
layout->addWidget(commanderPicture);
layout->addWidget(label);
layout->addWidget(salt);
layout->addWidget(comboPushButton);
layout->addWidget(averageDeckPushButton);
QWidget *currentParent = parentWidget();
TabEdhRecMain *parentTab = nullptr;
while (currentParent) {
if ((parentTab = qobject_cast<TabEdhRecMain *>(currentParent))) {
break;
}
currentParent = currentParent->parentWidget();
}
if (parentTab) {
connect(comboPushButton, &QPushButton::clicked, this,
&EdhrecCommanderResponseCommanderDetailsDisplayWidget::actRequestComboNavigation);
connect(averageDeckPushButton, &QPushButton::clicked, this,
&EdhrecCommanderResponseCommanderDetailsDisplayWidget::actRequestAverageDeckNavigation);
connect(this, &EdhrecCommanderResponseCommanderDetailsDisplayWidget::requestUrl, parentTab,
&TabEdhRecMain::actNavigatePage);
}
retranslateUi();
}
void EdhrecCommanderResponseCommanderDetailsDisplayWidget::retranslateUi()
{
label->setText(commanderDetails.getLabel());
salt->setText(tr("Salt: ") + QString::number(commanderDetails.getSalt()));
comboPushButton->setText(tr("Combos"));
averageDeckPushButton->setText(tr("Average Deck"));
}
void EdhrecCommanderResponseCommanderDetailsDisplayWidget::actRequestComboNavigation()
{
emit requestUrl("/combos/" + commanderDetails.getSanitized());
}
void EdhrecCommanderResponseCommanderDetailsDisplayWidget::actRequestAverageDeckNavigation()
{
emit requestUrl("/average-decks/" + commanderDetails.getSanitized());
}

View file

@ -1,10 +1,11 @@
#ifndef EDHREC_COMMANDER_API_RESPONSE_COMMANDER_DETAILS_DISPLAY_WIDGET_H
#define EDHREC_COMMANDER_API_RESPONSE_COMMANDER_DETAILS_DISPLAY_WIDGET_H
#include "../../../ui/widgets/cards/card_info_picture_widget.h"
#include "api_response/edhrec_commander_api_response_commander_details.h"
#include "../../../../../ui/widgets/cards/card_info_picture_widget.h"
#include "../../api_response/commander/edhrec_commander_api_response_commander_details.h"
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>
@ -17,9 +18,17 @@ public:
const EdhrecCommanderApiResponseCommanderDetails &_commanderDetails);
void retranslateUi();
public slots:
void actRequestComboNavigation();
void actRequestAverageDeckNavigation();
signals:
void requestUrl(QString url);
private:
QLabel *label;
QLabel *salt;
QPushButton *comboPushButton;
QPushButton *averageDeckPushButton;
QVBoxLayout *layout;
CardInfoPictureWidget *commanderPicture;
EdhrecCommanderApiResponseCommanderDetails commanderDetails;

View file

@ -1,7 +1,7 @@
#include "edhrec_commander_api_response_display_widget.h"
#include "../../../ui/widgets/cards/card_info_picture_widget.h"
#include "api_response/edhrec_commander_api_response.h"
#include "../../../../../ui/widgets/cards/card_info_picture_widget.h"
#include "../../api_response/commander/edhrec_commander_api_response.h"
#include "edhrec_commander_api_response_card_list_display_widget.h"
#include "edhrec_commander_api_response_commander_details_display_widget.h"

View file

@ -1,7 +1,7 @@
#ifndef EDHREC_COMMANDER_API_RESPONSE_DISPLAY_WIDGET_H
#define EDHREC_COMMANDER_API_RESPONSE_DISPLAY_WIDGET_H
#include "api_response/edhrec_commander_api_response.h"
#include "../../api_response/commander/edhrec_commander_api_response.h"
#include <QScrollArea>
#include <QVBoxLayout>

View file

@ -0,0 +1,45 @@
#include "edhrec_top_cards_api_response_display_widget.h"
#include "../../api_response/top_cards/edhrec_top_cards_api_response.h"
#include "../commander/edhrec_commander_api_response_card_list_display_widget.h"
EdhrecTopCardsApiResponseDisplayWidget::EdhrecTopCardsApiResponseDisplayWidget(QWidget *parent,
EdhrecTopCardsApiResponse response)
: QWidget(parent)
{
layout = new QHBoxLayout(this);
setLayout(layout);
cardDisplayLayout = new QVBoxLayout(this);
// Add card list widgets
auto edhrec_commander_api_response_card_lists = response.container.getCardlists();
for (const EdhrecCommanderApiResponseCardList &card_list : edhrec_commander_api_response_card_lists) {
auto cardListDisplayWidget = new EdhrecCommanderApiResponseCardListDisplayWidget(this, card_list);
cardDisplayLayout->addWidget(cardListDisplayWidget);
}
// Create a QScrollArea to hold the card display widgets
scrollArea = new QScrollArea(this);
scrollArea->setWidgetResizable(true);
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
// Set the cardDisplayLayout inside the scroll area
auto scrollWidget = new QWidget(scrollArea);
scrollWidget->setLayout(cardDisplayLayout);
scrollArea->setWidget(scrollWidget);
layout->addWidget(scrollArea);
}
void EdhrecTopCardsApiResponseDisplayWidget::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
layout->invalidate();
layout->activate();
layout->update();
if (scrollArea && scrollArea->widget()) {
scrollArea->widget()->resize(event->size());
}
}

View file

@ -0,0 +1,25 @@
#ifndef EDHREC_TOP_CARDS_API_RESPONSE_DISPLAY_WIDGET_H
#define EDHREC_TOP_CARDS_API_RESPONSE_DISPLAY_WIDGET_H
#include "../../api_response/top_cards/edhrec_top_cards_api_response.h"
#include <QResizeEvent>
#include <QScrollArea>
#include <QVBoxLayout>
#include <QWidget>
class EdhrecTopCardsApiResponseDisplayWidget : public QWidget
{
Q_OBJECT
public:
explicit EdhrecTopCardsApiResponseDisplayWidget(QWidget *parent, EdhrecTopCardsApiResponse response);
void resizeEvent(QResizeEvent *event) override;
private:
QHBoxLayout *layout;
QVBoxLayout *cardDisplayLayout;
QScrollArea *scrollArea;
};
#endif // EDHREC_TOP_CARDS_API_RESPONSE_DISPLAY_WIDGET_H

View file

@ -0,0 +1,47 @@
#include "edhrec_top_commanders_api_response_display_widget.h"
#include "../../api_response/top_commanders/edhrec_top_commanders_api_response.h"
#include "../commander/edhrec_commander_api_response_card_list_display_widget.h"
EdhrecTopCommandersApiResponseDisplayWidget::EdhrecTopCommandersApiResponseDisplayWidget(
QWidget *parent,
EdhrecTopCommandersApiResponse response)
: QWidget(parent)
{
layout = new QHBoxLayout(this);
setLayout(layout);
cardDisplayLayout = new QVBoxLayout(this);
// Add card list widgets
auto edhrec_commander_api_response_card_lists = response.container.getCardlists();
for (const EdhrecCommanderApiResponseCardList &card_list : edhrec_commander_api_response_card_lists) {
auto cardListDisplayWidget = new EdhrecCommanderApiResponseCardListDisplayWidget(this, card_list);
cardDisplayLayout->addWidget(cardListDisplayWidget);
}
// Create a QScrollArea to hold the card display widgets
scrollArea = new QScrollArea(this);
scrollArea->setWidgetResizable(true);
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
// Set the cardDisplayLayout inside the scroll area
auto scrollWidget = new QWidget(scrollArea);
scrollWidget->setLayout(cardDisplayLayout);
scrollArea->setWidget(scrollWidget);
layout->addWidget(scrollArea);
}
void EdhrecTopCommandersApiResponseDisplayWidget::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
qDebug() << event->size();
layout->invalidate();
layout->activate();
layout->update();
if (scrollArea && scrollArea->widget()) {
scrollArea->widget()->resize(event->size());
}
}

View file

@ -0,0 +1,25 @@
#ifndef EDHREC_TOP_COMMANDERS_API_RESPONSE_DISPLAY_WIDGET_H
#define EDHREC_TOP_COMMANDERS_API_RESPONSE_DISPLAY_WIDGET_H
#include "../../api_response/top_commanders/edhrec_top_commanders_api_response.h"
#include <QResizeEvent>
#include <QScrollArea>
#include <QVBoxLayout>
#include <QWidget>
class EdhrecTopCommandersApiResponseDisplayWidget : public QWidget
{
Q_OBJECT
public:
explicit EdhrecTopCommandersApiResponseDisplayWidget(QWidget *parent, EdhrecTopCommandersApiResponse response);
void resizeEvent(QResizeEvent *event) override;
private:
QHBoxLayout *layout;
QVBoxLayout *cardDisplayLayout;
QScrollArea *scrollArea;
};
#endif // EDHREC_TOP_COMMANDERS_API_RESPONSE_DISPLAY_WIDGET_H

View file

@ -0,0 +1,45 @@
#include "edhrec_top_tags_api_response_display_widget.h"
#include "../../api_response/top_tags/edhrec_top_tags_api_response.h"
#include "../commander/edhrec_commander_api_response_card_list_display_widget.h"
EdhrecTopTagsApiResponseDisplayWidget::EdhrecTopTagsApiResponseDisplayWidget(QWidget *parent,
EdhrecTopTagsApiResponse response)
: QWidget(parent)
{
layout = new QHBoxLayout(this);
setLayout(layout);
cardDisplayLayout = new QVBoxLayout(this);
// Add card list widgets
auto edhrec_commander_api_response_card_lists = response.container.getCardlists();
for (const EdhrecCommanderApiResponseCardList &card_list : edhrec_commander_api_response_card_lists) {
auto cardListDisplayWidget = new EdhrecCommanderApiResponseCardListDisplayWidget(this, card_list);
cardDisplayLayout->addWidget(cardListDisplayWidget);
}
// Create a QScrollArea to hold the card display widgets
scrollArea = new QScrollArea(this);
scrollArea->setWidgetResizable(true);
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
// Set the cardDisplayLayout inside the scroll area
auto scrollWidget = new QWidget(scrollArea);
scrollWidget->setLayout(cardDisplayLayout);
scrollArea->setWidget(scrollWidget);
layout->addWidget(scrollArea);
}
void EdhrecTopTagsApiResponseDisplayWidget::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
layout->invalidate();
layout->activate();
layout->update();
if (scrollArea && scrollArea->widget()) {
scrollArea->widget()->resize(event->size());
}
}

View file

@ -0,0 +1,25 @@
#ifndef EDHREC_TOP_TAGS_API_RESPONSE_DISPLAY_WIDGET_H
#define EDHREC_TOP_TAGS_API_RESPONSE_DISPLAY_WIDGET_H
#include "../../api_response/top_tags/edhrec_top_tags_api_response.h"
#include <QResizeEvent>
#include <QScrollArea>
#include <QVBoxLayout>
#include <QWidget>
class EdhrecTopTagsApiResponseDisplayWidget : public QWidget
{
Q_OBJECT
public:
explicit EdhrecTopTagsApiResponseDisplayWidget(QWidget *parent, EdhrecTopTagsApiResponse response);
void resizeEvent(QResizeEvent *event) override;
private:
QHBoxLayout *layout;
QVBoxLayout *cardDisplayLayout;
QScrollArea *scrollArea;
};
#endif // EDHREC_TOP_TAGS_API_RESPONSE_DISPLAY_WIDGET_H

View file

@ -1,36 +0,0 @@
#include "edhrec_commander_api_response_commander_details_display_widget.h"
#include "../../../../game/cards/card_database_manager.h"
#include "../../../ui/widgets/cards/card_info_picture_widget.h"
#include <QLabel>
EdhrecCommanderResponseCommanderDetailsDisplayWidget::EdhrecCommanderResponseCommanderDetailsDisplayWidget(
QWidget *parent,
const EdhrecCommanderApiResponseCommanderDetails &_commanderDetails)
: QWidget(parent), commanderDetails(_commanderDetails)
{
layout = new QVBoxLayout(this);
setLayout(layout);
commanderPicture = new CardInfoPictureWidget(this);
commanderPicture->setCard(CardDatabaseManager::getInstance()->getCard(commanderDetails.getName()));
commanderDetails.debugPrint();
label = new QLabel(this);
label->setAlignment(Qt::AlignCenter);
salt = new QLabel(this);
salt->setAlignment(Qt::AlignCenter);
layout->addWidget(commanderPicture);
layout->addWidget(label);
layout->addWidget(salt);
retranslateUi();
}
void EdhrecCommanderResponseCommanderDetailsDisplayWidget::retranslateUi()
{
label->setText(commanderDetails.getLabel());
salt->setText(tr("Salt: ") + QString::number(commanderDetails.getSalt()));
}

View file

@ -1,7 +1,7 @@
#include "tab_edhrec.h"
#include "api_response/edhrec_commander_api_response.h"
#include "edhrec_commander_api_response_display_widget.h"
#include "api_response/commander/edhrec_commander_api_response.h"
#include "display/commander/edhrec_commander_api_response_display_widget.h"
#include <QDebug>
#include <QHBoxLayout>
@ -21,7 +21,7 @@ TabEdhRec::TabEdhRec(TabSupervisor *_tabSupervisor) : Tab(_tabSupervisor)
#endif
networkManager->setRedirectPolicy(QNetworkRequest::ManualRedirectPolicy);
connect(networkManager, SIGNAL(finished(QNetworkReply *)), this, SLOT(processApiJson(QNetworkReply *)));
connect(networkManager, &QNetworkAccessManager::finished, this, &TabEdhRec::processApiJson);
}
void TabEdhRec::retranslateUi()

View file

@ -1,12 +1,11 @@
#ifndef TAB_EDHREC_H
#define TAB_EDHREC_H
#include "../../../../game/cards/card_database.h"
#include "../../../../game/cards/card_info.h"
#include "../../../ui/widgets/general/layout_containers/flow_widget.h"
#include "../../tab.h"
#include "edhrec_commander_api_response_display_widget.h"
#include "display/commander/edhrec_commander_api_response_display_widget.h"
#include <QHBoxLayout>
#include <QNetworkAccessManager>
class TabEdhRec : public Tab

View file

@ -0,0 +1,378 @@
#include "tab_edhrec_main.h"
#include "../../../../game/cards/card_completer_proxy_model.h"
#include "../../../../game/cards/card_database_manager.h"
#include "../../../../game/cards/card_search_model.h"
#include "../../tab_supervisor.h"
#include "api_response/average_deck/edhrec_average_deck_api_response.h"
#include "api_response/commander/edhrec_commander_api_response.h"
#include "api_response/top_cards/edhrec_top_cards_api_response.h"
#include "api_response/top_commanders/edhrec_top_commanders_api_response.h"
#include "api_response/top_tags/edhrec_top_tags_api_response.h"
#include "display/commander/edhrec_commander_api_response_display_widget.h"
#include "display/top_cards/edhrec_top_cards_api_response_display_widget.h"
#include "display/top_commander/edhrec_top_commanders_api_response_display_widget.h"
#include "display/top_tags/edhrec_top_tags_api_response_display_widget.h"
#include <QCompleter>
#include <QDebug>
#include <QHBoxLayout>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QPushButton>
#include <QRegularExpression>
#include <QResizeEvent>
static bool canBeCommander(const CardInfoPtr &cardInfo)
{
return ((cardInfo->getCardType().contains("Legendary", Qt::CaseInsensitive) &&
cardInfo->getCardType().contains("Creature", Qt::CaseInsensitive))) ||
cardInfo->getText().contains("can be your commander", Qt::CaseInsensitive);
}
TabEdhRecMain::TabEdhRecMain(TabSupervisor *_tabSupervisor) : Tab(_tabSupervisor)
{
networkManager = new QNetworkAccessManager(this);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
networkManager->setTransferTimeout(); // Use Qt's default timeout
#endif
networkManager->setRedirectPolicy(QNetworkRequest::ManualRedirectPolicy);
connect(networkManager, SIGNAL(finished(QNetworkReply *)), this, SLOT(processApiJson(QNetworkReply *)));
container = new QWidget(this);
mainLayout = new QVBoxLayout(container);
container->setLayout(mainLayout);
navigationContainer = new QWidget(container);
navigationContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
navigationLayout = new QHBoxLayout(navigationContainer);
navigationLayout->setSpacing(5);
navigationContainer->setLayout(navigationLayout);
cardsPushButton = new QPushButton(navigationContainer);
connect(cardsPushButton, &QPushButton::clicked, this, &TabEdhRecMain::getTopCards);
topCommandersPushButton = new QPushButton(navigationContainer);
connect(topCommandersPushButton, &QPushButton::clicked, this, &TabEdhRecMain::getTopCommanders);
tagsPushButton = new QPushButton(navigationContainer);
connect(tagsPushButton, &QPushButton::clicked, this, &TabEdhRecMain::getTopTags);
searchBar = new QLineEdit(this);
auto cardDatabaseModel = new CardDatabaseModel(CardDatabaseManager::getInstance(), false, this);
auto displayModel = new CardDatabaseDisplayModel(this);
displayModel->setSourceModel(cardDatabaseModel);
CardSearchModel *searchModel = new CardSearchModel(displayModel, this);
CardCompleterProxyModel *proxyModel = new CardCompleterProxyModel(this);
proxyModel->setSourceModel(searchModel);
proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
proxyModel->setFilterRole(Qt::DisplayRole);
QCompleter *completer = new QCompleter(proxyModel, this);
completer->setCompletionRole(Qt::DisplayRole);
completer->setCompletionMode(QCompleter::PopupCompletion);
completer->setCaseSensitivity(Qt::CaseInsensitive);
completer->setFilterMode(Qt::MatchContains);
completer->setMaxVisibleItems(10);
searchBar->setCompleter(completer);
// Update suggestions dynamically
connect(searchBar, &QLineEdit::textChanged, searchModel, &CardSearchModel::updateSearchResults);
connect(searchBar, &QLineEdit::textChanged, this, [=](const QString &text) {
// Ensure substring matching
QString pattern = ".*" + QRegularExpression::escape(text) + ".*";
proxyModel->setFilterRegularExpression(QRegularExpression(pattern, QRegularExpression::CaseInsensitiveOption));
if (!text.isEmpty()) {
completer->complete(); // Force the dropdown to appear
}
});
searchPushButton = new QPushButton(navigationContainer);
connect(searchPushButton, &QPushButton::clicked, this, [=, this]() { doSearch(); });
navigationLayout->addWidget(cardsPushButton);
navigationLayout->addWidget(topCommandersPushButton);
navigationLayout->addWidget(tagsPushButton);
navigationLayout->addWidget(searchBar);
navigationLayout->addWidget(searchPushButton);
currentPageDisplay = new QWidget(container);
currentPageLayout = new QVBoxLayout(currentPageDisplay);
currentPageDisplay->setLayout(currentPageLayout);
mainLayout->addWidget(navigationContainer);
mainLayout->addWidget(currentPageDisplay);
// Ensure navigation stays at the top and currentPageDisplay takes remaining space
mainLayout->setStretch(0, 0); // navigationContainer gets minimum space
mainLayout->setStretch(1, 1); // currentPageDisplay expands as much as possible
setCentralWidget(container);
TabEdhRecMain::retranslateUi();
getTopCards();
}
void TabEdhRecMain::retranslateUi()
{
cardsPushButton->setText(tr("&Cards"));
topCommandersPushButton->setText(tr("Top Commanders"));
tagsPushButton->setText(tr("Tags"));
searchBar->setPlaceholderText(tr("Search for a card ..."));
searchPushButton->setText(tr("Search"));
}
void TabEdhRecMain::doSearch()
{
CardInfoPtr searchedCard = CardDatabaseManager::getInstance()->getCard(searchBar->text());
if (!searchedCard) {
return;
}
setCard(searchedCard, canBeCommander(searchedCard));
}
void TabEdhRecMain::setCard(CardInfoPtr _cardToQuery, bool isCommander)
{
cardToQuery = _cardToQuery;
if (!cardToQuery) {
qDebug() << "Invalid card information provided.";
return;
}
QString cardName = cardToQuery->getName();
QString formattedName = cardName.toLower().replace(" ", "-").remove(QRegularExpression("[^a-z0-9\\-]"));
QString url;
if (isCommander) {
url = QString("https://json.edhrec.com/pages/commanders/%1.json").arg(formattedName);
} else {
url = QString("https://json.edhrec.com/pages/cards/%1.json").arg(formattedName);
}
QNetworkRequest request{QUrl(url)};
networkManager->get(request);
}
void TabEdhRecMain::actNavigatePage(QString url)
{
QNetworkRequest request{QUrl("https://json.edhrec.com/pages" + url + ".json")};
networkManager->get(request);
}
void TabEdhRecMain::getTopCards()
{
QNetworkRequest request{QUrl("https://json.edhrec.com/pages/top/year.json")};
networkManager->get(request);
}
void TabEdhRecMain::getTopCommanders()
{
QNetworkRequest request{QUrl("https://json.edhrec.com/pages/commanders/year.json")};
networkManager->get(request);
}
void TabEdhRecMain::getTopTags()
{
QNetworkRequest request{QUrl("https://json.edhrec.com/pages/tags.json")};
networkManager->get(request);
}
void TabEdhRecMain::processApiJson(QNetworkReply *reply)
{
if (reply->error() != QNetworkReply::NoError) {
qDebug() << "Network error occurred:" << reply->errorString();
reply->deleteLater();
return;
}
QByteArray responseData = reply->readAll();
QJsonDocument jsonDoc = QJsonDocument::fromJson(responseData);
if (!jsonDoc.isObject()) {
qDebug() << "Invalid JSON response received.";
reply->deleteLater();
return;
}
QJsonObject jsonObj = jsonDoc.object();
// Get the actual URL from the reply
QString responseUrl = reply->url().toString();
// Check if the response URL matches a commander request
if (responseUrl.startsWith("https://json.edhrec.com/pages/commanders/year.json")) {
processTopCommandersResponse(jsonObj);
} else if (responseUrl.startsWith("https://json.edhrec.com/pages/commanders/")) {
processCommanderResponse(jsonObj);
} else if (responseUrl.startsWith("https://json.edhrec.com/pages/cards/")) {
processCommanderResponse(jsonObj);
} else if (responseUrl.startsWith("https://json.edhrec.com/pages/tags/")) {
processCommanderResponse(jsonObj);
} else if (responseUrl.startsWith("https://json.edhrec.com/pages/tags.json")) {
processTopTagsResponse(jsonObj);
} else if (responseUrl.startsWith("https://json.edhrec.com/pages/top/year.json")) {
processTopCardsResponse(jsonObj);
} else if (responseUrl.startsWith("https://json.edhrec.com/pages/combos/")) {
processCommanderResponse(jsonObj);
} else if (responseUrl.startsWith("https://json.edhrec.com/pages/average-decks/")) {
processAverageDeckResponse(jsonObj);
} else {
prettyPrintJson(jsonObj, 4);
}
reply->deleteLater();
}
void TabEdhRecMain::processTopCardsResponse(QJsonObject reply)
{
EdhrecTopCardsApiResponse deckData;
deckData.fromJson(reply);
// **Remove previous page display to prevent stacking**
if (currentPageDisplay) {
mainLayout->removeWidget(currentPageDisplay);
delete currentPageDisplay;
currentPageDisplay = nullptr;
}
// **Create new currentPageDisplay**
currentPageDisplay = new QWidget(container);
currentPageLayout = new QVBoxLayout(currentPageDisplay);
currentPageDisplay->setLayout(currentPageLayout);
auto display = new EdhrecTopCardsApiResponseDisplayWidget(currentPageDisplay, deckData);
currentPageLayout->addWidget(display);
mainLayout->addWidget(currentPageDisplay);
// **Ensure layout stays correct**
mainLayout->setStretch(0, 0); // Keep navigationContainer at the top
mainLayout->setStretch(1, 1); // Make sure currentPageDisplay takes remaining space
}
void TabEdhRecMain::processTopTagsResponse(QJsonObject reply)
{
EdhrecTopTagsApiResponse deckData;
deckData.fromJson(reply);
// **Remove previous page display to prevent stacking**
if (currentPageDisplay) {
mainLayout->removeWidget(currentPageDisplay);
delete currentPageDisplay;
currentPageDisplay = nullptr;
}
// **Create new currentPageDisplay**
currentPageDisplay = new QWidget(container);
currentPageLayout = new QVBoxLayout(currentPageDisplay);
currentPageDisplay->setLayout(currentPageLayout);
auto display = new EdhrecTopTagsApiResponseDisplayWidget(currentPageDisplay, deckData);
currentPageLayout->addWidget(display);
mainLayout->addWidget(currentPageDisplay);
// **Ensure layout stays correct**
mainLayout->setStretch(0, 0); // Keep navigationContainer at the top
mainLayout->setStretch(1, 1); // Make sure currentPageDisplay takes remaining space
}
void TabEdhRecMain::processTopCommandersResponse(QJsonObject reply)
{
EdhrecTopCommandersApiResponse deckData;
deckData.fromJson(reply);
// **Remove previous page display to prevent stacking**
if (currentPageDisplay) {
mainLayout->removeWidget(currentPageDisplay);
delete currentPageDisplay;
currentPageDisplay = nullptr;
}
// **Create new currentPageDisplay**
currentPageDisplay = new QWidget(container);
currentPageLayout = new QVBoxLayout(currentPageDisplay);
currentPageDisplay->setLayout(currentPageLayout);
auto display = new EdhrecTopCommandersApiResponseDisplayWidget(currentPageDisplay, deckData);
currentPageLayout->addWidget(display);
mainLayout->addWidget(currentPageDisplay);
// **Ensure layout stays correct**
mainLayout->setStretch(0, 0); // Keep navigationContainer at the top
mainLayout->setStretch(1, 1); // Make sure currentPageDisplay takes remaining space
}
void TabEdhRecMain::processCommanderResponse(QJsonObject reply)
{
EdhrecCommanderApiResponse deckData;
deckData.fromJson(reply);
// **Remove previous page display to prevent stacking**
if (currentPageDisplay) {
mainLayout->removeWidget(currentPageDisplay);
delete currentPageDisplay;
currentPageDisplay = nullptr;
}
// **Create new currentPageDisplay**
currentPageDisplay = new QWidget(container);
currentPageLayout = new QVBoxLayout(currentPageDisplay);
currentPageDisplay->setLayout(currentPageLayout);
auto display = new EdhrecCommanderApiResponseDisplayWidget(currentPageDisplay, deckData);
currentPageLayout->addWidget(display);
mainLayout->addWidget(currentPageDisplay);
// **Ensure layout stays correct**
mainLayout->setStretch(0, 0); // Keep navigationContainer at the top
mainLayout->setStretch(1, 1); // Make sure currentPageDisplay takes remaining space
}
void TabEdhRecMain::processAverageDeckResponse(QJsonObject reply)
{
EdhrecAverageDeckApiResponse deckData;
deckData.fromJson(reply);
tabSupervisor->addVisualDeckEditorTab(deckData.deck.deckLoader);
}
void TabEdhRecMain::prettyPrintJson(const QJsonValue &value, int indentLevel)
{
const QString indent(indentLevel * 2, ' '); // Adjust spacing as needed for pretty printing
if (value.isObject()) {
QJsonObject obj = value.toObject();
for (auto it = obj.begin(); it != obj.end(); ++it) {
qDebug().noquote() << indent + it.key() + ":";
prettyPrintJson(it.value(), indentLevel + 1);
}
} else if (value.isArray()) {
QJsonArray array = value.toArray();
for (int i = 0; i < array.size(); ++i) {
qDebug().noquote() << indent + QString("[%1]:").arg(i);
prettyPrintJson(array[i], indentLevel + 1);
}
} else if (value.isString()) {
qDebug().noquote() << indent + "\"" + value.toString() + "\"";
} else if (value.isDouble()) {
qDebug().noquote() << indent + QString::number(value.toDouble());
} else if (value.isBool()) {
qDebug().noquote() << indent + (value.toBool() ? "true" : "false");
} else if (value.isNull()) {
qDebug().noquote() << indent + "null";
}
}

View file

@ -0,0 +1,61 @@
#ifndef TAB_EDHREC_MAIN_H
#define TAB_EDHREC_MAIN_H
#include "../../../../game/cards/card_database.h"
#include "../../../ui/widgets/general/layout_containers/flow_widget.h"
#include "../../tab.h"
#include "display/commander/edhrec_commander_api_response_display_widget.h"
#include <QHBoxLayout>
#include <QLineEdit>
#include <QNetworkAccessManager>
#include <QPushButton>
class TabEdhRecMain : public Tab
{
Q_OBJECT
public:
explicit TabEdhRecMain(TabSupervisor *_tabSupervisor);
void retranslateUi() override;
void doSearch();
QString getTabText() const override
{
auto cardName = cardToQuery.isNull() ? QString() : cardToQuery->getName();
return tr("EDHREC: ") + cardName;
}
QNetworkAccessManager *networkManager;
public slots:
void processApiJson(QNetworkReply *reply);
void processTopCardsResponse(QJsonObject reply);
void processTopTagsResponse(QJsonObject reply);
void processTopCommandersResponse(QJsonObject reply);
void processAverageDeckResponse(QJsonObject reply);
void prettyPrintJson(const QJsonValue &value, int indentLevel);
void setCard(CardInfoPtr _cardToQuery, bool isCommander = false);
void actNavigatePage(QString url);
void getTopCards();
void getTopCommanders();
void getTopTags();
private:
QWidget *container;
QWidget *navigationContainer;
QWidget *currentPageDisplay;
QVBoxLayout *mainLayout;
QHBoxLayout *navigationLayout;
QVBoxLayout *currentPageLayout;
QPushButton *cardsPushButton;
QPushButton *topCommandersPushButton;
QPushButton *tagsPushButton;
QLineEdit *searchBar;
QPushButton *searchPushButton;
CardInfoPtr cardToQuery;
EdhrecCommanderApiResponseDisplayWidget *displayWidget;
void processCommanderResponse(QJsonObject reply);
};
#endif // TAB_EDHREC_MAIN_H

View file

@ -55,7 +55,7 @@ TabDeckEditor::TabDeckEditor(TabSupervisor *_tabSupervisor) : AbstractTabDeckEdi
void TabDeckEditor::createMenus()
{
deckMenu = new DeckEditorMenu(this, this);
deckMenu = new DeckEditorMenu(this);
addTabMenu(deckMenu);
viewMenu = new QMenu(this);
@ -67,36 +67,36 @@ void TabDeckEditor::createMenus()
aCardInfoDockVisible = cardInfoDockMenu->addAction(QString());
aCardInfoDockVisible->setCheckable(true);
connect(aCardInfoDockVisible, SIGNAL(triggered()), this, SLOT(dockVisibleTriggered()));
connect(aCardInfoDockVisible, &QAction::triggered, this, &TabDeckEditor::dockVisibleTriggered);
aCardInfoDockFloating = cardInfoDockMenu->addAction(QString());
aCardInfoDockFloating->setCheckable(true);
connect(aCardInfoDockFloating, SIGNAL(triggered()), this, SLOT(dockFloatingTriggered()));
connect(aCardInfoDockFloating, &QAction::triggered, this, &TabDeckEditor::dockFloatingTriggered);
aDeckDockVisible = deckDockMenu->addAction(QString());
aDeckDockVisible->setCheckable(true);
connect(aDeckDockVisible, SIGNAL(triggered()), this, SLOT(dockVisibleTriggered()));
connect(aDeckDockVisible, &QAction::triggered, this, &TabDeckEditor::dockVisibleTriggered);
aDeckDockFloating = deckDockMenu->addAction(QString());
aDeckDockFloating->setCheckable(true);
connect(aDeckDockFloating, SIGNAL(triggered()), this, SLOT(dockFloatingTriggered()));
connect(aDeckDockFloating, &QAction::triggered, this, &TabDeckEditor::dockFloatingTriggered);
aFilterDockVisible = filterDockMenu->addAction(QString());
aFilterDockVisible->setCheckable(true);
connect(aFilterDockVisible, SIGNAL(triggered()), this, SLOT(dockVisibleTriggered()));
connect(aFilterDockVisible, &QAction::triggered, this, &TabDeckEditor::dockVisibleTriggered);
aFilterDockFloating = filterDockMenu->addAction(QString());
aFilterDockFloating->setCheckable(true);
connect(aFilterDockFloating, SIGNAL(triggered()), this, SLOT(dockFloatingTriggered()));
connect(aFilterDockFloating, &QAction::triggered, this, &TabDeckEditor::dockFloatingTriggered);
aPrintingSelectorDockVisible = printingSelectorDockMenu->addAction(QString());
aPrintingSelectorDockVisible->setCheckable(true);
connect(aPrintingSelectorDockVisible, SIGNAL(triggered()), this, SLOT(dockVisibleTriggered()));
connect(aPrintingSelectorDockVisible, &QAction::triggered, this, &TabDeckEditor::dockVisibleTriggered);
aPrintingSelectorDockFloating = printingSelectorDockMenu->addAction(QString());
aPrintingSelectorDockFloating->setCheckable(true);
connect(aPrintingSelectorDockFloating, SIGNAL(triggered()), this, SLOT(dockFloatingTriggered()));
connect(aPrintingSelectorDockFloating, &QAction::triggered, this, &TabDeckEditor::dockFloatingTriggered);
viewMenu->addSeparator();
aResetLayout = viewMenu->addAction(QString());
connect(aResetLayout, SIGNAL(triggered()), this, SLOT(restartLayout()));
connect(aResetLayout, &QAction::triggered, this, &TabDeckEditor::restartLayout);
viewMenu->addAction(aResetLayout);
deckMenu->setSaveStatus(false);
@ -200,7 +200,7 @@ void TabDeckEditor::loadLayout()
databaseDisplayDockWidget->setMinimumSize(100, 100);
databaseDisplayDockWidget->setMaximumSize(1400, 5000);
QTimer::singleShot(100, this, SLOT(freeDocksSize()));
QTimer::singleShot(100, this, &TabDeckEditor::freeDocksSize);
}
void TabDeckEditor::restartLayout()
@ -236,7 +236,7 @@ void TabDeckEditor::restartLayout()
splitDockWidget(cardInfoDockWidget, printingSelectorDockWidget, Qt::Horizontal);
splitDockWidget(cardInfoDockWidget, filterDockWidget, Qt::Vertical);
QTimer::singleShot(100, this, SLOT(freeDocksSize()));
QTimer::singleShot(100, this, &TabDeckEditor::freeDocksSize);
}
void TabDeckEditor::freeDocksSize()

View file

@ -1,7 +1,7 @@
#ifndef WINDOW_DECKEDITOR_H
#define WINDOW_DECKEDITOR_H
#include "../../game/cards/card_database.h"
#include "../../game/cards/card_info.h"
#include "../game_logic/key_signals.h"
#include "../ui/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h"
#include "abstract_tab_deck_editor.h"

View file

@ -105,19 +105,19 @@ TabDeckStorage::TabDeckStorage(TabSupervisor *_tabSupervisor,
// Left side actions
aOpenLocalDeck = new QAction(this);
aOpenLocalDeck->setIcon(QPixmap("theme:icons/pencil"));
connect(aOpenLocalDeck, SIGNAL(triggered()), this, SLOT(actOpenLocalDeck()));
connect(aOpenLocalDeck, &QAction::triggered, this, &TabDeckStorage::actOpenLocalDeck);
aRenameLocal = new QAction(this);
aRenameLocal->setIcon(QPixmap("theme:icons/rename"));
connect(aRenameLocal, &QAction::triggered, this, &TabDeckStorage::actRenameLocal);
aUpload = new QAction(this);
aUpload->setIcon(QPixmap("theme:icons/arrow_right_green"));
connect(aUpload, SIGNAL(triggered()), this, SLOT(actUpload()));
connect(aUpload, &QAction::triggered, this, &TabDeckStorage::actUpload);
aNewLocalFolder = new QAction(this);
aNewLocalFolder->setIcon(qApp->style()->standardIcon(QStyle::SP_FileDialogNewFolder));
connect(aNewLocalFolder, &QAction::triggered, this, &TabDeckStorage::actNewLocalFolder);
aDeleteLocalDeck = new QAction(this);
aDeleteLocalDeck->setIcon(QPixmap("theme:icons/remove_row"));
connect(aDeleteLocalDeck, SIGNAL(triggered()), this, SLOT(actDeleteLocalDeck()));
connect(aDeleteLocalDeck, &QAction::triggered, this, &TabDeckStorage::actDeleteLocalDeck);
aOpenDecksFolder = new QAction(this);
aOpenDecksFolder->setIcon(qApp->style()->standardIcon(QStyle::SP_DirOpenIcon));
@ -126,16 +126,16 @@ TabDeckStorage::TabDeckStorage(TabSupervisor *_tabSupervisor,
// Right side actions
aOpenRemoteDeck = new QAction(this);
aOpenRemoteDeck->setIcon(QPixmap("theme:icons/pencil"));
connect(aOpenRemoteDeck, SIGNAL(triggered()), this, SLOT(actOpenRemoteDeck()));
connect(aOpenRemoteDeck, &QAction::triggered, this, &TabDeckStorage::actOpenRemoteDeck);
aDownload = new QAction(this);
aDownload->setIcon(QPixmap("theme:icons/arrow_left_green"));
connect(aDownload, SIGNAL(triggered()), this, SLOT(actDownload()));
connect(aDownload, &QAction::triggered, this, &TabDeckStorage::actDownload);
aNewFolder = new QAction(this);
aNewFolder->setIcon(qApp->style()->standardIcon(QStyle::SP_FileDialogNewFolder));
connect(aNewFolder, SIGNAL(triggered()), this, SLOT(actNewFolder()));
connect(aNewFolder, &QAction::triggered, this, &TabDeckStorage::actNewFolder);
aDeleteRemoteDeck = new QAction(this);
aDeleteRemoteDeck->setIcon(QPixmap("theme:icons/remove_row"));
connect(aDeleteRemoteDeck, SIGNAL(triggered()), this, SLOT(actDeleteRemoteDeck()));
connect(aDeleteRemoteDeck, &QAction::triggered, this, &TabDeckStorage::actDeleteRemoteDeck);
// Add actions to toolbars
leftToolBar->addAction(aOpenLocalDeck);
@ -339,8 +339,7 @@ void TabDeckStorage::uploadDeck(const QString &filePath, const QString &targetPa
cmd.set_deck_list(deckString.toStdString());
PendingCommand *pend = client->prepareSessionCommand(cmd);
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
SLOT(uploadFinished(Response, CommandContainer)));
connect(pend, &PendingCommand::finished, this, &TabDeckStorage::uploadFinished);
client->sendCommand(pend);
}
@ -421,8 +420,7 @@ void TabDeckStorage::actOpenRemoteDeck()
cmd.set_deck_id(node->getId());
PendingCommand *pend = client->prepareSessionCommand(cmd);
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
SLOT(openRemoteDeckFinished(Response, CommandContainer)));
connect(pend, &PendingCommand::finished, this, &TabDeckStorage::openRemoteDeckFinished);
client->sendCommand(pend);
}
}
@ -479,8 +477,7 @@ void TabDeckStorage::downloadNodeAtIndex(const QModelIndex &curLeft, const QMode
PendingCommand *pend = client->prepareSessionCommand(cmd);
pend->setExtraData(filePath);
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
SLOT(downloadFinished(Response, CommandContainer, QVariant)));
connect(pend, &PendingCommand::finished, this, &TabDeckStorage::downloadFinished);
client->sendCommand(pend);
}
// node at index is invalid
@ -522,8 +519,7 @@ void TabDeckStorage::actNewFolder()
cmd.set_dir_name(folder);
PendingCommand *pend = client->prepareSessionCommand(cmd);
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
SLOT(newFolderFinished(Response, CommandContainer)));
connect(pend, &PendingCommand::finished, this, &TabDeckStorage::newFolderFinished);
client->sendCommand(pend);
}
@ -573,15 +569,13 @@ void TabDeckStorage::deleteRemoteDeck(const RemoteDeckList_TreeModel::Node *curR
Command_DeckDelDir cmd;
cmd.set_path(targetPath.toStdString());
pend = client->prepareSessionCommand(cmd);
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
SLOT(deleteFolderFinished(Response, CommandContainer)));
connect(pend, &PendingCommand::finished, this, &TabDeckStorage::deleteFolderFinished);
} else {
const auto *deckNode = dynamic_cast<const RemoteDeckList_TreeModel::FileNode *>(curRight);
Command_DeckDel cmd;
cmd.set_deck_id(deckNode->getId());
pend = client->prepareSessionCommand(cmd);
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
SLOT(deleteDeckFinished(Response, CommandContainer)));
connect(pend, &PendingCommand::finished, this, &TabDeckStorage::deleteDeckFinished);
}
client->sendCommand(pend);

View file

@ -115,11 +115,12 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor, GameReplay *_replay)
createReplayMenuItems();
createViewMenuItems();
retranslateUi();
connect(&SettingsCache::instance().shortcuts(), SIGNAL(shortCutChanged()), this, SLOT(refreshShortcuts()));
connect(&SettingsCache::instance().shortcuts(), &ShortcutsSettings::shortCutChanged, this,
&TabGame::refreshShortcuts);
refreshShortcuts();
messageLog->logReplayStarted(gameInfo.game_id());
QTimer::singleShot(0, this, SLOT(loadLayout()));
QTimer::singleShot(0, this, &TabGame::loadLayout);
}
TabGame::TabGame(TabSupervisor *_tabSupervisor,
@ -156,14 +157,15 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor,
createMenuItems();
createViewMenuItems();
retranslateUi();
connect(&SettingsCache::instance().shortcuts(), SIGNAL(shortCutChanged()), this, SLOT(refreshShortcuts()));
connect(&SettingsCache::instance().shortcuts(), &ShortcutsSettings::shortCutChanged, this,
&TabGame::refreshShortcuts);
refreshShortcuts();
// append game to rooms game list for others to see
for (int i = gameInfo.game_types_size() - 1; i >= 0; i--)
gameTypes.append(roomGameTypes.find(gameInfo.game_types(i)).value());
QTimer::singleShot(0, this, SLOT(loadLayout()));
QTimer::singleShot(0, this, &TabGame::loadLayout);
}
void TabGame::addMentionTag(const QString &value)
@ -626,7 +628,7 @@ Player *TabGame::addPlayer(int playerId, const ServerInfo_User &info)
}
scene->addPlayer(newPlayer);
connect(newPlayer, SIGNAL(newCardAdded(AbstractCardItem *)), this, SLOT(newCardAdded(AbstractCardItem *)));
connect(newPlayer, &Player::newCardAdded, this, &TabGame::newCardAdded);
messageLog->connectToPlayer(newPlayer);
if (local && !spectator) {
@ -634,7 +636,7 @@ Player *TabGame::addPlayer(int playerId, const ServerInfo_User &info)
newPlayer->setShortcutsActive();
auto *deckView = new DeckViewContainer(playerId, this);
connect(deckView, SIGNAL(newCardAdded(AbstractCardItem *)), this, SLOT(newCardAdded(AbstractCardItem *)));
connect(deckView, &DeckViewContainer::newCardAdded, this, &TabGame::newCardAdded);
deckViewContainers.insert(playerId, deckView);
deckViewContainerLayout->addWidget(deckView);
@ -751,7 +753,7 @@ void TabGame::processGameEventContainer(const GameEventContainer &cont,
default: {
Player *player = players.value(playerId, 0);
if (!player) {
qCDebug(TabGameLog) << "unhandled game event: invalid player id";
qCWarning(TabGameLog) << "unhandled game event: invalid player id";
break;
}
player->processGameEvent(eventType, event, context, options);
@ -782,8 +784,7 @@ void TabGame::sendGameCommand(PendingCommand *pend, int playerId)
if (!client)
return;
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
SLOT(commandFinished(const Response &)));
connect(pend, &PendingCommand::finished, this, &TabGame::commandFinished);
client->sendCommand(pend);
}
@ -794,8 +795,7 @@ void TabGame::sendGameCommand(const google::protobuf::Message &command, int play
return;
PendingCommand *pend = prepareGameCommand(command);
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
SLOT(commandFinished(const Response &)));
connect(pend, &PendingCommand::finished, this, &TabGame::commandFinished);
client->sendCommand(pend);
}
@ -1196,10 +1196,11 @@ void TabGame::eventSetActivePhase(const Event_SetActivePhase &event,
void TabGame::newCardAdded(AbstractCardItem *card)
{
connect(card, SIGNAL(hovered(AbstractCardItem *)), cardInfoFrameWidget, SLOT(setCard(AbstractCardItem *)));
connect(card, &AbstractCardItem::hovered, cardInfoFrameWidget,
qOverload<AbstractCardItem *>(&CardInfoFrameWidget::setCard));
connect(card, &AbstractCardItem::showCardInfoPopup, this, &TabGame::showCardInfoPopup);
connect(card, SIGNAL(deleteCardInfoPopup(QString)), this, SLOT(deleteCardInfoPopup(QString)));
connect(card, SIGNAL(cardShiftClicked(QString)), this, SLOT(linkCardToChat(QString)));
connect(card, &AbstractCardItem::cardShiftClicked, this, &TabGame::linkCardToChat);
}
CardItem *TabGame::getCard(int playerId, const QString &zoneName, int cardId) const
@ -1287,34 +1288,34 @@ void TabGame::updateCardMenu(AbstractCardItem *card)
void TabGame::createMenuItems()
{
aNextPhase = new QAction(this);
connect(aNextPhase, SIGNAL(triggered()), this, SLOT(actNextPhase()));
connect(aNextPhase, &QAction::triggered, this, &TabGame::actNextPhase);
aNextPhaseAction = new QAction(this);
connect(aNextPhaseAction, SIGNAL(triggered()), this, SLOT(actNextPhaseAction()));
connect(aNextPhaseAction, &QAction::triggered, this, &TabGame::actNextPhaseAction);
aNextTurn = new QAction(this);
connect(aNextTurn, SIGNAL(triggered()), this, SLOT(actNextTurn()));
connect(aNextTurn, &QAction::triggered, this, &TabGame::actNextTurn);
aReverseTurn = new QAction(this);
connect(aReverseTurn, SIGNAL(triggered()), this, SLOT(actReverseTurn()));
connect(aReverseTurn, &QAction::triggered, this, &TabGame::actReverseTurn);
aRemoveLocalArrows = new QAction(this);
connect(aRemoveLocalArrows, SIGNAL(triggered()), this, SLOT(actRemoveLocalArrows()));
connect(aRemoveLocalArrows, &QAction::triggered, this, &TabGame::actRemoveLocalArrows);
aRotateViewCW = new QAction(this);
connect(aRotateViewCW, SIGNAL(triggered()), this, SLOT(actRotateViewCW()));
connect(aRotateViewCW, &QAction::triggered, this, &TabGame::actRotateViewCW);
aRotateViewCCW = new QAction(this);
connect(aRotateViewCCW, SIGNAL(triggered()), this, SLOT(actRotateViewCCW()));
connect(aRotateViewCCW, &QAction::triggered, this, &TabGame::actRotateViewCCW);
aGameInfo = new QAction(this);
connect(aGameInfo, SIGNAL(triggered()), this, SLOT(actGameInfo()));
connect(aGameInfo, &QAction::triggered, this, &TabGame::actGameInfo);
aConcede = new QAction(this);
connect(aConcede, SIGNAL(triggered()), this, SLOT(actConcede()));
connect(aConcede, &QAction::triggered, this, &TabGame::actConcede);
aLeaveGame = new QAction(this);
connect(aLeaveGame, &QAction::triggered, this, [this] { closeRequest(); });
aFocusChat = new QAction(this);
connect(aFocusChat, SIGNAL(triggered()), sayEdit, SLOT(setFocus()));
connect(aFocusChat, &QAction::triggered, sayEdit, qOverload<>(&LineEditCompleter::setFocus));
aCloseReplay = nullptr;
phasesMenu = new TearOffMenu(this);
for (int i = 0; i < phasesToolbar->phaseCount(); ++i) {
QAction *temp = new QAction(QString(), this);
connect(temp, SIGNAL(triggered()), this, SLOT(actPhaseAction()));
connect(temp, &QAction::triggered, this, &TabGame::actPhaseAction);
phasesMenu->addAction(temp);
phaseActions.append(temp);
}
@ -1373,40 +1374,40 @@ void TabGame::createViewMenuItems()
aCardInfoDockVisible = cardInfoDockMenu->addAction(QString());
aCardInfoDockVisible->setCheckable(true);
connect(aCardInfoDockVisible, SIGNAL(triggered()), this, SLOT(dockVisibleTriggered()));
connect(aCardInfoDockVisible, &QAction::triggered, this, &TabGame::dockVisibleTriggered);
aCardInfoDockFloating = cardInfoDockMenu->addAction(QString());
aCardInfoDockFloating->setCheckable(true);
connect(aCardInfoDockFloating, SIGNAL(triggered()), this, SLOT(dockFloatingTriggered()));
connect(aCardInfoDockFloating, &QAction::triggered, this, &TabGame::dockFloatingTriggered);
aMessageLayoutDockVisible = messageLayoutDockMenu->addAction(QString());
aMessageLayoutDockVisible->setCheckable(true);
connect(aMessageLayoutDockVisible, SIGNAL(triggered()), this, SLOT(dockVisibleTriggered()));
connect(aMessageLayoutDockVisible, &QAction::triggered, this, &TabGame::dockVisibleTriggered);
aMessageLayoutDockFloating = messageLayoutDockMenu->addAction(QString());
aMessageLayoutDockFloating->setCheckable(true);
connect(aMessageLayoutDockFloating, SIGNAL(triggered()), this, SLOT(dockFloatingTriggered()));
connect(aMessageLayoutDockFloating, &QAction::triggered, this, &TabGame::dockFloatingTriggered);
aPlayerListDockVisible = playerListDockMenu->addAction(QString());
aPlayerListDockVisible->setCheckable(true);
connect(aPlayerListDockVisible, SIGNAL(triggered()), this, SLOT(dockVisibleTriggered()));
connect(aPlayerListDockVisible, &QAction::triggered, this, &TabGame::dockVisibleTriggered);
aPlayerListDockFloating = playerListDockMenu->addAction(QString());
aPlayerListDockFloating->setCheckable(true);
connect(aPlayerListDockFloating, SIGNAL(triggered()), this, SLOT(dockFloatingTriggered()));
connect(aPlayerListDockFloating, &QAction::triggered, this, &TabGame::dockFloatingTriggered);
if (replayDock) {
replayDockMenu = viewMenu->addMenu(QString());
aReplayDockVisible = replayDockMenu->addAction(QString());
aReplayDockVisible->setCheckable(true);
connect(aReplayDockVisible, SIGNAL(triggered()), this, SLOT(dockVisibleTriggered()));
connect(aReplayDockVisible, &QAction::triggered, this, &TabGame::dockVisibleTriggered);
aReplayDockFloating = replayDockMenu->addAction(QString());
aReplayDockFloating->setCheckable(true);
connect(aReplayDockFloating, SIGNAL(triggered()), this, SLOT(dockFloatingTriggered()));
connect(aReplayDockFloating, &QAction::triggered, this, &TabGame::dockFloatingTriggered);
}
viewMenu->addSeparator();
aResetLayout = viewMenu->addAction(QString());
connect(aResetLayout, SIGNAL(triggered()), this, SLOT(actResetLayout()));
connect(aResetLayout, &QAction::triggered, this, &TabGame::actResetLayout);
viewMenu->addAction(aResetLayout);
addTabMenu(viewMenu);
@ -1457,7 +1458,7 @@ void TabGame::loadLayout()
aReplayDockFloating->setChecked(replayDock->isFloating());
}
QTimer::singleShot(100, this, SLOT(freeDocksSize()));
QTimer::singleShot(100, this, &TabGame::freeDocksSize);
}
void TabGame::freeDocksSize()
@ -1523,15 +1524,15 @@ void TabGame::actResetLayout()
playerListDock->setMaximumSize(250, 50);
}
QTimer::singleShot(100, this, SLOT(freeDocksSize()));
QTimer::singleShot(100, this, &TabGame::freeDocksSize);
}
void TabGame::createPlayAreaWidget(bool bReplay)
{
phasesToolbar = new PhasesToolbar;
if (!bReplay)
connect(phasesToolbar, SIGNAL(sendGameCommand(const ::google::protobuf::Message &, int)), this,
SLOT(sendGameCommand(const ::google::protobuf::Message &, int)));
connect(phasesToolbar, &PhasesToolbar::sendGameCommand, this,
qOverload<const ::google::protobuf::Message &, int>(&TabGame::sendGameCommand));
scene = new GameScene(phasesToolbar, this);
gameView = new GameView(scene);
@ -1549,9 +1550,8 @@ void TabGame::createReplayDock()
// timeline widget
timelineWidget = new ReplayTimelineWidget;
timelineWidget->setTimeline(replayTimeline);
connect(timelineWidget, SIGNAL(processNextEvent(Player::EventProcessingOptions)), this,
SLOT(replayNextEvent(Player::EventProcessingOptions)));
connect(timelineWidget, SIGNAL(replayFinished()), this, SLOT(replayFinished()));
connect(timelineWidget, &ReplayTimelineWidget::processNextEvent, this, &TabGame::replayNextEvent);
connect(timelineWidget, &ReplayTimelineWidget::replayFinished, this, &TabGame::replayFinished);
connect(timelineWidget, &ReplayTimelineWidget::rewound, this, &TabGame::replayRewind);
// timeline skip shortcuts
@ -1583,13 +1583,13 @@ void TabGame::createReplayDock()
playButtonIcon.addPixmap(QPixmap("theme:replay/pause"), QIcon::Normal, QIcon::On);
replayPlayButton->setIcon(playButtonIcon);
replayPlayButton->setCheckable(true);
connect(replayPlayButton, SIGNAL(toggled(bool)), this, SLOT(replayPlayButtonToggled(bool)));
connect(replayPlayButton, &QToolButton::toggled, this, &TabGame::replayPlayButtonToggled);
replayFastForwardButton = new QToolButton;
replayFastForwardButton->setIconSize(QSize(32, 32));
replayFastForwardButton->setIcon(QPixmap("theme:replay/fastforward"));
replayFastForwardButton->setCheckable(true);
connect(replayFastForwardButton, SIGNAL(toggled(bool)), this, SLOT(replayFastForwardButtonToggled(bool)));
connect(replayFastForwardButton, &QToolButton::toggled, this, &TabGame::replayFastForwardButtonToggled);
// putting everything together
replayControlLayout = new QHBoxLayout;
@ -1609,7 +1609,7 @@ void TabGame::createReplayDock()
replayDock->setFloating(false);
replayDock->installEventFilter(this);
connect(replayDock, SIGNAL(topLevelChanged(bool)), this, SLOT(dockTopLevelChanged(bool)));
connect(replayDock, &QDockWidget::topLevelChanged, this, &TabGame::dockTopLevelChanged);
}
void TabGame::createDeckViewContainerWidget(bool bReplay)
@ -1650,7 +1650,7 @@ void TabGame::createCardInfoDock(bool bReplay)
cardInfoDock->setFloating(false);
cardInfoDock->installEventFilter(this);
connect(cardInfoDock, SIGNAL(topLevelChanged(bool)), this, SLOT(dockTopLevelChanged(bool)));
connect(cardInfoDock, &QDockWidget::topLevelChanged, this, &TabGame::dockTopLevelChanged);
}
void TabGame::createPlayerListDock(bool bReplay)
@ -1672,26 +1672,28 @@ void TabGame::createPlayerListDock(bool bReplay)
playerListDock->setFloating(false);
playerListDock->installEventFilter(this);
connect(playerListDock, SIGNAL(topLevelChanged(bool)), this, SLOT(dockTopLevelChanged(bool)));
connect(playerListDock, &QDockWidget::topLevelChanged, this, &TabGame::dockTopLevelChanged);
}
void TabGame::createMessageDock(bool bReplay)
{
messageLog = new MessageLogWidget(tabSupervisor, this);
connect(messageLog, SIGNAL(cardNameHovered(QString)), cardInfoFrameWidget, SLOT(setCard(QString)));
connect(messageLog, &MessageLogWidget::cardNameHovered, cardInfoFrameWidget,
qOverload<const QString &>(&CardInfoFrameWidget::setCard));
connect(messageLog, &MessageLogWidget::showCardInfoPopup, this, &TabGame::showCardInfoPopup);
connect(messageLog, SIGNAL(deleteCardInfoPopup(QString)), this, SLOT(deleteCardInfoPopup(QString)));
connect(messageLog, &MessageLogWidget::deleteCardInfoPopup, this, &TabGame::deleteCardInfoPopup);
if (!bReplay) {
connect(messageLog, SIGNAL(openMessageDialog(QString, bool)), this, SIGNAL(openMessageDialog(QString, bool)));
connect(messageLog, SIGNAL(addMentionTag(QString)), this, SLOT(addMentionTag(QString)));
connect(&SettingsCache::instance(), SIGNAL(chatMentionCompleterChanged()), this, SLOT(actCompleterChanged()));
connect(messageLog, &MessageLogWidget::openMessageDialog, this, &TabGame::openMessageDialog);
connect(messageLog, &MessageLogWidget::addMentionTag, this, &TabGame::addMentionTag);
connect(&SettingsCache::instance(), &SettingsCache::chatMentionCompleterChanged, this,
&TabGame::actCompleterChanged);
timeElapsedLabel = new QLabel;
timeElapsedLabel->setAlignment(Qt::AlignCenter);
gameTimer = new QTimer(this);
gameTimer->setInterval(1000);
connect(gameTimer, SIGNAL(timeout()), this, SLOT(incrementGameTime()));
connect(gameTimer, &QTimer::timeout, this, &TabGame::incrementGameTime);
gameTimer->start();
sayLabel = new QLabel;
@ -1719,8 +1721,8 @@ void TabGame::createMessageDock(bool bReplay)
}
}
connect(tabSupervisor, SIGNAL(adminLockChanged(bool)), this, SLOT(adminLockChanged(bool)));
connect(sayEdit, SIGNAL(returnPressed()), this, SLOT(actSay()));
connect(tabSupervisor, &TabSupervisor::adminLockChanged, this, &TabGame::adminLockChanged);
connect(sayEdit, &LineEditCompleter::returnPressed, this, &TabGame::actSay);
sayHLayout = new QHBoxLayout;
sayHLayout->addWidget(sayLabel);
@ -1746,7 +1748,7 @@ void TabGame::createMessageDock(bool bReplay)
messageLayoutDock->setFloating(false);
messageLayoutDock->installEventFilter(this);
connect(messageLayoutDock, SIGNAL(topLevelChanged(bool)), this, SLOT(dockTopLevelChanged(bool)));
connect(messageLayoutDock, &QDockWidget::topLevelChanged, this, &TabGame::dockTopLevelChanged);
}
void TabGame::hideEvent(QHideEvent *event)

View file

@ -116,8 +116,7 @@ void TabLog::getClicked()
cmd.set_date_range(dateRange);
cmd.set_maximum_results(maximumResults->value());
PendingCommand *pend = client->prepareModeratorCommand(cmd);
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
SLOT(viewLogHistory_processResponse(Response)));
connect(pend, &PendingCommand::finished, this, &TabLog::viewLogHistory_processResponse);
client->sendCommand(pend);
}
@ -186,11 +185,11 @@ void TabLog::createDock()
getButton = new QPushButton(tr("Get User Logs"));
getButton->setAutoDefault(true);
connect(getButton, SIGNAL(clicked()), this, SLOT(getClicked()));
connect(getButton, &QPushButton::clicked, this, &TabLog::getClicked);
clearButton = new QPushButton(tr("Clear Filters"));
clearButton->setAutoDefault(true);
connect(clearButton, SIGNAL(clicked()), this, SLOT(clearClicked()));
connect(clearButton, &QPushButton::clicked, this, &TabLog::clearClicked);
criteriaGrid = new QGridLayout;
criteriaGrid->addWidget(labelFindUserName, 0, 0);

View file

@ -28,11 +28,11 @@ TabMessage::TabMessage(TabSupervisor *_tabSupervisor,
{
chatView = new ChatView(tabSupervisor, 0, true);
connect(chatView, &ChatView::showCardInfoPopup, this, &TabMessage::showCardInfoPopup);
connect(chatView, SIGNAL(deleteCardInfoPopup(QString)), this, SLOT(deleteCardInfoPopup(QString)));
connect(chatView, SIGNAL(addMentionTag(QString)), this, SLOT(addMentionTag(QString)));
connect(chatView, &ChatView::deleteCardInfoPopup, this, &TabMessage::deleteCardInfoPopup);
connect(chatView, &ChatView::addMentionTag, this, &TabMessage::addMentionTag);
sayEdit = new LineEditUnfocusable;
sayEdit->setMaxLength(MAX_TEXT_LENGTH);
connect(sayEdit, SIGNAL(returnPressed()), this, SLOT(sendMessage()));
connect(sayEdit, &LineEditUnfocusable::returnPressed, this, &TabMessage::sendMessage);
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget(chatView);
@ -102,7 +102,7 @@ void TabMessage::sendMessage()
cmd.set_message(sayEdit->text().toStdString());
PendingCommand *pend = client->prepareSessionCommand(cmd);
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this, SLOT(messageSent(const Response &)));
connect(pend, &PendingCommand::finished, this, &TabMessage::messageSent);
client->sendCommand(pend);
sayEdit->clear();
@ -140,12 +140,12 @@ bool TabMessage::shouldShowSystemPopup(const Event_UserMessage &event)
void TabMessage::showSystemPopup(const Event_UserMessage &event)
{
if (trayIcon) {
disconnect(trayIcon, SIGNAL(messageClicked()), 0, 0);
disconnect(trayIcon, &QSystemTrayIcon::messageClicked, 0, 0);
trayIcon->showMessage(tr("Private message from") + " " + otherUserInfo->name().c_str(),
event.message().c_str());
connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(messageClicked()));
connect(trayIcon, &QSystemTrayIcon::messageClicked, this, &TabMessage::messageClicked);
} else {
qCDebug(TabMessageLog) << "Error: trayIcon is NULL. TabMessage::showSystemPopup failed";
qCWarning(TabMessageLog) << "Error: trayIcon is NULL. TabMessage::showSystemPopup failed";
}
}

View file

@ -96,8 +96,8 @@ TabReplays::TabReplays(TabSupervisor *_tabSupervisor, AbstractClient *_client, c
// Left side actions
aOpenLocalReplay = new QAction(this);
aOpenLocalReplay->setIcon(QPixmap("theme:icons/view"));
connect(aOpenLocalReplay, SIGNAL(triggered()), this, SLOT(actOpenLocalReplay()));
connect(localDirView, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(actOpenLocalReplay()));
connect(aOpenLocalReplay, &QAction::triggered, this, &TabReplays::actOpenLocalReplay);
connect(localDirView, &QTreeView::doubleClicked, this, &TabReplays::actOpenLocalReplay);
aRenameLocal = new QAction(this);
aRenameLocal->setIcon(QPixmap("theme:icons/rename"));
connect(aRenameLocal, &QAction::triggered, this, &TabReplays::actRenameLocal);
@ -106,7 +106,7 @@ TabReplays::TabReplays(TabSupervisor *_tabSupervisor, AbstractClient *_client, c
connect(aNewLocalFolder, &QAction::triggered, this, &TabReplays::actNewLocalFolder);
aDeleteLocalReplay = new QAction(this);
aDeleteLocalReplay->setIcon(QPixmap("theme:icons/remove_row"));
connect(aDeleteLocalReplay, SIGNAL(triggered()), this, SLOT(actDeleteLocalReplay()));
connect(aDeleteLocalReplay, &QAction::triggered, this, &TabReplays::actDeleteLocalReplay);
aOpenReplaysFolder = new QAction(this);
aOpenReplaysFolder->setIcon(qApp->style()->standardIcon(QStyle::SP_DirOpenIcon));
@ -115,17 +115,17 @@ TabReplays::TabReplays(TabSupervisor *_tabSupervisor, AbstractClient *_client, c
// Right side actions
aOpenRemoteReplay = new QAction(this);
aOpenRemoteReplay->setIcon(QPixmap("theme:icons/view"));
connect(aOpenRemoteReplay, SIGNAL(triggered()), this, SLOT(actOpenRemoteReplay()));
connect(serverDirView, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(actOpenRemoteReplay()));
connect(aOpenRemoteReplay, &QAction::triggered, this, &TabReplays::actOpenRemoteReplay);
connect(serverDirView, &QTreeView::doubleClicked, this, &TabReplays::actOpenRemoteReplay);
aDownload = new QAction(this);
aDownload->setIcon(QPixmap("theme:icons/arrow_left_green"));
connect(aDownload, SIGNAL(triggered()), this, SLOT(actDownload()));
connect(aDownload, &QAction::triggered, this, &TabReplays::actDownload);
aKeep = new QAction(this);
aKeep->setIcon(QPixmap("theme:icons/lock"));
connect(aKeep, SIGNAL(triggered()), this, SLOT(actKeepRemoteReplay()));
connect(aKeep, &QAction::triggered, this, &TabReplays::actKeepRemoteReplay);
aDeleteRemoteReplay = new QAction(this);
aDeleteRemoteReplay->setIcon(QPixmap("theme:icons/remove_row"));
connect(aDeleteRemoteReplay, SIGNAL(triggered()), this, SLOT(actDeleteRemoteReplay()));
connect(aDeleteRemoteReplay, &QAction::triggered, this, &TabReplays::actDeleteRemoteReplay);
// Add actions to toolbars
leftToolBar->addAction(aOpenLocalReplay);
@ -146,8 +146,7 @@ TabReplays::TabReplays(TabSupervisor *_tabSupervisor, AbstractClient *_client, c
mainWidget->setLayout(hbox);
setCentralWidget(mainWidget);
connect(client, SIGNAL(replayAddedEventReceived(const Event_ReplayAdded &)), this,
SLOT(replayAddedEventReceived(const Event_ReplayAdded &)));
connect(client, &AbstractClient::replayAddedEventReceived, this, &TabReplays::replayAddedEventReceived);
connect(client, &AbstractClient::userInfoChanged, this, &TabReplays::handleConnected);
connect(client, &AbstractClient::statusChanged, this, &TabReplays::handleConnectionChanged);
@ -323,8 +322,7 @@ void TabReplays::actOpenRemoteReplay()
cmd.set_replay_id(curRight->replay_id());
PendingCommand *pend = client->prepareSessionCommand(cmd);
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
SLOT(openRemoteReplayFinished(const Response &)));
connect(pend, &PendingCommand::finished, this, &TabReplays::openRemoteReplayFinished);
client->sendCommand(pend);
}
}
@ -378,8 +376,7 @@ void TabReplays::downloadNodeAtIndex(const QModelIndex &curLeft, const QModelInd
PendingCommand *pend = client->prepareSessionCommand(cmd);
pend->setExtraData(filePath);
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
SLOT(downloadFinished(Response, CommandContainer, QVariant)));
connect(pend, &PendingCommand::finished, this, &TabReplays::downloadFinished);
client->sendCommand(pend);
}
// node at index was invalid
@ -416,8 +413,7 @@ void TabReplays::actKeepRemoteReplay()
cmd.set_do_not_hide(!curRight->do_not_hide());
PendingCommand *pend = client->prepareSessionCommand(cmd);
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
SLOT(keepRemoteReplayFinished(Response, CommandContainer)));
connect(pend, &PendingCommand::finished, this, &TabReplays::keepRemoteReplayFinished);
client->sendCommand(pend);
}
}
@ -455,8 +451,7 @@ void TabReplays::actDeleteRemoteReplay()
cmd.set_game_id(curRight->game_id());
PendingCommand *pend = client->prepareSessionCommand(cmd);
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
SLOT(deleteRemoteReplayFinished(Response, CommandContainer)));
connect(pend, &PendingCommand::finished, this, &TabReplays::deleteRemoteReplayFinished);
client->sendCommand(pend);
}
}

View file

@ -53,28 +53,29 @@ TabRoom::TabRoom(TabSupervisor *_tabSupervisor,
SIGNAL(openMessageDialog(const QString &, bool)));
chatView = new ChatView(tabSupervisor, nullptr, true, this);
connect(chatView, SIGNAL(showMentionPopup(const QString &)), this, SLOT(actShowMentionPopup(const QString &)));
connect(chatView, SIGNAL(messageClickedSignal()), this, SLOT(focusTab()));
connect(chatView, SIGNAL(openMessageDialog(QString, bool)), this, SIGNAL(openMessageDialog(QString, bool)));
connect(chatView, &ChatView::showMentionPopup, this, &TabRoom::actShowMentionPopup);
connect(chatView, &ChatView::messageClickedSignal, this, &TabRoom::focusTab);
connect(chatView, &ChatView::openMessageDialog, this, &TabRoom::openMessageDialog);
connect(chatView, &ChatView::showCardInfoPopup, this, &TabRoom::showCardInfoPopup);
connect(chatView, SIGNAL(deleteCardInfoPopup(QString)), this, SLOT(deleteCardInfoPopup(QString)));
connect(chatView, SIGNAL(addMentionTag(QString)), this, SLOT(addMentionTag(QString)));
connect(&SettingsCache::instance(), SIGNAL(chatMentionCompleterChanged()), this, SLOT(actCompleterChanged()));
connect(chatView, &ChatView::deleteCardInfoPopup, this, &TabRoom::deleteCardInfoPopup);
connect(chatView, &ChatView::addMentionTag, this, &TabRoom::addMentionTag);
connect(&SettingsCache::instance(), &SettingsCache::chatMentionCompleterChanged, this,
&TabRoom::actCompleterChanged);
sayLabel = new QLabel;
sayEdit = new LineEditCompleter;
sayEdit->setMaxLength(MAX_TEXT_LENGTH);
sayLabel->setBuddy(sayEdit);
connect(sayEdit, SIGNAL(returnPressed()), this, SLOT(sendMessage()));
connect(sayEdit, &LineEditCompleter::returnPressed, this, &TabRoom::sendMessage);
QMenu *chatSettingsMenu = new QMenu(this);
aClearChat = chatSettingsMenu->addAction(QString());
connect(aClearChat, SIGNAL(triggered()), this, SLOT(actClearChat()));
connect(aClearChat, &QAction::triggered, this, &TabRoom::actClearChat);
chatSettingsMenu->addSeparator();
aOpenChatSettings = chatSettingsMenu->addAction(QString());
connect(aOpenChatSettings, SIGNAL(triggered()), this, SLOT(actOpenChatSettings()));
connect(aOpenChatSettings, &QAction::triggered, this, &TabRoom::actOpenChatSettings);
QToolButton *chatSettingsButton = new QToolButton;
chatSettingsButton->setIcon(QPixmap("theme:icons/settings"));
@ -126,7 +127,8 @@ TabRoom::TabRoom(TabSupervisor *_tabSupervisor,
sayEdit->setCompleter(completer);
actCompleterChanged();
connect(&SettingsCache::instance().shortcuts(), SIGNAL(shortCutChanged()), this, SLOT(refreshShortcuts()));
connect(&SettingsCache::instance().shortcuts(), &ShortcutsSettings::shortCutChanged, this,
&TabRoom::refreshShortcuts);
refreshShortcuts();
retranslateUi();
@ -165,9 +167,9 @@ void TabRoom::actShowPopup(const QString &message)
{
if (trayIcon && (tabSupervisor->currentIndex() != tabSupervisor->indexOf(this) ||
QApplication::activeWindow() == nullptr || QApplication::focusWidget() == nullptr)) {
disconnect(trayIcon, SIGNAL(messageClicked()), nullptr, nullptr);
disconnect(trayIcon, &QSystemTrayIcon::messageClicked, nullptr, nullptr);
trayIcon->showMessage(message, tr("Click to view"));
connect(trayIcon, SIGNAL(messageClicked()), chatView, SLOT(actMessageClicked()));
connect(trayIcon, &QSystemTrayIcon::messageClicked, chatView, &ChatView::messageClickedSignal);
}
}
@ -201,8 +203,7 @@ void TabRoom::sendMessage()
cmd.set_message(sayEdit->text().toStdString());
PendingCommand *pend = prepareRoomCommand(cmd);
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
SLOT(sayFinished(const Response &)));
connect(pend, &PendingCommand::finished, this, &TabRoom::sayFinished);
sendRoomCommand(pend);
sayEdit->clear();
}

View file

@ -33,7 +33,7 @@ RoomSelector::RoomSelector(AbstractClient *_client, QWidget *parent) : QGroupBox
roomList->header()->setSectionResizeMode(3, QHeaderView::ResizeToContents);
joinButton = new QPushButton;
connect(joinButton, SIGNAL(clicked()), this, SLOT(joinClicked()));
connect(joinButton, &QPushButton::clicked, this, &RoomSelector::joinClicked);
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addStretch();
buttonLayout->addWidget(joinButton);
@ -44,9 +44,8 @@ RoomSelector::RoomSelector(AbstractClient *_client, QWidget *parent) : QGroupBox
retranslateUi();
setLayout(vbox);
connect(client, SIGNAL(listRoomsEventReceived(const Event_ListRooms &)), this,
SLOT(processListRoomsEvent(const Event_ListRooms &)));
connect(roomList, SIGNAL(activated(const QModelIndex &)), this, SLOT(joinClicked()));
connect(client, &AbstractClient::listRoomsEventReceived, this, &RoomSelector::processListRoomsEvent);
connect(roomList, &QTreeWidget::activated, this, &RoomSelector::joinClicked);
client->sendCommand(client->prepareSessionCommand(Command_ListRooms()));
}
@ -144,10 +143,9 @@ TabServer::TabServer(TabSupervisor *_tabSupervisor, AbstractClient *_client) : T
serverInfoBox = new QTextBrowser;
serverInfoBox->setOpenExternalLinks(true);
connect(roomSelector, SIGNAL(joinRoomRequest(int, bool)), this, SLOT(joinRoom(int, bool)));
connect(roomSelector, &RoomSelector::joinRoomRequest, this, &TabServer::joinRoom);
connect(client, SIGNAL(serverMessageEventReceived(const Event_ServerMessage &)), this,
SLOT(processServerMessageEvent(const Event_ServerMessage &)));
connect(client, &AbstractClient::serverMessageEventReceived, this, &TabServer::processServerMessageEvent);
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget(roomSelector);
@ -185,8 +183,7 @@ void TabServer::joinRoom(int id, bool setCurrent)
PendingCommand *pend = client->prepareSessionCommand(cmd);
pend->setExtraData(setCurrent);
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
SLOT(joinRoomFinished(Response, CommandContainer, QVariant)));
connect(pend, &PendingCommand::finished, this, &TabServer::joinRoomFinished);
client->sendCommand(pend);

View file

@ -6,6 +6,7 @@
#include "../../server/user/user_list_widget.h"
#include "../../settings/cache_settings.h"
#include "../ui/pixel_map_generator.h"
#include "api/edhrec/tab_edhrec_main.h"
#include "pb/event_game_joined.pb.h"
#include "pb/event_notify_user.pb.h"
#include "pb/event_user_message.pb.h"
@ -25,6 +26,9 @@
#include "tab_replays.h"
#include "tab_room.h"
#include "tab_server.h"
#include "tab_visual_database_display.h"
#include "visual_deck_editor/tab_deck_editor_visual.h"
#include "visual_deck_editor/tab_deck_editor_visual_tab_widget.h"
#include "visual_deck_storage/tab_deck_storage_visual.h"
#include <QApplication>
@ -130,10 +134,19 @@ TabSupervisor::TabSupervisor(AbstractClient *_client, QMenu *tabsMenu, QWidget *
aTabDeckEditor = new QAction(this);
connect(aTabDeckEditor, &QAction::triggered, this, [this] { addDeckEditorTab(nullptr); });
aTabVisualDeckEditor = new QAction(this);
connect(aTabVisualDeckEditor, &QAction::triggered, this, [this] { addVisualDeckEditorTab(nullptr); });
aTabEdhRec = new QAction(this);
connect(aTabEdhRec, &QAction::triggered, this, [this] { addEdhrecMainTab(); });
aTabVisualDeckStorage = new QAction(this);
aTabVisualDeckStorage->setCheckable(true);
connect(aTabVisualDeckStorage, &QAction::triggered, this, &TabSupervisor::actTabVisualDeckStorage);
aTabVisualDatabaseDisplay = new QAction(this);
connect(aTabVisualDatabaseDisplay, &QAction::triggered, this, [this] { addVisualDatabaseDisplayTab(); });
aTabServer = new QAction(this);
aTabServer->setCheckable(true);
connect(aTabServer, &QAction::triggered, this, &TabSupervisor::actTabServer);
@ -176,7 +189,10 @@ void TabSupervisor::retranslateUi()
{
// tab menu actions
aTabDeckEditor->setText(tr("Deck Editor"));
aTabVisualDeckEditor->setText(tr("Visual Deck Editor"));
aTabEdhRec->setText(tr("EDHRec"));
aTabVisualDeckStorage->setText(tr("&Visual Deck Storage"));
aTabVisualDatabaseDisplay->setText(tr("Visual Database Display"));
aTabServer->setText(tr("Server"));
aTabAccount->setText(tr("Account"));
aTabDeckStorage->setText(tr("Deck Storage"));
@ -223,6 +239,7 @@ void TabSupervisor::refreshShortcuts()
{
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
aTabDeckEditor->setShortcuts(shortcuts.getShortcut("Tabs/aTabDeckEditor"));
aTabVisualDeckEditor->setShortcuts(shortcuts.getShortcut("Tabs/aTabVisualDeckEditor"));
aTabVisualDeckStorage->setShortcuts(shortcuts.getShortcut("Tabs/aTabVisualDeckStorage"));
aTabServer->setShortcuts(shortcuts.getShortcut("Tabs/aTabServer"));
aTabAccount->setShortcuts(shortcuts.getShortcut("Tabs/aTabAccount"));
@ -370,8 +387,11 @@ void TabSupervisor::resetTabsMenu()
{
tabsMenu->clear();
tabsMenu->addAction(aTabDeckEditor);
tabsMenu->addAction(aTabVisualDeckEditor);
tabsMenu->addAction(aTabEdhRec);
tabsMenu->addSeparator();
tabsMenu->addAction(aTabVisualDeckStorage);
tabsMenu->addAction(aTabVisualDatabaseDisplay);
tabsMenu->addAction(aTabDeckStorage);
tabsMenu->addAction(aTabReplays);
}
@ -804,6 +824,36 @@ TabDeckEditor *TabSupervisor::addDeckEditorTab(const DeckLoader *deckToOpen)
return tab;
}
TabDeckEditorVisual *TabSupervisor::addVisualDeckEditorTab(const DeckLoader *deckToOpen)
{
auto *tab = new TabDeckEditorVisual(this);
if (deckToOpen)
tab->openDeck(new DeckLoader(*deckToOpen));
connect(tab, &AbstractTabDeckEditor::deckEditorClosing, this, &TabSupervisor::deckEditorClosed);
connect(tab, &AbstractTabDeckEditor::openDeckEditor, this, &TabSupervisor::addVisualDeckEditorTab);
myAddTab(tab);
deckEditorTabs.append(tab);
setCurrentWidget(tab);
return tab;
}
TabEdhRecMain *TabSupervisor::addEdhrecMainTab()
{
auto *tab = new TabEdhRecMain(this);
myAddTab(tab);
setCurrentWidget(tab);
return tab;
}
TabVisualDatabaseDisplay *TabSupervisor::addVisualDatabaseDisplayTab()
{
auto *tab = new TabVisualDatabaseDisplay(this);
myAddTab(tab);
setCurrentWidget(tab);
return tab;
}
TabEdhRec *TabSupervisor::addEdhrecTab(const CardInfoPtr &cardToQuery, bool isCommander)
{
auto *tab = new TabEdhRec(this);
@ -856,7 +906,7 @@ void TabSupervisor::processGameEventContainer(const GameEventContainer &cont)
if (tab)
tab->processGameEventContainer(cont, qobject_cast<AbstractClient *>(sender()), {});
else
qCDebug(TabSupervisorLog) << "gameEvent: invalid gameId";
qCInfo(TabSupervisorLog) << "gameEvent: invalid gameId" << cont.game_id();
}
void TabSupervisor::processUserMessageEvent(const Event_UserMessage &event)

View file

@ -5,6 +5,10 @@
#include "../../server/user/user_list_proxy.h"
#include "abstract_tab_deck_editor.h"
#include "api/edhrec/tab_edhrec.h"
#include "api/edhrec/tab_edhrec_main.h"
#include "tab_visual_database_display.h"
#include "visual_deck_editor/tab_deck_editor_visual.h"
#include "visual_deck_editor/tab_deck_editor_visual_tab_widget.h"
#include "visual_deck_storage/tab_deck_storage_visual.h"
#include <QAbstractButton>
@ -91,8 +95,8 @@ private:
QList<AbstractTabDeckEditor *> deckEditorTabs;
bool isLocalGame;
QAction *aTabDeckEditor, *aTabVisualDeckStorage, *aTabServer, *aTabAccount, *aTabDeckStorage, *aTabReplays,
*aTabAdmin, *aTabLog;
QAction *aTabDeckEditor, *aTabVisualDeckEditor, *aTabEdhRec, *aTabVisualDeckStorage, *aTabVisualDatabaseDisplay,
*aTabServer, *aTabAccount, *aTabDeckStorage, *aTabReplays, *aTabAdmin, *aTabLog;
int myAddTab(Tab *tab, QAction *manager = nullptr);
void addCloseButtonToTab(Tab *tab, int tabIndex, QAction *manager);
@ -149,6 +153,9 @@ signals:
public slots:
TabDeckEditor *addDeckEditorTab(const DeckLoader *deckToOpen);
TabDeckEditorVisual *addVisualDeckEditorTab(const DeckLoader *deckToOpen);
TabVisualDatabaseDisplay *addVisualDatabaseDisplayTab();
TabEdhRecMain *addEdhrecMainTab();
TabEdhRec *addEdhrecTab(const CardInfoPtr &cardToQuery, bool isCommander = false);
void openReplay(GameReplay *replay);
void maximizeMainWindow();

View file

@ -0,0 +1,20 @@
#include "tab_visual_database_display.h"
#include "tab_deck_editor.h"
TabVisualDatabaseDisplay::TabVisualDatabaseDisplay(TabSupervisor *_tabSupervisor) : Tab(_tabSupervisor)
{
deckEditor = new TabDeckEditor(_tabSupervisor);
deckEditor->setHidden(true);
visualDatabaseDisplayWidget =
new VisualDatabaseDisplayWidget(this, deckEditor, deckEditor->databaseDisplayDockWidget->databaseModel,
deckEditor->databaseDisplayDockWidget->databaseDisplayModel);
setCentralWidget(visualDatabaseDisplayWidget);
TabVisualDatabaseDisplay::retranslateUi();
}
void TabVisualDatabaseDisplay::retranslateUi()
{
}

View file

@ -0,0 +1,26 @@
#ifndef TAB_VISUAL_DATABASE_DISPLAY_H
#define TAB_VISUAL_DATABASE_DISPLAY_H
#include "../ui/widgets/visual_database_display/visual_database_display_widget.h"
#include "tab.h"
#include <QVBoxLayout>
class TabVisualDatabaseDisplay : public Tab
{
Q_OBJECT
private:
TabDeckEditor *deckEditor;
VisualDatabaseDisplayWidget *visualDatabaseDisplayWidget;
public:
TabVisualDatabaseDisplay(TabSupervisor *_tabSupervisor);
void retranslateUi() override;
QString getTabText() const override
{
return tr("Visual Database Display");
}
};
#endif // TAB_VISUAL_DATABASE_DISPLAY_H

View file

@ -0,0 +1,470 @@
#include "tab_deck_editor_visual.h"
#include "../../../deck/deck_list_model.h"
#include "../../../deck/deck_stats_interface.h"
#include "../../../game/cards/card_database_model.h"
#include "../../../game/filters/filter_builder.h"
#include "../../../server/pending_command.h"
#include "../../../settings/cache_settings.h"
#include "../../ui/pixel_map_generator.h"
#include "../../ui/widgets/cards/card_info_frame_widget.h"
#include "../../ui/widgets/deck_analytics/deck_analytics_widget.h"
#include "../../ui/widgets/visual_deck_editor/visual_deck_editor_widget.h"
#include "../tab_deck_editor.h"
#include "../tab_supervisor.h"
#include "pb/command_deck_upload.pb.h"
#include "tab_deck_editor_visual_tab_widget.h"
#include "trice_limits.h"
#include <QAction>
#include <QApplication>
#include <QCloseEvent>
#include <QCompleter>
#include <QDir>
#include <QDockWidget>
#include <QFileDialog>
#include <QHeaderView>
#include <QLineEdit>
#include <QMenu>
#include <QPrintPreviewDialog>
#include <QProcessEnvironment>
#include <QSplitter>
#include <QTextStream>
#include <QTimer>
#include <QTreeView>
#include <QVBoxLayout>
TabDeckEditorVisual::TabDeckEditorVisual(TabSupervisor *_tabSupervisor) : AbstractTabDeckEditor(_tabSupervisor)
{
setObjectName("TabDeckEditorVisual");
createCentralFrame();
TabDeckEditorVisual::createMenus();
installEventFilter(this);
TabDeckEditorVisual::retranslateUi();
connect(&SettingsCache::instance().shortcuts(), SIGNAL(shortCutChanged()), this, SLOT(refreshShortcuts()));
TabDeckEditorVisual::refreshShortcuts();
TabDeckEditorVisual::loadLayout();
databaseDisplayDockWidget->setHidden(true);
}
void TabDeckEditorVisual::createCentralFrame()
{
centralWidget = new QWidget(this);
centralWidget->setObjectName("centralWidget");
centralFrame = new QVBoxLayout;
centralWidget->setLayout(centralFrame);
tabContainer = new TabDeckEditorVisualTabWidget(centralWidget, this, deckDockWidget->deckModel,
databaseDisplayDockWidget->databaseModel,
databaseDisplayDockWidget->databaseDisplayModel);
connect(tabContainer, &TabDeckEditorVisualTabWidget::cardChanged, this,
&TabDeckEditorVisual::changeModelIndexAndCardInfo);
connect(tabContainer, &TabDeckEditorVisualTabWidget::cardChangedDatabaseDisplay, this,
&AbstractTabDeckEditor::updateCard);
connect(tabContainer, &TabDeckEditorVisualTabWidget::cardClicked, this,
&TabDeckEditorVisual::processMainboardCardClick);
connect(tabContainer, &TabDeckEditorVisualTabWidget::cardClickedDatabaseDisplay, this,
&TabDeckEditorVisual::processCardClickDatabaseDisplay);
centralFrame->addWidget(tabContainer);
setCentralWidget(centralWidget);
setDockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowNestedDocks | QMainWindow::AllowTabbedDocks);
}
void TabDeckEditorVisual::onDeckChanged()
{
AbstractTabDeckEditor::onDeckChanged();
tabContainer->visualDeckView->decklistDataChanged(QModelIndex(), QModelIndex());
tabContainer->deckAnalytics->refreshDisplays(deckDockWidget->deckModel);
tabContainer->sampleHandWidget->setDeckModel(deckDockWidget->deckModel);
}
void TabDeckEditorVisual::createMenus()
{
deckMenu = new DeckEditorMenu(this);
addTabMenu(deckMenu);
viewMenu = new QMenu(this);
cardInfoDockMenu = viewMenu->addMenu(QString());
deckDockMenu = viewMenu->addMenu(QString());
deckAnalyticsMenu = viewMenu->addMenu(QString());
filterDockMenu = viewMenu->addMenu(QString());
printingSelectorDockMenu = viewMenu->addMenu(QString());
aCardInfoDockVisible = cardInfoDockMenu->addAction(QString());
aCardInfoDockVisible->setCheckable(true);
connect(aCardInfoDockVisible, SIGNAL(triggered()), this, SLOT(dockVisibleTriggered()));
aCardInfoDockFloating = cardInfoDockMenu->addAction(QString());
aCardInfoDockFloating->setCheckable(true);
connect(aCardInfoDockFloating, SIGNAL(triggered()), this, SLOT(dockFloatingTriggered()));
aDeckDockVisible = deckDockMenu->addAction(QString());
aDeckDockVisible->setCheckable(true);
connect(aDeckDockVisible, SIGNAL(triggered()), this, SLOT(dockVisibleTriggered()));
aDeckDockFloating = deckDockMenu->addAction(QString());
aDeckDockFloating->setCheckable(true);
connect(aDeckDockFloating, SIGNAL(triggered()), this, SLOT(dockFloatingTriggered()));
aDeckAnalyticsDockVisible = deckAnalyticsMenu->addAction(QString());
aDeckAnalyticsDockVisible->setCheckable(true);
connect(aDeckAnalyticsDockVisible, SIGNAL(triggered()), this, SLOT(dockVisibleTriggered()));
aDeckAnalyticsDockFloating = deckAnalyticsMenu->addAction(QString());
aDeckAnalyticsDockFloating->setCheckable(true);
connect(aDeckAnalyticsDockFloating, SIGNAL(triggered()), this, SLOT(dockFloatingTriggered()));
aFilterDockVisible = filterDockMenu->addAction(QString());
aFilterDockVisible->setCheckable(true);
connect(aFilterDockVisible, SIGNAL(triggered()), this, SLOT(dockVisibleTriggered()));
aFilterDockFloating = filterDockMenu->addAction(QString());
aFilterDockFloating->setCheckable(true);
connect(aFilterDockFloating, SIGNAL(triggered()), this, SLOT(dockFloatingTriggered()));
aPrintingSelectorDockVisible = printingSelectorDockMenu->addAction(QString());
aPrintingSelectorDockVisible->setCheckable(true);
connect(aPrintingSelectorDockVisible, SIGNAL(triggered()), this, SLOT(dockVisibleTriggered()));
aPrintingSelectorDockFloating = printingSelectorDockMenu->addAction(QString());
aPrintingSelectorDockFloating->setCheckable(true);
connect(aPrintingSelectorDockFloating, SIGNAL(triggered()), this, SLOT(dockFloatingTriggered()));
viewMenu->addSeparator();
aResetLayout = viewMenu->addAction(QString());
connect(aResetLayout, SIGNAL(triggered()), this, SLOT(restartLayout()));
viewMenu->addAction(aResetLayout);
deckMenu->setSaveStatus(false);
addTabMenu(viewMenu);
}
QString TabDeckEditorVisual::getTabText() const
{
QString result = tr("Visual Deck: %1").arg(deckDockWidget->getSimpleDeckName());
if (modified)
result.prepend("* ");
return result;
}
void TabDeckEditorVisual::changeModelIndexAndCardInfo(const CardInfoPtr &activeCard)
{
updateCard(activeCard);
changeModelIndexToCard(activeCard);
}
void TabDeckEditorVisual::changeModelIndexToCard(const CardInfoPtr &activeCard)
{
QString cardName = activeCard->getName();
QModelIndex index = deckDockWidget->deckModel->findCard(cardName, DECK_ZONE_MAIN);
if (!index.isValid()) {
index = deckDockWidget->deckModel->findCard(cardName, DECK_ZONE_SIDE);
}
deckDockWidget->deckView->setCurrentIndex(index);
}
void TabDeckEditorVisual::processMainboardCardClick(QMouseEvent *event,
CardInfoPictureWithTextOverlayWidget *instance,
QString zoneName)
{
if (event->button() == Qt::LeftButton) {
actSwapCard(instance->getInfo(), zoneName);
} else if (event->button() == Qt::RightButton) {
actDecrementCard(instance->getInfo());
} else if (event->button() == Qt::MiddleButton) {
deckDockWidget->actRemoveCard();
}
}
void TabDeckEditorVisual::processCardClickDatabaseDisplay(QMouseEvent *event,
CardInfoPictureWithTextOverlayWidget *instance)
{
if (event->button() == Qt::LeftButton) {
actAddCard(instance->getInfo());
} else if (event->button() == Qt::RightButton) {
actDecrementCard(instance->getInfo());
} else if (event->button() == Qt::MiddleButton) {
deckDockWidget->actRemoveCard();
}
}
bool TabDeckEditorVisual::actSaveDeckAs()
{
// We have to disable the quick-add search bar or else it'll steal focus after dialog creation.
tabContainer->visualDeckView->searchBar->setEnabled(false);
auto result = AbstractTabDeckEditor::actSaveDeckAs();
tabContainer->visualDeckView->searchBar->setEnabled(true);
return result;
}
void TabDeckEditorVisual::showPrintingSelector()
{
printingSelectorDockWidget->printingSelector->setCard(cardInfoDockWidget->cardInfo->getInfo(), DECK_ZONE_MAIN);
printingSelectorDockWidget->printingSelector->updateDisplay();
aPrintingSelectorDockVisible->setChecked(true);
printingSelectorDockWidget->setVisible(true);
}
void TabDeckEditorVisual::restartLayout()
{
deckDockWidget->setVisible(true);
cardInfoDockWidget->setVisible(true);
filterDockWidget->setVisible(true);
deckDockWidget->setFloating(false);
cardInfoDockWidget->setFloating(false);
filterDockWidget->setFloating(false);
aCardInfoDockVisible->setChecked(true);
aDeckDockVisible->setChecked(true);
aFilterDockVisible->setChecked(true);
aCardInfoDockFloating->setChecked(false);
aDeckDockFloating->setChecked(false);
aFilterDockFloating->setChecked(false);
addDockWidget(static_cast<Qt::DockWidgetArea>(2), deckDockWidget);
addDockWidget(static_cast<Qt::DockWidgetArea>(2), cardInfoDockWidget);
addDockWidget(static_cast<Qt::DockWidgetArea>(1), deckAnalyticsDock);
addDockWidget(static_cast<Qt::DockWidgetArea>(2), filterDockWidget);
splitDockWidget(cardInfoDockWidget, deckDockWidget, Qt::Horizontal);
splitDockWidget(cardInfoDockWidget, filterDockWidget, Qt::Vertical);
splitDockWidget(searchAndDatabaseDock, deckAnalyticsDock, Qt::Vertical);
deckDockWidget->setMinimumWidth(360);
deckDockWidget->setMaximumWidth(360);
cardInfoDockWidget->setMinimumSize(250, 360);
cardInfoDockWidget->setMaximumSize(250, 360);
QTimer::singleShot(100, this, SLOT(freeDocksSize()));
}
void TabDeckEditorVisual::freeDocksSize()
{
deckDockWidget->setMinimumSize(100, 100);
deckDockWidget->setMaximumSize(5000, 5000);
cardInfoDockWidget->setMinimumSize(100, 100);
cardInfoDockWidget->setMaximumSize(5000, 5000);
filterDockWidget->setMinimumSize(100, 100);
filterDockWidget->setMaximumSize(5000, 5000);
databaseDisplayDockWidget->setMinimumSize(100, 100);
databaseDisplayDockWidget->setMaximumSize(1400, 5000);
}
void TabDeckEditorVisual::refreshShortcuts()
{
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
aResetLayout->setShortcuts(shortcuts.getShortcut("TabDeckEditorVisual/aResetLayout"));
}
void TabDeckEditorVisual::loadLayout()
{
LayoutsSettings &layouts = SettingsCache::instance().layouts();
auto &layoutState = layouts.getDeckEditorLayoutState();
if (layoutState.isNull()) {
restartLayout();
} else {
restoreState(layoutState);
restoreGeometry(layouts.getDeckEditorGeometry());
}
aCardInfoDockVisible->setChecked(!cardInfoDockWidget->isHidden());
aFilterDockVisible->setChecked(!filterDockWidget->isHidden());
aDeckDockVisible->setChecked(!deckDockWidget->isHidden());
aPrintingSelectorDockVisible->setChecked(!printingSelectorDockWidget->isHidden());
aCardInfoDockFloating->setEnabled(aCardInfoDockVisible->isChecked());
aDeckDockFloating->setEnabled(aDeckDockVisible->isChecked());
aFilterDockFloating->setEnabled(aFilterDockVisible->isChecked());
aPrintingSelectorDockFloating->setEnabled(aPrintingSelectorDockVisible->isChecked());
aCardInfoDockFloating->setChecked(cardInfoDockWidget->isFloating());
aFilterDockFloating->setChecked(filterDockWidget->isFloating());
aDeckDockFloating->setChecked(deckDockWidget->isFloating());
aPrintingSelectorDockFloating->setChecked(printingSelectorDockWidget->isFloating());
cardInfoDockWidget->setMinimumSize(layouts.getDeckEditorCardSize());
cardInfoDockWidget->setMaximumSize(layouts.getDeckEditorCardSize());
filterDockWidget->setMinimumSize(layouts.getDeckEditorFilterSize());
filterDockWidget->setMaximumSize(layouts.getDeckEditorFilterSize());
deckDockWidget->setMinimumSize(layouts.getDeckEditorDeckSize());
deckDockWidget->setMaximumSize(layouts.getDeckEditorDeckSize());
printingSelectorDockWidget->setMinimumSize(layouts.getDeckEditorPrintingSelectorSize());
printingSelectorDockWidget->setMaximumSize(layouts.getDeckEditorPrintingSelectorSize());
databaseDisplayDockWidget->setMinimumSize(100, 100);
databaseDisplayDockWidget->setMaximumSize(1400, 5000);
QTimer::singleShot(100, this, &TabDeckEditorVisual::freeDocksSize);
}
void TabDeckEditorVisual::retranslateUi()
{
deckMenu->setTitle(tr("&Visual Deck Editor"));
cardInfoDockWidget->setWindowTitle(tr("Card Info"));
deckDockWidget->setWindowTitle(tr("Deck"));
filterDockWidget->setWindowTitle(tr("Filters"));
viewMenu->setTitle(tr("&View"));
cardInfoDockMenu->setTitle(tr("Card Info"));
deckDockMenu->setTitle(tr("Deck"));
deckAnalyticsMenu->setTitle(tr("Deck Analytics"));
filterDockMenu->setTitle(tr("Filters"));
printingSelectorDockMenu->setTitle(tr("Printing"));
aCardInfoDockVisible->setText(tr("Visible"));
aCardInfoDockFloating->setText(tr("Floating"));
aDeckDockVisible->setText(tr("Visible"));
aDeckDockFloating->setText(tr("Floating"));
aDeckAnalyticsDockVisible->setText(tr("Visible"));
aDeckAnalyticsDockFloating->setText(tr("Floating"));
aFilterDockVisible->setText(tr("Visible"));
aFilterDockFloating->setText(tr("Floating"));
aPrintingSelectorDockVisible->setText(tr("Visible"));
aPrintingSelectorDockFloating->setText(tr("Floating"));
aResetLayout->setText(tr("Reset layout"));
}
// Method uses to sync docks state with menu items state
bool TabDeckEditorVisual::eventFilter(QObject *o, QEvent *e)
{
if (e->type() == QEvent::Close) {
if (o == cardInfoDockWidget) {
aCardInfoDockVisible->setChecked(false);
aCardInfoDockFloating->setEnabled(false);
} else if (o == deckDockWidget) {
aDeckDockVisible->setChecked(false);
aDeckDockFloating->setEnabled(false);
} else if (o == deckAnalyticsDock) {
aDeckAnalyticsDockVisible->setChecked(false);
aDeckAnalyticsDockFloating->setEnabled(false);
} else if (o == filterDockWidget) {
aFilterDockVisible->setChecked(false);
aFilterDockFloating->setEnabled(false);
} else if (o == printingSelectorDockWidget) {
aPrintingSelectorDockVisible->setChecked(false);
aPrintingSelectorDockFloating->setEnabled(false);
}
}
if (o == this && e->type() == QEvent::Hide) {
LayoutsSettings &layouts = SettingsCache::instance().layouts();
layouts.setDeckEditorLayoutState(saveState());
layouts.setDeckEditorGeometry(saveGeometry());
layouts.setDeckEditorCardSize(cardInfoDockWidget->size());
layouts.setDeckEditorFilterSize(filterDockWidget->size());
layouts.setDeckEditorDeckSize(deckDockWidget->size());
layouts.setDeckEditorPrintingSelectorSize(printingSelectorDockWidget->size());
}
return false;
}
void TabDeckEditorVisual::dockVisibleTriggered()
{
QObject *o = sender();
if (o == aCardInfoDockVisible) {
cardInfoDockWidget->setHidden(!aCardInfoDockVisible->isChecked());
aCardInfoDockFloating->setEnabled(aCardInfoDockVisible->isChecked());
return;
}
if (o == aDeckDockVisible) {
deckDockWidget->setHidden(!aDeckDockVisible->isChecked());
aDeckDockFloating->setEnabled(aDeckDockVisible->isChecked());
return;
}
if (o == aDeckAnalyticsDockVisible) {
deckAnalyticsDock->setHidden(!aDeckAnalyticsDockVisible->isChecked());
aDeckAnalyticsDockFloating->setEnabled(aDeckAnalyticsDockVisible->isChecked());
return;
}
if (o == aFilterDockVisible) {
filterDockWidget->setHidden(!aFilterDockVisible->isChecked());
aFilterDockFloating->setEnabled(aFilterDockVisible->isChecked());
return;
}
if (o == aPrintingSelectorDockVisible) {
printingSelectorDockWidget->setHidden(!aPrintingSelectorDockVisible->isChecked());
aPrintingSelectorDockFloating->setEnabled(aPrintingSelectorDockVisible->isChecked());
return;
}
}
void TabDeckEditorVisual::dockFloatingTriggered()
{
QObject *o = sender();
if (o == aCardInfoDockFloating) {
cardInfoDockWidget->setFloating(aCardInfoDockFloating->isChecked());
return;
}
if (o == aDeckDockFloating) {
deckDockWidget->setFloating(aDeckDockFloating->isChecked());
return;
}
if (o == aDeckAnalyticsDockFloating) {
deckAnalyticsDock->setFloating(aDeckAnalyticsDockFloating->isChecked());
return;
}
if (o == aFilterDockFloating) {
filterDockWidget->setFloating(aFilterDockFloating->isChecked());
return;
}
if (o == aPrintingSelectorDockFloating) {
printingSelectorDockWidget->setFloating(aPrintingSelectorDockFloating->isChecked());
return;
}
}
void TabDeckEditorVisual::dockTopLevelChanged(bool topLevel)
{
QObject *o = sender();
if (o == cardInfoDockWidget) {
aCardInfoDockFloating->setChecked(topLevel);
return;
}
if (o == deckDockWidget) {
aDeckDockFloating->setChecked(topLevel);
return;
}
if (o == filterDockWidget) {
aFilterDockFloating->setChecked(topLevel);
return;
}
if (o == deckAnalyticsDock) {
aDeckAnalyticsDockFloating->setChecked(topLevel);
return;
}
if (o == printingSelectorDockWidget) {
aPrintingSelectorDockFloating->setChecked(topLevel);
return;
}
}

View file

@ -0,0 +1,53 @@
#ifndef WINDOW_DECKEDITORVISUAL_H
#define WINDOW_DECKEDITORVISUAL_H
#include "../tab.h"
#include "tab_deck_editor_visual_tab_widget.h"
class TabDeckEditorVisual : public AbstractTabDeckEditor
{
Q_OBJECT
protected slots:
void loadLayout() override;
void restartLayout() override;
void freeDocksSize() override;
void refreshShortcuts() override;
bool eventFilter(QObject *o, QEvent *e) override;
void dockVisibleTriggered() override;
void dockFloatingTriggered() override;
void dockTopLevelChanged(bool topLevel) override;
protected:
TabDeckEditorVisualTabWidget *tabContainer;
QVBoxLayout *centralFrame;
QVBoxLayout *searchAndDatabaseFrame;
QHBoxLayout *searchLayout;
QDockWidget *searchAndDatabaseDock;
QDockWidget *deckAnalyticsDock;
QWidget *centralWidget;
QMenu *deckAnalyticsMenu;
QAction *aDeckAnalyticsDockVisible, *aDeckAnalyticsDockFloating;
public:
explicit TabDeckEditorVisual(TabSupervisor *_tabSupervisor);
void retranslateUi() override;
QString getTabText() const override;
void changeModelIndexAndCardInfo(const CardInfoPtr &activeCard);
void changeModelIndexToCard(const CardInfoPtr &activeCard);
void createDeckAnalyticsDock();
void createMenus() override;
void createSearchAndDatabaseFrame();
void createCentralFrame();
public slots:
void onDeckChanged() override;
void showPrintingSelector() override;
void
processMainboardCardClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance, QString zoneName);
void processCardClickDatabaseDisplay(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
bool actSaveDeckAs() override;
};
#endif

View file

@ -0,0 +1,113 @@
#include "tab_deck_editor_visual_tab_widget.h"
#include "../../ui/widgets/visual_database_display/visual_database_display_widget.h"
#include "../abstract_tab_deck_editor.h"
TabDeckEditorVisualTabWidget::TabDeckEditorVisualTabWidget(QWidget *parent,
AbstractTabDeckEditor *_deckEditor,
DeckListModel *_deckModel,
CardDatabaseModel *_cardDatabaseModel,
CardDatabaseDisplayModel *_cardDatabaseDisplayModel)
: QTabWidget(parent), deckEditor(_deckEditor), deckModel(_deckModel), cardDatabaseModel(_cardDatabaseModel),
cardDatabaseDisplayModel(_cardDatabaseDisplayModel)
{
this->setTabsClosable(true); // Enable tab closing
connect(this, &QTabWidget::tabCloseRequested, this, &TabDeckEditorVisualTabWidget::handleTabClose);
// Set up the layout and add tab widget
layout = new QVBoxLayout(this);
setLayout(layout);
visualDeckView = new VisualDeckEditorWidget(this, deckModel);
visualDeckView->setObjectName("visualDeckView");
connect(visualDeckView, &VisualDeckEditorWidget::activeCardChanged, this,
&TabDeckEditorVisualTabWidget::onCardChanged);
connect(visualDeckView, &VisualDeckEditorWidget::cardClicked, this,
&TabDeckEditorVisualTabWidget::onCardClickedDeckEditor);
connect(visualDeckView, &VisualDeckEditorWidget::cardAdditionRequested, deckEditor,
&AbstractTabDeckEditor::actAddCard);
visualDatabaseDisplay =
new VisualDatabaseDisplayWidget(this, deckEditor, _cardDatabaseModel, _cardDatabaseDisplayModel);
visualDatabaseDisplay->setObjectName("visualDatabaseView");
connect(visualDatabaseDisplay, &VisualDatabaseDisplayWidget::cardHoveredDatabaseDisplay, this,
&TabDeckEditorVisualTabWidget::onCardChangedDatabaseDisplay);
connect(visualDatabaseDisplay, &VisualDatabaseDisplayWidget::cardClickedDatabaseDisplay, this,
&TabDeckEditorVisualTabWidget::onCardClickedDatabaseDisplay);
deckAnalytics = new DeckAnalyticsWidget(this, deckModel);
deckAnalytics->setObjectName("deckAnalytics");
sampleHandWidget = new VisualDeckEditorSampleHandWidget(this, deckModel);
this->addNewTab(visualDeckView, tr("Visual Deck View"));
this->addNewTab(visualDatabaseDisplay, tr("Visual Database Display"));
this->addNewTab(deckAnalytics, tr("Deck Analytics"));
this->addNewTab(sampleHandWidget, tr("Sample Hand"));
}
void TabDeckEditorVisualTabWidget::onCardChanged(CardInfoPtr activeCard)
{
emit cardChanged(activeCard);
}
void TabDeckEditorVisualTabWidget::onCardChangedDatabaseDisplay(CardInfoPtr activeCard)
{
emit cardChangedDatabaseDisplay(activeCard);
}
void TabDeckEditorVisualTabWidget::onCardClickedDeckEditor(QMouseEvent *event,
CardInfoPictureWithTextOverlayWidget *instance,
QString zoneName)
{
emit cardClicked(event, instance, zoneName);
}
void TabDeckEditorVisualTabWidget::onCardClickedDatabaseDisplay(QMouseEvent *event,
CardInfoPictureWithTextOverlayWidget *instance)
{
emit cardClickedDatabaseDisplay(event, instance);
}
void TabDeckEditorVisualTabWidget::addNewTab(QWidget *widget, const QString &title)
{
// Add new tab to the tab widget
this->addTab(widget, title);
}
void TabDeckEditorVisualTabWidget::removeCurrentTab()
{
// Remove the currently selected tab
int currentIndex = this->currentIndex();
if (currentIndex != -1) {
this->removeTab(currentIndex);
}
}
void TabDeckEditorVisualTabWidget::setTabTitle(int index, const QString &title)
{
// Set the title of the tab at the given index
if (index >= 0 && index < this->count()) {
this->setTabText(index, title);
}
}
QWidget *TabDeckEditorVisualTabWidget::getCurrentTab() const
{
// Return the currently selected tab widget
return this->currentWidget();
}
int TabDeckEditorVisualTabWidget::getTabCount() const
{
// Return the number of tabs
return this->count();
}
void TabDeckEditorVisualTabWidget::handleTabClose(int index)
{
// Handle closing of the tab at the given index
QWidget *tab = this->widget(index);
this->removeTab(index);
delete tab; // Delete the tab's widget to free memory
}

View file

@ -0,0 +1,62 @@
#ifndef TAB_DECK_EDITOR_VISUAL_TAB_WIDGET_H
#define TAB_DECK_EDITOR_VISUAL_TAB_WIDGET_H
#include "../../ui/widgets/deck_analytics/deck_analytics_widget.h"
#include "../../ui/widgets/printing_selector/printing_selector.h"
#include "../../ui/widgets/visual_database_display/visual_database_display_widget.h"
#include "../../ui/widgets/visual_deck_editor/visual_deck_editor_sample_hand_widget.h"
#include "../../ui/widgets/visual_deck_editor/visual_deck_editor_widget.h"
#include "../abstract_tab_deck_editor.h"
#include <QTabWidget>
#include <QVBoxLayout>
#include <QWidget>
class TabDeckEditorVisualTabWidget : public QTabWidget
{
Q_OBJECT
public:
explicit TabDeckEditorVisualTabWidget(QWidget *parent,
AbstractTabDeckEditor *_deckEditor,
DeckListModel *_deckModel,
CardDatabaseModel *_cardDatabaseModel,
CardDatabaseDisplayModel *_cardDatabaseDisplayModel);
// Utility functions
void addNewTab(QWidget *widget, const QString &title);
void removeCurrentTab();
void setTabTitle(int index, const QString &title);
QWidget *getCurrentTab() const;
int getTabCount() const;
VisualDeckEditorWidget *visualDeckView;
DeckAnalyticsWidget *deckAnalytics;
VisualDatabaseDisplayWidget *visualDatabaseDisplay;
PrintingSelector *printingSelector;
VisualDeckEditorSampleHandWidget *sampleHandWidget;
public slots:
void onCardChanged(CardInfoPtr activeCard);
void onCardChangedDatabaseDisplay(CardInfoPtr activeCard);
void onCardClickedDeckEditor(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance, QString zoneName);
void onCardClickedDatabaseDisplay(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
signals:
void cardChanged(CardInfoPtr activeCard);
void cardChangedDatabaseDisplay(CardInfoPtr activeCard);
void cardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance, QString zoneName);
void cardClickedDatabaseDisplay(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance);
private:
QVBoxLayout *layout; // Layout for the tab widget and other controls
AbstractTabDeckEditor *deckEditor;
DeckListModel *deckModel;
CardDatabaseModel *cardDatabaseModel;
CardDatabaseDisplayModel *cardDatabaseDisplayModel;
private slots:
void handleTabClose(int index); // Slot for closing a tab
};
#endif // TAB_DECK_EDITOR_VISUAL_TAB_WIDGET_H

View file

@ -12,7 +12,7 @@
TabDeckStorageVisual::TabDeckStorageVisual(TabSupervisor *_tabSupervisor)
: Tab(_tabSupervisor), visualDeckStorageWidget(new VisualDeckStorageWidget(this))
{
connect(this, &TabDeckStorageVisual::openDeckEditor, tabSupervisor, &TabSupervisor::addDeckEditorTab);
connect(this, &TabDeckStorageVisual::openDeckEditor, tabSupervisor, &TabSupervisor::addVisualDeckEditorTab);
connect(visualDeckStorageWidget, &VisualDeckStorageWidget::deckLoadRequested, this,
&TabDeckStorageVisual::actOpenLocalDeck);
connect(visualDeckStorageWidget, &VisualDeckStorageWidget::openDeckEditor, this,

View file

@ -33,7 +33,7 @@ void TappedOutInterface::queryFinished(QNetworkReply *reply)
* can be extracted from the header. The http status is a 302 "redirect".
*/
QString deckUrl = reply->rawHeader("Location");
qCDebug(TappedOutInterfaceLog) << "Tappedout: good reply, http status" << httpStatus << "location" << deckUrl;
qCInfo(TappedOutInterfaceLog) << "Tappedout: good reply, http status" << httpStatus << "location" << deckUrl;
QDesktopServices::openUrl("https://tappedout.net" + deckUrl);
} else {
/*
@ -57,8 +57,8 @@ void TappedOutInterface::queryFinished(QNetworkReply *reply)
}
QString errorMessage = errorMessageList.join("\n");
qCDebug(TappedOutInterfaceLog) << "Tappedout: bad reply, http status" << httpStatus << "size" << data.size()
<< "message" << errorMessage;
qCWarning(TappedOutInterfaceLog) << "Tappedout: bad reply, http status" << httpStatus << "size" << data.size()
<< "message" << errorMessage;
QMessageBox::critical(nullptr, tr("Error"), errorMessage);
}

View file

@ -7,7 +7,7 @@
#include <QWidget>
#include <qstyle.h>
inline Q_LOGGING_CATEGORY(FlowLayoutLog, "flow_layout");
inline Q_LOGGING_CATEGORY(FlowLayoutLog, "flow_layout", QtInfoMsg);
class FlowLayout : public QLayout
{

View file

@ -1,5 +1,6 @@
#include "overlap_layout.h"
#include <QDebug>
#include <QtMath>
/**
@ -32,9 +33,10 @@ OverlapLayout::OverlapLayout(QWidget *parent,
const int overlapPercentage,
const int maxColumns,
const int maxRows,
const Qt::Orientation direction)
const Qt::Orientation _overlapDirection,
const Qt::Orientation _flowDirection)
: QLayout(parent), overlapPercentage(overlapPercentage), maxColumns(maxColumns), maxRows(maxRows),
direction(direction)
overlapDirection(_overlapDirection), flowDirection(_flowDirection)
{
}
@ -148,17 +150,21 @@ void OverlapLayout::setGeometry(const QRect &rect)
}
// Calculate the overlap offsets based on the layout direction and overlap percentage.
const int overlapOffsetWidth = (direction == Qt::Horizontal) ? (maxItemWidth * overlapPercentage / 100) : 0;
const int overlapOffsetHeight = (direction == Qt::Vertical) ? (maxItemHeight * overlapPercentage / 100) : 0;
const int overlapOffsetWidth = (overlapDirection == Qt::Horizontal) ? (maxItemWidth * overlapPercentage / 100) : 0;
const int overlapOffsetHeight = (overlapDirection == Qt::Vertical) ? (maxItemHeight * overlapPercentage / 100) : 0;
// Determine the number of columns based on layout constraints and available space.
int columns;
if (direction == Qt::Horizontal) {
if (flowDirection == Qt::Horizontal) {
if (maxColumns > 0) {
// Calculate the maximum possible columns given the available width and overlap.
const int availableColumns = (availableWidth + overlapOffsetWidth) / (maxItemWidth - overlapOffsetWidth);
// Use the smaller of maxColumns and availableColumns.
qCDebug(OverlapLayoutLog) << " Max Columns " << maxColumns << " available columns " << availableColumns;
columns = qMin(maxColumns, availableColumns);
if (columns < 1) {
columns = 1;
}
} else {
// If no maxColumns constraint, allow as many columns as possible.
columns = INT_MAX;
@ -170,12 +176,16 @@ void OverlapLayout::setGeometry(const QRect &rect)
// Determine the number of rows based on layout constraints and available space.
int rows;
if (direction == Qt::Vertical) {
if (flowDirection == Qt::Vertical) {
if (maxRows > 0) {
// Calculate the maximum possible rows given the available height and overlap.
const int availableRows = (availableHeight + overlapOffsetHeight) / (maxItemHeight - overlapOffsetHeight);
// Use the smaller of maxRows and availableRows.
qCDebug(OverlapLayoutLog) << " Max Rows " << maxRows << " available rows " << availableRows;
rows = qMin(maxRows, availableRows);
if (rows < 1) {
rows = 1;
}
} else {
// If no maxRows constraint, allow as many rows as possible.
rows = INT_MAX;
@ -200,16 +210,17 @@ void OverlapLayout::setGeometry(const QRect &rect)
const int yPos = rect.top() + currentRow * (maxItemHeight - overlapOffsetHeight);
item->setGeometry(QRect(xPos, yPos, maxItemWidth, maxItemHeight));
// TODO: Figure this out properly or maybe adjust size hint to account for this?
// Update row and column indices based on the layout direction.
if (direction == Qt::Horizontal) {
if (overlapDirection == Qt::Horizontal) {
currentColumn++;
if (currentColumn >= columns) {
if (currentColumn > qCeil(itemList.size() / rows)) {
currentColumn = 0;
currentRow++;
}
} else {
currentRow++;
if (currentRow >= rows) {
if (currentRow > qCeil(itemList.size() / columns)) {
currentRow = 0;
currentColumn++;
}
@ -223,88 +234,86 @@ void OverlapLayout::setGeometry(const QRect &rect)
*/
QSize OverlapLayout::calculatePreferredSize() const
{
// Get the parent widget for size and margin calculations.
const QWidget *parentWidget = this->parentWidget();
if (!parentWidget) {
return QSize(0, 0);
}
// Determine the maximum item dimensions.
if (itemList.isEmpty()) {
return QSize(0, 0);
}
int availableWidth = parentWidget->width();
int availableHeight = parentWidget->height();
const QMargins margins = parentWidget->contentsMargins();
availableWidth -= margins.left() + margins.right();
availableHeight -= margins.top() + margins.bottom();
// Determine the maximum item width and height among all layout items.
int maxItemWidth = 0;
int maxItemHeight = 0;
for (QLayoutItem *item : itemList) {
if (item == nullptr) {
continue;
if (item != nullptr && item->widget()) {
QSize itemSize = item->widget()->sizeHint();
maxItemWidth = qMax(maxItemWidth, itemSize.width());
maxItemHeight = qMax(maxItemHeight, itemSize.height());
}
if (!item->widget()) {
continue;
}
QSize itemSize = item->widget()->sizeHint();
maxItemWidth = qMax(maxItemWidth, itemSize.width());
maxItemHeight = qMax(maxItemHeight, itemSize.height());
}
// Calculate the overlap offsets.
const int extra_for_overlap = (100 - overlapPercentage);
const int overlapOffsetWidth =
(direction == Qt::Horizontal) ? qRound((maxItemWidth / 100.0) * extra_for_overlap) : 0;
const int overlapOffsetHeight =
(direction == Qt::Vertical) ? qRound((maxItemHeight / 100.0) * extra_for_overlap) : 0;
// Calculate the overlap offsets based on the layout direction and overlap percentage.
const int overlapOffsetWidth = (overlapDirection == Qt::Horizontal) ? (maxItemWidth * overlapPercentage / 100) : 0;
const int overlapOffsetHeight = (overlapDirection == Qt::Vertical) ? (maxItemHeight * overlapPercentage / 100) : 0;
// Variables to hold the total dimensions based on layout orientation.
int totalWidth = 0;
int totalHeight = 0;
// Calculate the total size based on the layout direction and constraints.
if (direction == Qt::Horizontal) {
// Determine the number of columns:
// - Use maxColumns if it is greater than 0 (constraint set by the user).
// - Otherwise, set the number of columns to the total number of items in the layout.
const int numColumns = (maxColumns > 0) ? static_cast<int>(maxColumns) : static_cast<int>(itemList.size());
// Calculate the extra space required for overlaps between columns:
// - Each overlap reduces the effective width of subsequent items.
const int extra_space_for_overlaps = overlapOffsetWidth * (numColumns - 1);
// Total width:
// - The first item's width is fully included (maxItemWidth).
// - Add the space for all overlaps between adjacent items.
totalWidth = maxItemWidth + extra_space_for_overlaps;
// Determine the number of rows:
// - Use maxRows if maxColumns is set (to constrain the number of rows).
// - Otherwise, assume a single row.
const int numRows =
(maxColumns > 0) ? qCeil(static_cast<double>(itemList.size()) / static_cast<double>(numColumns)) : 1;
// Total height:
// - Multiply the number of rows by the item height (maxItemHeight).
// - Subtract the height overlap between rows to avoid double-counting.
totalHeight = maxItemHeight * numRows - (numRows - 1) * overlapOffsetHeight;
} else if (direction == Qt::Vertical) {
// Determine the number of columns:
// - Use maxRows to calculate how many columns are needed if a row constraint exists.
// - Otherwise, assume a single column.
const int numColumns =
(maxRows != 0) ? qCeil(static_cast<double>(itemList.size()) / static_cast<double>(maxRows)) : 1;
// Total width:
// - Multiply the number of columns by the item width (maxItemWidth).
// - Subtract the width overlap between columns to avoid double-counting.
totalWidth = maxItemWidth * numColumns - (numColumns - 1) * overlapOffsetWidth;
// Determine the number of rows:
// - Use maxRows if it is greater than 0 (constraint set by the user).
// - Otherwise, set the number of rows to the total number of items in the layout.
const int numRows = (maxRows > 0) ? static_cast<int>(maxRows) : static_cast<int>(itemList.size());
// Calculate the extra space required for overlaps between rows:
// - Each overlap reduces the effective height of subsequent items.
const int extraSpaceForOverlaps = overlapOffsetHeight * (numRows - 1);
// Total height:
// - The first item's height is fully included (maxItemHeight).
// - Add the space for all overlaps between adjacent items.
totalHeight = maxItemHeight + extraSpaceForOverlaps;
// Determine the number of columns based on layout constraints and available space.
int columns;
if (flowDirection == Qt::Horizontal) {
if (maxColumns > 0) {
// Calculate the maximum possible columns given the available width and overlap.
const int availableColumns = (availableWidth + overlapOffsetWidth) / (maxItemWidth - overlapOffsetWidth);
// Use the smaller of maxColumns and availableColumns.
qCDebug(OverlapLayoutLog) << " Max Columns " << maxColumns << " available columns " << availableColumns;
columns = qMin(maxColumns, availableColumns);
if (columns < 1) {
columns = 1;
}
} else {
// If no maxColumns constraint, allow as many columns as possible.
columns = INT_MAX;
}
} else {
// If not a horizontal layout, column count is irrelevant.
columns = INT_MAX;
}
return {totalWidth, totalHeight};
// Determine the number of rows based on layout constraints and available space.
int rows;
if (flowDirection == Qt::Vertical) {
if (maxRows > 0) {
// Calculate the maximum possible rows given the available height and overlap.
const int availableRows = (availableHeight + overlapOffsetHeight) / (maxItemHeight - overlapOffsetHeight);
// Use the smaller of maxRows and availableRows.
qCDebug(OverlapLayoutLog) << " Max Rows " << maxRows << " available rows " << availableRows;
rows = qMin(maxRows, availableRows);
if (rows < 1) {
rows = 1;
}
} else {
// If no maxRows constraint, allow as many rows as possible.
rows = INT_MAX;
}
} else {
// If not a vertical layout, row count is irrelevant.
rows = INT_MAX;
}
if (overlapDirection == Qt::Horizontal) {
return QSize(maxItemWidth + ((qCeil(itemList.size() / rows)) * (maxItemWidth - overlapOffsetWidth)),
rows * maxItemHeight);
} else {
return QSize(columns * maxItemWidth,
maxItemHeight + ((qCeil(itemList.size() / columns)) * (maxItemHeight - overlapOffsetHeight)));
}
}
/**
@ -341,7 +350,7 @@ QSize OverlapLayout::minimumSize() const
*/
void OverlapLayout::setDirection(const Qt::Orientation _direction)
{
direction = _direction;
overlapDirection = _direction;
}
/**
@ -378,7 +387,7 @@ void OverlapLayout::setMaxRows(const int _maxRows)
*/
int OverlapLayout::calculateMaxColumns() const
{
if (direction != Qt::Vertical || itemList.isEmpty()) {
if (overlapDirection != Qt::Vertical || itemList.isEmpty()) {
return 1; // Only relevant if the layout direction is vertical
}
@ -410,7 +419,7 @@ int OverlapLayout::calculateMaxColumns() const
*/
int OverlapLayout::calculateRowsForColumns(const int columns) const
{
if (direction != Qt::Vertical || itemList.isEmpty() || columns <= 0) {
if (overlapDirection != Qt::Vertical || itemList.isEmpty() || columns <= 0) {
return 1; // Only relevant if the layout direction is vertical and there are items
}
@ -429,7 +438,7 @@ int OverlapLayout::calculateRowsForColumns(const int columns) const
*/
int OverlapLayout::calculateMaxRows() const
{
if (direction != Qt::Horizontal || itemList.isEmpty()) {
if (overlapDirection != Qt::Horizontal || itemList.isEmpty()) {
return 1; // Only relevant if the layout direction is horizontal
}
@ -464,7 +473,7 @@ int OverlapLayout::calculateMaxRows() const
*/
int OverlapLayout::calculateColumnsForRows(const int rows) const
{
if (direction != Qt::Horizontal || itemList.isEmpty() || rows <= 0) {
if (overlapDirection != Qt::Horizontal || itemList.isEmpty() || rows <= 0) {
return 1; // Only relevant if the layout direction is horizontal and there are items
}

View file

@ -3,8 +3,11 @@
#include <QLayout>
#include <QList>
#include <QLoggingCategory>
#include <QWidget>
inline Q_LOGGING_CATEGORY(OverlapLayoutLog, "overlap_layout");
class OverlapLayout : public QLayout
{
public:
@ -12,7 +15,8 @@ public:
int overlapPercentage = 10,
int maxColumns = 2,
int maxRows = 2,
Qt::Orientation direction = Qt::Horizontal);
Qt::Orientation overlapDirection = Qt::Vertical,
Qt::Orientation flowDirection = Qt::Horizontal);
~OverlapLayout();
void addItem(QLayoutItem *item) override;
@ -35,7 +39,8 @@ private:
int overlapPercentage;
int maxColumns;
int maxRows;
Qt::Orientation direction;
Qt::Orientation overlapDirection;
Qt::Orientation flowDirection;
// Calculate the preferred size of the layout
QSize calculatePreferredSize() const;

View file

@ -117,7 +117,7 @@ void LineEditCompleter::setCompleter(QCompleter *completer)
{
c = completer;
c->setWidget(this);
connect(c, SIGNAL(activated(QString)), this, SLOT(insertCompletion(QString)));
connect(c, qOverload<const QString &>(&QCompleter::activated), this, &LineEditCompleter::insertCompletion);
}
void LineEditCompleter::setCompletionList(QStringList completionList)

View file

@ -18,7 +18,7 @@ PhaseButton::PhaseButton(const QString &_name, QGraphicsItem *parent, QAction *_
{
if (highlightable) {
activeAnimationTimer = new QTimer(this);
connect(activeAnimationTimer, SIGNAL(timeout()), this, SLOT(updateAnimation()));
connect(activeAnimationTimer, &QTimer::timeout, this, &PhaseButton::updateAnimation);
activeAnimationTimer->setSingleShot(false);
} else
activeAnimationCounter = 9;
@ -106,9 +106,9 @@ PhasesToolbar::PhasesToolbar(QGraphicsItem *parent)
: QGraphicsItem(parent), width(100), height(100), ySpacing(1), symbolSize(8)
{
auto *aUntapAll = new QAction(this);
connect(aUntapAll, SIGNAL(triggered()), this, SLOT(actUntapAll()));
connect(aUntapAll, &QAction::triggered, this, &PhasesToolbar::actUntapAll);
auto *aDrawCard = new QAction(this);
connect(aDrawCard, SIGNAL(triggered()), this, SLOT(actDrawCard()));
connect(aDrawCard, &QAction::triggered, this, &PhasesToolbar::actDrawCard);
PhaseButton *untapButton = new PhaseButton("untap", this, aUntapAll);
PhaseButton *upkeepButton = new PhaseButton("upkeep", this);
@ -126,10 +126,10 @@ PhasesToolbar::PhasesToolbar(QGraphicsItem *parent)
<< combatBlockersButton << combatDamageButton << combatEndButton << main2Button << cleanupButton;
for (auto &i : buttonList)
connect(i, SIGNAL(clicked()), this, SLOT(phaseButtonClicked()));
connect(i, &PhaseButton::clicked, this, &PhasesToolbar::phaseButtonClicked);
nextTurnButton = new PhaseButton("nextturn", this, nullptr, false);
connect(nextTurnButton, SIGNAL(clicked()), this, SLOT(actNextTurn()));
connect(nextTurnButton, &PhaseButton::clicked, this, &PhasesToolbar::actNextTurn);
rearrangeButtons();

View file

@ -23,11 +23,10 @@
PictureLoader::PictureLoader() : QObject(nullptr)
{
worker = new PictureLoaderWorker;
connect(&SettingsCache::instance(), SIGNAL(picsPathChanged()), this, SLOT(picsPathChanged()));
connect(&SettingsCache::instance(), SIGNAL(picDownloadChanged()), this, SLOT(picDownloadChanged()));
connect(&SettingsCache::instance(), &SettingsCache::picsPathChanged, this, &PictureLoader::picsPathChanged);
connect(&SettingsCache::instance(), &SettingsCache::picDownloadChanged, this, &PictureLoader::picDownloadChanged);
connect(worker, SIGNAL(imageLoaded(CardInfoPtr, const QImage &)), this,
SLOT(imageLoaded(CardInfoPtr, const QImage &)));
connect(worker, &PictureLoaderWorker::imageLoaded, this, &PictureLoader::imageLoaded);
}
PictureLoader::~PictureLoader()
@ -115,7 +114,7 @@ void PictureLoader::getPixmap(QPixmap &pixmap, CardInfoPtr card, QSize size)
QPixmap bigPixmap;
if (QPixmapCache::find(key, &bigPixmap)) {
if (bigPixmap.isNull()) {
qCWarning(PictureLoaderLog) << "Cached pixmap for key" << key << "is NULL!";
qCDebug(PictureLoaderLog) << "Cached pixmap for key" << key << "is NULL!";
return;
}
@ -140,7 +139,11 @@ void PictureLoader::imageLoaded(CardInfoPtr card, const QImage &image)
QPixmapCache::insert(card->getPixmapCacheKey(), QPixmap());
} else {
if (card->getUpsideDownArt()) {
#if (QT_VERSION >= QT_VERSION_CHECK(6, 9, 0))
QImage mirrorImage = image.flipped(Qt::Horizontal | Qt::Vertical);
#else
QImage mirrorImage = image.mirrored(true, true);
#endif
QPixmapCache::insert(card->getPixmapCacheKey(), QPixmap::fromImage(mirrorImage));
} else {
QPixmapCache::insert(card->getPixmapCacheKey(), QPixmap::fromImage(image));
@ -195,3 +198,31 @@ void PictureLoader::picsPathChanged()
{
QPixmapCache::clear();
}
bool PictureLoader::hasCustomArt()
{
auto picsPath = SettingsCache::instance().getPicsPath();
QDirIterator it(picsPath, QDir::Dirs | QDir::NoDotAndDotDot);
// Check if there is at least one non-directory file in the pics path, other
// than in the "downloadedPics" subdirectory.
while (it.hasNext()) {
#if (QT_VERSION >= QT_VERSION_CHECK(6, 3, 0))
QFileInfo dir(it.nextFileInfo());
#else
// nextFileInfo() is only available in Qt 6.3+, for previous versions, we build
// the QFileInfo from a QString which requires more system calls.
QFileInfo dir(it.next());
#endif
if (it.fileName() == "downloadedPics")
continue;
QDirIterator subIt(it.filePath(), QDir::Files, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
if (subIt.hasNext()) {
return true;
}
}
return false;
}

View file

@ -1,7 +1,7 @@
#ifndef PICTURELOADER_H
#define PICTURELOADER_H
#include "../../../game/cards/card_database.h"
#include "../../../game/cards/card_info.h"
#include "picture_loader_worker.h"
#include <QLoggingCategory>
@ -36,6 +36,7 @@ public:
static void clearPixmapCache(CardInfoPtr card);
static void clearPixmapCache();
static void cacheCardPixmaps(QList<CardInfoPtr> cards);
static bool hasCustomArt();
public slots:
static void clearNetworkCache();

View file

@ -16,11 +16,16 @@ QStringList PictureLoaderWorker::md5Blacklist = QStringList() << "db0c48db407a90
PictureLoaderWorker::PictureLoaderWorker()
: QObject(nullptr), picsPath(SettingsCache::instance().getPicsPath()),
customPicsPath(SettingsCache::instance().getCustomPicsPath()),
picDownload(SettingsCache::instance().getPicDownload()), downloadRunning(false), loadQueueRunning(false)
picDownload(SettingsCache::instance().getPicDownload()), downloadRunning(false), loadQueueRunning(false),
overrideAllCardArtWithPersonalPreference(SettingsCache::instance().getOverrideAllCardArtWithPersonalPreference())
{
connect(this, SIGNAL(startLoadQueue()), this, SLOT(processLoadQueue()), Qt::QueuedConnection);
connect(&SettingsCache::instance(), SIGNAL(picsPathChanged()), this, SLOT(picsPathChanged()));
connect(&SettingsCache::instance(), SIGNAL(picDownloadChanged()), this, SLOT(picDownloadChanged()));
connect(this, &PictureLoaderWorker::startLoadQueue, this, &PictureLoaderWorker::processLoadQueue,
Qt::QueuedConnection);
connect(&SettingsCache::instance(), &SettingsCache::picsPathChanged, this, &PictureLoaderWorker::picsPathChanged);
connect(&SettingsCache::instance(), &SettingsCache::picDownloadChanged, this,
&PictureLoaderWorker::picDownloadChanged);
connect(&SettingsCache::instance(), &SettingsCache::overrideAllCardArtWithPersonalPreferenceChanged, this,
&PictureLoaderWorker::setOverrideAllCardArtWithPersonalPreference);
networkManager = new QNetworkAccessManager(this);
// We need a timeout to ensure requests don't hang indefinitely in case of
@ -40,7 +45,7 @@ PictureLoaderWorker::PictureLoaderWorker()
// Use a ManualRedirectPolicy since we keep track of redirects in picDownloadFinished
// We can't use NoLessSafeRedirectPolicy because it is not applied with AlwaysCache
networkManager->setRedirectPolicy(QNetworkRequest::ManualRedirectPolicy);
connect(networkManager, SIGNAL(finished(QNetworkReply *)), this, SLOT(picDownloadFinished(QNetworkReply *)));
connect(networkManager, &QNetworkAccessManager::finished, this, &PictureLoaderWorker::picDownloadFinished);
cacheFilePath = SettingsCache::instance().getRedirectCachePath() + REDIRECT_CACHE_FILENAME;
loadRedirectCache();
@ -83,11 +88,24 @@ void PictureLoaderWorker::processLoadQueue()
qCDebug(PictureLoaderWorkerLog).nospace()
<< "[card: " << cardName << " set: " << setName << "]: Trying to load picture";
if (CardDatabaseManager::getInstance()->isProviderIdForPreferredPrinting(
cardName, cardBeingLoaded.getCard()->getPixmapCacheKey())) {
if (cardImageExistsOnDisk(setName, correctedCardName)) {
continue;
}
// FIXME: This is a hack so that to keep old Cockatrice behavior
// (ignoring provider ID) when the "override all card art with personal
// preference" is set.
//
// Figure out a proper way to integrate the two systems at some point.
//
// Note: need to go through a member for
// overrideAllCardArtWithPersonalPreference as reading from the
// SettingsCache instance from the PictureLoaderWorker thread could
// cause race conditions.
//
// XXX: Reading from the CardDatabaseManager instance from the
// PictureLoaderWorker thread might not be safe either
bool searchCustomPics = overrideAllCardArtWithPersonalPreference ||
CardDatabaseManager::getInstance()->isProviderIdForPreferredPrinting(
cardName, cardBeingLoaded.getCard()->getPixmapCacheKey());
if (searchCustomPics && cardImageExistsOnDisk(setName, correctedCardName, searchCustomPics)) {
continue;
}
qCDebug(PictureLoaderWorkerLog).nospace()
@ -100,23 +118,26 @@ void PictureLoaderWorker::processLoadQueue()
}
}
bool PictureLoaderWorker::cardImageExistsOnDisk(QString &setName, QString &correctedCardname)
bool PictureLoaderWorker::cardImageExistsOnDisk(QString &setName, QString &correctedCardname, bool searchCustomPics)
{
QImage image;
QImageReader imgReader;
imgReader.setDecideFormatFromContent(true);
QList<QString> picsPaths = QList<QString>();
QDirIterator it(customPicsPath, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
// Recursively check all subdirectories of the CUSTOM folder
while (it.hasNext()) {
QString thisPath(it.next());
QFileInfo thisFileInfo(thisPath);
if (searchCustomPics) {
QDirIterator it(customPicsPath, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
if (thisFileInfo.isFile() &&
(thisFileInfo.fileName() == correctedCardname || thisFileInfo.completeBaseName() == correctedCardname ||
thisFileInfo.baseName() == correctedCardname)) {
picsPaths << thisPath; // Card found in the CUSTOM directory, somewhere
// Recursively check all subdirectories of the CUSTOM folder
while (it.hasNext()) {
QString thisPath(it.next());
QFileInfo thisFileInfo(thisPath);
if (thisFileInfo.isFile() &&
(thisFileInfo.fileName() == correctedCardname || thisFileInfo.completeBaseName() == correctedCardname ||
thisFileInfo.baseName() == correctedCardname)) {
picsPaths << thisPath; // Card found in the CUSTOM directory, somewhere
}
}
}
@ -194,7 +215,7 @@ void PictureLoaderWorker::picDownloadFailed()
loadQueue.prepend(cardBeingDownloaded);
mutex.unlock();
} else {
qCDebug(PictureLoaderWorkerLog).nospace()
qCWarning(PictureLoaderWorkerLog).nospace()
<< "[card: " << cardBeingDownloaded.getCard()->getCorrectedName()
<< " set: " << cardBeingDownloaded.getSetName() << "]: Picture NOT found, "
<< (picDownload ? "download failed" : "downloads disabled")
@ -225,6 +246,23 @@ QNetworkReply *PictureLoaderWorker::makeRequest(const QUrl &url)
QNetworkRequest req(url);
// QNetworkDiskCache leaks file descriptors when downloading compressed
// files, see https://bugreports.qt.io/browse/QTBUG-135641
//
// We can set the Accept-Encoding header manually to disable Qt's automatic
// response decompression, but then we would have to deal with decompression
// ourselves.
//
// Since we are dowloading images that are usually stored in a
// compressed format (e.g. jpeg or webp), it's not clear compression at the
// HTTP level helps; in fact, images are typically returned without
// compression. Redirects, on the other hand, are compressed and cause file
// descriptor leaks -- but since redirects have no payload, we don't really
// care either.
//
// In the end, just do the simple thing and disable HTTP compression.
req.setRawHeader("accept-encoding", "identity");
if (!picDownload) {
req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysCache);
}
@ -405,7 +443,7 @@ void PictureLoaderWorker::picDownloadFinished(QNetworkReply *reply)
}
if (logSuccessMessage) {
qCDebug(PictureLoaderWorkerLog).nospace()
qCInfo(PictureLoaderWorkerLog).nospace()
<< "[card: " << cardBeingDownloaded.getCard()->getName() << " set: " << cardBeingDownloaded.getSetName()
<< "]: Image successfully " << (isFromCache ? "loaded from cached" : "downloaded from") << " url "
<< reply->url().toDisplayString();
@ -451,7 +489,12 @@ void PictureLoaderWorker::picsPathChanged()
customPicsPath = SettingsCache::instance().getCustomPicsPath();
}
void PictureLoaderWorker::setOverrideAllCardArtWithPersonalPreference(bool _overrideAllCardArtWithPersonalPreference)
{
overrideAllCardArtWithPersonalPreference = _overrideAllCardArtWithPersonalPreference;
}
void PictureLoaderWorker::clearNetworkCache()
{
networkManager->cache()->clear();
}
}

View file

@ -1,7 +1,7 @@
#ifndef PICTURE_LOADER_WORKER_H
#define PICTURE_LOADER_WORKER_H
#include "../../../game/cards/card_database.h"
#include "../../../game/cards/card_info.h"
#include "picture_to_load.h"
#include <QLoggingCategory>
@ -42,8 +42,16 @@ private:
PictureToLoad cardBeingLoaded;
PictureToLoad cardBeingDownloaded;
bool picDownload, downloadRunning, loadQueueRunning;
bool overrideAllCardArtWithPersonalPreference;
void startNextPicDownload();
bool cardImageExistsOnDisk(QString &setName, QString &correctedCardName);
/** Emit the `imageLoaded` signal and return `true` if a picture is found on
disk, return `false` otherwise.
If `searchCustomPics` is `true`, the CUSTOM folder is searched for a
matching image first; otherwise, only the set-based folders are used. */
bool cardImageExistsOnDisk(QString &setName, QString &correctedCardName, bool searchCustomPics);
bool imageIsBlackListed(const QByteArray &);
QNetworkReply *makeRequest(const QUrl &url);
void cacheRedirect(const QUrl &originalUrl, const QUrl &redirectUrl);
@ -58,6 +66,7 @@ private slots:
void picDownloadChanged();
void picsPathChanged();
void setOverrideAllCardArtWithPersonalPreference(bool _overrideAllCardArtWithPersonalPreference);
public slots:
void processLoadQueue();

View file

@ -1,7 +1,7 @@
#ifndef PICTURE_TO_LOAD_H
#define PICTURE_TO_LOAD_H
#include "../../../game/cards/card_database.h"
#include "../../../game/cards/card_info.h"
#include <QLoggingCategory>

View file

@ -24,7 +24,7 @@ static const QStringList DEFAULT_RESOURCE_PATHS = {":/resources"};
ThemeManager::ThemeManager(QObject *parent) : QObject(parent)
{
ensureThemeDirectoryExists();
connect(&SettingsCache::instance(), SIGNAL(themeChanged()), this, SLOT(themeChangedSlot()));
connect(&SettingsCache::instance(), &SettingsCache::themeChanged, this, &ThemeManager::themeChangedSlot);
themeChangedSlot();
}
@ -32,7 +32,7 @@ void ThemeManager::ensureThemeDirectoryExists()
{
if (SettingsCache::instance().getThemeName().isEmpty() ||
!getAvailableThemes().contains(SettingsCache::instance().getThemeName())) {
qCDebug(ThemeManagerLog) << "Theme name not set, setting default value";
qCInfo(ThemeManagerLog) << "Theme name not set, setting default value";
SettingsCache::instance().setThemeName(NONE_THEME_NAME);
}
}
@ -105,7 +105,7 @@ QBrush ThemeManager::loadExtraBrush(QString fileName, QBrush &fallbackBrush)
void ThemeManager::themeChangedSlot()
{
QString themeName = SettingsCache::instance().getThemeName();
qCDebug(ThemeManagerLog) << "Theme changed:" << themeName;
qCInfo(ThemeManagerLog) << "Theme changed:" << themeName;
QString dirPath = getAvailableThemes().value(themeName);
QDir dir = dirPath;

View file

@ -1,7 +1,7 @@
#ifndef COLOR_IDENTITY_WIDGET_H
#define COLOR_IDENTITY_WIDGET_H
#include "../../../../../game/cards/card_database.h"
#include "../../../../../game/cards/card_info.h"
#include <QHBoxLayout>
#include <QWidget>

View file

@ -1,7 +1,7 @@
#ifndef MANA_COST_WIDGET_H
#define MANA_COST_WIDGET_H
#include "../../../../../game/cards/card_database.h"
#include "../../../../../game/cards/card_info.h"
#include <QHBoxLayout>
#include <QWidget>

View file

@ -0,0 +1,81 @@
#include "card_group_display_widget.h"
#include "../../../../../deck/deck_list_model.h"
#include "../../../../../game/cards/card_database_manager.h"
#include "../../../../../utility/card_info_comparator.h"
#include "../card_info_picture_with_text_overlay_widget.h"
#include <QResizeEvent>
CardGroupDisplayWidget::CardGroupDisplayWidget(QWidget *parent,
DeckListModel *_deckListModel,
QString _zoneName,
QString _cardGroupCategory,
QString _activeGroupCriteria,
QStringList _activeSortCriteria,
int bannerOpacity,
CardSizeWidget *_cardSizeWidget)
: QWidget(parent), deckListModel(_deckListModel), 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);
updateCardDisplays();
}
void CardGroupDisplayWidget::updateCardDisplays()
{
}
QList<CardInfoPtr> CardGroupDisplayWidget::getCardsMatchingGroup(QList<CardInfoPtr> cardsToSort)
{
cardsToSort = sortCardList(cardsToSort, activeSortCriteria, Qt::SortOrder::AscendingOrder);
QList<CardInfoPtr> activeList;
for (const CardInfoPtr &info : cardsToSort) {
if (info && info->getProperty(activeGroupCriteria) == cardGroupCategory) {
activeList.append(info);
}
}
return activeList;
}
QList<CardInfoPtr> CardGroupDisplayWidget::sortCardList(QList<CardInfoPtr> cardsToSort,
const QStringList properties,
Qt::SortOrder order = Qt::AscendingOrder)
{
CardInfoComparator comparator(properties, order);
std::sort(cardsToSort.begin(), cardsToSort.end(), comparator);
return cardsToSort;
}
void CardGroupDisplayWidget::onActiveSortCriteriaChanged(QStringList _activeSortCriteria)
{
if (activeSortCriteria != _activeSortCriteria) {
activeSortCriteria = _activeSortCriteria;
updateCardDisplays(); // Refresh display with new sorting
}
}
void CardGroupDisplayWidget::onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card)
{
emit cardClicked(event, card);
}
void CardGroupDisplayWidget::onHover(CardInfoPtr card)
{
emit cardHovered(card);
}
void CardGroupDisplayWidget::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
}

View file

@ -0,0 +1,53 @@
#ifndef CARD_GROUP_DISPLAY_WIDGET_H
#define CARD_GROUP_DISPLAY_WIDGET_H
#include "../../../../../deck/deck_list_model.h"
#include "../../../../../game/cards/card_info.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,
QString zoneName,
QString cardGroupCategory,
QString activeGroupCriteria,
QStringList activeSortCriteria,
int bannerOpacity,
CardSizeWidget *cardSizeWidget);
QList<CardInfoPtr> getCardsMatchingGroup(QList<CardInfoPtr> cardsToSort);
void resizeEvent(QResizeEvent *event) override;
DeckListModel *deckListModel;
QString zoneName;
QString cardGroupCategory;
QString activeGroupCriteria;
QStringList activeSortCriteria;
CardSizeWidget *cardSizeWidget;
public slots:
QList<CardInfoPtr> sortCardList(QList<CardInfoPtr> cardsToSort, QStringList properties, Qt::SortOrder order);
void onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card);
void onHover(CardInfoPtr card);
virtual void updateCardDisplays();
void onActiveSortCriteriaChanged(QStringList activeSortCriteria);
signals:
void cardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card);
void cardHovered(CardInfoPtr card);
protected:
QVBoxLayout *layout;
BannerWidget *banner;
};
#endif // CARD_GROUP_DISPLAY_WIDGET_H

View file

@ -0,0 +1,107 @@
#include "flat_card_group_display_widget.h"
#include "../../../../../deck/deck_list_model.h"
#include "../../../../../game/cards/card_database_manager.h"
#include "../../../../../utility/card_info_comparator.h"
#include "../card_info_picture_with_text_overlay_widget.h"
#include <QResizeEvent>
FlatCardGroupDisplayWidget::FlatCardGroupDisplayWidget(QWidget *parent,
DeckListModel *_deckListModel,
QString _zoneName,
QString _cardGroupCategory,
QString _activeGroupCriteria,
QStringList _activeSortCriteria,
int bannerOpacity,
CardSizeWidget *_cardSizeWidget)
: CardGroupDisplayWidget(parent,
_deckListModel,
_zoneName,
_cardGroupCategory,
_activeGroupCriteria,
_activeSortCriteria,
bannerOpacity,
_cardSizeWidget)
{
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAlwaysOff);
banner->setBuddy(flowWidget);
layout->addWidget(flowWidget);
FlatCardGroupDisplayWidget::updateCardDisplays();
connect(deckListModel, &DeckListModel::dataChanged, this, &FlatCardGroupDisplayWidget::updateCardDisplays);
}
void FlatCardGroupDisplayWidget::updateCardDisplays()
{
// Retrieve and sort cards
QList<CardInfoPtr> cardsInZone = getCardsMatchingGroup(deckListModel->getCardsAsCardInfoPtrsForZone(zoneName));
// Show or hide widget
bool shouldBeVisible = !cardsInZone.isEmpty();
if (shouldBeVisible != isVisible()) {
setVisible(shouldBeVisible);
}
// Retrieve existing widgets
QList<CardInfoPictureWithTextOverlayWidget *> existingWidgets =
flowWidget->findChildren<CardInfoPictureWithTextOverlayWidget *>();
QHash<QString, QList<CardInfoPictureWithTextOverlayWidget *>> widgetMap;
for (CardInfoPictureWithTextOverlayWidget *widget : existingWidgets) {
widgetMap[widget->getInfo()->getName()].append(widget);
}
QList<CardInfoPictureWithTextOverlayWidget *> sortedWidgets;
QSet<CardInfoPictureWithTextOverlayWidget *> usedWidgets;
// Ensure widgets are ordered to match the sorted cards
for (const CardInfoPtr &card : cardsInZone) {
QString name = card->getName();
CardInfoPictureWithTextOverlayWidget *widget = nullptr;
if (!widgetMap[name].isEmpty()) {
// Reuse an existing widget
widget = widgetMap[name].takeFirst();
} else {
// Create a new widget if needed
widget = new CardInfoPictureWithTextOverlayWidget(flowWidget, true);
widget->setScaleFactor(cardSizeWidget->getSlider()->value());
widget->setCard(card);
connect(widget, &CardInfoPictureWithTextOverlayWidget::imageClicked, this,
&FlatCardGroupDisplayWidget::onClick);
connect(widget, &CardInfoPictureWithTextOverlayWidget::hoveredOnCard, this,
&FlatCardGroupDisplayWidget::onHover);
connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, widget,
&CardInfoPictureWidget::setScaleFactor);
flowWidget->addWidget(widget);
}
// Store in sorted order
sortedWidgets.append(widget);
usedWidgets.insert(widget);
}
// Remove extra widgets
for (CardInfoPictureWithTextOverlayWidget *widget : existingWidgets) {
if (!usedWidgets.contains(widget)) {
flowWidget->layout()->removeWidget(widget);
widget->deleteLater();
}
}
// **Reorder widgets in place**
for (int i = 0; i < sortedWidgets.size(); ++i) {
sortedWidgets[i]->setParent(nullptr); // Temporarily detach
}
for (int i = 0; i < sortedWidgets.size(); ++i) {
flowWidget->addWidget(sortedWidgets[i]); // Reattach in correct order
}
}
void FlatCardGroupDisplayWidget::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
}

View file

@ -0,0 +1,30 @@
#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,
QString zoneName,
QString cardGroupCategory,
QString activeGroupCriteria,
QStringList activeSortCriteria,
int bannerOpacity,
CardSizeWidget *cardSizeWidget);
void resizeEvent(QResizeEvent *event) override;
public slots:
void updateCardDisplays() override;
private:
FlowWidget *flowWidget;
};
#endif // FLAT_CARD_GROUP_DISPLAY_WIDGET_H

View file

@ -0,0 +1,122 @@
#include "overlapped_card_group_display_widget.h"
#include "../../../../../deck/deck_list_model.h"
#include "../../../../../game/cards/card_database_manager.h"
#include "../../../../../utility/card_info_comparator.h"
#include "../card_info_picture_with_text_overlay_widget.h"
#include <QResizeEvent>
OverlappedCardGroupDisplayWidget::OverlappedCardGroupDisplayWidget(QWidget *parent,
DeckListModel *_deckListModel,
QString _zoneName,
QString _cardGroupCategory,
QString _activeGroupCriteria,
QStringList _activeSortCriteria,
int bannerOpacity,
CardSizeWidget *_cardSizeWidget)
: CardGroupDisplayWidget(parent,
_deckListModel,
_zoneName,
_cardGroupCategory,
_activeGroupCriteria,
_activeSortCriteria,
bannerOpacity,
_cardSizeWidget)
{
overlapWidget = new OverlapWidget(this, 80, 1, 1, Qt::Vertical, true);
banner->setBuddy(overlapWidget);
layout->addWidget(overlapWidget);
OverlappedCardGroupDisplayWidget::updateCardDisplays();
connect(deckListModel, &DeckListModel::dataChanged, this, &OverlappedCardGroupDisplayWidget::updateCardDisplays);
connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, this,
[this]() { overlapWidget->adjustMaxColumnsAndRows(); });
}
void OverlappedCardGroupDisplayWidget::updateCardDisplays()
{
overlapWidget->setUpdatesEnabled(false);
// Retrieve and sort cards
QList<CardInfoPtr> cardsInZone = getCardsMatchingGroup(deckListModel->getCardsAsCardInfoPtrsForZone(zoneName));
// Show or hide widget
bool shouldBeVisible = !cardsInZone.isEmpty();
if (shouldBeVisible != isVisible()) {
setVisible(shouldBeVisible);
}
// Retrieve existing widgets
QList<CardInfoPictureWithTextOverlayWidget *> existingWidgets =
overlapWidget->findChildren<CardInfoPictureWithTextOverlayWidget *>();
QHash<QString, QList<CardInfoPictureWithTextOverlayWidget *>> widgetMap;
for (CardInfoPictureWithTextOverlayWidget *widget : existingWidgets) {
widgetMap[widget->getInfo()->getName()].append(widget);
}
QList<CardInfoPictureWithTextOverlayWidget *> sortedWidgets;
QSet<CardInfoPictureWithTextOverlayWidget *> usedWidgets;
// Ensure widgets are ordered to match the sorted cards
for (const CardInfoPtr &card : cardsInZone) {
QString name = card->getName();
CardInfoPictureWithTextOverlayWidget *widget = nullptr;
if (!widgetMap[name].isEmpty()) {
// Reuse an existing widget
widget = widgetMap[name].takeFirst();
} else {
// Create a new widget if needed
widget = new CardInfoPictureWithTextOverlayWidget(overlapWidget, true);
widget->setScaleFactor(cardSizeWidget->getSlider()->value());
widget->setCard(card);
connect(widget, &CardInfoPictureWithTextOverlayWidget::imageClicked, this,
&OverlappedCardGroupDisplayWidget::onClick);
connect(widget, &CardInfoPictureWithTextOverlayWidget::hoveredOnCard, this,
&OverlappedCardGroupDisplayWidget::onHover);
connect(cardSizeWidget->getSlider(), &QSlider::valueChanged, widget,
&CardInfoPictureWidget::setScaleFactor);
overlapWidget->addWidget(widget);
}
// Store in sorted order
sortedWidgets.append(widget);
usedWidgets.insert(widget);
}
// Remove extra widgets
for (CardInfoPictureWithTextOverlayWidget *widget : existingWidgets) {
if (!usedWidgets.contains(widget)) {
overlapWidget->layout()->removeWidget(widget);
delete widget;
}
}
// **Reorder widgets in place**
for (int i = 0; i < sortedWidgets.size(); ++i) {
sortedWidgets[i]->setParent(nullptr); // Temporarily detach
}
for (int i = 0; i < sortedWidgets.size(); ++i) {
overlapWidget->addWidget(sortedWidgets[i]); // Reattach in correct order
}
// Ensure proper layering
for (CardInfoPictureWithTextOverlayWidget *widget : sortedWidgets) {
widget->raise();
}
overlapWidget->adjustMaxColumnsAndRows();
overlapWidget->setUpdatesEnabled(true);
overlapWidget->update();
}
void OverlappedCardGroupDisplayWidget::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
overlapWidget->resize(event->size());
overlapWidget->adjustMaxColumnsAndRows();
}

View file

@ -0,0 +1,30 @@
#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,
QString zoneName,
QString cardGroupCategory,
QString activeGroupCriteria,
QStringList activeSortCriteria,
int bannerOpacity,
CardSizeWidget *cardSizeWidget);
void resizeEvent(QResizeEvent *event) override;
public slots:
void updateCardDisplays() override;
private:
OverlapWidget *overlapWidget;
};
#endif // OVERLAPPED_CARD_GROUP_DISPLAY_WIDGET_H

View file

@ -22,7 +22,7 @@ CardInfoDisplayWidget::CardInfoDisplayWidget(const QString &cardName,
pic->setObjectName("pic");
text = new CardInfoTextWidget();
text->setObjectName("text");
connect(text, SIGNAL(linkActivated(const QString &)), this, SLOT(setCard(const QString &)));
connect(text, &CardInfoTextWidget::linkActivated, this, [this](const QString &card) { setCard(card); });
auto *layout = new QVBoxLayout();
layout->setObjectName("layout");
@ -52,7 +52,7 @@ void CardInfoDisplayWidget::setCard(CardInfoPtr card)
disconnect(info.data(), nullptr, this, nullptr);
info = std::move(card);
if (info)
connect(info.data(), SIGNAL(destroyed()), this, SLOT(clear()));
connect(info.data(), &QObject::destroyed, this, &CardInfoDisplayWidget::clear);
text->setCard(info);
pic->setCard(info);

View file

@ -1,7 +1,7 @@
#ifndef CARDINFOWIDGET_H
#define CARDINFOWIDGET_H
#include "../../../../game/cards/card_database.h"
#include "../../../../game/cards/card_info.h"
#include <QComboBox>
#include <QFrame>

View file

@ -21,7 +21,7 @@ CardInfoFrameWidget::CardInfoFrameWidget(const QString &cardName, QWidget *paren
text = new CardInfoTextWidget();
text->setObjectName("text");
connect(text, SIGNAL(linkActivated(const QString &)), this, SLOT(setCard(const QString &)));
connect(text, &CardInfoTextWidget::linkActivated, this, qOverload<const QString &>(&CardInfoFrameWidget::setCard));
tab1 = new QWidget(this);
tab2 = new QWidget(this);
@ -34,7 +34,7 @@ CardInfoFrameWidget::CardInfoFrameWidget(const QString &cardName, QWidget *paren
insertTab(ImageOnlyView, tab1, QString());
insertTab(TextOnlyView, tab2, QString());
insertTab(ImageAndTextView, tab3, QString());
connect(this, SIGNAL(currentChanged(int)), this, SLOT(setViewMode(int)));
connect(this, &CardInfoFrameWidget::currentChanged, this, &CardInfoFrameWidget::setViewMode);
tab1Layout = new QVBoxLayout();
tab1Layout->setObjectName("tab1Layout");
@ -61,6 +61,7 @@ CardInfoFrameWidget::CardInfoFrameWidget(const QString &cardName, QWidget *paren
setViewMode(SettingsCache::instance().getCardInfoViewMode());
// TODO: Change this to be by UUID
setCard(CardDatabaseManager::getInstance()->getCard(cardName));
}
@ -154,7 +155,7 @@ void CardInfoFrameWidget::setCard(CardInfoPtr card)
info = std::move(card);
if (info) {
connect(info.data(), SIGNAL(destroyed()), this, SLOT(clearCard()));
connect(info.data(), &QObject::destroyed, this, &CardInfoFrameWidget::clearCard);
}
setViewTransformationButtonVisibility(hasTransformation(info));

View file

@ -1,7 +1,7 @@
#ifndef CARDFRAME_H
#define CARDFRAME_H
#include "../../../../game/cards/card_database.h"
#include "../../../../game/cards/card_info.h"
#include <QPushButton>
#include <QTabWidget>

View file

@ -1,7 +1,7 @@
#ifndef CARD_PICTURE_ENLARGED_WIDGET_H
#define CARD_PICTURE_ENLARGED_WIDGET_H
#include "../../../../game/cards/card_database.h"
#include "../../../../game/cards/card_info.h"
#include <QPixmap>
#include <QWidget>

View file

@ -9,6 +9,7 @@
#include <QMenu>
#include <QMouseEvent>
#include <QScreen>
#include <QStylePainter>
#include <QWidget>
#include <utility>
@ -37,7 +38,7 @@ CardInfoPictureWidget::CardInfoPictureWidget(QWidget *parent, const bool hoverTo
setMouseTracking(true);
}
enlargedPixmapWidget = new CardInfoPictureEnlargedWidget(this);
enlargedPixmapWidget = new CardInfoPictureEnlargedWidget(this->window());
enlargedPixmapWidget->hide();
hoverTimer = new QTimer(this);
@ -67,7 +68,7 @@ void CardInfoPictureWidget::setCard(CardInfoPtr card)
info = std::move(card);
if (info) {
connect(info.data(), SIGNAL(pixmapUpdated()), this, SLOT(updatePixmap()));
connect(info.data(), &CardInfo::pixmapUpdated, this, &CardInfoPictureWidget::updatePixmap);
}
updatePixmap();
@ -210,7 +211,8 @@ void CardInfoPictureWidget::paintEvent(QPaintEvent *event)
*/
QSize CardInfoPictureWidget::sizeHint() const
{
return {static_cast<int>(baseWidth * scaleFactor), static_cast<int>(baseHeight * scaleFactor)};
return {static_cast<int>(baseWidth * scaleFactor / 100.0),
static_cast<int>(baseWidth * scaleFactor / 100.0 * aspectRatio)};
}
/**
@ -254,10 +256,24 @@ void CardInfoPictureWidget::leaveEvent(QEvent *event)
void CardInfoPictureWidget::mouseMoveEvent(QMouseEvent *event)
{
QWidget::mouseMoveEvent(event);
if (hoverToZoomEnabled && enlargedPixmapWidget->isVisible()) {
const QPointF cursorPos = QCursor::pos();
enlargedPixmapWidget->move(QPoint(static_cast<int>(cursorPos.x()) + enlargedPixmapOffset,
static_cast<int>(cursorPos.y()) + enlargedPixmapOffset));
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);
}
}
@ -267,6 +283,8 @@ void CardInfoPictureWidget::mousePressEvent(QMouseEvent *event)
if (event->button() == Qt::RightButton) {
createRightClickMenu()->popup(QCursor::pos());
}
emit cardClicked();
}
QMenu *CardInfoPictureWidget::createRightClickMenu()
@ -312,11 +330,26 @@ QMenu *CardInfoPictureWidget::createViewRelatedCardsMenu()
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 = qobject_cast<MainWindow *>(window());
auto mainWindow = findMainWindow();
QList<AbstractTabDeckEditor *> deckEditorTabs = mainWindow->getTabSupervisor()->getDeckEditorTabs();
if (deckEditorTabs.isEmpty()) {
@ -355,13 +388,25 @@ void CardInfoPictureWidget::showEnlargedPixmap() const
return;
}
const QSize enlargedSize(static_cast<int>(size().width() * scaleFactor),
static_cast<int>(size().width() * aspectRatio * scaleFactor));
const QSize enlargedSize(static_cast<int>(size().width() * 2), static_cast<int>(size().width() * aspectRatio * 2));
enlargedPixmapWidget->setCardPixmap(info, enlargedSize);
const QPointF cursorPos = QCursor::pos();
enlargedPixmapWidget->move(static_cast<int>(cursorPos.x()) + enlargedPixmapOffset,
static_cast<int>(cursorPos.y()) + enlargedPixmapOffset);
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();
}

View file

@ -1,12 +1,14 @@
#ifndef CARD_INFO_PICTURE_H
#define CARD_INFO_PICTURE_H
#include "../../../../game/cards/card_database.h"
#include "../../../../game/cards/card_info.h"
#include "card_info_picture_enlarged_widget.h"
#include <QTimer>
#include <QWidget>
inline Q_LOGGING_CATEGORY(CardInfoPictureWidgetLog, "card_info_picture_widget");
class AbstractCardItem;
class QMenu;
@ -32,6 +34,7 @@ signals:
void hoveredOnCard(CardInfoPtr hoveredCard);
void cardScaleFactorChanged(int _scale);
void cardChanged(CardInfoPtr card);
void cardClicked();
protected:
void resizeEvent(QResizeEvent *event) override;
@ -58,7 +61,7 @@ private:
qreal aspectRatio = magicTheGatheringCardAspectRatio;
int baseWidth = 200;
int baseHeight = 200;
double scaleFactor = 1.5;
double scaleFactor = 100;
QPixmap resizedPixmap;
bool pixmapDirty;
bool hoverToZoomEnabled;

View file

@ -1,7 +1,7 @@
#ifndef CARDINFOTEXT_H
#define CARDINFOTEXT_H
#include "../../../../game/cards/card_database.h"
#include "../../../../game/cards/card_info.h"
#include <QFrame>
class QLabel;

View file

@ -0,0 +1,168 @@
#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,
QString _zoneName,
QString _activeGroupCriteria,
QStringList _activeSortCriteria,
int bannerOpacity,
int subBannerOpacity,
CardSizeWidget *_cardSizeWidget)
: QWidget(parent), deckListModel(_deckListModel), zoneName(_zoneName), activeGroupCriteria(_activeGroupCriteria),
activeSortCriteria(_activeSortCriteria), 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, &DeckListModel::dataChanged, this, &DeckCardZoneDisplayWidget::displayCards);
}
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(CardInfoPtr card)
{
emit cardHovered(card);
}
void DeckCardZoneDisplayWidget::displayCards()
{
addCardGroupIfItDoesNotExist();
deleteCardGroupIfItDoesNotExist();
}
void DeckCardZoneDisplayWidget::refreshDisplayType(const QString &_displayType)
{
displayType = _displayType;
QLayoutItem *item;
while ((item = cardGroupLayout->takeAt(0)) != nullptr) {
if (item->widget()) {
item->widget()->deleteLater();
} else if (item->layout()) {
delete item->layout();
}
delete item;
}
// 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::addCardGroupIfItDoesNotExist()
{
QList<CardGroupDisplayWidget *> cardGroupsDisplayWidgets =
cardGroupContainer->findChildren<CardGroupDisplayWidget *>();
QList<QString> cardGroups = getGroupCriteriaValueList();
for (QString cardGroup : cardGroups) {
bool found = false;
for (CardGroupDisplayWidget *cardGroupDisplayWidget : cardGroupsDisplayWidgets) {
if (cardGroupDisplayWidget->cardGroupCategory == cardGroup) {
found = true;
}
}
if (found) {
continue;
}
if (displayType == "overlap") {
auto *display_widget = new OverlappedCardGroupDisplayWidget(
cardGroupContainer, deckListModel, zoneName, cardGroup, activeGroupCriteria, activeSortCriteria,
subBannerOpacity, cardSizeWidget);
connect(display_widget, SIGNAL(cardClicked(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)), this,
SLOT(onClick(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)));
connect(display_widget, SIGNAL(cardHovered(CardInfoPtr)), this, SLOT(onHover(CardInfoPtr)));
connect(this, &DeckCardZoneDisplayWidget::activeSortCriteriaChanged, display_widget,
&CardGroupDisplayWidget::onActiveSortCriteriaChanged);
cardGroupLayout->addWidget(display_widget);
} else if (displayType == "flat") {
auto *display_widget = new FlatCardGroupDisplayWidget(cardGroupContainer, deckListModel, zoneName,
cardGroup, activeGroupCriteria, activeSortCriteria,
subBannerOpacity, cardSizeWidget);
connect(display_widget, SIGNAL(cardClicked(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)), this,
SLOT(onClick(QMouseEvent *, CardInfoPictureWithTextOverlayWidget *)));
connect(display_widget, SIGNAL(cardHovered(CardInfoPtr)), this, SLOT(onHover(CardInfoPtr)));
connect(this, &DeckCardZoneDisplayWidget::activeSortCriteriaChanged, display_widget,
&CardGroupDisplayWidget::onActiveSortCriteriaChanged);
cardGroupLayout->addWidget(display_widget);
}
}
}
void DeckCardZoneDisplayWidget::deleteCardGroupIfItDoesNotExist()
{
QList<CardGroupDisplayWidget *> cardGroupsDisplayWidgets =
cardGroupContainer->findChildren<CardGroupDisplayWidget *>();
QList<QString> validGroups = getGroupCriteriaValueList();
for (CardGroupDisplayWidget *cardGroupDisplayWidget : cardGroupsDisplayWidgets) {
if (!validGroups.contains(cardGroupDisplayWidget->cardGroupCategory)) {
cardGroupLayout->removeWidget(cardGroupDisplayWidget);
cardGroupDisplayWidget->deleteLater(); // Properly delete the widget after the event loop cycles
}
}
}
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<CardInfoPtr> cardsInZone = deckListModel->getCardsAsCardInfoPtrsForZone(zoneName);
for (CardInfoPtr cardInZone : cardsInZone) {
groupCriteriaValues.append(cardInZone->getProperty(activeGroupCriteria));
}
groupCriteriaValues.removeDuplicates();
groupCriteriaValues.sort();
return groupCriteriaValues;
}

View file

@ -0,0 +1,62 @@
#ifndef DECK_CARD_ZONE_DISPLAY_WIDGET_H
#define DECK_CARD_ZONE_DISPLAY_WIDGET_H
#include "../../../../deck/deck_list_model.h"
#include "../../../../game/cards/card_info.h"
#include "../general/display/banner_widget.h"
#include "../general/layout_containers/overlap_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,
QString zoneName,
QString activeGroupCriteria,
QStringList activeSortCriteria,
int bannerOpacity,
int subBannerOpacity,
CardSizeWidget *_cardSizeWidget);
DeckListModel *deckListModel;
QString zoneName;
void addCardsToOverlapWidget();
void resizeEvent(QResizeEvent *event) override;
public slots:
void onClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card);
void onHover(CardInfoPtr card);
void displayCards();
void refreshDisplayType(const QString &displayType);
void addCardGroupIfItDoesNotExist();
void deleteCardGroupIfItDoesNotExist();
void onActiveGroupCriteriaChanged(QString activeGroupCriteria);
void onActiveSortCriteriaChanged(QStringList activeSortCriteria);
QList<QString> getGroupCriteriaValueList();
signals:
void cardClicked(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *card, QString zoneName);
void cardHovered(CardInfoPtr card);
void activeSortCriteriaChanged(QStringList activeSortCriteria);
private:
QString activeGroupCriteria;
QStringList activeSortCriteria;
int bannerOpacity = 20;
int subBannerOpacity = 10;
CardSizeWidget *cardSizeWidget;
QVBoxLayout *layout;
BannerWidget *banner;
QWidget *cardGroupContainer;
QVBoxLayout *cardGroupLayout;
QString displayType = "flat";
OverlapWidget *overlapWidget;
};
#endif // DECK_CARD_ZONE_DISPLAY_WIDGET_H

Some files were not shown because too many files have changed in this diff Show more