Merge branch 'master' into card-rounding-option

This commit is contained in:
Basile Clement 2025-03-21 09:14:49 +01:00 committed by GitHub
commit 8389884aae
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 1608 additions and 1142 deletions

File diff suppressed because it is too large Load diff

View file

@ -47,12 +47,10 @@
# card_info = false
# card_list = false
# stack_zone = false
flow_layout.debug = false
flow_widget.debug = false
flow_widget.size.debug = false
# pixel_map_generator = false
# filter_string = false
# filter_string = false

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

@ -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:
/**

View file

@ -14,7 +14,7 @@
#include <QLabel>
DeckPreviewDeckTagsDisplayWidget::DeckPreviewDeckTagsDisplayWidget(QWidget *_parent, DeckList *_deckList)
: QWidget(_parent), deckList(_deckList)
: QWidget(_parent), deckList(nullptr)
{
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
@ -27,8 +27,8 @@ DeckPreviewDeckTagsDisplayWidget::DeckPreviewDeckTagsDisplayWidget(QWidget *_par
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
if (deckList) {
connectDeckList(deckList);
if (_deckList) {
connectDeckList(_deckList);
}
layout->addWidget(flowWidget);
@ -36,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));
}
@ -50,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
*/
@ -160,4 +160,4 @@ void DeckPreviewDeckTagsDisplayWidget::openTagEditDlg()
}
}
}
}
}

View file

@ -59,7 +59,7 @@ void VisualDeckStorageFolderDisplayWidget::refreshUi()
}
/**
* Gets all files in the directory that have a .txt or .cod extension
* 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

View file

@ -226,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.
@ -275,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

@ -31,6 +31,12 @@ public:
*/
static const QStringList FILE_NAME_FILTERS;
enum DecklistWebsite
{
DecklistOrg,
DecklistXyz
};
private:
QString lastFileName;
FileFormat lastFileFormat;
@ -71,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

@ -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

@ -10,7 +10,6 @@
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QPainter>
#include <QStyleOption>
#include <algorithm>
AbstractCardItem::AbstractCardItem(QGraphicsItem *parent,
@ -19,7 +18,7 @@ AbstractCardItem::AbstractCardItem(QGraphicsItem *parent,
Player *_owner,
int _id)
: ArrowTarget(_owner, parent), id(_id), name(_name), providerId(_providerId), tapped(false), facedown(false),
tapAngle(0), bgColor(Qt::transparent), realZValue(0)
tapAngle(0), bgColor(Qt::transparent), isHovered(false), realZValue(0)
{
setCursor(Qt::OpenHandCursor);
setFlag(ItemIsSelectable);
@ -28,8 +27,6 @@ AbstractCardItem::AbstractCardItem(QGraphicsItem *parent,
connect(&SettingsCache::instance(), &SettingsCache::displayCardNamesChanged, this, [this] { update(); });
refreshCardInfo();
setAcceptHoverEvents(true);
connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
Q_UNUSED(_roundCardCorners);
@ -168,7 +165,7 @@ void AbstractCardItem::paintPicture(QPainter *painter, const QSizeF &translatedS
painter->restore();
}
void AbstractCardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget * /*widget*/)
void AbstractCardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
{
painter->save();
@ -177,7 +174,6 @@ void AbstractCardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *
painter->setRenderHint(QPainter::Antialiasing, false);
bool isHovered = option->state.testFlag(QStyle::State_MouseOver);
if (isSelected() || isHovered) {
QPen pen;
if (isHovered)
@ -220,24 +216,17 @@ void AbstractCardItem::setProviderId(const QString &_providerId)
refreshCardInfo();
}
void AbstractCardItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
void AbstractCardItem::setHovered(bool _hovered)
{
Q_UNUSED(event);
if (isHovered == _hovered)
return;
emit hovered(this);
setZValue(2000000004);
setScale(SettingsCache::instance().getScaleCards() ? 1.1 : 1);
setTransformOriginPoint(CARD_WIDTH / 2, CARD_HEIGHT / 2);
update();
}
void AbstractCardItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event);
setZValue(realZValue);
setScale(1);
setTransformOriginPoint(0, 0);
if (_hovered)
processHoverEvent();
isHovered = _hovered;
setZValue(_hovered ? 2000000004 : realZValue);
setScale(_hovered && SettingsCache::instance().getScaleCards() ? 1.1 : 1);
setTransformOriginPoint(_hovered ? CARD_WIDTH / 2 : 0, _hovered ? CARD_HEIGHT / 2 : 0);
update();
}
@ -333,6 +322,11 @@ void AbstractCardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
event->accept();
}
void AbstractCardItem::processHoverEvent()
{
emit hovered(this);
}
QVariant AbstractCardItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
{
if (change == ItemSelectedHasChanged) {

View file

@ -24,6 +24,7 @@ protected:
QColor bgColor;
private:
bool isHovered;
qreal realZValue;
private slots:
void pixmapUpdated();
@ -85,6 +86,7 @@ public:
return realZValue;
}
void setRealZValue(qreal _zValue);
void setHovered(bool _hovered);
QString getColor() const
{
return color;
@ -100,6 +102,7 @@ public:
return facedown;
}
void setFaceDown(bool _facedown);
void processHoverEvent();
void deleteCardInfoPopup()
{
emit deleteCardInfoPopup(name);
@ -111,9 +114,6 @@ protected:
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override;
void cacheBgColor();
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override;
};
#endif

View file

@ -469,6 +469,7 @@ bool CardItem::animationEvent()
.translate(CARD_WIDTH_HALF, CARD_HEIGHT_HALF)
.rotate(tapAngle)
.translate(-CARD_WIDTH_HALF, -CARD_HEIGHT_HALF));
setHovered(false);
update();
return animationIncomplete;

