Merge branch 'master' into game-time-part2-checkbox

This commit is contained in:
lilyhuang-github 2025-03-25 20:36:38 -04:00 committed by GitHub
commit dee3d6998f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
87 changed files with 3472 additions and 2613 deletions

View file

@ -55,6 +55,9 @@ DeckEditorMenu::DeckEditorMenu(QWidget *parent, AbstractTabDeckEditor *_deckEdit
aExportDeckDecklist = new QAction(QString(), this);
connect(aExportDeckDecklist, SIGNAL(triggered()), deckEditor, SLOT(actExportDeckDecklist()));
aExportDeckDecklistXyz = new QAction(QString(), this);
connect(aExportDeckDecklistXyz, SIGNAL(triggered()), deckEditor, SLOT(actExportDeckDecklistXyz()));
aAnalyzeDeckDeckstats = new QAction(QString(), this);
connect(aAnalyzeDeckDeckstats, SIGNAL(triggered()), deckEditor, SLOT(actAnalyzeDeckDeckstats()));
@ -63,6 +66,8 @@ DeckEditorMenu::DeckEditorMenu(QWidget *parent, AbstractTabDeckEditor *_deckEdit
analyzeDeckMenu = new QMenu(this);
analyzeDeckMenu->addAction(aExportDeckDecklist);
analyzeDeckMenu->addAction(aExportDeckDecklistXyz);
analyzeDeckMenu->addSeparator();
analyzeDeckMenu->addAction(aAnalyzeDeckDeckstats);
analyzeDeckMenu->addAction(aAnalyzeDeckTappedout);
@ -160,6 +165,7 @@ void DeckEditorMenu::retranslateUi()
analyzeDeckMenu->setTitle(tr("&Send deck to online service"));
aExportDeckDecklist->setText(tr("Create decklist (decklist.org)"));
aExportDeckDecklistXyz->setText(tr("Create decklist (decklist.xyz)"));
aAnalyzeDeckDeckstats->setText(tr("Analyze deck (deckstats.net)"));
aAnalyzeDeckTappedout->setText(tr("Analyze deck (tappedout.net)"));
@ -172,13 +178,17 @@ void DeckEditorMenu::refreshShortcuts()
aNewDeck->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aNewDeck"));
aLoadDeck->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aLoadDeck"));
aSaveDeck->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aSaveDeck"));
aExportDeckDecklist->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aExportDeckDecklist"));
aSaveDeckAs->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aSaveDeckAs"));
aLoadDeckFromClipboard->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aLoadDeckFromClipboard"));
aEditDeckInClipboard->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aEditDeckInClipboard"));
aEditDeckInClipboardRaw->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aEditDeckInClipboardRaw"));
aPrintDeck->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aPrintDeck"));
aExportDeckDecklist->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aExportDeckDecklist"));
aExportDeckDecklistXyz->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aExportDeckDecklistXyz"));
aAnalyzeDeckDeckstats->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aAnalyzeDeck"));
aAnalyzeDeckTappedout->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aAnalyzeDeckTappedout"));
aClose->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aClose"));
aSaveDeckToClipboard->setShortcuts(shortcuts.getShortcut("TabDeckEditor/aSaveDeckToClipboard"));

View file

@ -17,7 +17,7 @@ public:
QAction *aNewDeck, *aLoadDeck, *aClearRecents, *aSaveDeck, *aSaveDeckAs, *aLoadDeckFromClipboard,
*aEditDeckInClipboard, *aEditDeckInClipboardRaw, *aSaveDeckToClipboard, *aSaveDeckToClipboardNoSetInfo,
*aSaveDeckToClipboardRaw, *aSaveDeckToClipboardRawNoSetInfo, *aPrintDeck, *aExportDeckDecklist,
*aAnalyzeDeckDeckstats, *aAnalyzeDeckTappedout, *aClose;
*aExportDeckDecklistXyz, *aAnalyzeDeckDeckstats, *aAnalyzeDeckTappedout, *aClose;
QMenu *loadRecentDeckMenu, *analyzeDeckMenu, *editDeckInClipboardMenu, *saveDeckToClipboardMenu;
void setSaveStatus(bool newStatus);

View file

@ -355,8 +355,8 @@ bool AbstractTabDeckEditor::actSaveDeckAs()
dialog.setDirectory(SettingsCache::instance().getDeckPath());
dialog.setAcceptMode(QFileDialog::AcceptSave);
dialog.setDefaultSuffix("cod");
dialog.setNameFilters(DeckLoader::fileNameFilters);
dialog.selectFile(getDeckList()->getName().trimmed() + ".cod");
dialog.setNameFilters(DeckLoader::FILE_NAME_FILTERS);
dialog.selectFile(getDeckList()->getName().trimmed());
if (!dialog.exec())
return false;
@ -455,17 +455,12 @@ void AbstractTabDeckEditor::actPrintDeck()
dlg->exec();
}
// Action called when export deck to decklist menu item is pressed.
void AbstractTabDeckEditor::actExportDeckDecklist()
void AbstractTabDeckEditor::exportToDecklistWebsite(DeckLoader::DecklistWebsite website)
{
// Get the decklist class for the deck.
DeckLoader *const deck = getDeckList();
// create a string to load the decklist url into.
QString decklistUrlString;
// check if deck is not null
if (deck) {
if (DeckLoader *const deck = getDeckList()) {
// Get the decklist url string from the deck loader class.
decklistUrlString = deck->exportDeckToDecklist();
QString decklistUrlString = deck->exportDeckToDecklist(website);
// Check to make sure the string isn't empty.
if (QString::compare(decklistUrlString, "", Qt::CaseInsensitive) == 0) {
// Show an error if the deck is empty, and return.
@ -481,10 +476,26 @@ void AbstractTabDeckEditor::actExportDeckDecklist()
QDesktopServices::openUrl(decklistUrlString);
} else {
// if there's no deck loader object, return an error
QMessageBox::critical(this, tr("Error"), tr("No deck was selected to be saved."));
QMessageBox::critical(this, tr("Error"), tr("No deck was selected to be exported."));
}
}
/**
* Exports the deck to www.decklist.org (the old website)
*/
void AbstractTabDeckEditor::actExportDeckDecklist()
{
exportToDecklistWebsite(DeckLoader::DecklistOrg);
}
/**
* Exports the deck to www.decklist.xyz (the new website)
*/
void AbstractTabDeckEditor::actExportDeckDecklistXyz()
{
exportToDecklistWebsite(DeckLoader::DecklistXyz);
}
void AbstractTabDeckEditor::actAnalyzeDeckDeckstats()
{
auto *interface = new DeckStatsInterface(*databaseDisplayDockWidget->databaseModel->getDatabase(),

View file

@ -100,6 +100,7 @@ protected slots:
void actSaveDeckToClipboardRawNoSetInfo();
void actPrintDeck();
void actExportDeckDecklist();
void actExportDeckDecklistXyz();
void actAnalyzeDeckDeckstats();
void actAnalyzeDeckTappedout();
@ -119,6 +120,7 @@ protected slots:
private:
virtual void setDeck(DeckLoader *_deck);
void editDeckInClipboard(bool annotated);
void exportToDecklistWebsite(DeckLoader::DecklistWebsite website);
protected:
/**
@ -147,7 +149,7 @@ protected:
QAction *aCardInfoDockVisible, *aCardInfoDockFloating, *aDeckDockVisible, *aDeckDockFloating;
QAction *aFilterDockVisible, *aFilterDockFloating, *aPrintingSelectorDockVisible, *aPrintingSelectorDockFloating;
bool modified;
bool modified = false;
};
#endif // TAB_GENERIC_DECK_EDITOR_H

View file

@ -119,7 +119,6 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor, GameReplay *_replay)
refreshShortcuts();
messageLog->logReplayStarted(gameInfo.game_id());
this->installEventFilter(this);
QTimer::singleShot(0, this, SLOT(loadLayout()));
}
@ -164,7 +163,6 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor,
for (int i = gameInfo.game_types_size() - 1; i >= 0; i--)
gameTypes.append(roomGameTypes.find(gameInfo.game_types(i)).value());
this->installEventFilter(this);
QTimer::singleShot(0, this, SLOT(loadLayout()));
}
@ -1753,6 +1751,27 @@ void TabGame::createMessageDock(bool bReplay)
connect(messageLayoutDock, SIGNAL(topLevelChanged(bool)), this, SLOT(dockTopLevelChanged(bool)));
}
void TabGame::hideEvent(QHideEvent *event)
{
LayoutsSettings &layouts = SettingsCache::instance().layouts();
if (replay) {
layouts.setReplayPlayAreaState(saveState());
layouts.setReplayPlayAreaGeometry(saveGeometry());
layouts.setReplayCardInfoSize(cardInfoDock->size());
layouts.setReplayMessageLayoutSize(messageLayoutDock->size());
layouts.setReplayPlayerListSize(playerListDock->size());
layouts.setReplayReplaySize(replayDock->size());
} else {
layouts.setGamePlayAreaState(saveState());
layouts.setGamePlayAreaGeometry(saveGeometry());
layouts.setGameCardInfoSize(cardInfoDock->size());
layouts.setGameMessageLayoutSize(messageLayoutDock->size());
layouts.setGamePlayerListSize(playerListDock->size());
}
Tab::hideEvent(event);
}
// Method uses to sync docks state with menu items state
bool TabGame::eventFilter(QObject *o, QEvent *e)
{
@ -1772,23 +1791,6 @@ bool TabGame::eventFilter(QObject *o, QEvent *e)
}
}
if (o == this && e->type() == QEvent::Hide) {
LayoutsSettings &layouts = SettingsCache::instance().layouts();
if (replay) {
layouts.setReplayPlayAreaState(saveState());
layouts.setReplayPlayAreaGeometry(saveGeometry());
layouts.setReplayCardInfoSize(cardInfoDock->size());
layouts.setReplayMessageLayoutSize(messageLayoutDock->size());
layouts.setReplayPlayerListSize(playerListDock->size());
layouts.setReplayReplaySize(replayDock->size());
} else {
layouts.setGamePlayAreaState(saveState());
layouts.setGamePlayAreaGeometry(saveGeometry());
layouts.setGameCardInfoSize(cardInfoDock->size());
layouts.setGameMessageLayoutSize(messageLayoutDock->size());
layouts.setGamePlayerListSize(playerListDock->size());
}
}
return false;
}

View file

@ -208,6 +208,7 @@ private slots:
void actResetLayout();
void freeDocksSize();
void hideEvent(QHideEvent *event) override;
bool eventFilter(QObject *o, QEvent *e) override;
void dockVisibleTriggered();
void dockFloatingTriggered();

View file

@ -232,22 +232,45 @@ void TabSupervisor::refreshShortcuts()
aTabLog->setShortcuts(shortcuts.getShortcut("Tabs/aTabLog"));
}
bool TabSupervisor::closeRequest()
void TabSupervisor::closeEvent(QCloseEvent *event)
{
// This will accept the event, which we may then override.
QTabWidget::closeEvent(event);
if (getGameCount()) {
if (QMessageBox::question(this, tr("Are you sure?"),
tr("There are still open games. Are you sure you want to quit?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No) {
return false;
event->ignore();
return;
}
}
for (AbstractTabDeckEditor *tab : deckEditorTabs) {
if (!tab->confirmClose())
return false;
if (!tab->confirmClose()) {
event->ignore();
}
}
return true;
// Close the game tabs in order to make sure they store their layout.
QSet<int> gameTabsToRemove;
for (auto it = gameTabs.begin(), end = gameTabs.end(); it != end; ++it) {
if (it.value()->close()) {
// Hotfix: the tab owns the `QMenu`s so they need to be cleared,
// otherwise we end up with use-after-free bugs.
if (it.value() == currentWidget()) {
emit setMenu();
}
gameTabsToRemove.insert(it.key());
} else {
event->ignore();
}
}
for (auto tabId : gameTabsToRemove) {
gameTabs.remove(tabId);
}
}
AbstractClient *TabSupervisor::getClient() const

View file

@ -138,7 +138,7 @@ public:
return deckEditorTabs;
}
bool getAdminLocked() const;
bool closeRequest();
void closeEvent(QCloseEvent *event) override;
bool switchToGameTabIfAlreadyExists(const int gameId);
static void actShowPopup(const QString &message);
signals:
@ -192,4 +192,4 @@ private slots:
void processNotifyUserEvent(const Event_NotifyUser &event);
};
#endif
#endif

View file

@ -180,6 +180,12 @@ QMap<QString, QPixmap> CountryPixmapGenerator::pmCache;
* @param idName id that the tag has to match
* @param attrValue the value to update the attribute to
*/
static void setAttrRecur(QDomElement &elem,
const QString &tagName,
const QString &attrName,
const QString &idName,
const QString &attrValue);
void setAttrRecur(QDomElement &elem,
const QString &tagName,
const QString &attrName,

View file

@ -120,10 +120,10 @@ void ThemeManager::themeChangedSlot()
if (dirPath.isEmpty()) {
// set default values
QDir::setSearchPaths("theme", DEFAULT_RESOURCE_PATHS);
handBgBrush = HANDZONE_BG_DEFAULT;
tableBgBrush = TABLEZONE_BG_DEFAULT;
playerBgBrush = PLAYERZONE_BG_DEFAULT;
stackBgBrush = STACKZONE_BG_DEFAULT;
brushes[Role::Hand] = HANDZONE_BG_DEFAULT;
brushes[Role::Table] = TABLEZONE_BG_DEFAULT;
brushes[Role::Player] = PLAYERZONE_BG_DEFAULT;
brushes[Role::Stack] = STACKZONE_BG_DEFAULT;
} else {
// resources
QStringList resources;
@ -132,73 +132,58 @@ void ThemeManager::themeChangedSlot()
// zones bg
dir.cd("zones");
handBgBrush = loadBrush(HANDZONE_BG_NAME, HANDZONE_BG_DEFAULT);
tableBgBrush = loadBrush(TABLEZONE_BG_NAME, TABLEZONE_BG_DEFAULT);
playerBgBrush = loadBrush(PLAYERZONE_BG_NAME, PLAYERZONE_BG_DEFAULT);
stackBgBrush = loadBrush(STACKZONE_BG_NAME, STACKZONE_BG_DEFAULT);
brushes[Role::Hand] = loadBrush(HANDZONE_BG_NAME, HANDZONE_BG_DEFAULT);
brushes[Role::Table] = loadBrush(TABLEZONE_BG_NAME, TABLEZONE_BG_DEFAULT);
brushes[Role::Player] = loadBrush(PLAYERZONE_BG_NAME, PLAYERZONE_BG_DEFAULT);
brushes[Role::Stack] = loadBrush(STACKZONE_BG_NAME, STACKZONE_BG_DEFAULT);
}
for (auto &brushCache : brushesCache) {
brushCache.clear();
}
tableBgBrushesCache.clear();
stackBgBrushesCache.clear();
playerBgBrushesCache.clear();
handBgBrushesCache.clear();
QPixmapCache::clear();
emit themeChanged();
}
QBrush ThemeManager::getExtraTableBgBrush(QString extraNumber, QBrush &fallbackBrush)
static QString roleBgName(ThemeManager::Role role)
{
QBrush returnBrush;
switch (role) {
case ThemeManager::Hand:
return HANDZONE_BG_NAME;
if (!tableBgBrushesCache.contains(extraNumber.toInt())) {
returnBrush = loadExtraBrush(TABLEZONE_BG_NAME + extraNumber, fallbackBrush);
tableBgBrushesCache.insert(extraNumber.toInt(), returnBrush);
} else {
returnBrush = tableBgBrushesCache.value(extraNumber.toInt());
case ThemeManager::Player:
return PLAYERZONE_BG_NAME;
case ThemeManager::Stack:
return STACKZONE_BG_NAME;
case ThemeManager::Table:
return TABLEZONE_BG_NAME;
default:
Q_ASSERT(false);
}
return returnBrush;
}
QBrush ThemeManager::getExtraStackBgBrush(QString extraNumber, QBrush &fallbackBrush)
QBrush &ThemeManager::getBgBrush(Role role)
{
QBrush returnBrush;
if (!stackBgBrushesCache.contains(extraNumber.toInt())) {
returnBrush = loadExtraBrush(STACKZONE_BG_NAME + extraNumber, fallbackBrush);
stackBgBrushesCache.insert(extraNumber.toInt(), returnBrush);
} else {
returnBrush = stackBgBrushesCache.value(extraNumber.toInt());
}
return returnBrush;
return brushes[role];
}
QBrush ThemeManager::getExtraPlayerBgBrush(QString extraNumber, QBrush &fallbackBrush)
QBrush ThemeManager::getExtraBgBrush(Role role, int zoneId)
{
QBrush returnBrush;
if (!playerBgBrushesCache.contains(extraNumber.toInt())) {
returnBrush = loadExtraBrush(PLAYERZONE_BG_NAME + extraNumber, fallbackBrush);
playerBgBrushesCache.insert(extraNumber.toInt(), returnBrush);
} else {
returnBrush = playerBgBrushesCache.value(extraNumber.toInt());
if (zoneId <= 0) {
return getBgBrush(role);
}
return returnBrush;
}
QBrushMap &brushCache = brushesCache[role];
QBrush ThemeManager::getExtraHandBgBrush(QString extraNumber, QBrush &fallbackBrush)
{
QBrush returnBrush;
if (!handBgBrushesCache.contains(extraNumber.toInt())) {
returnBrush = loadExtraBrush(HANDZONE_BG_NAME + extraNumber, fallbackBrush);
handBgBrushesCache.insert(extraNumber.toInt(), returnBrush);
} else {
returnBrush = handBgBrushesCache.value(extraNumber.toInt());
if (!brushCache.contains(zoneId)) {
QBrush brush = loadExtraBrush(roleBgName(role) + QString::number(zoneId), getBgBrush(role));
brushCache.insert(zoneId, brush);
return brush;
}
return returnBrush;
return brushCache.value(zoneId);
}

View file

@ -8,6 +8,7 @@
#include <QObject>
#include <QPixmap>
#include <QString>
#include <array>
inline Q_LOGGING_CATEGORY(ThemeManagerLog, "theme_manager");
@ -22,13 +23,23 @@ class ThemeManager : public QObject
public:
ThemeManager(QObject *parent = nullptr);
enum Role
{
MinRole = 0,
Hand = MinRole,
Stack,
Table,
Player,
MaxRole = Player,
};
private:
QBrush handBgBrush, stackBgBrush, tableBgBrush, playerBgBrush;
std::array<QBrush, Role::MaxRole + 1> brushes;
QStringMap availableThemes;
/*
Internal cache for multiple backgrounds
*/
QBrushMap tableBgBrushesCache, stackBgBrushesCache, playerBgBrushesCache, handBgBrushesCache;
std::array<QBrushMap, Role::MaxRole + 1> brushesCache;
protected:
void ensureThemeDirectoryExists();
@ -36,27 +47,10 @@ protected:
QBrush loadExtraBrush(QString fileName, QBrush &fallbackBrush);
public:
QBrush &getHandBgBrush()
{
return handBgBrush;
}
QBrush &getStackBgBrush()
{
return stackBgBrush;
}
QBrush &getTableBgBrush()
{
return tableBgBrush;
}
QBrush &getPlayerBgBrush()
{
return playerBgBrush;
}
QStringMap &getAvailableThemes();
QBrush getExtraTableBgBrush(QString extraNumber, QBrush &fallbackBrush);
QBrush getExtraStackBgBrush(QString extraNumber, QBrush &fallbackBrush);
QBrush getExtraPlayerBgBrush(QString extraNumber, QBrush &fallbackBrush);
QBrush getExtraHandBgBrush(QString extraNumber, QBrush &fallbackBrush);
QBrush &getBgBrush(Role zone);
QBrush getExtraBgBrush(Role zone, int zoneId = 0);
protected slots:
void themeChangedSlot();
signals:

View file

@ -1,5 +1,6 @@
#include "color_identity_widget.h"
#include "../../../../../settings/cache_settings.h"
#include "mana_symbol_widget.h"
#include <QHBoxLayout>
@ -17,18 +18,21 @@ ColorIdentityWidget::ColorIdentityWidget(QWidget *parent, CardInfoPtr _card) : Q
layout->setAlignment(Qt::AlignCenter); // Ensure icons are centered
setLayout(layout);
// Define the full WUBRG set (White, Blue, Black, Red, Green)
QString fullColorIdentity = "WUBRG";
if (card) {
QString manaCost = card->getColors(); // Get mana cost string
manaCost = card->getColors(); // Get mana cost string
QStringList symbols = parseColorIdentity(manaCost); // Parse mana cost string
for (const QString &symbol : symbols) {
ManaSymbolWidget *manaSymbol = new ManaSymbolWidget(this, symbol, true);
layout->addWidget(manaSymbol);
}
populateManaSymbolWidgets();
}
connect(&SettingsCache::instance(), &SettingsCache::visualDeckStorageDrawUnusedColorIdentitiesChanged, this,
&ColorIdentityWidget::toggleUnusedVisibility);
}
ColorIdentityWidget::ColorIdentityWidget(QWidget *parent, QString manaCost) : QWidget(parent), card(nullptr)
ColorIdentityWidget::ColorIdentityWidget(QWidget *parent, QString _manaCost)
: QWidget(parent), card(nullptr), manaCost(_manaCost)
{
layout = new QHBoxLayout(this);
layout->setSpacing(5); // Small spacing between icons
@ -36,14 +40,43 @@ ColorIdentityWidget::ColorIdentityWidget(QWidget *parent, QString manaCost) : QW
layout->setAlignment(Qt::AlignCenter); // Ensure icons are centered
setLayout(layout);
populateManaSymbolWidgets();
connect(&SettingsCache::instance(), &SettingsCache::visualDeckStorageDrawUnusedColorIdentitiesChanged, this,
&ColorIdentityWidget::toggleUnusedVisibility);
}
void ColorIdentityWidget::populateManaSymbolWidgets()
{
// Define the full WUBRG set (White, Blue, Black, Red, Green)
QString fullColorIdentity = "WUBRG";
QStringList symbols = parseColorIdentity(manaCost); // Parse mana cost string
for (const QString &symbol : symbols) {
ManaSymbolWidget *manaSymbol = new ManaSymbolWidget(this, symbol);
layout->addWidget(manaSymbol);
if (SettingsCache::instance().getVisualDeckStorageDrawUnusedColorIdentities()) {
for (const QString symbol : fullColorIdentity) {
auto *manaSymbol = new ManaSymbolWidget(this, symbol, symbols.contains(symbol));
layout->addWidget(manaSymbol);
}
} else {
for (const QString &symbol : symbols) {
auto *manaSymbol = new ManaSymbolWidget(this, symbol, symbols.contains(symbol));
layout->addWidget(manaSymbol);
}
}
}
void ColorIdentityWidget::toggleUnusedVisibility()
{
if (layout != nullptr) {
QLayoutItem *item;
while ((item = layout->takeAt(0)) != nullptr) {
item->widget()->deleteLater(); // Delete the widget
delete item; // Delete the layout item
}
}
populateManaSymbolWidgets();
}
void ColorIdentityWidget::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);

View file

@ -12,13 +12,17 @@ class ColorIdentityWidget : public QWidget
public:
explicit ColorIdentityWidget(QWidget *parent, CardInfoPtr card);
explicit ColorIdentityWidget(QWidget *parent, QString manaCost);
void populateManaSymbolWidgets();
QStringList parseColorIdentity(const QString &manaString);
public slots:
void resizeEvent(QResizeEvent *event) override;
void toggleUnusedVisibility();
private:
CardInfoPtr card;
QString manaCost;
QHBoxLayout *layout;
};

View file

@ -1,5 +1,7 @@
#include "mana_symbol_widget.h"
#include "../../../../../settings/cache_settings.h"
#include <QResizeEvent>
ManaSymbolWidget::ManaSymbolWidget(QWidget *parent, QString _symbol, bool _isActive, bool _mayBeToggled)
@ -13,6 +15,9 @@ ManaSymbolWidget::ManaSymbolWidget(QWidget *parent, QString _symbol, bool _isAct
opacityEffect = new QGraphicsOpacityEffect(this);
setGraphicsEffect(opacityEffect);
updateOpacity();
connect(&SettingsCache::instance(), &SettingsCache::visualDeckStorageUnusedColorIdentitiesOpacityChanged, this,
&ManaSymbolWidget::updateOpacity);
}
void ManaSymbolWidget::setColorActive(bool active)
@ -26,7 +31,14 @@ void ManaSymbolWidget::setColorActive(bool active)
void ManaSymbolWidget::updateOpacity()
{
qreal opacity = isActive ? 1.0 : 0.5;
qreal opacity;
if (mayBeToggled) {
// UI elements that users can click on shouldn't be transparent.
opacity = isActive ? 1.0 : 0.5;
} else {
// It's just for display, they can do whatever they want.
opacity = isActive ? 1.0 : SettingsCache::instance().getVisualDeckStorageUnusedColorIdentitiesOpacity() / 100.0;
}
opacityEffect->setOpacity(opacity);
}

View file

@ -1,5 +1,6 @@
#include "card_info_picture_enlarged_widget.h"
#include "../../../../settings/cache_settings.h"
#include "../../picture_loader/picture_loader.h"
#include <QPainterPath>
@ -17,6 +18,12 @@ CardInfoPictureEnlargedWidget::CardInfoPictureEnlargedWidget(QWidget *parent)
{
setWindowFlags(Qt::ToolTip); // Keeps this widget on top of everything
setAttribute(Qt::WA_TranslucentBackground);
connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
Q_UNUSED(_roundCardCorners);
update();
});
}
/**
@ -79,7 +86,8 @@ void CardInfoPictureEnlargedWidget::paintEvent(QPaintEvent *event)
QPoint topLeft{(width() - scaledSize.width()) / 2, (height() - scaledSize.height()) / 2};
// Define the radius for rounded corners
qreal radius = 0.05 * scaledSize.width(); // Adjust the radius as needed for rounded corners
// Adjust the radius as needed for rounded corners
qreal radius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * scaledSize.width() : 0.;
QStylePainter painter(this);
// Fill the background with transparent color to ensure rounded corners are rendered properly

View file

@ -3,7 +3,6 @@
#include "../../../../game/cards/card_database_manager.h"
#include "../../../../game/cards/card_item.h"
#include "../../../../settings/cache_settings.h"
#include "../../../tabs/tab_deck_editor.h"
#include "../../../tabs/tab_supervisor.h"
#include "../../picture_loader/picture_loader.h"
#include "../../window_main.h"
@ -44,6 +43,12 @@ CardInfoPictureWidget::CardInfoPictureWidget(QWidget *parent, const bool hoverTo
hoverTimer = new QTimer(this);
hoverTimer->setSingleShot(true);
connect(hoverTimer, &QTimer::timeout, this, &CardInfoPictureWidget::showEnlargedPixmap);
connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
Q_UNUSED(_roundCardCorners);
update();
});
}
/**
@ -186,7 +191,8 @@ void CardInfoPictureWidget::paintEvent(QPaintEvent *event)
QRect targetRect{targetX, targetY, targetW, targetH};
// Compute rounded corner radius
qreal radius = 0.05 * static_cast<qreal>(targetRect.width()); // Ensure consistent rounding
// Ensure consistent rounding
qreal radius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * static_cast<qreal>(targetRect.width()) : 0.;
// Draw the pixmap with rounded corners
QStylePainter painter(this);

View file

@ -105,6 +105,8 @@ void DeckEditorDeckDockWidget::createDeckDock()
auto *upperLayout = new QGridLayout;
upperLayout->setObjectName("upperLayout");
upperLayout->setContentsMargins(11, 11, 11, 0);
upperLayout->addWidget(nameLabel, 0, 0);
upperLayout->addWidget(nameEdit, 0, 1);
@ -314,12 +316,17 @@ DeckLoader *DeckEditorDeckDockWidget::getDeckList()
return deckModel->getDeckList();
}
/**
* Resets the tab to the state for a blank new tab.
*/
void DeckEditorDeckDockWidget::cleanDeck()
{
deckModel->cleanList();
nameEdit->setText(QString());
commentsEdit->setText(QString());
hashLabel->setText(QString());
updateBannerCardComboBox();
deckTagsDisplayWidget->connectDeckList(deckModel->getDeckList());
}
void DeckEditorDeckDockWidget::recursiveExpand(const QModelIndex &index)

View file

@ -96,11 +96,11 @@ void DeckEditorFilterDockWidget::filterViewCustomContextMenu(const QPoint &point
action = menu.addAction(QString("delete"));
action->setData(point);
connect(&menu, SIGNAL(triggered(QAction *)), this, SLOT(filterRemove(QAction *)));
connect(&menu, &QMenu::triggered, this, &DeckEditorFilterDockWidget::filterRemove);
menu.exec(filterView->mapToGlobal(point));
}
void DeckEditorFilterDockWidget::filterRemove(QAction *action)
void DeckEditorFilterDockWidget::filterRemove(const QAction *action)
{
QPoint point;
QModelIndex idx;

View file

@ -28,10 +28,9 @@ private:
KeySignals filterViewKeySignals;
QWidget *filterBox;
void filterRemove(QAction *action);
private slots:
void filterViewCustomContextMenu(const QPoint &point);
void filterRemove(const QAction *action);
void actClearFilterAll();
void actClearFilterOne();
void refreshShortcuts();

View file

@ -14,22 +14,21 @@
#include <QLabel>
DeckPreviewDeckTagsDisplayWidget::DeckPreviewDeckTagsDisplayWidget(QWidget *_parent, DeckList *_deckList)
: QWidget(_parent), deckList(_deckList)
: QWidget(_parent), deckList(nullptr)
{
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
// Create layout
auto *layout = new QHBoxLayout(this);
layout->setContentsMargins(5, 5, 5, 5);
layout->setSpacing(5);
layout->setContentsMargins(0, 0, 0, 0);
setFixedHeight(100);
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
if (deckList) {
connectDeckList(deckList);
if (_deckList) {
connectDeckList(_deckList);
}
layout->addWidget(flowWidget);
@ -37,10 +36,20 @@ DeckPreviewDeckTagsDisplayWidget::DeckPreviewDeckTagsDisplayWidget(QWidget *_par
void DeckPreviewDeckTagsDisplayWidget::connectDeckList(DeckList *_deckList)
{
flowWidget->clearLayout();
if (deckList) {
disconnect(deckList, &DeckList::deckTagsChanged, this, &DeckPreviewDeckTagsDisplayWidget::refreshTags);
}
deckList = _deckList;
connect(deckList, &DeckList::deckTagsChanged, this, &DeckPreviewDeckTagsDisplayWidget::refreshTags);
refreshTags();
}
void DeckPreviewDeckTagsDisplayWidget::refreshTags()
{
flowWidget->clearLayout();
for (const QString &tag : deckList->getTags()) {
flowWidget->addWidget(new DeckPreviewTagDisplayWidget(this, tag));
}
@ -51,16 +60,6 @@ void DeckPreviewDeckTagsDisplayWidget::connectDeckList(DeckList *_deckList)
flowWidget->addWidget(tagAdditionWidget);
}
void DeckPreviewDeckTagsDisplayWidget::refreshTags()
{
flowWidget->clearLayout();
QStringList tags = deckList->getTags();
for (const QString &tag : tags) {
flowWidget->addWidget(new DeckPreviewTagDisplayWidget(this, tag));
}
flowWidget->addWidget(new DeckPreviewTagAdditionWidget(this, tr("Edit tags ...")));
}
/**
* Gets the filepath of all files (no directories) in target directory and all subdirectories
*/
@ -161,4 +160,4 @@ void DeckPreviewDeckTagsDisplayWidget::openTagEditDlg()
}
}
}
}
}

View file

@ -298,11 +298,11 @@ QMenu *DeckPreviewWidget::createRightClickMenu()
connect(saveToClipboardMenu->addAction(tr("Annotated")), &QAction::triggered, this,
[this] { deckLoader->saveToClipboard(true, true); });
connect(saveToClipboardMenu->addAction(tr("Annotated (No set name or number)")), &QAction::triggered, this,
connect(saveToClipboardMenu->addAction(tr("Annotated (No set info)")), &QAction::triggered, this,
[this] { deckLoader->saveToClipboard(true, false); });
connect(saveToClipboardMenu->addAction(tr("Not Annotated")), &QAction::triggered, this,
[this] { deckLoader->saveToClipboard(false, true); });
connect(saveToClipboardMenu->addAction(tr("Not Annotated (No set name or number)")), &QAction::triggered, this,
connect(saveToClipboardMenu->addAction(tr("Not Annotated (No set info)")), &QAction::triggered, this,
[this] { deckLoader->saveToClipboard(false, false); });
menu->addSeparator();

View file

@ -58,6 +58,12 @@ void VisualDeckStorageFolderDisplayWidget::refreshUi()
header->setText(bannerText);
}
/**
* Gets all files in the directory that have an accepted decklist file extension
*
* @param filePath The directory to search through
* @param recursive Whether to search through subdirectories
*/
static QStringList getAllFiles(const QString &filePath, bool recursive)
{
QStringList allFiles;
@ -65,7 +71,7 @@ static QStringList getAllFiles(const QString &filePath, bool recursive)
// QDirIterator with QDir::Files ensures only files are listed (no directories)
auto flags =
recursive ? QDirIterator::Subdirectories | QDirIterator::FollowSymlinks : QDirIterator::NoIteratorFlags;
QDirIterator it(filePath, QDir::Files, flags);
QDirIterator it(filePath, DeckLoader::ACCEPTED_FILE_EXTENSIONS, QDir::Files, flags);
while (it.hasNext()) {
allFiles << it.next(); // Add each file path to the list

View file

@ -12,6 +12,7 @@
#include <QComboBox>
#include <QDirIterator>
#include <QMouseEvent>
#include <QSpinBox>
#include <QVBoxLayout>
VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(parent), folderWidget(nullptr)
@ -40,6 +41,7 @@ VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(pare
refreshButton->setFixedSize(32, 32);
connect(refreshButton, &QPushButton::clicked, this, &VisualDeckStorageWidget::refreshIfPossible);
// quick settings menu
showFoldersCheckBox = new QCheckBox(this);
showFoldersCheckBox->setChecked(SettingsCache::instance().getVisualDeckStorageShowFolders());
connect(showFoldersCheckBox, &QCheckBox::QT_STATE_CHANGED, this, &VisualDeckStorageWidget::updateShowFolders);
@ -77,6 +79,29 @@ VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(pare
connect(searchFolderNamesCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
&SettingsCache::setVisualDeckStorageSearchFolderNames);
// color identity opacity selector
auto unusedColorIdentityOpacityWidget = new QWidget(this);
unusedColorIdentitiesOpacityLabel = new QLabel(unusedColorIdentityOpacityWidget);
unusedColorIdentitiesOpacitySpinBox = new QSpinBox(unusedColorIdentityOpacityWidget);
unusedColorIdentitiesOpacitySpinBox->setMinimum(0);
unusedColorIdentitiesOpacitySpinBox->setMaximum(100);
unusedColorIdentitiesOpacitySpinBox->setValue(
SettingsCache::instance().getVisualDeckStorageUnusedColorIdentitiesOpacity());
connect(unusedColorIdentitiesOpacitySpinBox, QOverload<int>::of(&QSpinBox::valueChanged),
&SettingsCache::instance(), &SettingsCache::setVisualDeckStorageUnusedColorIdentitiesOpacity);
unusedColorIdentitiesOpacityLabel->setBuddy(unusedColorIdentitiesOpacitySpinBox);
unusedColorIdentitiesOpacitySpinBox->setValue(
SettingsCache::instance().getVisualDeckStorageUnusedColorIdentitiesOpacity());
auto unusedColorIdentityOpacityLayout = new QHBoxLayout(unusedColorIdentityOpacityWidget);
unusedColorIdentityOpacityLayout->setContentsMargins(11, 0, 11, 0);
unusedColorIdentityOpacityLayout->addWidget(unusedColorIdentitiesOpacityLabel);
unusedColorIdentityOpacityLayout->addWidget(unusedColorIdentitiesOpacitySpinBox);
// card size slider
cardSizeWidget = new CardSizeWidget(this, nullptr, SettingsCache::instance().getVisualDeckStorageCardSize());
@ -84,9 +109,10 @@ VisualDeckStorageWidget::VisualDeckStorageWidget(QWidget *parent) : QWidget(pare
quickSettingsWidget->addSettingsWidget(showFoldersCheckBox);
quickSettingsWidget->addSettingsWidget(tagFilterVisibilityCheckBox);
quickSettingsWidget->addSettingsWidget(tagsOnWidgetsVisibilityCheckBox);
quickSettingsWidget->addSettingsWidget(drawUnusedColorIdentitiesCheckBox);
quickSettingsWidget->addSettingsWidget(bannerCardComboBoxVisibilityCheckBox);
quickSettingsWidget->addSettingsWidget(searchFolderNamesCheckBox);
quickSettingsWidget->addSettingsWidget(drawUnusedColorIdentitiesCheckBox);
quickSettingsWidget->addSettingsWidget(unusedColorIdentityOpacityWidget);
quickSettingsWidget->addSettingsWidget(cardSizeWidget);
searchAndSortLayout->addWidget(deckPreviewColorIdentityFilterWidget);
@ -159,9 +185,11 @@ void VisualDeckStorageWidget::retranslateUi()
showFoldersCheckBox->setText(tr("Show Folders"));
tagFilterVisibilityCheckBox->setText(tr("Show Tag Filter"));
tagsOnWidgetsVisibilityCheckBox->setText(tr("Show Tags On Deck Previews"));
drawUnusedColorIdentitiesCheckBox->setText(tr("Draw not contained Color Identities"));
bannerCardComboBoxVisibilityCheckBox->setText(tr("Show Banner Card Selection Option"));
searchFolderNamesCheckBox->setText(tr("Include Folder Names in Search"));
drawUnusedColorIdentitiesCheckBox->setText(tr("Draw unused Color Identities"));
unusedColorIdentitiesOpacityLabel->setText(tr("Unused Color Identities Opacity"));
unusedColorIdentitiesOpacitySpinBox->setSuffix("%");
}
/**

View file

@ -15,6 +15,7 @@
#include <QCheckBox>
#include <QFileSystemModel>
class QSpinBox;
class VisualDeckStorageSearchWidget;
class VisualDeckStorageSortWidget;
class VisualDeckStorageTagFilterWidget;
@ -64,6 +65,8 @@ private:
QCheckBox *tagFilterVisibilityCheckBox;
QCheckBox *tagsOnWidgetsVisibilityCheckBox;
QCheckBox *searchFolderNamesCheckBox;
QLabel *unusedColorIdentitiesOpacityLabel;
QSpinBox *unusedColorIdentitiesOpacitySpinBox;
QScrollArea *scrollArea;
VisualDeckStorageFolderDisplayWidget *folderWidget;

View file

@ -1018,7 +1018,7 @@ void MainWindow::closeEvent(QCloseEvent *event)
return;
bClosingDown = true;
if (!tabSupervisor->closeRequest()) {
if (!tabSupervisor->close()) {
event->ignore();
bClosingDown = false;
return;

View file

@ -16,9 +16,10 @@
#include <QStringList>
#include <QtConcurrentRun>
const QStringList DeckLoader::fileNameFilters = QStringList()
<< QObject::tr("Common deck formats (*.cod *.dec *.dek *.txt *.mwDeck)")
<< QObject::tr("All files (*.*)");
const QStringList DeckLoader::ACCEPTED_FILE_EXTENSIONS = {"*.cod", "*.dec", "*.dek", "*.txt", "*.mwDeck"};
const QStringList DeckLoader::FILE_NAME_FILTERS = {
tr("Common deck formats (%1)").arg(ACCEPTED_FILE_EXTENSIONS.join(" ")), tr("All files (*.*)")};
DeckLoader::DeckLoader() : DeckList(), lastFileName(QString()), lastFileFormat(CockatriceFormat), lastRemoteDeckId(-1)
{
@ -225,6 +226,19 @@ bool DeckLoader::updateLastLoadedTimestamp(const QString &fileName, FileFormat f
return result;
}
static QString getDomainForWebsite(DeckLoader::DecklistWebsite website)
{
switch (website) {
case DeckLoader::DecklistOrg:
return "www.decklist.org";
case DeckLoader::DecklistXyz:
return "www.decklist.xyz";
default:
qCWarning(DeckLoaderLog) << "Invalid decklist website enum:" << website;
return "";
}
}
// This struct is here to support the forEachCard function call, defined in decklist. It
// requires a function to be called for each card, and passes an inner node and a card for
// each card in the decklist.
@ -274,11 +288,14 @@ struct FormatDeckListForExport
}
};
// Export deck to decklist function, called to format the deck in a way to be sent to a server
QString DeckLoader::exportDeckToDecklist()
/**
* Export deck to decklist function, called to format the deck in a way to be sent to a server
* @param website The website we're sending the deck to
*/
QString DeckLoader::exportDeckToDecklist(DecklistWebsite website)
{
// Add the base url
QString deckString = "https://www.decklist.org/?";
QString deckString = "https://" + getDomainForWebsite(website) + "/?";
// Create two strings to pass to function
QString mainBoardCards, sideBoardCards;
// Set up the struct to call.

View file

@ -20,7 +20,22 @@ public:
PlainTextFormat,
CockatriceFormat
};
static const QStringList fileNameFilters;
/**
* Supported file extensions for decklist files
*/
static const QStringList ACCEPTED_FILE_EXTENSIONS;
/**
* For use with `QFileDialog::setNameFilters`
*/
static const QStringList FILE_NAME_FILTERS;
enum DecklistWebsite
{
DecklistOrg,
DecklistXyz
};
private:
QString lastFileName;
@ -62,7 +77,7 @@ public:
bool loadFromRemote(const QString &nativeString, int remoteDeckId);
bool saveToFile(const QString &fileName, FileFormat fmt);
bool updateLastLoadedTimestamp(const QString &fileName, FileFormat fmt);
QString exportDeckToDecklist();
QString exportDeckToDecklist(DecklistWebsite website);
void resolveSetNameAndNumberToProviderID();

View file

@ -11,7 +11,7 @@ DlgLoadDeck::DlgLoadDeck(QWidget *parent) : QFileDialog(parent, tr("Load Deck"))
}
setDirectory(startingDir);
setNameFilters(DeckLoader::fileNameFilters);
setNameFilters(DeckLoader::FILE_NAME_FILTERS);
connect(this, &DlgLoadDeck::accepted, this, &DlgLoadDeck::actAccepted);
}

View file

@ -80,7 +80,7 @@ bool AbstractDlgDeckTextEdit::loadIntoDeck(DeckLoader *deckLoader) const
QTextStream stream(&buffer);
if (deckLoader->loadFromStream_Plain(stream)) {
if (deckLoader->loadFromStream_Plain(stream, true)) {
if (loadSetNameAndNumberCheckBox->isChecked()) {
deckLoader->resolveSetNameAndNumberToProviderID();
} else {

View file

@ -8,6 +8,7 @@
#include "../settings/cache_settings.h"
#include <QAction>
#include <QCheckBox>
#include <QDebug>
#include <QDialogButtonBox>
#include <QGridLayout>
@ -162,6 +163,11 @@ WndSets::WndSets(QWidget *parent) : QMainWindow(parent)
sortWarning->setLayout(sortWarningLayout);
sortWarning->setVisible(false);
includeOnlineOnlyCards = SettingsCache::instance().getIncludeOnlineOnlyCards();
QCheckBox *onlineOnly = new QCheckBox(tr("Include online-only (Arena) cards [requires restart]"));
onlineOnly->setChecked(includeOnlineOnlyCards);
connect(onlineOnly, &QAbstractButton::toggled, this, &WndSets::includeOnlineOnlyCardsChanged);
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttonBox, SIGNAL(accepted()), this, SLOT(actSave()));
connect(buttonBox, SIGNAL(rejected()), this, SLOT(actRestore()));
@ -175,8 +181,9 @@ WndSets::WndSets(QWidget *parent) : QMainWindow(parent)
mainLayout->addWidget(enableSomeButton, 2, 1);
mainLayout->addWidget(disableSomeButton, 2, 2);
mainLayout->addWidget(sortWarning, 3, 1, 1, 2);
mainLayout->addWidget(hintsGroupBox, 4, 1, 1, 2);
mainLayout->addWidget(buttonBox, 5, 1, 1, 2);
mainLayout->addWidget(onlineOnly, 4, 1, 1, 2);
mainLayout->addWidget(hintsGroupBox, 5, 1, 1, 2);
mainLayout->addWidget(buttonBox, 6, 1, 1, 2);
mainLayout->setColumnStretch(1, 1);
mainLayout->setColumnStretch(2, 1);
@ -239,9 +246,15 @@ void WndSets::rebuildMainLayout(int actionToTake)
}
}
void WndSets::includeOnlineOnlyCardsChanged(bool _includeOnlineOnlyCards)
{
includeOnlineOnlyCards = _includeOnlineOnlyCards;
}
void WndSets::actSave()
{
model->save(CardDatabaseManager::getInstance());
SettingsCache::instance().setIncludeOnlineOnlyCards(includeOnlineOnlyCards);
PictureLoader::clearPixmapCache();
close();
}

View file

@ -44,6 +44,7 @@ private:
void saveHeaderState();
void rebuildMainLayout(int actionToTake);
bool setOrderIsSorted;
bool includeOnlineOnlyCards;
enum
{
NO_SETS_SELECTED,
@ -73,6 +74,7 @@ private slots:
void actDisableResetButton(const QString &filterText);
void actSort(int index);
void actIgnoreWarning();
void includeOnlineOnlyCardsChanged(bool _includeOnlineOnlyCardsChanged);
};
#endif

View file

@ -3,7 +3,6 @@
#include "../game/cards/card_database.h"
#include "../game/cards/card_database_manager.h"
#include "../game/filters/filter_string.h"
#include "trice_limits.h"
#include <QDialogButtonBox>
#include <QLabel>
@ -14,15 +13,17 @@
#include <QVBoxLayout>
#include <QWidget>
DlgMoveTopCardsUntil::DlgMoveTopCardsUntil(QWidget *parent, QString _expr, uint _numberOfHits, bool autoPlay)
DlgMoveTopCardsUntil::DlgMoveTopCardsUntil(QWidget *parent, QStringList exprs, uint _numberOfHits, bool autoPlay)
: QDialog(parent)
{
exprLabel = new QLabel(tr("Card name (or search expressions):"));
exprEdit = new QLineEdit(this);
exprEdit->setFocus();
exprEdit->setText(_expr);
exprLabel->setBuddy(exprEdit);
exprComboBox = new QComboBox(this);
exprComboBox->setFocus();
exprComboBox->setEditable(true);
exprComboBox->setInsertPolicy(QComboBox::InsertAtTop);
exprComboBox->insertItems(0, exprs);
exprLabel->setBuddy(exprComboBox);
numberOfHitsLabel = new QLabel(tr("Number of hits:"));
numberOfHitsEdit = new QSpinBox(this);
@ -43,7 +44,7 @@ DlgMoveTopCardsUntil::DlgMoveTopCardsUntil(QWidget *parent, QString _expr, uint
auto *mainLayout = new QVBoxLayout;
mainLayout->addWidget(exprLabel);
mainLayout->addWidget(exprEdit);
mainLayout->addWidget(exprComboBox);
mainLayout->addItem(grid);
mainLayout->addWidget(autoPlayCheckBox);
mainLayout->addWidget(buttonBox);
@ -92,7 +93,7 @@ bool DlgMoveTopCardsUntil::validateMatchExists(const FilterString &filterString)
void DlgMoveTopCardsUntil::validateAndAccept()
{
auto movingCardsUntilFilter = FilterString(exprEdit->text());
auto movingCardsUntilFilter = FilterString(exprComboBox->currentText());
if (!movingCardsUntilFilter.valid()) {
QMessageBox::warning(this, tr("Invalid filter"), movingCardsUntilFilter.error(), QMessageBox::Ok);
return;
@ -102,12 +103,29 @@ void DlgMoveTopCardsUntil::validateAndAccept()
return;
}
// move currently selected text to top of history list
if (exprComboBox->currentIndex() != 0) {
QString currentExpr = exprComboBox->currentText();
exprComboBox->removeItem(exprComboBox->currentIndex());
exprComboBox->insertItem(0, currentExpr);
exprComboBox->setCurrentIndex(0);
}
accept();
}
QString DlgMoveTopCardsUntil::getExpr() const
{
return exprEdit->text();
return exprComboBox->currentText();
}
QStringList DlgMoveTopCardsUntil::getExprs() const
{
QStringList exprs;
for (int i = 0; i < exprComboBox->count(); ++i) {
exprs.append(exprComboBox->itemText(i));
}
return exprs;
}
uint DlgMoveTopCardsUntil::getNumberOfHits() const

View file

@ -2,10 +2,10 @@
#define DLG_MOVE_TOP_CARDS_UNTIL_H
#include <QCheckBox>
#include <QComboBox>
#include <QDialog>
#include <QDialogButtonBox>
#include <QLabel>
#include <QLineEdit>
#include <QSpinBox>
class FilterString;
@ -15,7 +15,7 @@ class DlgMoveTopCardsUntil : public QDialog
Q_OBJECT
QLabel *exprLabel, *numberOfHitsLabel;
QLineEdit *exprEdit;
QComboBox *exprComboBox;
QSpinBox *numberOfHitsEdit;
QDialogButtonBox *buttonBox;
QCheckBox *autoPlayCheckBox;
@ -25,10 +25,11 @@ class DlgMoveTopCardsUntil : public QDialog
public:
explicit DlgMoveTopCardsUntil(QWidget *parent = nullptr,
QString expr = QString(),
QStringList exprs = QStringList(),
uint numberOfHits = 1,
bool autoPlay = false);
QString getExpr() const;
QStringList getExprs() const;
uint getNumberOfHits() const;
bool isAutoPlay() const;
};

View file

@ -41,6 +41,7 @@
#include <QStackedWidget>
#include <QToolBar>
#include <QTranslator>
#include <qabstractbutton.h>
#define WIKI_CUSTOM_PIC_URL "https://github.com/Cockatrice/Cockatrice/wiki/Custom-Picture-Download-URLs"
#define WIKI_CUSTOM_SHORTCUTS "https://github.com/Cockatrice/Cockatrice/wiki/Custom-Keyboard-Shortcuts"
@ -358,25 +359,8 @@ AppearanceSettingsPage::AppearanceSettingsPage()
showShortcutsCheckBox.setChecked(settings.getShowShortcuts());
connect(&showShortcutsCheckBox, &QCheckBox::QT_STATE_CHANGED, this, &AppearanceSettingsPage::showShortcutsChanged);
visualDeckStorageDrawUnusedColorIdentitiesCheckBox.setChecked(
settings.getVisualDeckStorageDrawUnusedColorIdentities());
connect(&visualDeckStorageDrawUnusedColorIdentitiesCheckBox, &QCheckBox::QT_STATE_CHANGED, &settings,
&SettingsCache::setVisualDeckStorageDrawUnusedColorIdentities);
visualDeckStorageUnusedColorIdentitiesOpacitySpinBox.setMinimum(0);
visualDeckStorageUnusedColorIdentitiesOpacitySpinBox.setMaximum(100);
visualDeckStorageUnusedColorIdentitiesOpacitySpinBox.setValue(
settings.getVisualDeckStorageUnusedColorIdentitiesOpacity());
connect(&visualDeckStorageUnusedColorIdentitiesOpacitySpinBox, QOverload<int>::of(&QSpinBox::valueChanged),
&settings, &SettingsCache::setVisualDeckStorageUnusedColorIdentitiesOpacity);
visualDeckStorageUnusedColorIdentitiesOpacityLabel.setBuddy(&visualDeckStorageUnusedColorIdentitiesOpacitySpinBox);
auto *menuGrid = new QGridLayout;
menuGrid->addWidget(&showShortcutsCheckBox, 0, 0);
menuGrid->addWidget(&visualDeckStorageDrawUnusedColorIdentitiesCheckBox, 1, 0);
menuGrid->addWidget(&visualDeckStorageUnusedColorIdentitiesOpacityLabel, 2, 0);
menuGrid->addWidget(&visualDeckStorageUnusedColorIdentitiesOpacitySpinBox, 2, 1);
menuGroupBox = new QGroupBox;
menuGroupBox->setLayout(menuGrid);
@ -400,6 +384,9 @@ AppearanceSettingsPage::AppearanceSettingsPage()
cardScalingCheckBox.setChecked(settings.getScaleCards());
connect(&cardScalingCheckBox, &QCheckBox::QT_STATE_CHANGED, &settings, &SettingsCache::setCardScaling);
roundCardCornersCheckBox.setChecked(settings.getRoundCardCorners());
connect(&roundCardCornersCheckBox, &QAbstractButton::toggled, &settings, &SettingsCache::setRoundCardCorners);
verticalCardOverlapPercentBox.setValue(settings.getStackCardOverlapPercent());
verticalCardOverlapPercentBox.setRange(0, 80);
connect(&verticalCardOverlapPercentBox, SIGNAL(valueChanged(int)), &settings,
@ -419,14 +406,15 @@ AppearanceSettingsPage::AppearanceSettingsPage()
cardsGrid->addWidget(&displayCardNamesCheckBox, 0, 0, 1, 2);
cardsGrid->addWidget(&autoRotateSidewaysLayoutCardsCheckBox, 1, 0, 1, 2);
cardsGrid->addWidget(&cardScalingCheckBox, 2, 0, 1, 2);
cardsGrid->addWidget(&overrideAllCardArtWithPersonalPreferenceCheckBox, 3, 0, 1, 2);
cardsGrid->addWidget(&bumpSetsWithCardsInDeckToTopCheckBox, 4, 0, 1, 2);
cardsGrid->addWidget(&verticalCardOverlapPercentLabel, 5, 0, 1, 1);
cardsGrid->addWidget(&verticalCardOverlapPercentBox, 5, 1, 1, 1);
cardsGrid->addWidget(&cardViewInitialRowsMaxLabel, 6, 0);
cardsGrid->addWidget(&cardViewInitialRowsMaxBox, 6, 1);
cardsGrid->addWidget(&cardViewExpandedRowsMaxLabel, 7, 0);
cardsGrid->addWidget(&cardViewExpandedRowsMaxBox, 7, 1);
cardsGrid->addWidget(&roundCardCornersCheckBox, 3, 0, 1, 2);
cardsGrid->addWidget(&overrideAllCardArtWithPersonalPreferenceCheckBox, 4, 0, 1, 2);
cardsGrid->addWidget(&bumpSetsWithCardsInDeckToTopCheckBox, 5, 0, 1, 2);
cardsGrid->addWidget(&verticalCardOverlapPercentLabel, 6, 0, 1, 1);
cardsGrid->addWidget(&verticalCardOverlapPercentBox, 6, 1, 1, 1);
cardsGrid->addWidget(&cardViewInitialRowsMaxLabel, 7, 0);
cardsGrid->addWidget(&cardViewInitialRowsMaxBox, 7, 1);
cardsGrid->addWidget(&cardViewExpandedRowsMaxLabel, 8, 0);
cardsGrid->addWidget(&cardViewExpandedRowsMaxBox, 8, 1);
cardsGroupBox = new QGroupBox;
cardsGroupBox->setLayout(cardsGrid);
@ -547,10 +535,6 @@ void AppearanceSettingsPage::retranslateUi()
menuGroupBox->setTitle(tr("Menu settings"));
showShortcutsCheckBox.setText(tr("Show keyboard shortcuts in right-click menus"));
visualDeckStorageDrawUnusedColorIdentitiesCheckBox.setText(
tr("Draw missing color identities in visual deck storage without color label"));
visualDeckStorageUnusedColorIdentitiesOpacityLabel.setText(tr("Missing color identity opacity"));
visualDeckStorageUnusedColorIdentitiesOpacitySpinBox.setSuffix("%");
cardsGroupBox->setTitle(tr("Card rendering"));
displayCardNamesCheckBox.setText(tr("Display card names on cards having a picture"));
@ -561,6 +545,7 @@ void AppearanceSettingsPage::retranslateUi()
bumpSetsWithCardsInDeckToTopCheckBox.setText(
tr("Bump sets that the deck contains cards from to the top in the printing selector"));
cardScalingCheckBox.setText(tr("Scale cards on mouse over"));
roundCardCornersCheckBox.setText(tr("Use rounded card corners"));
verticalCardOverlapPercentLabel.setText(
tr("Minimum overlap percentage of cards on the stack and in vertical hand"));
cardViewInitialRowsMaxLabel.setText(tr("Maximum initial height for card view window:"));

View file

@ -102,14 +102,12 @@ private:
QLabel minPlayersForMultiColumnLayoutLabel;
QLabel maxFontSizeForCardsLabel;
QCheckBox showShortcutsCheckBox;
QCheckBox visualDeckStorageDrawUnusedColorIdentitiesCheckBox;
QLabel visualDeckStorageUnusedColorIdentitiesOpacityLabel;
QSpinBox visualDeckStorageUnusedColorIdentitiesOpacitySpinBox;
QCheckBox displayCardNamesCheckBox;
QCheckBox autoRotateSidewaysLayoutCardsCheckBox;
QCheckBox overrideAllCardArtWithPersonalPreferenceCheckBox;
QCheckBox bumpSetsWithCardsInDeckToTopCheckBox;
QCheckBox cardScalingCheckBox;
QCheckBox roundCardCornersCheckBox;
QLabel verticalCardOverlapPercentLabel;
QSpinBox verticalCardOverlapPercentBox;
QLabel cardViewInitialRowsMaxLabel;

View file

@ -165,10 +165,12 @@ void DlgUpdate::finishedUpdateCheck(bool needToUpdate, bool isCompatible, Releas
QString(":</b> %1<br>").arg(release->getName()) + "<b>" + tr("Released") +
QString(":</b> %1 (<a href=\"%2\">").arg(publishDate, release->getDescriptionUrl()) + tr("Changelog") +
"</a>)<br><br>" +
tr("Unfortunately there are no download packages available for your operating system. \nYou may have "
"to build from source yourself.") +
tr("Unfortunately, the automatic updater failed to find a compatible download. \nYou may have to "
"manually download the new version.") +
"<br><br>" +
tr("Please check the download page manually and visit the wiki for instructions on compiling."));
tr("Please check the <a href=\"%1\">releases page</a> on our Github and download the build for your "
"system.")
.arg(release->getDescriptionUrl()));
}
}

View file

@ -6,6 +6,7 @@
ArrowTarget::ArrowTarget(Player *_owner, QGraphicsItem *parent)
: AbstractGraphicsItem(parent), owner(_owner), beingPointedAt(false)
{
setFlag(ItemSendsScenePositionChanges);
}
ArrowTarget::~ArrowTarget()
@ -25,3 +26,16 @@ void ArrowTarget::setBeingPointedAt(bool _beingPointedAt)
beingPointedAt = _beingPointedAt;
update();
}
QVariant ArrowTarget::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
{
if (change == ItemScenePositionHasChanged && scene()) {
for (auto *arrow : arrowsFrom)
arrow->updatePath();
for (auto *arrow : arrowsTo)
arrow->updatePath();
}
return QGraphicsItem::itemChange(change, value);
}

View file

@ -57,5 +57,8 @@ public:
{
arrowsTo.removeOne(arrow);
}
protected:
QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override;
};
#endif

View file

@ -1,6 +1,6 @@
#include "abstract_card_drag_item.h"
#include "card_database.h"
#include "../../settings/cache_settings.h"
#include <QCursor>
#include <QDebug>
@ -32,6 +32,13 @@ AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item,
.translate(-CARD_WIDTH_HALF, -CARD_HEIGHT_HALF));
setCacheMode(DeviceCoordinateCache);
connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
Q_UNUSED(_roundCardCorners);
prepareGeometryChange();
update();
});
}
AbstractCardDragItem::~AbstractCardDragItem()
@ -43,7 +50,8 @@ AbstractCardDragItem::~AbstractCardDragItem()
QPainterPath AbstractCardDragItem::shape() const
{
QPainterPath shape;
shape.addRoundedRect(boundingRect(), 0.05 * CARD_WIDTH, 0.05 * CARD_WIDTH);
qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CARD_WIDTH : 0.0;
shape.addRoundedRect(boundingRect(), cardCornerRadius, cardCornerRadius);
return shape;
}

