make cards on the stack slightly overlap to stress order (#4930)

* make cards on the stack slightly overlap to stress order

dragging cards to the stack now places the card at the location it is
dropped

* make default play action append to stack

* add vertical overlap to settings and vertical hand

* Update cockatrice/src/dlg_settings.cpp

Co-authored-by: tooomm <tooomm@users.noreply.github.com>

* Fix format

---------

Co-authored-by: tooomm <tooomm@users.noreply.github.com>
Co-authored-by: ZeldaZach <zahalpern+github@gmail.com>
This commit is contained in:
ebbit1q 2023-12-15 20:00:58 +01:00 committed by GitHub
parent 28f80e18a0
commit fa727524dc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 104 additions and 49 deletions

View file

@ -299,6 +299,7 @@ void GeneralSettingsPage::retranslateUi()
AppearanceSettingsPage::AppearanceSettingsPage() AppearanceSettingsPage::AppearanceSettingsPage()
{ {
SettingsCache &settings = SettingsCache::instance();
QString themeName = SettingsCache::instance().getThemeName(); QString themeName = SettingsCache::instance().getThemeName();
QStringList themeDirs = themeManager->getAvailableThemes().keys(); QStringList themeDirs = themeManager->getAvailableThemes().keys();
@ -319,27 +320,31 @@ AppearanceSettingsPage::AppearanceSettingsPage()
themeGroupBox = new QGroupBox; themeGroupBox = new QGroupBox;
themeGroupBox->setLayout(themeGrid); themeGroupBox->setLayout(themeGrid);
displayCardNamesCheckBox.setChecked(SettingsCache::instance().getDisplayCardNames()); displayCardNamesCheckBox.setChecked(settings.getDisplayCardNames());
connect(&displayCardNamesCheckBox, SIGNAL(stateChanged(int)), &SettingsCache::instance(), connect(&displayCardNamesCheckBox, SIGNAL(stateChanged(int)), &settings, SLOT(setDisplayCardNames(int)));
SLOT(setDisplayCardNames(int)));
cardScalingCheckBox.setChecked(SettingsCache::instance().getScaleCards()); cardScalingCheckBox.setChecked(settings.getScaleCards());
connect(&cardScalingCheckBox, SIGNAL(stateChanged(int)), &SettingsCache::instance(), SLOT(setCardScaling(int))); connect(&cardScalingCheckBox, SIGNAL(stateChanged(int)), &settings, SLOT(setCardScaling(int)));
verticalCardOverlapPercentBox.setValue(settings.getStackCardOverlapPercent());
verticalCardOverlapPercentBox.setRange(0, 80);
connect(&verticalCardOverlapPercentBox, SIGNAL(valueChanged(int)), &settings,
SLOT(setStackCardOverlapPercent(int)));
auto *cardsGrid = new QGridLayout; auto *cardsGrid = new QGridLayout;
cardsGrid->addWidget(&displayCardNamesCheckBox, 0, 0, 1, 2); cardsGrid->addWidget(&displayCardNamesCheckBox, 0, 0, 1, 2);
cardsGrid->addWidget(&cardScalingCheckBox, 1, 0, 1, 2); cardsGrid->addWidget(&cardScalingCheckBox, 1, 0, 1, 2);
cardsGrid->addWidget(&verticalCardOverlapPercentLabel, 2, 0, 1, 1);
cardsGrid->addWidget(&verticalCardOverlapPercentBox, 2, 1, 1, 1);
cardsGroupBox = new QGroupBox; cardsGroupBox = new QGroupBox;
cardsGroupBox->setLayout(cardsGrid); cardsGroupBox->setLayout(cardsGrid);
horizontalHandCheckBox.setChecked(SettingsCache::instance().getHorizontalHand()); horizontalHandCheckBox.setChecked(settings.getHorizontalHand());
connect(&horizontalHandCheckBox, SIGNAL(stateChanged(int)), &SettingsCache::instance(), connect(&horizontalHandCheckBox, SIGNAL(stateChanged(int)), &settings, SLOT(setHorizontalHand(int)));
SLOT(setHorizontalHand(int)));
leftJustifiedHandCheckBox.setChecked(SettingsCache::instance().getLeftJustified()); leftJustifiedHandCheckBox.setChecked(settings.getLeftJustified());
connect(&leftJustifiedHandCheckBox, SIGNAL(stateChanged(int)), &SettingsCache::instance(), connect(&leftJustifiedHandCheckBox, SIGNAL(stateChanged(int)), &settings, SLOT(setLeftJustified(int)));
SLOT(setLeftJustified(int)));
auto *handGrid = new QGridLayout; auto *handGrid = new QGridLayout;
handGrid->addWidget(&horizontalHandCheckBox, 0, 0, 1, 2); handGrid->addWidget(&horizontalHandCheckBox, 0, 0, 1, 2);
@ -348,18 +353,18 @@ AppearanceSettingsPage::AppearanceSettingsPage()
handGroupBox = new QGroupBox; handGroupBox = new QGroupBox;
handGroupBox->setLayout(handGrid); handGroupBox->setLayout(handGrid);
invertVerticalCoordinateCheckBox.setChecked(SettingsCache::instance().getInvertVerticalCoordinate()); invertVerticalCoordinateCheckBox.setChecked(settings.getInvertVerticalCoordinate());
connect(&invertVerticalCoordinateCheckBox, SIGNAL(stateChanged(int)), &SettingsCache::instance(), connect(&invertVerticalCoordinateCheckBox, SIGNAL(stateChanged(int)), &settings,
SLOT(setInvertVerticalCoordinate(int))); SLOT(setInvertVerticalCoordinate(int)));
minPlayersForMultiColumnLayoutEdit.setMinimum(2); minPlayersForMultiColumnLayoutEdit.setMinimum(2);
minPlayersForMultiColumnLayoutEdit.setValue(SettingsCache::instance().getMinPlayersForMultiColumnLayout()); minPlayersForMultiColumnLayoutEdit.setValue(settings.getMinPlayersForMultiColumnLayout());
connect(&minPlayersForMultiColumnLayoutEdit, SIGNAL(valueChanged(int)), &SettingsCache::instance(), connect(&minPlayersForMultiColumnLayoutEdit, SIGNAL(valueChanged(int)), &settings,
SLOT(setMinPlayersForMultiColumnLayout(int))); SLOT(setMinPlayersForMultiColumnLayout(int)));
minPlayersForMultiColumnLayoutLabel.setBuddy(&minPlayersForMultiColumnLayoutEdit); minPlayersForMultiColumnLayoutLabel.setBuddy(&minPlayersForMultiColumnLayoutEdit);
connect(&maxFontSizeForCardsEdit, SIGNAL(valueChanged(int)), &SettingsCache::instance(), SLOT(setMaxFontSize(int))); connect(&maxFontSizeForCardsEdit, SIGNAL(valueChanged(int)), &settings, SLOT(setMaxFontSize(int)));
maxFontSizeForCardsEdit.setValue(SettingsCache::instance().getMaxFontSize()); maxFontSizeForCardsEdit.setValue(settings.getMaxFontSize());
maxFontSizeForCardsLabel.setBuddy(&maxFontSizeForCardsEdit); maxFontSizeForCardsLabel.setBuddy(&maxFontSizeForCardsEdit);
maxFontSizeForCardsEdit.setMinimum(9); maxFontSizeForCardsEdit.setMinimum(9);
maxFontSizeForCardsEdit.setMaximum(100); maxFontSizeForCardsEdit.setMaximum(100);
@ -413,6 +418,8 @@ void AppearanceSettingsPage::retranslateUi()
cardsGroupBox->setTitle(tr("Card rendering")); cardsGroupBox->setTitle(tr("Card rendering"));
displayCardNamesCheckBox.setText(tr("Display card names on cards having a picture")); displayCardNamesCheckBox.setText(tr("Display card names on cards having a picture"));
cardScalingCheckBox.setText(tr("Scale cards on mouse over")); cardScalingCheckBox.setText(tr("Scale cards on mouse over"));
verticalCardOverlapPercentLabel.setText(
tr("Minimum overlap percentage of cards on the stack and in vertical hand"));
handGroupBox->setTitle(tr("Hand layout")); handGroupBox->setTitle(tr("Hand layout"));
horizontalHandCheckBox.setText(tr("Display hand horizontally (wastes space)")); horizontalHandCheckBox.setText(tr("Display hand horizontally (wastes space)"));

View file

@ -90,6 +90,8 @@ private:
QLabel maxFontSizeForCardsLabel; QLabel maxFontSizeForCardsLabel;
QCheckBox displayCardNamesCheckBox; QCheckBox displayCardNamesCheckBox;
QCheckBox cardScalingCheckBox; QCheckBox cardScalingCheckBox;
QLabel verticalCardOverlapPercentLabel;
QSpinBox verticalCardOverlapPercentBox;
QCheckBox horizontalHandCheckBox; QCheckBox horizontalHandCheckBox;
QCheckBox leftJustifiedHandCheckBox; QCheckBox leftJustifiedHandCheckBox;
QCheckBox invertVerticalCoordinateCheckBox; QCheckBox invertVerticalCoordinateCheckBox;

View file

@ -114,23 +114,18 @@ void HandZone::reorganizeCards()
} }
} else { } else {
qreal totalWidth = boundingRect().width(); qreal totalWidth = boundingRect().width();
qreal totalHeight = boundingRect().height();
qreal cardWidth = cards.at(0)->boundingRect().width(); qreal cardWidth = cards.at(0)->boundingRect().width();
qreal cardHeight = cards.at(0)->boundingRect().height();
qreal xspace = 5; qreal xspace = 5;
qreal x1 = xspace; qreal x1 = xspace;
qreal x2 = totalWidth - xspace - cardWidth; qreal x2 = totalWidth - xspace - cardWidth;
for (int i = 0; i < cardCount; i++) { for (int i = 0; i < cardCount; i++) {
CardItem *c = cards.at(i); CardItem *card = cards.at(i);
qreal x = (i % 2) ? x2 : x1; qreal x = (i % 2) ? x2 : x1;
// If the total height of the cards is smaller than the available height, qreal y =
// the cards do not need to overlap and are displayed in the center of the area. divideCardSpaceInZone(i, cardCount, boundingRect().height(), cards.at(0)->boundingRect().height());
if (cardHeight * cardCount > totalHeight) card->setPos(x, y);
c->setPos(x, ((qreal)i) * (totalHeight - cardHeight) / (cardCount - 1)); card->setRealZValue(i);
else
c->setPos(x, ((qreal)i) * cardHeight + (totalHeight - cardCount * cardHeight) / 2);
c->setRealZValue(i);
} }
} }
} }