View file

@ -164,6 +164,12 @@ void DeckView::mouseDoubleClickEvent(QMouseEvent *event)
}
}
void DeckViewCard::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
event->accept();
processHoverEvent();
}
DeckViewCardContainer::DeckViewCardContainer(const QString &_name) : QGraphicsItem(), name(_name), width(0), height(0)
{
setCacheMode(DeviceCoordinateCache);

View file

@ -37,6 +37,7 @@ public:
protected:
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
};
class DeckViewCardDragItem : public AbstractCardDragItem

View file

@ -253,6 +253,51 @@ void GameScene::processViewSizeChange(const QSize &newSize)
}
}
void GameScene::updateHover(const QPointF &scenePos)
{
QList<QGraphicsItem *> itemList =
items(scenePos, Qt::IntersectsItemBoundingRect, Qt::DescendingOrder, getViewTransform());
// Search for the topmost zone and ignore all cards not belonging to that zone.
CardZone *zone = 0;
for (int i = 0; i < itemList.size(); ++i)
if ((zone = qgraphicsitem_cast<CardZone *>(itemList[i])))
break;
CardItem *maxZCard = 0;
if (zone) {
qreal maxZ = -1;
for (int i = 0; i < itemList.size(); ++i) {
CardItem *card = qgraphicsitem_cast<CardItem *>(itemList[i]);
if (!card)
continue;
if (card->getAttachedTo()) {
if (card->getAttachedTo()->getZone() != zone)
continue;
} else if (card->getZone() != zone)
continue;
if (card->getRealZValue() > maxZ) {
maxZ = card->getRealZValue();
maxZCard = card;
}
}
}
if (hoveredCard && (maxZCard != hoveredCard))
hoveredCard->setHovered(false);
if (maxZCard && (maxZCard != hoveredCard))
maxZCard->setHovered(true);
hoveredCard = maxZCard;
}
bool GameScene::event(QEvent *event)
{
if (event->type() == QEvent::GraphicsSceneMouseMove)
updateHover(static_cast<QGraphicsSceneMouseEvent *>(event)->scenePos());
return QGraphicsScene::event(event);
}
void GameScene::timerEvent(QTimerEvent * /*event*/)
{
QMutableSetIterator<CardItem *> i(cardsToAnimate);

View file

@ -30,9 +30,11 @@ private:
QList<QList<Player *>> playersByColumn;
QList<ZoneViewWidget *> zoneViews;
QSize viewSize;
QPointer<CardItem> hoveredCard;
QBasicTimer *animationTimer;
QSet<CardItem *> cardsToAnimate;
int playerRotation;
void updateHover(const QPointF &scenePos);
public:
explicit GameScene(PhasesToolbar *_phasesToolbar, QObject *parent = nullptr);
@ -63,6 +65,7 @@ public slots:
void rearrange();
protected:
bool event(QEvent *event) override;
void timerEvent(QTimerEvent *event) override;
signals:
void sigStartRubberBand(const QPointF &selectionOrigin);

View file

@ -1443,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();
@ -2386,6 +2387,7 @@ void Player::eventMoveCard(const Event_MoveCard &event, const GameEventContext &
card->setFaceDown(event.face_down());
if (startZone != targetZone) {
card->setBeingPointedAt(false);
card->setHovered(false);
const QList<CardItem *> &attachedCards = card->getAttachedCards();
for (auto attachedCard : attachedCards) {

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

@ -139,7 +139,6 @@ void PileZone::mouseReleaseEvent(QGraphicsSceneMouseEvent * /*event*/)
void PileZone::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
if (!cards.isEmpty())
emit cards[0]->hovered(cards[0]);
cards[0]->processHoverEvent();
QGraphicsItem::hoverEnterEvent(event);
}

View file

@ -66,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;
}
}
}

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