View file

@ -26,6 +26,13 @@ AbstractCardItem::AbstractCardItem(QGraphicsItem *parent,
connect(&SettingsCache::instance(), &SettingsCache::displayCardNamesChanged, this, [this] { update(); });
refreshCardInfo();
connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
Q_UNUSED(_roundCardCorners);
prepareGeometryChange();
update();
});
}
AbstractCardItem::~AbstractCardItem()
@ -41,7 +48,8 @@ QRectF AbstractCardItem::boundingRect() const
QPainterPath AbstractCardItem::shape() const
{
QPainterPath shape;
shape.addRoundedRect(boundingRect(), 0.05 * CARD_WIDTH, 0.05 * CARD_WIDTH);
qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CARD_WIDTH : 0.0;
shape.addRoundedRect(boundingRect(), cardCornerRadius, cardCornerRadius);
return shape;
}
@ -325,5 +333,5 @@ QVariant AbstractCardItem::itemChange(QGraphicsItem::GraphicsItemChange change,
update();
return value;
} else
return QGraphicsItem::itemChange(change, value);
return ArrowTarget::itemChange(change, value);
}

View file

@ -1,10 +1,8 @@
#include "card_database.h"
#include "../../client/network/spoiler_background_updater.h"
#include "../../client/ui/picture_loader/picture_loader.h"
#include "../../settings/cache_settings.h"
#include "../../utility/card_set_comparator.h"
#include "../game_specific_terms.h"
#include "./card_database_parser/cockatrice_xml_3.h"
#include "./card_database_parser/cockatrice_xml_4.h"
@ -20,351 +18,6 @@
const char *CardDatabase::TOKENS_SETNAME = "TK";
CardSet::CardSet(const QString &_shortName,
const QString &_longName,
const QString &_setType,
const QDate &_releaseDate,
const CardSet::Priority _priority)
: shortName(_shortName), longName(_longName), releaseDate(_releaseDate), setType(_setType), priority(_priority)
{
loadSetOptions();
}
CardSetPtr CardSet::newInstance(const QString &_shortName,
const QString &_longName,
const QString &_setType,
const QDate &_releaseDate,
const Priority _priority)
{
CardSetPtr ptr(new CardSet(_shortName, _longName, _setType, _releaseDate, _priority));
// ptr->setSmartPointer(ptr);
return ptr;
}
QString CardSet::getCorrectedShortName() const
{
// For Windows machines.
QSet<QString> invalidFileNames;
invalidFileNames << "CON"
<< "PRN"
<< "AUX"
<< "NUL"
<< "COM1"
<< "COM2"
<< "COM3"
<< "COM4"
<< "COM5"
<< "COM6"
<< "COM7"
<< "COM8"
<< "COM9"
<< "LPT1"
<< "LPT2"
<< "LPT3"
<< "LPT4"
<< "LPT5"
<< "LPT6"
<< "LPT7"
<< "LPT8"
<< "LPT9";
return invalidFileNames.contains(shortName) ? shortName + "_" : shortName;
}
void CardSet::loadSetOptions()
{
sortKey = SettingsCache::instance().cardDatabase().getSortKey(shortName);
enabled = SettingsCache::instance().cardDatabase().isEnabled(shortName);
isknown = SettingsCache::instance().cardDatabase().isKnown(shortName);
}
void CardSet::setSortKey(unsigned int _sortKey)
{
sortKey = _sortKey;
SettingsCache::instance().cardDatabase().setSortKey(shortName, _sortKey);
}
void CardSet::setEnabled(bool _enabled)
{
enabled = _enabled;
SettingsCache::instance().cardDatabase().setEnabled(shortName, _enabled);
}
void CardSet::setIsKnown(bool _isknown)
{
isknown = _isknown;
SettingsCache::instance().cardDatabase().setIsKnown(shortName, _isknown);
}
class SetList::KeyCompareFunctor
{
public:
inline bool operator()(const CardSetPtr &a, const CardSetPtr &b) const
{
if (a.isNull() || b.isNull()) {
qCDebug(CardDatabaseLog) << "SetList::KeyCompareFunctor a or b is null";
return false;
}
return a->getSortKey() < b->getSortKey();
}
};
void SetList::sortByKey()
{
std::sort(begin(), end(), KeyCompareFunctor());
}
int SetList::getEnabledSetsNum()
{
int num = 0;
for (int i = 0; i < size(); ++i) {
CardSetPtr set = at(i);
if (set && set->getEnabled()) {
++num;
}
}
return num;
}
int SetList::getUnknownSetsNum()
{
int num = 0;
for (int i = 0; i < size(); ++i) {
CardSetPtr set = at(i);
if (set && !set->getIsKnown() && !set->getIsKnownIgnored()) {
++num;
}
}
return num;
}
QStringList SetList::getUnknownSetsNames()
{
QStringList sets = QStringList();
for (int i = 0; i < size(); ++i) {
CardSetPtr set = at(i);
if (set && !set->getIsKnown() && !set->getIsKnownIgnored()) {
sets << set->getShortName();
}
}
return sets;
}
void SetList::enableAllUnknown()
{
for (int i = 0; i < size(); ++i) {
CardSetPtr set = at(i);
if (set && !set->getIsKnown() && !set->getIsKnownIgnored()) {
set->setIsKnown(true);
set->setEnabled(true);
} else if (set && set->getIsKnownIgnored() && !set->getEnabled()) {
set->setEnabled(true);
}
}
}
void SetList::enableAll()
{
for (int i = 0; i < size(); ++i) {
CardSetPtr set = at(i);
if (set == nullptr) {
qCDebug(CardDatabaseLog) << "enabledAll has null";
continue;
}
if (!set->getIsKnownIgnored()) {
set->setIsKnown(true);
}
set->setEnabled(true);
}
}
void SetList::markAllAsKnown()
{
for (int i = 0; i < size(); ++i) {
CardSetPtr set = at(i);
if (set && !set->getIsKnown() && !set->getIsKnownIgnored()) {
set->setIsKnown(true);
set->setEnabled(false);
} else if (set && set->getIsKnownIgnored() && !set->getEnabled()) {
set->setEnabled(true);
}
}
}
void SetList::guessSortKeys()
{
defaultSort();
for (int i = 0; i < size(); ++i) {
CardSetPtr set = at(i);
if (set.isNull()) {
qCDebug(CardDatabaseLog) << "guessSortKeys set is null";
continue;
}
set->setSortKey(i);
}
}
void SetList::defaultSort()
{
std::sort(begin(), end(), [](const CardSetPtr &a, const CardSetPtr &b) {
// Sort by priority, then by release date, then by short name
if (a->getPriority() != b->getPriority()) {
return a->getPriority() < b->getPriority(); // lowest first
} else if (a->getReleaseDate() != b->getReleaseDate()) {
return a->getReleaseDate() > b->getReleaseDate(); // most recent first
} else {
return a->getShortName() < b->getShortName(); // alphabetically
}
});
}
CardInfoPerSet::CardInfoPerSet(const CardSetPtr &_set) : set(_set)
{
}
CardInfo::CardInfo(const QString &_name,
const QString &_text,
bool _isToken,
QVariantHash _properties,
const QList<CardRelation *> &_relatedCards,
const QList<CardRelation *> &_reverseRelatedCards,
CardInfoPerSetMap _sets,
bool _cipt,
bool _landscapeOrientation,
int _tableRow,
bool _upsideDownArt)
: name(_name), text(_text), isToken(_isToken), properties(std::move(_properties)), relatedCards(_relatedCards),
reverseRelatedCards(_reverseRelatedCards), sets(std::move(_sets)), cipt(_cipt),
landscapeOrientation(_landscapeOrientation), tableRow(_tableRow), upsideDownArt(_upsideDownArt)
{
pixmapCacheKey = QLatin1String("card_") + name;
simpleName = CardInfo::simplifyName(name);
refreshCachedSetNames();
}
CardInfo::~CardInfo()
{
PictureLoader::clearPixmapCache(smartThis);
}
CardInfoPtr CardInfo::newInstance(const QString &_name)
{
return newInstance(_name, QString(), false, QVariantHash(), QList<CardRelation *>(), QList<CardRelation *>(),
CardInfoPerSetMap(), false, false, 0, false);
}
CardInfoPtr CardInfo::newInstance(const QString &_name,
const QString &_text,
bool _isToken,
QVariantHash _properties,
const QList<CardRelation *> &_relatedCards,
const QList<CardRelation *> &_reverseRelatedCards,
CardInfoPerSetMap _sets,
bool _cipt,
bool _landscapeOrientation,
int _tableRow,
bool _upsideDownArt)
{
CardInfoPtr ptr(new CardInfo(_name, _text, _isToken, std::move(_properties), _relatedCards, _reverseRelatedCards,
_sets, _cipt, _landscapeOrientation, _tableRow, _upsideDownArt));
ptr->setSmartPointer(ptr);
for (const auto &cardInfoPerSetList : _sets) {
for (const CardInfoPerSet &set : cardInfoPerSetList) {
set.getPtr()->append(ptr);
break;
}
}
return ptr;
}
QString CardInfo::getCorrectedName() const
{
// remove all the characters reserved in windows file paths,
// other oses only disallow a subset of these so it covers all
static const QRegularExpression rmrx(R"(( // |[*<>:"\\?\x00-\x08\x10-\x1f]))");
static const QRegularExpression spacerx(R"([/\x09-\x0f])");
static const QString space(' ');
QString result = name;
// Fire // Ice, Circle of Protection: Red, "Ach! Hans, Run!", Who/What/When/Where/Why, Question Elemental?
return result.remove(rmrx).replace(spacerx, space);
}
void CardInfo::addToSet(const CardSetPtr &_set, const CardInfoPerSet _info)
{
_set->append(smartThis);
sets[_set->getShortName()].append(_info);
refreshCachedSetNames();
}
void CardInfo::combineLegalities(const QVariantHash &props)
{
QHashIterator<QString, QVariant> it(props);
while (it.hasNext()) {
it.next();
if (it.key().startsWith("format-")) {
smartThis->setProperty(it.key(), it.value().toString());
}
}
}
void CardInfo::refreshCachedSetNames()
{
QStringList setList;
// update the cached list of set names
for (const auto &cardInfoPerSetList : sets) {
for (const auto &set : cardInfoPerSetList) {
if (set.getPtr()->getEnabled()) {
setList << set.getPtr()->getShortName();
}
break;
}
}
setsNames = setList.join(", ");
}
QString CardInfo::simplifyName(const QString &name)
{
static const QRegularExpression spaceOrSplit("(\\s+|\\/\\/.*)");
static const QRegularExpression nonAlnum("[^a-z0-9]");
QString simpleName = name.toLower();
// remove spaces and right halves of split cards
simpleName.remove(spaceOrSplit);
// So Aetherling would work, but not Ætherling since 'Æ' would get replaced
// with nothing.
simpleName.replace("æ", "ae");
// Replace Jötun Grunt with Jotun Grunt.
simpleName = simpleName.normalized(QString::NormalizationForm_KD);
// remove all non alphanumeric characters from the name
simpleName.remove(nonAlnum);
return simpleName;
}
const QChar CardInfo::getColorChar() const
{
QString colors = getColors();
switch (colors.size()) {
case 0:
return QChar();
case 1:
return colors.at(0);
default:
return QChar('m');
}
}
CardDatabase::CardDatabase(QObject *parent) : QObject(parent), loadStatus(NotLoaded)
{
qRegisterMetaType<CardInfoPtr>("CardInfoPtr");
@ -884,64 +537,3 @@ bool CardDatabase::saveCustomTokensToFile()
availableParsers.first()->saveToFile(tmpSets, tmpCards, fileName);
return true;
}
CardRelation::CardRelation(const QString &_name,
AttachType _attachType,
bool _isCreateAllExclusion,
bool _isVariableCount,
int _defaultCount,
bool _isPersistent)
: name(_name), attachType(_attachType), isCreateAllExclusion(_isCreateAllExclusion),
isVariableCount(_isVariableCount), defaultCount(_defaultCount), isPersistent(_isPersistent)
{
}
void CardInfo::resetReverseRelatedCards2Me()
{
for (CardRelation *cardRelation : this->getReverseRelatedCards2Me()) {
cardRelation->deleteLater();
}
reverseRelatedCardsToMe = QList<CardRelation *>();
}
// Back-compatibility methods. Remove ASAP
const QString CardInfo::getCardType() const
{
return getProperty(Mtg::CardType);
}
void CardInfo::setCardType(const QString &value)
{
setProperty(Mtg::CardType, value);
}
const QString CardInfo::getCmc() const
{
return getProperty(Mtg::ConvertedManaCost);
}
const QString CardInfo::getColors() const
{
return getProperty(Mtg::Colors);
}
void CardInfo::setColors(const QString &value)
{
setProperty(Mtg::Colors, value);
}
const QString CardInfo::getLoyalty() const
{
return getProperty(Mtg::Loyalty);
}
const QString CardInfo::getMainCardType() const
{
return getProperty(Mtg::MainCardType);
}
const QString CardInfo::getManaCost() const
{
return getProperty(Mtg::ManaCost);
}
const QString CardInfo::getPowTough() const
{
return getProperty(Mtg::PowTough);
}
void CardInfo::setPowTough(const QString &value)
{
setProperty(Mtg::PowTough, value);
}