View file

@ -2567,7 +2567,7 @@ void Player::playCard(CardItem *card, bool faceDown, bool tapped)
} else if (!faceDown && } else if (!faceDown &&
((!playToStack && tableRow == 3) || ((playToStack && tableRow != 0) && currentZone != "stack"))) { ((!playToStack && tableRow == 3) || ((playToStack && tableRow != 0) && currentZone != "stack"))) {
cmd.set_target_zone("stack"); cmd.set_target_zone("stack");
cmd.set_x(0); cmd.set_x(-1);
cmd.set_y(0); cmd.set_y(0);
} else { } else {
tableRow = faceDown ? 2 : info->getTableRow(); tableRow = faceDown ? 2 : info->getTableRow();

View file

@ -2,10 +2,36 @@
#include "carditem.h" #include "carditem.h"
#include "gamescene.h" #include "gamescene.h"
#include "settingscache.h"
#include <QDebug> #include <QDebug>
#include <QGraphicsSceneMouseEvent> #include <QGraphicsSceneMouseEvent>
qreal divideCardSpaceInZone(qreal index, int cardCount, qreal totalHeight, qreal cardHeight, bool reverse)
{
qreal cardMinOverlap = cardHeight * SettingsCache::instance().getStackCardOverlapPercent() / 100;
qreal desiredHeight = cardHeight * cardCount - cardMinOverlap * (cardCount - 1);
qreal y;
if (desiredHeight > totalHeight) {
if (reverse) {
y = index / ((totalHeight - cardHeight) / (cardCount - 1));
} else {
y = index * (totalHeight - cardHeight) / (cardCount - 1);
}
} else {
qreal start = (totalHeight - desiredHeight) / 2;
if (reverse) {
if (index <= start) {
return 0;
}
y = (index - start) / (cardHeight - cardMinOverlap);
} else {
y = index * (cardHeight - cardMinOverlap) + start;
}
}
return y;
}
SelectZone::SelectZone(Player *_player, SelectZone::SelectZone(Player *_player,
const QString &_name, const QString &_name,
bool _hasCardAttr, bool _hasCardAttr,

View file

@ -24,4 +24,6 @@ public:
bool isView = false); bool isView = false);
}; };
qreal divideCardSpaceInZone(qreal index, int cardCount, qreal totalHeight, qreal cardHeight, bool reverse = false);
#endif #endif