@ -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)},

View file

@ -1,6 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="en_US">
<context>
<name>BetaReleaseChannel</name>
<message>
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="210"/>
<source>Beta</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="236"/>
<source>No reply received from the release update server.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="245"/>
<source>Invalid reply received from the release update server.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="278"/>
<source>No reply received from the file update server.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>IntroPage</name>
<message>
@ -63,7 +86,8 @@
</message>
<message>
<location filename="src/oraclewizard.cpp" line="287"/>
<source>Sets JSON file (%1)</source>
<source>Sets file (%1)</source>
<oldsource>Sets JSON file (%1)</oldsource>
<translation type="unfinished"></translation>
</message>
<message>
@ -247,7 +271,7 @@
<context>
<name>OracleImporter</name>
<message>
<location filename="src/oracleimporter.cpp" line="465"/>
<location filename="src/oracleimporter.cpp" line="471"/>
<source>Dummy set containing tokens</source>
<translation type="unfinished"></translation>
</message>
@ -283,6 +307,15 @@
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>PictureLoader</name>
<message>
<location filename="../cockatrice/src/client/ui/picture_loader/picture_to_load.cpp" line="219"/>
<source>en</source>
<comment>code for scryfall&apos;s language property, not available for all languages</comment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SaveSetsPage</name>
<message>
@ -357,6 +390,21 @@
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ShortcutsSettings</name>
<message>
<location filename="../cockatrice/src/settings/shortcuts_settings.cpp" line="54"/>
<source>Your configuration file contained invalid shortcuts.
Please check your shortcut settings!</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../cockatrice/src/settings/shortcuts_settings.cpp" line="56"/>
<source>The following shortcuts have been set to default:
</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SimpleDownloadFilePage</name>
<message>
@ -392,6 +440,34 @@
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>StableReleaseChannel</name>
<message>
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="104"/>
<source>Default</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="120"/>
<source>No reply received from the release update server.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="128"/>
<source>Invalid reply received from the release update server.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="176"/>
<source>No reply received from the tag update server.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../cockatrice/src/client/network/release_channel.cpp" line="183"/>
<source>Invalid reply received from the tag update server.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>UnZip</name>
<message>
@ -537,6 +613,7 @@
<name>i18n</name>
<message>
<location filename="src/oraclewizard.cpp" line="58"/>
<location filename="../cockatrice/src/settings/cache_settings.cpp" line="167"/>
<source>English</source>
<translation type="unfinished"></translation>
</message>