View file

@ -1,16 +1,14 @@
#ifndef CARDDATABASE_H
#define CARDDATABASE_H
#include "card_info.h"
#include <QBasicMutex>
#include <QDate>
#include <QHash>
#include <QList>
#include <QLoggingCategory>
#include <QMap>
#include <QMetaType>
#include <QSharedPointer>
#include <QStringList>
#include <QVariant>
#include <QVector>
#include <utility>
@ -18,406 +16,8 @@ inline Q_LOGGING_CATEGORY(CardDatabaseLog, "card_database");
inline Q_LOGGING_CATEGORY(CardDatabaseLoadingLog, "card_database.loading");
inline Q_LOGGING_CATEGORY(CardDatabaseLoadingSuccessOrFailureLog, "card_database.loading.success_or_failure");
class CardDatabase;
class CardInfo;
class CardInfoPerSet;
class CardSet;
class CardRelation;
class ICardDatabaseParser;
typedef QMap<QString, QString> QStringMap;
typedef QSharedPointer<CardInfo> CardInfoPtr;
typedef QSharedPointer<CardSet> CardSetPtr;
typedef QMap<QString, QList<CardInfoPerSet>> CardInfoPerSetMap;
Q_DECLARE_METATYPE(CardInfoPtr)
class CardSet : public QList<CardInfoPtr>
{
public:
enum Priority
{
PriorityFallback = 0,
PriorityPrimary = 10,
PrioritySecondary = 20,
PriorityReprint = 30,
PriorityOther = 40,
PriorityLowest = 100,
};
private:
QString shortName, longName;
unsigned int sortKey;
QDate releaseDate;
QString setType;
Priority priority;
bool enabled, isknown;
public:
explicit CardSet(const QString &_shortName = QString(),
const QString &_longName = QString(),
const QString &_setType = QString(),
const QDate &_releaseDate = QDate(),
const Priority _priority = PriorityFallback);
static CardSetPtr newInstance(const QString &_shortName = QString(),
const QString &_longName = QString(),
const QString &_setType = QString(),
const QDate &_releaseDate = QDate(),
const Priority _priority = PriorityFallback);
QString getCorrectedShortName() const;
QString getShortName() const
{
return shortName;
}
QString getLongName() const
{
return longName;
}
QString getSetType() const
{
return setType;
}
QDate getReleaseDate() const
{
return releaseDate;
}
Priority getPriority() const
{
return priority;
}
void setLongName(const QString &_longName)
{
longName = _longName;
}
void setSetType(const QString &_setType)
{
setType = _setType;
}
void setReleaseDate(const QDate &_releaseDate)
{
releaseDate = _releaseDate;
}
void setPriority(const Priority _priority)
{
priority = _priority;
}
void loadSetOptions();
int getSortKey() const
{
return sortKey;
}
void setSortKey(unsigned int _sortKey);
bool getEnabled() const
{
return enabled;
}
void setEnabled(bool _enabled);
bool getIsKnown() const
{
return isknown;
}
void setIsKnown(bool _isknown);
// Determine incomplete sets.
bool getIsKnownIgnored() const
{
return longName.length() + setType.length() + releaseDate.toString().length() == 0;
}
};
class SetList : public QList<CardSetPtr>
{
private:
class KeyCompareFunctor;
public:
void sortByKey();
void guessSortKeys();
void enableAllUnknown();
void enableAll();
void markAllAsKnown();
int getEnabledSetsNum();
int getUnknownSetsNum();
QStringList getUnknownSetsNames();
void defaultSort();
};
class CardInfoPerSet
{
public:
explicit CardInfoPerSet(const CardSetPtr &_set = QSharedPointer<CardSet>(nullptr));
~CardInfoPerSet() = default;
bool operator==(const CardInfoPerSet &other) const
{
return this->set == other.set && this->properties == other.properties;
}
private:
CardSetPtr set;
// per-set card properties;
QVariantHash properties;
public:
const CardSetPtr getPtr() const
{
return set;
}
const QStringList getProperties() const
{
return properties.keys();
}
const QString getProperty(const QString &propertyName) const
{
return properties.value(propertyName).toString();
}
void setProperty(const QString &_name, const QString &_value)
{
properties.insert(_name, _value);
}
};
class CardInfo : public QObject
{
Q_OBJECT
private:
CardInfoPtr smartThis;
// The card name
QString name;
// The name without punctuation or capitalization, for better card name recognition.
QString simpleName;
// The key used to identify this card in the cache
QString pixmapCacheKey;
// card text
QString text;
// whether this is not a "real" card but a token
bool isToken;
// basic card properties; common for all the sets
QVariantHash properties;
// the cards i'm related to
QList<CardRelation *> relatedCards;
// the card i'm reverse-related to
QList<CardRelation *> reverseRelatedCards;
// the cards thare are reverse-related to me
QList<CardRelation *> reverseRelatedCardsToMe;
// card sets
CardInfoPerSetMap sets;
// cached set names
QString setsNames;
// positioning properties; used by UI
bool cipt;
bool landscapeOrientation;
int tableRow;
bool upsideDownArt;
public:
explicit CardInfo(const QString &_name,
const QString &_text,
bool _isToken,
QVariantHash _properties,
const QList<CardRelation *> &_relatedCards,
const QList<CardRelation *> &_reverseRelatedCards,
CardInfoPerSetMap _sets,
bool _cipt,
bool _landscapeOrientation,
int _tableRow,
bool _upsideDownArt);
CardInfo(const CardInfo &other)
: QObject(other.parent()), name(other.name), simpleName(other.simpleName), pixmapCacheKey(other.pixmapCacheKey),
text(other.text), isToken(other.isToken), properties(other.properties), relatedCards(other.relatedCards),
reverseRelatedCards(other.reverseRelatedCards), reverseRelatedCardsToMe(other.reverseRelatedCardsToMe),
sets(other.sets), setsNames(other.setsNames), cipt(other.cipt),
landscapeOrientation(other.landscapeOrientation), tableRow(other.tableRow), upsideDownArt(other.upsideDownArt)
{
}
~CardInfo() override;
static CardInfoPtr newInstance(const QString &_name);
static CardInfoPtr newInstance(const QString &_name,
const QString &_text,
bool _isToken,
QVariantHash _properties,
const QList<CardRelation *> &_relatedCards,
const QList<CardRelation *> &_reverseRelatedCards,
CardInfoPerSetMap _sets,
bool _cipt,
bool _landscapeOrientation,
int _tableRow,
bool _upsideDownArt);
CardInfoPtr clone() const
{
// Use the copy constructor to create a new instance
CardInfoPtr newCardInfo = CardInfoPtr(new CardInfo(*this));
newCardInfo->setSmartPointer(newCardInfo); // Set the smart pointer for the new instance
return newCardInfo;
}
void setSmartPointer(CardInfoPtr _ptr)
{
smartThis = std::move(_ptr);
}
// basic properties
inline const QString &getName() const
{
return name;
}
const QString &getSimpleName() const
{
return simpleName;
}
void setPixmapCacheKey(QString _pixmapCacheKey)
{
pixmapCacheKey = _pixmapCacheKey;
}
const QString &getPixmapCacheKey() const
{
return pixmapCacheKey;
}
const QString &getText() const
{
return text;
}
void setText(const QString &_text)
{
text = _text;
emit cardInfoChanged(smartThis);
}
bool getIsToken() const
{
return isToken;
}
const QStringList getProperties() const
{
return properties.keys();
}
const QString getProperty(const QString &propertyName) const
{
return properties.value(propertyName).toString();
}
void setProperty(const QString &_name, const QString &_value)
{
properties.insert(_name, _value);
emit cardInfoChanged(smartThis);
}
bool hasProperty(const QString &propertyName) const
{
return properties.contains(propertyName);
}
const CardInfoPerSetMap &getSets() const
{
return sets;
}
const QString &getSetsNames() const
{
return setsNames;
}
const QString getSetProperty(const QString &setName, const QString &propertyName) const
{
if (!sets.contains(setName))
return "";
for (const auto &set : sets[setName]) {
if (QLatin1String("card_") + this->getName() + QString("_") + QString(set.getProperty("uuid")) ==
this->getPixmapCacheKey()) {
return set.getProperty(propertyName);
}
}
return sets[setName][0].getProperty(propertyName);
}
// related cards
const QList<CardRelation *> &getRelatedCards() const
{
return relatedCards;
}
const QList<CardRelation *> &getReverseRelatedCards() const
{
return reverseRelatedCards;
}
const QList<CardRelation *> &getReverseRelatedCards2Me() const
{
return reverseRelatedCardsToMe;
}
const QList<CardRelation *> getAllRelatedCards() const
{
QList<CardRelation *> result;
result.append(getRelatedCards());
result.append(getReverseRelatedCards2Me());
return result;
}
void resetReverseRelatedCards2Me();
void addReverseRelatedCards2Me(CardRelation *cardRelation)
{
reverseRelatedCardsToMe.append(cardRelation);
}
// positioning
bool getCipt() const
{
return cipt;
}
bool getLandscapeOrientation() const
{
return landscapeOrientation;
}
int getTableRow() const
{
return tableRow;
}
void setTableRow(int _tableRow)
{
tableRow = _tableRow;
}
bool getUpsideDownArt() const
{
return upsideDownArt;
}
const QChar getColorChar() const;
// Back-compatibility methods. Remove ASAP
const QString getCardType() const;
void setCardType(const QString &value);
const QString getCmc() const;
const QString getColors() const;
void setColors(const QString &value);
const QString getLoyalty() const;
const QString getMainCardType() const;
const QString getManaCost() const;
const QString getPowTough() const;
void setPowTough(const QString &value);
// methods using per-set properties
QString getCustomPicURL(const QString &set) const
{
return getSetProperty(set, "picurl");
}
QString getCorrectedName() const;
void addToSet(const CardSetPtr &_set, CardInfoPerSet _info = CardInfoPerSet());
void combineLegalities(const QVariantHash &props);
void emitPixmapUpdated()
{
emit pixmapUpdated();
}
void refreshCachedSetNames();
/**
* Simplify a name to have no punctuation and lowercase all letters, for
* less strict name-matching.
*/
static QString simplifyName(const QString &name);
signals:
void pixmapUpdated();
void cardInfoChanged(CardInfoPtr card);
};
enum LoadStatus
{
Ok,
@ -523,79 +123,4 @@ signals:
void cardRemoved(CardInfoPtr card);
};
class CardRelation : public QObject
{
Q_OBJECT
public:
enum AttachType
{
DoesNotAttach = 0,
AttachTo = 1,
TransformInto = 2,
};
private:
QString name;
AttachType attachType;
bool isCreateAllExclusion;
bool isVariableCount;
int defaultCount;
bool isPersistent;
public:
explicit CardRelation(const QString &_name = QString(),
AttachType _attachType = DoesNotAttach,
bool _isCreateAllExclusion = false,
bool _isVariableCount = false,
int _defaultCount = 1,
bool _isPersistent = false);
inline const QString &getName() const
{
return name;
}
AttachType getAttachType() const
{
return attachType;
}
bool getDoesAttach() const
{
return attachType != DoesNotAttach;
}
bool getDoesTransform() const
{
return attachType == TransformInto;
}
QString getAttachTypeAsString() const
{
switch (attachType) {
case AttachTo:
return "attach";
case TransformInto:
return "transform";
default:
return "";
}
}
bool getCanCreateAnother() const
{
return !getDoesAttach();
}
bool getIsCreateAllExclusion() const
{
return isCreateAllExclusion;
}
bool getIsVariable() const
{
return isVariableCount;
}
int getDefaultCount() const
{
return defaultCount;
}
bool getIsPersistent() const
{
return isPersistent;
}
};
#endif