View file

@ -262,6 +262,7 @@ SettingsCache::SettingsCache()
ignoreUnregisteredUserMessages = settings->value("chat/ignore_unregistered_messages", false).toBool(); ignoreUnregisteredUserMessages = settings->value("chat/ignore_unregistered_messages", false).toBool();
scaleCards = settings->value("cards/scaleCards", true).toBool(); scaleCards = settings->value("cards/scaleCards", true).toBool();
verticalCardOverlapPercent = settings->value("cards/verticalCardOverlapPercent", 33).toInt();
showMessagePopups = settings->value("chat/showmessagepopups", true).toBool(); showMessagePopups = settings->value("chat/showmessagepopups", true).toBool();
showMentionPopups = settings->value("chat/showmentionpopups", true).toBool(); showMentionPopups = settings->value("chat/showmentionpopups", true).toBool();
roomHistory = settings->value("chat/roomhistory", true).toBool(); roomHistory = settings->value("chat/roomhistory", true).toBool();
@ -332,6 +333,12 @@ void SettingsCache::setCardScaling(const int _scaleCards)
settings->setValue("cards/scaleCards", scaleCards); settings->setValue("cards/scaleCards", scaleCards);
} }
void SettingsCache::setStackCardOverlapPercent(const int _verticalCardOverlapPercent)
{
verticalCardOverlapPercent = _verticalCardOverlapPercent;
settings->setValue("cards/verticalCardOverlapPercent", verticalCardOverlapPercent);
}
void SettingsCache::setShowMessagePopups(const int _showMessagePopups) void SettingsCache::setShowMessagePopups(const int _showMessagePopups)
{ {
showMessagePopups = (bool)_showMessagePopups; showMessagePopups = (bool)_showMessagePopups;

View file

@ -115,6 +115,7 @@ private:
int pixmapCacheSize; int pixmapCacheSize;
int networkCacheSize; int networkCacheSize;
bool scaleCards; bool scaleCards;
int verticalCardOverlapPercent;
bool showMessagePopups; bool showMessagePopups;
bool showMentionPopups; bool showMentionPopups;
bool roomHistory; bool roomHistory;
@ -352,6 +353,10 @@ public:
{ {
return scaleCards; return scaleCards;
} }
int getStackCardOverlapPercent() const
{
return verticalCardOverlapPercent;
}
bool getShowMessagePopup() const bool getShowMessagePopup() const
{ {
return showMessagePopups; return showMessagePopups;
@ -541,6 +546,7 @@ public slots:
void setPixmapCacheSize(const int _pixmapCacheSize); void setPixmapCacheSize(const int _pixmapCacheSize);
void setNetworkCacheSizeInMB(const int _networkCacheSize); void setNetworkCacheSizeInMB(const int _networkCacheSize);
void setCardScaling(const int _scaleCards); void setCardScaling(const int _scaleCards);
void setStackCardOverlapPercent(const int _verticalCardOverlapPercent);
void setShowMessagePopups(const int _showMessagePopups); void setShowMessagePopups(const int _showMessagePopups);
void setShowMentionPopups(const int _showMentionPopups); void setShowMentionPopups(const int _showMentionPopups);
void setRoomHistory(const int _roomHistory); void setRoomHistory(const int _roomHistory);

View file

@ -58,23 +58,32 @@ void StackZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*opti
painter->fillRect(boundingRect(), brush); painter->fillRect(boundingRect(), brush);
} }
void StackZone::handleDropEvent(const QList<CardDragItem *> &dragItems, void StackZone::handleDropEvent(const QList<CardDragItem *> &dragItems, CardZone *startZone, const QPoint &dropPoint)
CardZone *startZone,
const QPoint & /*dropPoint*/)
{ {
if (startZone == this)
return;
Command_MoveCard cmd; Command_MoveCard cmd;
cmd.set_start_player_id(startZone->getPlayer()->getId()); cmd.set_start_player_id(startZone->getPlayer()->getId());
cmd.set_start_zone(startZone->getName().toStdString()); cmd.set_start_zone(startZone->getName().toStdString());
cmd.set_target_player_id(player->getId()); cmd.set_target_player_id(player->getId());
cmd.set_target_zone(getName().toStdString()); cmd.set_target_zone(getName().toStdString());
cmd.set_x(0); int index;
if (cards.isEmpty()) {
index = 0;
} else {
const int cardCount = cards.size();
index = qRound(divideCardSpaceInZone(dropPoint.y(), cardCount, boundingRect().height(),
cards.at(0)->boundingRect().height(), true));
}
if (startZone == this) {
if (cards.at(index)->getId() == dragItems.at(0)->getId()) {
return;
}
}
cmd.set_x(index);
cmd.set_y(0); cmd.set_y(0);
for (int i = 0; i < dragItems.size(); ++i) for (CardDragItem *item : dragItems) {
cmd.mutable_cards_to_move()->add_card()->set_card_id(dragItems[i]->getId()); cmd.mutable_cards_to_move()->add_card()->set_card_id(item->getId());
}
player->sendGameCommand(cmd); player->sendGameCommand(cmd);
} }
@ -86,28 +95,23 @@ void StackZone::reorganizeCards()
const int cardCount = cards.size(); const int cardCount = cards.size();
qreal totalWidth = boundingRect().width(); qreal totalWidth = boundingRect().width();
qreal totalHeight = boundingRect().height();
qreal cardWidth = cards.at(0)->boundingRect().width(); qreal cardWidth = cards.at(0)->boundingRect().width();
qreal cardHeight = cards.at(0)->boundingRect().height();
qreal xspace = 5; qreal xspace = 5;
qreal x1 = xspace; qreal x1 = xspace;
qreal x2 = totalWidth - xspace - cardWidth; qreal x2 = totalWidth - xspace - cardWidth;
for (int i = 0; i < cardCount; i++) { for (int i = 0; i < cardCount; i++) {
CardItem *c = cards.at(i); CardItem *card = cards.at(i);
qreal x = (i % 2) ? x2 : x1; qreal x = (i % 2) ? x2 : x1;
// If the total height of the cards is smaller than the available height, qreal y =
// the cards do not need to overlap and are displayed in the center of the area. divideCardSpaceInZone(i, cardCount, boundingRect().height(), cards.at(0)->boundingRect().height());
if (cardHeight * cardCount > totalHeight) card->setPos(x, y);
c->setPos(x, ((qreal)i) * (totalHeight - cardHeight) / (cardCount - 1)); card->setRealZValue(i);
else
c->setPos(x, ((qreal)i) * cardHeight + (totalHeight - cardCount * cardHeight) / 2);
c->setRealZValue(i);
for (ArrowItem *item : c->getArrowsFrom()) { for (ArrowItem *item : card->getArrowsFrom()) {
arrowsToUpdate.insert(item); arrowsToUpdate.insert(item);
} }
for (ArrowItem *item : c->getArrowsTo()) { for (ArrowItem *item : card->getArrowsTo()) {
arrowsToUpdate.insert(item); arrowsToUpdate.insert(item);
} }
} }

View file

@ -67,6 +67,9 @@ void SettingsCache::setLeftJustified(const int /* _leftJustified */)
void SettingsCache::setCardScaling(const int /* _scaleCards */) void SettingsCache::setCardScaling(const int /* _scaleCards */)
{ {
} }
void SettingsCache::setStackCardOverlapPercent(const int /* _verticalCardOverlapPercent */)
{
}
void SettingsCache::setShowMessagePopups(const int /* _showMessagePopups */) void SettingsCache::setShowMessagePopups(const int /* _showMessagePopups */)
{ {
} }

View file

@ -71,6 +71,9 @@ void SettingsCache::setLeftJustified(const int /* _leftJustified */)
void SettingsCache::setCardScaling(const int /* _scaleCards */) void SettingsCache::setCardScaling(const int /* _scaleCards */)
{ {
} }
void SettingsCache::setStackCardOverlapPercent(const int /* _verticalCardOverlapPercent */)
{
}
void SettingsCache::setShowMessagePopups(const int /* _showMessagePopups */) void SettingsCache::setShowMessagePopups(const int /* _showMessagePopups */)
{ {
} }