View file

@ -1,5 +1,7 @@
#include "cockatrice_xml_4.h"
#include "../../../settings/cache_settings.h"
#include <QCoreApplication>
#include <QDebug>
#include <QFile>
@ -124,6 +126,7 @@ QVariantHash CockatriceXml4Parser::loadCardPropertiesFromXml(QXmlStreamReader &x
void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml)
{
bool includeOnlineOnlyCards = SettingsCache::instance().getIncludeOnlineOnlyCards();
while (!xml.atEnd()) {
if (xml.readNext() == QXmlStreamReader::EndElement) {
break;
@ -183,7 +186,17 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml)
attrName = "picurl";
setInfo.setProperty(attrName, attr.value().toString());
}
_sets[setName].append(setInfo);
// This is very much a hack and not the right place to
// put this check, as it requires a reload of Cockatrice
// to be apply.
//
// However, this is also true of the `set->getEnabled()`
// check above (which is currently bugged as well), so
// we'll fix both at the same time.
if (includeOnlineOnlyCards || setInfo.getProperty("isOnlineOnly") != "true") {
_sets[setName].append(setInfo);
}
}
// related cards
} else if (xmlName == "related" || xmlName == "reverse-related") {

View file

@ -0,0 +1,418 @@
#include "card_info.h"
#include "../../client/ui/picture_loader/picture_loader.h"
#include "../../settings/cache_settings.h"
#include "../game_specific_terms.h"
#include <QDebug>
#include <QDir>
#include <QMessageBox>
#include <QRegularExpression>
#include <algorithm>
#include <utility>
CardSet::CardSet(const QString &_shortName,
const QString &_longName,
const QString &_setType,
const QDate &_releaseDate,
const CardSet::Priority _priority)
: shortName(_shortName), longName(_longName), releaseDate(_releaseDate), setType(_setType), priority(_priority)
{
loadSetOptions();
}
CardSetPtr CardSet::newInstance(const QString &_shortName,
const QString &_longName,
const QString &_setType,
const QDate &_releaseDate,
const Priority _priority)
{
CardSetPtr ptr(new CardSet(_shortName, _longName, _setType, _releaseDate, _priority));
// ptr->setSmartPointer(ptr);
return ptr;
}
QString CardSet::getCorrectedShortName() const
{
// For Windows machines.
QSet<QString> invalidFileNames;
invalidFileNames << "CON"
<< "PRN"
<< "AUX"
<< "NUL"
<< "COM1"
<< "COM2"
<< "COM3"
<< "COM4"
<< "COM5"
<< "COM6"
<< "COM7"
<< "COM8"
<< "COM9"
<< "LPT1"
<< "LPT2"
<< "LPT3"
<< "LPT4"
<< "LPT5"
<< "LPT6"
<< "LPT7"
<< "LPT8"
<< "LPT9";
return invalidFileNames.contains(shortName) ? shortName + "_" : shortName;
}
void CardSet::loadSetOptions()
{
sortKey = SettingsCache::instance().cardDatabase().getSortKey(shortName);
enabled = SettingsCache::instance().cardDatabase().isEnabled(shortName);
isknown = SettingsCache::instance().cardDatabase().isKnown(shortName);
}
void CardSet::setSortKey(unsigned int _sortKey)
{
sortKey = _sortKey;
SettingsCache::instance().cardDatabase().setSortKey(shortName, _sortKey);
}
void CardSet::setEnabled(bool _enabled)
{
enabled = _enabled;
SettingsCache::instance().cardDatabase().setEnabled(shortName, _enabled);
}
void CardSet::setIsKnown(bool _isknown)
{
isknown = _isknown;
SettingsCache::instance().cardDatabase().setIsKnown(shortName, _isknown);
}
class SetList::KeyCompareFunctor
{
public:
inline bool operator()(const CardSetPtr &a, const CardSetPtr &b) const
{
if (a.isNull() || b.isNull()) {
qCDebug(CardInfoLog) << "SetList::KeyCompareFunctor a or b is null";
return false;
}
return a->getSortKey() < b->getSortKey();
}
};
void SetList::sortByKey()
{
std::sort(begin(), end(), KeyCompareFunctor());
}
int SetList::getEnabledSetsNum()
{
int num = 0;
for (int i = 0; i < size(); ++i) {
CardSetPtr set = at(i);
if (set && set->getEnabled()) {
++num;
}
}
return num;
}
int SetList::getUnknownSetsNum()
{
int num = 0;
for (int i = 0; i < size(); ++i) {
CardSetPtr set = at(i);
if (set && !set->getIsKnown() && !set->getIsKnownIgnored()) {
++num;
}
}
return num;
}
QStringList SetList::getUnknownSetsNames()
{
QStringList sets = QStringList();
for (int i = 0; i < size(); ++i) {
CardSetPtr set = at(i);
if (set && !set->getIsKnown() && !set->getIsKnownIgnored()) {
sets << set->getShortName();
}
}
return sets;
}
void SetList::enableAllUnknown()
{
for (int i = 0; i < size(); ++i) {
CardSetPtr set = at(i);
if (set && !set->getIsKnown() && !set->getIsKnownIgnored()) {
set->setIsKnown(true);
set->setEnabled(true);
} else if (set && set->getIsKnownIgnored() && !set->getEnabled()) {
set->setEnabled(true);
}
}
}
void SetList::enableAll()
{
for (int i = 0; i < size(); ++i) {
CardSetPtr set = at(i);
if (set == nullptr) {
qCDebug(CardInfoLog) << "enabledAll has null";
continue;
}
if (!set->getIsKnownIgnored()) {
set->setIsKnown(true);
}
set->setEnabled(true);
}
}
void SetList::markAllAsKnown()
{
for (int i = 0; i < size(); ++i) {
CardSetPtr set = at(i);
if (set && !set->getIsKnown() && !set->getIsKnownIgnored()) {
set->setIsKnown(true);
set->setEnabled(false);
} else if (set && set->getIsKnownIgnored() && !set->getEnabled()) {
set->setEnabled(true);
}
}
}
void SetList::guessSortKeys()
{
defaultSort();
for (int i = 0; i < size(); ++i) {
CardSetPtr set = at(i);
if (set.isNull()) {
qCDebug(CardInfoLog) << "guessSortKeys set is null";
continue;
}
set->setSortKey(i);
}
}
void SetList::defaultSort()
{
std::sort(begin(), end(), [](const CardSetPtr &a, const CardSetPtr &b) {
// Sort by priority, then by release date, then by short name
if (a->getPriority() != b->getPriority()) {
return a->getPriority() < b->getPriority(); // lowest first
} else if (a->getReleaseDate() != b->getReleaseDate()) {
return a->getReleaseDate() > b->getReleaseDate(); // most recent first
} else {
return a->getShortName() < b->getShortName(); // alphabetically
}
});
}
CardInfoPerSet::CardInfoPerSet(const CardSetPtr &_set) : set(_set)
{
}
CardInfo::CardInfo(const QString &_name,
const QString &_text,
bool _isToken,
QVariantHash _properties,
const QList<CardRelation *> &_relatedCards,
const QList<CardRelation *> &_reverseRelatedCards,
CardInfoPerSetMap _sets,
bool _cipt,
bool _landscapeOrientation,
int _tableRow,
bool _upsideDownArt)
: name(_name), text(_text), isToken(_isToken), properties(std::move(_properties)), relatedCards(_relatedCards),
reverseRelatedCards(_reverseRelatedCards), sets(std::move(_sets)), cipt(_cipt),
landscapeOrientation(_landscapeOrientation), tableRow(_tableRow), upsideDownArt(_upsideDownArt)
{
pixmapCacheKey = QLatin1String("card_") + name;
simpleName = CardInfo::simplifyName(name);
refreshCachedSetNames();
}
CardInfo::~CardInfo()
{
PictureLoader::clearPixmapCache(smartThis);
}
CardInfoPtr CardInfo::newInstance(const QString &_name)
{
return newInstance(_name, QString(), false, QVariantHash(), QList<CardRelation *>(), QList<CardRelation *>(),
CardInfoPerSetMap(), false, false, 0, false);
}
CardInfoPtr CardInfo::newInstance(const QString &_name,
const QString &_text,
bool _isToken,
QVariantHash _properties,
const QList<CardRelation *> &_relatedCards,
const QList<CardRelation *> &_reverseRelatedCards,
CardInfoPerSetMap _sets,
bool _cipt,
bool _landscapeOrientation,
int _tableRow,
bool _upsideDownArt)
{
CardInfoPtr ptr(new CardInfo(_name, _text, _isToken, std::move(_properties), _relatedCards, _reverseRelatedCards,
_sets, _cipt, _landscapeOrientation, _tableRow, _upsideDownArt));
ptr->setSmartPointer(ptr);
for (const auto &cardInfoPerSetList : _sets) {
for (const CardInfoPerSet &set : cardInfoPerSetList) {
set.getPtr()->append(ptr);
break;
}
}
return ptr;
}
QString CardInfo::getCorrectedName() const
{
// remove all the characters reserved in windows file paths,
// other oses only disallow a subset of these so it covers all
static const QRegularExpression rmrx(R"(( // |[*<>:"\\?\x00-\x08\x10-\x1f]))");
static const QRegularExpression spacerx(R"([/\x09-\x0f])");
static const QString space(' ');
QString result = name;
// Fire // Ice, Circle of Protection: Red, "Ach! Hans, Run!", Who/What/When/Where/Why, Question Elemental?
return result.remove(rmrx).replace(spacerx, space);
}
void CardInfo::addToSet(const CardSetPtr &_set, const CardInfoPerSet _info)
{
_set->append(smartThis);
sets[_set->getShortName()].append(_info);
refreshCachedSetNames();
}
void CardInfo::combineLegalities(const QVariantHash &props)
{
QHashIterator<QString, QVariant> it(props);
while (it.hasNext()) {
it.next();
if (it.key().startsWith("format-")) {
smartThis->setProperty(it.key(), it.value().toString());
}
}
}
void CardInfo::refreshCachedSetNames()
{
QStringList setList;
// update the cached list of set names
for (const auto &cardInfoPerSetList : sets) {
for (const auto &set : cardInfoPerSetList) {
if (set.getPtr()->getEnabled()) {
setList << set.getPtr()->getShortName();
}
break;
}
}
setsNames = setList.join(", ");
}
QString CardInfo::simplifyName(const QString &name)
{
static const QRegularExpression spaceOrSplit("(\\s+|\\/\\/.*)");
static const QRegularExpression nonAlnum("[^a-z0-9]");
QString simpleName = name.toLower();
// remove spaces and right halves of split cards
simpleName.remove(spaceOrSplit);
// So Aetherling would work, but not Ætherling since 'Æ' would get replaced
// with nothing.
simpleName.replace("æ", "ae");
// Replace Jötun Grunt with Jotun Grunt.
simpleName = simpleName.normalized(QString::NormalizationForm_KD);
// remove all non alphanumeric characters from the name
simpleName.remove(nonAlnum);
return simpleName;
}
const QChar CardInfo::getColorChar() const
{
QString colors = getColors();
switch (colors.size()) {
case 0:
return QChar();
case 1:
return colors.at(0);
default:
return QChar('m');
}
}
CardRelation::CardRelation(const QString &_name,
AttachType _attachType,
bool _isCreateAllExclusion,
bool _isVariableCount,
int _defaultCount,
bool _isPersistent)
: name(_name), attachType(_attachType), isCreateAllExclusion(_isCreateAllExclusion),
isVariableCount(_isVariableCount), defaultCount(_defaultCount), isPersistent(_isPersistent)
{
}
void CardInfo::resetReverseRelatedCards2Me()
{
for (CardRelation *cardRelation : this->getReverseRelatedCards2Me()) {
cardRelation->deleteLater();
}
reverseRelatedCardsToMe = QList<CardRelation *>();
}
// Back-compatibility methods. Remove ASAP
const QString CardInfo::getCardType() const
{
return getProperty(Mtg::CardType);
}
void CardInfo::setCardType(const QString &value)
{
setProperty(Mtg::CardType, value);
}
const QString CardInfo::getCmc() const
{
return getProperty(Mtg::ConvertedManaCost);
}
const QString CardInfo::getColors() const
{
return getProperty(Mtg::Colors);
}
void CardInfo::setColors(const QString &value)
{
setProperty(Mtg::Colors, value);
}
const QString CardInfo::getLoyalty() const
{
return getProperty(Mtg::Loyalty);
}
const QString CardInfo::getMainCardType() const
{
return getProperty(Mtg::MainCardType);
}
const QString CardInfo::getManaCost() const
{
return getProperty(Mtg::ManaCost);
}
const QString CardInfo::getPowTough() const
{
return getProperty(Mtg::PowTough);
}
void CardInfo::setPowTough(const QString &value)
{
setProperty(Mtg::PowTough, value);
}

View file

@ -0,0 +1,491 @@
#ifndef CARD_INFO_H
#define CARD_INFO_H
#include <QDate>
#include <QHash>
#include <QList>
#include <QLoggingCategory>
#include <QMap>
#include <QMetaType>
#include <QSharedPointer>
#include <QStringList>
#include <QVariant>
#include <utility>
inline Q_LOGGING_CATEGORY(CardInfoLog, "card_info");
class CardInfo;
class CardInfoPerSet;
class CardSet;
class CardRelation;
class ICardDatabaseParser;
typedef QMap<QString, QString> QStringMap;
typedef QSharedPointer<CardInfo> CardInfoPtr;
typedef QSharedPointer<CardSet> CardSetPtr;
typedef QMap<QString, QList<CardInfoPerSet>> CardInfoPerSetMap;
Q_DECLARE_METATYPE(CardInfoPtr)
class CardSet : public QList<CardInfoPtr>
{
public:
enum Priority
{
PriorityFallback = 0,
PriorityPrimary = 10,
PrioritySecondary = 20,
PriorityReprint = 30,
PriorityOther = 40,
PriorityLowest = 100,
};
private:
QString shortName, longName;
unsigned int sortKey;
QDate releaseDate;
QString setType;
Priority priority;
bool enabled, isknown;
public:
explicit CardSet(const QString &_shortName = QString(),
const QString &_longName = QString(),
const QString &_setType = QString(),
const QDate &_releaseDate = QDate(),
const Priority _priority = PriorityFallback);
static CardSetPtr newInstance(const QString &_shortName = QString(),
const QString &_longName = QString(),
const QString &_setType = QString(),
const QDate &_releaseDate = QDate(),
const Priority _priority = PriorityFallback);
QString getCorrectedShortName() const;
QString getShortName() const
{
return shortName;
}
QString getLongName() const
{
return longName;
}
QString getSetType() const
{
return setType;
}
QDate getReleaseDate() const
{
return releaseDate;
}
Priority getPriority() const
{
return priority;
}
void setLongName(const QString &_longName)
{
longName = _longName;
}
void setSetType(const QString &_setType)
{
setType = _setType;
}
void setReleaseDate(const QDate &_releaseDate)
{
releaseDate = _releaseDate;
}
void setPriority(const Priority _priority)
{
priority = _priority;
}
void loadSetOptions();
int getSortKey() const
{
return sortKey;
}
void setSortKey(unsigned int _sortKey);
bool getEnabled() const
{
return enabled;
}
void setEnabled(bool _enabled);
bool getIsKnown() const
{
return isknown;
}
void setIsKnown(bool _isknown);
// Determine incomplete sets.
bool getIsKnownIgnored() const
{
return longName.length() + setType.length() + releaseDate.toString().length() == 0;
}
};
class SetList : public QList<CardSetPtr>
{
private:
class KeyCompareFunctor;
public:
void sortByKey();
void guessSortKeys();
void enableAllUnknown();
void enableAll();
void markAllAsKnown();
int getEnabledSetsNum();
int getUnknownSetsNum();
QStringList getUnknownSetsNames();
void defaultSort();
};
class CardInfoPerSet
{
public:
explicit CardInfoPerSet(const CardSetPtr &_set = QSharedPointer<CardSet>(nullptr));
~CardInfoPerSet() = default;
bool operator==(const CardInfoPerSet &other) const
{
return this->set == other.set && this->properties == other.properties;
}
private:
CardSetPtr set;
// per-set card properties;
QVariantHash properties;
public:
const CardSetPtr getPtr() const
{
return set;
}
const QStringList getProperties() const
{
return properties.keys();
}
const QString getProperty(const QString &propertyName) const
{
return properties.value(propertyName).toString();
}
void setProperty(const QString &_name, const QString &_value)
{
properties.insert(_name, _value);
}
};
class CardInfo : public QObject
{
Q_OBJECT
private:
CardInfoPtr smartThis;
// The card name
QString name;
// The name without punctuation or capitalization, for better card name recognition.
QString simpleName;
// The key used to identify this card in the cache
QString pixmapCacheKey;
// card text
QString text;
// whether this is not a "real" card but a token
bool isToken;
// basic card properties; common for all the sets
QVariantHash properties;
// the cards i'm related to
QList<CardRelation *> relatedCards;
// the card i'm reverse-related to
QList<CardRelation *> reverseRelatedCards;
// the cards thare are reverse-related to me
QList<CardRelation *> reverseRelatedCardsToMe;
// card sets
CardInfoPerSetMap sets;
// cached set names
QString setsNames;
// positioning properties; used by UI
bool cipt;
bool landscapeOrientation;
int tableRow;
bool upsideDownArt;
public:
explicit CardInfo(const QString &_name,
const QString &_text,
bool _isToken,
QVariantHash _properties,
const QList<CardRelation *> &_relatedCards,
const QList<CardRelation *> &_reverseRelatedCards,
CardInfoPerSetMap _sets,
bool _cipt,
bool _landscapeOrientation,
int _tableRow,
bool _upsideDownArt);
CardInfo(const CardInfo &other)
: QObject(other.parent()), name(other.name), simpleName(other.simpleName), pixmapCacheKey(other.pixmapCacheKey),
text(other.text), isToken(other.isToken), properties(other.properties), relatedCards(other.relatedCards),
reverseRelatedCards(other.reverseRelatedCards), reverseRelatedCardsToMe(other.reverseRelatedCardsToMe),
sets(other.sets), setsNames(other.setsNames), cipt(other.cipt),
landscapeOrientation(other.landscapeOrientation), tableRow(other.tableRow), upsideDownArt(other.upsideDownArt)
{
}
~CardInfo() override;
static CardInfoPtr newInstance(const QString &_name);
static CardInfoPtr newInstance(const QString &_name,
const QString &_text,
bool _isToken,
QVariantHash _properties,
const QList<CardRelation *> &_relatedCards,
const QList<CardRelation *> &_reverseRelatedCards,
CardInfoPerSetMap _sets,
bool _cipt,
bool _landscapeOrientation,
int _tableRow,
bool _upsideDownArt);
CardInfoPtr clone() const
{
// Use the copy constructor to create a new instance
CardInfoPtr newCardInfo = CardInfoPtr(new CardInfo(*this));
newCardInfo->setSmartPointer(newCardInfo); // Set the smart pointer for the new instance
return newCardInfo;
}
void setSmartPointer(CardInfoPtr _ptr)
{
smartThis = std::move(_ptr);
}
// basic properties
inline const QString &getName() const
{
return name;
}
const QString &getSimpleName() const
{
return simpleName;
}
void setPixmapCacheKey(QString _pixmapCacheKey)
{
pixmapCacheKey = _pixmapCacheKey;
}
const QString &getPixmapCacheKey() const
{
return pixmapCacheKey;
}
const QString &getText() const
{
return text;
}
void setText(const QString &_text)
{
text = _text;
emit cardInfoChanged(smartThis);
}
bool getIsToken() const
{
return isToken;
}
const QStringList getProperties() const
{
return properties.keys();
}
const QString getProperty(const QString &propertyName) const
{
return properties.value(propertyName).toString();
}
void setProperty(const QString &_name, const QString &_value)
{
properties.insert(_name, _value);
emit cardInfoChanged(smartThis);
}
bool hasProperty(const QString &propertyName) const
{
return properties.contains(propertyName);
}
const CardInfoPerSetMap &getSets() const
{
return sets;
}
const QString &getSetsNames() const
{
return setsNames;
}
const QString getSetProperty(const QString &setName, const QString &propertyName) const
{
if (!sets.contains(setName))
return "";
for (const auto &set : sets[setName]) {
if (QLatin1String("card_") + this->getName() + QString("_") + QString(set.getProperty("uuid")) ==
this->getPixmapCacheKey()) {
return set.getProperty(propertyName);
}
}
return sets[setName][0].getProperty(propertyName);
}
// related cards
const QList<CardRelation *> &getRelatedCards() const
{
return relatedCards;
}
const QList<CardRelation *> &getReverseRelatedCards() const
{
return reverseRelatedCards;
}
const QList<CardRelation *> &getReverseRelatedCards2Me() const
{
return reverseRelatedCardsToMe;
}
const QList<CardRelation *> getAllRelatedCards() const
{
QList<CardRelation *> result;
result.append(getRelatedCards());
result.append(getReverseRelatedCards2Me());
return result;
}
void resetReverseRelatedCards2Me();
void addReverseRelatedCards2Me(CardRelation *cardRelation)
{
reverseRelatedCardsToMe.append(cardRelation);
}
// positioning
bool getCipt() const
{
return cipt;
}
bool getLandscapeOrientation() const
{
return landscapeOrientation;
}
int getTableRow() const
{
return tableRow;
}
void setTableRow(int _tableRow)
{
tableRow = _tableRow;
}
bool getUpsideDownArt() const
{
return upsideDownArt;
}
const QChar getColorChar() const;
// Back-compatibility methods. Remove ASAP
const QString getCardType() const;
void setCardType(const QString &value);
const QString getCmc() const;
const QString getColors() const;
void setColors(const QString &value);
const QString getLoyalty() const;
const QString getMainCardType() const;
const QString getManaCost() const;
const QString getPowTough() const;
void setPowTough(const QString &value);
// methods using per-set properties
QString getCustomPicURL(const QString &set) const
{
return getSetProperty(set, "picurl");
}
QString getCorrectedName() const;
void addToSet(const CardSetPtr &_set, CardInfoPerSet _info = CardInfoPerSet());
void combineLegalities(const QVariantHash &props);
void emitPixmapUpdated()
{
emit pixmapUpdated();
}
void refreshCachedSetNames();
/**
* Simplify a name to have no punctuation and lowercase all letters, for
* less strict name-matching.
*/
static QString simplifyName(const QString &name);
signals:
void pixmapUpdated();
void cardInfoChanged(CardInfoPtr card);
};
class CardRelation : public QObject
{
Q_OBJECT
public:
enum AttachType
{
DoesNotAttach = 0,
AttachTo = 1,
TransformInto = 2,
};
private:
QString name;
AttachType attachType;
bool isCreateAllExclusion;
bool isVariableCount;
int defaultCount;
bool isPersistent;
public:
explicit CardRelation(const QString &_name = QString(),
AttachType _attachType = DoesNotAttach,
bool _isCreateAllExclusion = false,
bool _isVariableCount = false,
int _defaultCount = 1,
bool _isPersistent = false);
inline const QString &getName() const
{
return name;
}
AttachType getAttachType() const
{
return attachType;
}
bool getDoesAttach() const
{
return attachType != DoesNotAttach;
}
bool getDoesTransform() const
{
return attachType == TransformInto;
}
QString getAttachTypeAsString() const
{
switch (attachType) {
case AttachTo:
return "attach";
case TransformInto:
return "transform";
default:
return "";
}
}
bool getCanCreateAnother() const
{
return !getDoesAttach();
}
bool getIsCreateAllExclusion() const
{
return isCreateAllExclusion;
}
bool getIsVariable() const
{
return isVariableCount;
}
int getDefaultCount() const
{
return defaultCount;
}
bool getIsPersistent() const
{
return isPersistent;
}
};
#endif

View file

@ -22,10 +22,9 @@ CardItem::CardItem(Player *_owner,
const QString &_name,
const QString &_providerId,
int _cardid,
bool _revealedCard,
CardZone *_zone)
: AbstractCardItem(parent, _name, _providerId, _owner, _cardid), zone(_zone), revealedCard(_revealedCard),
attacking(false), destroyOnZoneChange(false), doesntUntap(false), dragItem(nullptr), attachedTo(nullptr)
: AbstractCardItem(parent, _name, _providerId, _owner, _cardid), zone(_zone), attacking(false),
destroyOnZoneChange(false), doesntUntap(false), dragItem(nullptr), attachedTo(nullptr)
{
owner->addCard(this);
@ -483,11 +482,9 @@ QVariant CardItem::itemChange(GraphicsItemChange change, const QVariant &value)
owner->setCardMenu(cardMenu);
owner->getGame()->setActiveCard(this);
} else if (owner->getCardMenu() == cardMenu) {
if (scene() && scene()->selectedItems().isEmpty()) {
owner->setCardMenu(nullptr);
}
owner->setCardMenu(nullptr);
owner->getGame()->setActiveCard(nullptr);
}
}
return QGraphicsItem::itemChange(change, value);
return AbstractCardItem::itemChange(change, value);
}

View file

@ -22,7 +22,6 @@ class CardItem : public AbstractCardItem
Q_OBJECT
private:
CardZone *zone;
bool revealedCard;
bool attacking;
QMap<int, int> counters;
QString annotation;
@ -55,7 +54,6 @@ public:
const QString &_name = QString(),
const QString &_providerId = QString(),
int _cardid = -1,
bool revealedCard = false,
CardZone *_zone = nullptr);
~CardItem() override;
void retranslateUi();
@ -85,10 +83,6 @@ public:
{
owner = _owner;
}
bool getRevealedCard() const
{
return revealedCard;
}
bool getAttacking() const
{
return attacking;

View file

@ -74,6 +74,12 @@ DeckViewCard::DeckViewCard(QGraphicsItem *parent,
: AbstractCardItem(parent, _name, _providerId, 0, -1), originZone(_originZone), dragItem(0)
{
setAcceptHoverEvents(true);
connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
Q_UNUSED(_roundCardCorners);
update();
});
}
DeckViewCard::~DeckViewCard()
@ -91,7 +97,7 @@ void DeckViewCard::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti
pen.setJoinStyle(Qt::MiterJoin);
pen.setColor(originZone == DECK_ZONE_MAIN ? Qt::green : Qt::red);
painter->setPen(pen);
qreal cardRadius = 0.05 * (CARD_WIDTH - 3);
qreal cardRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * (CARD_WIDTH - 3) : 0.0;
painter->drawRoundedRect(QRectF(1.5, 1.5, CARD_WIDTH - 3., CARD_HEIGHT - 3.), cardRadius, cardRadius);
painter->restore();
}
@ -178,7 +184,7 @@ void DeckViewCardContainer::paint(QPainter *painter, const QStyleOptionGraphicsI
{
qreal totalTextWidth = getCardTypeTextWidth();
painter->fillRect(boundingRect(), themeManager->getTableBgBrush());
painter->fillRect(boundingRect(), themeManager->getBgBrush(ThemeManager::Table));
painter->setPen(QColor(255, 255, 255, 100));
painter->drawLine(QPointF(0, separatorY), QPointF(width, separatorY));
@ -525,4 +531,4 @@ void DeckView::clearDeck()
void DeckView::resetSideboardPlan()
{
deckViewScene->resetSideboardPlan();
}
}

View file

@ -93,12 +93,7 @@ void PlayerArea::updateBg()
void PlayerArea::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
{
QBrush brush = themeManager->getPlayerBgBrush();
if (playerZoneId > 0) {
// If the extra image is not found, load the default one
brush = themeManager->getExtraPlayerBgBrush(QString::number(playerZoneId), brush);
}
QBrush brush = themeManager->getExtraBgBrush(ThemeManager::Player, playerZoneId);
painter->fillRect(boundingRect(), brush);
}
@ -1448,19 +1443,20 @@ void Player::actMoveTopCardsUntil()
{
stopMoveTopCardsUntil();
DlgMoveTopCardsUntil dlg(game, movingCardsUntilExpr, movingCardsUntilNumberOfHits, movingCardsUntilAutoPlay);
DlgMoveTopCardsUntil dlg(game, movingCardsUntilExprs, movingCardsUntilNumberOfHits, movingCardsUntilAutoPlay);
if (!dlg.exec()) {
return;
}
movingCardsUntilExpr = dlg.getExpr();
auto expr = dlg.getExpr();
movingCardsUntilExprs = dlg.getExprs();
movingCardsUntilNumberOfHits = dlg.getNumberOfHits();
movingCardsUntilAutoPlay = dlg.isAutoPlay();
if (zones.value("deck")->getCards().empty()) {
stopMoveTopCardsUntil();
} else {
movingCardsUntilFilter = FilterString(movingCardsUntilExpr);
movingCardsUntilFilter = FilterString(expr);
movingCardsUntilCounter = movingCardsUntilNumberOfHits;
movingCardsUntil = true;
actMoveTopCardToPlay();
@ -2069,7 +2065,6 @@ void Player::createCard(const CardItem *sourceCard,
cmd.set_target_zone("table"); // We currently only support creating tokens on the table
cmd.set_target_card_id(sourceCard->getId());
cmd.set_target_mode(Command_CreateToken::ATTACH_TO);
cmd.set_card_provider_id(sourceCard->getProviderId().toStdString());
break;
case CardRelation::TransformInto:

View file

@ -279,7 +279,7 @@ private:
bool movingCardsUntil;
QTimer *moveTopCardTimer;
QString movingCardsUntilExpr = {};
QStringList movingCardsUntilExprs = {};
int movingCardsUntilNumberOfHits = 1;
bool movingCardsUntilAutoPlay = false;
FilterString movingCardsUntilFilter;

View file

@ -78,12 +78,7 @@ QRectF HandZone::boundingRect() const
void HandZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
{
QBrush brush = themeManager->getHandBgBrush();
if (player->getZoneId() > 0) {
// If the extra image is not found, load the default one
brush = themeManager->getExtraHandBgBrush(QString::number(player->getZoneId()), brush);
}
QBrush brush = themeManager->getExtraBgBrush(ThemeManager::Hand, player->getZoneId());
painter->fillRect(boundingRect(), brush);
}

View file

@ -21,6 +21,13 @@ PileZone::PileZone(Player *_p, const QString &_name, bool _isShufflable, bool _c
.translate((float)CARD_WIDTH / 2, (float)CARD_HEIGHT / 2)
.rotate(90)
.translate((float)-CARD_WIDTH / 2, (float)-CARD_HEIGHT / 2));
connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
Q_UNUSED(_roundCardCorners);
prepareGeometryChange();
update();
});
}
QRectF PileZone::boundingRect() const
@ -31,7 +38,8 @@ QRectF PileZone::boundingRect() const
QPainterPath PileZone::shape() const
{
QPainterPath shape;
shape.addRoundedRect(boundingRect(), 0.05 * CARD_WIDTH, 0.05 * CARD_WIDTH);
qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CARD_WIDTH : 0.0;
shape.addRoundedRect(boundingRect(), cardCornerRadius, cardCornerRadius);
return shape;
}

View file

@ -49,12 +49,7 @@ QRectF StackZone::boundingRect() const
void StackZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
{
QBrush brush = themeManager->getStackBgBrush();
if (player->getZoneId() > 0) {
// If the extra image is not found, load the default one
brush = themeManager->getExtraStackBgBrush(QString::number(player->getZoneId()), brush);
}
QBrush brush = themeManager->getExtraBgBrush(ThemeManager::Stack, player->getZoneId());
painter->fillRect(boundingRect(), brush);
}
@ -71,26 +66,25 @@ void StackZone::handleDropEvent(const QList<CardDragItem *> &dragItems, CardZone
cmd.set_target_zone(getName().toStdString());
int index = 0;
if (cards.isEmpty()) {
index = 0;
} else {
if (!cards.isEmpty()) {
const auto cardCount = static_cast<int>(cards.size());
const auto &card = cards.at(0);
if (card == nullptr) {
qCWarning(StackZoneLog) << "Attempted to move card from" << startZone->getName() << ", but was null";
return;
}
index = qRound(divideCardSpaceInZone(dropPoint.y(), cardCount, boundingRect().height(),
card->boundingRect().height(), true));
}
if (startZone == this) {
const auto &dragItem = dragItems.at(0);
const auto &card = cards.at(index);
if (card != nullptr && dragItem != nullptr && card->getId() == dragItem->getId()) {
return;
// divideCardSpaceInZone is not guaranteed to return a valid index
// currently, so clamp it to avoid crashes.
index = qBound(0, index, cardCount - 1);
if (startZone == this) {
const auto &dragItem = dragItems.at(0);
const auto &card = cards.at(index);
if (card->getId() == dragItem->getId()) {
return;
}
}
}
@ -109,8 +103,6 @@ void StackZone::handleDropEvent(const QList<CardDragItem *> &dragItems, CardZone
void StackZone::reorganizeCards()
{
if (!cards.isEmpty()) {
QSet<ArrowItem *> arrowsToUpdate;
const auto cardCount = static_cast<int>(cards.size());
qreal totalWidth = boundingRect().width();
qreal cardWidth = cards.at(0)->boundingRect().width();
@ -125,16 +117,6 @@ void StackZone::reorganizeCards()
divideCardSpaceInZone(i, cardCount, boundingRect().height(), cards.at(0)->boundingRect().height());
card->setPos(x, y);
card->setRealZValue(i);
for (ArrowItem *item : card->getArrowsFrom()) {
arrowsToUpdate.insert(item);
}
for (ArrowItem *item : card->getArrowsTo()) {
arrowsToUpdate.insert(item);
}
}
for (ArrowItem *item : arrowsToUpdate) {
item->updatePath();
}
}
update();

View file

@ -3,8 +3,6 @@
#include "select_zone.h"
inline Q_LOGGING_CATEGORY(StackZoneLog, "stack_zone");
class StackZone : public SelectZone
{
Q_OBJECT

View file

@ -54,12 +54,7 @@ bool TableZone::isInverted() const
void TableZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
{
QBrush brush = themeManager->getTableBgBrush();
if (player->getZoneId() > 0) {
// If the extra image is not found, load the default one
brush = themeManager->getExtraTableBgBrush(QString::number(player->getZoneId()), brush);
}
QBrush brush = themeManager->getExtraBgBrush(ThemeManager::Table, player->getZoneId());
painter->fillRect(boundingRect(), brush);
if (active) {
@ -157,8 +152,6 @@ void TableZone::handleDropEventByGrid(const QList<CardDragItem *> &dragItems,
void TableZone::reorganizeCards()
{
QSet<ArrowItem *> arrowsToUpdate;
// Calculate card stack widths so mapping functions work properly
computeCardStackWidths();
@ -189,23 +182,7 @@ void TableZone::reorganizeCards()
qreal childY = y + 5;
attachedCard->setPos(childX, childY);
attachedCard->setRealZValue((childY + CARD_HEIGHT) * 100000 + (childX + 1) * 100);
for (ArrowItem *item : attachedCard->getArrowsFrom()) {
arrowsToUpdate.insert(item);
}
for (ArrowItem *item : attachedCard->getArrowsTo()) {
arrowsToUpdate.insert(item);
}
}
for (ArrowItem *item : cards[i]->getArrowsFrom()) {
arrowsToUpdate.insert(item);
}
for (ArrowItem *item : cards[i]->getArrowsTo()) {
arrowsToUpdate.insert(item);
}
}
for (ArrowItem *item : arrowsToUpdate) {
item->updatePath();
}
resizeToContents();

View file

@ -70,7 +70,7 @@ void ZoneViewZone::initializeCards(const QList<const ServerInfo_Card *> &cardLis
if (!cardList.isEmpty()) {
for (int i = 0; i < cardList.size(); ++i)
addCard(new CardItem(player, this, QString::fromStdString(cardList[i]->name()),
QString::fromStdString(cardList[i]->provider_id()), cardList[i]->id(), revealZone),
QString::fromStdString(cardList[i]->provider_id()), cardList[i]->id()),
false, i);
reorganizeCards();
} else if (!origZone->contentsKnown()) {
@ -88,8 +88,7 @@ void ZoneViewZone::initializeCards(const QList<const ServerInfo_Card *> &cardLis
int number = numberCards == -1 ? c.size() : (numberCards < c.size() ? numberCards : c.size());
for (int i = 0; i < number; i++) {
CardItem *card = c.at(i);
addCard(new CardItem(player, this, card->getName(), card->getProviderId(), card->getId(), revealZone),
false, i);
addCard(new CardItem(player, this, card->getName(), card->getProviderId(), card->getId()), false, i);
}
reorganizeCards();
}
@ -103,7 +102,7 @@ void ZoneViewZone::zoneDumpReceived(const Response &r)
const ServerInfo_Card &cardInfo = resp.zone_info().card_list(i);
auto cardName = QString::fromStdString(cardInfo.name());
auto cardProviderId = QString::fromStdString(cardInfo.provider_id());
auto *card = new CardItem(player, this, cardName, cardProviderId, cardInfo.id(), revealZone, this);
auto *card = new CardItem(player, this, cardName, cardProviderId, cardInfo.id(), this);
cards.insert(i, card);
}

View file

@ -254,11 +254,13 @@ SettingsCache::SettingsCache()
showShortcuts = settings->value("menu/showshortcuts", true).toBool();
displayCardNames = settings->value("cards/displaycardnames", true).toBool();
roundCardCorners = settings->value("cards/roundcardcorners", true).toBool();
overrideAllCardArtWithPersonalPreference =
settings->value("cards/overrideallcardartwithpersonalpreference", false).toBool();
bumpSetsWithCardsInDeckToTop = settings->value("cards/bumpsetswithcardsindecktotop", true).toBool();
printingSelectorSortOrder = settings->value("cards/printingselectorsortorder", 1).toInt();
printingSelectorCardSize = settings->value("cards/printingselectorcardsize", 100).toInt();
includeOnlineOnlyCards = settings->value("cards/includeonlineonlycards", false).toBool();
printingSelectorNavigationButtonsVisible =
settings->value("cards/printingselectornavigationbuttonsvisible", true).toBool();
visualDeckStorageCardSize = settings->value("interface/visualdeckstoragecardsize", 100).toInt();
@ -661,6 +663,13 @@ void SettingsCache::setPrintingSelectorCardSize(int _printingSelectorCardSize)
emit printingSelectorCardSizeChanged();
}
void SettingsCache::setIncludeOnlineOnlyCards(bool _includeOnlineOnlyCards)
{
includeOnlineOnlyCards = _includeOnlineOnlyCards;
settings->setValue("cards/includeonlineonlycards", includeOnlineOnlyCards);
emit includeOnlineOnlyCardsChanged(includeOnlineOnlyCards);
}
void SettingsCache::setPrintingSelectorNavigationButtonsVisible(QT_STATE_CHANGED_T _navigationButtonsVisible)
{
printingSelectorNavigationButtonsVisible = _navigationButtonsVisible;
@ -728,6 +737,7 @@ void SettingsCache::setVisualDeckStorageUnusedColorIdentitiesOpacity(int _visual
visualDeckStorageUnusedColorIdentitiesOpacity = _visualDeckStorageUnusedColorIdentitiesOpacity;
settings->setValue("interface/visualdeckstorageunusedcoloridentitiesopacity",
visualDeckStorageUnusedColorIdentitiesOpacity);
emit visualDeckStorageUnusedColorIdentitiesOpacityChanged(visualDeckStorageUnusedColorIdentitiesOpacity);
}
void SettingsCache::setVisualDeckStoragePromptForConversion(QT_STATE_CHANGED_T _visualDeckStoragePromptForConversion)
@ -1292,6 +1302,16 @@ void SettingsCache::setMaxFontSize(int _max)
settings->setValue("game/maxfontsize", maxFontSize);
}
void SettingsCache::setRoundCardCorners(bool _roundCardCorners)
{
if (_roundCardCorners == roundCardCorners)
return;
roundCardCorners = _roundCardCorners;
settings->setValue("cards/roundcardcorners", _roundCardCorners);
emit roundCardCornersChanged(roundCardCorners);
}
void SettingsCache::loadPaths()
{
QString dataPath = getDataPath();

View file

@ -47,6 +47,7 @@ class QSettings;
class SettingsCache : public QObject
{
Q_OBJECT
signals:
void langChanged();
void picsPathChanged();
@ -58,12 +59,14 @@ signals:
void bumpSetsWithCardsInDeckToTopChanged();
void printingSelectorSortOrderChanged();
void printingSelectorCardSizeChanged();
void includeOnlineOnlyCardsChanged(bool _includeOnlineOnlyCards);
void printingSelectorNavigationButtonsVisibleChanged();
void visualDeckStorageShowTagFilterChanged(bool _visible);
void visualDeckStorageShowBannerCardComboBoxChanged(bool _visible);
void visualDeckStorageShowTagsOnDeckPreviewsChanged(bool _visible);
void visualDeckStorageCardSizeChanged();
void visualDeckStorageDrawUnusedColorIdentitiesChanged(bool _visible);
void visualDeckStorageUnusedColorIdentitiesOpacityChanged(bool value);
void visualDeckStorageInGameChanged(bool enabled);
void horizontalHandChanged();
void handJustificationChanged();
@ -81,6 +84,7 @@ signals:
void downloadSpoilerTimeIndexChanged();
void downloadSpoilerStatusChanged();
void useTearOffMenusChanged(bool state);
void roundCardCornersChanged(bool roundCardCorners);
private:
QSettings *settings;
@ -127,6 +131,7 @@ private:
bool bumpSetsWithCardsInDeckToTop;
int printingSelectorSortOrder;
int printingSelectorCardSize;
bool includeOnlineOnlyCards;
bool printingSelectorNavigationButtonsVisible;
int visualDeckStorageSortingOrder;
bool visualDeckStorageShowFolders;
@ -201,6 +206,7 @@ private:
QList<ReleaseChannel *> releaseChannels;
bool isPortableBuild;
bool localTime;
bool roundCardCorners;
public:
SettingsCache();
@ -401,6 +407,10 @@ public:
{
return printingSelectorCardSize;
}
bool getIncludeOnlineOnlyCards() const
{
return includeOnlineOnlyCards;
}
bool getPrintingSelectorNavigationButtonsVisible() const
{
return printingSelectorNavigationButtonsVisible;
@ -731,6 +741,10 @@ public:
{
return mbDownloadSpoilers;
}
bool getRoundCardCorners() const
{
return roundCardCorners;
}
static SettingsCache &instance();
void resetPaths();
@ -778,6 +792,7 @@ public slots:
void setBumpSetsWithCardsInDeckToTop(QT_STATE_CHANGED_T _bumpSetsWithCardsInDeckToTop);
void setPrintingSelectorSortOrder(int _printingSelectorSortOrder);
void setPrintingSelectorCardSize(int _printingSelectorCardSize);
void setIncludeOnlineOnlyCards(bool _includeOnlineOnlyCards);
void setPrintingSelectorNavigationButtonsVisible(QT_STATE_CHANGED_T _navigationButtonsVisible);
void setVisualDeckStorageSortingOrder(int _visualDeckStorageSortingOrder);
void setVisualDeckStorageShowFolders(QT_STATE_CHANGED_T value);
@ -839,6 +854,7 @@ public slots:
void setNotifyAboutNewVersion(QT_STATE_CHANGED_T _notifyaboutnewversion);
void setUpdateReleaseChannelIndex(int value);
void setMaxFontSize(int _max);
void setRoundCardCorners(bool _roundCardCorners);
};
#endif

View file

@ -173,9 +173,13 @@ private:
{"MainWindow/aWatchReplay", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Watch Replay..."),
parseSequenceString(""),
ShortcutGroup::Main_Window)},
{"TabDeckEditor/aAnalyzeDeck", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Analyze Deck"),
{"TabDeckEditor/aAnalyzeDeck", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Analyze Deck (deckstats.net)"),
parseSequenceString(""),
ShortcutGroup::Deck_Editor)},
{"TabDeckEditor/aAnalyzeDeckTappedout",
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Analyze Deck (tappedout.net)"),
parseSequenceString(""),
ShortcutGroup::Deck_Editor)},
{"TabDeckEditor/aClearFilterAll", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Clear All Filters"),
parseSequenceString(""),
ShortcutGroup::Deck_Editor)},
@ -193,9 +197,14 @@ private:
{"TabDeckEditor/aEditTokens", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Edit Custom Tokens..."),
parseSequenceString(""),
ShortcutGroup::Deck_Editor)},
{"TabDeckEditor/aExportDeckDecklist", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Export Deck"),
parseSequenceString(""),
ShortcutGroup::Deck_Editor)},
{"TabDeckEditor/aExportDeckDecklist",
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Export Deck (decklist.org)"),
parseSequenceString(""),
ShortcutGroup::Deck_Editor)},
{"TabDeckEditor/aExportDeckDecklistXyz",
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Export Deck (decklist.xyz)"),
parseSequenceString(""),
ShortcutGroup::Deck_Editor)},
{"TabDeckEditor/aIncrement", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Add Card"),
parseSequenceString("+"),
ShortcutGroup::Deck_Editor)},