mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-07-04 04:23:55 -07:00
[Game] Move graphics out of game and into game_graphics (#6928)
Some checks are pending
Build Desktop / Configure (push) Waiting to run
Build Desktop / Debian 13 (push) Blocked by required conditions
Build Desktop / Debian 12 (push) Blocked by required conditions
Build Desktop / Fedora 44 (push) Blocked by required conditions
Build Desktop / Fedora 43 (push) Blocked by required conditions
Build Desktop / Servatrice_Debian 12 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 (push) Blocked by required conditions
Build Desktop / Ubuntu 24.04 (push) Blocked by required conditions
Build Desktop / Arch (push) Blocked by required conditions
Build Desktop / macOS 14 (push) Blocked by required conditions
Build Desktop / macOS 15 (push) Blocked by required conditions
Build Desktop / macOS 13 Intel (push) Blocked by required conditions
Build Desktop / macOS 15 Debug (push) Blocked by required conditions
Build Desktop / Windows 10 (push) Blocked by required conditions
Build Docker Image / amd64 & arm64 (push) Waiting to run
Some checks are pending
Build Desktop / Configure (push) Waiting to run
Build Desktop / Debian 13 (push) Blocked by required conditions
Build Desktop / Debian 12 (push) Blocked by required conditions
Build Desktop / Fedora 44 (push) Blocked by required conditions
Build Desktop / Fedora 43 (push) Blocked by required conditions
Build Desktop / Servatrice_Debian 12 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 (push) Blocked by required conditions
Build Desktop / Ubuntu 24.04 (push) Blocked by required conditions
Build Desktop / Arch (push) Blocked by required conditions
Build Desktop / macOS 14 (push) Blocked by required conditions
Build Desktop / macOS 15 (push) Blocked by required conditions
Build Desktop / macOS 13 Intel (push) Blocked by required conditions
Build Desktop / macOS 15 Debug (push) Blocked by required conditions
Build Desktop / Windows 10 (push) Blocked by required conditions
Build Docker Image / amd64 & arm64 (push) Waiting to run
* [Game][Player] Pull out graphics_items out of player_logic Took 25 seconds Took 9 minutes * [Game] Move graphics files into game_graphics Took 1 minute Took 2 minutes Took 23 seconds Took 1 minute Took 2 seconds * Include. Took 4 minutes Took 3 minutes Took 4 minutes Took 1 minute Took 3 minutes --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
parent
cbfd286908
commit
da4ba222c0
116 changed files with 208 additions and 198 deletions
|
|
@ -3,7 +3,7 @@
|
|||
#include "../interface/widgets/tabs/tab_game.h"
|
||||
#include "player/player_logic.h"
|
||||
|
||||
AbstractGame::AbstractGame(TabGame *_tab) : QObject(_tab), tab(_tab)
|
||||
AbstractGame::AbstractGame(QObject *_parent) : QObject(_parent)
|
||||
{
|
||||
gameMetaInfo = new GameMetaInfo(this);
|
||||
gameEventHandler = new GameEventHandler(this);
|
||||
|
|
|
|||
|
|
@ -16,26 +16,19 @@
|
|||
#include <libcockatrice/protocol/pb/game_replay.pb.h>
|
||||
|
||||
class CardItem;
|
||||
class TabGame;
|
||||
class AbstractGame : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AbstractGame(TabGame *tab);
|
||||
explicit AbstractGame(QObject *parent);
|
||||
|
||||
TabGame *tab;
|
||||
GameMetaInfo *gameMetaInfo;
|
||||
GameState *gameState;
|
||||
GameEventHandler *gameEventHandler;
|
||||
PlayerManager *playerManager;
|
||||
CardItem *activeCard;
|
||||
|
||||
TabGame *getTab() const
|
||||
{
|
||||
return tab;
|
||||
}
|
||||
|
||||
GameMetaInfo *getGameMetaInfo()
|
||||
{
|
||||
return gameMetaInfo;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include "arrow_registry.h"
|
||||
|
||||
#include "board/arrow_item.h"
|
||||
#include "../game_graphics/board/arrow_item.h"
|
||||
|
||||
void ArrowRegistry::insert(QSharedPointer<ArrowData> data, ArrowItem *arrow)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,72 +0,0 @@
|
|||
#include "abstract_card_drag_item.h"
|
||||
|
||||
#include "../../client/settings/cache_settings.h"
|
||||
#include "../z_values.h"
|
||||
|
||||
#include <QCursor>
|
||||
#include <QDebug>
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QPainter>
|
||||
|
||||
const QColor GHOST_MASK = QColor(255, 255, 255, 50);
|
||||
|
||||
AbstractCardDragItem::AbstractCardDragItem(AbstractCardItem *_item,
|
||||
const QPointF &_hotSpot,
|
||||
AbstractCardDragItem *parentDrag)
|
||||
: QGraphicsItem(), item(_item), hotSpot(_hotSpot)
|
||||
{
|
||||
if (parentDrag) {
|
||||
parentDrag->addChildDrag(this);
|
||||
setZValue(ZValues::childDragZValue(hotSpot.x(), hotSpot.y()));
|
||||
connect(parentDrag, &QObject::destroyed, this, &AbstractCardDragItem::deleteLater);
|
||||
} else {
|
||||
hotSpot = QPointF{qBound(0.0, hotSpot.x(), CardDimensions::WIDTH_F - 1),
|
||||
qBound(0.0, hotSpot.y(), CardDimensions::HEIGHT_F - 1)};
|
||||
setCursor(Qt::ClosedHandCursor);
|
||||
setZValue(ZValues::DRAG_ITEM);
|
||||
}
|
||||
if (item->getTapped()) {
|
||||
setTransform(QTransform()
|
||||
.translate(CardDimensions::WIDTH_HALF_F, CardDimensions::HEIGHT_HALF_F)
|
||||
.rotate(90)
|
||||
.translate(-CardDimensions::WIDTH_HALF_F, -CardDimensions::HEIGHT_HALF_F));
|
||||
}
|
||||
|
||||
setCacheMode(DeviceCoordinateCache);
|
||||
|
||||
connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
|
||||
Q_UNUSED(_roundCardCorners);
|
||||
|
||||
prepareGeometryChange();
|
||||
update();
|
||||
});
|
||||
|
||||
connect(item, &QObject::destroyed, this, &AbstractCardDragItem::deleteLater);
|
||||
}
|
||||
|
||||
QPainterPath AbstractCardDragItem::shape() const
|
||||
{
|
||||
QPainterPath shape;
|
||||
qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CardDimensions::WIDTH_F : 0.0;
|
||||
shape.addRoundedRect(boundingRect(), cardCornerRadius, cardCornerRadius);
|
||||
return shape;
|
||||
}
|
||||
|
||||
void AbstractCardDragItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
|
||||
{
|
||||
item->paint(painter, option, widget);
|
||||
|
||||
// adds a mask to the card so it looks like the card hasnt been placed yet
|
||||
painter->fillPath(shape(), GHOST_MASK);
|
||||
}
|
||||
|
||||
void AbstractCardDragItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
event->accept();
|
||||
updatePosition(event->scenePos());
|
||||
}
|
||||
|
||||
void AbstractCardDragItem::addChildDrag(AbstractCardDragItem *child)
|
||||
{
|
||||
childDrags << child;
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
/**
|
||||
* @file abstract_card_drag_item.h
|
||||
* @ingroup GameGraphicsCards
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef ABSTRACTCARDDRAGITEM_H
|
||||
#define ABSTRACTCARDDRAGITEM_H
|
||||
|
||||
#include "abstract_card_item.h"
|
||||
|
||||
class QGraphicsScene;
|
||||
class CardZone;
|
||||
class CardInfo;
|
||||
|
||||
class AbstractCardDragItem : public QObject, public QGraphicsItem
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(QGraphicsItem)
|
||||
protected:
|
||||
AbstractCardItem *item;
|
||||
QPointF hotSpot;
|
||||
QList<AbstractCardDragItem *> childDrags;
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
Type = typeCardDrag
|
||||
};
|
||||
[[nodiscard]] int type() const override
|
||||
{
|
||||
return Type;
|
||||
}
|
||||
AbstractCardDragItem(AbstractCardItem *_item, const QPointF &_hotSpot, AbstractCardDragItem *parentDrag = 0);
|
||||
[[nodiscard]] QRectF boundingRect() const override
|
||||
{
|
||||
return QRectF(0, 0, CardDimensions::WIDTH_F, CardDimensions::HEIGHT_F);
|
||||
}
|
||||
[[nodiscard]] QPainterPath shape() const override;
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||
[[nodiscard]] AbstractCardItem *getItem() const
|
||||
{
|
||||
return item;
|
||||
}
|
||||
[[nodiscard]] QPointF getHotSpot() const
|
||||
{
|
||||
return hotSpot;
|
||||
}
|
||||
void addChildDrag(AbstractCardDragItem *child);
|
||||
virtual void updatePosition(const QPointF &cursorScenePos) = 0;
|
||||
|
||||
protected:
|
||||
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,349 +0,0 @@
|
|||
#include "abstract_card_item.h"
|
||||
|
||||
#include "../../client/settings/cache_settings.h"
|
||||
#include "../../interface/card_picture_loader/card_picture_loader.h"
|
||||
#include "../game_scene.h"
|
||||
#include "../z_values.h"
|
||||
|
||||
#include <QCursor>
|
||||
#include <QGraphicsScene>
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <algorithm>
|
||||
#include <libcockatrice/card/database/card_database.h>
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
|
||||
AbstractCardItem::AbstractCardItem(QGraphicsItem *parent, const CardRef &cardRef, PlayerLogic *_owner, int _id)
|
||||
: ArrowTarget(_owner, parent), id(_id), cardRef(cardRef), tapped(false), facedown(false), tapAngle(0),
|
||||
bgColor(Qt::transparent), isHovered(false), realZValue(0)
|
||||
{
|
||||
setCursor(Qt::OpenHandCursor);
|
||||
setFlag(ItemIsSelectable);
|
||||
setCacheMode(DeviceCoordinateCache);
|
||||
|
||||
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()
|
||||
{
|
||||
emit deleteCardInfoPopup(cardRef.name);
|
||||
}
|
||||
|
||||
QRectF AbstractCardItem::boundingRect() const
|
||||
{
|
||||
return QRectF(0, 0, CardDimensions::WIDTH_F, CardDimensions::HEIGHT_F);
|
||||
}
|
||||
|
||||
QPainterPath AbstractCardItem::shape() const
|
||||
{
|
||||
QPainterPath shape;
|
||||
qreal cardCornerRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * CardDimensions::WIDTH_F : 0.0;
|
||||
shape.addRoundedRect(boundingRect(), cardCornerRadius, cardCornerRadius);
|
||||
return shape;
|
||||
}
|
||||
|
||||
void AbstractCardItem::pixmapUpdated()
|
||||
{
|
||||
update();
|
||||
emit sigPixmapUpdated();
|
||||
}
|
||||
|
||||
void AbstractCardItem::refreshCardInfo()
|
||||
{
|
||||
exactCard = CardDatabaseManager::query()->getCard(cardRef);
|
||||
|
||||
if (!exactCard && !cardRef.name.isEmpty()) {
|
||||
CardInfo::UiAttributes attributes = {.tableRow = -1};
|
||||
auto info = CardInfo::newInstance(cardRef.name, "", true, {}, {}, {}, {}, attributes);
|
||||
exactCard = ExactCard(info);
|
||||
}
|
||||
if (exactCard) {
|
||||
connect(exactCard.getCardPtr().data(), &CardInfo::pixmapUpdated, this, &AbstractCardItem::pixmapUpdated);
|
||||
}
|
||||
|
||||
cacheBgColor();
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to get the CardInfo of the exactCard
|
||||
* @return A const reference to the CardInfo, or an empty CardInfo if card was null
|
||||
*/
|
||||
const CardInfo &AbstractCardItem::getCardInfo() const
|
||||
{
|
||||
return exactCard.getInfo();
|
||||
}
|
||||
|
||||
void AbstractCardItem::setRealZValue(qreal _zValue)
|
||||
{
|
||||
realZValue = _zValue;
|
||||
// During hover, zValue is overridden to HOVERED_CARD. Layout operations
|
||||
// like reorganizeCards() call setRealZValue() on all cards including the
|
||||
// hovered one — skip setZValue() here to avoid clobbering the override.
|
||||
if (!isHovered) {
|
||||
setZValue(_zValue);
|
||||
}
|
||||
}
|
||||
|
||||
QSizeF AbstractCardItem::getTranslatedSize(QPainter *painter) const
|
||||
{
|
||||
return QSizeF(painter->combinedTransform().map(QLineF(0, 0, boundingRect().width(), 0)).length(),
|
||||
painter->combinedTransform().map(QLineF(0, 0, 0, boundingRect().height())).length());
|
||||
}
|
||||
|
||||
void AbstractCardItem::transformPainter(QPainter *painter, const QSizeF &translatedSize, int angle)
|
||||
{
|
||||
const int MAX_FONT_SIZE = SettingsCache::instance().getMaxFontSize();
|
||||
const int fontSize = std::max(9, MAX_FONT_SIZE);
|
||||
|
||||
QRectF totalBoundingRect = painter->combinedTransform().mapRect(boundingRect());
|
||||
|
||||
int scale = resetPainterTransform(painter);
|
||||
|
||||
painter->translate(totalBoundingRect.width() / 2, totalBoundingRect.height() / 2);
|
||||
painter->rotate(angle);
|
||||
painter->translate(-translatedSize.width() / 2, -translatedSize.height() / 2);
|
||||
|
||||
QFont f;
|
||||
f.setPixelSize(fontSize * scale);
|
||||
|
||||
painter->setFont(f);
|
||||
}
|
||||
|
||||
void AbstractCardItem::paintPicture(QPainter *painter, const QSizeF &translatedSize, int angle)
|
||||
{
|
||||
qreal scaleFactor = translatedSize.width() / boundingRect().width();
|
||||
QPixmap translatedPixmap;
|
||||
bool paintImage = true;
|
||||
|
||||
if (facedown || cardRef.name.isEmpty()) {
|
||||
// never reveal card color, always paint the card back
|
||||
CardPictureLoader::getCardBackPixmap(translatedPixmap, translatedSize.toSize());
|
||||
} else {
|
||||
// don't even spend time trying to load the picture if our size is too small
|
||||
if (translatedSize.width() > 10) {
|
||||
CardPictureLoader::getPixmap(translatedPixmap, exactCard, translatedSize.toSize());
|
||||
if (translatedPixmap.isNull()) {
|
||||
paintImage = false;
|
||||
}
|
||||
} else {
|
||||
paintImage = false;
|
||||
}
|
||||
}
|
||||
|
||||
painter->save();
|
||||
|
||||
if (paintImage) {
|
||||
painter->save();
|
||||
painter->setClipPath(shape());
|
||||
painter->drawPixmap(boundingRect(), translatedPixmap, QRectF({0, 0}, translatedPixmap.size()));
|
||||
painter->restore();
|
||||
} else {
|
||||
painter->setBrush(bgColor);
|
||||
painter->drawPath(shape());
|
||||
}
|
||||
|
||||
if (translatedPixmap.isNull() || SettingsCache::instance().getDisplayCardNames() || facedown) {
|
||||
painter->save();
|
||||
transformPainter(painter, translatedSize, angle);
|
||||
painter->setPen(Qt::white);
|
||||
painter->setBackground(Qt::black);
|
||||
painter->setBackgroundMode(Qt::OpaqueMode);
|
||||
QString nameStr;
|
||||
if (facedown) {
|
||||
nameStr = "# " + QString::number(id);
|
||||
} else {
|
||||
QString prefix = "";
|
||||
if (SettingsCache::instance().debug().getShowCardId()) {
|
||||
prefix = "#" + QString::number(id) + " ";
|
||||
}
|
||||
nameStr = prefix + cardRef.name;
|
||||
}
|
||||
painter->drawText(QRectF(3 * scaleFactor, 3 * scaleFactor, translatedSize.width() - 6 * scaleFactor,
|
||||
translatedSize.height() - 6 * scaleFactor),
|
||||
Qt::AlignTop | Qt::AlignLeft | Qt::TextWrapAnywhere, nameStr);
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
void AbstractCardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
||||
{
|
||||
painter->save();
|
||||
|
||||
QSizeF translatedSize = getTranslatedSize(painter);
|
||||
paintPicture(painter, translatedSize, tapAngle);
|
||||
|
||||
painter->setRenderHint(QPainter::Antialiasing, false);
|
||||
|
||||
if (isSelected() || isHovered) {
|
||||
QPen pen;
|
||||
if (isHovered) {
|
||||
pen.setColor(Qt::yellow);
|
||||
}
|
||||
if (isSelected()) {
|
||||
pen.setColor(Qt::red);
|
||||
}
|
||||
pen.setWidth(0); // Cosmetic pen
|
||||
painter->setPen(pen);
|
||||
painter->drawPath(shape());
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
void AbstractCardItem::setCardRef(const CardRef &_cardRef)
|
||||
{
|
||||
if (cardRef == _cardRef) {
|
||||
return;
|
||||
}
|
||||
|
||||
emit deleteCardInfoPopup(cardRef.name);
|
||||
if (exactCard) {
|
||||
disconnect(exactCard.getCardPtr().data(), nullptr, this, nullptr);
|
||||
}
|
||||
cardRef = _cardRef;
|
||||
|
||||
refreshCardInfo();
|
||||
}
|
||||
|
||||
void AbstractCardItem::setHovered(bool _hovered)
|
||||
{
|
||||
if (isHovered == _hovered) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_hovered) {
|
||||
processHoverEvent();
|
||||
} else {
|
||||
// Mark the hovered card's current scene footprint dirty so overlapped
|
||||
// sibling zones (e.g. StackZone) repaint after the card moves away.
|
||||
if (scene()) {
|
||||
scene()->update(sceneBoundingRect());
|
||||
}
|
||||
}
|
||||
|
||||
isHovered = _hovered;
|
||||
setZValue(_hovered ? ZValues::HOVERED_CARD : realZValue);
|
||||
setScale(_hovered && SettingsCache::instance().getScaleCards() ? 1.1 : 1);
|
||||
setTransformOriginPoint(_hovered ? CardDimensions::WIDTH_HALF_F : 0, _hovered ? CardDimensions::HEIGHT_HALF_F : 0);
|
||||
update();
|
||||
}
|
||||
|
||||
void AbstractCardItem::setColor(const QString &_color)
|
||||
{
|
||||
color = _color;
|
||||
cacheBgColor();
|
||||
update();
|
||||
}
|
||||
|
||||
void AbstractCardItem::cacheBgColor()
|
||||
{
|
||||
QChar colorChar;
|
||||
if (color.isEmpty()) {
|
||||
colorChar = exactCard.getInfo().getColorChar();
|
||||
} else {
|
||||
colorChar = color.at(0);
|
||||
}
|
||||
|
||||
switch (colorChar.toLower().toLatin1()) {
|
||||
case 'b':
|
||||
bgColor = QColor(0, 0, 0);
|
||||
break;
|
||||
case 'u':
|
||||
bgColor = QColor(0, 140, 180);
|
||||
break;
|
||||
case 'w':
|
||||
bgColor = QColor(255, 250, 140);
|
||||
break;
|
||||
case 'r':
|
||||
bgColor = QColor(230, 0, 0);
|
||||
break;
|
||||
case 'g':
|
||||
bgColor = QColor(0, 160, 0);
|
||||
break;
|
||||
case 'm':
|
||||
bgColor = QColor(250, 190, 30);
|
||||
break;
|
||||
default:
|
||||
bgColor = QColor(230, 230, 230);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractCardItem::setTapped(bool _tapped, bool canAnimate)
|
||||
{
|
||||
if (tapped == _tapped) {
|
||||
return;
|
||||
}
|
||||
|
||||
tapped = _tapped;
|
||||
if (SettingsCache::instance().getTapAnimation() && canAnimate) {
|
||||
static_cast<GameScene *>(scene())->registerAnimationItem(this);
|
||||
} else {
|
||||
tapAngle = tapped ? 90 : 0;
|
||||
setTransform(QTransform()
|
||||
.translate(CardDimensions::WIDTH_HALF_F, CardDimensions::HEIGHT_HALF_F)
|
||||
.rotate(tapAngle)
|
||||
.translate(-CardDimensions::WIDTH_HALF_F, -CardDimensions::HEIGHT_HALF_F));
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractCardItem::setFaceDown(bool _facedown)
|
||||
{
|
||||
facedown = _facedown;
|
||||
update();
|
||||
}
|
||||
|
||||
void AbstractCardItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
if ((event->modifiers() & Qt::AltModifier) && event->button() == Qt::LeftButton) {
|
||||
emit cardShiftClicked(cardRef.name);
|
||||
} else if ((event->modifiers() & Qt::ControlModifier)) {
|
||||
setSelected(!isSelected());
|
||||
} else if (!isSelected()) {
|
||||
scene()->clearSelection();
|
||||
setSelected(true);
|
||||
}
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
setCursor(Qt::ClosedHandCursor);
|
||||
} else if (event->button() == Qt::MiddleButton) {
|
||||
emit showCardInfoPopup(event->screenPos(), cardRef);
|
||||
}
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void AbstractCardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
if (event->button() == Qt::MiddleButton) {
|
||||
emit deleteCardInfoPopup(cardRef.name);
|
||||
}
|
||||
|
||||
// This function ensures the parent function doesn't mess around with our selection.
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void AbstractCardItem::processHoverEvent()
|
||||
{
|
||||
emit hovered(this);
|
||||
}
|
||||
|
||||
QVariant AbstractCardItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
|
||||
{
|
||||
if (change == ItemSelectedHasChanged) {
|
||||
update();
|
||||
return value;
|
||||
} else {
|
||||
return ArrowTarget::itemChange(change, value);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,137 +0,0 @@
|
|||
/**
|
||||
* @file abstract_card_item.h
|
||||
* @ingroup GameGraphicsCards
|
||||
* @brief Base class for graphical card items, providing shared rendering, identity, and interaction logic.
|
||||
*/
|
||||
|
||||
#ifndef ABSTRACTCARDITEM_H
|
||||
#define ABSTRACTCARDITEM_H
|
||||
|
||||
#include "../../game_graphics/board/graphics_item_type.h"
|
||||
#include "../card_dimensions.h"
|
||||
#include "arrow_target.h"
|
||||
|
||||
#include <libcockatrice/card/printing/exact_card.h>
|
||||
#include <libcockatrice/utility/card_ref.h>
|
||||
|
||||
class PlayerLogic;
|
||||
|
||||
class AbstractCardItem : public ArrowTarget
|
||||
{
|
||||
Q_OBJECT
|
||||
protected:
|
||||
ExactCard exactCard;
|
||||
int id;
|
||||
CardRef cardRef;
|
||||
bool tapped;
|
||||
bool facedown;
|
||||
int tapAngle;
|
||||
QString color;
|
||||
QColor bgColor;
|
||||
|
||||
private:
|
||||
bool isHovered;
|
||||
qreal realZValue;
|
||||
private slots:
|
||||
void pixmapUpdated();
|
||||
|
||||
public slots:
|
||||
void refreshCardInfo();
|
||||
|
||||
signals:
|
||||
void hovered(AbstractCardItem *card);
|
||||
void showCardInfoPopup(const QPoint &pos, const CardRef &cardRef);
|
||||
void deleteCardInfoPopup(QString cardName);
|
||||
void sigPixmapUpdated();
|
||||
void cardShiftClicked(QString cardName);
|
||||
void rightClicked(AbstractCardItem *card, QPoint screenPos);
|
||||
void playSelected(AbstractCardItem *card);
|
||||
void playSelectedFaceDown(AbstractCardItem *card);
|
||||
void hideSelected(AbstractCardItem *card);
|
||||
void selectionChanged(AbstractCardItem *card, bool selected);
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
Type = typeCard
|
||||
};
|
||||
int type() const override
|
||||
{
|
||||
return Type;
|
||||
}
|
||||
explicit AbstractCardItem(QGraphicsItem *parent = nullptr,
|
||||
const CardRef &cardRef = {},
|
||||
PlayerLogic *_owner = nullptr,
|
||||
int _id = -1);
|
||||
~AbstractCardItem() override;
|
||||
QRectF boundingRect() const override;
|
||||
QPainterPath shape() const override;
|
||||
QSizeF getTranslatedSize(QPainter *painter) const;
|
||||
void paintPicture(QPainter *painter, const QSizeF &translatedSize, int angle);
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||
ExactCard getCard() const
|
||||
{
|
||||
return exactCard;
|
||||
}
|
||||
const CardInfo &getCardInfo() const;
|
||||
int getId() const
|
||||
{
|
||||
return id;
|
||||
}
|
||||
void setId(int _id)
|
||||
{
|
||||
id = _id;
|
||||
}
|
||||
QString getName() const
|
||||
{
|
||||
return cardRef.name;
|
||||
}
|
||||
QString getProviderId() const
|
||||
{
|
||||
return cardRef.providerId;
|
||||
}
|
||||
void setCardRef(const CardRef &_cardRef);
|
||||
CardRef getCardRef() const
|
||||
{
|
||||
return cardRef;
|
||||
}
|
||||
qreal getRealZValue() const
|
||||
{
|
||||
return realZValue;
|
||||
}
|
||||
void setRealZValue(qreal _zValue);
|
||||
void setHovered(bool _hovered);
|
||||
bool getIsHovered() const
|
||||
{
|
||||
return isHovered;
|
||||
}
|
||||
QString getColor() const
|
||||
{
|
||||
return color;
|
||||
}
|
||||
void setColor(const QString &_color);
|
||||
bool getTapped() const
|
||||
{
|
||||
return tapped;
|
||||
}
|
||||
void setTapped(bool _tapped, bool canAnimate = false);
|
||||
bool getFaceDown() const
|
||||
{
|
||||
return facedown;
|
||||
}
|
||||
void setFaceDown(bool _facedown);
|
||||
void processHoverEvent();
|
||||
void deleteCardInfoPopup()
|
||||
{
|
||||
emit deleteCardInfoPopup(cardRef.name);
|
||||
}
|
||||
|
||||
protected:
|
||||
void transformPainter(QPainter *painter, const QSizeF &translatedSize, int angle);
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override;
|
||||
void cacheBgColor();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,229 +0,0 @@
|
|||
#include "abstract_counter.h"
|
||||
|
||||
#include "../../client/settings/cache_settings.h"
|
||||
#include "../../interface/widgets/tabs/tab_game.h"
|
||||
#include "../player/player_actions.h"
|
||||
#include "../player/player_logic.h"
|
||||
#include "translate_counter_name.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QApplication>
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QGraphicsView>
|
||||
#include <QKeyEvent>
|
||||
#include <QMenu>
|
||||
#include <QString>
|
||||
#include <libcockatrice/protocol/pb/command_inc_counter.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_set_counter.pb.h>
|
||||
#include <libcockatrice/utility/expression.h>
|
||||
|
||||
AbstractCounter::AbstractCounter(CounterState *state,
|
||||
PlayerLogic *_player,
|
||||
bool _shownInCounterArea,
|
||||
bool _useNameForShortcut,
|
||||
QGraphicsItem *parent)
|
||||
: QGraphicsItem(parent), player(_player), id(state->getId()), name(state->getName()), value(state->getValue()),
|
||||
color(state->getColor()), radius(state->getRadius()), useNameForShortcut(_useNameForShortcut),
|
||||
shownInCounterArea(_shownInCounterArea)
|
||||
{
|
||||
setAcceptHoverEvents(true);
|
||||
|
||||
connect(state, &CounterState::valueChanged, this, [this](int, int newValue) {
|
||||
value = newValue;
|
||||
update();
|
||||
});
|
||||
|
||||
if (player->getPlayerInfo()->getLocalOrJudge()) {
|
||||
menu = new TearOffMenu(TranslateCounterName::getDisplayName(state->getName()));
|
||||
aSet = new QAction(this);
|
||||
connect(aSet, &QAction::triggered, this, &AbstractCounter::setCounter);
|
||||
menu->addAction(aSet);
|
||||
menu->addSeparator();
|
||||
for (int i = 10; i >= -10; --i) {
|
||||
if (i == 0) {
|
||||
menu->addSeparator();
|
||||
continue;
|
||||
}
|
||||
auto *a = new QAction(QString(i < 0 ? "%1" : "+%1").arg(i), this);
|
||||
if (i == -1) {
|
||||
aDec = a;
|
||||
}
|
||||
if (i == 1) {
|
||||
aInc = a;
|
||||
}
|
||||
a->setData(i);
|
||||
connect(a, &QAction::triggered, this, &AbstractCounter::incrementCounter);
|
||||
menu->addAction(a);
|
||||
}
|
||||
} else {
|
||||
menu = nullptr;
|
||||
}
|
||||
|
||||
connect(&SettingsCache::instance().shortcuts(), &ShortcutsSettings::shortCutChanged, this,
|
||||
&AbstractCounter::refreshShortcuts);
|
||||
refreshShortcuts();
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
AbstractCounter::~AbstractCounter()
|
||||
{
|
||||
delete menu;
|
||||
}
|
||||
|
||||
void AbstractCounter::delCounter()
|
||||
{
|
||||
if (dialogSemaphore) {
|
||||
deleteAfterDialog = true;
|
||||
} else {
|
||||
deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractCounter::retranslateUi()
|
||||
{
|
||||
if (aSet) {
|
||||
aSet->setText(tr("&Set counter..."));
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractCounter::setShortcutsActive()
|
||||
{
|
||||
if (!menu || !player->getPlayerInfo()->getLocal()) {
|
||||
return;
|
||||
}
|
||||
ShortcutsSettings &sc = SettingsCache::instance().shortcuts();
|
||||
shortcutActive = true;
|
||||
if (name == "life") {
|
||||
aSet->setShortcuts(sc.getShortcut("Player/aSet"));
|
||||
aDec->setShortcuts(sc.getShortcut("Player/aDec"));
|
||||
aInc->setShortcuts(sc.getShortcut("Player/aInc"));
|
||||
} else if (useNameForShortcut) {
|
||||
aSet->setShortcuts(sc.getShortcut("Player/aSetCounter_" + name));
|
||||
aDec->setShortcuts(sc.getShortcut("Player/aDecCounter_" + name));
|
||||
aInc->setShortcuts(sc.getShortcut("Player/aIncCounter_" + name));
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractCounter::setShortcutsInactive()
|
||||
{
|
||||
if (!menu) {
|
||||
return;
|
||||
}
|
||||
|
||||
shortcutActive = false;
|
||||
if (name == "life" || useNameForShortcut) {
|
||||
aSet->setShortcut(QKeySequence());
|
||||
aDec->setShortcut(QKeySequence());
|
||||
aInc->setShortcut(QKeySequence());
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractCounter::refreshShortcuts()
|
||||
{
|
||||
if (shortcutActive) {
|
||||
setShortcutsActive();
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractCounter::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
if (!isUnderMouse() || !player->getPlayerInfo()->getLocalOrJudge()) {
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event->button() == Qt::MiddleButton || QApplication::keyboardModifiers() & Qt::ShiftModifier) {
|
||||
if (menu) {
|
||||
menu->exec(event->screenPos());
|
||||
}
|
||||
} else {
|
||||
Command_IncCounter cmd;
|
||||
cmd.set_counter_id(id);
|
||||
cmd.set_delta(event->button() == Qt::LeftButton ? 1 : -1);
|
||||
player->getPlayerActions()->sendGameCommand(cmd);
|
||||
}
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void AbstractCounter::hoverEnterEvent(QGraphicsSceneHoverEvent *)
|
||||
{
|
||||
hovered = true;
|
||||
update();
|
||||
}
|
||||
void AbstractCounter::hoverLeaveEvent(QGraphicsSceneHoverEvent *)
|
||||
{
|
||||
hovered = false;
|
||||
update();
|
||||
}
|
||||
|
||||
void AbstractCounter::incrementCounter()
|
||||
{
|
||||
Command_IncCounter cmd;
|
||||
cmd.set_counter_id(id);
|
||||
cmd.set_delta(static_cast<QAction *>(sender())->data().toInt());
|
||||
player->getPlayerActions()->sendGameCommand(cmd);
|
||||
}
|
||||
|
||||
void AbstractCounter::setCounter()
|
||||
{
|
||||
QWidget *parent = nullptr;
|
||||
if (auto *view = scene() ? scene()->views().value(0) : nullptr) {
|
||||
parent = view->window();
|
||||
}
|
||||
|
||||
dialogSemaphore = true;
|
||||
AbstractCounterDialog dlg(name, QString::number(value), parent);
|
||||
const int ok = dlg.exec();
|
||||
dialogSemaphore = false;
|
||||
|
||||
if (deleteAfterDialog) {
|
||||
deleteLater();
|
||||
return;
|
||||
}
|
||||
if (!ok) {
|
||||
return;
|
||||
}
|
||||
|
||||
Expression exp(value);
|
||||
Command_SetCounter cmd;
|
||||
cmd.set_counter_id(id);
|
||||
cmd.set_value(static_cast<int>(exp.parse(dlg.textValue())));
|
||||
player->getPlayerActions()->sendGameCommand(cmd);
|
||||
}
|
||||
|
||||
AbstractCounterDialog::AbstractCounterDialog(const QString &name, const QString &value, QWidget *parent)
|
||||
: QInputDialog(parent)
|
||||
{
|
||||
setWindowTitle(tr("Set counter"));
|
||||
setLabelText(tr("New value for counter '%1':").arg(name));
|
||||
setTextValue(value);
|
||||
qApp->installEventFilter(this);
|
||||
}
|
||||
|
||||
bool AbstractCounterDialog::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
Q_UNUSED(obj);
|
||||
if (event->type() == QEvent::KeyPress) {
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
||||
switch (keyEvent->key()) {
|
||||
case Qt::Key_Up:
|
||||
changeValue(+1);
|
||||
return true;
|
||||
case Qt::Key_Down:
|
||||
changeValue(-1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AbstractCounterDialog::changeValue(int diff)
|
||||
{
|
||||
bool ok;
|
||||
int curValue = textValue().toInt(&ok);
|
||||
if (!ok) {
|
||||
return;
|
||||
}
|
||||
curValue += diff;
|
||||
setTextValue(QString::number(curValue));
|
||||
}
|
||||
|
|
@ -1,109 +0,0 @@
|
|||
/**
|
||||
* @file abstract_counter.h
|
||||
* @ingroup GameGraphicsPlayers
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef COUNTER_H
|
||||
#define COUNTER_H
|
||||
|
||||
#include "../../interface/widgets/menus/tearoff_menu.h"
|
||||
#include "../player/menu/abstract_player_component.h"
|
||||
#include "counter_state.h"
|
||||
|
||||
#include <QGraphicsItem>
|
||||
#include <QInputDialog>
|
||||
|
||||
class PlayerLogic;
|
||||
class QAction;
|
||||
class QKeyEvent;
|
||||
class QMenu;
|
||||
class QString;
|
||||
|
||||
class AbstractCounter : public QObject, public QGraphicsItem, public AbstractPlayerComponent
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(QGraphicsItem)
|
||||
|
||||
protected:
|
||||
PlayerLogic *player;
|
||||
int id;
|
||||
QString name;
|
||||
int value;
|
||||
QColor color;
|
||||
int radius;
|
||||
bool hovered = false;
|
||||
bool useNameForShortcut;
|
||||
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
|
||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override;
|
||||
|
||||
private:
|
||||
QAction *aSet = nullptr, *aDec = nullptr, *aInc = nullptr;
|
||||
TearOffMenu *menu = nullptr;
|
||||
bool dialogSemaphore = false;
|
||||
bool deleteAfterDialog = false;
|
||||
bool shownInCounterArea;
|
||||
bool shortcutActive = false;
|
||||
|
||||
private slots:
|
||||
void refreshShortcuts();
|
||||
void incrementCounter();
|
||||
void setCounter();
|
||||
|
||||
public:
|
||||
AbstractCounter(CounterState *state,
|
||||
PlayerLogic *player,
|
||||
bool shownInCounterArea,
|
||||
bool useNameForShortcut = false,
|
||||
QGraphicsItem *parent = nullptr);
|
||||
~AbstractCounter() override;
|
||||
|
||||
void retranslateUi() override;
|
||||
void setShortcutsActive() override;
|
||||
void setShortcutsInactive() override;
|
||||
void delCounter();
|
||||
|
||||
QMenu *getMenu() const
|
||||
{
|
||||
return menu;
|
||||
}
|
||||
int getId() const
|
||||
{
|
||||
return id;
|
||||
}
|
||||
QString getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
QColor getColor() const
|
||||
{
|
||||
return color;
|
||||
}
|
||||
int getRadius() const
|
||||
{
|
||||
return radius;
|
||||
}
|
||||
int getValue() const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
bool getShownInCounterArea() const
|
||||
{
|
||||
return shownInCounterArea;
|
||||
}
|
||||
};
|
||||
|
||||
class AbstractCounterDialog : public QInputDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AbstractCounterDialog(const QString &name, const QString &value, QWidget *parent = nullptr);
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
void changeValue(int diff);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,392 +0,0 @@
|
|||
#define _USE_MATH_DEFINES
|
||||
#include "arrow_item.h"
|
||||
|
||||
#include "../../client/settings/cache_settings.h"
|
||||
#include "../../game_graphics/zones/card_zone.h"
|
||||
#include "../player/player_actions.h"
|
||||
#include "../player/player_logic.h"
|
||||
#include "../player/player_target.h"
|
||||
#include "../z_values.h"
|
||||
#include "card_item.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QGraphicsScene>
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QtMath>
|
||||
#include <libcockatrice/card/card_info.h>
|
||||
#include <libcockatrice/protocol/pb/command_attach_card.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_create_arrow.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_delete_arrow.pb.h>
|
||||
#include <libcockatrice/utility/color.h>
|
||||
#include <libcockatrice/utility/zone_names.h>
|
||||
|
||||
ArrowItem::ArrowItem(QSharedPointer<const ArrowData> _data, ArrowTarget *_startItem, ArrowTarget *_targetItem)
|
||||
: data(std::move(_data)), startItem(_startItem), targetItem(_targetItem)
|
||||
{
|
||||
setZValue(ZValues::ARROWS);
|
||||
|
||||
auto doUpdate = [this]() {
|
||||
if (startItem && targetItem) {
|
||||
updatePath();
|
||||
}
|
||||
};
|
||||
|
||||
if (startItem) {
|
||||
connect(startItem, &ArrowTarget::scenePositionChanged, this, doUpdate);
|
||||
connect(startItem, &QObject::destroyed, this, &ArrowItem::onTargetDestroyed);
|
||||
}
|
||||
if (targetItem) {
|
||||
connect(targetItem, &ArrowTarget::scenePositionChanged, this, doUpdate);
|
||||
connect(targetItem, &QObject::destroyed, this, &ArrowItem::onTargetDestroyed);
|
||||
}
|
||||
|
||||
if (startItem && targetItem) {
|
||||
updatePath();
|
||||
}
|
||||
}
|
||||
|
||||
void ArrowItem::onTargetDestroyed()
|
||||
{
|
||||
emit requestDeletion(data->creatorId, data->id);
|
||||
}
|
||||
|
||||
void ArrowItem::delArrow()
|
||||
{
|
||||
if (targetItem) {
|
||||
targetItem->setBeingPointedAt(false);
|
||||
}
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
void ArrowItem::updatePath()
|
||||
{
|
||||
if (!targetItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
QPointF endPoint = targetItem->mapToScene(
|
||||
QPointF(targetItem->boundingRect().width() / 2, targetItem->boundingRect().height() / 2));
|
||||
updatePath(endPoint);
|
||||
}
|
||||
|
||||
void ArrowItem::updatePath(const QPointF &endPoint)
|
||||
{
|
||||
const double arrowWidth = 15.0;
|
||||
const double headWidth = 40.0;
|
||||
const double headLength =
|
||||
headWidth / qPow(2, 0.5); // aka headWidth / sqrt (2) but this produces a compile error with MSVC++
|
||||
const double phi = 15;
|
||||
|
||||
if (!startItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
QPointF startPoint =
|
||||
startItem->mapToScene(QPointF(startItem->boundingRect().width() / 2, startItem->boundingRect().height() / 2));
|
||||
QLineF line(startPoint, endPoint);
|
||||
qreal lineLength = line.length();
|
||||
|
||||
prepareGeometryChange();
|
||||
if (lineLength < 30) {
|
||||
path = QPainterPath();
|
||||
} else {
|
||||
QPointF c(lineLength / 2, qTan(phi * M_PI / 180) * lineLength);
|
||||
|
||||
QPainterPath centerLine;
|
||||
centerLine.moveTo(0, 0);
|
||||
centerLine.quadTo(c, QPointF(lineLength, 0));
|
||||
|
||||
double percentage = 1 - headLength / lineLength;
|
||||
QPointF arrowBodyEndPoint = centerLine.pointAtPercent(percentage);
|
||||
QLineF testLine(arrowBodyEndPoint, centerLine.pointAtPercent(percentage + 0.001));
|
||||
qreal alpha = testLine.angle() - 90;
|
||||
QPointF endPoint1 =
|
||||
arrowBodyEndPoint + arrowWidth / 2 * QPointF(qCos(alpha * M_PI / 180), -qSin(alpha * M_PI / 180));
|
||||
QPointF endPoint2 =
|
||||
arrowBodyEndPoint + arrowWidth / 2 * QPointF(-qCos(alpha * M_PI / 180), qSin(alpha * M_PI / 180));
|
||||
QPointF point1 =
|
||||
endPoint1 + (headWidth - arrowWidth) / 2 * QPointF(qCos(alpha * M_PI / 180), -qSin(alpha * M_PI / 180));
|
||||
QPointF point2 =
|
||||
endPoint2 + (headWidth - arrowWidth) / 2 * QPointF(-qCos(alpha * M_PI / 180), qSin(alpha * M_PI / 180));
|
||||
|
||||
path = QPainterPath(-arrowWidth / 2 * QPointF(qCos((phi - 90) * M_PI / 180), qSin((phi - 90) * M_PI / 180)));
|
||||
path.quadTo(c, endPoint1);
|
||||
path.lineTo(point1);
|
||||
path.lineTo(QPointF(lineLength, 0));
|
||||
path.lineTo(point2);
|
||||
path.lineTo(endPoint2);
|
||||
path.quadTo(c, arrowWidth / 2 * QPointF(qCos((phi - 90) * M_PI / 180), qSin((phi - 90) * M_PI / 180)));
|
||||
path.lineTo(-arrowWidth / 2 * QPointF(qCos((phi - 90) * M_PI / 180), qSin((phi - 90) * M_PI / 180)));
|
||||
}
|
||||
|
||||
setPos(startPoint);
|
||||
setTransform(QTransform().rotate(-line.angle()));
|
||||
}
|
||||
|
||||
void ArrowItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
||||
{
|
||||
QColor paintColor(data->color);
|
||||
if (fullColor) {
|
||||
paintColor.setAlpha(200);
|
||||
} else {
|
||||
paintColor.setAlpha(150);
|
||||
}
|
||||
painter->setBrush(paintColor);
|
||||
painter->drawPath(path);
|
||||
}
|
||||
|
||||
void ArrowItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
if (!data->isLocalCreator) {
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto *item : scene()->items(event->scenePos())) {
|
||||
if (qgraphicsitem_cast<CardItem *>(item)) {
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
event->accept();
|
||||
if (event->button() == Qt::RightButton) {
|
||||
emit requestDeletion(data->creatorId, data->id);
|
||||
}
|
||||
}
|
||||
|
||||
// ArrowDragItem
|
||||
|
||||
ArrowDragItem::ArrowDragItem(PlayerLogic *_owner, ArrowTarget *_startItem, const QColor &_color, int _deleteInPhase)
|
||||
: ArrowItem(QSharedPointer<ArrowData>::create(ArrowData{.creatorId = _owner->getPlayerInfo()->getId(),
|
||||
.isLocalCreator = true,
|
||||
.id = -1,
|
||||
.color = _color}),
|
||||
_startItem,
|
||||
nullptr),
|
||||
player(_owner), deleteInPhase(_deleteInPhase)
|
||||
{
|
||||
}
|
||||
|
||||
void ArrowDragItem::addChildArrow(ArrowDragItem *child)
|
||||
{
|
||||
childArrows.append(child);
|
||||
}
|
||||
|
||||
void ArrowDragItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
if (targetLocked || !startItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QPointF endPos = event->scenePos();
|
||||
|
||||
ArrowTarget *cursorItem = nullptr;
|
||||
qreal cursorItemZ = -1;
|
||||
for (auto *item : scene()->items(endPos)) {
|
||||
ArrowTarget *candidate = nullptr;
|
||||
if (auto *card = qgraphicsitem_cast<CardItem *>(item)) {
|
||||
candidate = card;
|
||||
} else if (auto *pt = qgraphicsitem_cast<PlayerTarget *>(item)) {
|
||||
candidate = pt;
|
||||
}
|
||||
|
||||
if (candidate && candidate->zValue() > cursorItemZ) {
|
||||
cursorItem = candidate;
|
||||
cursorItemZ = candidate->zValue();
|
||||
}
|
||||
}
|
||||
|
||||
if (cursorItem != targetItem) {
|
||||
if (targetItem) {
|
||||
disconnect(positionConnection);
|
||||
targetItem->setBeingPointedAt(false);
|
||||
}
|
||||
|
||||
targetItem = cursorItem;
|
||||
fullColor = (cursorItem != nullptr);
|
||||
|
||||
if (cursorItem && cursorItem != startItem) {
|
||||
cursorItem->setBeingPointedAt(true);
|
||||
positionConnection =
|
||||
connect(cursorItem, &ArrowTarget::scenePositionChanged, this, [this]() { updatePath(); });
|
||||
}
|
||||
}
|
||||
|
||||
targetItem ? updatePath() : updatePath(endPos);
|
||||
update();
|
||||
|
||||
for (auto *child : childArrows) {
|
||||
child->mouseMoveEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void ArrowDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
if (!startItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (targetItem && targetItem != startItem) {
|
||||
CardItem *startCard = qgraphicsitem_cast<CardItem *>(startItem);
|
||||
// For now, we can safely assume that the start item is always a card.
|
||||
// The target item can be a player as well.
|
||||
if (!startCard) {
|
||||
delArrow();
|
||||
return;
|
||||
}
|
||||
|
||||
CardZoneLogic *startZone = startCard->getZone();
|
||||
|
||||
Command_CreateArrow cmd;
|
||||
cmd.mutable_arrow_color()->CopyFrom(convertQColorToColor(data->color));
|
||||
cmd.set_start_player_id(startZone->getPlayer()->getPlayerInfo()->getId());
|
||||
cmd.set_start_zone(startZone->getName().toStdString());
|
||||
cmd.set_start_card_id(startCard->getId());
|
||||
|
||||
if (auto *targetCard = qgraphicsitem_cast<CardItem *>(targetItem)) {
|
||||
CardZoneLogic *targetZone = targetCard->getZone();
|
||||
cmd.set_target_player_id(targetZone->getPlayer()->getPlayerInfo()->getId());
|
||||
cmd.set_target_zone(targetZone->getName().toStdString());
|
||||
cmd.set_target_card_id(targetCard->getId());
|
||||
} else if (auto *targetPlayer = qgraphicsitem_cast<PlayerTarget *>(targetItem)) {
|
||||
cmd.set_target_player_id(targetPlayer->getOwner()->getPlayerInfo()->getId());
|
||||
} else {
|
||||
delArrow();
|
||||
return;
|
||||
}
|
||||
|
||||
// if the card is in hand then we will move the card to stack or table as part of drawing the arrow
|
||||
if (startZone->getName() == ZoneNames::HAND) {
|
||||
startCard->playCard(false);
|
||||
CardInfoPtr ci = startCard->getCard().getCardPtr();
|
||||
bool playToStack = SettingsCache::instance().getPlayToStack();
|
||||
if (ci && ((!playToStack && ci->getUiAttributes().tableRow == 3) ||
|
||||
(playToStack && ci->getUiAttributes().tableRow != 0 &&
|
||||
startCard->getZone()->getName() != ZoneNames::STACK))) {
|
||||
cmd.set_start_zone(ZoneNames::STACK);
|
||||
} else {
|
||||
cmd.set_start_zone(playToStack ? ZoneNames::STACK : ZoneNames::TABLE);
|
||||
}
|
||||
}
|
||||
|
||||
if (deleteInPhase != 0) {
|
||||
cmd.set_delete_in_phase(deleteInPhase);
|
||||
}
|
||||
|
||||
player->getPlayerActions()->sendGameCommand(cmd);
|
||||
}
|
||||
|
||||
delArrow();
|
||||
for (auto *child : childArrows) {
|
||||
child->mouseReleaseEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
// ArrowAttachItem
|
||||
ArrowAttachItem::ArrowAttachItem(ArrowTarget *_startItem)
|
||||
: ArrowItem(
|
||||
QSharedPointer<ArrowData>::create(ArrowData{.creatorId = _startItem->getOwner()->getPlayerInfo()->getId(),
|
||||
.isLocalCreator = true,
|
||||
.id = -1,
|
||||
.color = Qt::green}),
|
||||
_startItem,
|
||||
nullptr),
|
||||
player(_startItem->getOwner())
|
||||
{
|
||||
}
|
||||
|
||||
void ArrowAttachItem::addChildArrow(ArrowAttachItem *child)
|
||||
{
|
||||
childArrows.append(child);
|
||||
}
|
||||
|
||||
void ArrowAttachItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
if (targetLocked || !startItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QPointF endPos = event->scenePos();
|
||||
|
||||
ArrowTarget *cursorItem = nullptr;
|
||||
qreal cursorItemZ = -1;
|
||||
for (auto *item : scene()->items(endPos)) {
|
||||
if (auto *card = qgraphicsitem_cast<CardItem *>(item)) {
|
||||
if (card->zValue() > cursorItemZ) {
|
||||
cursorItem = card;
|
||||
cursorItemZ = card->zValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cursorItem != targetItem) {
|
||||
if (targetItem) {
|
||||
disconnect(positionConnection);
|
||||
targetItem->setBeingPointedAt(false);
|
||||
}
|
||||
|
||||
targetItem = cursorItem;
|
||||
fullColor = (cursorItem != nullptr);
|
||||
|
||||
if (cursorItem && cursorItem != startItem) {
|
||||
cursorItem->setBeingPointedAt(true);
|
||||
positionConnection =
|
||||
connect(cursorItem, &ArrowTarget::scenePositionChanged, this, [this]() { updatePath(); });
|
||||
}
|
||||
}
|
||||
|
||||
targetItem ? updatePath() : updatePath(endPos);
|
||||
update();
|
||||
|
||||
for (auto *child : childArrows) {
|
||||
child->mouseMoveEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void ArrowAttachItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
if (!startItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Attaching could move startItem under the current cursor position, causing all children to retarget to it right
|
||||
// before they are processed. Prevent that.
|
||||
for (auto *child : childArrows) {
|
||||
child->setTargetLocked(true);
|
||||
}
|
||||
|
||||
if (targetItem && targetItem != startItem) {
|
||||
auto *startCard = qgraphicsitem_cast<CardItem *>(startItem);
|
||||
auto *targetCard = qgraphicsitem_cast<CardItem *>(targetItem);
|
||||
if (startCard && targetCard) {
|
||||
attachCards(startCard, targetCard);
|
||||
}
|
||||
}
|
||||
|
||||
delArrow();
|
||||
for (auto *child : childArrows) {
|
||||
child->mouseReleaseEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void ArrowAttachItem::attachCards(CardItem *startCard, const CardItem *targetCard)
|
||||
{
|
||||
if (targetCard->getAttachedTo() || targetCard->getZone()->getName() != ZoneNames::TABLE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// move card onto table first if attaching from some other zone
|
||||
if (startCard->getZone()->getName() != ZoneNames::TABLE) {
|
||||
player->getPlayerActions()->playCardToTable(startCard, false);
|
||||
}
|
||||
|
||||
Command_AttachCard cmd;
|
||||
cmd.set_start_zone(ZoneNames::TABLE);
|
||||
cmd.set_card_id(startCard->getId());
|
||||
cmd.set_target_player_id(targetCard->getZone()->getPlayer()->getPlayerInfo()->getId());
|
||||
cmd.set_target_zone(targetCard->getZone()->getName().toStdString());
|
||||
cmd.set_target_card_id(targetCard->getId());
|
||||
player->getPlayerActions()->sendGameCommand(cmd);
|
||||
}
|
||||
|
|
@ -1,109 +0,0 @@
|
|||
#ifndef ARROWITEM_H
|
||||
#define ARROWITEM_H
|
||||
|
||||
#include "arrow_data.h"
|
||||
#include "arrow_target.h"
|
||||
|
||||
#include <QGraphicsItem>
|
||||
#include <QPointer>
|
||||
#include <QSharedPointer>
|
||||
|
||||
class CardItem;
|
||||
class QGraphicsSceneMouseEvent;
|
||||
class PlayerLogic;
|
||||
|
||||
class ArrowItem : public QObject, public QGraphicsItem
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(QGraphicsItem)
|
||||
signals:
|
||||
void requestDeletion(int creatorId, int id);
|
||||
|
||||
private:
|
||||
QPainterPath path;
|
||||
|
||||
protected:
|
||||
QSharedPointer<const ArrowData> data;
|
||||
QPointer<ArrowTarget> startItem;
|
||||
QPointer<ArrowTarget> targetItem;
|
||||
bool targetLocked = false;
|
||||
bool fullColor = true;
|
||||
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
|
||||
public:
|
||||
ArrowItem(QSharedPointer<const ArrowData> _data, ArrowTarget *_startItem, ArrowTarget *_targetItem);
|
||||
|
||||
void onTargetDestroyed();
|
||||
void delArrow();
|
||||
void updatePath();
|
||||
void updatePath(const QPointF &endPoint);
|
||||
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||
[[nodiscard]] QRectF boundingRect() const override
|
||||
{
|
||||
return path.boundingRect();
|
||||
}
|
||||
[[nodiscard]] QPainterPath shape() const override
|
||||
{
|
||||
return path;
|
||||
}
|
||||
[[nodiscard]] int getId() const
|
||||
{
|
||||
return data->id;
|
||||
}
|
||||
[[nodiscard]] int getCreatorId() const
|
||||
{
|
||||
return data->creatorId;
|
||||
}
|
||||
[[nodiscard]] ArrowTarget *getStartItem() const
|
||||
{
|
||||
return startItem;
|
||||
}
|
||||
[[nodiscard]] ArrowTarget *getTargetItem() const
|
||||
{
|
||||
return targetItem;
|
||||
}
|
||||
void setTargetLocked(bool _targetLocked)
|
||||
{
|
||||
targetLocked = _targetLocked;
|
||||
}
|
||||
};
|
||||
|
||||
class ArrowDragItem : public ArrowItem
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
PlayerLogic *player;
|
||||
int deleteInPhase;
|
||||
QList<ArrowDragItem *> childArrows;
|
||||
QMetaObject::Connection positionConnection;
|
||||
|
||||
public:
|
||||
ArrowDragItem(PlayerLogic *_owner, ArrowTarget *_startItem, const QColor &_color, int _deleteInPhase);
|
||||
void addChildArrow(ArrowDragItem *child);
|
||||
|
||||
protected:
|
||||
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
};
|
||||
|
||||
class ArrowAttachItem : public ArrowItem
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
PlayerLogic *player;
|
||||
QList<ArrowAttachItem *> childArrows;
|
||||
QMetaObject::Connection positionConnection;
|
||||
void attachCards(CardItem *startCard, const CardItem *targetCard);
|
||||
|
||||
public:
|
||||
explicit ArrowAttachItem(ArrowTarget *_startItem);
|
||||
void addChildArrow(ArrowAttachItem *child);
|
||||
|
||||
protected:
|
||||
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
#include "arrow_target.h"
|
||||
|
||||
#include "../player/player_logic.h"
|
||||
#include "arrow_item.h"
|
||||
|
||||
ArrowTarget::ArrowTarget(PlayerLogic *_owner, QGraphicsItem *parent) : AbstractGraphicsItem(parent), owner(_owner)
|
||||
{
|
||||
setFlag(ItemSendsScenePositionChanges);
|
||||
}
|
||||
|
||||
void ArrowTarget::setBeingPointedAt(bool _beingPointedAt)
|
||||
{
|
||||
beingPointedAt = _beingPointedAt;
|
||||
update();
|
||||
}
|
||||
|
||||
QVariant ArrowTarget::itemChange(GraphicsItemChange change, const QVariant &value)
|
||||
{
|
||||
if (change == ItemScenePositionHasChanged) {
|
||||
emit scenePositionChanged();
|
||||
}
|
||||
return AbstractGraphicsItem::itemChange(change, value);
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
/**
|
||||
* @file arrow_target.h
|
||||
* @ingroup GameGraphics
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef ARROWTARGET_H
|
||||
#define ARROWTARGET_H
|
||||
|
||||
#include "../../game_graphics/board/abstract_graphics_item.h"
|
||||
|
||||
#include <QList>
|
||||
|
||||
class PlayerLogic;
|
||||
class ArrowItem;
|
||||
|
||||
class ArrowTarget : public AbstractGraphicsItem
|
||||
{
|
||||
Q_OBJECT
|
||||
protected:
|
||||
PlayerLogic *owner;
|
||||
|
||||
private:
|
||||
bool beingPointedAt = false;
|
||||
|
||||
signals:
|
||||
void scenePositionChanged();
|
||||
|
||||
public:
|
||||
explicit ArrowTarget(PlayerLogic *_owner, QGraphicsItem *parent = nullptr);
|
||||
~ArrowTarget() override = default;
|
||||
|
||||
[[nodiscard]] PlayerLogic *getOwner() const
|
||||
{
|
||||
return owner;
|
||||
}
|
||||
|
||||
void setBeingPointedAt(bool _beingPointedAt);
|
||||
[[nodiscard]] bool getBeingPointedAt() const
|
||||
{
|
||||
return beingPointedAt;
|
||||
}
|
||||
|
||||
protected:
|
||||
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
|
||||
};
|
||||
#endif
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
#include "card_drag_item.h"
|
||||
|
||||
#include "../../game_graphics/zones/card_zone.h"
|
||||
#include "../../game_graphics/zones/table_zone.h"
|
||||
#include "../../game_graphics/zones/view_zone.h"
|
||||
#include "../game_scene.h"
|
||||
#include "card_item.h"
|
||||
|
||||
#include <QCursor>
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QPainter>
|
||||
|
||||
CardDragItem::CardDragItem(CardItem *_item,
|
||||
int _id,
|
||||
const QPointF &_hotSpot,
|
||||
bool _forceFaceDown,
|
||||
AbstractCardDragItem *parentDrag)
|
||||
: AbstractCardDragItem(_item, _hotSpot, parentDrag), id(_id), forceFaceDown(_forceFaceDown), occupied(false),
|
||||
currentZone(0)
|
||||
{
|
||||
}
|
||||
|
||||
void CardDragItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
|
||||
{
|
||||
AbstractCardDragItem::paint(painter, option, widget);
|
||||
|
||||
if (occupied) {
|
||||
painter->fillPath(shape(), QColor(200, 0, 0, 100));
|
||||
}
|
||||
}
|
||||
|
||||
void CardDragItem::updatePosition(const QPointF &cursorScenePos)
|
||||
{
|
||||
QList<QGraphicsItem *> colliding =
|
||||
scene()->items(cursorScenePos, Qt::IntersectsItemBoundingRect, Qt::DescendingOrder,
|
||||
static_cast<GameScene *>(scene())->getViewTransform());
|
||||
|
||||
CardZone *cardZone = 0;
|
||||
ZoneViewZone *zoneViewZone = 0;
|
||||
for (int i = colliding.size() - 1; i >= 0; i--) {
|
||||
CardZone *temp = qgraphicsitem_cast<CardZone *>(colliding.at(i));
|
||||
if (!cardZone) {
|
||||
cardZone = temp;
|
||||
}
|
||||
if (!zoneViewZone) {
|
||||
zoneViewZone = qobject_cast<ZoneViewZone *>(temp);
|
||||
}
|
||||
}
|
||||
CardZone *cursorZone = 0;
|
||||
if (zoneViewZone) {
|
||||
cursorZone = zoneViewZone;
|
||||
} else if (cardZone) {
|
||||
cursorZone = cardZone;
|
||||
}
|
||||
|
||||
// Always update the current zone, even if its null, to cancel the drag
|
||||
// instead of dropping cards into an non-intuitive location.
|
||||
currentZone = cursorZone;
|
||||
|
||||
if (!cursorZone) {
|
||||
// Avoid the cards getting stuck visually when not over
|
||||
// any zone.
|
||||
QPointF newPos = cursorScenePos - hotSpot;
|
||||
|
||||
if (newPos != pos()) {
|
||||
for (int i = 0; i < childDrags.size(); i++) {
|
||||
childDrags[i]->setPos(newPos + childDrags[i]->getHotSpot());
|
||||
}
|
||||
setPos(newPos);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
QPointF zonePos = currentZone->scenePos();
|
||||
QPointF cursorPosInZone = cursorScenePos - zonePos;
|
||||
|
||||
// If we are on a Table, we center the card around the cursor, because we
|
||||
// snap it into place and no longer see it being dragged.
|
||||
//
|
||||
// For other zones (where we do display the card under the cursor), we use
|
||||
// the hotspot to feel like the card was dragged at the corresponding
|
||||
// position.
|
||||
TableZone *tableZone = qobject_cast<TableZone *>(cursorZone);
|
||||
QPointF closestGridPoint;
|
||||
if (tableZone) {
|
||||
closestGridPoint = tableZone->closestGridPoint(cursorPosInZone);
|
||||
} else {
|
||||
closestGridPoint = cursorPosInZone - hotSpot;
|
||||
}
|
||||
|
||||
QPointF newPos = zonePos + closestGridPoint;
|
||||
|
||||
if (newPos != pos()) {
|
||||
for (int i = 0; i < childDrags.size(); i++) {
|
||||
childDrags[i]->setPos(newPos + childDrags[i]->getHotSpot());
|
||||
}
|
||||
setPos(newPos);
|
||||
|
||||
bool newOccupied = false;
|
||||
TableZone *table = qobject_cast<TableZone *>(cursorZone);
|
||||
if (table) {
|
||||
if (table->getCardFromCoords(closestGridPoint)) {
|
||||
newOccupied = true;
|
||||
}
|
||||
}
|
||||
if (newOccupied != occupied) {
|
||||
occupied = newOccupied;
|
||||
update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CardDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
setCursor(Qt::OpenHandCursor);
|
||||
QGraphicsScene *sc = scene();
|
||||
QPointF sp = pos();
|
||||
sc->removeItem(this);
|
||||
|
||||
QList<CardDragItem *> dragItemList;
|
||||
CardZoneLogic *startZone = static_cast<CardItem *>(item)->getZone();
|
||||
if (currentZone && !(static_cast<CardItem *>(item)->getAttachedTo() && (startZone == currentZone->getLogic()))) {
|
||||
if (!occupied) {
|
||||
dragItemList.append(this);
|
||||
}
|
||||
|
||||
for (int i = 0; i < childDrags.size(); i++) {
|
||||
CardDragItem *c = static_cast<CardDragItem *>(childDrags[i]);
|
||||
if (!occupied &&
|
||||
!(static_cast<CardItem *>(c->item)->getAttachedTo() && (startZone == currentZone->getLogic())) &&
|
||||
!c->occupied) {
|
||||
dragItemList.append(c);
|
||||
}
|
||||
sc->removeItem(c);
|
||||
}
|
||||
}
|
||||
|
||||
if (currentZone) {
|
||||
currentZone->handleDropEvent(dragItemList, startZone, (sp - currentZone->scenePos()).toPoint());
|
||||
}
|
||||
|
||||
event->accept();
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
/**
|
||||
* @file card_drag_item.h
|
||||
* @ingroup GameGraphicsCards
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef CARDDRAGITEM_H
|
||||
#define CARDDRAGITEM_H
|
||||
|
||||
#include "abstract_card_drag_item.h"
|
||||
|
||||
class CardItem;
|
||||
|
||||
class CardDragItem : public AbstractCardDragItem
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
int id;
|
||||
bool forceFaceDown;
|
||||
bool occupied;
|
||||
CardZone *currentZone;
|
||||
|
||||
public:
|
||||
CardDragItem(CardItem *_item,
|
||||
int _id,
|
||||
const QPointF &_hotSpot,
|
||||
bool _forceFaceDown,
|
||||
AbstractCardDragItem *parentDrag = 0);
|
||||
int getId() const
|
||||
{
|
||||
return id;
|
||||
}
|
||||
bool isForceFaceDown() const
|
||||
{
|
||||
return forceFaceDown;
|
||||
}
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||
void updatePosition(const QPointF &cursorScenePos) override;
|
||||
|
||||
protected:
|
||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,542 +0,0 @@
|
|||
#include "card_item.h"
|
||||
|
||||
#include "../../client/settings/cache_settings.h"
|
||||
#include "../../game_graphics/zones/table_zone.h"
|
||||
#include "../../game_graphics/zones/view_zone.h"
|
||||
#include "../../interface/widgets/tabs/tab_game.h"
|
||||
#include "../game_scene.h"
|
||||
#include "../phase.h"
|
||||
#include "../player/player_actions.h"
|
||||
#include "../player/player_logic.h"
|
||||
#include "../zones/view_zone_logic.h"
|
||||
#include "arrow_item.h"
|
||||
#include "card_drag_item.h"
|
||||
|
||||
#include <../../client/settings/card_counter_settings.h>
|
||||
#include <QApplication>
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QMenu>
|
||||
#include <QPainter>
|
||||
#include <libcockatrice/card/card_info.h>
|
||||
#include <libcockatrice/protocol/pb/serverinfo_card.pb.h>
|
||||
|
||||
CardItem::CardItem(PlayerLogic *_owner,
|
||||
QGraphicsItem *parent,
|
||||
const CardRef &cardRef,
|
||||
int _cardid,
|
||||
CardZoneLogic *_zone)
|
||||
: AbstractCardItem(parent, cardRef, _owner, _cardid), state(new CardState(this, _zone)), dragItem(nullptr)
|
||||
{
|
||||
owner->addCard(this);
|
||||
|
||||
connect(&SettingsCache::instance().cardCounters(), &CardCounterSettings::colorChanged, this, [this](int counterId) {
|
||||
if (state->getCounters().contains(counterId)) {
|
||||
update();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void CardItem::prepareDelete()
|
||||
{
|
||||
if (owner != nullptr) {
|
||||
if (owner->getGame()->getActiveCard() == this) {
|
||||
emit owner->requestCardMenuUpdate(nullptr);
|
||||
owner->getGame()->setActiveCard(nullptr);
|
||||
}
|
||||
owner = nullptr;
|
||||
}
|
||||
|
||||
while (!attachedCards.isEmpty()) {
|
||||
attachedCards.first()->setZone(nullptr); // so that it won't try to call reorganizeCards()
|
||||
attachedCards.first()->setAttachedTo(nullptr);
|
||||
}
|
||||
|
||||
if (state->getAttachedTo() != nullptr) {
|
||||
state->getAttachedTo()->removeAttachedCard(this);
|
||||
state->setAttachedTo(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void CardItem::deleteLater()
|
||||
{
|
||||
prepareDelete();
|
||||
if (scene()) {
|
||||
static_cast<GameScene *>(scene())->unregisterAnimationItem(this);
|
||||
}
|
||||
AbstractCardItem::deleteLater();
|
||||
}
|
||||
|
||||
void CardItem::setZone(CardZoneLogic *_zone)
|
||||
{
|
||||
state->setZone(_zone);
|
||||
}
|
||||
|
||||
void CardItem::retranslateUi()
|
||||
{
|
||||
}
|
||||
|
||||
void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
|
||||
{
|
||||
auto &cardCounterSettings = SettingsCache::instance().cardCounters();
|
||||
|
||||
painter->save();
|
||||
AbstractCardItem::paint(painter, option, widget);
|
||||
|
||||
int i = 0;
|
||||
QMapIterator<int, int> counterIterator(state->getCounters());
|
||||
while (counterIterator.hasNext()) {
|
||||
counterIterator.next();
|
||||
QColor _color = cardCounterSettings.color(counterIterator.key());
|
||||
|
||||
paintNumberEllipse(counterIterator.value(), 14, _color, i, state->getCounters().size(), painter);
|
||||
++i;
|
||||
}
|
||||
|
||||
QSizeF translatedSize = getTranslatedSize(painter);
|
||||
qreal scaleFactor = translatedSize.width() / boundingRect().width();
|
||||
|
||||
if (!state->getPT().isEmpty()) {
|
||||
painter->save();
|
||||
transformPainter(painter, translatedSize, tapAngle);
|
||||
|
||||
if (!getFaceDown() && state->getPT() == exactCard.getInfo().getPowTough()) {
|
||||
painter->setPen(Qt::white);
|
||||
} else {
|
||||
painter->setPen(QColor(255, 150, 0)); // dark orange
|
||||
}
|
||||
|
||||
painter->setBackground(Qt::black);
|
||||
painter->setBackgroundMode(Qt::OpaqueMode);
|
||||
|
||||
painter->drawText(QRectF(4 * scaleFactor, 4 * scaleFactor, translatedSize.width() - 10 * scaleFactor,
|
||||
translatedSize.height() - 8 * scaleFactor),
|
||||
Qt::AlignRight | Qt::AlignBottom, state->getPT());
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
if (!state->getAnnotation().isEmpty()) {
|
||||
painter->save();
|
||||
|
||||
transformPainter(painter, translatedSize, tapAngle);
|
||||
painter->setBackground(Qt::black);
|
||||
painter->setBackgroundMode(Qt::OpaqueMode);
|
||||
painter->setPen(Qt::white);
|
||||
|
||||
painter->drawText(QRectF(4 * scaleFactor, 4 * scaleFactor, translatedSize.width() - 8 * scaleFactor,
|
||||
translatedSize.height() - 8 * scaleFactor),
|
||||
Qt::AlignCenter | Qt::TextWrapAnywhere, state->getAnnotation());
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
if (getBeingPointedAt()) {
|
||||
painter->fillPath(shape(), QBrush(QColor(255, 0, 0, 100)));
|
||||
}
|
||||
|
||||
if (state->getDoesntUntap()) {
|
||||
painter->save();
|
||||
|
||||
painter->setRenderHint(QPainter::Antialiasing, false);
|
||||
|
||||
QPen pen;
|
||||
pen.setColor(Qt::magenta);
|
||||
pen.setWidth(0); // Cosmetic pen
|
||||
painter->setPen(pen);
|
||||
painter->drawPath(shape());
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
void CardItem::setAttacking(bool _attacking)
|
||||
{
|
||||
state->setAttacking(_attacking);
|
||||
update();
|
||||
}
|
||||
|
||||
void CardItem::setCounter(int _id, int _value)
|
||||
{
|
||||
state->setCounter(_id, _value);
|
||||
update();
|
||||
}
|
||||
|
||||
void CardItem::setAnnotation(const QString &_annotation)
|
||||
{
|
||||
state->setAnnotation(_annotation);
|
||||
update();
|
||||
}
|
||||
|
||||
void CardItem::setDoesntUntap(bool _doesntUntap)
|
||||
{
|
||||
state->setDoesntUntap(_doesntUntap);
|
||||
update();
|
||||
}
|
||||
|
||||
void CardItem::setPT(const QString &_pt)
|
||||
{
|
||||
state->setPT(_pt);
|
||||
update();
|
||||
}
|
||||
|
||||
void CardItem::setAttachedTo(CardItem *_attachedTo)
|
||||
{
|
||||
if (state->getAttachedTo() != nullptr) {
|
||||
state->getAttachedTo()->removeAttachedCard(this);
|
||||
}
|
||||
|
||||
gridPoint.setX(-1);
|
||||
state->setAttachedTo(_attachedTo);
|
||||
if (state->getAttachedTo() != nullptr) {
|
||||
// If the zone is being torn down, it might already be null by the time a card tries to un-attach all its
|
||||
// attached cards
|
||||
if (state->getAttachedTo()->getZone() == nullptr) {
|
||||
deleteLater();
|
||||
} else {
|
||||
emit state->getAttachedTo()->getZone()->cardAdded(this);
|
||||
state->getAttachedTo()->addAttachedCard(this);
|
||||
if (state->getZone() != state->getAttachedTo()->getZone()) {
|
||||
state->getAttachedTo()->getZone()->reorganizeCards();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If the zone is being torn down, it might already be null by the time a card tries to un-attach all its
|
||||
// attached cards
|
||||
if (state->getZone() == nullptr) {
|
||||
deleteLater();
|
||||
} else {
|
||||
emit state->getZone()->cardAdded(this);
|
||||
}
|
||||
}
|
||||
|
||||
if (state->getZone() != nullptr) {
|
||||
state->getZone()->reorganizeCards();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resets the fields that should be reset after a zone transition
|
||||
*/
|
||||
void CardItem::resetState(bool keepAnnotations)
|
||||
{
|
||||
state->resetState(keepAnnotations);
|
||||
attachedCards.clear();
|
||||
setTapped(false, false);
|
||||
setDoesntUntap(false);
|
||||
if (scene()) {
|
||||
static_cast<GameScene *>(scene())->unregisterAnimationItem(this);
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void CardItem::processCardInfo(const ServerInfo_Card &_info)
|
||||
{
|
||||
state->clearCounters();
|
||||
const int counterListSize = _info.counter_list_size();
|
||||
for (int i = 0; i < counterListSize; ++i) {
|
||||
const ServerInfo_CardCounter &counterInfo = _info.counter_list(i);
|
||||
state->insertCounter(counterInfo.id(), counterInfo.value());
|
||||
}
|
||||
|
||||
setId(_info.id());
|
||||
setCardRef({QString::fromStdString(_info.name()), QString::fromStdString(_info.provider_id())});
|
||||
setAttacking(_info.attacking());
|
||||
setFaceDown(_info.face_down());
|
||||
setPT(QString::fromStdString(_info.pt()));
|
||||
setAnnotation(QString::fromStdString(_info.annotation()));
|
||||
setColor(QString::fromStdString(_info.color()));
|
||||
setTapped(_info.tapped());
|
||||
setDestroyOnZoneChange(_info.destroy_on_zone_change());
|
||||
setDoesntUntap(_info.doesnt_untap());
|
||||
}
|
||||
|
||||
CardDragItem *CardItem::createDragItem(int _id, const QPointF &_pos, const QPointF &_scenePos, bool forceFaceDown)
|
||||
{
|
||||
deleteDragItem();
|
||||
dragItem = new CardDragItem(this, _id, _pos, forceFaceDown);
|
||||
dragItem->setVisible(false);
|
||||
scene()->addItem(dragItem);
|
||||
dragItem->updatePosition(_scenePos);
|
||||
dragItem->setVisible(true);
|
||||
|
||||
return dragItem;
|
||||
}
|
||||
|
||||
void CardItem::deleteDragItem()
|
||||
{
|
||||
if (dragItem) {
|
||||
dragItem->deleteLater();
|
||||
}
|
||||
dragItem = nullptr;
|
||||
}
|
||||
|
||||
void CardItem::drawArrow(const QColor &arrowColor)
|
||||
{
|
||||
if (owner->getGame()->getPlayerManager()->isSpectator()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto *game = owner->getGame();
|
||||
PlayerLogic *arrowOwner = game->getPlayerManager()->getActiveLocalPlayer(game->getGameState()->getActivePlayer());
|
||||
int phase = 0; // 0 means to not set the phase
|
||||
if (SettingsCache::instance().getDoNotDeleteArrowsInSubPhases()) {
|
||||
int currentPhase = game->getGameState()->getCurrentPhase();
|
||||
phase = Phases::getLastSubphase(currentPhase) + 1;
|
||||
}
|
||||
ArrowDragItem *arrow = new ArrowDragItem(arrowOwner, this, arrowColor, phase);
|
||||
scene()->addItem(arrow);
|
||||
arrow->grabMouse();
|
||||
|
||||
for (const auto &item : scene()->selectedItems()) {
|
||||
CardItem *card = qgraphicsitem_cast<CardItem *>(item);
|
||||
if (card == nullptr || card == this) {
|
||||
continue;
|
||||
}
|
||||
if (card->getZone() != state->getZone()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ArrowDragItem *childArrow = new ArrowDragItem(arrowOwner, card, arrowColor, phase);
|
||||
scene()->addItem(childArrow);
|
||||
arrow->addChildArrow(childArrow);
|
||||
}
|
||||
}
|
||||
|
||||
void CardItem::drawAttachArrow()
|
||||
{
|
||||
if (owner->getGame()->getPlayerManager()->isSpectator()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto *arrow = new ArrowAttachItem(this);
|
||||
scene()->addItem(arrow);
|
||||
arrow->grabMouse();
|
||||
|
||||
for (const auto &item : scene()->selectedItems()) {
|
||||
CardItem *card = qgraphicsitem_cast<CardItem *>(item);
|
||||
if (card == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (card->getZone() != state->getZone()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ArrowAttachItem *childArrow = new ArrowAttachItem(card);
|
||||
scene()->addItem(childArrow);
|
||||
arrow->addChildArrow(childArrow);
|
||||
}
|
||||
}
|
||||
|
||||
void CardItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
if (event->buttons().testFlag(Qt::RightButton)) {
|
||||
if ((event->screenPos() - event->buttonDownScreenPos(Qt::RightButton)).manhattanLength() <
|
||||
2 * QApplication::startDragDistance()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QColor arrowColor = Qt::red;
|
||||
if (event->modifiers().testFlag(Qt::ControlModifier)) {
|
||||
arrowColor = Qt::yellow;
|
||||
} else if (event->modifiers().testFlag(Qt::AltModifier)) {
|
||||
arrowColor = Qt::blue;
|
||||
} else if (event->modifiers().testFlag(Qt::ShiftModifier)) {
|
||||
arrowColor = Qt::green;
|
||||
}
|
||||
|
||||
drawArrow(arrowColor);
|
||||
} else if (event->buttons().testFlag(Qt::LeftButton)) {
|
||||
if ((event->screenPos() - event->buttonDownScreenPos(Qt::LeftButton)).manhattanLength() <
|
||||
2 * QApplication::startDragDistance()) {
|
||||
return;
|
||||
}
|
||||
if (const ZoneViewZoneLogic *view = qobject_cast<const ZoneViewZoneLogic *>(state->getZone())) {
|
||||
if (view->getRevealZone() && !view->getWriteableRevealZone()) {
|
||||
return;
|
||||
}
|
||||
} else if (!owner->getPlayerInfo()->getLocalOrJudge()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool forceFaceDown = event->modifiers().testFlag(Qt::ShiftModifier);
|
||||
|
||||
// Use the buttonDownPos to align the hot spot with the position when
|
||||
// the user originally clicked
|
||||
createDragItem(id, event->buttonDownPos(Qt::LeftButton), event->scenePos(), forceFaceDown);
|
||||
dragItem->grabMouse();
|
||||
|
||||
int childIndex = 0;
|
||||
for (const auto &item : scene()->selectedItems()) {
|
||||
CardItem *card = static_cast<CardItem *>(item);
|
||||
if ((card == this) || (card->getZone() != state->getZone())) {
|
||||
continue;
|
||||
}
|
||||
++childIndex;
|
||||
QPointF childPos;
|
||||
if (state->getZone()->getHasCardAttr()) {
|
||||
childPos = card->pos() - pos();
|
||||
} else {
|
||||
childPos = QPointF(childIndex * CardDimensions::WIDTH_HALF_F, 0);
|
||||
}
|
||||
CardDragItem *drag =
|
||||
new CardDragItem(card, card->getId(), childPos, card->getFaceDown() || forceFaceDown, dragItem);
|
||||
drag->setPos(dragItem->pos() + childPos);
|
||||
scene()->addItem(drag);
|
||||
}
|
||||
}
|
||||
setCursor(Qt::OpenHandCursor);
|
||||
}
|
||||
|
||||
void CardItem::playCard(bool faceDown)
|
||||
{
|
||||
// Do nothing if the card belongs to another player
|
||||
if (!owner->getPlayerInfo()->getLocalOrJudge()) {
|
||||
return;
|
||||
}
|
||||
|
||||
TableZoneLogic *tz = qobject_cast<TableZoneLogic *>(state->getZone());
|
||||
if (tz) {
|
||||
emit tz->toggleTapped();
|
||||
} else {
|
||||
if (SettingsCache::instance().getClickPlaysAllSelected()) {
|
||||
if (faceDown) {
|
||||
emit playSelectedFaceDown(this);
|
||||
} else {
|
||||
emit playSelected(this);
|
||||
}
|
||||
} else {
|
||||
state->getZone()->getPlayer()->getPlayerActions()->playCard(this, faceDown);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QVariantList CardItem::parsePT(const QString &pt)
|
||||
{
|
||||
QVariantList ptList = QVariantList();
|
||||
if (!pt.isEmpty()) {
|
||||
int sep = pt.indexOf('/');
|
||||
if (sep == 0) {
|
||||
ptList.append(QVariant(pt.mid(1))); // cut off starting '/' and take full string
|
||||
} else {
|
||||
int start = 0;
|
||||
for (;;) {
|
||||
QString item = pt.mid(start, sep - start);
|
||||
if (item.isEmpty()) {
|
||||
ptList.append(QVariant(QString()));
|
||||
} else if (item[0] == '+') {
|
||||
ptList.append(QVariant(item.mid(1).toInt())); // add as int
|
||||
} else if (item[0] == '-') {
|
||||
ptList.append(QVariant(item.toInt())); // add as int
|
||||
} else {
|
||||
ptList.append(QVariant(item)); // add as qstring
|
||||
}
|
||||
if (sep == -1) {
|
||||
break;
|
||||
}
|
||||
start = sep + 1;
|
||||
sep = pt.indexOf('/', start);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ptList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief returns true if the zone is a unwritable reveal zone view (eg a card reveal window). Will return false if zone
|
||||
* is nullptr.
|
||||
*/
|
||||
static bool isUnwritableRevealZone(CardZoneLogic *zone)
|
||||
{
|
||||
if (auto *view = qobject_cast<ZoneViewZoneLogic *>(zone)) {
|
||||
return view->getRevealZone() && !view->getWriteableRevealZone();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called when a "click to play" is done on the card.
|
||||
* This is either triggered by a single click or double click, depending on the settings.
|
||||
*
|
||||
* @param shiftHeld if the shift key was held during the click
|
||||
*/
|
||||
void CardItem::handleClickedToPlay(bool shiftHeld)
|
||||
{
|
||||
if (isUnwritableRevealZone(state->getZone())) {
|
||||
if (SettingsCache::instance().getClickPlaysAllSelected()) {
|
||||
emit hideSelected(this);
|
||||
} else {
|
||||
state->getZone()->removeCard(this);
|
||||
}
|
||||
} else {
|
||||
playCard(shiftHeld);
|
||||
}
|
||||
}
|
||||
|
||||
void CardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
if (event->button() == Qt::RightButton && owner != nullptr) {
|
||||
emit rightClicked(this, event->screenPos());
|
||||
return;
|
||||
}
|
||||
if ((event->modifiers() != Qt::AltModifier) && (event->button() == Qt::LeftButton) &&
|
||||
(!SettingsCache::instance().getDoubleClickToPlay())) {
|
||||
handleClickedToPlay(event->modifiers().testFlag(Qt::ShiftModifier));
|
||||
}
|
||||
|
||||
if (owner != nullptr) { // cards without owner will be deleted
|
||||
setCursor(Qt::OpenHandCursor);
|
||||
}
|
||||
AbstractCardItem::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
void CardItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
if ((event->modifiers() != Qt::AltModifier) && (event->buttons() == Qt::LeftButton) &&
|
||||
(SettingsCache::instance().getDoubleClickToPlay())) {
|
||||
handleClickedToPlay(event->modifiers().testFlag(Qt::ShiftModifier));
|
||||
}
|
||||
event->accept();
|
||||
}
|
||||
|
||||
bool CardItem::animationEvent()
|
||||
{
|
||||
int rotation = ROTATION_DEGREES_PER_FRAME;
|
||||
bool animationIncomplete = true;
|
||||
if (!tapped) {
|
||||
rotation *= -1;
|
||||
}
|
||||
|
||||
tapAngle += rotation;
|
||||
if (tapped && (tapAngle > 90)) {
|
||||
tapAngle = 90;
|
||||
animationIncomplete = false;
|
||||
}
|
||||
if (!tapped && (tapAngle < 0)) {
|
||||
tapAngle = 0;
|
||||
animationIncomplete = false;
|
||||
}
|
||||
|
||||
setTransform(QTransform()
|
||||
.translate(CardDimensions::WIDTH_HALF_F, CardDimensions::HEIGHT_HALF_F)
|
||||
.rotate(tapAngle)
|
||||
.translate(-CardDimensions::WIDTH_HALF_F, -CardDimensions::HEIGHT_HALF_F));
|
||||
setHovered(false);
|
||||
update();
|
||||
|
||||
return animationIncomplete;
|
||||
}
|
||||
|
||||
QVariant CardItem::itemChange(GraphicsItemChange change, const QVariant &value)
|
||||
{
|
||||
if ((change == ItemSelectedHasChanged) && owner != nullptr) {
|
||||
bool selected = value.toBool();
|
||||
|
||||
if (selected) {
|
||||
owner->getGame()->setActiveCard(this);
|
||||
}
|
||||
|
||||
emit selectionChanged(this, selected);
|
||||
}
|
||||
|
||||
return AbstractCardItem::itemChange(change, value);
|
||||
}
|
||||
|
|
@ -1,175 +0,0 @@
|
|||
/**
|
||||
* @file card_item.h
|
||||
* @ingroup GameGraphicsCards
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef CARDITEM_H
|
||||
#define CARDITEM_H
|
||||
|
||||
#include "../zones/card_zone_logic.h"
|
||||
#include "abstract_card_item.h"
|
||||
#include "card_state.h"
|
||||
|
||||
#include <libcockatrice/network/server/remote/game/server_card.h>
|
||||
#include <libcockatrice/utility/trice_limits.h>
|
||||
|
||||
class CardDatabase;
|
||||
class CardDragItem;
|
||||
class CardZone;
|
||||
class ServerInfo_Card;
|
||||
class PlayerLogic;
|
||||
class QAction;
|
||||
class QColor;
|
||||
|
||||
const int ROTATION_DEGREES_PER_FRAME = 10;
|
||||
|
||||
class CardItem : public AbstractCardItem
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
CardState *state;
|
||||
|
||||
QPoint gridPoint;
|
||||
CardDragItem *dragItem;
|
||||
QList<CardItem *> attachedCards;
|
||||
|
||||
void prepareDelete();
|
||||
void handleClickedToPlay(bool shiftHeld);
|
||||
public slots:
|
||||
void deleteLater();
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
Type = typeCard
|
||||
};
|
||||
[[nodiscard]] int type() const override
|
||||
{
|
||||
return Type;
|
||||
}
|
||||
explicit CardItem(PlayerLogic *_owner,
|
||||
QGraphicsItem *parent = nullptr,
|
||||
const CardRef &cardRef = {},
|
||||
int _cardid = -1,
|
||||
CardZoneLogic *_zone = nullptr);
|
||||
|
||||
void retranslateUi();
|
||||
[[nodiscard]] CardState *getState() const
|
||||
{
|
||||
return state;
|
||||
}
|
||||
[[nodiscard]] CardZoneLogic *getZone() const
|
||||
{
|
||||
return state->getZone();
|
||||
}
|
||||
void setZone(CardZoneLogic *_zone);
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||
[[nodiscard]] QPoint getGridPoint() const
|
||||
{
|
||||
return gridPoint;
|
||||
}
|
||||
void setGridPoint(const QPoint &_gridPoint)
|
||||
{
|
||||
gridPoint = _gridPoint;
|
||||
}
|
||||
[[nodiscard]] QPoint getGridPos() const
|
||||
{
|
||||
return gridPoint;
|
||||
}
|
||||
[[nodiscard]] PlayerLogic *getOwner() const
|
||||
{
|
||||
return owner;
|
||||
}
|
||||
void setOwner(PlayerLogic *_owner)
|
||||
{
|
||||
owner = _owner;
|
||||
}
|
||||
[[nodiscard]] bool getAttacking() const
|
||||
{
|
||||
return state->getAttacking();
|
||||
}
|
||||
void setAttacking(bool _attacking);
|
||||
[[nodiscard]] const QMap<int, int> &getCounters() const
|
||||
{
|
||||
return state->getCounters();
|
||||
}
|
||||
void setCounter(int _id, int _value);
|
||||
[[nodiscard]] QString getAnnotation() const
|
||||
{
|
||||
return state->getAnnotation();
|
||||
}
|
||||
void setAnnotation(const QString &_annotation);
|
||||
[[nodiscard]] bool getDoesntUntap() const
|
||||
{
|
||||
return state->getDoesntUntap();
|
||||
}
|
||||
void setDoesntUntap(bool _doesntUntap);
|
||||
[[nodiscard]] QString getPT() const
|
||||
{
|
||||
return state->getPT();
|
||||
}
|
||||
void setPT(const QString &_pt);
|
||||
[[nodiscard]] bool getDestroyOnZoneChange() const
|
||||
{
|
||||
return state->getDestroyOnZoneChange();
|
||||
}
|
||||
void setDestroyOnZoneChange(bool _destroy)
|
||||
{
|
||||
state->setDestroyOnZoneChange(_destroy);
|
||||
}
|
||||
[[nodiscard]] CardItem *getAttachedTo() const
|
||||
{
|
||||
return state->getAttachedTo();
|
||||
}
|
||||
void setAttachedTo(CardItem *_attachedTo);
|
||||
void addAttachedCard(CardItem *card)
|
||||
{
|
||||
attachedCards.append(card);
|
||||
}
|
||||
void removeAttachedCard(CardItem *card)
|
||||
{
|
||||
attachedCards.removeOne(card);
|
||||
}
|
||||
[[nodiscard]] const QList<CardItem *> &getAttachedCards() const
|
||||
{
|
||||
return attachedCards;
|
||||
}
|
||||
void resetState(bool keepAnnotations = false);
|
||||
void processCardInfo(const ServerInfo_Card &_info);
|
||||
|
||||
bool animationEvent();
|
||||
CardDragItem *createDragItem(int _id, const QPointF &_pos, const QPointF &_scenePos, bool forceFaceDown);
|
||||
void deleteDragItem();
|
||||
void drawArrow(const QColor &arrowColor);
|
||||
void drawAttachArrow();
|
||||
void playCard(bool faceDown);
|
||||
|
||||
/**
|
||||
* @brief Parses a string representing a p/t in order to extract the values from it.
|
||||
*
|
||||
* If the string contains '/', the string will be split at the '/' and each side will be parsed separately,
|
||||
* which means the result list will have two elements.
|
||||
*
|
||||
* If '/' is not found, then the entire string is parsed together, which means the result list will
|
||||
* have a single element.
|
||||
*
|
||||
* If either side of the split is empty, there will also only be a single element in the result list.
|
||||
*
|
||||
* This function will attempt to parse each substring as an int first, handling plus and minus prefixes.
|
||||
* If successful, it will put the parsed value into the QVariant as an int.
|
||||
* If failed, it will just put the substring into the QVariant as a QString.
|
||||
*
|
||||
* @param pt The p/t string
|
||||
* @return A QVariantList that can contain one or two elements, where each QVariant can be either int or QString
|
||||
*/
|
||||
static QVariantList parsePT(const QString &pt);
|
||||
|
||||
protected:
|
||||
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#include "card_list.h"
|
||||
|
||||
#include "card_item.h"
|
||||
#include "../../game_graphics/board/card_item.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <algorithm>
|
||||
|
|
|
|||
|
|
@ -1,39 +0,0 @@
|
|||
#include "counter_general.h"
|
||||
|
||||
#include "../../game_graphics/board/abstract_graphics_item.h"
|
||||
#include "../../interface/pixel_map_generator.h"
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
GeneralCounter::GeneralCounter(CounterState *state, PlayerLogic *player, bool useNameForShortcut, QGraphicsItem *parent)
|
||||
: AbstractCounter(state, player, true, useNameForShortcut, parent)
|
||||
{
|
||||
setCacheMode(DeviceCoordinateCache);
|
||||
}
|
||||
|
||||
QRectF GeneralCounter::boundingRect() const
|
||||
{
|
||||
return QRectF(0, 0, radius * 2, radius * 2);
|
||||
}
|
||||
|
||||
void GeneralCounter::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
||||
{
|
||||
QRectF mapRect = painter->combinedTransform().mapRect(boundingRect());
|
||||
int translatedHeight = mapRect.size().height();
|
||||
qreal scaleFactor = translatedHeight / boundingRect().height();
|
||||
QPixmap pixmap = CounterPixmapGenerator::generatePixmap(translatedHeight, name, hovered);
|
||||
|
||||
painter->save();
|
||||
resetPainterTransform(painter);
|
||||
painter->drawPixmap(QPoint(0, 0), pixmap);
|
||||
|
||||
if (value) {
|
||||
QFont f("Serif");
|
||||
f.setPixelSize(qMax((int)(radius * scaleFactor), 10));
|
||||
f.setWeight(QFont::Bold);
|
||||
painter->setPen(Qt::black);
|
||||
painter->setFont(f);
|
||||
painter->drawText(mapRect, Qt::AlignCenter, QString::number(value));
|
||||
}
|
||||
painter->restore();
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
/**
|
||||
* @file counter_general.h
|
||||
* @ingroup GameGraphicsPlayers
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef COUNTER_GENERAL_H
|
||||
#define COUNTER_GENERAL_H
|
||||
|
||||
#include "abstract_counter.h"
|
||||
|
||||
class GeneralCounter : public AbstractCounter
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GeneralCounter(CounterState *state,
|
||||
PlayerLogic *player,
|
||||
bool useNameForShortcut = false,
|
||||
QGraphicsItem *parent = nullptr);
|
||||
QRectF boundingRect() const override;
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
#include "translate_counter_name.h"
|
||||
|
||||
const QMap<QString, QString> TranslateCounterName::translated = {
|
||||
{"life", QT_TRANSLATE_NOOP("TranslateCounterName", "Life")},
|
||||
{"w", QT_TRANSLATE_NOOP("TranslateCounterName", "White")},
|
||||
{"u", QT_TRANSLATE_NOOP("TranslateCounterName", "Blue")},
|
||||
{"b", QT_TRANSLATE_NOOP("TranslateCounterName", "Black")},
|
||||
{"r", QT_TRANSLATE_NOOP("TranslateCounterName", "Red")},
|
||||
{"g", QT_TRANSLATE_NOOP("TranslateCounterName", "Green")},
|
||||
{"x", QT_TRANSLATE_NOOP("TranslateCounterName", "Colorless")},
|
||||
{"storm", QT_TRANSLATE_NOOP("TranslateCounterName", "Other")}};
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
/**
|
||||
* @file translate_counter_name.h
|
||||
* @ingroup GameGraphicsPlayers
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef TRANSLATECOUNTERNAME_H
|
||||
#define TRANSLATECOUNTERNAME_H
|
||||
|
||||
#include <QString>
|
||||
#include <QtCore>
|
||||
|
||||
class TranslateCounterName
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(TranslateCounterName)
|
||||
|
||||
static const QMap<QString, QString> translated;
|
||||
|
||||
public:
|
||||
static QString getDisplayName(const QString &name)
|
||||
{
|
||||
if (translated.contains(name)) {
|
||||
return tr(translated[name].toLatin1());
|
||||
} else {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // TRANSLATECOUNTERNAME_H
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
#ifndef CARD_DIMENSIONS_H
|
||||
#define CARD_DIMENSIONS_H
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
/**
|
||||
* @file card_dimensions.h
|
||||
* @brief Canonical card dimension constants for layout and Z-value calculations.
|
||||
*
|
||||
* These values represent the logical pixel dimensions of a standard card graphic.
|
||||
* They are used throughout the game scene for layout, rendering, and Z-value computation.
|
||||
*/
|
||||
namespace CardDimensions
|
||||
{
|
||||
/** @brief Card width in pixels. */
|
||||
constexpr int WIDTH = 72;
|
||||
/** @brief Card height in pixels. */
|
||||
constexpr int HEIGHT = 102;
|
||||
|
||||
/** @brief Pre-converted for floating-point contexts (Z-value calculations). */
|
||||
constexpr qreal WIDTH_F = static_cast<qreal>(WIDTH);
|
||||
constexpr qreal HEIGHT_F = static_cast<qreal>(HEIGHT);
|
||||
|
||||
/** @brief Half-dimensions for centering and rotation transforms. */
|
||||
constexpr qreal WIDTH_HALF_F = WIDTH_F / 2;
|
||||
constexpr qreal HEIGHT_HALF_F = HEIGHT_F / 2;
|
||||
} // namespace CardDimensions
|
||||
|
||||
#endif // CARD_DIMENSIONS_H
|
||||
|
|
@ -1,556 +0,0 @@
|
|||
#include "deck_view.h"
|
||||
|
||||
#include "../../client/settings/cache_settings.h"
|
||||
#include "../../interface/theme_manager.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QMouseEvent>
|
||||
#include <QtMath>
|
||||
#include <algorithm>
|
||||
#include <libcockatrice/card/card_info.h>
|
||||
#include <libcockatrice/deck_list/deck_list.h>
|
||||
#include <libcockatrice/deck_list/tree/deck_list_card_node.h>
|
||||
|
||||
DeckViewCardDragItem::DeckViewCardDragItem(DeckViewCard *_item,
|
||||
const QPointF &_hotSpot,
|
||||
AbstractCardDragItem *parentDrag)
|
||||
: AbstractCardDragItem(_item, _hotSpot, parentDrag), currentZone(0)
|
||||
{
|
||||
}
|
||||
|
||||
void DeckViewCardDragItem::updatePosition(const QPointF &cursorScenePos)
|
||||
{
|
||||
QList<QGraphicsItem *> colliding = scene()->items(cursorScenePos);
|
||||
|
||||
DeckViewCardContainer *cursorZone = 0;
|
||||
for (int i = colliding.size() - 1; i >= 0; i--) {
|
||||
if ((cursorZone = qgraphicsitem_cast<DeckViewCardContainer *>(colliding.at(i)))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!cursorZone) {
|
||||
return;
|
||||
}
|
||||
currentZone = cursorZone;
|
||||
|
||||
QPointF newPos = cursorScenePos;
|
||||
if (newPos != pos()) {
|
||||
for (int i = 0; i < childDrags.size(); i++) {
|
||||
childDrags[i]->setPos(newPos + childDrags[i]->getHotSpot());
|
||||
}
|
||||
setPos(newPos);
|
||||
}
|
||||
}
|
||||
|
||||
void DeckViewCardDragItem::handleDrop(DeckViewCardContainer *target)
|
||||
{
|
||||
auto *card = static_cast<DeckViewCard *>(item);
|
||||
auto *start = static_cast<DeckViewCardContainer *>(item->parentItem());
|
||||
start->removeCard(card);
|
||||
target->addCard(card);
|
||||
card->setParentItem(target);
|
||||
}
|
||||
|
||||
void DeckViewCardDragItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
setCursor(Qt::OpenHandCursor);
|
||||
auto *sc = static_cast<DeckViewScene *>(scene());
|
||||
sc->removeItem(this);
|
||||
|
||||
if (currentZone) {
|
||||
handleDrop(currentZone);
|
||||
for (int i = 0; i < childDrags.size(); i++) {
|
||||
auto *c = static_cast<DeckViewCardDragItem *>(childDrags[i]);
|
||||
c->handleDrop(currentZone);
|
||||
sc->removeItem(c);
|
||||
}
|
||||
|
||||
sc->updateContents();
|
||||
}
|
||||
|
||||
event->accept();
|
||||
}
|
||||
|
||||
DeckViewCard::DeckViewCard(QGraphicsItem *parent, const CardRef &cardRef, const QString &_originZone)
|
||||
: AbstractCardItem(parent, cardRef, 0, -1), originZone(_originZone), dragItem(0)
|
||||
{
|
||||
setAcceptHoverEvents(true);
|
||||
|
||||
connect(&SettingsCache::instance(), &SettingsCache::roundCardCornersChanged, this, [this](bool _roundCardCorners) {
|
||||
Q_UNUSED(_roundCardCorners);
|
||||
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
DeckViewCard::~DeckViewCard()
|
||||
{
|
||||
delete dragItem;
|
||||
}
|
||||
|
||||
void DeckViewCard::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
|
||||
{
|
||||
AbstractCardItem::paint(painter, option, widget);
|
||||
|
||||
painter->save();
|
||||
QPen pen;
|
||||
pen.setWidth(3);
|
||||
pen.setJoinStyle(Qt::MiterJoin);
|
||||
pen.setColor(originZone == DECK_ZONE_MAIN ? Qt::green : Qt::red);
|
||||
painter->setPen(pen);
|
||||
qreal cardRadius = SettingsCache::instance().getRoundCardCorners() ? 0.05 * (CardDimensions::WIDTH_F - 3) : 0.0;
|
||||
painter->drawRoundedRect(QRectF(1.5, 1.5, CardDimensions::WIDTH_F - 3, CardDimensions::HEIGHT_F - 3), cardRadius,
|
||||
cardRadius);
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
void DeckViewCard::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
if ((event->screenPos() - event->buttonDownScreenPos(Qt::LeftButton)).manhattanLength() <
|
||||
2 * QApplication::startDragDistance()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (static_cast<DeckViewScene *>(scene())->getLocked()) {
|
||||
return;
|
||||
}
|
||||
|
||||
delete dragItem;
|
||||
dragItem = new DeckViewCardDragItem(this, event->pos());
|
||||
scene()->addItem(dragItem);
|
||||
dragItem->updatePosition(event->scenePos());
|
||||
dragItem->grabMouse();
|
||||
|
||||
QList<QGraphicsItem *> sel = scene()->selectedItems();
|
||||
int j = 0;
|
||||
for (int i = 0; i < sel.size(); i++) {
|
||||
auto *c = static_cast<DeckViewCard *>(sel.at(i));
|
||||
if (c == this) {
|
||||
continue;
|
||||
}
|
||||
++j;
|
||||
auto childPos = QPointF(j * CardDimensions::WIDTH_HALF_F, 0);
|
||||
auto *drag = new DeckViewCardDragItem(c, childPos, dragItem);
|
||||
drag->setPos(dragItem->pos() + childPos);
|
||||
scene()->addItem(drag);
|
||||
}
|
||||
setCursor(Qt::OpenHandCursor);
|
||||
}
|
||||
|
||||
void DeckView::mouseDoubleClickEvent(QMouseEvent *event)
|
||||
{
|
||||
if (static_cast<DeckViewScene *>(scene())->getLocked()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
QList<MoveCard_ToZone> result;
|
||||
QList<QGraphicsItem *> sel = scene()->selectedItems();
|
||||
|
||||
for (int i = 0; i < sel.size(); i++) {
|
||||
auto *c = static_cast<DeckViewCard *>(sel.at(i));
|
||||
auto *zone = static_cast<DeckViewCardContainer *>(c->parentItem());
|
||||
MoveCard_ToZone m;
|
||||
m.set_card_name(c->getName().toStdString());
|
||||
m.set_start_zone(zone->getName().toStdString());
|
||||
|
||||
if (zone->getName() == DECK_ZONE_MAIN) {
|
||||
m.set_target_zone(DECK_ZONE_SIDE);
|
||||
} else if (zone->getName() == DECK_ZONE_SIDE) {
|
||||
m.set_target_zone(DECK_ZONE_MAIN);
|
||||
} else { // Trying to move from another zone
|
||||
m.set_target_zone(zone->getName().toStdString());
|
||||
}
|
||||
|
||||
result.append(m);
|
||||
}
|
||||
|
||||
deckViewScene->applySideboardPlan(result);
|
||||
deckViewScene->rearrangeItems();
|
||||
emit deckViewScene->sideboardPlanChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void DeckViewCard::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
|
||||
{
|
||||
event->accept();
|
||||
processHoverEvent();
|
||||
}
|
||||
|
||||
DeckViewCardContainer::DeckViewCardContainer(const QString &_name) : QGraphicsItem(), name(_name), width(0), height(0)
|
||||
{
|
||||
setCacheMode(DeviceCoordinateCache);
|
||||
}
|
||||
|
||||
QRectF DeckViewCardContainer::boundingRect() const
|
||||
{
|
||||
return QRectF(0, 0, width, height);
|
||||
}
|
||||
|
||||
void DeckViewCardContainer::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
||||
{
|
||||
qreal totalTextWidth = getCardTypeTextWidth();
|
||||
|
||||
painter->fillRect(boundingRect(), themeManager->getBgBrush(ThemeManager::Table));
|
||||
painter->setPen(QColor(255, 255, 255, 100));
|
||||
painter->drawLine(QPointF(0, separatorY), QPointF(width, separatorY));
|
||||
|
||||
painter->setPen(QColor(Qt::white));
|
||||
QFont f("Serif");
|
||||
f.setStyleHint(QFont::Serif);
|
||||
f.setPixelSize(24);
|
||||
f.setWeight(QFont::Bold);
|
||||
painter->setFont(f);
|
||||
painter->drawText(10, 0, width - 20, separatorY, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine,
|
||||
InnerDecklistNode::visibleNameFromName(name) + QString(": %1").arg(cards.size()));
|
||||
|
||||
f.setPixelSize(16);
|
||||
painter->setFont(f);
|
||||
QList<QString> cardTypeList = cardsByType.uniqueKeys();
|
||||
qreal yUntilNow = separatorY + paddingY;
|
||||
for (int i = 0; i < cardTypeList.size(); ++i) {
|
||||
if (i != 0) {
|
||||
painter->setPen(QColor(255, 255, 255, 100));
|
||||
painter->drawLine(QPointF(0, yUntilNow - paddingY / 2), QPointF(width, yUntilNow - paddingY / 2));
|
||||
}
|
||||
qreal thisRowHeight = CardDimensions::HEIGHT_F * currentRowsAndCols[i].first;
|
||||
QRectF textRect(0, yUntilNow, totalTextWidth, thisRowHeight);
|
||||
yUntilNow += thisRowHeight + paddingY;
|
||||
|
||||
QString displayString = QString("%1\n(%2)").arg(cardTypeList[i]).arg(cardsByType.count(cardTypeList[i]));
|
||||
|
||||
painter->setPen(Qt::white);
|
||||
painter->drawText(textRect, Qt::AlignHCenter | Qt::AlignVCenter, displayString);
|
||||
}
|
||||
}
|
||||
|
||||
void DeckViewCardContainer::addCard(DeckViewCard *card)
|
||||
{
|
||||
cards.append(card);
|
||||
cardsByType.insert(card->getCard().isEmpty() ? "" : card->getCardInfo().getMainCardType(), card);
|
||||
}
|
||||
|
||||
void DeckViewCardContainer::removeCard(DeckViewCard *card)
|
||||
{
|
||||
cards.removeOne(card);
|
||||
cardsByType.remove(card->getCard().isEmpty() ? "" : card->getCardInfo().getMainCardType(), card);
|
||||
}
|
||||
|
||||
QList<QPair<int, int>> DeckViewCardContainer::getRowsAndCols() const
|
||||
{
|
||||
QList<QPair<int, int>> result;
|
||||
QList<QString> cardTypeList = cardsByType.uniqueKeys();
|
||||
for (int i = 0; i < cardTypeList.size(); ++i) {
|
||||
result.append(QPair<int, int>(1, cardsByType.count(cardTypeList[i])));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int DeckViewCardContainer::getCardTypeTextWidth() const
|
||||
{
|
||||
QFont f("Serif");
|
||||
f.setStyleHint(QFont::Serif);
|
||||
f.setPixelSize(16);
|
||||
f.setWeight(QFont::Bold);
|
||||
QFontMetrics fm(f);
|
||||
|
||||
int maxCardTypeWidth = 0;
|
||||
for (const auto &key : cardsByType.keys()) {
|
||||
int cardTypeWidth = fm.size(Qt::TextSingleLine, key).width();
|
||||
maxCardTypeWidth = qMax(maxCardTypeWidth, cardTypeWidth);
|
||||
}
|
||||
|
||||
return maxCardTypeWidth + 15;
|
||||
}
|
||||
|
||||
QSizeF DeckViewCardContainer::calculateBoundingRect(const QList<QPair<int, int>> &rowsAndCols) const
|
||||
{
|
||||
qreal totalHeight = 0;
|
||||
qreal totalWidth = 0;
|
||||
|
||||
// Calculate space needed for cards
|
||||
for (int i = 0; i < rowsAndCols.size(); ++i) {
|
||||
totalHeight += CardDimensions::HEIGHT_F * rowsAndCols[i].first + paddingY;
|
||||
if (CardDimensions::WIDTH_F * rowsAndCols[i].second > totalWidth) {
|
||||
totalWidth = CardDimensions::WIDTH_F * rowsAndCols[i].second;
|
||||
}
|
||||
}
|
||||
|
||||
return QSizeF(getCardTypeTextWidth() + totalWidth, totalHeight + separatorY + paddingY);
|
||||
}
|
||||
|
||||
bool DeckViewCardContainer::sortCardsByName(DeckViewCard *c1, DeckViewCard *c2)
|
||||
{
|
||||
if (c1 && c2) {
|
||||
return c1->getName() < c2->getName();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeckViewCardContainer::rearrangeItems(const QList<QPair<int, int>> &rowsAndCols)
|
||||
{
|
||||
currentRowsAndCols = rowsAndCols;
|
||||
|
||||
qreal yUntilNow = separatorY + paddingY;
|
||||
qreal x = (qreal)getCardTypeTextWidth();
|
||||
for (int i = 0; i < rowsAndCols.size(); ++i) {
|
||||
const int tempRows = rowsAndCols[i].first;
|
||||
const int tempCols = rowsAndCols[i].second;
|
||||
QList<QString> cardTypeList = cardsByType.uniqueKeys();
|
||||
QList<DeckViewCard *> row = cardsByType.values(cardTypeList[i]);
|
||||
std::sort(row.begin(), row.end(), DeckViewCardContainer::sortCardsByName);
|
||||
for (int j = 0; j < row.size(); ++j) {
|
||||
DeckViewCard *card = row[j];
|
||||
card->setPos(x + (j % tempCols) * CardDimensions::WIDTH_F,
|
||||
yUntilNow + (j / tempCols) * CardDimensions::HEIGHT_F);
|
||||
}
|
||||
yUntilNow += tempRows * CardDimensions::HEIGHT_F + paddingY;
|
||||
}
|
||||
|
||||
prepareGeometryChange();
|
||||
QSizeF bRect = calculateBoundingRect(rowsAndCols);
|
||||
width = bRect.width();
|
||||
height = bRect.height();
|
||||
}
|
||||
|
||||
void DeckViewCardContainer::setWidth(qreal _width)
|
||||
{
|
||||
prepareGeometryChange();
|
||||
width = _width;
|
||||
update();
|
||||
}
|
||||
|
||||
DeckViewScene::DeckViewScene(QObject *parent) : QGraphicsScene(parent), locked(true), deck(0), optimalAspectRatio(1.0)
|
||||
{
|
||||
}
|
||||
|
||||
DeckViewScene::~DeckViewScene()
|
||||
{
|
||||
clearContents();
|
||||
delete deck;
|
||||
}
|
||||
|
||||
void DeckViewScene::clearContents()
|
||||
{
|
||||
QMapIterator<QString, DeckViewCardContainer *> i(cardContainers);
|
||||
while (i.hasNext()) {
|
||||
delete i.next().value();
|
||||
}
|
||||
cardContainers.clear();
|
||||
}
|
||||
|
||||
void DeckViewScene::setDeck(const DeckList &_deck)
|
||||
{
|
||||
if (deck) {
|
||||
delete deck;
|
||||
}
|
||||
|
||||
deck = new DeckList(_deck.writeToString_Native());
|
||||
rebuildTree();
|
||||
applySideboardPlan(deck->getCurrentSideboardPlan());
|
||||
rearrangeItems();
|
||||
}
|
||||
|
||||
void DeckViewScene::rebuildTree()
|
||||
{
|
||||
clearContents();
|
||||
|
||||
if (!deck) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto *currentZone : deck->getZoneNodes()) {
|
||||
DeckViewCardContainer *container = cardContainers.value(currentZone->getName(), 0);
|
||||
if (!container) {
|
||||
container = new DeckViewCardContainer(currentZone->getName());
|
||||
cardContainers.insert(currentZone->getName(), container);
|
||||
addItem(container);
|
||||
}
|
||||
|
||||
for (int j = 0; j < currentZone->size(); j++) {
|
||||
auto *currentCard = dynamic_cast<DecklistCardNode *>(currentZone->at(j));
|
||||
if (!currentCard) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
||||
auto *newCard = new DeckViewCard(container, currentCard->toCardRef(), currentZone->getName());
|
||||
container->addCard(newCard);
|
||||
emit newCardAdded(newCard);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DeckViewScene::applySideboardPlan(const QList<MoveCard_ToZone> &plan)
|
||||
{
|
||||
for (int i = 0; i < plan.size(); ++i) {
|
||||
const MoveCard_ToZone &m = plan[i];
|
||||
DeckViewCardContainer *start = cardContainers.value(QString::fromStdString(m.start_zone()));
|
||||
DeckViewCardContainer *target = cardContainers.value(QString::fromStdString(m.target_zone()));
|
||||
if (!start || !target) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DeckViewCard *card = 0;
|
||||
const QList<DeckViewCard *> &cardList = start->getCards();
|
||||
for (int j = 0; j < cardList.size(); ++j) {
|
||||
if (cardList[j]->getName() == QString::fromStdString(m.card_name())) {
|
||||
card = cardList[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!card) {
|
||||
continue;
|
||||
}
|
||||
|
||||
start->removeCard(card);
|
||||
target->addCard(card);
|
||||
card->setParentItem(target);
|
||||
}
|
||||
}
|
||||
|
||||
void DeckViewScene::rearrangeItems()
|
||||
{
|
||||
const int spacing = CardDimensions::HEIGHT / 3;
|
||||
QList<DeckViewCardContainer *> contList = cardContainers.values();
|
||||
|
||||
// Initialize space requirements
|
||||
QList<QList<QPair<int, int>>> rowsAndColsList;
|
||||
QList<QList<int>> cardCountList;
|
||||
for (int i = 0; i < contList.size(); ++i) {
|
||||
QList<QPair<int, int>> rowsAndCols = contList[i]->getRowsAndCols();
|
||||
rowsAndColsList.append(rowsAndCols);
|
||||
|
||||
cardCountList.append(QList<int>());
|
||||
for (int j = 0; j < rowsAndCols.size(); ++j) {
|
||||
cardCountList[i].append(rowsAndCols[j].second);
|
||||
}
|
||||
}
|
||||
|
||||
qreal totalHeight, totalWidth;
|
||||
for (;;) {
|
||||
// Calculate total size before this iteration
|
||||
totalHeight = -spacing;
|
||||
totalWidth = 0;
|
||||
for (int i = 0; i < contList.size(); ++i) {
|
||||
QSizeF contSize = contList[i]->calculateBoundingRect(rowsAndColsList[i]);
|
||||
totalHeight += contSize.height() + spacing;
|
||||
if (contSize.width() > totalWidth) {
|
||||
totalWidth = contSize.width();
|
||||
}
|
||||
}
|
||||
|
||||
// We're done when the aspect ratio shifts from too high to too low.
|
||||
if (totalWidth / totalHeight <= optimalAspectRatio) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Find category with highest column count
|
||||
int maxIndex1 = -1, maxIndex2 = -1, maxCols = 0;
|
||||
for (int i = 0; i < rowsAndColsList.size(); ++i) {
|
||||
for (int j = 0; j < rowsAndColsList[i].size(); ++j) {
|
||||
if (rowsAndColsList[i][j].second > maxCols) {
|
||||
maxIndex1 = i;
|
||||
maxIndex2 = j;
|
||||
maxCols = rowsAndColsList[i][j].second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add row to category
|
||||
const int maxRows = rowsAndColsList[maxIndex1][maxIndex2].first;
|
||||
const int maxCardCount = cardCountList[maxIndex1][maxIndex2];
|
||||
rowsAndColsList[maxIndex1][maxIndex2] =
|
||||
QPair<int, int>(maxRows + 1, (int)qCeil((qreal)maxCardCount / (qreal)(maxRows + 1)));
|
||||
}
|
||||
|
||||
totalHeight = -spacing;
|
||||
for (int i = 0; i < contList.size(); ++i) {
|
||||
DeckViewCardContainer *c = contList[i];
|
||||
c->rearrangeItems(rowsAndColsList[i]);
|
||||
c->setPos(0, totalHeight + spacing);
|
||||
totalHeight += c->boundingRect().height() + spacing;
|
||||
}
|
||||
|
||||
totalWidth = totalHeight * optimalAspectRatio;
|
||||
for (int i = 0; i < contList.size(); ++i) {
|
||||
contList[i]->setWidth(totalWidth);
|
||||
}
|
||||
|
||||
setSceneRect(QRectF(0, 0, totalWidth, totalHeight));
|
||||
}
|
||||
|
||||
void DeckViewScene::updateContents()
|
||||
{
|
||||
rearrangeItems();
|
||||
emit sideboardPlanChanged();
|
||||
}
|
||||
|
||||
QList<MoveCard_ToZone> DeckViewScene::getSideboardPlan() const
|
||||
{
|
||||
QList<MoveCard_ToZone> result;
|
||||
QMapIterator<QString, DeckViewCardContainer *> containerIterator(cardContainers);
|
||||
while (containerIterator.hasNext()) {
|
||||
DeckViewCardContainer *cont = containerIterator.next().value();
|
||||
const QList<DeckViewCard *> cardList = cont->getCards();
|
||||
for (int i = 0; i < cardList.size(); ++i) {
|
||||
if (cardList[i]->getOriginZone() != cont->getName()) {
|
||||
MoveCard_ToZone m;
|
||||
m.set_card_name(cardList[i]->getName().toStdString());
|
||||
m.set_start_zone(cardList[i]->getOriginZone().toStdString());
|
||||
m.set_target_zone(cont->getName().toStdString());
|
||||
result.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void DeckViewScene::resetSideboardPlan()
|
||||
{
|
||||
rebuildTree();
|
||||
rearrangeItems();
|
||||
}
|
||||
|
||||
DeckView::DeckView(QWidget *parent) : QGraphicsView(parent)
|
||||
{
|
||||
deckViewScene = new DeckViewScene(this);
|
||||
|
||||
setBackgroundBrush(QBrush(QColor(0, 0, 0)));
|
||||
setDragMode(RubberBandDrag);
|
||||
setRenderHints(QPainter::TextAntialiasing | QPainter::Antialiasing /* | QPainter::SmoothPixmapTransform*/);
|
||||
setScene(deckViewScene);
|
||||
|
||||
connect(deckViewScene, &DeckViewScene::sceneRectChanged, this, &DeckView::updateSceneRect);
|
||||
connect(deckViewScene, &DeckViewScene::newCardAdded, this, &DeckView::newCardAdded);
|
||||
connect(deckViewScene, &DeckViewScene::sideboardPlanChanged, this, &DeckView::sideboardPlanChanged);
|
||||
}
|
||||
|
||||
void DeckView::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QGraphicsView::resizeEvent(event);
|
||||
deckViewScene->setOptimalAspectRatio((qreal)width() / (qreal)height());
|
||||
deckViewScene->rearrangeItems();
|
||||
}
|
||||
|
||||
void DeckView::updateSceneRect(const QRectF &rect)
|
||||
{
|
||||
fitInView(rect, Qt::KeepAspectRatio);
|
||||
}
|
||||
|
||||
void DeckView::setDeck(const DeckList &_deck)
|
||||
{
|
||||
deckViewScene->setDeck(_deck);
|
||||
}
|
||||
|
||||
void DeckView::clearDeck()
|
||||
{
|
||||
deckViewScene->clearContents();
|
||||
}
|
||||
|
||||
void DeckView::resetSideboardPlan()
|
||||
{
|
||||
deckViewScene->resetSideboardPlan();
|
||||
}
|
||||
|
|
@ -1,170 +0,0 @@
|
|||
/**
|
||||
* @file deck_view.h
|
||||
* @ingroup Lobby
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef DECKVIEW_H
|
||||
#define DECKVIEW_H
|
||||
|
||||
#include "../board/abstract_card_drag_item.h"
|
||||
|
||||
#include <QGraphicsView>
|
||||
#include <QMap>
|
||||
#include <libcockatrice/protocol/pb/move_card_to_zone.pb.h>
|
||||
|
||||
class DeckList;
|
||||
class InnerDecklistNode;
|
||||
class CardInfo;
|
||||
class DeckViewCardContainer;
|
||||
class DeckViewCardDragItem;
|
||||
class MoveCardToZone;
|
||||
|
||||
class DeckViewCard : public AbstractCardItem
|
||||
{
|
||||
private:
|
||||
QString originZone;
|
||||
DeckViewCardDragItem *dragItem;
|
||||
|
||||
public:
|
||||
explicit DeckViewCard(QGraphicsItem *parent = nullptr,
|
||||
const CardRef &cardRef = {},
|
||||
const QString &_originZone = QString());
|
||||
~DeckViewCard() override;
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||
[[nodiscard]] const QString &getOriginZone() const
|
||||
{
|
||||
return originZone;
|
||||
}
|
||||
|
||||
protected:
|
||||
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
|
||||
};
|
||||
|
||||
class DeckViewCardDragItem : public AbstractCardDragItem
|
||||
{
|
||||
private:
|
||||
DeckViewCardContainer *currentZone;
|
||||
void handleDrop(DeckViewCardContainer *target);
|
||||
|
||||
public:
|
||||
DeckViewCardDragItem(DeckViewCard *_item, const QPointF &_hotSpot, AbstractCardDragItem *parentDrag = 0);
|
||||
void updatePosition(const QPointF &cursorScenePos) override;
|
||||
|
||||
protected:
|
||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
};
|
||||
|
||||
class DeckViewCardContainer : public QGraphicsItem
|
||||
{
|
||||
private:
|
||||
static const int separatorY = 20;
|
||||
static const int paddingY = 10;
|
||||
static bool sortCardsByName(DeckViewCard *c1, DeckViewCard *c2);
|
||||
|
||||
QString name;
|
||||
QList<DeckViewCard *> cards;
|
||||
QMultiMap<QString, DeckViewCard *> cardsByType;
|
||||
QList<QPair<int, int>> currentRowsAndCols;
|
||||
qreal width, height;
|
||||
[[nodiscard]] int getCardTypeTextWidth() const;
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
Type = typeDeckViewCardContainer
|
||||
};
|
||||
[[nodiscard]] int type() const override
|
||||
{
|
||||
return Type;
|
||||
}
|
||||
explicit DeckViewCardContainer(const QString &_name);
|
||||
[[nodiscard]] QRectF boundingRect() const override;
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||
void addCard(DeckViewCard *card);
|
||||
void removeCard(DeckViewCard *card);
|
||||
[[nodiscard]] const QList<DeckViewCard *> &getCards() const
|
||||
{
|
||||
return cards;
|
||||
}
|
||||
[[nodiscard]] const QString &getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
void setWidth(qreal _width);
|
||||
|
||||
[[nodiscard]] QList<QPair<int, int>> getRowsAndCols() const;
|
||||
[[nodiscard]] QSizeF calculateBoundingRect(const QList<QPair<int, int>> &rowsAndCols) const;
|
||||
void rearrangeItems(const QList<QPair<int, int>> &rowsAndCols);
|
||||
};
|
||||
|
||||
class DeckViewScene : public QGraphicsScene
|
||||
{
|
||||
Q_OBJECT
|
||||
signals:
|
||||
void newCardAdded(AbstractCardItem *card);
|
||||
void sideboardPlanChanged();
|
||||
|
||||
private:
|
||||
bool locked;
|
||||
DeckList *deck;
|
||||
QMap<QString, DeckViewCardContainer *> cardContainers;
|
||||
qreal optimalAspectRatio;
|
||||
void rebuildTree();
|
||||
|
||||
public:
|
||||
explicit DeckViewScene(QObject *parent = nullptr);
|
||||
~DeckViewScene() override;
|
||||
void setLocked(bool _locked)
|
||||
{
|
||||
locked = _locked;
|
||||
}
|
||||
[[nodiscard]] bool getLocked() const
|
||||
{
|
||||
return locked;
|
||||
}
|
||||
void clearContents();
|
||||
void setDeck(const DeckList &_deck);
|
||||
void setOptimalAspectRatio(qreal _optimalAspectRatio)
|
||||
{
|
||||
optimalAspectRatio = _optimalAspectRatio;
|
||||
}
|
||||
void rearrangeItems();
|
||||
void updateContents();
|
||||
[[nodiscard]] QList<MoveCard_ToZone> getSideboardPlan() const;
|
||||
void resetSideboardPlan();
|
||||
void applySideboardPlan(const QList<MoveCard_ToZone> &plan);
|
||||
};
|
||||
|
||||
class DeckView : public QGraphicsView
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
DeckViewScene *deckViewScene;
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
public slots:
|
||||
void updateSceneRect(const QRectF &rect);
|
||||
signals:
|
||||
void newCardAdded(AbstractCardItem *card);
|
||||
void sideboardPlanChanged();
|
||||
|
||||
public:
|
||||
explicit DeckView(QWidget *parent = nullptr);
|
||||
void setDeck(const DeckList &_deck);
|
||||
void clearDeck();
|
||||
void setLocked(bool _locked)
|
||||
{
|
||||
deckViewScene->setLocked(_locked);
|
||||
}
|
||||
[[nodiscard]] QList<MoveCard_ToZone> getSideboardPlan() const
|
||||
{
|
||||
return deckViewScene->getSideboardPlan();
|
||||
}
|
||||
void mouseDoubleClickEvent(QMouseEvent *event) override;
|
||||
void resetSideboardPlan();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,418 +0,0 @@
|
|||
#include "deck_view_container.h"
|
||||
|
||||
#include "../../client/settings/cache_settings.h"
|
||||
#include "../../interface/card_picture_loader/card_picture_loader.h"
|
||||
#include "../../interface/deck_loader/deck_loader.h"
|
||||
#include "../../interface/widgets/dialogs/dlg_load_deck.h"
|
||||
#include "../../interface/widgets/dialogs/dlg_load_deck_from_clipboard.h"
|
||||
#include "../../interface/widgets/dialogs/dlg_load_deck_from_website.h"
|
||||
#include "../../interface/widgets/dialogs/dlg_load_remote_deck.h"
|
||||
#include "../../interface/widgets/tabs/tab_game.h"
|
||||
#include "deck_view.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <libcockatrice/card/database/card_database.h>
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
#include <libcockatrice/protocol/pb/command_deck_select.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_ready_start.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_set_sideboard_lock.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_set_sideboard_plan.pb.h>
|
||||
#include <libcockatrice/protocol/pb/response_deck_download.pb.h>
|
||||
#include <libcockatrice/protocol/pending_command.h>
|
||||
#include <libcockatrice/utility/trice_limits.h>
|
||||
|
||||
ToggleButton::ToggleButton(QWidget *parent) : QPushButton(parent), state(false)
|
||||
{
|
||||
}
|
||||
|
||||
void ToggleButton::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
QPushButton::paintEvent(event);
|
||||
|
||||
QPainter painter(this);
|
||||
QPen pen;
|
||||
pen.setWidth(3);
|
||||
pen.setJoinStyle(Qt::MiterJoin);
|
||||
pen.setColor(state ? Qt::green : Qt::red);
|
||||
painter.setPen(pen);
|
||||
painter.drawRect(QRect(1, 1, width() - 3, height() - 3));
|
||||
}
|
||||
|
||||
void ToggleButton::setState(bool _state)
|
||||
{
|
||||
state = _state;
|
||||
emit stateChanged();
|
||||
update();
|
||||
}
|
||||
|
||||
DeckViewContainer::DeckViewContainer(int _playerId, TabGame *parent)
|
||||
: QWidget(nullptr), visualDeckStorageWidget(nullptr), parentGame(parent), playerId(_playerId)
|
||||
{
|
||||
loadLocalButton = new QPushButton;
|
||||
loadRemoteButton = new QPushButton;
|
||||
loadFromClipboardButton = new QPushButton;
|
||||
loadFromWebsiteButton = new QPushButton;
|
||||
unloadDeckButton = new QPushButton;
|
||||
readyStartButton = new ToggleButton;
|
||||
forceStartGameButton = new QPushButton;
|
||||
sideboardLockButton = new ToggleButton;
|
||||
|
||||
connect(loadLocalButton, &QPushButton::clicked, this, &DeckViewContainer::loadLocalDeck);
|
||||
connect(loadRemoteButton, &QPushButton::clicked, this, &DeckViewContainer::loadRemoteDeck);
|
||||
connect(loadFromClipboardButton, &QPushButton::clicked, this, &DeckViewContainer::loadFromClipboard);
|
||||
connect(loadFromWebsiteButton, &QPushButton::clicked, this, &DeckViewContainer::loadFromWebsite);
|
||||
connect(readyStartButton, &QPushButton::clicked, this, &DeckViewContainer::readyStart);
|
||||
connect(unloadDeckButton, &QPushButton::clicked, this, &DeckViewContainer::unloadDeck);
|
||||
connect(forceStartGameButton, &QPushButton::clicked, this, &DeckViewContainer::forceStart);
|
||||
connect(sideboardLockButton, &QPushButton::clicked, this, &DeckViewContainer::sideboardLockButtonClicked);
|
||||
connect(sideboardLockButton, &ToggleButton::stateChanged, this, &DeckViewContainer::updateSideboardLockButtonText);
|
||||
|
||||
auto *buttonHBox = new QHBoxLayout;
|
||||
buttonHBox->addWidget(loadLocalButton);
|
||||
buttonHBox->addWidget(loadRemoteButton);
|
||||
buttonHBox->addWidget(loadFromClipboardButton);
|
||||
buttonHBox->addWidget(loadFromWebsiteButton);
|
||||
buttonHBox->addWidget(unloadDeckButton);
|
||||
buttonHBox->addWidget(readyStartButton);
|
||||
buttonHBox->addWidget(sideboardLockButton);
|
||||
buttonHBox->addWidget(forceStartGameButton);
|
||||
|
||||
buttonHBox->setContentsMargins(11, 0, 11, 0);
|
||||
buttonHBox->addStretch();
|
||||
|
||||
deckView = new DeckView;
|
||||
connect(deckView, &DeckView::newCardAdded, this, &DeckViewContainer::newCardAdded);
|
||||
connect(deckView, &DeckView::sideboardPlanChanged, this, &DeckViewContainer::sideboardPlanChanged);
|
||||
|
||||
deckViewLayout = new QVBoxLayout;
|
||||
deckViewLayout->addLayout(buttonHBox);
|
||||
deckViewLayout->addWidget(deckView);
|
||||
deckViewLayout->setContentsMargins(0, 0, 0, 0);
|
||||
setLayout(deckViewLayout);
|
||||
|
||||
retranslateUi();
|
||||
connect(&SettingsCache::instance().shortcuts(), &ShortcutsSettings::shortCutChanged, this,
|
||||
&DeckViewContainer::refreshShortcuts);
|
||||
refreshShortcuts();
|
||||
|
||||
connect(&SettingsCache::instance(), &SettingsCache::visualDeckStorageInGameChanged, this,
|
||||
&DeckViewContainer::setVisualDeckStorageExists);
|
||||
|
||||
switchToDeckSelectView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the VDS widget and inserts it into the layout. No-ops if the widget already exists
|
||||
*/
|
||||
void DeckViewContainer::tryCreateVisualDeckStorageWidget()
|
||||
{
|
||||
if (visualDeckStorageWidget) {
|
||||
return;
|
||||
}
|
||||
|
||||
visualDeckStorageWidget = new VisualDeckStorageWidget(this);
|
||||
connect(visualDeckStorageWidget, &VisualDeckStorageWidget::deckLoadRequested, this,
|
||||
&DeckViewContainer::loadDeckFromFile);
|
||||
connect(visualDeckStorageWidget, &VisualDeckStorageWidget::openDeckEditor, parentGame, &TabGame::openDeckEditor);
|
||||
|
||||
deckViewLayout->addWidget(visualDeckStorageWidget);
|
||||
}
|
||||
|
||||
void DeckViewContainer::retranslateUi()
|
||||
{
|
||||
loadLocalButton->setText(tr("Load deck..."));
|
||||
loadRemoteButton->setText(tr("Load remote deck..."));
|
||||
loadFromClipboardButton->setText(tr("Load from clipboard..."));
|
||||
loadFromWebsiteButton->setText(tr("Load from website..."));
|
||||
unloadDeckButton->setText(tr("Unload deck"));
|
||||
readyStartButton->setText(tr("Ready to start"));
|
||||
forceStartGameButton->setText(tr("Force start"));
|
||||
updateSideboardLockButtonText();
|
||||
}
|
||||
|
||||
static void setVisibility(QPushButton *button, bool visible)
|
||||
{
|
||||
button->setHidden(!visible);
|
||||
button->setEnabled(visible);
|
||||
}
|
||||
|
||||
void DeckViewContainer::switchToDeckSelectView()
|
||||
{
|
||||
if (SettingsCache::instance().getVisualDeckStorageInGame()) {
|
||||
deckView->setHidden(true);
|
||||
|
||||
tryCreateVisualDeckStorageWidget();
|
||||
visualDeckStorageWidget->setHidden(false);
|
||||
} else {
|
||||
deckView->setHidden(false);
|
||||
if (visualDeckStorageWidget) {
|
||||
visualDeckStorageWidget->setHidden(true);
|
||||
}
|
||||
}
|
||||
|
||||
deckViewLayout->update();
|
||||
|
||||
setVisibility(loadLocalButton, true);
|
||||
setVisibility(loadRemoteButton, !parentGame->getGame()->getGameState()->getIsLocalGame());
|
||||
setVisibility(loadFromClipboardButton, true);
|
||||
setVisibility(loadFromWebsiteButton, true);
|
||||
setVisibility(unloadDeckButton, false);
|
||||
setVisibility(readyStartButton, false);
|
||||
setVisibility(sideboardLockButton, false);
|
||||
setVisibility(forceStartGameButton, false);
|
||||
|
||||
readyStartButton->setState(false);
|
||||
sideboardLockButton->setState(false);
|
||||
|
||||
deckView->setLocked(true);
|
||||
|
||||
sendReadyStartCommand(false);
|
||||
}
|
||||
|
||||
void DeckViewContainer::switchToDeckLoadedView()
|
||||
{
|
||||
deckView->setHidden(false);
|
||||
if (visualDeckStorageWidget) {
|
||||
visualDeckStorageWidget->setHidden(true);
|
||||
}
|
||||
|
||||
deckViewLayout->update();
|
||||
|
||||
setVisibility(loadLocalButton, false);
|
||||
setVisibility(loadRemoteButton, false);
|
||||
setVisibility(loadFromClipboardButton, false);
|
||||
setVisibility(loadFromWebsiteButton, false);
|
||||
setVisibility(unloadDeckButton, true);
|
||||
setVisibility(readyStartButton, true);
|
||||
setVisibility(sideboardLockButton, true);
|
||||
|
||||
if (parentGame->getGame()->isHost()) {
|
||||
setVisibility(forceStartGameButton, true);
|
||||
}
|
||||
}
|
||||
|
||||
void DeckViewContainer::updateSideboardLockButtonText()
|
||||
{
|
||||
if (sideboardLockButton->getState()) {
|
||||
sideboardLockButton->setText(tr("Sideboard unlocked"));
|
||||
} else {
|
||||
sideboardLockButton->setText(tr("Sideboard locked"));
|
||||
}
|
||||
// setting text on a button removes its shortcut
|
||||
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
|
||||
sideboardLockButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/sideboardLockButton"));
|
||||
}
|
||||
|
||||
void DeckViewContainer::refreshShortcuts()
|
||||
{
|
||||
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
|
||||
loadLocalButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/loadLocalButton"));
|
||||
loadRemoteButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/loadRemoteButton"));
|
||||
loadFromClipboardButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/loadFromClipboardButton"));
|
||||
unloadDeckButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/unloadDeckButton"));
|
||||
readyStartButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/readyStartButton"));
|
||||
sideboardLockButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/sideboardLockButton"));
|
||||
forceStartGameButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/forceStartGameButton"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the existence of the embedded Visual Deck Storage, destroying or creating it if needed.
|
||||
* Note that this change is temporary; the VDS may get recreated when the view transitions to the deck select state,
|
||||
* depending on current settings.
|
||||
*/
|
||||
void DeckViewContainer::setVisualDeckStorageExists(bool exists)
|
||||
{
|
||||
if (exists) {
|
||||
// view mode state isn't stored in a field, so we determine state by checking the button
|
||||
if (loadLocalButton->isEnabled()) {
|
||||
// We only need to handle the setting changing while in deck select state; tryCreate already gets called
|
||||
// when switching from deck loaded to deck select state
|
||||
tryCreateVisualDeckStorageWidget();
|
||||
visualDeckStorageWidget->setHidden(false);
|
||||
deckView->setHidden(true);
|
||||
}
|
||||
} else {
|
||||
if (visualDeckStorageWidget) {
|
||||
visualDeckStorageWidget->deleteLater();
|
||||
visualDeckStorageWidget = nullptr;
|
||||
}
|
||||
deckView->setHidden(false);
|
||||
}
|
||||
|
||||
deckViewLayout->update();
|
||||
}
|
||||
|
||||
void DeckViewContainer::unloadDeck()
|
||||
{
|
||||
deckView->clearDeck();
|
||||
switchToDeckSelectView();
|
||||
}
|
||||
|
||||
void DeckViewContainer::loadLocalDeck()
|
||||
{
|
||||
DlgLoadDeck dialog(this);
|
||||
if (!dialog.exec()) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadDeckFromFile(dialog.selectedFiles().at(0));
|
||||
}
|
||||
|
||||
void DeckViewContainer::loadDeckFromFile(const QString &filePath)
|
||||
{
|
||||
DeckFileFormat::Format fmt = DeckFileFormat::getFormatFromName(filePath);
|
||||
|
||||
std::optional<LoadedDeck> deckOpt = DeckLoader::loadFromFile(filePath, fmt, true);
|
||||
|
||||
if (!deckOpt) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("The selected file could not be loaded."));
|
||||
return;
|
||||
}
|
||||
|
||||
loadDeckFromDeckList(deckOpt.value().deckList);
|
||||
}
|
||||
|
||||
void DeckViewContainer::loadDeckFromDeckList(const DeckList &deck)
|
||||
{
|
||||
QString deckString = deck.writeToString_Native();
|
||||
|
||||
if (deckString.length() > MAX_FILE_LENGTH) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Deck is greater than maximum file size."));
|
||||
return;
|
||||
}
|
||||
|
||||
Command_DeckSelect cmd;
|
||||
cmd.set_deck(deckString.toStdString());
|
||||
PendingCommand *pend = parentGame->getGame()->getGameEventHandler()->prepareGameCommand(cmd);
|
||||
connect(pend, &PendingCommand::finished, this, &DeckViewContainer::deckSelectFinished);
|
||||
parentGame->getGame()->getGameEventHandler()->sendGameCommand(pend, playerId);
|
||||
}
|
||||
|
||||
void DeckViewContainer::loadRemoteDeck()
|
||||
{
|
||||
DlgLoadRemoteDeck dlg(parentGame->getGame()->getClientForPlayer(playerId), this);
|
||||
if (dlg.exec()) {
|
||||
Command_DeckSelect cmd;
|
||||
cmd.set_deck_id(dlg.getDeckId());
|
||||
PendingCommand *pend = parentGame->getGame()->getGameEventHandler()->prepareGameCommand(cmd);
|
||||
connect(pend, &PendingCommand::finished, this, &DeckViewContainer::deckSelectFinished);
|
||||
parentGame->getGame()->getGameEventHandler()->sendGameCommand(pend, playerId);
|
||||
}
|
||||
}
|
||||
|
||||
void DeckViewContainer::loadFromClipboard()
|
||||
{
|
||||
auto dlg = DlgLoadDeckFromClipboard(this);
|
||||
|
||||
if (!dlg.exec()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DeckList deck = dlg.getDeckList();
|
||||
loadDeckFromDeckList(deck);
|
||||
}
|
||||
|
||||
void DeckViewContainer::loadFromWebsite()
|
||||
{
|
||||
auto dlg = DlgLoadDeckFromWebsite(this);
|
||||
|
||||
if (!dlg.exec()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DeckList deck = dlg.getDeck();
|
||||
loadDeckFromDeckList(deck);
|
||||
}
|
||||
|
||||
void DeckViewContainer::deckSelectFinished(const Response &r)
|
||||
{
|
||||
const Response_DeckDownload &resp = r.GetExtension(Response_DeckDownload::ext);
|
||||
DeckList newDeck = DeckList(QString::fromStdString(resp.deck()));
|
||||
CardPictureLoader::cacheCardPixmaps(CardDatabaseManager::query()->getCards(newDeck.getCardRefList()));
|
||||
setDeck(newDeck);
|
||||
switchToDeckLoadedView();
|
||||
}
|
||||
|
||||
void DeckViewContainer::readyStart()
|
||||
{
|
||||
sendReadyStartCommand(!readyStartButton->getState());
|
||||
}
|
||||
|
||||
void DeckViewContainer::forceStart()
|
||||
{
|
||||
const auto msg = tr("Are you sure you want to force start?\nThis will kick all non-ready players from the game.");
|
||||
const auto res =
|
||||
QMessageBox::question(this, tr("Cockatrice"), msg, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||
if (res == QMessageBox::No) {
|
||||
return;
|
||||
}
|
||||
|
||||
Command_ReadyStart cmd;
|
||||
cmd.set_force_start(true);
|
||||
cmd.set_ready(true);
|
||||
parentGame->getGame()->getGameEventHandler()->sendGameCommand(cmd, playerId);
|
||||
}
|
||||
|
||||
void DeckViewContainer::sideboardLockButtonClicked()
|
||||
{
|
||||
Command_SetSideboardLock cmd;
|
||||
cmd.set_locked(sideboardLockButton->getState());
|
||||
|
||||
parentGame->getGame()->getGameEventHandler()->sendGameCommand(cmd, playerId);
|
||||
}
|
||||
|
||||
void DeckViewContainer::sideboardPlanChanged()
|
||||
{
|
||||
Command_SetSideboardPlan cmd;
|
||||
const QList<MoveCard_ToZone> &newPlan = deckView->getSideboardPlan();
|
||||
for (const auto &i : newPlan) {
|
||||
cmd.add_move_list()->CopyFrom(i);
|
||||
}
|
||||
parentGame->getGame()->getGameEventHandler()->sendGameCommand(cmd, playerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the basic ReadyStart command.
|
||||
*/
|
||||
void DeckViewContainer::sendReadyStartCommand(bool ready)
|
||||
{
|
||||
Command_ReadyStart cmd;
|
||||
cmd.set_ready(ready);
|
||||
parentGame->getGame()->getGameEventHandler()->sendGameCommand(cmd, playerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the buttons to make the client-side ready state match the given state.
|
||||
*
|
||||
* Notably, this method only updates the client and *does not* send a ReadyStart command to the server.
|
||||
* This method is intended to be called upon receiving the response from a ReadyStart command.
|
||||
*/
|
||||
void DeckViewContainer::setReadyStart(bool ready)
|
||||
{
|
||||
readyStartButton->setState(ready);
|
||||
deckView->setLocked(ready || !sideboardLockButton->getState());
|
||||
sideboardLockButton->setEnabled(!readyStartButton->getState() && readyStartButton->isEnabled());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a ReadyStart command with ready=true to the server
|
||||
*/
|
||||
void DeckViewContainer::readyAndUpdate()
|
||||
{
|
||||
sendReadyStartCommand(true);
|
||||
}
|
||||
|
||||
void DeckViewContainer::setSideboardLocked(bool locked)
|
||||
{
|
||||
sideboardLockButton->setState(!locked);
|
||||
deckView->setLocked(readyStartButton->getState() || !sideboardLockButton->getState());
|
||||
if (locked) {
|
||||
deckView->resetSideboardPlan();
|
||||
}
|
||||
}
|
||||
|
||||
void DeckViewContainer::setDeck(const DeckList &deck)
|
||||
{
|
||||
deckView->setDeck(deck);
|
||||
switchToDeckLoadedView();
|
||||
}
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
/**
|
||||
* @file deck_view_container.h
|
||||
* @ingroup Lobby
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef DECK_VIEW_CONTAINER_H
|
||||
#define DECK_VIEW_CONTAINER_H
|
||||
|
||||
#include "../../interface/deck_loader/deck_loader.h"
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
class QVBoxLayout;
|
||||
class AbstractCardItem;
|
||||
class VisualDeckStorageWidget;
|
||||
class DeckPreviewWidget;
|
||||
class Response;
|
||||
class TabGame;
|
||||
class DeckView;
|
||||
|
||||
/**
|
||||
* Custom QButton implementation in order to have the red/green toggling square around the button
|
||||
*/
|
||||
class ToggleButton : public QPushButton
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
bool state;
|
||||
signals:
|
||||
void stateChanged();
|
||||
|
||||
public:
|
||||
explicit ToggleButton(QWidget *parent = nullptr);
|
||||
[[nodiscard]] bool getState() const
|
||||
{
|
||||
return state;
|
||||
}
|
||||
void setState(bool _state);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* This widget contains the deck selection view that is used before a game begins.
|
||||
*/
|
||||
class DeckViewContainer : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
QVBoxLayout *deckViewLayout;
|
||||
QPushButton *loadLocalButton, *loadRemoteButton, *loadFromClipboardButton, *loadFromWebsiteButton;
|
||||
QPushButton *unloadDeckButton, *forceStartGameButton;
|
||||
ToggleButton *readyStartButton, *sideboardLockButton;
|
||||
DeckView *deckView;
|
||||
VisualDeckStorageWidget *visualDeckStorageWidget;
|
||||
TabGame *parentGame;
|
||||
int playerId;
|
||||
|
||||
void tryCreateVisualDeckStorageWidget();
|
||||
void sendReadyStartCommand(bool ready);
|
||||
private slots:
|
||||
void switchToDeckSelectView();
|
||||
void switchToDeckLoadedView();
|
||||
void loadLocalDeck();
|
||||
void loadRemoteDeck();
|
||||
void loadFromClipboard();
|
||||
void loadFromWebsite();
|
||||
void unloadDeck();
|
||||
void readyStart();
|
||||
void forceStart();
|
||||
void deckSelectFinished(const Response &r);
|
||||
void sideboardPlanChanged();
|
||||
void sideboardLockButtonClicked();
|
||||
void updateSideboardLockButtonText();
|
||||
void refreshShortcuts();
|
||||
signals:
|
||||
void newCardAdded(AbstractCardItem *card);
|
||||
void notIdle();
|
||||
|
||||
public:
|
||||
DeckViewContainer(int _playerId, TabGame *parent);
|
||||
void retranslateUi();
|
||||
void setReadyStart(bool ready);
|
||||
void readyAndUpdate();
|
||||
void setSideboardLocked(bool locked);
|
||||
void setDeck(const DeckList &deck);
|
||||
void setVisualDeckStorageExists(bool exists);
|
||||
|
||||
public slots:
|
||||
void loadDeckFromFile(const QString &filePath);
|
||||
void loadDeckFromDeckList(const DeckList &deck);
|
||||
};
|
||||
|
||||
#endif // DECK_VIEW_CONTAINER_H
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
#include "tabbed_deck_view_container.h"
|
||||
|
||||
#include "../../interface/widgets/tabs/tab_game.h"
|
||||
#include "deck_view.h"
|
||||
|
||||
TabbedDeckViewContainer::TabbedDeckViewContainer(int _playerId, TabGame *parent)
|
||||
: QTabWidget(nullptr), playerId(_playerId), parentGame(parent)
|
||||
{
|
||||
setTabsClosable(true);
|
||||
connect(this, &QTabWidget::tabCloseRequested, this, &TabbedDeckViewContainer::closeTab);
|
||||
|
||||
playerDeckView = new DeckViewContainer(playerId, parentGame);
|
||||
int playerTabIndex = addTab(playerDeckView, "Your Deck");
|
||||
tabBar()->setTabButton(playerTabIndex, QTabBar::RightSide, nullptr);
|
||||
updateTabBarVisibility();
|
||||
}
|
||||
|
||||
void TabbedDeckViewContainer::addOpponentDeckView(const DeckList &opponentDeck, int opponentId, QString opponentName)
|
||||
{
|
||||
if (opponentDeckViews.contains(opponentId)) {
|
||||
opponentDeckViews[opponentId]->setDeck(opponentDeck);
|
||||
} else {
|
||||
auto *opponentDeckView = new DeckView(this);
|
||||
connect(opponentDeckView, &DeckView::newCardAdded, playerDeckView, &DeckViewContainer::newCardAdded);
|
||||
|
||||
opponentDeckView->setDeck(opponentDeck);
|
||||
|
||||
addTab(opponentDeckView, QString("%1's Deck").arg(opponentName));
|
||||
|
||||
opponentDeckViews.insert(opponentId, opponentDeckView);
|
||||
}
|
||||
updateTabBarVisibility();
|
||||
}
|
||||
|
||||
void TabbedDeckViewContainer::closeTab(int index)
|
||||
{
|
||||
QWidget *widgetToClose = widget(index);
|
||||
|
||||
// Prevent removing the player tab
|
||||
if (widgetToClose == playerDeckView) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove it from map if it's an opponent
|
||||
auto it = opponentDeckViews.begin();
|
||||
while (it != opponentDeckViews.end()) {
|
||||
if (it.value() == widgetToClose) {
|
||||
it = opponentDeckViews.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
removeTab(index);
|
||||
widgetToClose->deleteLater();
|
||||
updateTabBarVisibility();
|
||||
}
|
||||
|
||||
void TabbedDeckViewContainer::updateTabBarVisibility()
|
||||
{
|
||||
if (tabBar()->count() <= 1) {
|
||||
tabBar()->hide();
|
||||
} else {
|
||||
tabBar()->show();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
/**
|
||||
* @file tabbed_deck_view_container.h
|
||||
* @ingroup Lobby
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef TABBED_DECK_VIEW_CONTAINER_H
|
||||
#define TABBED_DECK_VIEW_CONTAINER_H
|
||||
#include "deck_view_container.h"
|
||||
|
||||
#include <QTabWidget>
|
||||
|
||||
class TabbedDeckViewContainer : public QTabWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TabbedDeckViewContainer(int _playerId, TabGame *parent);
|
||||
void closeTab(int index);
|
||||
void updateTabBarVisibility();
|
||||
void addOpponentDeckView(const DeckList &opponentDeck, int opponentId, QString opponentName);
|
||||
int playerId;
|
||||
TabGame *parentGame;
|
||||
DeckViewContainer *playerDeckView;
|
||||
|
||||
QMap<int, DeckView *> opponentDeckViews;
|
||||
};
|
||||
|
||||
#endif // TABBED_DECK_VIEW_CONTAINER_H
|
||||
|
|
@ -1,249 +0,0 @@
|
|||
#include "dlg_create_token.h"
|
||||
|
||||
#include "../../client/settings/cache_settings.h"
|
||||
#include "../../interface/widgets/cards/card_info_picture_widget.h"
|
||||
#include "../../main.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QCloseEvent>
|
||||
#include <QComboBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QGridLayout>
|
||||
#include <QGroupBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QHeaderView>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QRadioButton>
|
||||
#include <QTreeView>
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
#include <libcockatrice/deck_list/deck_list.h>
|
||||
#include <libcockatrice/models/database/card_database_model.h>
|
||||
#include <libcockatrice/models/database/token/token_display_model.h>
|
||||
#include <libcockatrice/utility/trice_limits.h>
|
||||
|
||||
DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *parent)
|
||||
: QDialog(parent), predefinedTokens(_predefinedTokens)
|
||||
{
|
||||
pic = new CardInfoPictureWidget();
|
||||
pic->setObjectName("pic");
|
||||
|
||||
nameLabel = new QLabel(tr("&Name:"));
|
||||
nameEdit = new QLineEdit(tr("Token"));
|
||||
nameEdit->setMaxLength(MAX_NAME_LENGTH);
|
||||
QTimer::singleShot(100, this, [=, this]() {
|
||||
nameEdit->selectAll();
|
||||
nameEdit->setFocus();
|
||||
});
|
||||
|
||||
connect(nameEdit, &QLineEdit::textChanged, this, &DlgCreateToken::updateSearch);
|
||||
nameLabel->setBuddy(nameEdit);
|
||||
|
||||
colorLabel = new QLabel(tr("C&olor:"));
|
||||
colorEdit = new QComboBox;
|
||||
colorEdit->addItem(tr("white"), QChar('w'));
|
||||
colorEdit->addItem(tr("blue"), QChar('u'));
|
||||
colorEdit->addItem(tr("black"), QChar('b'));
|
||||
colorEdit->addItem(tr("red"), QChar('r'));
|
||||
colorEdit->addItem(tr("green"), QChar('g'));
|
||||
colorEdit->addItem(tr("multicolor"), QChar('m'));
|
||||
colorEdit->addItem(tr("colorless"), QChar());
|
||||
colorLabel->setBuddy(colorEdit);
|
||||
|
||||
ptLabel = new QLabel(tr("&P/T:"));
|
||||
ptEdit = new QLineEdit;
|
||||
ptEdit->setMaxLength(MAX_NAME_LENGTH);
|
||||
ptLabel->setBuddy(ptEdit);
|
||||
|
||||
annotationLabel = new QLabel(tr("&Annotation:"));
|
||||
annotationEdit = new QLineEdit;
|
||||
annotationEdit->setMaxLength(MAX_NAME_LENGTH);
|
||||
annotationLabel->setBuddy(annotationEdit);
|
||||
|
||||
destroyCheckBox = new QCheckBox(tr("&Destroy token when it leaves the table"));
|
||||
destroyCheckBox->setChecked(true);
|
||||
|
||||
faceDownCheckBox = new QCheckBox(tr("Create face-down (Only hides name)"));
|
||||
connect(faceDownCheckBox, &QCheckBox::toggled, this, &DlgCreateToken::faceDownCheckBoxToggled);
|
||||
|
||||
auto *grid = new QGridLayout;
|
||||
grid->addWidget(nameLabel, 0, 0);
|
||||
grid->addWidget(nameEdit, 0, 1);
|
||||
grid->addWidget(colorLabel, 1, 0);
|
||||
grid->addWidget(colorEdit, 1, 1);
|
||||
grid->addWidget(ptLabel, 2, 0);
|
||||
grid->addWidget(ptEdit, 2, 1);
|
||||
grid->addWidget(annotationLabel, 3, 0);
|
||||
grid->addWidget(annotationEdit, 3, 1);
|
||||
grid->addWidget(destroyCheckBox, 4, 0, 1, 2);
|
||||
grid->addWidget(faceDownCheckBox, 5, 0, 1, 2);
|
||||
|
||||
auto *tokenDataGroupBox = new QGroupBox(tr("Token data"));
|
||||
tokenDataGroupBox->setLayout(grid);
|
||||
|
||||
cardDatabaseModel = new CardDatabaseModel(CardDatabaseManager::getInstance(), false, this);
|
||||
cardDatabaseDisplayModel = new TokenDisplayModel(this);
|
||||
cardDatabaseDisplayModel->setSourceModel(cardDatabaseModel);
|
||||
|
||||
chooseTokenFromAllRadioButton = new QRadioButton(tr("Show &all tokens"));
|
||||
connect(chooseTokenFromAllRadioButton, &QRadioButton::toggled, this, &DlgCreateToken::actChooseTokenFromAll);
|
||||
chooseTokenFromDeckRadioButton = new QRadioButton(tr("Show tokens from this &deck"));
|
||||
connect(chooseTokenFromDeckRadioButton, &QRadioButton::toggled, this, &DlgCreateToken::actChooseTokenFromDeck);
|
||||
|
||||
QByteArray deckHeaderState = SettingsCache::instance().layouts().getDeckEditorDbHeaderState();
|
||||
chooseTokenView = new QTreeView;
|
||||
chooseTokenView->setModel(cardDatabaseDisplayModel);
|
||||
chooseTokenView->setUniformRowHeights(true);
|
||||
chooseTokenView->setRootIsDecorated(false);
|
||||
chooseTokenView->setAlternatingRowColors(true);
|
||||
chooseTokenView->setSortingEnabled(true);
|
||||
chooseTokenView->sortByColumn(0, Qt::AscendingOrder);
|
||||
chooseTokenView->resizeColumnToContents(0);
|
||||
chooseTokenView->setWordWrap(true);
|
||||
|
||||
if (!deckHeaderState.isNull()) {
|
||||
chooseTokenView->header()->restoreState(deckHeaderState);
|
||||
}
|
||||
|
||||
chooseTokenView->header()->setStretchLastSection(false);
|
||||
chooseTokenView->header()->hideSection(1); // Sets
|
||||
chooseTokenView->header()->hideSection(2); // Mana Cost
|
||||
chooseTokenView->header()->setSectionResizeMode(5, QHeaderView::ResizeToContents); // Color(s)
|
||||
connect(chooseTokenView->selectionModel(), &QItemSelectionModel::currentRowChanged, this,
|
||||
&DlgCreateToken::tokenSelectionChanged);
|
||||
connect(chooseTokenView, &QTreeView::doubleClicked, this, &DlgCreateToken::actOk);
|
||||
|
||||
if (predefinedTokens.isEmpty()) {
|
||||
chooseTokenFromAllRadioButton->setChecked(true);
|
||||
chooseTokenFromDeckRadioButton->setDisabled(true); // No tokens in deck = no need for option
|
||||
} else {
|
||||
chooseTokenFromDeckRadioButton->setChecked(true);
|
||||
cardDatabaseDisplayModel->setCardNameSet(QSet<QString>(predefinedTokens.begin(), predefinedTokens.end()));
|
||||
}
|
||||
|
||||
auto *tokenChooseLayout = new QVBoxLayout;
|
||||
tokenChooseLayout->addWidget(chooseTokenFromAllRadioButton);
|
||||
tokenChooseLayout->addWidget(chooseTokenFromDeckRadioButton);
|
||||
tokenChooseLayout->addWidget(chooseTokenView);
|
||||
|
||||
auto *tokenChooseGroupBox = new QGroupBox(tr("Choose token from list"));
|
||||
tokenChooseGroupBox->setLayout(tokenChooseLayout);
|
||||
|
||||
auto *hbox = new QGridLayout;
|
||||
hbox->addWidget(pic, 0, 0, 1, 1);
|
||||
hbox->addWidget(tokenDataGroupBox, 1, 0, 1, 1);
|
||||
hbox->addWidget(tokenChooseGroupBox, 0, 1, 2, 1);
|
||||
hbox->setColumnStretch(1, 1);
|
||||
|
||||
auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgCreateToken::actOk);
|
||||
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgCreateToken::actReject);
|
||||
|
||||
auto *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(hbox);
|
||||
mainLayout->addWidget(buttonBox);
|
||||
setLayout(mainLayout);
|
||||
|
||||
setWindowTitle(tr("Create token"));
|
||||
|
||||
resize(600, 500);
|
||||
restoreGeometry(SettingsCache::instance().layouts().getTokenDialogGeometry());
|
||||
}
|
||||
|
||||
void DlgCreateToken::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
event->accept();
|
||||
SettingsCache::instance().layouts().setTokenDialogGeometry(saveGeometry());
|
||||
}
|
||||
|
||||
void DlgCreateToken::faceDownCheckBoxToggled(bool checked)
|
||||
{
|
||||
if (checked) {
|
||||
colorEdit->setCurrentIndex(6);
|
||||
colorEdit->setEnabled(false);
|
||||
ptEdit->clear();
|
||||
ptEdit->clearFocus();
|
||||
ptEdit->setEnabled(false);
|
||||
} else {
|
||||
colorEdit->setEnabled(true);
|
||||
ptEdit->setEnabled(true);
|
||||
annotationEdit->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void DlgCreateToken::tokenSelectionChanged(const QModelIndex ¤t, const QModelIndex & /*previous*/)
|
||||
{
|
||||
const QModelIndex realIndex = cardDatabaseDisplayModel->mapToSource(current);
|
||||
|
||||
CardInfoPtr cardInfo;
|
||||
|
||||
if (current.row() >= 0) {
|
||||
cardInfo = cardDatabaseModel->getCard(realIndex.row());
|
||||
}
|
||||
|
||||
if (cardInfo) {
|
||||
updateSearchFieldWithoutUpdatingFilter(cardInfo->getName());
|
||||
const QChar cardColor = cardInfo->getColorChar();
|
||||
colorEdit->setCurrentIndex(colorEdit->findData(cardColor, Qt::UserRole, Qt::MatchFixedString));
|
||||
ptEdit->setText(cardInfo->getPowTough());
|
||||
if (SettingsCache::instance().getAnnotateTokens()) {
|
||||
annotationEdit->setText(cardInfo->getText());
|
||||
}
|
||||
} else {
|
||||
nameEdit->setText("");
|
||||
colorEdit->setCurrentIndex(colorEdit->findData(QString(), Qt::UserRole, Qt::MatchFixedString));
|
||||
ptEdit->setText("");
|
||||
annotationEdit->setText("");
|
||||
}
|
||||
|
||||
pic->setCard(CardDatabaseManager::query()->getPreferredCard(cardInfo));
|
||||
}
|
||||
|
||||
void DlgCreateToken::updateSearchFieldWithoutUpdatingFilter(const QString &newValue) const
|
||||
{
|
||||
nameEdit->blockSignals(true);
|
||||
nameEdit->setText(newValue);
|
||||
nameEdit->blockSignals(false);
|
||||
}
|
||||
|
||||
void DlgCreateToken::updateSearch(const QString &search)
|
||||
{
|
||||
cardDatabaseDisplayModel->setCardName(search);
|
||||
}
|
||||
|
||||
void DlgCreateToken::actChooseTokenFromAll(bool checked)
|
||||
{
|
||||
if (checked) {
|
||||
cardDatabaseDisplayModel->setCardNameSet(QSet<QString>());
|
||||
}
|
||||
}
|
||||
|
||||
void DlgCreateToken::actChooseTokenFromDeck(bool checked)
|
||||
{
|
||||
if (checked) {
|
||||
cardDatabaseDisplayModel->setCardNameSet(QSet<QString>(predefinedTokens.begin(), predefinedTokens.end()));
|
||||
}
|
||||
}
|
||||
|
||||
void DlgCreateToken::actOk()
|
||||
{
|
||||
SettingsCache::instance().layouts().setTokenDialogGeometry(saveGeometry());
|
||||
accept();
|
||||
}
|
||||
|
||||
void DlgCreateToken::actReject()
|
||||
{
|
||||
SettingsCache::instance().layouts().setTokenDialogGeometry(saveGeometry());
|
||||
reject();
|
||||
}
|
||||
|
||||
TokenInfo DlgCreateToken::getTokenInfo() const
|
||||
{
|
||||
return {.name = nameEdit->text(),
|
||||
.color = colorEdit->itemData(colorEdit->currentIndex()).toString(),
|
||||
.pt = ptEdit->text(),
|
||||
.annotation = annotationEdit->text(),
|
||||
.destroy = destroyCheckBox->isChecked(),
|
||||
.faceDown = faceDownCheckBox->isChecked(),
|
||||
.providerId = SettingsCache::instance().cardOverrides().getCardPreferenceOverride(nameEdit->text())};
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
/**
|
||||
* @file dlg_create_token.h
|
||||
* @ingroup GameDialogs
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef DLG_CREATETOKEN_H
|
||||
#define DLG_CREATETOKEN_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
class QComboBox;
|
||||
class QCheckBox;
|
||||
class QPushButton;
|
||||
class QRadioButton;
|
||||
class QCloseEvent;
|
||||
class QTreeView;
|
||||
class DeckList;
|
||||
class CardDatabaseModel;
|
||||
class TokenDisplayModel;
|
||||
class CardInfoPictureWidget;
|
||||
|
||||
struct TokenInfo
|
||||
{
|
||||
QString name;
|
||||
QString color;
|
||||
QString pt;
|
||||
QString annotation;
|
||||
bool destroy = true;
|
||||
bool faceDown = false;
|
||||
QString providerId;
|
||||
};
|
||||
|
||||
class DlgCreateToken : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DlgCreateToken(const QStringList &_predefinedTokens, QWidget *parent = nullptr);
|
||||
[[nodiscard]] TokenInfo getTokenInfo() const;
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
private slots:
|
||||
void faceDownCheckBoxToggled(bool checked);
|
||||
void tokenSelectionChanged(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
void updateSearch(const QString &search);
|
||||
void actChooseTokenFromAll(bool checked);
|
||||
void actChooseTokenFromDeck(bool checked);
|
||||
void actOk();
|
||||
void actReject();
|
||||
|
||||
private:
|
||||
CardDatabaseModel *cardDatabaseModel;
|
||||
TokenDisplayModel *cardDatabaseDisplayModel;
|
||||
QStringList predefinedTokens;
|
||||
QLabel *nameLabel, *colorLabel, *ptLabel, *annotationLabel;
|
||||
QComboBox *colorEdit;
|
||||
QLineEdit *nameEdit, *ptEdit, *annotationEdit;
|
||||
QCheckBox *destroyCheckBox;
|
||||
QCheckBox *faceDownCheckBox;
|
||||
QRadioButton *chooseTokenFromAllRadioButton, *chooseTokenFromDeckRadioButton;
|
||||
CardInfoPictureWidget *pic;
|
||||
QTreeView *chooseTokenView;
|
||||
|
||||
void updateSearchFieldWithoutUpdatingFilter(const QString &newValue) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,134 +0,0 @@
|
|||
#include "dlg_move_top_cards_until.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QMessageBox>
|
||||
#include <QSpinBox>
|
||||
#include <QString>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
#include <libcockatrice/card/database/card_database.h>
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
#include <libcockatrice/filters/filter_string.h>
|
||||
|
||||
DlgMoveTopCardsUntil::DlgMoveTopCardsUntil(QWidget *parent, const MoveTopCardsUntilOptions &options) : QDialog(parent)
|
||||
{
|
||||
exprLabel = new QLabel(tr("Card name (or search expressions):"));
|
||||
|
||||
exprComboBox = new QComboBox(this);
|
||||
exprComboBox->setFocus();
|
||||
exprComboBox->setEditable(true);
|
||||
exprComboBox->setInsertPolicy(QComboBox::InsertAtTop);
|
||||
exprComboBox->insertItems(0, options.exprs);
|
||||
exprLabel->setBuddy(exprComboBox);
|
||||
|
||||
numberOfHitsLabel = new QLabel(tr("Number of hits:"));
|
||||
numberOfHitsEdit = new QSpinBox(this);
|
||||
numberOfHitsEdit->setRange(1, 99);
|
||||
numberOfHitsEdit->setValue(options.numberOfHits);
|
||||
numberOfHitsLabel->setBuddy(numberOfHitsEdit);
|
||||
|
||||
auto *grid = new QGridLayout;
|
||||
grid->addWidget(numberOfHitsLabel, 0, 0);
|
||||
grid->addWidget(numberOfHitsEdit, 0, 1);
|
||||
|
||||
autoPlayCheckBox = new QCheckBox(tr("Auto play hits"));
|
||||
autoPlayCheckBox->setChecked(options.autoPlay);
|
||||
|
||||
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgMoveTopCardsUntil::validateAndAccept);
|
||||
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
|
||||
auto *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addWidget(exprLabel);
|
||||
mainLayout->addWidget(exprComboBox);
|
||||
mainLayout->addItem(grid);
|
||||
mainLayout->addWidget(autoPlayCheckBox);
|
||||
mainLayout->addWidget(buttonBox);
|
||||
|
||||
setLayout(mainLayout);
|
||||
setWindowTitle(tr("Put top cards on stack until..."));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a card matching the expr exists in the card database.
|
||||
*
|
||||
* @returns true if a card matching the expression exists.
|
||||
*/
|
||||
static bool matchExistsInDb(const FilterString &filterString)
|
||||
{
|
||||
const auto *cardDatabase = CardDatabaseManager::getInstance();
|
||||
const auto &allCards = cardDatabase->getCardList();
|
||||
|
||||
const auto it = std::find_if(allCards.begin(), allCards.end(),
|
||||
[&filterString](const CardInfoPtr &card) { return filterString.check(card); });
|
||||
|
||||
return it != allCards.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Validates that a card matching the expr exists in the card database.
|
||||
* If no match is found, then pop up a window to warn the user, giving them a chance to back out.
|
||||
*
|
||||
* @returns whether to proceed with the action
|
||||
*/
|
||||
bool DlgMoveTopCardsUntil::validateMatchExists(const FilterString &filterString)
|
||||
{
|
||||
if (matchExistsInDb(filterString)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto msg = tr("No cards matching the search expression exists in the card database. Proceed anyways?");
|
||||
const auto res =
|
||||
QMessageBox::warning(this, tr("Cockatrice"), msg, QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
||||
if (res == QMessageBox::No) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DlgMoveTopCardsUntil::validateAndAccept()
|
||||
{
|
||||
auto movingCardsUntilFilter = FilterString(exprComboBox->currentText());
|
||||
if (!movingCardsUntilFilter.valid()) {
|
||||
QMessageBox::warning(this, tr("Invalid filter"), movingCardsUntilFilter.error(), QMessageBox::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validateMatchExists(movingCardsUntilFilter)) {
|
||||
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 exprComboBox->currentText();
|
||||
}
|
||||
|
||||
MoveTopCardsUntilOptions DlgMoveTopCardsUntil::getOptions() const
|
||||
{
|
||||
return {.exprs = getExprs(),
|
||||
.numberOfHits = numberOfHitsEdit->text().toInt(),
|
||||
.autoPlay = autoPlayCheckBox->isChecked()};
|
||||
}
|
||||
|
||||
QStringList DlgMoveTopCardsUntil::getExprs() const
|
||||
{
|
||||
QStringList exprs;
|
||||
for (int i = 0; i < exprComboBox->count(); ++i) {
|
||||
exprs.append(exprComboBox->itemText(i));
|
||||
}
|
||||
return exprs;
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
/**
|
||||
* @file dlg_move_top_cards_until.h
|
||||
* @ingroup GameDialogs
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef DLG_MOVE_TOP_CARDS_UNTIL_H
|
||||
#define DLG_MOVE_TOP_CARDS_UNTIL_H
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QDialog>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QLabel>
|
||||
#include <QSpinBox>
|
||||
|
||||
class FilterString;
|
||||
|
||||
struct MoveTopCardsUntilOptions
|
||||
{
|
||||
QStringList exprs = {};
|
||||
int numberOfHits = 1;
|
||||
bool autoPlay = false;
|
||||
};
|
||||
|
||||
class DlgMoveTopCardsUntil : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
QLabel *exprLabel, *numberOfHitsLabel;
|
||||
QComboBox *exprComboBox;
|
||||
QSpinBox *numberOfHitsEdit;
|
||||
QDialogButtonBox *buttonBox;
|
||||
QCheckBox *autoPlayCheckBox;
|
||||
|
||||
void validateAndAccept();
|
||||
bool validateMatchExists(const FilterString &filterString);
|
||||
|
||||
[[nodiscard]] QStringList getExprs() const;
|
||||
|
||||
public:
|
||||
explicit DlgMoveTopCardsUntil(QWidget *parent = nullptr, const MoveTopCardsUntilOptions &options = {});
|
||||
[[nodiscard]] QString getExpr() const;
|
||||
[[nodiscard]] MoveTopCardsUntilOptions getOptions() const;
|
||||
};
|
||||
|
||||
#endif // DLG_MOVE_TOP_CARDS_UNTIL_H
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
#include "dlg_roll_dice.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QLabel>
|
||||
#include <QSpinBox>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
#include <libcockatrice/utility/trice_limits.h>
|
||||
|
||||
DlgRollDice::DlgRollDice(QWidget *parent) : QDialog(parent)
|
||||
{
|
||||
numberOfSidesLabel = new QLabel(tr("Number of sides:"));
|
||||
numberOfSidesEdit = new QSpinBox(this);
|
||||
numberOfSidesEdit->setValue(DEFAULT_NUMBER_SIDES_DIE);
|
||||
numberOfSidesEdit->setRange(MINIMUM_DIE_SIDES, MAXIMUM_DIE_SIDES);
|
||||
numberOfSidesEdit->setFocus();
|
||||
numberOfSidesLabel->setBuddy(numberOfSidesEdit);
|
||||
|
||||
numberOfDiceLabel = new QLabel(tr("Number of dice:"));
|
||||
numberOfDiceEdit = new QSpinBox(this);
|
||||
numberOfDiceEdit->setValue(DEFAULT_NUMBER_DICE_TO_ROLL);
|
||||
numberOfDiceEdit->setRange(MINIMUM_DICE_TO_ROLL, MAXIMUM_DICE_TO_ROLL);
|
||||
numberOfDiceLabel->setBuddy(numberOfDiceEdit);
|
||||
|
||||
auto *grid = new QGridLayout;
|
||||
grid->addWidget(numberOfSidesLabel, 0, 0);
|
||||
grid->addWidget(numberOfSidesEdit, 0, 1);
|
||||
grid->addWidget(numberOfDiceLabel, 1, 0);
|
||||
grid->addWidget(numberOfDiceEdit, 1, 1);
|
||||
|
||||
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
|
||||
auto *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addItem(grid);
|
||||
mainLayout->addWidget(buttonBox);
|
||||
|
||||
setLayout(mainLayout);
|
||||
setWindowTitle(tr("Roll Dice"));
|
||||
}
|
||||
|
||||
uint DlgRollDice::getDieSideCount() const
|
||||
{
|
||||
return numberOfSidesEdit->text().toUInt();
|
||||
}
|
||||
|
||||
uint DlgRollDice::getDiceToRollCount() const
|
||||
{
|
||||
return numberOfDiceEdit->text().toUInt();
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
/**
|
||||
* @file dlg_roll_dice.h
|
||||
* @ingroup GameDialogs
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef DLG_ROLL_DICE_H
|
||||
#define DLG_ROLL_DICE_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QLabel>
|
||||
#include <QSpinBox>
|
||||
|
||||
class DlgRollDice : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
static constexpr uint DEFAULT_NUMBER_SIDES_DIE = 20;
|
||||
static constexpr uint DEFAULT_NUMBER_DICE_TO_ROLL = 1;
|
||||
|
||||
QLabel *numberOfSidesLabel, *numberOfDiceLabel;
|
||||
QSpinBox *numberOfSidesEdit, *numberOfDiceEdit;
|
||||
QDialogButtonBox *buttonBox;
|
||||
|
||||
public:
|
||||
explicit DlgRollDice(QWidget *parent = nullptr);
|
||||
[[nodiscard]] uint getDieSideCount() const;
|
||||
[[nodiscard]] uint getDiceToRollCount() const;
|
||||
};
|
||||
|
||||
#endif // DLG_ROLL_DICE_H
|
||||
|
|
@ -4,16 +4,16 @@
|
|||
|
||||
#include <libcockatrice/protocol/pb/event_game_joined.pb.h>
|
||||
|
||||
Game::Game(TabGame *_tab,
|
||||
Game::Game(QObject *_parent,
|
||||
bool isLocalGame,
|
||||
QList<AbstractClient *> &_clients,
|
||||
const Event_GameJoined &event,
|
||||
const QMap<int, QString> &_roomGameTypes)
|
||||
: AbstractGame(_tab)
|
||||
: AbstractGame(_parent)
|
||||
{
|
||||
gameMetaInfo->setFromProto(event.game_info());
|
||||
gameMetaInfo->setRoomGameTypes(_roomGameTypes);
|
||||
gameState = new GameState(this, 0, event.host_id(), tab->getTabSupervisor()->getIsLocalGame(), _clients, false,
|
||||
event.resuming(), -1, false);
|
||||
gameState = new GameState(this, 0, event.host_id(), isLocalGame, _clients, false, event.resuming(), -1, false);
|
||||
connect(gameMetaInfo, &GameMetaInfo::startedChanged, gameState, &GameState::onStartedChanged);
|
||||
playerManager = new PlayerManager(this, event.player_id(), event.judge(), event.spectator());
|
||||
gameMetaInfo->setStarted(false);
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@ class Game : public AbstractGame
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Game(TabGame *tab,
|
||||
Game(QObject *parent,
|
||||
bool isLocalGame,
|
||||
QList<AbstractClient *> &_clients,
|
||||
const Event_GameJoined &event,
|
||||
const QMap<int, QString> &_roomGameTypes);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#include "game_event_handler.h"
|
||||
|
||||
#include "../game_graphics/log/message_log_widget.h"
|
||||
#include "../interface/widgets/tabs/tab_game.h"
|
||||
#include "abstract_game.h"
|
||||
#include "log/message_log_widget.h"
|
||||
|
||||
#include <libcockatrice/network/client/abstract/abstract_client.h>
|
||||
#include <libcockatrice/protocol/get_pb_extension.h>
|
||||
|
|
|
|||
|
|
@ -1,766 +0,0 @@
|
|||
#include "game_scene.h"
|
||||
|
||||
#include "../client/settings/cache_settings.h"
|
||||
#include "../game_graphics/zones/select_zone.h"
|
||||
#include "../game_graphics/zones/view_zone.h"
|
||||
#include "../game_graphics/zones/view_zone_widget.h"
|
||||
#include "abstract_game.h"
|
||||
#include "board/card_item.h"
|
||||
#include "phases_toolbar.h"
|
||||
#include "player/player_actions.h"
|
||||
#include "player/player_graphics_item.h"
|
||||
#include "player/player_logic.h"
|
||||
|
||||
#include <QBasicTimer>
|
||||
#include <QDebug>
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QGraphicsView>
|
||||
#include <QSet>
|
||||
#include <QtMath>
|
||||
#include <libcockatrice/utility/zone_names.h>
|
||||
#include <numeric>
|
||||
|
||||
/**
|
||||
* @brief Constructs the GameScene.
|
||||
* @param _phasesToolbar Toolbar widget for phases.
|
||||
* @param parent Optional parent QObject.
|
||||
*
|
||||
* Initializes the animation timer, adds the phases toolbar to the scene,
|
||||
* and connects to settings changes for multi-column layout.
|
||||
* Finally, calls rearrange() to layout players initially.
|
||||
*/
|
||||
GameScene::GameScene(PhasesToolbar *_phasesToolbar, QObject *parent)
|
||||
: QGraphicsScene(parent), phasesToolbar(_phasesToolbar), viewSize(QSize()), playerRotation(0)
|
||||
{
|
||||
animationTimer = new QBasicTimer;
|
||||
addItem(phasesToolbar);
|
||||
connect(&SettingsCache::instance(), &SettingsCache::minPlayersForMultiColumnLayoutChanged, this,
|
||||
&GameScene::rearrange);
|
||||
|
||||
rearrange();
|
||||
}
|
||||
|
||||
GameScene::~GameScene()
|
||||
{
|
||||
delete animationTimer;
|
||||
|
||||
// DO NOT call clearViews() here
|
||||
// clearViews calls close() on the zoneViews, which sends signals; sending signals in destructors leads to segfaults
|
||||
// deleteLater() deletes the zoneView without allowing it to send signals
|
||||
for (const auto &zoneView : zoneViews) {
|
||||
zoneView->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Updates localized text in all zone views.
|
||||
*/
|
||||
void GameScene::retranslateUi()
|
||||
{
|
||||
for (ZoneViewWidget *view : zoneViews) {
|
||||
view->retranslateUi();
|
||||
}
|
||||
}
|
||||
|
||||
QList<CardItem *> GameScene::selectedCards() const
|
||||
{
|
||||
QList<CardItem *> selectedCards;
|
||||
for (auto item : selectedItems()) {
|
||||
if (auto card = qgraphicsitem_cast<CardItem *>(item)) {
|
||||
selectedCards.append(card);
|
||||
}
|
||||
}
|
||||
|
||||
return selectedCards;
|
||||
}
|
||||
|
||||
void GameScene::onCardSelectionChanged(AbstractCardItem *abstractCard, bool selected)
|
||||
{
|
||||
CardItem *card = qobject_cast<CardItem *>(abstractCard);
|
||||
if (!card || !card->getOwner()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto *owner = card->getOwner();
|
||||
|
||||
if (selected) {
|
||||
owner->requestCardMenuUpdate(card);
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedItems().isEmpty()) {
|
||||
owner->getGame()->setActiveCard(nullptr);
|
||||
owner->requestCardMenuUpdate(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void GameScene::onCardRightClicked(AbstractCardItem *abstractCard, QPoint screenPos)
|
||||
{
|
||||
auto *card = qobject_cast<CardItem *>(abstractCard);
|
||||
if (!card) {
|
||||
return;
|
||||
}
|
||||
if (!card->getOwner()) {
|
||||
return;
|
||||
}
|
||||
auto *view = playerViews.value(card->getOwner()->getPlayerInfo()->getId());
|
||||
if (!view) {
|
||||
return;
|
||||
}
|
||||
|
||||
card->getOwner()->getGame()->setActiveCard(card);
|
||||
|
||||
if (auto *menu = view->getPlayerMenu()->updateCardMenu(card)) {
|
||||
menu->popup(screenPos);
|
||||
}
|
||||
}
|
||||
|
||||
void GameScene::playSelected(AbstractCardItem *card)
|
||||
{
|
||||
if (!card) {
|
||||
return;
|
||||
}
|
||||
if (!card->getOwner()) {
|
||||
return;
|
||||
}
|
||||
card->getOwner()->getPlayerActions()->actPlay(selectedCards());
|
||||
}
|
||||
|
||||
void GameScene::playSelectedFaceDown(AbstractCardItem *card)
|
||||
{
|
||||
if (!card) {
|
||||
return;
|
||||
}
|
||||
if (!card->getOwner()) {
|
||||
return;
|
||||
}
|
||||
card->getOwner()->getPlayerActions()->actPlayFacedown(selectedCards());
|
||||
}
|
||||
|
||||
void GameScene::hideSelected(AbstractCardItem *card)
|
||||
{
|
||||
if (!card) {
|
||||
return;
|
||||
}
|
||||
if (!card->getOwner()) {
|
||||
return;
|
||||
}
|
||||
card->getOwner()->getPlayerActions()->actHide(selectedCards());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds a player to the scene and stores their graphics item.
|
||||
* @param player Player to add.
|
||||
*
|
||||
* Connects to the player's sizeChanged signal to recompute layout on resize.
|
||||
*/
|
||||
void GameScene::addPlayer(PlayerLogic *player)
|
||||
{
|
||||
qCInfo(GameScenePlayerAdditionRemovalLog) << "GameScene::addPlayer name=" << player->getPlayerInfo()->getName();
|
||||
|
||||
auto *view = new PlayerGraphicsItem(player);
|
||||
|
||||
playerViews.insert(player->getPlayerInfo()->getId(), view);
|
||||
addItem(view);
|
||||
connect(view, &PlayerGraphicsItem::sizeChanged, this, &GameScene::rearrange);
|
||||
|
||||
connect(player, &PlayerLogic::concededChanged, this, [this](int id, bool conceded) {
|
||||
if (conceded) {
|
||||
clearArrowsForPlayer(id);
|
||||
}
|
||||
rearrange();
|
||||
});
|
||||
|
||||
connect(player, &PlayerLogic::requestZoneViewToggle, this, &GameScene::toggleZoneView);
|
||||
connect(player, &PlayerLogic::requestRevealedZoneView, this, &GameScene::addRevealedZoneView);
|
||||
connect(player, &PlayerLogic::arrowDeleted, this, &GameScene::deleteArrow);
|
||||
connect(player, &PlayerLogic::arrowCreateRequested, this, &GameScene::addArrow);
|
||||
connect(player, &PlayerLogic::arrowDeleteRequested, this, &GameScene::requestArrowDeletion);
|
||||
connect(player, &PlayerLogic::arrowsClearedLocally, this,
|
||||
[this, id = player->getPlayerInfo()->getId()]() { clearArrowsForPlayerLocally(id); });
|
||||
|
||||
connect(player->getPlayerEventHandler(), &PlayerEventHandler::cardZoneChanged, this, &GameScene::onCardZoneChanged);
|
||||
|
||||
rearrange();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes a player from the scene.
|
||||
* @param player Player to remove.
|
||||
*
|
||||
* Closes any zone views associated with the player and recomputes layout.
|
||||
*/
|
||||
void GameScene::removePlayer(PlayerLogic *player)
|
||||
{
|
||||
qCInfo(GameScenePlayerAdditionRemovalLog) << "GameScene::removePlayer name=" << player->getPlayerInfo()->getName();
|
||||
|
||||
clearArrowsForPlayer(player->getPlayerInfo()->getId());
|
||||
|
||||
for (ZoneViewWidget *zone : zoneViews) {
|
||||
if (zone->getPlayer() == player) {
|
||||
zone->close();
|
||||
}
|
||||
}
|
||||
auto *view = playerViews.take(player->getPlayerInfo()->getId());
|
||||
removeItem(view);
|
||||
view->deleteLater();
|
||||
rearrange();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adjusts the global rotation offset for player layout.
|
||||
* @param rotationAdjustment Number of positions to rotate.
|
||||
*
|
||||
* Recomputes player layout after applying rotation.
|
||||
*/
|
||||
void GameScene::adjustPlayerRotation(int rotationAdjustment)
|
||||
{
|
||||
playerRotation += rotationAdjustment;
|
||||
rearrange();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Recomputes the layout of players and the scene size.
|
||||
*
|
||||
* Steps:
|
||||
* 1. Collect active players who haven't conceded.
|
||||
* 2. Rotate player list based on first local player and rotation offset.
|
||||
* 3. Determine number of columns.
|
||||
* 4. Compute scene size and layout.
|
||||
* 5. Update toolbar height and scene rectangle.
|
||||
* 6. Adjust columns and player positions to match view size.
|
||||
*/
|
||||
void GameScene::rearrange()
|
||||
{
|
||||
int firstPlayerIndex = 0;
|
||||
auto playersPlaying = collectActivePlayers(firstPlayerIndex);
|
||||
playersPlaying = rotatePlayers(playersPlaying, firstPlayerIndex);
|
||||
|
||||
int columns = determineColumnCount(playersPlaying.size());
|
||||
QSizeF sceneSize = computeSceneSizeAndPlayerLayout(playersPlaying, columns);
|
||||
|
||||
phasesToolbar->setHeight(sceneSize.height());
|
||||
setSceneRect(0, 0, sceneSize.width(), sceneSize.height());
|
||||
|
||||
processViewSizeChange(viewSize);
|
||||
}
|
||||
|
||||
// ---------- View Size ----------
|
||||
|
||||
/**
|
||||
* @brief Handles view resize and redistributes player positions.
|
||||
* @param newSize New view size.
|
||||
*
|
||||
* Steps:
|
||||
* 1. Compute minimum width per column from player items.
|
||||
* 2. Determine new scene width respecting aspect ratio.
|
||||
* 3. Resize columns and reposition players proportionally.
|
||||
*/
|
||||
void GameScene::processViewSizeChange(const QSize &newSize)
|
||||
{
|
||||
viewSize = newSize;
|
||||
|
||||
QList<qreal> minWidthByColumn = calculateMinWidthByColumn();
|
||||
qreal minWidth = std::accumulate(minWidthByColumn.begin(), minWidthByColumn.end(), phasesToolbar->getWidth());
|
||||
|
||||
qreal newWidth = calculateNewSceneWidth(newSize, minWidth);
|
||||
setSceneRect(0, 0, newWidth, sceneRect().height());
|
||||
|
||||
resizeColumnsAndPlayers(minWidthByColumn, newWidth);
|
||||
}
|
||||
|
||||
// ---------- Player Layout Helpers ----------
|
||||
|
||||
/**
|
||||
* @brief Collects all active (non-conceded) players.
|
||||
* @param firstPlayerIndex Output index of first local player.
|
||||
* @return List of active players.
|
||||
*
|
||||
* Used to determine rotation and layout order.
|
||||
*/
|
||||
QList<PlayerLogic *> GameScene::collectActivePlayers(int &firstPlayerIndex) const
|
||||
{
|
||||
QList<PlayerLogic *> activePlayers;
|
||||
firstPlayerIndex = 0;
|
||||
bool firstPlayerFound = false;
|
||||
|
||||
for (auto *pgItem : playerViews.values()) {
|
||||
PlayerLogic *p = pgItem->getLogic();
|
||||
if (p && !p->getConceded()) {
|
||||
activePlayers.append(p);
|
||||
if (!firstPlayerFound && p->getPlayerInfo()->getLocal()) {
|
||||
firstPlayerIndex = activePlayers.size() - 1;
|
||||
firstPlayerFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return activePlayers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Rotates the list of players for layout.
|
||||
* @param players Original list of players.
|
||||
* @param firstPlayerIndex Index of first local player.
|
||||
* @return Rotated list.
|
||||
*
|
||||
* Applies rotation offset and ensures the list wraps correctly.
|
||||
*/
|
||||
QList<PlayerLogic *> GameScene::rotatePlayers(const QList<PlayerLogic *> &activePlayers, int firstPlayerIndex) const
|
||||
{
|
||||
QList<PlayerLogic *> rotated = activePlayers;
|
||||
if (!rotated.isEmpty()) {
|
||||
int totalRotation = firstPlayerIndex + playerRotation;
|
||||
while (totalRotation < 0) {
|
||||
totalRotation += rotated.size();
|
||||
}
|
||||
for (int i = 0; i < totalRotation; ++i) {
|
||||
rotated.append(rotated.takeFirst());
|
||||
}
|
||||
}
|
||||
return rotated;
|
||||
}
|
||||
|
||||
int GameScene::determineColumnCount(int playerCount)
|
||||
{
|
||||
return playerCount < SettingsCache::instance().getMinPlayersForMultiColumnLayout() ? 1 : 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Computes layout positions and scene size based on players and columns.
|
||||
* @param playersPlaying List of active players.
|
||||
* @param columns Number of columns to split into.
|
||||
* @return Calculated scene size.
|
||||
*
|
||||
* Logic:
|
||||
* - Determine rows per column (rounding up).
|
||||
* - Calculate column widths based on widest player item.
|
||||
* - Accumulate scene width and height.
|
||||
* - Position players in columns with spacing.
|
||||
* - Mirror graphics for visual balance.
|
||||
*/
|
||||
QSizeF GameScene::computeSceneSizeAndPlayerLayout(const QList<PlayerLogic *> &playersPlaying, int columns)
|
||||
{
|
||||
playersByColumn.clear();
|
||||
|
||||
int rows = qCeil((qreal)playersPlaying.size() / columns);
|
||||
qreal sceneHeight = 0, sceneWidth = -playerAreaSpacing;
|
||||
QList<int> columnWidth;
|
||||
|
||||
QListIterator<PlayerLogic *> playersIter(playersPlaying);
|
||||
for (int col = 0; col < columns; ++col) {
|
||||
playersByColumn.append(QList<PlayerGraphicsItem *>());
|
||||
columnWidth.append(0);
|
||||
qreal thisColumnHeight = -playerAreaSpacing;
|
||||
int rowsInColumn = rows - (playersPlaying.size() % columns) * col; // Adjust rows for uneven columns
|
||||
|
||||
for (int j = 0; j < rowsInColumn; ++j) {
|
||||
PlayerLogic *player = playersIter.next();
|
||||
if (col == 0) {
|
||||
playersByColumn[col].prepend(playerViews.value(player->getPlayerInfo()->getId()));
|
||||
} else {
|
||||
playersByColumn[col].append(playerViews.value(player->getPlayerInfo()->getId()));
|
||||
}
|
||||
|
||||
auto *pgItem = playerViews.value(player->getPlayerInfo()->getId());
|
||||
thisColumnHeight += pgItem->boundingRect().height() + playerAreaSpacing;
|
||||
columnWidth[col] = std::max(columnWidth[col], (int)pgItem->boundingRect().width());
|
||||
}
|
||||
|
||||
sceneHeight = std::max(sceneHeight, thisColumnHeight);
|
||||
sceneWidth += columnWidth[col] + playerAreaSpacing;
|
||||
}
|
||||
|
||||
qreal phasesWidth = phasesToolbar->getWidth();
|
||||
sceneWidth += phasesWidth;
|
||||
|
||||
// Position players horizontally and vertically
|
||||
qreal x = phasesWidth;
|
||||
for (int col = 0; col < columns; ++col) {
|
||||
qreal y = 0;
|
||||
for (int row = 0; row < playersByColumn[col].size(); ++row) {
|
||||
PlayerGraphicsItem *player = playersByColumn[col][row];
|
||||
player->setPos(x, y);
|
||||
player->setMirrored(row != rows - 1); // Mirror all except bottom-most
|
||||
y += player->boundingRect().height() + playerAreaSpacing;
|
||||
}
|
||||
x += columnWidth[col] + playerAreaSpacing;
|
||||
}
|
||||
|
||||
return QSizeF(sceneWidth, sceneHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Computes the minimum width for each column based on player minimum widths.
|
||||
* @return List of minimum widths per column.
|
||||
*/
|
||||
QList<qreal> GameScene::calculateMinWidthByColumn() const
|
||||
{
|
||||
QList<qreal> minWidthByColumn;
|
||||
for (const auto &col : playersByColumn) {
|
||||
qreal maxWidth = 0;
|
||||
for (PlayerGraphicsItem *player : col) {
|
||||
maxWidth = std::max(maxWidth, player->getMinimumWidth());
|
||||
}
|
||||
minWidthByColumn.append(maxWidth);
|
||||
}
|
||||
return minWidthByColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates new scene width considering window aspect ratio.
|
||||
* @param newSize View size.
|
||||
* @param minWidth Minimum width needed to fit all players.
|
||||
* @return Scene width respecting window and content.
|
||||
*/
|
||||
qreal GameScene::calculateNewSceneWidth(const QSize &newSize, qreal minWidth) const
|
||||
{
|
||||
qreal newRatio = (qreal)newSize.width() / newSize.height();
|
||||
qreal minRatio = minWidth / sceneRect().height();
|
||||
|
||||
if (minRatio > newRatio) {
|
||||
return minWidth; // Table dominates width
|
||||
} else {
|
||||
return newRatio * sceneRect().height(); // Window ratio dominates
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resizes columns and distributes extra width to players.
|
||||
* @param minWidthByColumn Minimum widths per column.
|
||||
* @param newWidth Total scene width.
|
||||
*
|
||||
* Extra width is distributed evenly across columns. Each player item is
|
||||
* notified to adjust internal layout for the new column width.
|
||||
*/
|
||||
void GameScene::resizeColumnsAndPlayers(const QList<qreal> &minWidthByColumn, qreal newWidth)
|
||||
{
|
||||
qreal minWidth = std::accumulate(minWidthByColumn.begin(), minWidthByColumn.end(), phasesToolbar->getWidth());
|
||||
|
||||
qreal extraWidthPerColumn = (newWidth - minWidth) / playersByColumn.size();
|
||||
qreal newx = phasesToolbar->getWidth();
|
||||
|
||||
for (int col = 0; col < playersByColumn.size(); ++col) {
|
||||
for (PlayerGraphicsItem *player : playersByColumn[col]) {
|
||||
player->processSceneSizeChange(minWidthByColumn[col] + extraWidthPerColumn);
|
||||
player->setPos(newx, player->y());
|
||||
}
|
||||
newx += minWidthByColumn[col] + extraWidthPerColumn;
|
||||
}
|
||||
}
|
||||
|
||||
void GameScene::addArrow(QSharedPointer<ArrowData> data)
|
||||
{
|
||||
auto *startView = playerViews.value(data->startPlayerId);
|
||||
auto *targetView = playerViews.value(data->targetPlayerId);
|
||||
if (!startView || !targetView) {
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerLogic *startLogic = startView->getLogic();
|
||||
auto *startZone = startLogic->getZones().value(data->startZone);
|
||||
if (!startZone) {
|
||||
return;
|
||||
}
|
||||
|
||||
CardItem *startCard = startZone->getCard(data->startCardId);
|
||||
if (!startCard) {
|
||||
return;
|
||||
}
|
||||
|
||||
ArrowTarget *targetItem = nullptr;
|
||||
if (data->isPlayerTargeted()) {
|
||||
targetItem = targetView->getPlayerTarget();
|
||||
} else {
|
||||
auto *zone = targetView->getLogic()->getZones().value(data->targetZone);
|
||||
if (zone) {
|
||||
targetItem = zone->getCard(data->targetCardId);
|
||||
}
|
||||
}
|
||||
if (!targetItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto *arrow = new ArrowItem(data, startCard, targetItem);
|
||||
addItem(arrow);
|
||||
arrowRegistry.insert(data, arrow);
|
||||
connect(arrow, &ArrowItem::requestDeletion, this, &GameScene::requestArrowDeletion);
|
||||
}
|
||||
|
||||
void GameScene::deleteArrow(int playerId, int arrowId)
|
||||
{
|
||||
if (auto *arrow = arrowRegistry.take(playerId, arrowId)) {
|
||||
arrow->delArrow();
|
||||
}
|
||||
}
|
||||
|
||||
void GameScene::requestArrowDeletion(int playerId, int arrowId)
|
||||
{
|
||||
if (arrowRegistry.contains(playerId, arrowId)) {
|
||||
emit arrowDeletionRequested(playerId, arrowId);
|
||||
}
|
||||
}
|
||||
|
||||
void GameScene::onCardZoneChanged(CardItem *card, bool sameZone)
|
||||
{
|
||||
QList<ArrowItem *> toDelete;
|
||||
for (auto *arrow : arrowRegistry.all()) {
|
||||
if (arrow->getStartItem() == card || arrow->getTargetItem() == card) {
|
||||
if (sameZone) {
|
||||
arrow->updatePath();
|
||||
} else {
|
||||
toDelete.append(arrow);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto *arrow : toDelete) {
|
||||
deleteArrow(arrow->getCreatorId(), arrow->getId());
|
||||
}
|
||||
}
|
||||
|
||||
void GameScene::clearArrowsForPlayer(int playerId)
|
||||
{
|
||||
for (int arrowId : arrowRegistry.idsForPlayer(playerId)) {
|
||||
emit requestArrowDeletion(playerId, arrowId);
|
||||
}
|
||||
}
|
||||
|
||||
void GameScene::clearArrowsForPlayerLocally(int playerId)
|
||||
{
|
||||
for (int arrowId : arrowRegistry.idsForPlayer(playerId)) {
|
||||
arrowRegistry.take(playerId, arrowId)->delArrow();
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- Hover Handling ----------
|
||||
|
||||
void GameScene::updateHover(const QPointF &scenePos)
|
||||
{
|
||||
auto itemList = items(scenePos, Qt::IntersectsItemBoundingRect, Qt::DescendingOrder, getViewTransform());
|
||||
|
||||
CardZone *zone = findTopmostZone(itemList);
|
||||
CardItem *topCard = zone ? findTopmostCardInZone(itemList, zone) : nullptr;
|
||||
updateHoveredCard(topCard);
|
||||
}
|
||||
|
||||
void GameScene::updateHoveredCard(CardItem *newCard)
|
||||
{
|
||||
if (hoveredCard && (newCard != hoveredCard)) {
|
||||
endCardHover(hoveredCard);
|
||||
}
|
||||
if (newCard && (newCard != hoveredCard)) {
|
||||
beginCardHover(newCard);
|
||||
}
|
||||
hoveredCard = newCard;
|
||||
}
|
||||
|
||||
void GameScene::beginCardHover(CardItem *card)
|
||||
{
|
||||
card->setHovered(true);
|
||||
if (auto *zone = SelectZone::findOwningSelectZone(card)) {
|
||||
zone->escapeClipForHover(card);
|
||||
}
|
||||
}
|
||||
|
||||
void GameScene::endCardHover(CardItem *card)
|
||||
{
|
||||
if (auto *zone = SelectZone::findOwningSelectZone(card)) {
|
||||
zone->restoreClipAfterHover(card);
|
||||
}
|
||||
card->setHovered(false);
|
||||
}
|
||||
|
||||
CardZone *GameScene::findTopmostZone(const QList<QGraphicsItem *> &items)
|
||||
{
|
||||
for (QGraphicsItem *item : items) {
|
||||
if (auto *zone = qgraphicsitem_cast<CardZone *>(item)) {
|
||||
return zone;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CardItem *GameScene::findTopmostCardInZone(const QList<QGraphicsItem *> &items, CardZone *zone)
|
||||
{
|
||||
CardItem *maxZCard = nullptr;
|
||||
qreal maxZ = -1;
|
||||
|
||||
for (QGraphicsItem *item : items) {
|
||||
CardItem *card = qgraphicsitem_cast<CardItem *>(item);
|
||||
if (!card) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (card->getAttachedTo()) {
|
||||
if (card->getAttachedTo()->getZone() != zone->getLogic()) {
|
||||
continue;
|
||||
}
|
||||
} else if (card->getZone() != zone->getLogic()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (card->getRealZValue() > maxZ) {
|
||||
maxZ = card->getRealZValue();
|
||||
maxZCard = card;
|
||||
}
|
||||
}
|
||||
return maxZCard;
|
||||
}
|
||||
|
||||
// ---------- Zone Views ----------
|
||||
|
||||
/**
|
||||
* @brief Toggles a zone view for a player.
|
||||
* @param player Player owning the zone.
|
||||
* @param zoneName Name of the zone.
|
||||
* @param numberCards Number of cards visible in the view.
|
||||
* @param isReversed Whether the zone view is reversed.
|
||||
*
|
||||
* If an identical view exists, it is closed. Otherwise, a new ZoneViewWidget is created
|
||||
* and positioned based on zone type.
|
||||
*/
|
||||
void GameScene::toggleZoneView(PlayerLogic *player, const QString &zoneName, int numberCards, bool isReversed)
|
||||
{
|
||||
for (auto &view : zoneViews) {
|
||||
ZoneViewZone *temp = view->getZone();
|
||||
if (temp->getLogic()->getName() == zoneName && temp->getLogic()->getPlayer() == player &&
|
||||
qobject_cast<ZoneViewZoneLogic *>(temp->getLogic())->getNumberCards() == numberCards) {
|
||||
view->close();
|
||||
}
|
||||
}
|
||||
|
||||
ZoneViewWidget *item =
|
||||
new ZoneViewWidget(player, player->getZones().value(zoneName), numberCards, false, false, {}, isReversed);
|
||||
|
||||
zoneViews.append(item);
|
||||
connect(item, &ZoneViewWidget::closePressed, this, &GameScene::removeZoneView);
|
||||
addItem(item);
|
||||
|
||||
if (zoneName == ZoneNames::GRAVE) {
|
||||
item->setPos(360, 100);
|
||||
} else if (zoneName == ZoneNames::EXILE) {
|
||||
item->setPos(380, 120);
|
||||
} else {
|
||||
item->setPos(340, 80);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds a revealed zone view (for shown cards).
|
||||
* @param player Owning player.
|
||||
* @param zone Zone logic.
|
||||
* @param cardList List of cards to show.
|
||||
* @param withWritePermission Whether edits are allowed.
|
||||
*/
|
||||
void GameScene::addRevealedZoneView(PlayerLogic *player,
|
||||
CardZoneLogic *zone,
|
||||
const QList<const ServerInfo_Card *> &cardList,
|
||||
bool withWritePermission)
|
||||
{
|
||||
ZoneViewWidget *item = new ZoneViewWidget(player, zone, -2, true, withWritePermission, cardList);
|
||||
zoneViews.append(item);
|
||||
connect(item, &ZoneViewWidget::closePressed, this, &GameScene::removeZoneView);
|
||||
addItem(item);
|
||||
item->setPos(600, 80);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes a zone view widget from the scene.
|
||||
* @param item Zone view to remove.
|
||||
*/
|
||||
void GameScene::removeZoneView(ZoneViewWidget *item)
|
||||
{
|
||||
zoneViews.removeOne(item);
|
||||
removeItem(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Closes all zone views.
|
||||
*/
|
||||
void GameScene::clearViews()
|
||||
{
|
||||
while (!zoneViews.isEmpty()) {
|
||||
zoneViews.first()->close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Closes the most recently added zone view.
|
||||
*/
|
||||
void GameScene::closeMostRecentZoneView()
|
||||
{
|
||||
if (!zoneViews.isEmpty()) {
|
||||
zoneViews.last()->close();
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- View Transforms ----------
|
||||
|
||||
QTransform GameScene::getViewTransform() const
|
||||
{
|
||||
return views().at(0)->transform();
|
||||
}
|
||||
|
||||
QTransform GameScene::getViewportTransform() const
|
||||
{
|
||||
return views().at(0)->viewportTransform();
|
||||
}
|
||||
|
||||
// ---------- Event Handling ----------
|
||||
|
||||
bool GameScene::event(QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::GraphicsSceneMouseMove) {
|
||||
updateHover(static_cast<QGraphicsSceneMouseEvent *>(event)->scenePos());
|
||||
} else if (event->type() == QEvent::Leave) {
|
||||
updateHoveredCard(nullptr);
|
||||
}
|
||||
|
||||
return QGraphicsScene::event(event);
|
||||
}
|
||||
|
||||
void GameScene::timerEvent(QTimerEvent * /*event*/)
|
||||
{
|
||||
QMutableSetIterator<CardItem *> i(cardsToAnimate);
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
if (!i.value()->animationEvent()) {
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
if (cardsToAnimate.isEmpty()) {
|
||||
animationTimer->stop();
|
||||
}
|
||||
}
|
||||
|
||||
void GameScene::registerAnimationItem(AbstractCardItem *card)
|
||||
{
|
||||
cardsToAnimate.insert(static_cast<CardItem *>(card));
|
||||
if (!animationTimer->isActive()) {
|
||||
animationTimer->start(10, this);
|
||||
}
|
||||
}
|
||||
|
||||
void GameScene::unregisterAnimationItem(AbstractCardItem *card)
|
||||
{
|
||||
cardsToAnimate.remove(static_cast<CardItem *>(card));
|
||||
if (cardsToAnimate.isEmpty()) {
|
||||
animationTimer->stop();
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- Rubber Band ----------
|
||||
|
||||
void GameScene::startRubberBand(const QPointF &selectionOrigin)
|
||||
{
|
||||
emit sigStartRubberBand(selectionOrigin);
|
||||
}
|
||||
|
||||
void GameScene::resizeRubberBand(const QPointF &cursorPoint, int selectedCount)
|
||||
{
|
||||
emit sigResizeRubberBand(cursorPoint, selectedCount);
|
||||
}
|
||||
|
||||
void GameScene::stopRubberBand()
|
||||
{
|
||||
emit sigStopRubberBand();
|
||||
}
|
||||
|
|
@ -1,245 +0,0 @@
|
|||
#ifndef GAMESCENE_H
|
||||
#define GAMESCENE_H
|
||||
|
||||
#include "arrow_registry.h"
|
||||
#include "board/arrow_data.h"
|
||||
#include "board/arrow_item.h"
|
||||
#include "zones/card_zone_logic.h"
|
||||
|
||||
#include <QGraphicsScene>
|
||||
#include <QList>
|
||||
#include <QLoggingCategory>
|
||||
#include <QPointer>
|
||||
#include <QSet>
|
||||
|
||||
inline Q_LOGGING_CATEGORY(GameSceneLog, "game_scene");
|
||||
inline Q_LOGGING_CATEGORY(GameScenePlayerAdditionRemovalLog, "game_scene.player_addition_removal");
|
||||
|
||||
class PlayerLogic;
|
||||
class PlayerGraphicsItem;
|
||||
class ZoneViewWidget;
|
||||
class CardZone;
|
||||
class AbstractCardItem;
|
||||
class CardItem;
|
||||
class ServerInfo_Card;
|
||||
class PhasesToolbar;
|
||||
class QBasicTimer;
|
||||
|
||||
/**
|
||||
* @class GameScene
|
||||
* @ingroup GameGraphics
|
||||
* @brief Manages the game board display including players, zones, cards, and animations.
|
||||
*
|
||||
* GameScene handles:
|
||||
* - Dynamic arrangement of players in columns/rows.
|
||||
* - Player rotation adjustments.
|
||||
* - Zone views for cards (e.g., graveyard, library, revealed zones).
|
||||
* - Hover and animation handling for cards.
|
||||
* - Scene resizing and responsive layout.
|
||||
*/
|
||||
class GameScene : public QGraphicsScene
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
static const int playerAreaSpacing = 5; ///< Space between player areas
|
||||
|
||||
PhasesToolbar *phasesToolbar; ///< Toolbar showing game phases
|
||||
QMap<int, PlayerGraphicsItem *> playerViews; ///< ID lookup for player graphics items
|
||||
QList<QList<PlayerGraphicsItem *>> playersByColumn; ///< Players organized by column
|
||||
ArrowRegistry arrowRegistry; ///< ID registry for arrow graphics items
|
||||
QList<ZoneViewWidget *> zoneViews; ///< Active zone view widgets
|
||||
QSize viewSize; ///< Current view size
|
||||
QPointer<CardItem> hoveredCard; ///< Currently hovered card
|
||||
QBasicTimer *animationTimer; ///< Timer for card animations
|
||||
QSet<CardItem *> cardsToAnimate; ///< Cards currently animating
|
||||
int playerRotation; ///< Rotation offset for player layout
|
||||
|
||||
/**
|
||||
* @brief Updates which card is currently hovered based on scene coordinates.
|
||||
* @param scenePos Scene position of the cursor.
|
||||
*/
|
||||
void updateHover(const QPointF &scenePos);
|
||||
|
||||
/**
|
||||
* @brief Activates hover state and escapes the card from its clip container
|
||||
* so hover scaling is visible beyond zone bounds.
|
||||
*/
|
||||
void beginCardHover(CardItem *card);
|
||||
/** @brief Deactivates hover state and restores the card to its clip container. */
|
||||
void endCardHover(CardItem *card);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs the GameScene.
|
||||
* @param _phasesToolbar Toolbar widget for phases.
|
||||
* @param parent Optional parent QObject.
|
||||
*/
|
||||
explicit GameScene(PhasesToolbar *_phasesToolbar, QObject *parent = nullptr);
|
||||
|
||||
/** @brief Destructor, cleans up timer and zone views. */
|
||||
~GameScene() override;
|
||||
|
||||
/** @brief Updates UI text for all zone views. */
|
||||
void retranslateUi();
|
||||
|
||||
/** @brief Gets all selected CardItems. */
|
||||
QList<CardItem *> selectedCards() const;
|
||||
|
||||
/**
|
||||
* @brief Adds a player to the scene and stores their graphics item.
|
||||
* @param player Player to add.
|
||||
*/
|
||||
void addPlayer(PlayerLogic *player);
|
||||
|
||||
/**
|
||||
* @brief Removes a player from the scene.
|
||||
* @param player Player to remove.
|
||||
*/
|
||||
void removePlayer(PlayerLogic *player);
|
||||
|
||||
QMap<int, PlayerGraphicsItem *> getPlayers() const
|
||||
{
|
||||
return playerViews;
|
||||
}
|
||||
|
||||
PlayerGraphicsItem *viewForPlayer(int playerId)
|
||||
{
|
||||
return playerViews.value(playerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adjusts the global rotation offset for player layout.
|
||||
* @param rotationAdjustment Number of positions to rotate.
|
||||
*/
|
||||
void adjustPlayerRotation(int rotationAdjustment);
|
||||
|
||||
/** @brief Recomputes the layout of players and the scene size. */
|
||||
void rearrange();
|
||||
|
||||
/**
|
||||
* @brief Handles view resize and redistributes player positions.
|
||||
* @param newSize New view size.
|
||||
*/
|
||||
void processViewSizeChange(const QSize &newSize);
|
||||
|
||||
/**
|
||||
* @brief Collects all active (non-conceded) players.
|
||||
* @param firstPlayerIndex Output index of first local player.
|
||||
* @return List of active players.
|
||||
*/
|
||||
QList<PlayerLogic *> collectActivePlayers(int &firstPlayerIndex) const;
|
||||
|
||||
/**
|
||||
* @brief Rotates the list of players for layout.
|
||||
* @param players Original list of players.
|
||||
* @param firstPlayerIndex Index of first local player.
|
||||
* @return Rotated list.
|
||||
*/
|
||||
QList<PlayerLogic *> rotatePlayers(const QList<PlayerLogic *> &players, int firstPlayerIndex) const;
|
||||
|
||||
/**
|
||||
* @brief Determines the number of columns to display players in.
|
||||
* @param playerCount Total number of active players.
|
||||
* @return Number of columns (1 or 2).
|
||||
*/
|
||||
static int determineColumnCount(int playerCount);
|
||||
|
||||
/**
|
||||
* @brief Computes layout positions and scene size based on players and columns.
|
||||
* @param playersPlaying List of active players.
|
||||
* @param columns Number of columns to split into.
|
||||
* @return Calculated scene size.
|
||||
*/
|
||||
QSizeF computeSceneSizeAndPlayerLayout(const QList<PlayerLogic *> &playersPlaying, int columns);
|
||||
|
||||
/**
|
||||
* @brief Computes the minimum width for each column based on player minimum widths.
|
||||
* @return List of minimum widths per column.
|
||||
*/
|
||||
QList<qreal> calculateMinWidthByColumn() const;
|
||||
|
||||
/**
|
||||
* @brief Calculates new scene width considering window aspect ratio.
|
||||
* @param newSize View size.
|
||||
* @param minWidth Minimum width needed to fit all players.
|
||||
* @return Scene width respecting window and content.
|
||||
*/
|
||||
qreal calculateNewSceneWidth(const QSize &newSize, qreal minWidth) const;
|
||||
|
||||
/**
|
||||
* @brief Resizes columns and distributes extra width to players.
|
||||
* @param minWidthByColumn Minimum widths per column.
|
||||
* @param newWidth Total scene width.
|
||||
*/
|
||||
void resizeColumnsAndPlayers(const QList<qreal> &minWidthByColumn, qreal newWidth);
|
||||
|
||||
/** @brief Finds the topmost card zone under the cursor. */
|
||||
static CardZone *findTopmostZone(const QList<QGraphicsItem *> &items);
|
||||
|
||||
/** @brief Finds the topmost card in a given zone, considering attachments and Z-order. */
|
||||
static CardItem *findTopmostCardInZone(const QList<QGraphicsItem *> &items, CardZone *zone);
|
||||
|
||||
/** @brief Updates hovered card highlighting. */
|
||||
void updateHoveredCard(CardItem *newCard);
|
||||
|
||||
/** @brief Registers a card for animation updates. */
|
||||
void registerAnimationItem(AbstractCardItem *card);
|
||||
|
||||
/** @brief Unregisters a card from animation updates. */
|
||||
void unregisterAnimationItem(AbstractCardItem *card);
|
||||
void startRubberBand(const QPointF &selectionOrigin);
|
||||
void resizeRubberBand(const QPointF &cursorPoint, int selectedCount);
|
||||
void stopRubberBand();
|
||||
|
||||
public slots:
|
||||
void onCardSelectionChanged(AbstractCardItem *card, bool selected);
|
||||
void onCardRightClicked(AbstractCardItem *card, QPoint screenPos);
|
||||
void playSelected(AbstractCardItem *card);
|
||||
void playSelectedFaceDown(AbstractCardItem *card);
|
||||
void hideSelected(AbstractCardItem *card);
|
||||
/** @brief Toggles a zone view for a player. */
|
||||
void toggleZoneView(PlayerLogic *player, const QString &zoneName, int numberCards, bool isReversed = false);
|
||||
|
||||
/** @brief Adds a revealed zone view (for shown cards). */
|
||||
void addRevealedZoneView(PlayerLogic *player,
|
||||
CardZoneLogic *zone,
|
||||
const QList<const ServerInfo_Card *> &cardList,
|
||||
bool withWritePermission);
|
||||
|
||||
/** @brief Removes a zone view widget from the scene. */
|
||||
void removeZoneView(ZoneViewWidget *item);
|
||||
|
||||
/** @brief Closes all zone views. */
|
||||
void clearViews();
|
||||
|
||||
/** @brief Closes the most recently added zone view. */
|
||||
void closeMostRecentZoneView();
|
||||
QTransform getViewTransform() const;
|
||||
QTransform getViewportTransform() const;
|
||||
|
||||
/// Directly modifies the scene
|
||||
void addArrow(QSharedPointer<ArrowData> data);
|
||||
void deleteArrow(int playerId, int arrowId);
|
||||
void clearArrowsForPlayer(int playerId);
|
||||
void clearArrowsForPlayerLocally(int playerId);
|
||||
|
||||
/// Queues up arrow deletion but doesn't directly modify the scene
|
||||
void requestArrowDeletion(int playerId, int arrowId);
|
||||
|
||||
void onCardZoneChanged(CardItem *card, bool sameZone);
|
||||
|
||||
protected:
|
||||
/** @brief Handles hover updates. */
|
||||
bool event(QEvent *event) override;
|
||||
|
||||
/** @brief Handles animation timer updates. */
|
||||
void timerEvent(QTimerEvent *event) override;
|
||||
|
||||
signals:
|
||||
void sigStartRubberBand(const QPointF &selectionOrigin);
|
||||
void sigResizeRubberBand(const QPointF &cursorPoint, int selectedCount);
|
||||
void sigStopRubberBand();
|
||||
void arrowDeletionRequested(int creatorId, int arrowId);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,188 +0,0 @@
|
|||
#include "game_view.h"
|
||||
|
||||
#include "../client/settings/cache_settings.h"
|
||||
#include "game_scene.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QLabel>
|
||||
#include <QResizeEvent>
|
||||
#include <QRubberBand>
|
||||
|
||||
// QRubberBand calls raise() in showEvent() and changeEvent() to stay on top of siblings.
|
||||
// This subclass disables that behavior so dragCountLabel can appear above it.
|
||||
class SelectionRubberBand : public QRubberBand
|
||||
{
|
||||
public:
|
||||
using QRubberBand::QRubberBand;
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *event) override
|
||||
{
|
||||
QWidget::showEvent(event); // Skip QRubberBand's raise()
|
||||
}
|
||||
|
||||
void changeEvent(QEvent *event) override
|
||||
{
|
||||
if (event->type() == QEvent::ZOrderChange) {
|
||||
return; // Skip QRubberBand's raise() on z-order changes
|
||||
}
|
||||
QRubberBand::changeEvent(event);
|
||||
}
|
||||
};
|
||||
|
||||
GameView::GameView(GameScene *scene, QWidget *parent) : QGraphicsView(scene, parent), rubberBand(0)
|
||||
{
|
||||
setBackgroundBrush(QBrush(QColor(0, 0, 0)));
|
||||
setRenderHints(QPainter::TextAntialiasing | QPainter::Antialiasing);
|
||||
setFocusPolicy(Qt::ClickFocus);
|
||||
setViewportUpdateMode(BoundingRectViewportUpdate);
|
||||
|
||||
connect(scene, &GameScene::sceneRectChanged, this, &GameView::updateSceneRect);
|
||||
|
||||
connect(scene, &GameScene::sigStartRubberBand, this, &GameView::startRubberBand);
|
||||
connect(scene, &GameScene::sigResizeRubberBand, this, &GameView::resizeRubberBand);
|
||||
connect(scene, &GameScene::sigStopRubberBand, this, &GameView::stopRubberBand);
|
||||
connect(scene, &QGraphicsScene::selectionChanged, this, [this]() { updateTotalSelectionCount(); });
|
||||
|
||||
aCloseMostRecentZoneView = new QAction(this);
|
||||
|
||||
connect(aCloseMostRecentZoneView, &QAction::triggered, scene, &GameScene::closeMostRecentZoneView);
|
||||
addAction(aCloseMostRecentZoneView);
|
||||
connect(&SettingsCache::instance().shortcuts(), &ShortcutsSettings::shortCutChanged, this,
|
||||
&GameView::refreshShortcuts);
|
||||
refreshShortcuts();
|
||||
rubberBand = new SelectionRubberBand(QRubberBand::Rectangle, this);
|
||||
|
||||
const QString countLabelStyle = "color: white; "
|
||||
"font-size: 14px; "
|
||||
"font-weight: bold; "
|
||||
"background-color: rgba(0, 0, 0, 160); "
|
||||
"border-radius: 3px; "
|
||||
"padding: 1px 2px;";
|
||||
|
||||
dragCountLabel = new QLabel(this);
|
||||
dragCountLabel->setStyleSheet(countLabelStyle);
|
||||
dragCountLabel->hide();
|
||||
dragCountLabel->raise();
|
||||
|
||||
totalCountLabel = new QLabel(this);
|
||||
totalCountLabel->setStyleSheet(countLabelStyle);
|
||||
totalCountLabel->hide();
|
||||
}
|
||||
|
||||
void GameView::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QGraphicsView::resizeEvent(event);
|
||||
|
||||
GameScene *s = dynamic_cast<GameScene *>(scene());
|
||||
if (s) {
|
||||
s->processViewSizeChange(event->size());
|
||||
}
|
||||
|
||||
updateSceneRect(scene()->sceneRect());
|
||||
updateTotalSelectionCount(event->size());
|
||||
}
|
||||
|
||||
void GameView::updateSceneRect(const QRectF &rect)
|
||||
{
|
||||
fitInView(rect, Qt::KeepAspectRatio);
|
||||
}
|
||||
|
||||
void GameView::startRubberBand(const QPointF &_selectionOrigin)
|
||||
{
|
||||
if (!rubberBand) {
|
||||
return;
|
||||
}
|
||||
|
||||
selectionOrigin = _selectionOrigin;
|
||||
rubberBand->setGeometry(QRect(mapFromScene(selectionOrigin), QSize(0, 0)));
|
||||
rubberBand->show();
|
||||
}
|
||||
|
||||
void GameView::resizeRubberBand(const QPointF &cursorPoint, int selectedCount)
|
||||
{
|
||||
if (!rubberBand) {
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr int kLabelPaddingInPixels = 4;
|
||||
|
||||
QPoint cursor = cursorPoint.toPoint();
|
||||
QRect rect = QRect(mapFromScene(selectionOrigin), cursor).normalized();
|
||||
rubberBand->setGeometry(rect);
|
||||
|
||||
if (!SettingsCache::instance().getShowDragSelectionCount()) {
|
||||
dragCountLabel->hide();
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedCount > 0) {
|
||||
dragCountLabel->setText(QString::number(selectedCount));
|
||||
dragCountLabel->adjustSize();
|
||||
QSize labelSize = dragCountLabel->size();
|
||||
|
||||
if (rect.width() < labelSize.width() + 2 * kLabelPaddingInPixels ||
|
||||
rect.height() < labelSize.height() + 2 * kLabelPaddingInPixels) {
|
||||
dragCountLabel->hide();
|
||||
return;
|
||||
}
|
||||
|
||||
const int minX = rect.left() + kLabelPaddingInPixels;
|
||||
const int minY = rect.top() + kLabelPaddingInPixels;
|
||||
|
||||
int x = qMax(minX, cursor.x() - labelSize.width() - kLabelPaddingInPixels);
|
||||
int y = qMax(minY, cursor.y() - labelSize.height() - kLabelPaddingInPixels);
|
||||
|
||||
bool isAtTopLeftCorner = (x == minX) && (y == minY);
|
||||
if (isAtTopLeftCorner) {
|
||||
constexpr int kCursorClearanceInPixels = 16;
|
||||
x = qMin(cursor.x() + kCursorClearanceInPixels, rect.right() - labelSize.width() - kLabelPaddingInPixels);
|
||||
}
|
||||
|
||||
dragCountLabel->move(x, y);
|
||||
dragCountLabel->show();
|
||||
} else {
|
||||
dragCountLabel->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void GameView::stopRubberBand()
|
||||
{
|
||||
if (!rubberBand) {
|
||||
return;
|
||||
}
|
||||
|
||||
rubberBand->hide();
|
||||
dragCountLabel->hide();
|
||||
}
|
||||
|
||||
void GameView::refreshShortcuts()
|
||||
{
|
||||
aCloseMostRecentZoneView->setShortcuts(
|
||||
SettingsCache::instance().shortcuts().getShortcut("Player/aCloseMostRecentZoneView"));
|
||||
}
|
||||
|
||||
void GameView::updateTotalSelectionCount(const QSize &viewSize)
|
||||
{
|
||||
if (!SettingsCache::instance().getShowTotalSelectionCount()) {
|
||||
totalCountLabel->hide();
|
||||
return;
|
||||
}
|
||||
|
||||
int count = scene()->selectedItems().count();
|
||||
|
||||
if (count > 1) {
|
||||
totalCountLabel->setText(QString::number(count));
|
||||
totalCountLabel->adjustSize();
|
||||
|
||||
constexpr int kMarginInPixels = 10;
|
||||
int availableWidth = viewSize.isValid() ? viewSize.width() : viewport()->width();
|
||||
int availableHeight = viewSize.isValid() ? viewSize.height() : viewport()->height();
|
||||
int x = availableWidth - totalCountLabel->width() - kMarginInPixels;
|
||||
int y = availableHeight - totalCountLabel->height() - kMarginInPixels;
|
||||
totalCountLabel->move(x, y);
|
||||
totalCountLabel->show();
|
||||
} else {
|
||||
totalCountLabel->hide();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
/**
|
||||
* @file game_view.h
|
||||
* @ingroup GameGraphics
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef GAMEVIEW_H
|
||||
#define GAMEVIEW_H
|
||||
|
||||
#include <QGraphicsView>
|
||||
|
||||
class GameScene;
|
||||
class QLabel;
|
||||
class QRubberBand;
|
||||
|
||||
class GameView : public QGraphicsView
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
QAction *aCloseMostRecentZoneView;
|
||||
QRubberBand *rubberBand;
|
||||
QLabel *dragCountLabel;
|
||||
QLabel *totalCountLabel;
|
||||
QPointF selectionOrigin;
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
private slots:
|
||||
void startRubberBand(const QPointF &selectionOrigin);
|
||||
void resizeRubberBand(const QPointF &cursorPoint, int selectedCount);
|
||||
void stopRubberBand();
|
||||
void refreshShortcuts();
|
||||
void updateTotalSelectionCount(const QSize &viewSize = QSize());
|
||||
public slots:
|
||||
void updateSceneRect(const QRectF &rect);
|
||||
|
||||
public:
|
||||
explicit GameView(GameScene *scene, QWidget *parent = nullptr);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
#include "hand_counter.h"
|
||||
|
||||
#include "../game_graphics/zones/card_zone.h"
|
||||
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QPixmapCache>
|
||||
|
||||
HandCounter::HandCounter(QGraphicsItem *parent) : AbstractGraphicsItem(parent), number(0)
|
||||
{
|
||||
setCacheMode(DeviceCoordinateCache);
|
||||
}
|
||||
|
||||
HandCounter::~HandCounter()
|
||||
{
|
||||
}
|
||||
|
||||
void HandCounter::updateNumber()
|
||||
{
|
||||
number = static_cast<CardZoneLogic *>(sender())->getCards().size();
|
||||
update();
|
||||
}
|
||||
|
||||
QRectF HandCounter::boundingRect() const
|
||||
{
|
||||
return QRectF(0, 0, 72, 72);
|
||||
}
|
||||
|
||||
void HandCounter::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
||||
{
|
||||
painter->save();
|
||||
QSize translatedSize = painter->combinedTransform().mapRect(boundingRect()).size().toSize();
|
||||
QPixmap cachedPixmap;
|
||||
if (!QPixmapCache::find("handCounter" + QString::number(translatedSize.width()), &cachedPixmap)) {
|
||||
cachedPixmap = QPixmap("theme:hand").scaled(translatedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
QPixmapCache::insert("handCounter" + QString::number(translatedSize.width()), cachedPixmap);
|
||||
}
|
||||
resetPainterTransform(painter);
|
||||
painter->drawPixmap(cachedPixmap.rect(), cachedPixmap, cachedPixmap.rect());
|
||||
painter->restore();
|
||||
|
||||
paintNumberEllipse(number, 24, Qt::white, -1, -1, painter);
|
||||
}
|
||||
|
||||
void HandCounter::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
if (event->button() == Qt::RightButton) {
|
||||
emit showContextMenu(event->screenPos());
|
||||
event->accept();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
/**
|
||||
* @file hand_counter.h
|
||||
* @ingroup GameGraphicsPlayers
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef HANDCOUNTER_H
|
||||
#define HANDCOUNTER_H
|
||||
|
||||
#include "../game_graphics/board/abstract_graphics_item.h"
|
||||
#include "../game_graphics/board/graphics_item_type.h"
|
||||
|
||||
#include <QString>
|
||||
|
||||
class QPainter;
|
||||
class QPixmap;
|
||||
|
||||
class HandCounter : public AbstractGraphicsItem
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
int number;
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
public slots:
|
||||
void updateNumber();
|
||||
signals:
|
||||
void showContextMenu(const QPoint &screenPos);
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
Type = typeOther
|
||||
};
|
||||
int type() const override
|
||||
{
|
||||
return Type;
|
||||
}
|
||||
explicit HandCounter(QGraphicsItem *parent = nullptr);
|
||||
~HandCounter() override;
|
||||
QRectF boundingRect() const override;
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,861 +0,0 @@
|
|||
#include "message_log_widget.h"
|
||||
|
||||
#include "../../client/sound_engine.h"
|
||||
#include "../../interface/widgets/tabs/tab_game.h"
|
||||
#include "../board/card_item.h"
|
||||
#include "../board/translate_counter_name.h"
|
||||
#include "../phase.h"
|
||||
#include "../player/player_logic.h"
|
||||
|
||||
#include <../../client/settings/card_counter_settings.h>
|
||||
#include <libcockatrice/protocol/pb/context_move_card.pb.h>
|
||||
#include <libcockatrice/protocol/pb/context_mulligan.pb.h>
|
||||
#include <libcockatrice/utility/zone_names.h>
|
||||
#include <utility>
|
||||
|
||||
static QString sanitizeHtml(QString dirty)
|
||||
{
|
||||
return dirty.replace("&", "&").replace("<", "<").replace(">", ">").replace("\"", """);
|
||||
}
|
||||
|
||||
static QString cardLink(const QString &cardName)
|
||||
{
|
||||
return QString("<i><a href=\"card://%1\">%2</a></i>").arg(cardName).arg(cardName);
|
||||
}
|
||||
|
||||
QPair<QString, QString>
|
||||
MessageLogWidget::getFromStr(CardZoneLogic *zone, QString cardName, int position, bool ownerChange)
|
||||
{
|
||||
bool cardNameContainsStartZone = false;
|
||||
QString fromStr;
|
||||
QString zoneName = zone->getName();
|
||||
|
||||
if (zoneName == ZoneNames::TABLE) {
|
||||
fromStr = tr(" from play");
|
||||
} else if (zoneName == ZoneNames::GRAVE) {
|
||||
fromStr = tr(" from their graveyard");
|
||||
} else if (zoneName == ZoneNames::EXILE) {
|
||||
fromStr = tr(" from exile");
|
||||
} else if (zoneName == ZoneNames::HAND) {
|
||||
fromStr = tr(" from their hand");
|
||||
} else if (zoneName == ZoneNames::DECK) {
|
||||
if (position == 0) {
|
||||
if (cardName.isEmpty()) {
|
||||
if (ownerChange) {
|
||||
cardName = tr("the top card of %1's library").arg(zone->getPlayer()->getPlayerInfo()->getName());
|
||||
} else {
|
||||
cardName = tr("the top card of their library");
|
||||
}
|
||||
cardNameContainsStartZone = true;
|
||||
} else {
|
||||
if (ownerChange) {
|
||||
fromStr = tr(" from the top of %1's library").arg(zone->getPlayer()->getPlayerInfo()->getName());
|
||||
} else {
|
||||
fromStr = tr(" from the top of their library");
|
||||
}
|
||||
}
|
||||
} else if (position == zone->getCards().size()) {
|
||||
if (cardName.isEmpty()) {
|
||||
if (ownerChange) {
|
||||
cardName = tr("the bottom card of %1's library").arg(zone->getPlayer()->getPlayerInfo()->getName());
|
||||
} else {
|
||||
cardName = tr("the bottom card of their library");
|
||||
}
|
||||
cardNameContainsStartZone = true;
|
||||
} else {
|
||||
if (ownerChange) {
|
||||
fromStr = tr(" from the bottom of %1's library").arg(zone->getPlayer()->getPlayerInfo()->getName());
|
||||
} else {
|
||||
fromStr = tr(" from the bottom of their library");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (ownerChange) {
|
||||
fromStr = tr(" from %1's library").arg(zone->getPlayer()->getPlayerInfo()->getName());
|
||||
} else {
|
||||
fromStr = tr(" from their library");
|
||||
}
|
||||
}
|
||||
} else if (zoneName == ZoneNames::SIDEBOARD) {
|
||||
fromStr = tr(" from sideboard");
|
||||
} else if (zoneName == ZoneNames::STACK) {
|
||||
fromStr = tr(" from the stack");
|
||||
} else {
|
||||
fromStr = tr(" from custom zone '%1'").arg(zoneName);
|
||||
}
|
||||
|
||||
if (!cardNameContainsStartZone) {
|
||||
cardName.clear();
|
||||
}
|
||||
return {cardName, fromStr};
|
||||
}
|
||||
|
||||
void MessageLogWidget::containerProcessingDone()
|
||||
{
|
||||
currentContext = MessageContext_None;
|
||||
messageSuffix = messagePrefix = QString();
|
||||
}
|
||||
|
||||
void MessageLogWidget::containerProcessingStarted(const GameEventContext &context)
|
||||
{
|
||||
if (context.HasExtension(Context_MoveCard::ext)) {
|
||||
currentContext = MessageContext_MoveCard;
|
||||
} else if (context.HasExtension(Context_Mulligan::ext)) {
|
||||
currentContext = MessageContext_Mulligan;
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logAlwaysRevealTopCard(PlayerLogic *player, CardZoneLogic *zone, bool reveal)
|
||||
{
|
||||
appendHtmlServerMessage((reveal ? tr("%1 is now keeping the top card %2 revealed.")
|
||||
: tr("%1 is not revealing the top card %2 any longer."))
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(zone->getTranslatedName(true, CaseTopCardsOfZone)));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logAlwaysLookAtTopCard(PlayerLogic *player, CardZoneLogic *zone, bool reveal)
|
||||
{
|
||||
appendHtmlServerMessage((reveal ? tr("%1 can now look at top card %2 at any time.")
|
||||
: tr("%1 no longer can look at top card %2 at any time."))
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(zone->getTranslatedName(true, CaseTopCardsOfZone)));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logAttachCard(PlayerLogic *player,
|
||||
QString cardName,
|
||||
PlayerLogic *targetPlayer,
|
||||
QString targetCardName)
|
||||
{
|
||||
appendHtmlServerMessage(tr("%1 attaches %2 to %3's %4.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(cardLink(std::move(cardName)))
|
||||
.arg(sanitizeHtml(targetPlayer->getPlayerInfo()->getName()))
|
||||
.arg(cardLink(std::move(targetCardName))));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logConcede(int playerId)
|
||||
{
|
||||
soundEngine->playSound("player_concede");
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 has conceded the game.")
|
||||
.arg(sanitizeHtml(game->getPlayerManager()->getPlayer(playerId)->getPlayerInfo()->getName())),
|
||||
true);
|
||||
}
|
||||
|
||||
void MessageLogWidget::logUnconcede(int playerId)
|
||||
{
|
||||
soundEngine->playSound("player_concede");
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 has unconceded the game.")
|
||||
.arg(sanitizeHtml(game->getPlayerManager()->getPlayer(playerId)->getPlayerInfo()->getName())),
|
||||
true);
|
||||
}
|
||||
|
||||
void MessageLogWidget::logConnectionStateChanged(PlayerLogic *player, bool connectionState)
|
||||
{
|
||||
if (connectionState) {
|
||||
soundEngine->playSound("player_reconnect");
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 has restored connection to the game.").arg(sanitizeHtml(player->getPlayerInfo()->getName())), true);
|
||||
} else {
|
||||
soundEngine->playSound("player_disconnect");
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 has lost connection to the game.").arg(sanitizeHtml(player->getPlayerInfo()->getName())), true);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logCreateArrow(PlayerLogic *player,
|
||||
PlayerLogic *startPlayer,
|
||||
QString startCard,
|
||||
PlayerLogic *targetPlayer,
|
||||
QString targetCard,
|
||||
bool playerTarget)
|
||||
{
|
||||
startCard = cardLink(startCard);
|
||||
targetCard = cardLink(targetCard);
|
||||
QString str;
|
||||
if (playerTarget) {
|
||||
if (player == startPlayer && player == targetPlayer) {
|
||||
str = tr("%1 points from their %2 to themselves.");
|
||||
appendHtmlServerMessage(str.arg(sanitizeHtml(player->getPlayerInfo()->getName())).arg(startCard));
|
||||
} else if (player == startPlayer) {
|
||||
str = tr("%1 points from their %2 to %3.");
|
||||
appendHtmlServerMessage(str.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(startCard)
|
||||
.arg(sanitizeHtml(targetPlayer->getPlayerInfo()->getName())));
|
||||
} else if (player == targetPlayer) {
|
||||
str = tr("%1 points from %2's %3 to themselves.");
|
||||
appendHtmlServerMessage(str.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(sanitizeHtml(startPlayer->getPlayerInfo()->getName()))
|
||||
.arg(startCard));
|
||||
} else {
|
||||
str = tr("%1 points from %2's %3 to %4.");
|
||||
appendHtmlServerMessage(str.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(sanitizeHtml(startPlayer->getPlayerInfo()->getName()))
|
||||
.arg(startCard)
|
||||
.arg(sanitizeHtml(targetPlayer->getPlayerInfo()->getName())));
|
||||
}
|
||||
} else {
|
||||
if (player == startPlayer && player == targetPlayer) {
|
||||
str = tr("%1 points from their %2 to their %3.");
|
||||
appendHtmlServerMessage(
|
||||
str.arg(sanitizeHtml(player->getPlayerInfo()->getName())).arg(startCard).arg(targetCard));
|
||||
} else if (player == startPlayer) {
|
||||
str = tr("%1 points from their %2 to %3's %4.");
|
||||
appendHtmlServerMessage(str.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(startCard)
|
||||
.arg(sanitizeHtml(targetPlayer->getPlayerInfo()->getName()))
|
||||
.arg(targetCard));
|
||||
} else if (player == targetPlayer) {
|
||||
str = tr("%1 points from %2's %3 to their own %4.");
|
||||
appendHtmlServerMessage(str.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(sanitizeHtml(startPlayer->getPlayerInfo()->getName()))
|
||||
.arg(startCard)
|
||||
.arg(targetCard));
|
||||
} else {
|
||||
str = tr("%1 points from %2's %3 to %4's %5.");
|
||||
appendHtmlServerMessage(str.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(sanitizeHtml(startPlayer->getPlayerInfo()->getName()))
|
||||
.arg(startCard)
|
||||
.arg(sanitizeHtml(targetPlayer->getPlayerInfo()->getName()))
|
||||
.arg(targetCard));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logCreateToken(PlayerLogic *player, QString cardName, QString pt, bool faceDown)
|
||||
{
|
||||
if (faceDown) {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 creates a face down token.").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
|
||||
} else {
|
||||
appendHtmlServerMessage(tr("%1 creates token: %2%3.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(cardLink(std::move(cardName)))
|
||||
.arg(pt.isEmpty() ? QString() : QString(" (%1)").arg(sanitizeHtml(pt))));
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logDeckSelect(PlayerLogic *player, QString deckHash, int sideboardSize)
|
||||
{
|
||||
if (sideboardSize < 0) {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 has loaded a deck (%2).").arg(sanitizeHtml(player->getPlayerInfo()->getName())).arg(deckHash));
|
||||
} else {
|
||||
appendHtmlServerMessage(tr("%1 has loaded a deck with %2 sideboard cards (%3).")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg("<font class=\"blue\">" + QString::number(sideboardSize) + "</font>")
|
||||
.arg(deckHash));
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logDestroyCard(PlayerLogic *player, QString cardName)
|
||||
{
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 destroys %2.").arg(sanitizeHtml(player->getPlayerInfo()->getName())).arg(cardLink(std::move(cardName))));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logMoveCard(PlayerLogic *player,
|
||||
CardItem *card,
|
||||
CardZoneLogic *startZone,
|
||||
int oldX,
|
||||
CardZoneLogic *targetZone,
|
||||
int newX)
|
||||
{
|
||||
if (currentContext == MessageContext_Mulligan) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString startZoneName = startZone->getName();
|
||||
QString targetZoneName = targetZone->getName();
|
||||
bool ownerChanged = startZone->getPlayer() != targetZone->getPlayer();
|
||||
|
||||
// do not log if moved within the same zone
|
||||
if ((startZoneName == ZoneNames::TABLE && targetZoneName == ZoneNames::TABLE && !ownerChanged) ||
|
||||
(startZoneName == ZoneNames::HAND && targetZoneName == ZoneNames::HAND) ||
|
||||
(startZoneName == ZoneNames::EXILE && targetZoneName == ZoneNames::EXILE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString cardName = card->getName();
|
||||
QPair<QString, QString> nameFrom = getFromStr(startZone, cardName, oldX, ownerChanged);
|
||||
if (!nameFrom.first.isEmpty()) {
|
||||
cardName = nameFrom.first;
|
||||
}
|
||||
|
||||
QString cardStr;
|
||||
if (!nameFrom.first.isEmpty()) {
|
||||
cardStr = cardName;
|
||||
} else if (cardName.isEmpty()) {
|
||||
cardStr = tr("a card");
|
||||
} else {
|
||||
cardStr = cardLink(cardName);
|
||||
}
|
||||
|
||||
if (ownerChanged && (startZone->getPlayer() == player)) {
|
||||
appendHtmlServerMessage(tr("%1 gives %2 control over %3.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(sanitizeHtml(targetZone->getPlayer()->getPlayerInfo()->getName()))
|
||||
.arg(cardStr));
|
||||
return;
|
||||
}
|
||||
|
||||
QString finalStr;
|
||||
std::optional<QString> fourthArg;
|
||||
if (targetZoneName == ZoneNames::TABLE) {
|
||||
soundEngine->playSound("play_card");
|
||||
if (card->getFaceDown()) {
|
||||
finalStr = tr("%1 puts %2 into play%3 face down.");
|
||||
} else {
|
||||
finalStr = tr("%1 puts %2 into play%3.");
|
||||
}
|
||||
} else if (targetZoneName == ZoneNames::GRAVE) {
|
||||
if (card->getFaceDown()) {
|
||||
finalStr = tr("%1 puts %2%3 into their graveyard face down.");
|
||||
} else {
|
||||
finalStr = tr("%1 puts %2%3 into their graveyard.");
|
||||
}
|
||||
} else if (targetZoneName == ZoneNames::EXILE) {
|
||||
if (card->getFaceDown()) {
|
||||
finalStr = tr("%1 exiles %2%3 face down.");
|
||||
} else {
|
||||
finalStr = tr("%1 exiles %2%3.");
|
||||
}
|
||||
} else if (targetZoneName == ZoneNames::HAND) {
|
||||
finalStr = tr("%1 moves %2%3 to their hand.");
|
||||
} else if (targetZoneName == ZoneNames::DECK) {
|
||||
if (newX == -1) {
|
||||
finalStr = tr("%1 puts %2%3 into their library.");
|
||||
} else if (newX >= targetZone->getCards().size()) {
|
||||
finalStr = tr("%1 puts %2%3 onto the bottom of their library.");
|
||||
} else if (newX == 0) {
|
||||
finalStr = tr("%1 puts %2%3 on top of their library.");
|
||||
} else {
|
||||
++newX;
|
||||
fourthArg = QString::number(newX);
|
||||
finalStr = tr("%1 puts %2%3 into their library %4 cards from the top.");
|
||||
}
|
||||
} else if (targetZoneName == ZoneNames::SIDEBOARD) {
|
||||
finalStr = tr("%1 moves %2%3 to sideboard.");
|
||||
} else if (targetZoneName == ZoneNames::STACK) {
|
||||
soundEngine->playSound("play_card");
|
||||
if (card->getFaceDown()) {
|
||||
finalStr = tr("%1 plays %2%3 face down.");
|
||||
} else {
|
||||
finalStr = tr("%1 plays %2%3.");
|
||||
}
|
||||
} else {
|
||||
fourthArg = targetZoneName;
|
||||
if (card->getFaceDown()) {
|
||||
finalStr = tr("%1 moves %2%3 to custom zone '%4' face down.");
|
||||
} else {
|
||||
finalStr = tr("%1 moves %2%3 to custom zone '%4'.");
|
||||
}
|
||||
}
|
||||
|
||||
QString message = finalStr.arg(sanitizeHtml(player->getPlayerInfo()->getName()), cardStr, nameFrom.second);
|
||||
|
||||
if (fourthArg.has_value()) {
|
||||
message = message.arg(fourthArg.value());
|
||||
}
|
||||
|
||||
appendHtmlServerMessage(message);
|
||||
}
|
||||
|
||||
void MessageLogWidget::logDrawCards(PlayerLogic *player, int number, bool deckIsEmpty)
|
||||
{
|
||||
soundEngine->playSound("draw_card");
|
||||
if (currentContext == MessageContext_Mulligan) {
|
||||
logMulligan(player, number);
|
||||
} else {
|
||||
if (deckIsEmpty && number == 0) {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 tries to draw from an empty library").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
|
||||
} else {
|
||||
appendHtmlServerMessage(tr("%1 draws %2 card(s).", "", number)
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg("<font class=\"blue\">" + QString::number(number) + "</font>"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logDumpZone(PlayerLogic *player, CardZoneLogic *zone, int numberCards, bool isReversed)
|
||||
{
|
||||
if (numberCards == -1) {
|
||||
appendHtmlServerMessage(tr("%1 is looking at %2.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(zone->getTranslatedName(zone->getPlayer() == player, CaseLookAtZone)));
|
||||
} else {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 is looking at the %4 %3 card(s) %2.", "top card for singular, top %3 cards for plural", numberCards)
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(zone->getTranslatedName(zone->getPlayer() == player, CaseTopCardsOfZone))
|
||||
.arg("<font class=\"blue\">" + QString::number(numberCards) + "</font>")
|
||||
.arg(isReversed ? tr("bottom") : tr("top")));
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logFlipCard(PlayerLogic *player, QString cardName, bool faceDown)
|
||||
{
|
||||
if (faceDown) {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 turns %2 face-down.").arg(sanitizeHtml(player->getPlayerInfo()->getName())).arg(cardLink(cardName)));
|
||||
} else {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 turns %2 face-up.").arg(sanitizeHtml(player->getPlayerInfo()->getName())).arg(cardLink(cardName)));
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logGameClosed()
|
||||
{
|
||||
appendHtmlServerMessage(tr("The game has been closed."));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logGameStart()
|
||||
{
|
||||
appendHtmlServerMessage(tr("The game has started."));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logGameFlooded()
|
||||
{
|
||||
appendMessage(tr("You are flooding the game. Please wait a couple of seconds."));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logJoin(PlayerLogic *player)
|
||||
{
|
||||
soundEngine->playSound("player_join");
|
||||
appendHtmlServerMessage(tr("%1 has joined the game.").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logJoinSpectator(QString name)
|
||||
{
|
||||
soundEngine->playSound("spectator_join");
|
||||
appendHtmlServerMessage(tr("%1 is now watching the game.").arg(sanitizeHtml(std::move(name))));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logKicked()
|
||||
{
|
||||
appendHtmlServerMessage(tr("You have been kicked out of the game."), true);
|
||||
}
|
||||
|
||||
void MessageLogWidget::logLeave(PlayerLogic *player, QString reason)
|
||||
{
|
||||
soundEngine->playSound("player_leave");
|
||||
appendHtmlServerMessage(tr("%1 has left the game (%2).")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()), sanitizeHtml(std::move(reason))),
|
||||
true);
|
||||
}
|
||||
|
||||
void MessageLogWidget::logLeaveSpectator(QString name, QString reason)
|
||||
{
|
||||
soundEngine->playSound("spectator_leave");
|
||||
appendHtmlServerMessage(tr("%1 is not watching the game any more (%2).")
|
||||
.arg(sanitizeHtml(std::move(name)), sanitizeHtml(std::move(reason))));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logNotReadyStart(PlayerLogic *player)
|
||||
{
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 is not ready to start the game any more.").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logMulligan(PlayerLogic *player, int number)
|
||||
{
|
||||
if (!player) {
|
||||
return;
|
||||
}
|
||||
if (number > 0) {
|
||||
appendHtmlServerMessage(tr("%1 shuffles their deck and draws a new hand of %2 card(s).", "", number)
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(number));
|
||||
} else {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 shuffles their deck and draws a new hand.").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logReplayStarted(int gameId)
|
||||
{
|
||||
appendHtmlServerMessage(tr("You are watching a replay of game #%1.").arg(gameId));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logReadyStart(PlayerLogic *player)
|
||||
{
|
||||
appendHtmlServerMessage(tr("%1 is ready to start the game.").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logRevealCards(PlayerLogic *player,
|
||||
CardZoneLogic *zone,
|
||||
int cardId,
|
||||
QString cardName,
|
||||
PlayerLogic *otherPlayer,
|
||||
bool faceDown,
|
||||
int amount,
|
||||
bool isLentToAnotherPlayer)
|
||||
{
|
||||
// getFromStr uses cardname.empty() to check if it should contain the start zone, it's not actually used
|
||||
QPair<QString, QString> temp = getFromStr(zone, amount == 1 ? cardName : QString::number(amount), cardId, false);
|
||||
bool cardNameContainsStartZone = false;
|
||||
if (!temp.first.isEmpty()) {
|
||||
cardNameContainsStartZone = true;
|
||||
cardName = temp.first;
|
||||
}
|
||||
QString fromStr = temp.second;
|
||||
|
||||
QString cardStr;
|
||||
if (cardNameContainsStartZone) {
|
||||
cardStr = cardName;
|
||||
} else if (cardName.isEmpty()) {
|
||||
if (amount == 0) {
|
||||
cardStr = tr("cards", "an unknown amount of cards");
|
||||
} else {
|
||||
cardStr = tr("%1 card(s)", "a card for singular, %1 cards for plural", amount)
|
||||
.arg("<font class=\"blue\">" + QString::number(amount) + "</font>");
|
||||
}
|
||||
} else {
|
||||
cardStr = cardLink(cardName);
|
||||
}
|
||||
if (cardId == -1) {
|
||||
if (otherPlayer) {
|
||||
if (isLentToAnotherPlayer) {
|
||||
appendHtmlServerMessage(tr("%1 lends %2 to %3.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(zone->getTranslatedName(true, CaseRevealZone))
|
||||
.arg(sanitizeHtml(otherPlayer->getPlayerInfo()->getName())));
|
||||
} else {
|
||||
appendHtmlServerMessage(tr("%1 reveals %2 to %3.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(zone->getTranslatedName(true, CaseRevealZone))
|
||||
.arg(sanitizeHtml(otherPlayer->getPlayerInfo()->getName())));
|
||||
}
|
||||
} else {
|
||||
appendHtmlServerMessage(tr("%1 reveals %2.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(zone->getTranslatedName(true, CaseRevealZone)));
|
||||
}
|
||||
} else if (cardId == -2) {
|
||||
if (otherPlayer) {
|
||||
appendHtmlServerMessage(tr("%1 randomly reveals %2%3 to %4.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(cardStr)
|
||||
.arg(fromStr)
|
||||
.arg(sanitizeHtml(otherPlayer->getPlayerInfo()->getName())));
|
||||
} else {
|
||||
appendHtmlServerMessage(tr("%1 randomly reveals %2%3.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(cardStr)
|
||||
.arg(fromStr));
|
||||
}
|
||||
} else {
|
||||
if (faceDown && player == otherPlayer) {
|
||||
if (cardName.isEmpty()) {
|
||||
appendHtmlServerMessage(tr("%1 peeks at face down card #%2.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(cardId));
|
||||
} else {
|
||||
appendHtmlServerMessage(tr("%1 peeks at face down card #%2: %3.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(cardId)
|
||||
.arg(cardStr));
|
||||
}
|
||||
} else if (otherPlayer) {
|
||||
appendHtmlServerMessage(tr("%1 reveals %2%3 to %4.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(cardStr)
|
||||
.arg(fromStr)
|
||||
.arg(sanitizeHtml(otherPlayer->getPlayerInfo()->getName())));
|
||||
} else {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 reveals %2%3.").arg(sanitizeHtml(player->getPlayerInfo()->getName())).arg(cardStr).arg(fromStr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logReverseTurn(PlayerLogic *player, bool reversed)
|
||||
{
|
||||
appendHtmlServerMessage(tr("%1 reversed turn order, now it's %2.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(reversed ? tr("reversed") : tr("normal")));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logRollDie(PlayerLogic *player, int sides, const QList<uint> &rolls)
|
||||
{
|
||||
if (rolls.length() == 1) {
|
||||
const auto roll = rolls.at(0);
|
||||
if (sides == 2) {
|
||||
QString coinOptions[2] = {tr("Heads") + " (1)", tr("Tails") + " (2)"};
|
||||
appendHtmlServerMessage(tr("%1 flipped a coin. It landed as %2.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg("<font class=\"blue\">" + coinOptions[roll - 1] + "</font>"));
|
||||
} else {
|
||||
appendHtmlServerMessage(tr("%1 rolls a %2 with a %3-sided die.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg("<font class=\"blue\">" + QString::number(roll) + "</font>")
|
||||
.arg("<font class=\"blue\">" + QString::number(sides) + "</font>"));
|
||||
}
|
||||
} else {
|
||||
if (sides == 2) {
|
||||
appendHtmlServerMessage(tr("%1 flips %2 coins. There are %3 heads and %4 tails.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg("<font class=\"blue\">" + QString::number(rolls.length()) + "</font>")
|
||||
.arg("<font class=\"blue\">" + QString::number(rolls.count(1)) + "</font>")
|
||||
.arg("<font class=\"blue\">" + QString::number(rolls.count(2)) + "</font>"));
|
||||
} else {
|
||||
QStringList rollsStrings;
|
||||
for (const auto &roll : rolls) {
|
||||
rollsStrings.append(QString::number(roll));
|
||||
}
|
||||
appendHtmlServerMessage(tr("%1 rolls a %2-sided dice %3 times: %4.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg("<font class=\"blue\">" + QString::number(sides) + "</font>")
|
||||
.arg("<font class=\"blue\">" + QString::number(rolls.length()) + "</font>")
|
||||
.arg("<font class=\"blue\">" + rollsStrings.join(", ") + "</font>"));
|
||||
}
|
||||
}
|
||||
soundEngine->playSound("roll_dice");
|
||||
}
|
||||
|
||||
void MessageLogWidget::logSay(PlayerLogic *player, QString message)
|
||||
{
|
||||
appendMessage(std::move(message), {}, *player->getPlayerInfo()->getUserInfo(), true);
|
||||
}
|
||||
|
||||
void MessageLogWidget::logSetActivePhase(int phaseNumber)
|
||||
{
|
||||
Phase phase = Phases::getPhase(phaseNumber);
|
||||
|
||||
soundEngine->playSound(phase.soundFileName);
|
||||
|
||||
appendHtml("<font color=\"" + phase.color + "\"><b>" + QDateTime::currentDateTime().toString("[hh:mm:ss] ") +
|
||||
phase.getName() + "</b></font>");
|
||||
}
|
||||
|
||||
void MessageLogWidget::logSetActivePlayer(PlayerLogic *player)
|
||||
{
|
||||
appendHtml("<br><font color=\"green\"><b>" + QDateTime::currentDateTime().toString("[hh:mm:ss] ") +
|
||||
QString(tr("%1's turn.")).arg(player->getPlayerInfo()->getName()) + "</b></font><br>");
|
||||
}
|
||||
|
||||
void MessageLogWidget::logSetAnnotation(PlayerLogic *player, CardItem *card, QString newAnnotation)
|
||||
{
|
||||
appendHtmlServerMessage(
|
||||
QString(tr("%1 sets annotation of %2 to %3."))
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(cardLink(card->getName()))
|
||||
.arg(QString(""<font class=\"blue\">%1</font>"").arg(sanitizeHtml(std::move(newAnnotation)))));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logSetCardCounter(PlayerLogic *player, QString cardName, int counterId, int value, int oldValue)
|
||||
{
|
||||
QString finalStr;
|
||||
int delta = abs(oldValue - value);
|
||||
if (value > oldValue) {
|
||||
finalStr = tr("%1 places %2 %3%4 counter(s) on %5 (now %6).", "", delta);
|
||||
} else {
|
||||
finalStr = tr("%1 removes %2 %3%4 counter(s) from %5 (now %6).", "", delta);
|
||||
}
|
||||
|
||||
auto &cardCounterSettings = SettingsCache::instance().cardCounters();
|
||||
QString hex = cardCounterSettings.color(counterId).name();
|
||||
appendHtmlServerMessage(finalStr.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg("<font class=\"blue\">" + QString::number(delta) + "</font>")
|
||||
.arg("<font color=\"" + hex + "\">●</font>")
|
||||
.arg(cardCounterSettings.displayName(counterId))
|
||||
.arg(cardLink(std::move(cardName)))
|
||||
.arg(value));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logSetCounter(PlayerLogic *player, QString counterName, int value, int oldValue)
|
||||
{
|
||||
if (counterName == "life") {
|
||||
soundEngine->playSound("life_change");
|
||||
}
|
||||
|
||||
QString counterDisplayName = TranslateCounterName::getDisplayName(counterName);
|
||||
appendHtmlServerMessage(tr("%1 sets counter %2 to %3 (%4%5).")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(QString("<font class=\"blue\">%1</font>").arg(sanitizeHtml(counterDisplayName)))
|
||||
.arg(QString("<font class=\"blue\">%1</font>").arg(value))
|
||||
.arg(value > oldValue ? "+" : "")
|
||||
.arg(value - oldValue));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logSetDoesntUntap(PlayerLogic *player, CardItem *card, bool doesntUntap)
|
||||
{
|
||||
QString str;
|
||||
if (doesntUntap) {
|
||||
str = tr("%1 sets %2 to not untap normally.");
|
||||
} else {
|
||||
str = tr("%1 sets %2 to untap normally.");
|
||||
}
|
||||
appendHtmlServerMessage(str.arg(sanitizeHtml(player->getPlayerInfo()->getName())).arg(cardLink(card->getName())));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logSetPT(PlayerLogic *player, CardItem *card, QString newPT)
|
||||
{
|
||||
if (currentContext == MessageContext_MoveCard) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString name = card->getName();
|
||||
if (name.isEmpty()) {
|
||||
name = QString("<font class=\"blue\">card #%1</font>").arg(sanitizeHtml(QString::number(card->getId())));
|
||||
} else {
|
||||
name = cardLink(name);
|
||||
}
|
||||
QString playerName = sanitizeHtml(player->getPlayerInfo()->getName());
|
||||
if (newPT.isEmpty()) {
|
||||
appendHtmlServerMessage(tr("%1 removes the PT of %2.").arg(playerName).arg(name));
|
||||
} else {
|
||||
QString oldPT = card->getPT();
|
||||
if (oldPT.isEmpty()) {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 changes the PT of %2 from nothing to %4.").arg(playerName).arg(name).arg(newPT));
|
||||
} else {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 changes the PT of %2 from %3 to %4.").arg(playerName).arg(name).arg(oldPT).arg(newPT));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logSetSideboardLock(PlayerLogic *player, bool locked)
|
||||
{
|
||||
if (locked) {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 has locked their sideboard.").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
|
||||
} else {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 has unlocked their sideboard.").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logSetTapped(PlayerLogic *player, CardItem *card, bool tapped)
|
||||
{
|
||||
if (currentContext == MessageContext_MoveCard) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tapped) {
|
||||
soundEngine->playSound("tap_card");
|
||||
} else {
|
||||
soundEngine->playSound("untap_card");
|
||||
}
|
||||
|
||||
QString str;
|
||||
if (!card) {
|
||||
appendHtmlServerMessage((tapped ? tr("%1 taps their permanents.") : tr("%1 untaps their permanents."))
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName())));
|
||||
} else {
|
||||
appendHtmlServerMessage((tapped ? tr("%1 taps %2.") : tr("%1 untaps %2."))
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(cardLink(card->getName())));
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logShuffle(PlayerLogic *player, CardZoneLogic *zone, int start, int end)
|
||||
{
|
||||
if (currentContext == MessageContext_Mulligan) {
|
||||
return;
|
||||
}
|
||||
|
||||
soundEngine->playSound("shuffle");
|
||||
// start and end are indexes into the portion of the deck that was shuffled
|
||||
// with negitive numbers counging from the bottom up.
|
||||
if (start == 0 && end == -1) {
|
||||
appendHtmlServerMessage(tr("%1 shuffles %2.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(zone->getTranslatedName(true, CaseShuffleZone)));
|
||||
} else if (start < 0 && end == -1) {
|
||||
appendHtmlServerMessage(tr("%1 shuffles the bottom %3 cards of %2.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(zone->getTranslatedName(true, CaseShuffleZone))
|
||||
.arg(-start));
|
||||
} else if (start < 0 && end > 0) {
|
||||
appendHtmlServerMessage(tr("%1 shuffles the top %3 cards of %2.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(zone->getTranslatedName(true, CaseShuffleZone))
|
||||
.arg(end + 1));
|
||||
} else {
|
||||
appendHtmlServerMessage(tr("%1 shuffles cards %3 - %4 of %2.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(zone->getTranslatedName(true, CaseShuffleZone))
|
||||
.arg(start)
|
||||
.arg(end));
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logSpectatorSay(const ServerInfo_User &spectator, QString message)
|
||||
{
|
||||
appendMessage(std::move(message), {}, spectator, false);
|
||||
}
|
||||
|
||||
void MessageLogWidget::logUnattachCard(PlayerLogic *player, QString cardName)
|
||||
{
|
||||
appendHtmlServerMessage(tr("%1 unattaches %2.")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(cardLink(std::move(cardName))));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logUndoDraw(PlayerLogic *player, QString cardName)
|
||||
{
|
||||
if (cardName.isEmpty()) {
|
||||
appendHtmlServerMessage(tr("%1 undoes their last draw.").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
|
||||
} else {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 undoes their last draw (%2).")
|
||||
.arg(sanitizeHtml(player->getPlayerInfo()->getName()))
|
||||
.arg(QString("<a href=\"card://%1\">%2</a>").arg(sanitizeHtml(cardName)).arg(sanitizeHtml(cardName))));
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logUndoDrawFailed(PlayerLogic *player)
|
||||
{
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 failed to undo their last draw.").arg(sanitizeHtml(player->getPlayerInfo()->getName())));
|
||||
}
|
||||
|
||||
void MessageLogWidget::setContextJudgeName(QString name)
|
||||
{
|
||||
messagePrefix = QString("<span style=\"color:black\">");
|
||||
messageSuffix = QString("</span> [<img height=12 src=\"theme:icons/scales\"> %1]").arg(sanitizeHtml(name));
|
||||
}
|
||||
|
||||
void MessageLogWidget::appendHtmlServerMessage(const QString &html, bool optionalIsBold, QString optionalFontColor)
|
||||
{
|
||||
|
||||
ChatView::appendHtmlServerMessage(messagePrefix + html + messageSuffix, optionalIsBold, optionalFontColor);
|
||||
}
|
||||
|
||||
void MessageLogWidget::connectToPlayerEventHandler(PlayerEventHandler *playerEventHandler)
|
||||
{
|
||||
connect(playerEventHandler, &PlayerEventHandler::logSay, this, &MessageLogWidget::logSay);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logShuffle, this, &MessageLogWidget::logShuffle);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logRollDie, this, &MessageLogWidget::logRollDie);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logCreateArrow, this, &MessageLogWidget::logCreateArrow);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logCreateToken, this, &MessageLogWidget::logCreateToken);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logSetCounter, this, &MessageLogWidget::logSetCounter);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logSetCardCounter, this, &MessageLogWidget::logSetCardCounter);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logSetTapped, this, &MessageLogWidget::logSetTapped);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logSetDoesntUntap, this, &MessageLogWidget::logSetDoesntUntap);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logSetPT, this, &MessageLogWidget::logSetPT);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logSetAnnotation, this, &MessageLogWidget::logSetAnnotation);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logMoveCard, this, &MessageLogWidget::logMoveCard);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logFlipCard, this, &MessageLogWidget::logFlipCard);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logDestroyCard, this, &MessageLogWidget::logDestroyCard);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logAttachCard, this, &MessageLogWidget::logAttachCard);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logUnattachCard, this, &MessageLogWidget::logUnattachCard);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logDumpZone, this, &MessageLogWidget::logDumpZone);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logDrawCards, this, &MessageLogWidget::logDrawCards);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logUndoDraw, this, &MessageLogWidget::logUndoDraw);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logUndoDrawFailed, this, &MessageLogWidget::logUndoDrawFailed);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logRevealCards, this, &MessageLogWidget::logRevealCards);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logAlwaysRevealTopCard, this,
|
||||
&MessageLogWidget::logAlwaysRevealTopCard);
|
||||
connect(playerEventHandler, &PlayerEventHandler::logAlwaysLookAtTopCard, this,
|
||||
&MessageLogWidget::logAlwaysLookAtTopCard);
|
||||
}
|
||||
|
||||
MessageLogWidget::MessageLogWidget(TabSupervisor *_tabSupervisor, AbstractGame *_game, QWidget *parent)
|
||||
: ChatView(_tabSupervisor, _game, true, parent), currentContext(MessageContext_None)
|
||||
{
|
||||
}
|
||||
|
|
@ -1,109 +0,0 @@
|
|||
/**
|
||||
* @file message_log_widget.h
|
||||
* @ingroup GameWidgets
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef MESSAGELOGWIDGET_H
|
||||
#define MESSAGELOGWIDGET_H
|
||||
|
||||
#include "../../interface/widgets/server/chat_view/chat_view.h"
|
||||
#include "../zones/card_zone_logic.h"
|
||||
|
||||
class AbstractGame;
|
||||
class CardItem;
|
||||
class GameEventContext;
|
||||
class PlayerLogic;
|
||||
class PlayerEventHandler;
|
||||
|
||||
class MessageLogWidget : public ChatView
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
enum MessageContext
|
||||
{
|
||||
MessageContext_None,
|
||||
MessageContext_MoveCard,
|
||||
MessageContext_Mulligan
|
||||
};
|
||||
|
||||
MessageContext currentContext;
|
||||
QString messagePrefix, messageSuffix;
|
||||
|
||||
static QPair<QString, QString> getFromStr(CardZoneLogic *zone, QString cardName, int position, bool ownerChange);
|
||||
|
||||
public:
|
||||
void connectToPlayerEventHandler(PlayerEventHandler *player);
|
||||
MessageLogWidget(TabSupervisor *_tabSupervisor, AbstractGame *_game, QWidget *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void containerProcessingDone();
|
||||
void containerProcessingStarted(const GameEventContext &context);
|
||||
void logAlwaysRevealTopCard(PlayerLogic *player, CardZoneLogic *zone, bool reveal);
|
||||
void logAlwaysLookAtTopCard(PlayerLogic *player, CardZoneLogic *zone, bool reveal);
|
||||
void logAttachCard(PlayerLogic *player, QString cardName, PlayerLogic *targetPlayer, QString targetCardName);
|
||||
void logConcede(int playerId);
|
||||
void logUnconcede(int playerId);
|
||||
void logConnectionStateChanged(PlayerLogic *player, bool connectionState);
|
||||
void logCreateArrow(PlayerLogic *player,
|
||||
PlayerLogic *startPlayer,
|
||||
QString startCard,
|
||||
PlayerLogic *targetPlayer,
|
||||
QString targetCard,
|
||||
bool playerTarget);
|
||||
void logCreateToken(PlayerLogic *player, QString cardName, QString pt, bool faceDown);
|
||||
void logDeckSelect(PlayerLogic *player, QString deckHash, int sideboardSize);
|
||||
void logDestroyCard(PlayerLogic *player, QString cardName);
|
||||
void logDrawCards(PlayerLogic *player, int number, bool deckIsEmpty);
|
||||
void logDumpZone(PlayerLogic *player, CardZoneLogic *zone, int numberCards, bool isReversed = false);
|
||||
void logFlipCard(PlayerLogic *player, QString cardName, bool faceDown);
|
||||
void logGameClosed();
|
||||
void logGameStart();
|
||||
void logGameFlooded();
|
||||
void logJoin(PlayerLogic *player);
|
||||
void logJoinSpectator(QString name);
|
||||
void logKicked();
|
||||
void logLeave(PlayerLogic *player, QString reason);
|
||||
void logLeaveSpectator(QString name, QString reason);
|
||||
void logNotReadyStart(PlayerLogic *player);
|
||||
void logMoveCard(PlayerLogic *player,
|
||||
CardItem *card,
|
||||
CardZoneLogic *startZone,
|
||||
int oldX,
|
||||
CardZoneLogic *targetZone,
|
||||
int newX);
|
||||
void logMulligan(PlayerLogic *player, int number);
|
||||
void logReplayStarted(int gameId);
|
||||
void logReadyStart(PlayerLogic *player);
|
||||
void logRevealCards(PlayerLogic *player,
|
||||
CardZoneLogic *zone,
|
||||
int cardId,
|
||||
QString cardName,
|
||||
PlayerLogic *otherPlayer,
|
||||
bool faceDown,
|
||||
int amount,
|
||||
bool isLentToAnotherPlayer);
|
||||
void logReverseTurn(PlayerLogic *player, bool reversed);
|
||||
void logRollDie(PlayerLogic *player, int sides, const QList<uint> &rolls);
|
||||
void logSay(PlayerLogic *player, QString message);
|
||||
void logSetActivePhase(int phase);
|
||||
void logSetActivePlayer(PlayerLogic *player);
|
||||
void logSetAnnotation(PlayerLogic *player, CardItem *card, QString newAnnotation);
|
||||
void logSetCardCounter(PlayerLogic *player, QString cardName, int counterId, int value, int oldValue);
|
||||
void logSetCounter(PlayerLogic *player, QString counterName, int value, int oldValue);
|
||||
void logSetDoesntUntap(PlayerLogic *player, CardItem *card, bool doesntUntap);
|
||||
void logSetPT(PlayerLogic *player, CardItem *card, QString newPT);
|
||||
void logSetSideboardLock(PlayerLogic *player, bool locked);
|
||||
void logSetTapped(PlayerLogic *player, CardItem *card, bool tapped);
|
||||
void logShuffle(PlayerLogic *player, CardZoneLogic *zone, int start, int end);
|
||||
void logSpectatorSay(const ServerInfo_User &spectator, QString message);
|
||||
void logUnattachCard(PlayerLogic *player, QString cardName);
|
||||
void logUndoDraw(PlayerLogic *player, QString cardName);
|
||||
void logUndoDrawFailed(PlayerLogic *player);
|
||||
void setContextJudgeName(QString player);
|
||||
void appendHtmlServerMessage(const QString &html,
|
||||
bool optionalIsBold = false,
|
||||
QString optionalFontColor = QString()) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,286 +0,0 @@
|
|||
#include "phases_toolbar.h"
|
||||
|
||||
#include "../interface/pixel_map_generator.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QDebug>
|
||||
#include <QPainter>
|
||||
#include <QPen>
|
||||
#include <QTimer>
|
||||
#include <libcockatrice/protocol/pb/command_draw_cards.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_next_turn.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_set_active_phase.pb.h>
|
||||
#include <libcockatrice/protocol/pb/command_set_card_attr.pb.h>
|
||||
#include <libcockatrice/utility/zone_names.h>
|
||||
|
||||
PhaseButton::PhaseButton(const QString &_name, QGraphicsItem *parent, QAction *_doubleClickAction, bool _highlightable)
|
||||
: QObject(), QGraphicsItem(parent), name(_name), active(false), highlightable(_highlightable),
|
||||
activeAnimationCounter(0), doubleClickAction(_doubleClickAction), width(50)
|
||||
{
|
||||
if (highlightable) {
|
||||
activeAnimationTimer = new QTimer(this);
|
||||
connect(activeAnimationTimer, &QTimer::timeout, this, &PhaseButton::updateAnimation);
|
||||
activeAnimationTimer->setSingleShot(false);
|
||||
} else {
|
||||
activeAnimationCounter = 9;
|
||||
}
|
||||
|
||||
setCacheMode(DeviceCoordinateCache);
|
||||
}
|
||||
|
||||
QRectF PhaseButton::boundingRect() const
|
||||
{
|
||||
return {0, 0, width, width};
|
||||
}
|
||||
|
||||
void PhaseButton::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
||||
{
|
||||
QRectF iconRect = boundingRect().adjusted(3, 3, -3, -3);
|
||||
QRectF translatedIconRect = painter->combinedTransform().mapRect(iconRect);
|
||||
qreal scaleFactor = translatedIconRect.width() / iconRect.width();
|
||||
QPixmap iconPixmap = PhasePixmapGenerator::generatePixmap(qRound(translatedIconRect.height()), name);
|
||||
|
||||
painter->setBrush(QColor(static_cast<int>(220 * (activeAnimationCounter / 10.0)),
|
||||
static_cast<int>(220 * (activeAnimationCounter / 10.0)),
|
||||
static_cast<int>(220 * (activeAnimationCounter / 10.0))));
|
||||
painter->setPen(Qt::gray);
|
||||
painter->drawRect(0, 0, static_cast<int>(width - 1), static_cast<int>(width - 1));
|
||||
painter->save();
|
||||
resetPainterTransform(painter);
|
||||
painter->drawPixmap(iconPixmap.rect().translated(qRound(3 * scaleFactor), qRound(3 * scaleFactor)), iconPixmap,
|
||||
iconPixmap.rect());
|
||||
painter->restore();
|
||||
|
||||
painter->setBrush(QColor(0, 0, 0, static_cast<int>(255 * ((10 - activeAnimationCounter) / 15.0))));
|
||||
painter->setPen(Qt::gray);
|
||||
painter->drawRect(0, 0, static_cast<int>(width - 1), static_cast<int>(width - 1));
|
||||
}
|
||||
|
||||
void PhaseButton::setWidth(double _width)
|
||||
{
|
||||
prepareGeometryChange();
|
||||
width = _width;
|
||||
}
|
||||
|
||||
void PhaseButton::setActive(bool _active)
|
||||
{
|
||||
if ((active == _active) || !highlightable) {
|
||||
return;
|
||||
}
|
||||
|
||||
active = _active;
|
||||
activeAnimationTimer->start(25);
|
||||
}
|
||||
|
||||
void PhaseButton::updateAnimation()
|
||||
{
|
||||
if (!highlightable) {
|
||||
return;
|
||||
}
|
||||
|
||||
// the counter ticks up to 10 when active and down to 0 when inactive
|
||||
if (active && activeAnimationCounter < 10) {
|
||||
++activeAnimationCounter;
|
||||
} else if (!active && activeAnimationCounter > 0) {
|
||||
--activeAnimationCounter;
|
||||
} else {
|
||||
activeAnimationTimer->stop();
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void PhaseButton::mousePressEvent(QGraphicsSceneMouseEvent * /*event*/)
|
||||
{
|
||||
emit clicked();
|
||||
}
|
||||
|
||||
void PhaseButton::mouseDoubleClickEvent(QGraphicsSceneMouseEvent * /*event*/)
|
||||
{
|
||||
triggerDoubleClickAction();
|
||||
}
|
||||
|
||||
void PhaseButton::triggerDoubleClickAction()
|
||||
{
|
||||
if (doubleClickAction) {
|
||||
doubleClickAction->trigger();
|
||||
}
|
||||
}
|
||||
|
||||
PhasesToolbar::PhasesToolbar(QGraphicsItem *parent)
|
||||
: QGraphicsItem(parent), width(100), height(100), ySpacing(1), symbolSize(8)
|
||||
{
|
||||
auto *aUntapAll = new QAction(this);
|
||||
connect(aUntapAll, &QAction::triggered, this, &PhasesToolbar::actUntapAll);
|
||||
auto *aDrawCard = new QAction(this);
|
||||
connect(aDrawCard, &QAction::triggered, this, &PhasesToolbar::actDrawCard);
|
||||
|
||||
PhaseButton *untapButton = new PhaseButton("untap", this, aUntapAll);
|
||||
PhaseButton *upkeepButton = new PhaseButton("upkeep", this);
|
||||
PhaseButton *drawButton = new PhaseButton("draw", this, aDrawCard);
|
||||
PhaseButton *main1Button = new PhaseButton("main1", this);
|
||||
PhaseButton *combatStartButton = new PhaseButton("combat_start", this);
|
||||
PhaseButton *combatAttackersButton = new PhaseButton("combat_attackers", this);
|
||||
PhaseButton *combatBlockersButton = new PhaseButton("combat_blockers", this);
|
||||
PhaseButton *combatDamageButton = new PhaseButton("combat_damage", this);
|
||||
PhaseButton *combatEndButton = new PhaseButton("combat_end", this);
|
||||
PhaseButton *main2Button = new PhaseButton("main2", this);
|
||||
PhaseButton *cleanupButton = new PhaseButton("cleanup", this);
|
||||
|
||||
buttonList << untapButton << upkeepButton << drawButton << main1Button << combatStartButton << combatAttackersButton
|
||||
<< combatBlockersButton << combatDamageButton << combatEndButton << main2Button << cleanupButton;
|
||||
|
||||
for (auto &i : buttonList) {
|
||||
connect(i, &PhaseButton::clicked, this, &PhasesToolbar::phaseButtonClicked);
|
||||
}
|
||||
|
||||
nextTurnButton = new PhaseButton("nextturn", this, nullptr, false);
|
||||
connect(nextTurnButton, &PhaseButton::clicked, this, &PhasesToolbar::actNextTurn);
|
||||
|
||||
rearrangeButtons();
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
QRectF PhasesToolbar::boundingRect() const
|
||||
{
|
||||
return {0, 0, width, height};
|
||||
}
|
||||
|
||||
void PhasesToolbar::retranslateUi()
|
||||
{
|
||||
for (int i = 0; i < buttonList.size(); ++i) {
|
||||
buttonList[i]->setToolTip(getLongPhaseName(i));
|
||||
}
|
||||
}
|
||||
|
||||
QString PhasesToolbar::getLongPhaseName(int phase) const
|
||||
{
|
||||
switch (phase) {
|
||||
case 0:
|
||||
return tr("Untap step");
|
||||
case 1:
|
||||
return tr("Upkeep step");
|
||||
case 2:
|
||||
return tr("Draw step");
|
||||
case 3:
|
||||
return tr("First main phase");
|
||||
case 4:
|
||||
return tr("Beginning of combat step");
|
||||
case 5:
|
||||
return tr("Declare attackers step");
|
||||
case 6:
|
||||
return tr("Declare blockers step");
|
||||
case 7:
|
||||
return tr("Combat damage step");
|
||||
case 8:
|
||||
return tr("End of combat step");
|
||||
case 9:
|
||||
return tr("Second main phase");
|
||||
case 10:
|
||||
return tr("End of turn step");
|
||||
default:
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
|
||||
void PhasesToolbar::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
||||
{
|
||||
painter->fillRect(boundingRect(), QColor(50, 50, 50));
|
||||
}
|
||||
|
||||
const double PhasesToolbar::marginSize = 3;
|
||||
|
||||
void PhasesToolbar::rearrangeButtons()
|
||||
{
|
||||
for (auto &i : buttonList) {
|
||||
i->setWidth(symbolSize);
|
||||
}
|
||||
nextTurnButton->setWidth(symbolSize);
|
||||
|
||||
double y = marginSize;
|
||||
buttonList[0]->setPos(marginSize, y);
|
||||
buttonList[1]->setPos(marginSize, y += symbolSize);
|
||||
buttonList[2]->setPos(marginSize, y += symbolSize);
|
||||
y += ySpacing;
|
||||
buttonList[3]->setPos(marginSize, y += symbolSize);
|
||||
y += ySpacing;
|
||||
buttonList[4]->setPos(marginSize, y += symbolSize);
|
||||
buttonList[5]->setPos(marginSize, y += symbolSize);
|
||||
buttonList[6]->setPos(marginSize, y += symbolSize);
|
||||
buttonList[7]->setPos(marginSize, y += symbolSize);
|
||||
buttonList[8]->setPos(marginSize, y += symbolSize);
|
||||
y += ySpacing;
|
||||
buttonList[9]->setPos(marginSize, y += symbolSize);
|
||||
y += ySpacing;
|
||||
buttonList[10]->setPos(marginSize, y += symbolSize);
|
||||
y += ySpacing;
|
||||
y += ySpacing;
|
||||
nextTurnButton->setPos(marginSize, y + symbolSize);
|
||||
}
|
||||
|
||||
void PhasesToolbar::setHeight(double _height)
|
||||
{
|
||||
prepareGeometryChange();
|
||||
|
||||
height = _height;
|
||||
ySpacing = (height - 2 * marginSize) / (buttonCount * 5 + spaceCount);
|
||||
symbolSize = ySpacing * 5;
|
||||
width = symbolSize + 2 * marginSize;
|
||||
|
||||
rearrangeButtons();
|
||||
}
|
||||
|
||||
void PhasesToolbar::setActivePhase(int phase)
|
||||
{
|
||||
if (phase >= buttonList.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < buttonList.size(); ++i) {
|
||||
buttonList[i]->setActive(i == phase);
|
||||
}
|
||||
}
|
||||
|
||||
void PhasesToolbar::triggerPhaseAction(int phase)
|
||||
{
|
||||
if (0 <= phase && phase < buttonList.size()) {
|
||||
buttonList[phase]->triggerDoubleClickAction();
|
||||
}
|
||||
}
|
||||
|
||||
void PhasesToolbar::phaseButtonClicked()
|
||||
{
|
||||
auto *button = qobject_cast<PhaseButton *>(sender());
|
||||
if (button->getActive()) {
|
||||
button->triggerDoubleClickAction();
|
||||
}
|
||||
|
||||
Command_SetActivePhase cmd;
|
||||
cmd.set_phase(static_cast<google::protobuf::uint32>(buttonList.indexOf(button)));
|
||||
|
||||
emit sendGameCommand(cmd, -1);
|
||||
}
|
||||
|
||||
void PhasesToolbar::actNextTurn()
|
||||
{
|
||||
emit sendGameCommand(Command_NextTurn(), -1);
|
||||
}
|
||||
|
||||
void PhasesToolbar::actUntapAll()
|
||||
{
|
||||
Command_SetCardAttr cmd;
|
||||
cmd.set_zone(ZoneNames::TABLE);
|
||||
cmd.set_attribute(AttrTapped);
|
||||
cmd.set_attr_value("0");
|
||||
|
||||
emit sendGameCommand(cmd, -1);
|
||||
}
|
||||
|
||||
void PhasesToolbar::actDrawCard()
|
||||
{
|
||||
Command_DrawCards cmd;
|
||||
cmd.set_number(1);
|
||||
|
||||
emit sendGameCommand(cmd, -1);
|
||||
}
|
||||
|
|
@ -1,107 +0,0 @@
|
|||
/**
|
||||
* @file phases_toolbar.h
|
||||
* @ingroup GameGraphics
|
||||
* @ingroup GameWidgets
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef PHASESTOOLBAR_H
|
||||
#define PHASESTOOLBAR_H
|
||||
|
||||
#include "../game_graphics/board/abstract_graphics_item.h"
|
||||
|
||||
#include <QFrame>
|
||||
#include <QGraphicsObject>
|
||||
#include <QList>
|
||||
|
||||
namespace google
|
||||
{
|
||||
namespace protobuf
|
||||
{
|
||||
class Message;
|
||||
}
|
||||
} // namespace google
|
||||
class PlayerLogic;
|
||||
class GameCommand;
|
||||
|
||||
class PhaseButton : public QObject, public QGraphicsItem
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(QGraphicsItem)
|
||||
private:
|
||||
QString name;
|
||||
bool active, highlightable;
|
||||
int activeAnimationCounter;
|
||||
QTimer *activeAnimationTimer;
|
||||
QAction *doubleClickAction;
|
||||
double width;
|
||||
|
||||
// void updatePixmap(QPixmap &pixmap);
|
||||
private slots:
|
||||
void updateAnimation();
|
||||
|
||||
public:
|
||||
explicit PhaseButton(const QString &_name,
|
||||
QGraphicsItem *parent = nullptr,
|
||||
QAction *_doubleClickAction = nullptr,
|
||||
bool _highlightable = true);
|
||||
[[nodiscard]] QRectF boundingRect() const override;
|
||||
void setWidth(double _width);
|
||||
void setActive(bool _active);
|
||||
[[nodiscard]] bool getActive() const
|
||||
{
|
||||
return active;
|
||||
}
|
||||
void triggerDoubleClickAction();
|
||||
signals:
|
||||
void clicked();
|
||||
|
||||
protected:
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/) override;
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
};
|
||||
|
||||
class PhasesToolbar : public QObject, public QGraphicsItem
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(QGraphicsItem)
|
||||
private:
|
||||
QList<PhaseButton *> buttonList;
|
||||
PhaseButton *nextTurnButton;
|
||||
double width, height, ySpacing, symbolSize;
|
||||
static const int buttonCount = 12;
|
||||
static const int spaceCount = 6;
|
||||
static const double marginSize;
|
||||
void rearrangeButtons();
|
||||
|
||||
public:
|
||||
explicit PhasesToolbar(QGraphicsItem *parent = nullptr);
|
||||
[[nodiscard]] QRectF boundingRect() const override;
|
||||
void retranslateUi();
|
||||
void setHeight(double _height);
|
||||
[[nodiscard]] double getWidth() const
|
||||
{
|
||||
return width;
|
||||
}
|
||||
[[nodiscard]] int phaseCount() const
|
||||
{
|
||||
return buttonList.size();
|
||||
}
|
||||
[[nodiscard]] QString getLongPhaseName(int phase) const;
|
||||
public slots:
|
||||
void setActivePhase(int phase);
|
||||
void triggerPhaseAction(int phase);
|
||||
private slots:
|
||||
void phaseButtonClicked();
|
||||
void actNextTurn();
|
||||
void actUntapAll();
|
||||
void actDrawCard();
|
||||
signals:
|
||||
void sendGameCommand(const ::google::protobuf::Message &command, int playerId);
|
||||
|
||||
protected:
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
/**
|
||||
* @file card_menu_action_type.h
|
||||
* @ingroup GameMenusPlayers
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef COCKATRICE_CARD_MENU_ACTION_TYPE_H
|
||||
#define COCKATRICE_CARD_MENU_ACTION_TYPE_H
|
||||
|
||||
enum CardMenuActionType
|
||||
{
|
||||
// Per-card attribute actions (must be <= cmClone for cardMenuAction() dispatch)
|
||||
cmTap,
|
||||
cmUntap,
|
||||
cmDoesntUntap,
|
||||
cmFlip,
|
||||
cmPeek,
|
||||
cmClone,
|
||||
// Move actions (must be > cmClone for cardMenuAction() dispatch)
|
||||
cmMoveToTopLibrary,
|
||||
cmMoveToBottomLibrary,
|
||||
cmMoveToHand,
|
||||
cmMoveToGraveyard,
|
||||
cmMoveToExile,
|
||||
cmMoveToTable
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_CARD_MENU_ACTION_TYPE_H
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
/**
|
||||
* @file abstract_player_component.h
|
||||
* @ingroup GameMenusPlayers
|
||||
* @brief Polymorphic interface for player-bound UI components managed by PlayerMenu.
|
||||
*/
|
||||
|
||||
#ifndef COCKATRICE_ABSTRACT_PLAYER_COMPONENT_H
|
||||
#define COCKATRICE_ABSTRACT_PLAYER_COMPONENT_H
|
||||
|
||||
/**
|
||||
* @brief Interface for player-bound UI components that need shortcut and translation lifecycle management.
|
||||
*
|
||||
* Not a QObject — avoids diamond inheritance with Qt's MOC. Each concrete component
|
||||
* inherits QObject through its Qt base class (QMenu, TearOffMenu, QGraphicsItem, etc.)
|
||||
* and this interface through regular multiple inheritance.
|
||||
*/
|
||||
class AbstractPlayerComponent
|
||||
{
|
||||
public:
|
||||
virtual ~AbstractPlayerComponent() = default;
|
||||
|
||||
/** @brief Bind keyboard shortcuts. Called when this player gains focus. */
|
||||
virtual void setShortcutsActive() = 0;
|
||||
|
||||
/** @brief Unbind keyboard shortcuts. Called when this player loses focus. */
|
||||
virtual void setShortcutsInactive() = 0;
|
||||
|
||||
/** @brief Retranslate all user-visible strings. Called on language change. */
|
||||
virtual void retranslateUi() = 0;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_ABSTRACT_PLAYER_COMPONENT_H
|
||||
|
|
@ -1,551 +0,0 @@
|
|||
#include "card_menu.h"
|
||||
|
||||
#include "../../../client/settings/card_counter_settings.h"
|
||||
#include "../../../interface/widgets/tabs/tab_game.h"
|
||||
#include "../../board/card_item.h"
|
||||
#include "../../zones/view_zone_logic.h"
|
||||
#include "../card_menu_action_type.h"
|
||||
#include "../player_actions.h"
|
||||
#include "../player_graphics_item.h"
|
||||
#include "../player_logic.h"
|
||||
#include "move_menu.h"
|
||||
#include "pt_menu.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
#include <libcockatrice/card/relation/card_relation.h>
|
||||
#include <libcockatrice/utility/zone_names.h>
|
||||
|
||||
/**
|
||||
* @brief Creates a circular icon filled with the specified color.
|
||||
*/
|
||||
static QIcon createCircleIcon(const QColor &color)
|
||||
{
|
||||
QPixmap pixmap(32, 32);
|
||||
pixmap.fill(Qt::transparent);
|
||||
QPainter painter(&pixmap);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
painter.setPen(Qt::NoPen);
|
||||
painter.setBrush(color);
|
||||
painter.drawEllipse(pixmap.rect());
|
||||
|
||||
return QIcon(pixmap);
|
||||
}
|
||||
|
||||
template <typename Slot>
|
||||
static QAction *makeAction(QObject *parent, Slot &&slot, bool checkable = false, bool checked = false)
|
||||
{
|
||||
auto *a = new QAction(parent);
|
||||
a->setCheckable(checkable);
|
||||
if (checkable) {
|
||||
a->setChecked(checked);
|
||||
}
|
||||
QObject::connect(a, &QAction::triggered, parent, std::forward<Slot>(slot));
|
||||
return a;
|
||||
}
|
||||
|
||||
CardMenu::CardMenu(PlayerGraphicsItem *_player, const CardItem *_card, bool _shortcutsActive)
|
||||
: player(_player), card(_card), shortcutsActive(_shortcutsActive)
|
||||
{
|
||||
const QList<PlayerLogic *> &players = player->getLogic()->getGame()->getPlayerManager()->getPlayers().values();
|
||||
|
||||
for (auto playerToAdd : players) {
|
||||
if (playerToAdd == player->getLogic()) {
|
||||
continue;
|
||||
}
|
||||
playersInfo.append(qMakePair(playerToAdd->getPlayerInfo()->getName(), playerToAdd->getPlayerInfo()->getId()));
|
||||
}
|
||||
|
||||
connect(player->getLogic()->getGame()->getPlayerManager(), &PlayerManager::playerRemoved, this,
|
||||
&CardMenu::removePlayer);
|
||||
|
||||
auto *actions = player->getLogic()->getPlayerActions();
|
||||
auto *gameScene = player->getGameScene();
|
||||
|
||||
// Single selection resolver used by all lambdas — called at trigger time
|
||||
auto sel = [gameScene]() { return gameScene->selectedCards(); };
|
||||
|
||||
// Unified dispatcher for card menu actions
|
||||
auto invoke = [actions, sel](CardMenuActionType type) {
|
||||
return [actions, sel, type]() { actions->cardMenuAction(sel(), type); };
|
||||
};
|
||||
|
||||
// Actions using invoke (type dispatch, need selection)
|
||||
aTap = makeAction(this, invoke(cmTap));
|
||||
aDoesntUntap = makeAction(this, invoke(cmDoesntUntap), /*checkable=*/true, card && card->getDoesntUntap());
|
||||
aFlip = makeAction(this, invoke(cmFlip));
|
||||
aPeek = makeAction(this, invoke(cmPeek));
|
||||
aClone = makeAction(this, invoke(cmClone));
|
||||
|
||||
// Actions using selection directly
|
||||
aUnattach = makeAction(this, [actions, sel]() { actions->actUnattach(sel()); });
|
||||
aSetAnnotation = makeAction(this, [actions, sel]() { actions->actRequestSetAnnotationDialog(sel()); });
|
||||
aPlay = makeAction(this, [actions, sel]() { actions->actPlay(sel()); });
|
||||
aPlayFacedown = makeAction(this, [actions, sel]() { actions->actPlayFacedown(sel()); });
|
||||
aHide = makeAction(this, [actions, sel]() { actions->actHide(sel()); });
|
||||
aReduceLifeByPower = makeAction(this, [actions, sel]() { actions->actReduceLifeByPower(sel()); });
|
||||
|
||||
// Actions that use activeCard, not selection — direct connection
|
||||
aAttach = new QAction(this);
|
||||
aDrawArrow = new QAction(this);
|
||||
aSelectAll = new QAction(this);
|
||||
aSelectRow = new QAction(this);
|
||||
aSelectColumn = new QAction(this);
|
||||
|
||||
connect(aAttach, &QAction::triggered, actions, &PlayerActions::actAttach);
|
||||
connect(aDrawArrow, &QAction::triggered, actions, &PlayerActions::actDrawArrow);
|
||||
connect(aSelectAll, &QAction::triggered, actions, &PlayerActions::actSelectAll);
|
||||
connect(aSelectRow, &QAction::triggered, actions, &PlayerActions::actSelectRow);
|
||||
connect(aSelectColumn, &QAction::triggered, actions, &PlayerActions::actSelectColumn);
|
||||
|
||||
aRevealToAll = new QAction(this);
|
||||
|
||||
mCardCounters = new QMenu;
|
||||
|
||||
// Card counters
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
QColor color = SettingsCache::instance().cardCounters().color(i);
|
||||
QIcon circleIcon = createCircleIcon(color);
|
||||
|
||||
auto *addAction = makeAction(this, [actions, sel, i]() { actions->actAddCardCounter(sel(), i); });
|
||||
addAction->setIcon(circleIcon);
|
||||
aAddCounter.append(addAction);
|
||||
|
||||
auto *removeAction = makeAction(this, [actions, sel, i]() { actions->actRemoveCardCounter(sel(), i); });
|
||||
removeAction->setIcon(circleIcon);
|
||||
aRemoveCounter.append(removeAction);
|
||||
|
||||
auto *setAction = makeAction(this, [actions, sel, i]() { actions->actRequestSetCardCounterDialog(sel(), i); });
|
||||
setAction->setIcon(circleIcon);
|
||||
aSetCounter.append(setAction);
|
||||
}
|
||||
|
||||
setShortcutsActive();
|
||||
|
||||
retranslateUi();
|
||||
|
||||
if (card == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool revealedCard = false;
|
||||
bool writeableCard = player->getLogic()->getPlayerInfo()->getLocalOrJudge();
|
||||
if (auto *view = qobject_cast<ZoneViewZoneLogic *>(card->getZone())) {
|
||||
if (view->getRevealZone()) {
|
||||
if (view->getWriteableRevealZone()) {
|
||||
writeableCard = true;
|
||||
} else {
|
||||
revealedCard = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (revealedCard) {
|
||||
addAction(aHide);
|
||||
addSeparator();
|
||||
addAction(aClone);
|
||||
addSeparator();
|
||||
addAction(aSelectAll);
|
||||
addAction(aSelectColumn);
|
||||
addRelatedCardView();
|
||||
} else {
|
||||
if (card->getZone()) {
|
||||
if (card->getZone()->getName() == ZoneNames::TABLE) {
|
||||
createTableMenu(writeableCard);
|
||||
} else if (card->getZone()->getName() == ZoneNames::STACK) {
|
||||
createStackMenu(writeableCard);
|
||||
} else if (card->getZone()->getName() == ZoneNames::EXILE ||
|
||||
card->getZone()->getName() == ZoneNames::GRAVE) {
|
||||
createGraveyardOrExileMenu(writeableCard);
|
||||
} else {
|
||||
createHandOrCustomZoneMenu(writeableCard);
|
||||
}
|
||||
} else {
|
||||
createZonelessMenu(writeableCard);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CardMenu::removePlayer(PlayerLogic *playerToRemove)
|
||||
{
|
||||
for (auto it = playersInfo.begin(); it != playersInfo.end();) {
|
||||
if (it->second == playerToRemove->getPlayerInfo()->getId()) {
|
||||
it = playersInfo.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CardMenu::createTableMenu(bool canModifyCard)
|
||||
{
|
||||
// Card is on the battlefield
|
||||
if (!canModifyCard) {
|
||||
addAction(aDrawArrow);
|
||||
addSeparator();
|
||||
addAction(aClone);
|
||||
addSeparator();
|
||||
addAction(aReduceLifeByPower);
|
||||
addSeparator();
|
||||
addAction(aSelectAll);
|
||||
addAction(aSelectRow);
|
||||
addRelatedCardView();
|
||||
addRelatedCardActions();
|
||||
return;
|
||||
}
|
||||
|
||||
addAction(aTap);
|
||||
addAction(aDoesntUntap);
|
||||
addAction(aFlip);
|
||||
if (card->getFaceDown()) {
|
||||
addAction(aPeek);
|
||||
}
|
||||
addSeparator();
|
||||
addAction(aClone);
|
||||
addMenu(new MoveMenu(player));
|
||||
addSeparator();
|
||||
addAction(aAttach);
|
||||
if (card->getAttachedTo()) {
|
||||
addAction(aUnattach);
|
||||
}
|
||||
addAction(aDrawArrow);
|
||||
addSeparator();
|
||||
addMenu(new PtMenu(player));
|
||||
addAction(aSetAnnotation);
|
||||
addSeparator();
|
||||
addAction(aReduceLifeByPower);
|
||||
addSeparator();
|
||||
addAction(aSelectAll);
|
||||
addAction(aSelectRow);
|
||||
|
||||
addSeparator();
|
||||
mCardCounters->clear();
|
||||
for (int i = 0; i < aAddCounter.size(); ++i) {
|
||||
mCardCounters->addSeparator();
|
||||
mCardCounters->addAction(aAddCounter[i]);
|
||||
if (card->getCounters().contains(i)) {
|
||||
mCardCounters->addAction(aRemoveCounter[i]);
|
||||
}
|
||||
mCardCounters->addAction(aSetCounter[i]);
|
||||
}
|
||||
addSeparator();
|
||||
addMenu(mCardCounters);
|
||||
addRelatedCardView();
|
||||
addRelatedCardActions();
|
||||
}
|
||||
|
||||
void CardMenu::createStackMenu(bool canModifyCard)
|
||||
{
|
||||
// Card is on the stack
|
||||
if (!canModifyCard) {
|
||||
addAction(aDrawArrow);
|
||||
addSeparator();
|
||||
addAction(aClone);
|
||||
addSeparator();
|
||||
addAction(aSelectAll);
|
||||
addRelatedCardView();
|
||||
addRelatedCardActions();
|
||||
return;
|
||||
}
|
||||
|
||||
addAction(aPlay);
|
||||
addAction(aPlayFacedown);
|
||||
addSeparator();
|
||||
addAction(aClone);
|
||||
addMenu(new MoveMenu(player));
|
||||
addSeparator();
|
||||
addAction(aAttach);
|
||||
addAction(aDrawArrow);
|
||||
addSeparator();
|
||||
addAction(aSelectAll);
|
||||
addRelatedCardView();
|
||||
addRelatedCardActions();
|
||||
}
|
||||
|
||||
void CardMenu::createGraveyardOrExileMenu(bool canModifyCard)
|
||||
{
|
||||
// Card is in the graveyard or exile
|
||||
if (!canModifyCard) {
|
||||
addAction(aDrawArrow);
|
||||
addSeparator();
|
||||
addAction(aClone);
|
||||
addSeparator();
|
||||
addAction(aSelectAll);
|
||||
addAction(aSelectColumn);
|
||||
addRelatedCardView();
|
||||
addRelatedCardActions();
|
||||
return;
|
||||
}
|
||||
|
||||
addAction(aPlay);
|
||||
addAction(aPlayFacedown);
|
||||
addSeparator();
|
||||
addAction(aClone);
|
||||
addMenu(new MoveMenu(player));
|
||||
addSeparator();
|
||||
addAction(aAttach);
|
||||
addAction(aDrawArrow);
|
||||
addSeparator();
|
||||
addAction(aSelectAll);
|
||||
addAction(aSelectColumn);
|
||||
addRelatedCardView();
|
||||
addRelatedCardActions();
|
||||
}
|
||||
|
||||
void CardMenu::createHandOrCustomZoneMenu(bool canModifyCard)
|
||||
{
|
||||
if (!canModifyCard) {
|
||||
addAction(aDrawArrow);
|
||||
addSeparator();
|
||||
addAction(aClone);
|
||||
addSeparator();
|
||||
addAction(aSelectAll);
|
||||
addRelatedCardView();
|
||||
addRelatedCardActions();
|
||||
return;
|
||||
}
|
||||
|
||||
// Card is in hand or a custom zone specified by server
|
||||
addAction(aPlay);
|
||||
addAction(aPlayFacedown);
|
||||
|
||||
QMenu *revealMenu = addMenu(tr("Re&veal to..."));
|
||||
|
||||
initContextualPlayersMenu(revealMenu, aRevealToAll);
|
||||
|
||||
connect(revealMenu, &QMenu::triggered, this, [this](QAction *action) {
|
||||
player->getLogic()->getPlayerActions()->actReveal(player->getGameScene()->selectedCards(), action);
|
||||
});
|
||||
|
||||
addSeparator();
|
||||
addAction(aClone);
|
||||
addMenu(new MoveMenu(player));
|
||||
|
||||
// actions that are really wonky when done from deck or sideboard
|
||||
if (card->getZone()->getName() == ZoneNames::HAND) {
|
||||
addSeparator();
|
||||
addAction(aAttach);
|
||||
addAction(aDrawArrow);
|
||||
}
|
||||
|
||||
addSeparator();
|
||||
addAction(aSelectAll);
|
||||
if (qobject_cast<ZoneViewZoneLogic *>(card->getZone())) {
|
||||
addAction(aSelectColumn);
|
||||
}
|
||||
|
||||
addRelatedCardView();
|
||||
if (card->getZone()->getName() == ZoneNames::HAND) {
|
||||
addRelatedCardActions();
|
||||
}
|
||||
}
|
||||
|
||||
void CardMenu::createZonelessMenu(bool canModifyCard)
|
||||
{
|
||||
if (canModifyCard) {
|
||||
addMenu(new MoveMenu(player));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Populates the menu with an action for each active player.
|
||||
*
|
||||
* The "all players" action is created separately, so it has to be passed into this function.
|
||||
* It will be put at the top of the menu.
|
||||
*
|
||||
* @param menu The menu to add the player actions to.
|
||||
* @param allPlayersAction The action for "all players".
|
||||
*/
|
||||
void CardMenu::initContextualPlayersMenu(QMenu *menu, QAction *allPlayersAction)
|
||||
{
|
||||
allPlayersAction->setData(-1);
|
||||
menu->addAction(allPlayersAction);
|
||||
menu->addSeparator();
|
||||
|
||||
for (const auto &playerInfo : playersInfo) {
|
||||
menu->addAction(playerInfo.first)->setData(playerInfo.second);
|
||||
}
|
||||
}
|
||||
|
||||
void CardMenu::addRelatedCardView()
|
||||
{
|
||||
if (!card) {
|
||||
return;
|
||||
}
|
||||
auto exactCard = card->getCard();
|
||||
if (!exactCard) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool atLeastOneGoodRelationFound = false;
|
||||
QList<CardRelation *> relatedCards = exactCard.getInfo().getAllRelatedCards();
|
||||
for (const CardRelation *cardRelation : relatedCards) {
|
||||
CardInfoPtr relatedCard = CardDatabaseManager::query()->getCardInfo(cardRelation->getName());
|
||||
if (relatedCard != nullptr) {
|
||||
atLeastOneGoodRelationFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!atLeastOneGoodRelationFound) {
|
||||
return;
|
||||
}
|
||||
|
||||
addSeparator();
|
||||
auto viewRelatedCards = new QMenu(tr("View related cards"));
|
||||
addMenu(viewRelatedCards);
|
||||
for (const CardRelation *relatedCard : relatedCards) {
|
||||
QString relatedCardName = relatedCard->getName();
|
||||
CardRef cardRef = {relatedCardName, exactCard.getPrinting().getUuid()};
|
||||
QAction *viewCard = viewRelatedCards->addAction(relatedCardName);
|
||||
Q_UNUSED(viewCard);
|
||||
|
||||
connect(viewCard, &QAction::triggered, this, [this, cardRef] { emit cardInfoRequested(cardRef); });
|
||||
}
|
||||
}
|
||||
|
||||
void CardMenu::addRelatedCardActions()
|
||||
{
|
||||
if (!card) {
|
||||
return;
|
||||
}
|
||||
auto exactCard = card->getCard();
|
||||
if (!exactCard) {
|
||||
return;
|
||||
}
|
||||
|
||||
QList<CardRelation *> relatedCards = exactCard.getInfo().getAllRelatedCards();
|
||||
if (relatedCards.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
addSeparator();
|
||||
int index = 0;
|
||||
QAction *createRelatedCards = nullptr;
|
||||
for (const CardRelation *cardRelation : relatedCards) {
|
||||
ExactCard relatedCard =
|
||||
CardDatabaseManager::query()->getCardFromSameSet(cardRelation->getName(), card->getCard().getPrinting());
|
||||
if (!relatedCard) {
|
||||
relatedCard = CardDatabaseManager::query()->getCard({cardRelation->getName()});
|
||||
}
|
||||
if (!relatedCard) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QString relatedCardName;
|
||||
if (relatedCard.getInfo().getPowTough().size() > 0) {
|
||||
relatedCardName = relatedCard.getInfo().getPowTough() + " " + relatedCard.getName(); // "n/n name"
|
||||
} else {
|
||||
relatedCardName = relatedCard.getName(); // "name"
|
||||
}
|
||||
|
||||
QString text = tr("Token: ");
|
||||
if (cardRelation->getDoesAttach()) {
|
||||
text +=
|
||||
tr(cardRelation->getDoesTransform() ? "Transform into " : "Attach to ") + "\"" + relatedCardName + "\"";
|
||||
} else if (cardRelation->getIsVariable()) {
|
||||
text += "X " + relatedCardName;
|
||||
} else if (cardRelation->getDefaultCount() != 1) {
|
||||
text += QString::number(cardRelation->getDefaultCount()) + "x " + relatedCardName;
|
||||
} else {
|
||||
text += relatedCardName;
|
||||
}
|
||||
|
||||
if (createRelatedCards == nullptr) {
|
||||
if (relatedCards.length() == 1) {
|
||||
createRelatedCards = new QAction(text, this); // set actCreateAllRelatedCards with this text
|
||||
break; // do not set an individual entry as there is only one entry
|
||||
} else {
|
||||
createRelatedCards = new QAction(tr("All tokens"), this);
|
||||
}
|
||||
}
|
||||
|
||||
auto *createRelated = new QAction(text, this);
|
||||
createRelated->setData(QVariant(index++));
|
||||
connect(createRelated, &QAction::triggered, player->getLogic()->getPlayerActions(),
|
||||
&PlayerActions::actCreateRelatedCard);
|
||||
addAction(createRelated);
|
||||
}
|
||||
|
||||
if (createRelatedCards) {
|
||||
if (shortcutsActive) {
|
||||
createRelatedCards->setShortcuts(
|
||||
SettingsCache::instance().shortcuts().getShortcut("Player/aCreateRelatedTokens"));
|
||||
}
|
||||
connect(createRelatedCards, &QAction::triggered, player->getLogic()->getPlayerActions(),
|
||||
&PlayerActions::actCreateAllRelatedCards);
|
||||
addAction(createRelatedCards);
|
||||
}
|
||||
}
|
||||
|
||||
void CardMenu::retranslateUi()
|
||||
{
|
||||
aSelectAll->setText(tr("&Select All"));
|
||||
aSelectRow->setText(tr("S&elect Row"));
|
||||
aSelectColumn->setText(tr("S&elect Column"));
|
||||
|
||||
aPlay->setText(tr("&Play"));
|
||||
aHide->setText(tr("&Hide"));
|
||||
aPlayFacedown->setText(tr("Play &Face Down"));
|
||||
aRevealToAll->setText(tr("&All players"));
|
||||
//: Turn sideways or back again
|
||||
aTap->setText(tr("&Tap / Untap"));
|
||||
aDoesntUntap->setText(tr("Skip &untapping"));
|
||||
//: Turn face up/face down
|
||||
aFlip->setText(tr("T&urn Over")); // Only the user facing names in client got renamed to "turn over"
|
||||
// All code and proto bits are still unchanged (flip) for compatibility reasons
|
||||
// A protocol rewrite with v3 could incorporate that, see #3100
|
||||
aPeek->setText(tr("&Peek at card face"));
|
||||
aClone->setText(tr("&Clone"));
|
||||
aAttach->setText(tr("Attac&h to card..."));
|
||||
aUnattach->setText(tr("Unattac&h"));
|
||||
aDrawArrow->setText(tr("&Draw arrow..."));
|
||||
aSetAnnotation->setText(tr("&Set annotation..."));
|
||||
aReduceLifeByPower->setText(tr("Reduce life by power"));
|
||||
|
||||
mCardCounters->setTitle(tr("Ca&rd counters"));
|
||||
|
||||
auto &cardCounterSettings = SettingsCache::instance().cardCounters();
|
||||
|
||||
for (int i = 0; i < aAddCounter.size(); ++i) {
|
||||
aAddCounter[i]->setText(tr("&Add counter (%1)").arg(cardCounterSettings.displayName(i)));
|
||||
}
|
||||
for (int i = 0; i < aRemoveCounter.size(); ++i) {
|
||||
aRemoveCounter[i]->setText(tr("&Remove counter (%1)").arg(cardCounterSettings.displayName(i)));
|
||||
}
|
||||
for (int i = 0; i < aSetCounter.size(); ++i) {
|
||||
aSetCounter[i]->setText(tr("&Set counters (%1)...").arg(cardCounterSettings.displayName(i)));
|
||||
}
|
||||
}
|
||||
|
||||
void CardMenu::setShortcutsActive()
|
||||
{
|
||||
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
|
||||
|
||||
aHide->setShortcuts(shortcuts.getShortcut("Player/aHide"));
|
||||
aPlay->setShortcuts(shortcuts.getShortcut("Player/aPlay"));
|
||||
aPlayFacedown->setShortcuts(shortcuts.getShortcut("Player/aPlayFacedown"));
|
||||
aRevealToAll->setShortcuts(shortcuts.getShortcut("Player/aRevealToAll"));
|
||||
|
||||
aTap->setShortcuts(shortcuts.getShortcut("Player/aTap"));
|
||||
aDoesntUntap->setShortcuts(shortcuts.getShortcut("Player/aDoesntUntap"));
|
||||
aFlip->setShortcuts(shortcuts.getShortcut("Player/aFlip"));
|
||||
aPeek->setShortcuts(shortcuts.getShortcut("Player/aPeek"));
|
||||
aClone->setShortcuts(shortcuts.getShortcut("Player/aClone"));
|
||||
aAttach->setShortcuts(shortcuts.getShortcut("Player/aAttach"));
|
||||
aUnattach->setShortcuts(shortcuts.getShortcut("Player/aUnattach"));
|
||||
aDrawArrow->setShortcuts(shortcuts.getShortcut("Player/aDrawArrow"));
|
||||
aSetAnnotation->setShortcuts(shortcuts.getShortcut("Player/aSetAnnotation"));
|
||||
aReduceLifeByPower->setShortcuts(shortcuts.getShortcut("Player/aReduceLifeByPower"));
|
||||
|
||||
aSelectAll->setShortcuts(shortcuts.getShortcut("Player/aSelectAll"));
|
||||
aSelectRow->setShortcuts(shortcuts.getShortcut("Player/aSelectRow"));
|
||||
aSelectColumn->setShortcuts(shortcuts.getShortcut("Player/aSelectColumn"));
|
||||
|
||||
static const QStringList colorWords = {"Red", "Yellow", "Green", "Cyan", "Purple", "Magenta"};
|
||||
for (int i = 0; i < aAddCounter.size(); i++) {
|
||||
aAddCounter[i]->setShortcuts(shortcuts.getShortcut("Player/aCC" + colorWords[i]));
|
||||
aRemoveCounter[i]->setShortcuts(shortcuts.getShortcut("Player/aRC" + colorWords[i]));
|
||||
aSetCounter[i]->setShortcuts(shortcuts.getShortcut("Player/aSC" + colorWords[i]));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
/**
|
||||
* @file card_menu.h
|
||||
* @ingroup GameMenusCards
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef COCKATRICE_CARD_MENU_H
|
||||
#define COCKATRICE_CARD_MENU_H
|
||||
|
||||
#include <QMenu>
|
||||
#include <libcockatrice/utility/card_ref.h>
|
||||
|
||||
class CardItem;
|
||||
class PlayerGraphicsItem;
|
||||
class PlayerLogic;
|
||||
class CardMenu : public QMenu
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
signals:
|
||||
void cardInfoRequested(const CardRef &cardRef);
|
||||
|
||||
public:
|
||||
explicit CardMenu(PlayerGraphicsItem *player, const CardItem *card, bool shortcutsActive);
|
||||
void removePlayer(PlayerLogic *playerToRemove);
|
||||
void createTableMenu(bool canModifyCard);
|
||||
void createStackMenu(bool canModifyCard);
|
||||
void createGraveyardOrExileMenu(bool canModifyCard);
|
||||
void createHandOrCustomZoneMenu(bool canModifyCard);
|
||||
void createZonelessMenu(bool canModifyCard);
|
||||
|
||||
QMenu *mCardCounters;
|
||||
|
||||
QAction *aPlay, *aPlayFacedown;
|
||||
QAction *aRevealToAll;
|
||||
QAction *aHide;
|
||||
QAction *aClone;
|
||||
QAction *aSelectAll, *aSelectRow, *aSelectColumn;
|
||||
QAction *aDrawArrow;
|
||||
QAction *aTap, *aDoesntUntap;
|
||||
QAction *aFlip, *aPeek;
|
||||
QAction *aAttach, *aUnattach;
|
||||
QAction *aSetAnnotation;
|
||||
QAction *aReduceLifeByPower;
|
||||
|
||||
QList<QAction *> aAddCounter, aSetCounter, aRemoveCounter;
|
||||
|
||||
private:
|
||||
PlayerGraphicsItem *player;
|
||||
const CardItem *card;
|
||||
QList<QPair<QString, int>> playersInfo;
|
||||
bool shortcutsActive;
|
||||
|
||||
void addRelatedCardActions();
|
||||
void retranslateUi();
|
||||
void initContextualPlayersMenu(QMenu *menu, QAction *allPlayersAction);
|
||||
void setShortcutsActive();
|
||||
void addRelatedCardView();
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_CARD_MENU_H
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
#include "custom_zone_menu.h"
|
||||
|
||||
#include "../player_logic.h"
|
||||
|
||||
CustomZoneMenu::CustomZoneMenu(PlayerGraphicsItem *_player) : player(_player)
|
||||
{
|
||||
menuAction()->setVisible(false);
|
||||
|
||||
connect(player->getLogic(), &PlayerLogic::clearCustomZonesMenu, this, &CustomZoneMenu::clearCustomZonesMenu);
|
||||
connect(player->getLogic(), &PlayerLogic::addViewCustomZoneActionToCustomZoneMenu, this,
|
||||
&CustomZoneMenu::addViewCustomZoneActionToCustomZoneMenu);
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void CustomZoneMenu::retranslateUi()
|
||||
{
|
||||
setTitle(tr("C&ustom Zones"));
|
||||
|
||||
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
|
||||
|
||||
for (auto aViewZone : actions()) {
|
||||
aViewZone->setText(tr("View custom zone '%1'").arg(aViewZone->data().toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CustomZoneMenu::clearCustomZonesMenu()
|
||||
{
|
||||
clear();
|
||||
menuAction()->setVisible(false);
|
||||
}
|
||||
|
||||
void CustomZoneMenu::addViewCustomZoneActionToCustomZoneMenu(QString zoneName)
|
||||
{
|
||||
menuAction()->setVisible(true);
|
||||
QAction *aViewZone = addAction(tr("View custom zone '%1'").arg(zoneName));
|
||||
aViewZone->setData(zoneName);
|
||||
connect(aViewZone, &QAction::triggered, this,
|
||||
[zoneName, this]() { player->getGameScene()->toggleZoneView(player->getLogic(), zoneName, -1); });
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
/**
|
||||
* @file custom_zone_menu.h
|
||||
* @ingroup GameMenusZones
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef COCKATRICE_CUSTOM_ZONE_MENU_H
|
||||
#define COCKATRICE_CUSTOM_ZONE_MENU_H
|
||||
|
||||
#include "abstract_player_component.h"
|
||||
|
||||
#include <QMenu>
|
||||
|
||||
class PlayerGraphicsItem;
|
||||
class CustomZoneMenu : public QMenu, public AbstractPlayerComponent
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CustomZoneMenu(PlayerGraphicsItem *player);
|
||||
void retranslateUi() override;
|
||||
void setShortcutsActive() override
|
||||
{
|
||||
}
|
||||
void setShortcutsInactive() override
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
PlayerGraphicsItem *player;
|
||||
private slots:
|
||||
void clearCustomZonesMenu();
|
||||
void addViewCustomZoneActionToCustomZoneMenu(QString zoneName);
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_CUSTOM_ZONE_MENU_H
|
||||
|
|
@ -1,123 +0,0 @@
|
|||
#include "grave_menu.h"
|
||||
|
||||
#include "../../abstract_game.h"
|
||||
#include "../player_actions.h"
|
||||
#include "../player_logic.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QMenu>
|
||||
#include <libcockatrice/utility/zone_names.h>
|
||||
|
||||
GraveyardMenu::GraveyardMenu(PlayerGraphicsItem *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
|
||||
{
|
||||
createMoveActions();
|
||||
createViewActions();
|
||||
|
||||
addAction(aViewGraveyard);
|
||||
|
||||
if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) {
|
||||
mRevealRandomGraveyardCard = addMenu(QString());
|
||||
connect(mRevealRandomGraveyardCard, &QMenu::aboutToShow, this,
|
||||
&GraveyardMenu::populateRevealRandomMenuWithActivePlayers);
|
||||
|
||||
addSeparator();
|
||||
|
||||
moveGraveMenu = addTearOffMenu(QString());
|
||||
moveGraveMenu->addAction(aMoveGraveToTopLibrary);
|
||||
moveGraveMenu->addAction(aMoveGraveToBottomLibrary);
|
||||
moveGraveMenu->addSeparator();
|
||||
moveGraveMenu->addAction(aMoveGraveToHand);
|
||||
moveGraveMenu->addSeparator();
|
||||
moveGraveMenu->addAction(aMoveGraveToRfg);
|
||||
}
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void GraveyardMenu::createMoveActions()
|
||||
{
|
||||
auto grave = player->getLogic()->getGraveZone();
|
||||
|
||||
if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) {
|
||||
aMoveGraveToTopLibrary = new QAction(this);
|
||||
aMoveGraveToTopLibrary->setData(QList<QVariant>() << ZoneNames::DECK << 0);
|
||||
|
||||
aMoveGraveToBottomLibrary = new QAction(this);
|
||||
aMoveGraveToBottomLibrary->setData(QList<QVariant>() << ZoneNames::DECK << -1);
|
||||
|
||||
aMoveGraveToHand = new QAction(this);
|
||||
aMoveGraveToHand->setData(QList<QVariant>() << ZoneNames::HAND << 0);
|
||||
|
||||
aMoveGraveToRfg = new QAction(this);
|
||||
aMoveGraveToRfg->setData(QList<QVariant>() << ZoneNames::EXILE << 0);
|
||||
|
||||
connect(aMoveGraveToTopLibrary, &QAction::triggered, grave, &PileZoneLogic::moveAllToZone);
|
||||
connect(aMoveGraveToBottomLibrary, &QAction::triggered, grave, &PileZoneLogic::moveAllToZone);
|
||||
connect(aMoveGraveToHand, &QAction::triggered, grave, &PileZoneLogic::moveAllToZone);
|
||||
connect(aMoveGraveToRfg, &QAction::triggered, grave, &PileZoneLogic::moveAllToZone);
|
||||
}
|
||||
}
|
||||
|
||||
void GraveyardMenu::createViewActions()
|
||||
{
|
||||
PlayerActions *playerActions = player->getLogic()->getPlayerActions();
|
||||
|
||||
aViewGraveyard = new QAction(this);
|
||||
connect(aViewGraveyard, &QAction::triggered, playerActions, &PlayerActions::actViewGraveyard);
|
||||
}
|
||||
|
||||
void GraveyardMenu::populateRevealRandomMenuWithActivePlayers()
|
||||
{
|
||||
mRevealRandomGraveyardCard->clear();
|
||||
|
||||
QAction *allPlayers = mRevealRandomGraveyardCard->addAction(tr("&All players"));
|
||||
allPlayers->setData(-1);
|
||||
connect(allPlayers, &QAction::triggered, this, &GraveyardMenu::onRevealRandomTriggered);
|
||||
|
||||
mRevealRandomGraveyardCard->addSeparator();
|
||||
|
||||
const auto &players = player->getLogic()->getGame()->getPlayerManager()->getPlayers().values();
|
||||
for (auto *other : players) {
|
||||
if (other == player->getLogic()) {
|
||||
continue;
|
||||
}
|
||||
QAction *a = mRevealRandomGraveyardCard->addAction(other->getPlayerInfo()->getName());
|
||||
a->setData(other->getPlayerInfo()->getId());
|
||||
connect(a, &QAction::triggered, this, &GraveyardMenu::onRevealRandomTriggered);
|
||||
}
|
||||
}
|
||||
|
||||
void GraveyardMenu::onRevealRandomTriggered()
|
||||
{
|
||||
if (auto *a = qobject_cast<QAction *>(sender())) {
|
||||
player->getLogic()->getPlayerActions()->actRevealRandomGraveyardCard(a->data().toInt());
|
||||
}
|
||||
}
|
||||
|
||||
void GraveyardMenu::retranslateUi()
|
||||
{
|
||||
setTitle(tr("&Graveyard"));
|
||||
|
||||
aViewGraveyard->setText(tr("&View graveyard"));
|
||||
|
||||
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
|
||||
moveGraveMenu->setTitle(tr("&Move graveyard to..."));
|
||||
aMoveGraveToTopLibrary->setText(tr("&Top of library"));
|
||||
aMoveGraveToBottomLibrary->setText(tr("&Bottom of library"));
|
||||
aMoveGraveToHand->setText(tr("&Hand"));
|
||||
aMoveGraveToRfg->setText(tr("&Exile"));
|
||||
|
||||
mRevealRandomGraveyardCard->setTitle(tr("Reveal random card to..."));
|
||||
}
|
||||
}
|
||||
|
||||
void GraveyardMenu::setShortcutsActive()
|
||||
{
|
||||
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
|
||||
aViewGraveyard->setShortcuts(shortcuts.getShortcut("Player/aViewGraveyard"));
|
||||
}
|
||||
|
||||
void GraveyardMenu::setShortcutsInactive()
|
||||
{
|
||||
aViewGraveyard->setShortcut(QKeySequence());
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
/**
|
||||
* @file grave_menu.h
|
||||
* @ingroup GameMenusZones
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef COCKATRICE_GRAVE_MENU_H
|
||||
#define COCKATRICE_GRAVE_MENU_H
|
||||
|
||||
#include "../../../interface/widgets/menus/tearoff_menu.h"
|
||||
#include "abstract_player_component.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QMenu>
|
||||
|
||||
class PlayerGraphicsItem;
|
||||
class GraveyardMenu : public TearOffMenu, public AbstractPlayerComponent
|
||||
{
|
||||
Q_OBJECT
|
||||
signals:
|
||||
void newPlayerActionCreated(QAction *action);
|
||||
|
||||
public:
|
||||
explicit GraveyardMenu(PlayerGraphicsItem *player, QWidget *parent = nullptr);
|
||||
void createMoveActions();
|
||||
void createViewActions();
|
||||
void populateRevealRandomMenuWithActivePlayers();
|
||||
void onRevealRandomTriggered();
|
||||
void retranslateUi() override;
|
||||
void setShortcutsActive() override;
|
||||
void setShortcutsInactive() override;
|
||||
|
||||
QMenu *mRevealRandomGraveyardCard = nullptr;
|
||||
QMenu *moveGraveMenu = nullptr;
|
||||
|
||||
QAction *aViewGraveyard = nullptr;
|
||||
QAction *aMoveGraveToTopLibrary = nullptr;
|
||||
QAction *aMoveGraveToBottomLibrary = nullptr;
|
||||
QAction *aMoveGraveToHand = nullptr;
|
||||
QAction *aMoveGraveToRfg = nullptr;
|
||||
|
||||
private:
|
||||
PlayerGraphicsItem *player;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_GRAVE_MENU_H
|
||||
|
|
@ -1,223 +0,0 @@
|
|||
#include "hand_menu.h"
|
||||
|
||||
#include "../../../client/settings/cache_settings.h"
|
||||
#include "../../../client/settings/shortcuts_settings.h"
|
||||
#include "../../../game_graphics/zones/hand_zone.h"
|
||||
#include "../../abstract_game.h"
|
||||
#include "../player_actions.h"
|
||||
#include "../player_graphics_item.h"
|
||||
#include "../player_logic.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QMenu>
|
||||
#include <libcockatrice/utility/zone_names.h>
|
||||
|
||||
HandMenu::HandMenu(PlayerGraphicsItem *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
|
||||
{
|
||||
auto *actions = player->getLogic()->getPlayerActions();
|
||||
|
||||
if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) {
|
||||
aViewHand = new QAction(this);
|
||||
|
||||
connect(aViewHand, &QAction::triggered, actions, &PlayerActions::actViewHand);
|
||||
addAction(aViewHand);
|
||||
|
||||
mSortHand = addMenu(QString());
|
||||
|
||||
aSortHandByName = new QAction(this);
|
||||
aSortHandByName->setData(CardList::SortByName);
|
||||
aSortHandByType = new QAction(this);
|
||||
aSortHandByType->setData(CardList::SortByMainType);
|
||||
aSortHandByManaValue = new QAction(this);
|
||||
aSortHandByManaValue->setData(CardList::SortByManaValue);
|
||||
|
||||
connect(aSortHandByType, &QAction::triggered, actions, &PlayerActions::actSortHand);
|
||||
connect(aSortHandByName, &QAction::triggered, actions, &PlayerActions::actSortHand);
|
||||
connect(aSortHandByManaValue, &QAction::triggered, actions, &PlayerActions::actSortHand);
|
||||
|
||||
mSortHand->addAction(aSortHandByName);
|
||||
mSortHand->addAction(aSortHandByType);
|
||||
mSortHand->addAction(aSortHandByManaValue);
|
||||
}
|
||||
|
||||
mRevealHand = addMenu(QString());
|
||||
connect(mRevealHand, &QMenu::aboutToShow, this, &HandMenu::populateRevealHandMenuWithActivePlayers);
|
||||
|
||||
aRevealHandToAll = new QAction(this);
|
||||
aRevealHandToAll->setData(-1);
|
||||
connect(aRevealHandToAll, &QAction::triggered, this, &HandMenu::onRevealHandTriggered);
|
||||
|
||||
mRevealRandomHandCard = addMenu(QString());
|
||||
connect(mRevealRandomHandCard, &QMenu::aboutToShow, this,
|
||||
&HandMenu::populateRevealRandomHandCardMenuWithActivePlayers);
|
||||
|
||||
aRevealRandomHandCardToAll = new QAction(this);
|
||||
aRevealRandomHandCardToAll->setData(-1);
|
||||
connect(aRevealRandomHandCardToAll, &QAction::triggered, this, &HandMenu::onRevealRandomHandCardTriggered);
|
||||
|
||||
// We still need to add these actions to menu here so that the shortcuts are active right away
|
||||
mRevealHand->addAction(aRevealHandToAll);
|
||||
mRevealRandomHandCard->addAction(aRevealRandomHandCardToAll);
|
||||
|
||||
addSeparator();
|
||||
|
||||
aMulligan = new QAction(this);
|
||||
connect(aMulligan, &QAction::triggered, actions, &PlayerActions::actRequestMulliganDialog);
|
||||
addAction(aMulligan);
|
||||
|
||||
// Mulligan same size
|
||||
aMulliganSame = new QAction(this);
|
||||
connect(aMulliganSame, &QAction::triggered, actions, &PlayerActions::actMulliganSameSize);
|
||||
addAction(aMulliganSame);
|
||||
|
||||
// Mulligan -1
|
||||
aMulliganMinusOne = new QAction(this);
|
||||
connect(aMulliganMinusOne, &QAction::triggered, actions, &PlayerActions::actMulliganMinusOne);
|
||||
addAction(aMulliganMinusOne);
|
||||
|
||||
addSeparator();
|
||||
|
||||
mMoveHandMenu = addTearOffMenu(QString());
|
||||
|
||||
if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) {
|
||||
aMoveHandToTopLibrary = new QAction(this);
|
||||
aMoveHandToTopLibrary->setData(QList<QVariant>() << ZoneNames::DECK << 0);
|
||||
aMoveHandToBottomLibrary = new QAction(this);
|
||||
aMoveHandToBottomLibrary->setData(QList<QVariant>() << ZoneNames::DECK << -1);
|
||||
aMoveHandToGrave = new QAction(this);
|
||||
aMoveHandToGrave->setData(QList<QVariant>() << ZoneNames::GRAVE << 0);
|
||||
aMoveHandToRfg = new QAction(this);
|
||||
aMoveHandToRfg->setData(QList<QVariant>() << ZoneNames::EXILE << 0);
|
||||
|
||||
auto hand = player->getLogic()->getHandZone();
|
||||
|
||||
connect(aMoveHandToTopLibrary, &QAction::triggered, hand, &HandZoneLogic::moveAllToZone);
|
||||
connect(aMoveHandToBottomLibrary, &QAction::triggered, hand, &HandZoneLogic::moveAllToZone);
|
||||
connect(aMoveHandToGrave, &QAction::triggered, hand, &HandZoneLogic::moveAllToZone);
|
||||
connect(aMoveHandToRfg, &QAction::triggered, hand, &HandZoneLogic::moveAllToZone);
|
||||
|
||||
mMoveHandMenu->addAction(aMoveHandToTopLibrary);
|
||||
mMoveHandMenu->addAction(aMoveHandToBottomLibrary);
|
||||
mMoveHandMenu->addSeparator();
|
||||
mMoveHandMenu->addAction(aMoveHandToGrave);
|
||||
mMoveHandMenu->addSeparator();
|
||||
mMoveHandMenu->addAction(aMoveHandToRfg);
|
||||
}
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void HandMenu::retranslateUi()
|
||||
{
|
||||
setTitle(tr("&Hand"));
|
||||
|
||||
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
|
||||
aViewHand->setText(tr("&View hand"));
|
||||
|
||||
mSortHand->setTitle(tr("Sort hand by..."));
|
||||
aSortHandByName->setText(tr("Name"));
|
||||
aSortHandByType->setText(tr("Type"));
|
||||
aSortHandByManaValue->setText(tr("Mana Value"));
|
||||
|
||||
aMulligan->setText(tr("Take &mulligan (Choose hand size)"));
|
||||
aMulliganSame->setText(tr("Take mulligan (Same hand size)"));
|
||||
aMulliganMinusOne->setText(tr("Take mulligan (Hand size - 1)"));
|
||||
|
||||
mMoveHandMenu->setTitle(tr("&Move hand to..."));
|
||||
aMoveHandToTopLibrary->setText(tr("&Top of library"));
|
||||
aMoveHandToBottomLibrary->setText(tr("&Bottom of library"));
|
||||
aMoveHandToGrave->setText(tr("&Graveyard"));
|
||||
aMoveHandToRfg->setText(tr("&Exile"));
|
||||
|
||||
mRevealHand->setTitle(tr("&Reveal hand to..."));
|
||||
aRevealHandToAll->setText(tr("All players"));
|
||||
|
||||
mRevealRandomHandCard->setTitle(tr("Reveal r&andom card to..."));
|
||||
aRevealRandomHandCardToAll->setText(tr("All players"));
|
||||
}
|
||||
}
|
||||
|
||||
void HandMenu::setShortcutsActive()
|
||||
{
|
||||
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
|
||||
aViewHand->setShortcuts(shortcuts.getShortcut("Player/aViewHand"));
|
||||
aSortHandByName->setShortcuts(shortcuts.getShortcut("Player/aSortHandByName"));
|
||||
aSortHandByType->setShortcuts(shortcuts.getShortcut("Player/aSortHandByType"));
|
||||
aSortHandByManaValue->setShortcuts(shortcuts.getShortcut("Player/aSortHandByManaValue"));
|
||||
aMulligan->setShortcuts(shortcuts.getShortcut("Player/aMulligan"));
|
||||
aMulliganSame->setShortcuts(shortcuts.getShortcut("Player/aMulliganSame"));
|
||||
aMulliganMinusOne->setShortcuts(shortcuts.getShortcut("Player/aMulliganMinusOne"));
|
||||
aRevealHandToAll->setShortcuts(shortcuts.getShortcut("Player/aRevealHandToAll"));
|
||||
aRevealRandomHandCardToAll->setShortcuts(shortcuts.getShortcut("Player/aRevealRandomHandCardToAll"));
|
||||
}
|
||||
|
||||
void HandMenu::setShortcutsInactive()
|
||||
{
|
||||
aViewHand->setShortcut(QKeySequence());
|
||||
aSortHandByName->setShortcut(QKeySequence());
|
||||
aSortHandByType->setShortcut(QKeySequence());
|
||||
aSortHandByManaValue->setShortcut(QKeySequence());
|
||||
aMulligan->setShortcut(QKeySequence());
|
||||
aRevealHandToAll->setShortcut(QKeySequence());
|
||||
aRevealRandomHandCardToAll->setShortcut(QKeySequence());
|
||||
}
|
||||
|
||||
void HandMenu::populateRevealHandMenuWithActivePlayers()
|
||||
{
|
||||
mRevealHand->clear();
|
||||
|
||||
mRevealHand->addAction(aRevealHandToAll);
|
||||
|
||||
mRevealHand->addSeparator();
|
||||
|
||||
const auto &players = player->getLogic()->getGame()->getPlayerManager()->getPlayers().values();
|
||||
for (auto *other : players) {
|
||||
if (other == player->getLogic()) {
|
||||
continue;
|
||||
}
|
||||
QAction *a = mRevealHand->addAction(other->getPlayerInfo()->getName());
|
||||
a->setData(other->getPlayerInfo()->getId());
|
||||
connect(a, &QAction::triggered, this, &HandMenu::onRevealHandTriggered);
|
||||
}
|
||||
}
|
||||
|
||||
void HandMenu::populateRevealRandomHandCardMenuWithActivePlayers()
|
||||
{
|
||||
mRevealRandomHandCard->clear();
|
||||
|
||||
mRevealRandomHandCard->addAction(aRevealRandomHandCardToAll);
|
||||
|
||||
mRevealRandomHandCard->addSeparator();
|
||||
|
||||
const auto &players = player->getLogic()->getGame()->getPlayerManager()->getPlayers().values();
|
||||
for (auto *other : players) {
|
||||
if (other == player->getLogic()) {
|
||||
continue;
|
||||
}
|
||||
QAction *a = mRevealRandomHandCard->addAction(other->getPlayerInfo()->getName());
|
||||
a->setData(other->getPlayerInfo()->getId());
|
||||
connect(a, &QAction::triggered, this, &HandMenu::onRevealRandomHandCardTriggered);
|
||||
}
|
||||
}
|
||||
|
||||
void HandMenu::onRevealHandTriggered()
|
||||
{
|
||||
auto *action = qobject_cast<QAction *>(sender());
|
||||
if (!action) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int targetId = action->data().toInt();
|
||||
player->getLogic()->getPlayerActions()->actRevealHand(targetId);
|
||||
}
|
||||
|
||||
void HandMenu::onRevealRandomHandCardTriggered()
|
||||
{
|
||||
auto *action = qobject_cast<QAction *>(sender());
|
||||
if (!action) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int targetId = action->data().toInt();
|
||||
player->getLogic()->getPlayerActions()->actRevealRandomHandCard(targetId);
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
/**
|
||||
* @file hand_menu.h
|
||||
* @ingroup GameMenusZones
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef COCKATRICE_HAND_MENU_H
|
||||
#define COCKATRICE_HAND_MENU_H
|
||||
|
||||
#include "../../../interface/widgets/menus/tearoff_menu.h"
|
||||
#include "abstract_player_component.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QMenu>
|
||||
|
||||
class PlayerGraphicsItem;
|
||||
class PlayerActions;
|
||||
|
||||
class HandMenu : public TearOffMenu, public AbstractPlayerComponent
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
HandMenu(PlayerGraphicsItem *player, QWidget *parent = nullptr);
|
||||
|
||||
QMenu *revealHandMenu() const
|
||||
{
|
||||
return mRevealHand;
|
||||
}
|
||||
QMenu *revealRandomHandCardMenu() const
|
||||
{
|
||||
return mRevealRandomHandCard;
|
||||
}
|
||||
|
||||
void retranslateUi() override;
|
||||
void setShortcutsActive() override;
|
||||
void setShortcutsInactive() override;
|
||||
|
||||
private slots:
|
||||
void populateRevealHandMenuWithActivePlayers();
|
||||
void populateRevealRandomHandCardMenuWithActivePlayers();
|
||||
void onRevealHandTriggered();
|
||||
void onRevealRandomHandCardTriggered();
|
||||
|
||||
private:
|
||||
PlayerGraphicsItem *player;
|
||||
|
||||
QAction *aViewHand = nullptr;
|
||||
QAction *aMulligan = nullptr;
|
||||
QAction *aMulliganSame = nullptr;
|
||||
QAction *aMulliganMinusOne = nullptr;
|
||||
|
||||
QMenu *mSortHand = nullptr;
|
||||
QAction *aSortHandByName = nullptr;
|
||||
QAction *aSortHandByType = nullptr;
|
||||
QAction *aSortHandByManaValue = nullptr;
|
||||
|
||||
QMenu *mRevealHand = nullptr;
|
||||
QAction *aRevealHandToAll = nullptr;
|
||||
|
||||
QMenu *mRevealRandomHandCard = nullptr;
|
||||
QAction *aRevealRandomHandCardToAll = nullptr;
|
||||
|
||||
QMenu *mMoveHandMenu = nullptr;
|
||||
QAction *aMoveHandToTopLibrary = nullptr;
|
||||
QAction *aMoveHandToBottomLibrary = nullptr;
|
||||
QAction *aMoveHandToGrave = nullptr;
|
||||
QAction *aMoveHandToRfg = nullptr;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_HAND_MENU_H
|
||||
|
|
@ -1,420 +0,0 @@
|
|||
#include "library_menu.h"
|
||||
|
||||
#include "../../../client/settings/cache_settings.h"
|
||||
#include "../../../client/settings/shortcuts_settings.h"
|
||||
#include "../../../interface/widgets/tabs/tab_game.h"
|
||||
#include "../../abstract_game.h"
|
||||
#include "../player_actions.h"
|
||||
#include "../player_logic.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QGraphicsView>
|
||||
#include <QMenu>
|
||||
|
||||
LibraryMenu::LibraryMenu(PlayerGraphicsItem *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
|
||||
{
|
||||
createDrawActions();
|
||||
createShuffleActions();
|
||||
createMoveActions();
|
||||
createViewActions();
|
||||
|
||||
addAction(aDrawCard);
|
||||
addAction(aDrawCards);
|
||||
addAction(aUndoDraw);
|
||||
addSeparator();
|
||||
addAction(aShuffle);
|
||||
addSeparator();
|
||||
addAction(aViewLibrary);
|
||||
addAction(aViewTopCards);
|
||||
addAction(aViewBottomCards);
|
||||
addSeparator();
|
||||
|
||||
mRevealLibrary = addMenu(QString());
|
||||
connect(mRevealLibrary, &QMenu::aboutToShow, this, &LibraryMenu::populateRevealLibraryMenuWithActivePlayers);
|
||||
|
||||
mLendLibrary = addMenu(QString());
|
||||
connect(mLendLibrary, &QMenu::aboutToShow, this, &LibraryMenu::populateLendLibraryMenuWithActivePlayers);
|
||||
|
||||
mRevealTopCard = addMenu(QString());
|
||||
connect(mRevealTopCard, &QMenu::aboutToShow, this, &LibraryMenu::populateRevealTopCardMenuWithActivePlayers);
|
||||
|
||||
addAction(aAlwaysRevealTopCard);
|
||||
addAction(aAlwaysLookAtTopCard);
|
||||
addSeparator();
|
||||
topLibraryMenu = addTearOffMenu(QString());
|
||||
bottomLibraryMenu = addTearOffMenu(QString());
|
||||
addSeparator();
|
||||
addAction(aOpenDeckInDeckEditor);
|
||||
|
||||
topLibraryMenu->addAction(aMoveTopToPlay);
|
||||
topLibraryMenu->addAction(aMoveTopToPlayFaceDown);
|
||||
topLibraryMenu->addAction(aMoveTopCardToBottom);
|
||||
topLibraryMenu->addSeparator();
|
||||
topLibraryMenu->addAction(aMoveTopCardToGraveyard);
|
||||
topLibraryMenu->addAction(aMoveTopCardsToGraveyard);
|
||||
topLibraryMenu->addAction(aMoveTopCardsToGraveyardFaceDown);
|
||||
topLibraryMenu->addAction(aMoveTopCardToExile);
|
||||
topLibraryMenu->addAction(aMoveTopCardsToExile);
|
||||
topLibraryMenu->addAction(aMoveTopCardsToExileFaceDown);
|
||||
topLibraryMenu->addAction(aMoveTopCardsUntil);
|
||||
topLibraryMenu->addSeparator();
|
||||
topLibraryMenu->addAction(aShuffleTopCards);
|
||||
|
||||
bottomLibraryMenu->addAction(aDrawBottomCard);
|
||||
bottomLibraryMenu->addAction(aDrawBottomCards);
|
||||
bottomLibraryMenu->addSeparator();
|
||||
bottomLibraryMenu->addAction(aMoveBottomToPlay);
|
||||
bottomLibraryMenu->addAction(aMoveBottomToPlayFaceDown);
|
||||
bottomLibraryMenu->addAction(aMoveBottomCardToTop);
|
||||
bottomLibraryMenu->addSeparator();
|
||||
bottomLibraryMenu->addAction(aMoveBottomCardToGraveyard);
|
||||
bottomLibraryMenu->addAction(aMoveBottomCardsToGraveyard);
|
||||
bottomLibraryMenu->addAction(aMoveBottomCardsToGraveyardFaceDown);
|
||||
bottomLibraryMenu->addAction(aMoveBottomCardToExile);
|
||||
bottomLibraryMenu->addAction(aMoveBottomCardsToExile);
|
||||
bottomLibraryMenu->addAction(aMoveBottomCardsToExileFaceDown);
|
||||
bottomLibraryMenu->addSeparator();
|
||||
bottomLibraryMenu->addAction(aShuffleBottomCards);
|
||||
|
||||
connect(player->getLogic(), &PlayerLogic::resetTopCardMenuActions, this, &LibraryMenu::resetTopCardMenuActions);
|
||||
connect(player->getLogic(), &PlayerLogic::deckChanged, this, &LibraryMenu::enableOpenInDeckEditorAction);
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void LibraryMenu::enableOpenInDeckEditorAction() const
|
||||
{
|
||||
aOpenDeckInDeckEditor->setEnabled(true);
|
||||
}
|
||||
|
||||
void LibraryMenu::resetTopCardMenuActions()
|
||||
{
|
||||
aAlwaysRevealTopCard->setChecked(false);
|
||||
aAlwaysLookAtTopCard->setChecked(false);
|
||||
}
|
||||
|
||||
void LibraryMenu::createDrawActions()
|
||||
{
|
||||
PlayerActions *playerActions = player->getLogic()->getPlayerActions();
|
||||
|
||||
if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) {
|
||||
aDrawCard = new QAction(this);
|
||||
connect(aDrawCard, &QAction::triggered, playerActions, &PlayerActions::actDrawCard);
|
||||
aDrawCards = new QAction(this);
|
||||
connect(aDrawCards, &QAction::triggered, playerActions, &PlayerActions::actRequestDrawCardsDialog);
|
||||
aUndoDraw = new QAction(this);
|
||||
connect(aUndoDraw, &QAction::triggered, playerActions, &PlayerActions::actUndoDraw);
|
||||
aDrawBottomCard = new QAction(this);
|
||||
connect(aDrawBottomCard, &QAction::triggered, playerActions, &PlayerActions::actDrawBottomCard);
|
||||
aDrawBottomCards = new QAction(this);
|
||||
connect(aDrawBottomCards, &QAction::triggered, playerActions, &PlayerActions::actRequestDrawBottomCardsDialog);
|
||||
}
|
||||
}
|
||||
|
||||
void LibraryMenu::createShuffleActions()
|
||||
{
|
||||
PlayerActions *playerActions = player->getLogic()->getPlayerActions();
|
||||
|
||||
if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) {
|
||||
aShuffle = new QAction(this);
|
||||
connect(aShuffle, &QAction::triggered, playerActions, &PlayerActions::actShuffle);
|
||||
aShuffleTopCards = new QAction(this);
|
||||
connect(aShuffleTopCards, &QAction::triggered, playerActions, &PlayerActions::actRequestShuffleTopDialog);
|
||||
aShuffleBottomCards = new QAction(this);
|
||||
connect(aShuffleBottomCards, &QAction::triggered, playerActions, &PlayerActions::actRequestShuffleBottomDialog);
|
||||
}
|
||||
}
|
||||
|
||||
void LibraryMenu::createMoveActions()
|
||||
{
|
||||
PlayerActions *playerActions = player->getLogic()->getPlayerActions();
|
||||
|
||||
if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) {
|
||||
aMoveTopToPlay = new QAction(this);
|
||||
connect(aMoveTopToPlay, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardToPlay);
|
||||
aMoveTopToPlayFaceDown = new QAction(this);
|
||||
connect(aMoveTopToPlayFaceDown, &QAction::triggered, playerActions,
|
||||
&PlayerActions::actMoveTopCardToPlayFaceDown);
|
||||
aMoveTopCardToGraveyard = new QAction(this);
|
||||
connect(aMoveTopCardToGraveyard, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardToGrave);
|
||||
aMoveTopCardToExile = new QAction(this);
|
||||
connect(aMoveTopCardToExile, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardToExile);
|
||||
aMoveTopCardsToGraveyard = new QAction(this);
|
||||
connect(aMoveTopCardsToGraveyard, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardsToGrave);
|
||||
aMoveTopCardsToGraveyardFaceDown = new QAction(this);
|
||||
connect(aMoveTopCardsToGraveyardFaceDown, &QAction::triggered, playerActions,
|
||||
&PlayerActions::actMoveTopCardsToGraveFaceDown);
|
||||
aMoveTopCardsToExile = new QAction(this);
|
||||
connect(aMoveTopCardsToExile, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardsToExile);
|
||||
aMoveTopCardsToExileFaceDown = new QAction(this);
|
||||
connect(aMoveTopCardsToExileFaceDown, &QAction::triggered, playerActions,
|
||||
&PlayerActions::actMoveTopCardsToExileFaceDown);
|
||||
aMoveTopCardsUntil = new QAction(this);
|
||||
connect(aMoveTopCardsUntil, &QAction::triggered, playerActions,
|
||||
&PlayerActions::actRequestMoveTopCardsUntilDialog);
|
||||
aMoveTopCardToBottom = new QAction(this);
|
||||
connect(aMoveTopCardToBottom, &QAction::triggered, playerActions, &PlayerActions::actMoveTopCardToBottom);
|
||||
|
||||
aMoveBottomToPlay = new QAction(this);
|
||||
connect(aMoveBottomToPlay, &QAction::triggered, playerActions, &PlayerActions::actMoveBottomCardToPlay);
|
||||
aMoveBottomToPlayFaceDown = new QAction(this);
|
||||
connect(aMoveBottomToPlayFaceDown, &QAction::triggered, playerActions,
|
||||
&PlayerActions::actMoveBottomCardToPlayFaceDown);
|
||||
aMoveBottomCardToGraveyard = new QAction(this);
|
||||
connect(aMoveBottomCardToGraveyard, &QAction::triggered, playerActions,
|
||||
&PlayerActions::actMoveBottomCardToGrave);
|
||||
aMoveBottomCardToExile = new QAction(this);
|
||||
connect(aMoveBottomCardToExile, &QAction::triggered, playerActions, &PlayerActions::actMoveBottomCardToExile);
|
||||
aMoveBottomCardsToGraveyard = new QAction(this);
|
||||
connect(aMoveBottomCardsToGraveyard, &QAction::triggered, playerActions,
|
||||
&PlayerActions::actMoveBottomCardsToGrave);
|
||||
aMoveBottomCardsToGraveyardFaceDown = new QAction(this);
|
||||
connect(aMoveBottomCardsToGraveyardFaceDown, &QAction::triggered, playerActions,
|
||||
&PlayerActions::actMoveBottomCardsToGraveFaceDown);
|
||||
aMoveBottomCardsToExile = new QAction(this);
|
||||
connect(aMoveBottomCardsToExile, &QAction::triggered, playerActions, &PlayerActions::actMoveBottomCardsToExile);
|
||||
aMoveBottomCardsToExileFaceDown = new QAction(this);
|
||||
connect(aMoveBottomCardsToExileFaceDown, &QAction::triggered, playerActions,
|
||||
&PlayerActions::actMoveBottomCardsToExileFaceDown);
|
||||
aMoveBottomCardToTop = new QAction(this);
|
||||
connect(aMoveBottomCardToTop, &QAction::triggered, playerActions, &PlayerActions::actMoveBottomCardToTop);
|
||||
}
|
||||
}
|
||||
|
||||
void LibraryMenu::createViewActions()
|
||||
{
|
||||
PlayerActions *playerActions = player->getLogic()->getPlayerActions();
|
||||
|
||||
if (player->getLogic()->getPlayerInfo()->local || player->getLogic()->getPlayerInfo()->judge) {
|
||||
aViewLibrary = new QAction(this);
|
||||
connect(aViewLibrary, &QAction::triggered, playerActions, &PlayerActions::actViewLibrary);
|
||||
|
||||
aViewTopCards = new QAction(this);
|
||||
connect(aViewTopCards, &QAction::triggered, playerActions, &PlayerActions::actRequestViewTopCardsDialog);
|
||||
aViewBottomCards = new QAction(this);
|
||||
connect(aViewBottomCards, &QAction::triggered, playerActions, &PlayerActions::actRequestViewBottomCardsDialog);
|
||||
aAlwaysRevealTopCard = new QAction(this);
|
||||
aAlwaysRevealTopCard->setCheckable(true);
|
||||
connect(aAlwaysRevealTopCard, &QAction::triggered, playerActions, &PlayerActions::actAlwaysRevealTopCard);
|
||||
aAlwaysLookAtTopCard = new QAction(this);
|
||||
aAlwaysLookAtTopCard->setCheckable(true);
|
||||
connect(aAlwaysLookAtTopCard, &QAction::triggered, playerActions, &PlayerActions::actAlwaysLookAtTopCard);
|
||||
aOpenDeckInDeckEditor = new QAction(this);
|
||||
aOpenDeckInDeckEditor->setEnabled(false);
|
||||
connect(aOpenDeckInDeckEditor, &QAction::triggered, playerActions, &PlayerActions::actOpenDeckInDeckEditor);
|
||||
}
|
||||
}
|
||||
|
||||
void LibraryMenu::retranslateUi()
|
||||
{
|
||||
setTitle(tr("&Library"));
|
||||
|
||||
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
|
||||
aViewLibrary->setText(tr("&View library"));
|
||||
aViewTopCards->setText(tr("View &top cards of library..."));
|
||||
aViewBottomCards->setText(tr("View bottom cards of library..."));
|
||||
mRevealLibrary->setTitle(tr("Reveal &library to..."));
|
||||
mLendLibrary->setTitle(tr("Lend library to..."));
|
||||
mRevealTopCard->setTitle(tr("Reveal &top cards to..."));
|
||||
topLibraryMenu->setTitle(tr("&Top of library..."));
|
||||
bottomLibraryMenu->setTitle(tr("&Bottom of library..."));
|
||||
aAlwaysRevealTopCard->setText(tr("&Always reveal top card"));
|
||||
aAlwaysLookAtTopCard->setText(tr("&Always look at top card"));
|
||||
aOpenDeckInDeckEditor->setText(tr("&Open deck in deck editor"));
|
||||
|
||||
aDrawCard->setText(tr("&Draw card"));
|
||||
aDrawCards->setText(tr("D&raw cards..."));
|
||||
aUndoDraw->setText(tr("&Undo last draw"));
|
||||
|
||||
aShuffle->setText(tr("Shuffle"));
|
||||
|
||||
aMoveTopToPlay->setText(tr("&Play top card"));
|
||||
aMoveTopToPlayFaceDown->setText(tr("Play top card &face down"));
|
||||
aMoveTopCardToBottom->setText(tr("Put top card on &bottom"));
|
||||
aMoveTopCardToGraveyard->setText(tr("Move top card to grave&yard"));
|
||||
aMoveTopCardToExile->setText(tr("Move top card to e&xile"));
|
||||
aMoveTopCardsToGraveyard->setText(tr("Move top cards to &graveyard..."));
|
||||
aMoveTopCardsToGraveyardFaceDown->setText(tr("Move top cards to graveyard face down..."));
|
||||
aMoveTopCardsToExile->setText(tr("Move top cards to &exile..."));
|
||||
aMoveTopCardsToExileFaceDown->setText(tr("Move top cards to exile face down..."));
|
||||
aMoveTopCardsUntil->setText(tr("Put top cards on stack &until..."));
|
||||
aShuffleTopCards->setText(tr("Shuffle top cards..."));
|
||||
|
||||
aDrawBottomCard->setText(tr("&Draw bottom card"));
|
||||
aDrawBottomCards->setText(tr("D&raw bottom cards..."));
|
||||
aMoveBottomToPlay->setText(tr("&Play bottom card"));
|
||||
aMoveBottomToPlayFaceDown->setText(tr("Play bottom card &face down"));
|
||||
aMoveBottomCardToGraveyard->setText(tr("Move bottom card to grave&yard"));
|
||||
aMoveBottomCardToExile->setText(tr("Move bottom card to e&xile"));
|
||||
aMoveBottomCardsToGraveyard->setText(tr("Move bottom cards to &graveyard..."));
|
||||
aMoveBottomCardsToGraveyardFaceDown->setText(tr("Move bottom cards to graveyard face down..."));
|
||||
aMoveBottomCardsToExile->setText(tr("Move bottom cards to &exile..."));
|
||||
aMoveBottomCardsToExileFaceDown->setText(tr("Move bottom cards to exile face down..."));
|
||||
aMoveBottomCardToTop->setText(tr("Put bottom card on &top"));
|
||||
aShuffleBottomCards->setText(tr("Shuffle bottom cards..."));
|
||||
}
|
||||
}
|
||||
|
||||
void LibraryMenu::populateRevealLibraryMenuWithActivePlayers()
|
||||
{
|
||||
mRevealLibrary->clear();
|
||||
|
||||
QAction *allPlayers = mRevealLibrary->addAction(tr("&All players"));
|
||||
allPlayers->setData(-1);
|
||||
connect(allPlayers, &QAction::triggered, this, &LibraryMenu::onRevealLibraryTriggered);
|
||||
|
||||
mRevealLibrary->addSeparator();
|
||||
|
||||
const auto &players = player->getLogic()->getGame()->getPlayerManager()->getPlayers().values();
|
||||
for (auto *other : players) {
|
||||
if (other == player->getLogic()) {
|
||||
continue;
|
||||
}
|
||||
QAction *a = mRevealLibrary->addAction(other->getPlayerInfo()->getName());
|
||||
a->setData(other->getPlayerInfo()->getId());
|
||||
connect(a, &QAction::triggered, this, &LibraryMenu::onRevealLibraryTriggered);
|
||||
}
|
||||
}
|
||||
|
||||
void LibraryMenu::populateLendLibraryMenuWithActivePlayers()
|
||||
{
|
||||
mLendLibrary->clear();
|
||||
|
||||
const auto &players = player->getLogic()->getGame()->getPlayerManager()->getPlayers().values();
|
||||
for (auto *other : players) {
|
||||
if (other == player->getLogic()) {
|
||||
continue;
|
||||
}
|
||||
QAction *a = mLendLibrary->addAction(other->getPlayerInfo()->getName());
|
||||
a->setData(other->getPlayerInfo()->getId());
|
||||
connect(a, &QAction::triggered, this, &LibraryMenu::onLendLibraryTriggered);
|
||||
}
|
||||
}
|
||||
|
||||
void LibraryMenu::populateRevealTopCardMenuWithActivePlayers()
|
||||
{
|
||||
mRevealTopCard->clear();
|
||||
|
||||
QAction *allPlayers = mRevealTopCard->addAction(tr("&All players"));
|
||||
allPlayers->setData(-1);
|
||||
connect(allPlayers, &QAction::triggered, this, &LibraryMenu::onRevealTopCardTriggered);
|
||||
|
||||
mRevealTopCard->addSeparator();
|
||||
|
||||
const auto &players = player->getLogic()->getGame()->getPlayerManager()->getPlayers().values();
|
||||
for (auto *other : players) {
|
||||
if (other == player->getLogic()) {
|
||||
continue;
|
||||
}
|
||||
QAction *a = mRevealTopCard->addAction(other->getPlayerInfo()->getName());
|
||||
a->setData(other->getPlayerInfo()->getId());
|
||||
connect(a, &QAction::triggered, this, &LibraryMenu::onRevealTopCardTriggered);
|
||||
}
|
||||
}
|
||||
|
||||
void LibraryMenu::onRevealLibraryTriggered()
|
||||
{
|
||||
if (auto *a = qobject_cast<QAction *>(sender())) {
|
||||
player->getLogic()->getPlayerActions()->actRevealLibrary(a->data().toInt());
|
||||
}
|
||||
}
|
||||
|
||||
void LibraryMenu::onLendLibraryTriggered()
|
||||
{
|
||||
if (auto *a = qobject_cast<QAction *>(sender())) {
|
||||
player->getLogic()->getPlayerActions()->actLendLibrary(a->data().toInt());
|
||||
}
|
||||
}
|
||||
|
||||
void LibraryMenu::onRevealTopCardTriggered()
|
||||
{
|
||||
QWidget *parent = nullptr;
|
||||
if (auto *view = player->scene() ? player->scene()->views().value(0) : nullptr) {
|
||||
parent = view->window();
|
||||
}
|
||||
if (auto *a = qobject_cast<QAction *>(sender())) {
|
||||
|
||||
int deckSize = player->getLogic()->getDeckZone()->getCards().size();
|
||||
bool ok = true;
|
||||
int number = QInputDialog::getInt(parent, tr("Reveal top cards of library"),
|
||||
tr("Number of cards: (max. %1)").arg(deckSize), defaultNumberTopCards, 1,
|
||||
deckSize, 1, &ok);
|
||||
|
||||
if (ok) {
|
||||
player->getLogic()->getPlayerActions()->actRevealTopCards(a->data().toInt(), number);
|
||||
defaultNumberTopCards = number;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LibraryMenu::setShortcutsActive()
|
||||
{
|
||||
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
|
||||
|
||||
aViewLibrary->setShortcuts(shortcuts.getShortcut("Player/aViewLibrary"));
|
||||
aViewTopCards->setShortcuts(shortcuts.getShortcut("Player/aViewTopCards"));
|
||||
aViewBottomCards->setShortcuts(shortcuts.getShortcut("Player/aViewBottomCards"));
|
||||
aDrawCard->setShortcuts(shortcuts.getShortcut("Player/aDrawCard"));
|
||||
aDrawCards->setShortcuts(shortcuts.getShortcut("Player/aDrawCards"));
|
||||
aUndoDraw->setShortcuts(shortcuts.getShortcut("Player/aUndoDraw"));
|
||||
aShuffle->setShortcuts(shortcuts.getShortcut("Player/aShuffle"));
|
||||
aShuffleTopCards->setShortcuts(shortcuts.getShortcut("Player/aShuffleTopCards"));
|
||||
aShuffleBottomCards->setShortcuts(shortcuts.getShortcut("Player/aShuffleBottomCards"));
|
||||
aAlwaysRevealTopCard->setShortcuts(shortcuts.getShortcut("Player/aAlwaysRevealTopCard"));
|
||||
aAlwaysLookAtTopCard->setShortcuts(shortcuts.getShortcut("Player/aAlwaysLookAtTopCard"));
|
||||
aMoveTopToPlay->setShortcuts(shortcuts.getShortcut("Player/aMoveTopToPlay"));
|
||||
aMoveTopToPlayFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveTopToPlayFaceDown"));
|
||||
aMoveTopCardToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToGraveyard"));
|
||||
aMoveTopCardsToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToGraveyard"));
|
||||
aMoveTopCardsToGraveyardFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToGraveyardFaceDown"));
|
||||
aMoveTopCardToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToExile"));
|
||||
aMoveTopCardsToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToExile"));
|
||||
aMoveTopCardsToExileFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToExileFaceDown"));
|
||||
aMoveTopCardsUntil->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsUntil"));
|
||||
aMoveTopCardToBottom->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToBottom"));
|
||||
aDrawBottomCard->setShortcuts(shortcuts.getShortcut("Player/aDrawBottomCard"));
|
||||
aDrawBottomCards->setShortcuts(shortcuts.getShortcut("Player/aDrawBottomCards"));
|
||||
aMoveBottomToPlay->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomToPlay"));
|
||||
aMoveBottomToPlayFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomToPlayFaceDown"));
|
||||
aMoveBottomCardToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToGrave"));
|
||||
aMoveBottomCardsToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToGrave"));
|
||||
aMoveBottomCardsToGraveyardFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToGraveFaceDown"));
|
||||
aMoveBottomCardToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToExile"));
|
||||
aMoveBottomCardsToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToExile"));
|
||||
aMoveBottomCardsToExileFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToExileFaceDown"));
|
||||
aMoveBottomCardToTop->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToTop"));
|
||||
}
|
||||
|
||||
void LibraryMenu::setShortcutsInactive()
|
||||
{
|
||||
aViewLibrary->setShortcut(QKeySequence());
|
||||
aViewTopCards->setShortcut(QKeySequence());
|
||||
aViewBottomCards->setShortcut(QKeySequence());
|
||||
aDrawCard->setShortcut(QKeySequence());
|
||||
aDrawCards->setShortcut(QKeySequence());
|
||||
aUndoDraw->setShortcut(QKeySequence());
|
||||
aShuffle->setShortcut(QKeySequence());
|
||||
aShuffleTopCards->setShortcut(QKeySequence());
|
||||
aShuffleBottomCards->setShortcut(QKeySequence());
|
||||
aAlwaysRevealTopCard->setShortcut(QKeySequence());
|
||||
aAlwaysLookAtTopCard->setShortcut(QKeySequence());
|
||||
aMoveTopToPlay->setShortcut(QKeySequence());
|
||||
aMoveTopToPlayFaceDown->setShortcut(QKeySequence());
|
||||
aMoveTopCardToGraveyard->setShortcut(QKeySequence());
|
||||
aMoveTopCardsToGraveyard->setShortcut(QKeySequence());
|
||||
aMoveTopCardsToGraveyardFaceDown->setShortcut(QKeySequence());
|
||||
aMoveTopCardToExile->setShortcut(QKeySequence());
|
||||
aMoveTopCardsToExile->setShortcut(QKeySequence());
|
||||
aMoveTopCardsToExileFaceDown->setShortcut(QKeySequence());
|
||||
aMoveTopCardsUntil->setShortcut(QKeySequence());
|
||||
aDrawBottomCard->setShortcut(QKeySequence());
|
||||
aDrawBottomCards->setShortcut(QKeySequence());
|
||||
aMoveBottomToPlay->setShortcut(QKeySequence());
|
||||
aMoveBottomToPlayFaceDown->setShortcut(QKeySequence());
|
||||
aMoveBottomCardToGraveyard->setShortcut(QKeySequence());
|
||||
aMoveBottomCardsToGraveyard->setShortcut(QKeySequence());
|
||||
aMoveBottomCardsToGraveyardFaceDown->setShortcut(QKeySequence());
|
||||
aMoveBottomCardToExile->setShortcut(QKeySequence());
|
||||
aMoveBottomCardsToExile->setShortcut(QKeySequence());
|
||||
aMoveBottomCardsToExileFaceDown->setShortcut(QKeySequence());
|
||||
}
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
/**
|
||||
* @file library_menu.h
|
||||
* @ingroup GameMenusZones
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef COCKATRICE_LIBRARY_MENU_H
|
||||
#define COCKATRICE_LIBRARY_MENU_H
|
||||
|
||||
#include "../../../interface/widgets/menus/tearoff_menu.h"
|
||||
#include "abstract_player_component.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QMenu>
|
||||
|
||||
class PlayerGraphicsItem;
|
||||
class PlayerLogic;
|
||||
class PlayerActions;
|
||||
|
||||
class LibraryMenu : public TearOffMenu, public AbstractPlayerComponent
|
||||
{
|
||||
Q_OBJECT
|
||||
public slots:
|
||||
void enableOpenInDeckEditorAction() const;
|
||||
void resetTopCardMenuActions();
|
||||
|
||||
public:
|
||||
LibraryMenu(PlayerGraphicsItem *player, QWidget *parent = nullptr);
|
||||
void createDrawActions();
|
||||
void createShuffleActions();
|
||||
void createMoveActions();
|
||||
void createViewActions();
|
||||
void retranslateUi() override;
|
||||
void populateRevealLibraryMenuWithActivePlayers();
|
||||
void populateLendLibraryMenuWithActivePlayers();
|
||||
void populateRevealTopCardMenuWithActivePlayers();
|
||||
void onRevealLibraryTriggered();
|
||||
void onLendLibraryTriggered();
|
||||
void onRevealTopCardTriggered();
|
||||
void setShortcutsActive() override;
|
||||
void setShortcutsInactive() override;
|
||||
|
||||
[[nodiscard]] bool isAlwaysRevealTopCardChecked() const
|
||||
{
|
||||
return aAlwaysRevealTopCard->isChecked();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isAlwaysLookAtTopCardChecked() const
|
||||
{
|
||||
return aAlwaysLookAtTopCard->isChecked();
|
||||
}
|
||||
|
||||
// expose useful actions/menus if PlayerMenu needs them
|
||||
[[nodiscard]] QMenu *revealLibrary() const
|
||||
{
|
||||
return mRevealLibrary;
|
||||
}
|
||||
[[nodiscard]] QMenu *lendLibraryMenu() const
|
||||
{
|
||||
return mLendLibrary;
|
||||
}
|
||||
[[nodiscard]] QMenu *revealTopCardMenu() const
|
||||
{
|
||||
return mRevealTopCard;
|
||||
}
|
||||
|
||||
QMenu *topLibraryMenu = nullptr;
|
||||
QMenu *bottomLibraryMenu = nullptr;
|
||||
|
||||
// Expose submenus that PlayerMenu tracks in its lists
|
||||
QMenu *mRevealLibrary = nullptr;
|
||||
QMenu *mLendLibrary = nullptr;
|
||||
QMenu *mRevealTopCard = nullptr;
|
||||
|
||||
QAction *aDrawCard = nullptr;
|
||||
QAction *aDrawCards = nullptr;
|
||||
QAction *aUndoDraw = nullptr;
|
||||
|
||||
QAction *aShuffle = nullptr;
|
||||
QAction *aViewLibrary = nullptr;
|
||||
QAction *aViewTopCards = nullptr;
|
||||
QAction *aViewBottomCards = nullptr;
|
||||
QAction *aAlwaysRevealTopCard = nullptr;
|
||||
QAction *aAlwaysLookAtTopCard = nullptr;
|
||||
QAction *aOpenDeckInDeckEditor = nullptr;
|
||||
|
||||
QAction *aMoveTopToPlay = nullptr;
|
||||
QAction *aMoveTopToPlayFaceDown = nullptr;
|
||||
QAction *aMoveTopCardToBottom = nullptr;
|
||||
QAction *aMoveTopCardToGraveyard = nullptr;
|
||||
QAction *aMoveTopCardToExile = nullptr;
|
||||
QAction *aMoveTopCardsToGraveyard = nullptr;
|
||||
QAction *aMoveTopCardsToGraveyardFaceDown = nullptr;
|
||||
QAction *aMoveTopCardsToExile = nullptr;
|
||||
QAction *aMoveTopCardsToExileFaceDown = nullptr;
|
||||
QAction *aMoveTopCardsUntil = nullptr;
|
||||
QAction *aShuffleTopCards = nullptr;
|
||||
|
||||
QAction *aDrawBottomCard = nullptr;
|
||||
QAction *aDrawBottomCards = nullptr;
|
||||
QAction *aMoveBottomToPlay = nullptr;
|
||||
QAction *aMoveBottomToPlayFaceDown = nullptr;
|
||||
QAction *aMoveBottomCardToTop = nullptr;
|
||||
QAction *aMoveBottomCardToGraveyard = nullptr;
|
||||
QAction *aMoveBottomCardToExile = nullptr;
|
||||
QAction *aMoveBottomCardsToGraveyard = nullptr;
|
||||
QAction *aMoveBottomCardsToGraveyardFaceDown = nullptr;
|
||||
QAction *aMoveBottomCardsToExile = nullptr;
|
||||
QAction *aMoveBottomCardsToExileFaceDown = nullptr;
|
||||
QAction *aShuffleBottomCards = nullptr;
|
||||
|
||||
int defaultNumberTopCards = 1;
|
||||
|
||||
private:
|
||||
PlayerGraphicsItem *player;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_LIBRARY_MENU_H
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
#include "move_menu.h"
|
||||
|
||||
#include "../card_menu_action_type.h"
|
||||
#include "../player_actions.h"
|
||||
#include "../player_logic.h"
|
||||
|
||||
MoveMenu::MoveMenu(PlayerGraphicsItem *player) : QMenu(tr("Move to"))
|
||||
{
|
||||
aMoveToTopLibrary = new QAction(this);
|
||||
aMoveToTopLibrary->setData(cmMoveToTopLibrary);
|
||||
aMoveToBottomLibrary = new QAction(this);
|
||||
aMoveToBottomLibrary->setData(cmMoveToBottomLibrary);
|
||||
aMoveToXfromTopOfLibrary = new QAction(this);
|
||||
aMoveToTable = new QAction(this);
|
||||
aMoveToTable->setData(cmMoveToTable);
|
||||
aMoveToGraveyard = new QAction(this);
|
||||
aMoveToHand = new QAction(this);
|
||||
aMoveToHand->setData(cmMoveToHand);
|
||||
aMoveToGraveyard->setData(cmMoveToGraveyard);
|
||||
aMoveToExile = new QAction(this);
|
||||
aMoveToExile->setData(cmMoveToExile);
|
||||
|
||||
auto *actions = player->getLogic()->getPlayerActions();
|
||||
|
||||
auto invoke = [player](CardMenuActionType type) {
|
||||
return [type, player]() {
|
||||
player->getLogic()->getPlayerActions()->cardMenuAction(player->getGameScene()->selectedCards(), type);
|
||||
};
|
||||
};
|
||||
|
||||
connect(aMoveToTopLibrary, &QAction::triggered, actions, invoke(cmMoveToTopLibrary));
|
||||
connect(aMoveToBottomLibrary, &QAction::triggered, actions, invoke(cmMoveToBottomLibrary));
|
||||
connect(aMoveToXfromTopOfLibrary, &QAction::triggered, actions,
|
||||
&PlayerActions::actRequestMoveCardXCardsFromTopDialog);
|
||||
connect(aMoveToTable, &QAction::triggered, actions, invoke(cmMoveToTable));
|
||||
connect(aMoveToHand, &QAction::triggered, actions, invoke(cmMoveToHand));
|
||||
connect(aMoveToGraveyard, &QAction::triggered, actions, invoke(cmMoveToGraveyard));
|
||||
connect(aMoveToExile, &QAction::triggered, actions, invoke(cmMoveToExile));
|
||||
|
||||
addAction(aMoveToTopLibrary);
|
||||
addAction(aMoveToXfromTopOfLibrary);
|
||||
addAction(aMoveToBottomLibrary);
|
||||
addSeparator();
|
||||
addAction(aMoveToTable);
|
||||
addSeparator();
|
||||
addAction(aMoveToHand);
|
||||
addSeparator();
|
||||
addAction(aMoveToGraveyard);
|
||||
addSeparator();
|
||||
addAction(aMoveToExile);
|
||||
|
||||
setShortcutsActive();
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void MoveMenu::setShortcutsActive()
|
||||
{
|
||||
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
|
||||
|
||||
aMoveToTopLibrary->setShortcuts(shortcuts.getShortcut("Player/aMoveToTopLibrary"));
|
||||
aMoveToBottomLibrary->setShortcuts(shortcuts.getShortcut("Player/aMoveToBottomLibrary"));
|
||||
aMoveToTable->setShortcuts(shortcuts.getShortcut("Player/aMoveToTable"));
|
||||
aMoveToHand->setShortcuts(shortcuts.getShortcut("Player/aMoveToHand"));
|
||||
aMoveToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveToGraveyard"));
|
||||
aMoveToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveToExile"));
|
||||
}
|
||||
|
||||
void MoveMenu::retranslateUi()
|
||||
{
|
||||
aMoveToTopLibrary->setText(tr("&Top of library in random order"));
|
||||
aMoveToXfromTopOfLibrary->setText(tr("X cards from the top of library..."));
|
||||
aMoveToBottomLibrary->setText(tr("&Bottom of library in random order"));
|
||||
aMoveToTable->setText(tr("T&able"));
|
||||
aMoveToHand->setText(tr("&Hand"));
|
||||
aMoveToGraveyard->setText(tr("&Graveyard"));
|
||||
aMoveToExile->setText(tr("&Exile"));
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
/**
|
||||
* @file move_menu.h
|
||||
* @ingroup GameMenusZones
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef COCKATRICE_MOVE_MENU_H
|
||||
#define COCKATRICE_MOVE_MENU_H
|
||||
#include <QMenu>
|
||||
|
||||
class PlayerGraphicsItem;
|
||||
class MoveMenu : public QMenu
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MoveMenu(PlayerGraphicsItem *player);
|
||||
void setShortcutsActive();
|
||||
void retranslateUi();
|
||||
|
||||
QAction *aMoveToTopLibrary = nullptr;
|
||||
QAction *aMoveToXfromTopOfLibrary = nullptr;
|
||||
QAction *aMoveToBottomLibrary = nullptr;
|
||||
|
||||
QAction *aMoveToHand = nullptr;
|
||||
QAction *aMoveToTable = nullptr;
|
||||
QAction *aMoveToGraveyard = nullptr;
|
||||
QAction *aMoveToExile = nullptr;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_MOVE_MENU_H
|
||||
|
|
@ -1,139 +0,0 @@
|
|||
#include "player_menu.h"
|
||||
|
||||
#include "../../../game_graphics/zones/hand_zone.h"
|
||||
#include "../../../game_graphics/zones/pile_zone.h"
|
||||
#include "../../../game_graphics/zones/table_zone.h"
|
||||
#include "../../../interface/widgets/tabs/tab_game.h"
|
||||
#include "../../board/card_item.h"
|
||||
#include "card_menu.h"
|
||||
#include "hand_menu.h"
|
||||
|
||||
#include <libcockatrice/protocol/pb/command_reveal_cards.pb.h>
|
||||
|
||||
PlayerMenu::PlayerMenu(PlayerGraphicsItem *_player) : QObject(_player), player(_player)
|
||||
{
|
||||
connect(player->getLogic(), &PlayerLogic::requestCardMenuUpdate, this, &PlayerMenu::updateCardMenu);
|
||||
connect(this, &PlayerMenu::cardInfoRequested, player, &PlayerGraphicsItem::cardInfoRequested);
|
||||
|
||||
playerMenu = new TearOffMenu();
|
||||
|
||||
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
|
||||
handMenu = addManagedMenu<HandMenu>(player, playerMenu);
|
||||
libraryMenu = addManagedMenu<LibraryMenu>(player, playerMenu);
|
||||
} else {
|
||||
handMenu = nullptr;
|
||||
libraryMenu = nullptr;
|
||||
}
|
||||
|
||||
graveMenu = addManagedMenu<GraveyardMenu>(player, playerMenu);
|
||||
rfgMenu = addManagedMenu<RfgMenu>(player, playerMenu);
|
||||
|
||||
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
|
||||
sideboardMenu = addManagedMenu<SideboardMenu>(player, playerMenu);
|
||||
customZonesMenu = addManagedMenu<CustomZoneMenu>(player);
|
||||
playerMenu->addSeparator();
|
||||
|
||||
countersMenu = playerMenu->addMenu(QString());
|
||||
|
||||
utilityMenu = createManagedComponent<UtilityMenu>(player, playerMenu);
|
||||
} else {
|
||||
sideboardMenu = nullptr;
|
||||
customZonesMenu = nullptr;
|
||||
countersMenu = nullptr;
|
||||
utilityMenu = nullptr;
|
||||
}
|
||||
|
||||
if (player->getLogic()->getPlayerInfo()->getLocal()) {
|
||||
sayMenu = addManagedMenu<SayMenu>(player);
|
||||
} else {
|
||||
sayMenu = nullptr;
|
||||
}
|
||||
|
||||
connect(&SettingsCache::instance().shortcuts(), &ShortcutsSettings::shortCutChanged, this,
|
||||
&PlayerMenu::refreshShortcuts);
|
||||
refreshShortcuts();
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void PlayerMenu::setMenusForGraphicItems()
|
||||
{
|
||||
player->getTableZoneGraphicsItem()->setMenu(playerMenu);
|
||||
player->getGraveyardZoneGraphicsItem()->setMenu(graveMenu, graveMenu->aViewGraveyard);
|
||||
player->getRfgZoneGraphicsItem()->setMenu(rfgMenu, rfgMenu->aViewRfg);
|
||||
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
|
||||
player->getHandZoneGraphicsItem()->setMenu(handMenu);
|
||||
player->getDeckZoneGraphicsItem()->setMenu(libraryMenu, libraryMenu->aDrawCard);
|
||||
player->getSideboardZoneGraphicsItem()->setMenu(sideboardMenu);
|
||||
}
|
||||
}
|
||||
|
||||
QMenu *PlayerMenu::updateCardMenu(const CardItem *card)
|
||||
{
|
||||
if (!card) {
|
||||
emit cardMenuUpdated(nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If is spectator (as spectators don't need card menus), return
|
||||
// only update the menu if the card is actually selected
|
||||
if ((player->getLogic()->getGame()->getPlayerManager()->isSpectator() &&
|
||||
!player->getLogic()->getGame()->getPlayerManager()->isJudge()) ||
|
||||
player->getLogic()->getGame()->getActiveCard() != card) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CardMenu *menu = new CardMenu(player, card, shortcutsActive);
|
||||
connect(menu, &CardMenu::cardInfoRequested, this, &PlayerMenu::cardInfoRequested);
|
||||
emit cardMenuUpdated(menu);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
void PlayerMenu::retranslateUi()
|
||||
{
|
||||
playerMenu->setTitle(tr("Player \"%1\"").arg(player->getLogic()->getPlayerInfo()->getName()));
|
||||
|
||||
for (auto *component : managedComponents) {
|
||||
component->retranslateUi();
|
||||
}
|
||||
|
||||
if (countersMenu) {
|
||||
countersMenu->setTitle(tr("&Counters"));
|
||||
}
|
||||
|
||||
emit retranslateRequested();
|
||||
}
|
||||
|
||||
void PlayerMenu::refreshShortcuts()
|
||||
{
|
||||
if (shortcutsActive) {
|
||||
// Judges get access to every player's menus but only want shortcuts to be set for their own.
|
||||
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge() &&
|
||||
!player->getLogic()->getPlayerInfo()->getLocal()) {
|
||||
setShortcutsInactive();
|
||||
} else {
|
||||
setShortcutsActive();
|
||||
}
|
||||
} else {
|
||||
setShortcutsInactive();
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerMenu::setShortcutsActive()
|
||||
{
|
||||
shortcutsActive = true;
|
||||
for (auto *c : managedComponents) {
|
||||
c->setShortcutsActive();
|
||||
}
|
||||
emit shortcutsActivated();
|
||||
}
|
||||
|
||||
void PlayerMenu::setShortcutsInactive()
|
||||
{
|
||||
shortcutsActive = false;
|
||||
for (auto *c : managedComponents) {
|
||||
c->setShortcutsInactive();
|
||||
}
|
||||
emit shortcutsDeactivated();
|
||||
}
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
/**
|
||||
* @file player_menu.h
|
||||
* @ingroup GameMenusPlayers
|
||||
* @brief Orchestrates lifecycle management for all player-bound UI components.
|
||||
*/
|
||||
|
||||
#ifndef COCKATRICE_PLAYER_MENU_H
|
||||
#define COCKATRICE_PLAYER_MENU_H
|
||||
|
||||
#include "../../../interface/widgets/menus/tearoff_menu.h"
|
||||
#include "custom_zone_menu.h"
|
||||
#include "grave_menu.h"
|
||||
#include "hand_menu.h"
|
||||
#include "library_menu.h"
|
||||
#include "rfg_menu.h"
|
||||
#include "say_menu.h"
|
||||
#include "sideboard_menu.h"
|
||||
#include "utility_menu.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QMenu>
|
||||
#include <QObject>
|
||||
|
||||
class CardItem;
|
||||
class CardMenu;
|
||||
class PlayerGraphicsItem;
|
||||
class PlayerMenu : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
signals:
|
||||
void cardMenuUpdated(CardMenu *cardMenu);
|
||||
void cardInfoRequested(const CardRef &cardRef);
|
||||
void shortcutsActivated();
|
||||
void shortcutsDeactivated();
|
||||
void retranslateRequested();
|
||||
|
||||
public slots:
|
||||
void setMenusForGraphicItems();
|
||||
QMenu *updateCardMenu(const CardItem *card);
|
||||
|
||||
private slots:
|
||||
void refreshShortcuts();
|
||||
|
||||
public:
|
||||
explicit PlayerMenu(PlayerGraphicsItem *player);
|
||||
/** @brief Retranslate all user-visible strings. Called on language change. */
|
||||
void retranslateUi();
|
||||
|
||||
[[nodiscard]] QMenu *getPlayerMenu() const
|
||||
{
|
||||
return playerMenu;
|
||||
}
|
||||
|
||||
[[nodiscard]] QMenu *getCountersMenu()
|
||||
{
|
||||
return countersMenu;
|
||||
}
|
||||
|
||||
[[nodiscard]] LibraryMenu *getLibraryMenu() const
|
||||
{
|
||||
return libraryMenu;
|
||||
}
|
||||
|
||||
[[nodiscard]] UtilityMenu *getUtilityMenu() const
|
||||
{
|
||||
return utilityMenu;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool getShortcutsActive() const
|
||||
{
|
||||
return shortcutsActive;
|
||||
}
|
||||
|
||||
/** @brief Bind keyboard shortcuts. Called when this player gains focus. */
|
||||
void setShortcutsActive();
|
||||
/** @brief Unbind keyboard shortcuts. Called when this player loses focus. */
|
||||
void setShortcutsInactive();
|
||||
|
||||
private:
|
||||
PlayerGraphicsItem *player;
|
||||
TearOffMenu *playerMenu;
|
||||
QMenu *countersMenu;
|
||||
HandMenu *handMenu;
|
||||
LibraryMenu *libraryMenu;
|
||||
SideboardMenu *sideboardMenu;
|
||||
GraveyardMenu *graveMenu;
|
||||
RfgMenu *rfgMenu;
|
||||
UtilityMenu *utilityMenu;
|
||||
SayMenu *sayMenu;
|
||||
CustomZoneMenu *customZonesMenu;
|
||||
|
||||
/** @brief Drives AbstractPlayerComponent lifecycle delegation. Counters are iterated separately via
|
||||
* player->getCounters().
|
||||
*/
|
||||
QList<AbstractPlayerComponent *> managedComponents;
|
||||
bool shortcutsActive = false;
|
||||
|
||||
/** @brief Creates component, adds it as a submenu of playerMenu, and registers in managedComponents. */
|
||||
template <typename MenuT, typename... Args> MenuT *addManagedMenu(Args &&...args)
|
||||
{
|
||||
auto *menu = new MenuT(std::forward<Args>(args)...);
|
||||
playerMenu->addMenu(menu);
|
||||
managedComponents.append(menu);
|
||||
return menu;
|
||||
}
|
||||
|
||||
/** @brief Creates component and registers in managedComponents, but does NOT add it as a submenu. */
|
||||
template <typename ComponentT, typename... Args> ComponentT *createManagedComponent(Args &&...args)
|
||||
{
|
||||
auto *component = new ComponentT(std::forward<Args>(args)...);
|
||||
managedComponents.append(component);
|
||||
return component;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_PLAYER_MENU_H
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
#include "pt_menu.h"
|
||||
|
||||
#include "../player_actions.h"
|
||||
#include "../player_logic.h"
|
||||
|
||||
PtMenu::PtMenu(PlayerGraphicsItem *player) : QMenu(tr("Power / toughness"))
|
||||
{
|
||||
PlayerActions *playerActions = player->getLogic()->getPlayerActions();
|
||||
|
||||
aIncP = new QAction(this);
|
||||
connect(aIncP, &QAction::triggered, playerActions,
|
||||
[player, playerActions] { playerActions->actIncP(player->getGameScene()->selectedCards()); });
|
||||
aDecP = new QAction(this);
|
||||
connect(aDecP, &QAction::triggered, playerActions,
|
||||
[player, playerActions] { playerActions->actDecP(player->getGameScene()->selectedCards()); });
|
||||
aIncT = new QAction(this);
|
||||
connect(aIncT, &QAction::triggered, playerActions,
|
||||
[player, playerActions] { playerActions->actIncT(player->getGameScene()->selectedCards()); });
|
||||
aDecT = new QAction(this);
|
||||
connect(aDecT, &QAction::triggered, playerActions,
|
||||
[player, playerActions] { playerActions->actDecT(player->getGameScene()->selectedCards()); });
|
||||
aIncPT = new QAction(this);
|
||||
connect(aIncPT, &QAction::triggered, playerActions,
|
||||
[player, playerActions] { playerActions->actIncPT(player->getGameScene()->selectedCards()); });
|
||||
aDecPT = new QAction(this);
|
||||
connect(aDecPT, &QAction::triggered, playerActions,
|
||||
[player, playerActions] { playerActions->actDecPT(player->getGameScene()->selectedCards()); });
|
||||
aFlowP = new QAction(this);
|
||||
connect(aFlowP, &QAction::triggered, playerActions,
|
||||
[player, playerActions] { playerActions->actFlowP(player->getGameScene()->selectedCards()); });
|
||||
aFlowT = new QAction(this);
|
||||
connect(aFlowT, &QAction::triggered, playerActions,
|
||||
[player, playerActions] { playerActions->actFlowT(player->getGameScene()->selectedCards()); });
|
||||
aSetPT = new QAction(this);
|
||||
connect(aSetPT, &QAction::triggered, playerActions,
|
||||
[player, playerActions] { playerActions->actRequestSetPTDialog(player->getGameScene()->selectedCards()); });
|
||||
aResetPT = new QAction(this);
|
||||
connect(aResetPT, &QAction::triggered, playerActions,
|
||||
[player, playerActions] { playerActions->actResetPT(player->getGameScene()->selectedCards()); });
|
||||
|
||||
addAction(aIncP);
|
||||
addAction(aDecP);
|
||||
addAction(aFlowP);
|
||||
addSeparator();
|
||||
addAction(aIncT);
|
||||
addAction(aDecT);
|
||||
addAction(aFlowT);
|
||||
addSeparator();
|
||||
addAction(aIncPT);
|
||||
addAction(aDecPT);
|
||||
addSeparator();
|
||||
addAction(aSetPT);
|
||||
addAction(aResetPT);
|
||||
|
||||
setShortcutsActive();
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void PtMenu::retranslateUi()
|
||||
{
|
||||
aIncP->setText(tr("&Increase power"));
|
||||
aDecP->setText(tr("&Decrease power"));
|
||||
aIncT->setText(tr("I&ncrease toughness"));
|
||||
aDecT->setText(tr("D&ecrease toughness"));
|
||||
aIncPT->setText(tr("In&crease power and toughness"));
|
||||
aDecPT->setText(tr("Dec&rease power and toughness"));
|
||||
aFlowP->setText(tr("Increase power and decrease toughness"));
|
||||
aFlowT->setText(tr("Decrease power and increase toughness"));
|
||||
aSetPT->setText(tr("Set &power and toughness..."));
|
||||
aResetPT->setText(tr("Reset p&ower and toughness"));
|
||||
}
|
||||
|
||||
void PtMenu::setShortcutsActive()
|
||||
{
|
||||
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
|
||||
|
||||
aIncP->setShortcuts(shortcuts.getShortcut("Player/aIncP"));
|
||||
aDecP->setShortcuts(shortcuts.getShortcut("Player/aDecP"));
|
||||
aIncT->setShortcuts(shortcuts.getShortcut("Player/aIncT"));
|
||||
aDecT->setShortcuts(shortcuts.getShortcut("Player/aDecT"));
|
||||
aIncPT->setShortcuts(shortcuts.getShortcut("Player/aIncPT"));
|
||||
aDecPT->setShortcuts(shortcuts.getShortcut("Player/aDecPT"));
|
||||
aFlowP->setShortcuts(shortcuts.getShortcut("Player/aFlowP"));
|
||||
aFlowT->setShortcuts(shortcuts.getShortcut("Player/aFlowT"));
|
||||
aSetPT->setShortcuts(shortcuts.getShortcut("Player/aSetPT"));
|
||||
aResetPT->setShortcuts(shortcuts.getShortcut("Player/aResetPT"));
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
/**
|
||||
* @file pt_menu.h
|
||||
* @ingroup GameMenusCards
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef COCKATRICE_PT_MENU_H
|
||||
#define COCKATRICE_PT_MENU_H
|
||||
#include <QMenu>
|
||||
|
||||
class PlayerGraphicsItem;
|
||||
class PtMenu : public QMenu
|
||||
{
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PtMenu(PlayerGraphicsItem *player);
|
||||
void retranslateUi();
|
||||
void setShortcutsActive();
|
||||
|
||||
QAction *aIncP = nullptr;
|
||||
QAction *aDecP = nullptr;
|
||||
QAction *aFlowP = nullptr;
|
||||
QAction *aIncT = nullptr;
|
||||
QAction *aDecT = nullptr;
|
||||
QAction *aFlowT = nullptr;
|
||||
|
||||
QAction *aIncPT = nullptr;
|
||||
QAction *aDecPT = nullptr;
|
||||
QAction *aSetPT = nullptr;
|
||||
QAction *aResetPT = nullptr;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_PT_MENU_H
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
#include "rfg_menu.h"
|
||||
|
||||
#include "../player_actions.h"
|
||||
#include "../player_logic.h"
|
||||
|
||||
#include <libcockatrice/utility/zone_names.h>
|
||||
|
||||
RfgMenu::RfgMenu(PlayerGraphicsItem *_player, QWidget *parent) : TearOffMenu(parent), player(_player)
|
||||
{
|
||||
createMoveActions();
|
||||
createViewActions();
|
||||
|
||||
addAction(aViewRfg);
|
||||
|
||||
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
|
||||
addSeparator();
|
||||
moveRfgMenu = addTearOffMenu(QString());
|
||||
moveRfgMenu->addAction(aMoveRfgToTopLibrary);
|
||||
moveRfgMenu->addAction(aMoveRfgToBottomLibrary);
|
||||
moveRfgMenu->addSeparator();
|
||||
moveRfgMenu->addAction(aMoveRfgToHand);
|
||||
moveRfgMenu->addSeparator();
|
||||
moveRfgMenu->addAction(aMoveRfgToGrave);
|
||||
}
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void RfgMenu::createMoveActions()
|
||||
{
|
||||
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
|
||||
auto rfg = player->getLogic()->getRfgZone();
|
||||
|
||||
aMoveRfgToTopLibrary = new QAction(this);
|
||||
aMoveRfgToTopLibrary->setData(QList<QVariant>() << ZoneNames::DECK << 0);
|
||||
aMoveRfgToBottomLibrary = new QAction(this);
|
||||
aMoveRfgToBottomLibrary->setData(QList<QVariant>() << ZoneNames::DECK << -1);
|
||||
aMoveRfgToHand = new QAction(this);
|
||||
aMoveRfgToHand->setData(QList<QVariant>() << ZoneNames::HAND << 0);
|
||||
aMoveRfgToGrave = new QAction(this);
|
||||
aMoveRfgToGrave->setData(QList<QVariant>() << ZoneNames::GRAVE << 0);
|
||||
|
||||
connect(aMoveRfgToTopLibrary, &QAction::triggered, rfg, &PileZoneLogic::moveAllToZone);
|
||||
connect(aMoveRfgToBottomLibrary, &QAction::triggered, rfg, &PileZoneLogic::moveAllToZone);
|
||||
connect(aMoveRfgToHand, &QAction::triggered, rfg, &PileZoneLogic::moveAllToZone);
|
||||
connect(aMoveRfgToGrave, &QAction::triggered, rfg, &PileZoneLogic::moveAllToZone);
|
||||
}
|
||||
}
|
||||
|
||||
void RfgMenu::createViewActions()
|
||||
{
|
||||
PlayerActions *playerActions = player->getLogic()->getPlayerActions();
|
||||
|
||||
aViewRfg = new QAction(this);
|
||||
connect(aViewRfg, &QAction::triggered, playerActions, &PlayerActions::actViewRfg);
|
||||
}
|
||||
|
||||
void RfgMenu::retranslateUi()
|
||||
{
|
||||
setTitle(tr("&Exile"));
|
||||
|
||||
aViewRfg->setText(tr("&View exile"));
|
||||
|
||||
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
|
||||
moveRfgMenu->setTitle(tr("&Move exile to..."));
|
||||
aMoveRfgToTopLibrary->setText(tr("&Top of library"));
|
||||
aMoveRfgToBottomLibrary->setText(tr("&Bottom of library"));
|
||||
aMoveRfgToHand->setText(tr("&Hand"));
|
||||
aMoveRfgToGrave->setText(tr("&Graveyard"));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
/**
|
||||
* @file rfg_menu.h
|
||||
* @ingroup GameMenusZones
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef COCKATRICE_RFG_MENU_H
|
||||
#define COCKATRICE_RFG_MENU_H
|
||||
|
||||
#include "../../../interface/widgets/menus/tearoff_menu.h"
|
||||
#include "abstract_player_component.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QMenu>
|
||||
|
||||
class PlayerGraphicsItem;
|
||||
class RfgMenu : public TearOffMenu, public AbstractPlayerComponent
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit RfgMenu(PlayerGraphicsItem *player, QWidget *parent = nullptr);
|
||||
void createMoveActions();
|
||||
void createViewActions();
|
||||
void retranslateUi() override;
|
||||
void setShortcutsActive() override
|
||||
{
|
||||
}
|
||||
void setShortcutsInactive() override
|
||||
{
|
||||
}
|
||||
|
||||
QMenu *moveRfgMenu = nullptr;
|
||||
|
||||
QAction *aViewRfg = nullptr;
|
||||
QAction *aMoveRfgToTopLibrary = nullptr;
|
||||
QAction *aMoveRfgToBottomLibrary = nullptr;
|
||||
QAction *aMoveRfgToHand = nullptr;
|
||||
QAction *aMoveRfgToGrave = nullptr;
|
||||
|
||||
private:
|
||||
PlayerGraphicsItem *player;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_RFG_MENU_H
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
#include "say_menu.h"
|
||||
|
||||
#include "../../../client/settings/cache_settings.h"
|
||||
#include "../player_actions.h"
|
||||
#include "../player_logic.h"
|
||||
|
||||
SayMenu::SayMenu(PlayerGraphicsItem *_player) : player(_player)
|
||||
{
|
||||
connect(&SettingsCache::instance().messages(), &MessageSettings::messageMacrosChanged, this, &SayMenu::initSayMenu);
|
||||
initSayMenu();
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void SayMenu::retranslateUi()
|
||||
{
|
||||
setTitle(tr("S&ay"));
|
||||
}
|
||||
|
||||
void SayMenu::setShortcutsActive()
|
||||
{
|
||||
shortcutsActive = true;
|
||||
|
||||
const auto menuActions = actions();
|
||||
for (int i = 0; i < menuActions.size() && i < 10; ++i) {
|
||||
menuActions[i]->setShortcut(QKeySequence("Ctrl+" + QString::number((i + 1) % 10)));
|
||||
}
|
||||
}
|
||||
|
||||
void SayMenu::setShortcutsInactive()
|
||||
{
|
||||
shortcutsActive = false;
|
||||
|
||||
for (auto *action : actions()) {
|
||||
action->setShortcut(QKeySequence());
|
||||
}
|
||||
}
|
||||
|
||||
void SayMenu::initSayMenu()
|
||||
{
|
||||
clear();
|
||||
|
||||
int count = SettingsCache::instance().messages().getCount();
|
||||
setEnabled(count > 0);
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
auto *newAction = new QAction(SettingsCache::instance().messages().getMessageAt(i), this);
|
||||
connect(newAction, &QAction::triggered, player->getLogic()->getPlayerActions(), &PlayerActions::actSayMessage);
|
||||
addAction(newAction);
|
||||
}
|
||||
|
||||
if (shortcutsActive) {
|
||||
setShortcutsActive();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
/**
|
||||
* @file say_menu.h
|
||||
* @ingroup GameMenusPlayers
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef COCKATRICE_SAY_MENU_H
|
||||
#define COCKATRICE_SAY_MENU_H
|
||||
|
||||
#include "abstract_player_component.h"
|
||||
|
||||
#include <QMenu>
|
||||
|
||||
class PlayerGraphicsItem;
|
||||
class SayMenu : public QMenu, public AbstractPlayerComponent
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SayMenu(PlayerGraphicsItem *player);
|
||||
|
||||
void retranslateUi() override;
|
||||
void setShortcutsActive() override;
|
||||
void setShortcutsInactive() override;
|
||||
|
||||
private slots:
|
||||
void initSayMenu();
|
||||
|
||||
private:
|
||||
PlayerGraphicsItem *player;
|
||||
bool shortcutsActive = false;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_SAY_MENU_H
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
#include "sideboard_menu.h"
|
||||
|
||||
#include "../player_actions.h"
|
||||
#include "../player_logic.h"
|
||||
|
||||
SideboardMenu::SideboardMenu(PlayerGraphicsItem *player, QMenu *playerMenu) : QMenu(playerMenu)
|
||||
{
|
||||
aViewSideboard = new QAction(this);
|
||||
connect(aViewSideboard, &QAction::triggered, player->getLogic()->getPlayerActions(),
|
||||
&PlayerActions::actViewSideboard);
|
||||
|
||||
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
|
||||
addAction(aViewSideboard);
|
||||
}
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void SideboardMenu::retranslateUi()
|
||||
{
|
||||
setTitle(tr("&Sideboard"));
|
||||
aViewSideboard->setText(tr("&View sideboard"));
|
||||
}
|
||||
|
||||
void SideboardMenu::setShortcutsActive()
|
||||
{
|
||||
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
|
||||
|
||||
aViewSideboard->setShortcuts(shortcuts.getShortcut("Player/aViewSideboard"));
|
||||
}
|
||||
|
||||
void SideboardMenu::setShortcutsInactive()
|
||||
{
|
||||
aViewSideboard->setShortcut(QKeySequence());
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
/**
|
||||
* @file sideboard_menu.h
|
||||
* @ingroup GameMenusZones
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef COCKATRICE_SIDEBOARD_MENU_H
|
||||
#define COCKATRICE_SIDEBOARD_MENU_H
|
||||
|
||||
#include "abstract_player_component.h"
|
||||
|
||||
#include <QMenu>
|
||||
|
||||
class PlayerGraphicsItem;
|
||||
class SideboardMenu : public QMenu, public AbstractPlayerComponent
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SideboardMenu(PlayerGraphicsItem *player, QMenu *playerMenu);
|
||||
void retranslateUi() override;
|
||||
void setShortcutsActive() override;
|
||||
void setShortcutsInactive() override;
|
||||
|
||||
private:
|
||||
PlayerGraphicsItem *player;
|
||||
|
||||
QAction *aViewSideboard;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_SIDEBOARD_MENU_H
|
||||
|
|
@ -1,146 +0,0 @@
|
|||
#include "utility_menu.h"
|
||||
|
||||
#include "../../../interface/deck_loader/deck_loader.h"
|
||||
#include "../player_actions.h"
|
||||
#include "../player_logic.h"
|
||||
#include "player_menu.h"
|
||||
|
||||
#include <libcockatrice/deck_list/tree/deck_list_card_node.h>
|
||||
#include <libcockatrice/deck_list/tree/inner_deck_list_node.h>
|
||||
|
||||
UtilityMenu::UtilityMenu(PlayerGraphicsItem *_player, QMenu *playerMenu) : QMenu(playerMenu), player(_player)
|
||||
{
|
||||
PlayerActions *playerActions = player->getLogic()->getPlayerActions();
|
||||
connect(playerActions, &PlayerActions::requestEnableAndSetCreateAnotherTokenAction, this,
|
||||
&UtilityMenu::setAndEnableCreateAnotherTokenAction);
|
||||
connect(playerActions, &PlayerActions::requestSetLastToken, this, &UtilityMenu::setLastToken);
|
||||
|
||||
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
|
||||
aUntapAll = new QAction(this);
|
||||
connect(aUntapAll, &QAction::triggered, playerActions, &PlayerActions::actUntapAll);
|
||||
|
||||
aRollDie = new QAction(this);
|
||||
connect(aRollDie, &QAction::triggered, playerActions, &PlayerActions::actRequestRollDieDialog);
|
||||
|
||||
aFlipCoin = new QAction(this);
|
||||
connect(aFlipCoin, &QAction::triggered, playerActions, &PlayerActions::actFlipCoin);
|
||||
|
||||
aCreateToken = new QAction(this);
|
||||
connect(aCreateToken, &QAction::triggered, playerActions, [this]() {
|
||||
player->getLogic()->getPlayerActions()->actRequestCreateTokenDialog(getPredefinedTokens());
|
||||
});
|
||||
|
||||
aCreateAnotherToken = new QAction(this);
|
||||
connect(aCreateAnotherToken, &QAction::triggered, playerActions, &PlayerActions::actCreateAnotherToken);
|
||||
aCreateAnotherToken->setEnabled(false);
|
||||
|
||||
aIncrementAllCardCounters = new QAction(this);
|
||||
connect(aIncrementAllCardCounters, &QAction::triggered, playerActions, [this]() {
|
||||
player->getLogic()->getPlayerActions()->actIncrementAllCardCounters(
|
||||
player->getGameScene()->selectedCards());
|
||||
});
|
||||
|
||||
createPredefinedTokenMenu = new QMenu(QString());
|
||||
createPredefinedTokenMenu->setEnabled(false);
|
||||
connect(player->getLogic(), &PlayerLogic::deckChanged, this, &UtilityMenu::populatePredefinedTokensMenu);
|
||||
|
||||
playerMenu->addAction(aIncrementAllCardCounters);
|
||||
playerMenu->addSeparator();
|
||||
playerMenu->addAction(aUntapAll);
|
||||
playerMenu->addSeparator();
|
||||
playerMenu->addAction(aRollDie);
|
||||
playerMenu->addAction(aFlipCoin);
|
||||
playerMenu->addSeparator();
|
||||
playerMenu->addAction(aCreateToken);
|
||||
playerMenu->addAction(aCreateAnotherToken);
|
||||
playerMenu->addMenu(createPredefinedTokenMenu);
|
||||
playerMenu->addSeparator();
|
||||
} else {
|
||||
aCreateToken = nullptr;
|
||||
aCreateAnotherToken = nullptr;
|
||||
createPredefinedTokenMenu = nullptr;
|
||||
aIncrementAllCardCounters = nullptr;
|
||||
aUntapAll = nullptr;
|
||||
aRollDie = nullptr;
|
||||
aFlipCoin = nullptr;
|
||||
}
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void UtilityMenu::populatePredefinedTokensMenu()
|
||||
{
|
||||
clear();
|
||||
setEnabled(false);
|
||||
predefinedTokens.clear();
|
||||
const DeckList &deckList = player->getLogic()->getDeck();
|
||||
|
||||
if (deckList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto tokenCardNodes = deckList.getCardNodes({DECK_ZONE_TOKENS});
|
||||
|
||||
if (!tokenCardNodes.isEmpty()) {
|
||||
setEnabled(true);
|
||||
|
||||
for (int i = 0; i < tokenCardNodes.size(); ++i) {
|
||||
const QString tokenName = tokenCardNodes[i]->getName();
|
||||
predefinedTokens.append(tokenName);
|
||||
QAction *a = addAction(tokenName);
|
||||
if (i < 10) {
|
||||
a->setShortcut(QKeySequence("Alt+" + QString::number((i + 1) % 10)));
|
||||
}
|
||||
connect(a, &QAction::triggered, player->getLogic()->getPlayerActions(),
|
||||
&PlayerActions::actCreatePredefinedToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UtilityMenu::setLastToken(CardInfoPtr lastToken)
|
||||
{
|
||||
if (!createAnotherTokenActionExists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
player->getLogic()->getPlayerActions()->setLastTokenInfo(lastToken);
|
||||
}
|
||||
|
||||
void UtilityMenu::retranslateUi()
|
||||
{
|
||||
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
|
||||
aIncrementAllCardCounters->setText(tr("Increment all card counters"));
|
||||
aUntapAll->setText(tr("&Untap all permanents"));
|
||||
aRollDie->setText(tr("R&oll die..."));
|
||||
aFlipCoin->setText(tr("Flip coin"));
|
||||
aCreateToken->setText(tr("&Create token..."));
|
||||
aCreateAnotherToken->setText(tr("C&reate another token"));
|
||||
createPredefinedTokenMenu->setTitle(tr("Cr&eate predefined token"));
|
||||
}
|
||||
}
|
||||
|
||||
void UtilityMenu::setShortcutsActive()
|
||||
{
|
||||
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
|
||||
|
||||
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
|
||||
aIncrementAllCardCounters->setShortcuts(shortcuts.getShortcut("Player/aIncrementAllCardCounters"));
|
||||
aUntapAll->setShortcuts(shortcuts.getShortcut("Player/aUntapAll"));
|
||||
aRollDie->setShortcuts(shortcuts.getShortcut("Player/aRollDie"));
|
||||
aFlipCoin->setShortcuts(shortcuts.getShortcut("Player/aFlipCoin"));
|
||||
aCreateToken->setShortcuts(shortcuts.getShortcut("Player/aCreateToken"));
|
||||
aCreateAnotherToken->setShortcuts(shortcuts.getShortcut("Player/aCreateAnotherToken"));
|
||||
}
|
||||
}
|
||||
|
||||
void UtilityMenu::setShortcutsInactive()
|
||||
{
|
||||
if (player->getLogic()->getPlayerInfo()->getLocalOrJudge()) {
|
||||
aUntapAll->setShortcut(QKeySequence());
|
||||
aRollDie->setShortcut(QKeySequence());
|
||||
aFlipCoin->setShortcut(QKeySequence());
|
||||
aCreateToken->setShortcut(QKeySequence());
|
||||
aCreateAnotherToken->setShortcut(QKeySequence());
|
||||
aIncrementAllCardCounters->setShortcut(QKeySequence());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
/**
|
||||
* @file utility_menu.h
|
||||
* @ingroup GameMenusPlayers
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef COCKATRICE_UTILITY_MENU_H
|
||||
#define COCKATRICE_UTILITY_MENU_H
|
||||
|
||||
#include "abstract_player_component.h"
|
||||
|
||||
#include <QMenu>
|
||||
#include <libcockatrice/card/card_info.h>
|
||||
|
||||
class PlayerGraphicsItem;
|
||||
class UtilityMenu : public QMenu, public AbstractPlayerComponent
|
||||
{
|
||||
Q_OBJECT
|
||||
public slots:
|
||||
void populatePredefinedTokensMenu();
|
||||
void setLastToken(CardInfoPtr lastToken);
|
||||
void retranslateUi() override;
|
||||
void setShortcutsActive() override;
|
||||
void setShortcutsInactive() override;
|
||||
|
||||
public:
|
||||
explicit UtilityMenu(PlayerGraphicsItem *player, QMenu *playerMenu);
|
||||
|
||||
[[nodiscard]] bool createAnotherTokenActionExists() const
|
||||
{
|
||||
return aCreateAnotherToken != nullptr;
|
||||
}
|
||||
|
||||
void setAndEnableCreateAnotherTokenAction(QString text)
|
||||
{
|
||||
aCreateAnotherToken->setText(tr("C&reate another %1 token").arg(text));
|
||||
aCreateAnotherToken->setEnabled(true);
|
||||
}
|
||||
|
||||
QStringList getPredefinedTokens() const
|
||||
{
|
||||
return predefinedTokens;
|
||||
}
|
||||
|
||||
private:
|
||||
PlayerGraphicsItem *player;
|
||||
QStringList predefinedTokens;
|
||||
|
||||
QMenu *createPredefinedTokenMenu;
|
||||
|
||||
QAction *aIncrementAllCardCounters;
|
||||
QAction *aUntapAll, *aRollDie, *aFlipCoin;
|
||||
QAction *aCreateToken, *aCreateAnotherToken;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_UTILITY_MENU_H
|
||||
|
|
@ -1,14 +1,13 @@
|
|||
#include "player_actions.h"
|
||||
|
||||
#include "../../game_graphics/dialogs/dlg_move_top_cards_until.h"
|
||||
#include "../../game_graphics/dialogs/dlg_roll_dice.h"
|
||||
#include "../../game_graphics/player/card_menu_action_type.h"
|
||||
#include "../../game_graphics/zones/hand_zone.h"
|
||||
#include "../../game_graphics/zones/table_zone.h"
|
||||
#include "../../interface/widgets/tabs/tab_game.h"
|
||||
#include "../../interface/widgets/utility/get_text_with_max.h"
|
||||
#include "../board/card_item.h"
|
||||
#include "../dialogs/dlg_move_top_cards_until.h"
|
||||
#include "../dialogs/dlg_roll_dice.h"
|
||||
#include "../zones/view_zone_logic.h"
|
||||
#include "card_menu_action_type.h"
|
||||
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
#include <libcockatrice/card/relation/card_relation.h>
|
||||
|
|
|
|||
|
|
@ -7,9 +7,11 @@
|
|||
|
||||
#ifndef COCKATRICE_PLAYER_ACTIONS_H
|
||||
#define COCKATRICE_PLAYER_ACTIONS_H
|
||||
#include "../dialogs/dlg_create_token.h"
|
||||
#include "../dialogs/dlg_move_top_cards_until.h"
|
||||
#include "card_menu_action_type.h"
|
||||
|
||||
#include "../../game_graphics/board/card_item.h"
|
||||
#include "../../game_graphics/dialogs/dlg_create_token.h"
|
||||
#include "../../game_graphics/dialogs/dlg_move_top_cards_until.h"
|
||||
#include "../../game_graphics/player/card_menu_action_type.h"
|
||||
#include "event_processing_options.h"
|
||||
#include "player_logic.h"
|
||||
|
||||
|
|
@ -26,7 +28,6 @@ class Message;
|
|||
}
|
||||
} // namespace google
|
||||
|
||||
class CardItem;
|
||||
class Command_MoveCard;
|
||||
class GameEventContext;
|
||||
class PendingCommand;
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
#include "player_area.h"
|
||||
|
||||
#include "../../interface/theme_manager.h"
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
PlayerArea::PlayerArea(QGraphicsItem *parentItem) : QObject(), QGraphicsItem(parentItem)
|
||||
{
|
||||
setCacheMode(DeviceCoordinateCache);
|
||||
connect(themeManager, &ThemeManager::themeChanged, this, &PlayerArea::updateBg);
|
||||
updateBg();
|
||||
}
|
||||
|
||||
void PlayerArea::updateBg()
|
||||
{
|
||||
update();
|
||||
}
|
||||
|
||||
void PlayerArea::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
||||
{
|
||||
QBrush brush = themeManager->getExtraBgBrush(ThemeManager::Player, playerZoneId);
|
||||
painter->fillRect(boundingRect(), brush);
|
||||
}
|
||||
|
||||
void PlayerArea::setSize(qreal width, qreal height)
|
||||
{
|
||||
prepareGeometryChange();
|
||||
bRect = QRectF(0, 0, width, height);
|
||||
}
|
||||
|
||||
void PlayerArea::setPlayerZoneId(int _playerZoneId)
|
||||
{
|
||||
playerZoneId = _playerZoneId;
|
||||
}
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
/**
|
||||
* @file player_area.h
|
||||
* @ingroup GameGraphicsPlayers
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef COCKATRICE_PLAYER_AREA_H
|
||||
#define COCKATRICE_PLAYER_AREA_H
|
||||
|
||||
#include "../../game_graphics/board/graphics_item_type.h"
|
||||
#include "QGraphicsItem"
|
||||
|
||||
/**
|
||||
* The entire graphical area belonging to a single player.
|
||||
*/
|
||||
class PlayerArea : public QObject, public QGraphicsItem
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(QGraphicsItem)
|
||||
private:
|
||||
QRectF bRect;
|
||||
int playerZoneId;
|
||||
private slots:
|
||||
void updateBg();
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
Type = typeOther
|
||||
};
|
||||
[[nodiscard]] int type() const override
|
||||
{
|
||||
return Type;
|
||||
}
|
||||
|
||||
explicit PlayerArea(QGraphicsItem *parent = nullptr);
|
||||
[[nodiscard]] QRectF boundingRect() const override
|
||||
{
|
||||
return bRect;
|
||||
}
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||
|
||||
void setSize(qreal width, qreal height);
|
||||
|
||||
void setPlayerZoneId(int _playerZoneId);
|
||||
[[nodiscard]] int getPlayerZoneId() const
|
||||
{
|
||||
return playerZoneId;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_PLAYER_AREA_H
|
||||
|
|
@ -1,298 +0,0 @@
|
|||
#include "player_dialogs.h"
|
||||
|
||||
#include "../../client/settings/card_counter_settings.h"
|
||||
#include "../../interface/widgets/utility/get_text_with_max.h"
|
||||
#include "../board/card_item.h"
|
||||
#include "../dialogs/dlg_roll_dice.h"
|
||||
#include "../player/player_graphics_item.h"
|
||||
|
||||
#include <QInputDialog>
|
||||
#include <libcockatrice/card/relation/card_relation.h>
|
||||
|
||||
PlayerDialogs::PlayerDialogs(PlayerGraphicsItem *_player, PlayerActions *_playerActions)
|
||||
: QObject(_player), player(_player), playerActions(_playerActions)
|
||||
{
|
||||
connect(playerActions, &PlayerActions::requestViewTopCardsDialog, this,
|
||||
&PlayerDialogs::onViewTopCardsDialogRequested);
|
||||
|
||||
connect(playerActions, &PlayerActions::requestViewBottomCardsDialog, this,
|
||||
&PlayerDialogs::onViewBottomCardsDialogRequested);
|
||||
|
||||
connect(playerActions, &PlayerActions::requestShuffleTopDialog, this, &PlayerDialogs::onShuffleTopDialogRequested);
|
||||
|
||||
connect(playerActions, &PlayerActions::requestShuffleBottomDialog, this,
|
||||
&PlayerDialogs::onShuffleBottomDialogRequested);
|
||||
|
||||
connect(playerActions, &PlayerActions::requestMulliganDialog, this, &PlayerDialogs::onMulliganDialogRequested);
|
||||
|
||||
connect(playerActions, &PlayerActions::requestDrawCardsDialog, this, &PlayerDialogs::onDrawCardsDialogRequested);
|
||||
|
||||
connect(playerActions, &PlayerActions::requestMoveTopCardsToDialog, this,
|
||||
&PlayerDialogs::onMoveTopCardsToDialogRequested);
|
||||
|
||||
connect(playerActions, &PlayerActions::requestMoveTopCardsUntilDialog, this,
|
||||
&PlayerDialogs::onMoveTopCardsUntilDialogRequested);
|
||||
|
||||
connect(playerActions, &PlayerActions::requestMoveBottomCardsToDialog, this,
|
||||
&PlayerDialogs::onMoveBottomCardsToDialogRequested);
|
||||
|
||||
connect(playerActions, &PlayerActions::requestDrawBottomCardsDialog, this,
|
||||
&PlayerDialogs::onDrawBottomCardsDialogRequested);
|
||||
|
||||
connect(playerActions, &PlayerActions::requestRollDieDialog, this, &PlayerDialogs::onRollDieDialogRequested);
|
||||
|
||||
connect(playerActions, &PlayerActions::requestCreateTokenDialog, this,
|
||||
&PlayerDialogs::onCreateTokenDialogRequested);
|
||||
|
||||
connect(playerActions, &PlayerActions::requestCreateRelatedFromRelationDialog, this,
|
||||
&PlayerDialogs::onCreateRelatedFromRelationDialogRequested);
|
||||
|
||||
connect(playerActions, &PlayerActions::requestMoveCardXCardsFromTopDialog, this,
|
||||
&PlayerDialogs::onMoveCardXCardsFromTopDialogRequested);
|
||||
|
||||
connect(playerActions, &PlayerActions::requestSetPTDialog, this, &PlayerDialogs::onSetPTDialogRequested);
|
||||
|
||||
connect(playerActions, &PlayerActions::requestSetAnnotationDialog, this,
|
||||
&PlayerDialogs::onSetAnnotationDialogRequested);
|
||||
|
||||
connect(playerActions, &PlayerActions::requestSetCardCounterDialog, this,
|
||||
&PlayerDialogs::onSetCardCounterDialogRequested);
|
||||
}
|
||||
|
||||
void PlayerDialogs::onViewTopCardsDialogRequested(int defaultNumberTopCards, int deckSize)
|
||||
{
|
||||
bool ok;
|
||||
int number = QInputDialog::getInt(dialogParent(), tr("View top cards of library"),
|
||||
tr("Number of cards: (max. %1)").arg(deckSize), defaultNumberTopCards, 1,
|
||||
deckSize, 1, &ok);
|
||||
if (ok) {
|
||||
playerActions->actViewTopCards(number);
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerDialogs::onViewBottomCardsDialogRequested(int defaultNumberBottomCards, int deckSize)
|
||||
{
|
||||
bool ok;
|
||||
int number = QInputDialog::getInt(dialogParent(), tr("View bottom cards of library"),
|
||||
tr("Number of cards: (max. %1)").arg(deckSize), defaultNumberBottomCards, 1,
|
||||
deckSize, 1, &ok);
|
||||
if (ok) {
|
||||
playerActions->actViewBottomCards(number);
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerDialogs::onShuffleTopDialogRequested(int defaultNumberTopCards, int maxCards)
|
||||
{
|
||||
bool ok;
|
||||
int number = QInputDialog::getInt(dialogParent(), tr("Shuffle top cards of library"),
|
||||
tr("Number of cards: (max. %1)").arg(maxCards), defaultNumberTopCards, 1,
|
||||
maxCards, 1, &ok);
|
||||
if (ok) {
|
||||
playerActions->actShuffleTop(number);
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerDialogs::onShuffleBottomDialogRequested(int defaultNumberBottomCards, int maxCards)
|
||||
{
|
||||
bool ok;
|
||||
int number = QInputDialog::getInt(dialogParent(), tr("Shuffle bottom cards of library"),
|
||||
tr("Number of cards: (max. %1)").arg(maxCards), defaultNumberBottomCards, 1,
|
||||
maxCards, 1, &ok);
|
||||
if (ok) {
|
||||
playerActions->actShuffleBottom(number);
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerDialogs::onMulliganDialogRequested(int startSize, int handSize, int deckSize)
|
||||
{
|
||||
bool ok;
|
||||
int number = QInputDialog::getInt(dialogParent(), tr("Draw hand"),
|
||||
tr("Number of cards: (max. %1)").arg(deckSize) + '\n' +
|
||||
tr("0 and lower are in comparison to current hand size"),
|
||||
startSize, -handSize, deckSize, 1, &ok);
|
||||
|
||||
if (ok) {
|
||||
playerActions->actMulligan(number);
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerDialogs::onDrawCardsDialogRequested(int defaultNumberTopCards, int deckSize)
|
||||
{
|
||||
bool ok;
|
||||
int number = QInputDialog::getInt(dialogParent(), tr("Draw cards"), tr("Number of cards: (max. %1)").arg(deckSize),
|
||||
defaultNumberTopCards, 1, deckSize, 1, &ok);
|
||||
|
||||
if (ok) {
|
||||
playerActions->actDrawCards(number);
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerDialogs::onMoveTopCardsToDialogRequested(int defaultNumberTopCards,
|
||||
int maxCards,
|
||||
const QString &targetZone,
|
||||
const QString &zoneDisplayName,
|
||||
bool faceDown)
|
||||
{
|
||||
bool ok;
|
||||
int number = QInputDialog::getInt(dialogParent(), tr("Move top cards to %1").arg(zoneDisplayName),
|
||||
tr("Number of cards: (max. %1)").arg(maxCards), defaultNumberTopCards, 1,
|
||||
maxCards, 1, &ok);
|
||||
if (ok) {
|
||||
playerActions->moveTopCardsTo(number, targetZone, faceDown);
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerDialogs::onMoveTopCardsUntilDialogRequested(MoveTopCardsUntilOptions options)
|
||||
{
|
||||
DlgMoveTopCardsUntil dlg(dialogParent(), options);
|
||||
if (!dlg.exec()) {
|
||||
return;
|
||||
}
|
||||
playerActions->moveTopCardsUntil(dlg.getExpr(), dlg.getOptions());
|
||||
}
|
||||
|
||||
void PlayerDialogs::onMoveBottomCardsToDialogRequested(int defaultNumberBottomCards,
|
||||
int maxCards,
|
||||
const QString &targetZone,
|
||||
const QString &zoneDisplayName,
|
||||
bool faceDown)
|
||||
{
|
||||
bool ok;
|
||||
int number = QInputDialog::getInt(dialogParent(), tr("Move bottom cards to %1").arg(zoneDisplayName),
|
||||
tr("Number of cards: (max. %1)").arg(maxCards), defaultNumberBottomCards, 1,
|
||||
maxCards, 1, &ok);
|
||||
if (ok) {
|
||||
playerActions->moveBottomCardsTo(number, targetZone, faceDown);
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerDialogs::onDrawBottomCardsDialogRequested(int defaultNumberBottomCards, int maxCards)
|
||||
{
|
||||
bool ok;
|
||||
int number =
|
||||
QInputDialog::getInt(dialogParent(), tr("Draw bottom cards"), tr("Number of cards: (max. %1)").arg(maxCards),
|
||||
defaultNumberBottomCards, 1, maxCards, 1, &ok);
|
||||
if (ok) {
|
||||
playerActions->actDrawBottomCards(number);
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerDialogs::onRollDieDialogRequested()
|
||||
{
|
||||
DlgRollDice dlg(dialogParent());
|
||||
if (!dlg.exec()) {
|
||||
return;
|
||||
}
|
||||
playerActions->actRollDie(dlg.getDieSideCount(), dlg.getDiceToRollCount());
|
||||
}
|
||||
|
||||
void PlayerDialogs::onCreateRelatedFromRelationDialogRequested(const CardItem *sourceCard,
|
||||
const CardRelation *cardRelation)
|
||||
{
|
||||
if (sourceCard == nullptr || cardRelation == nullptr) {
|
||||
playerActions->setLastRelatedCreationSucceeded(false);
|
||||
return;
|
||||
}
|
||||
|
||||
int variableCount = cardRelation->getDefaultCount();
|
||||
|
||||
if (cardRelation->getIsVariable()) {
|
||||
bool ok;
|
||||
|
||||
emit requestDialogSemaphore(true);
|
||||
|
||||
variableCount = QInputDialog::getInt(dialogParent(), tr("Create tokens"), tr("Number:"),
|
||||
cardRelation->getDefaultCount(), 1, MAX_TOKENS_PER_DIALOG, 1, &ok);
|
||||
|
||||
emit requestDialogSemaphore(false);
|
||||
|
||||
if (!ok) {
|
||||
playerActions->setLastRelatedCreationSucceeded(false); // cancelled
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const bool succeeded = playerActions->createRelatedFromRelation(sourceCard, cardRelation, variableCount);
|
||||
|
||||
playerActions->setLastRelatedCreationSucceeded(succeeded);
|
||||
|
||||
if (succeeded) {
|
||||
playerActions->onRelatedCardCreated(sourceCard, cardRelation); // only on confirmed success
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerDialogs::onCreateTokenDialogRequested(const QStringList &predefinedTokens)
|
||||
{
|
||||
DlgCreateToken dlg(predefinedTokens, dialogParent());
|
||||
if (!dlg.exec()) {
|
||||
return;
|
||||
}
|
||||
|
||||
playerActions->actCreateToken(dlg.getTokenInfo());
|
||||
}
|
||||
|
||||
void PlayerDialogs::onMoveCardXCardsFromTopDialogRequested(int defaultNumberTopCardsToPlaceBelow, int deckSize)
|
||||
{
|
||||
bool ok;
|
||||
int number =
|
||||
QInputDialog::getInt(dialogParent(), tr("Place card X cards from top of library"),
|
||||
tr("Which position should this card be placed:") + "\n" + tr("(max. %1)").arg(deckSize),
|
||||
defaultNumberTopCardsToPlaceBelow, 1, deckSize, 1, &ok);
|
||||
number -= 1; // indexes start at 0
|
||||
|
||||
if (ok) {
|
||||
playerActions->actMoveCardXCardsFromTop(player->getGameScene()->selectedCards(), number);
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerDialogs::onSetPTDialogRequested(const QString &oldPT)
|
||||
{
|
||||
bool ok;
|
||||
auto cards = player->getGameScene()->selectedCards();
|
||||
emit requestDialogSemaphore(true);
|
||||
QString pt = getTextWithMax(dialogParent(), tr("Change power/toughness"), tr("Change stats to:"), QLineEdit::Normal,
|
||||
oldPT, &ok);
|
||||
emit requestDialogSemaphore(false);
|
||||
|
||||
if (!ok || player->getLogic()->clearCardsToDelete()) {
|
||||
return;
|
||||
}
|
||||
|
||||
playerActions->actSetPT(cards, pt);
|
||||
}
|
||||
|
||||
void PlayerDialogs::onSetAnnotationDialogRequested(const QString &oldAnnotation)
|
||||
{
|
||||
auto cards = player->getGameScene()->selectedCards();
|
||||
emit requestDialogSemaphore(true);
|
||||
AnnotationDialog *dialog = new AnnotationDialog(dialogParent());
|
||||
dialog->setOptions(QInputDialog::UsePlainTextEditForTextInput);
|
||||
dialog->setWindowTitle(tr("Set annotation"));
|
||||
dialog->setLabelText(tr("Please enter the new annotation:"));
|
||||
dialog->setTextValue(oldAnnotation);
|
||||
bool ok = dialog->exec();
|
||||
emit requestDialogSemaphore(false);
|
||||
if (!ok || player->getLogic()->clearCardsToDelete()) {
|
||||
return;
|
||||
}
|
||||
QString annotation = dialog->textValue().left(MAX_NAME_LENGTH);
|
||||
playerActions->actSetAnnotation(cards, annotation);
|
||||
}
|
||||
|
||||
void PlayerDialogs::onSetCardCounterDialogRequested(int counterId, const QString &oldValueForDlg)
|
||||
{
|
||||
auto cards = player->getGameScene()->selectedCards();
|
||||
emit requestDialogSemaphore(true);
|
||||
|
||||
auto &cardCounterSettings = SettingsCache::instance().cardCounters();
|
||||
QString counterName = cardCounterSettings.displayName(counterId);
|
||||
|
||||
AbstractCounterDialog dialog(counterName, oldValueForDlg, dialogParent());
|
||||
int ok = dialog.exec();
|
||||
|
||||
emit requestDialogSemaphore(false);
|
||||
if (!ok || player->getLogic()->clearCardsToDelete()) {
|
||||
return;
|
||||
}
|
||||
playerActions->actSetCardCounter(cards, counterId, dialog.textValue());
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
#ifndef COCKATRICE_PLAYER_DIALOGS_H
|
||||
#define COCKATRICE_PLAYER_DIALOGS_H
|
||||
#include "player_actions.h"
|
||||
|
||||
#include <QGraphicsView>
|
||||
#include <QObject>
|
||||
|
||||
class PlayerGraphicsItem;
|
||||
class PlayerDialogs : public QObject
|
||||
{
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PlayerDialogs(PlayerGraphicsItem *player, PlayerActions *playerActions);
|
||||
|
||||
signals:
|
||||
void requestDialogSemaphore(bool active);
|
||||
|
||||
public slots:
|
||||
void onViewTopCardsDialogRequested(int defaultNumberTopCards, int deckSize);
|
||||
void onViewBottomCardsDialogRequested(int defaultNumberBottomCards, int deckSize);
|
||||
void onShuffleTopDialogRequested(int defaultNumberTopCards, int maxCards);
|
||||
void onShuffleBottomDialogRequested(int defaultNumberBottomCards, int maxCards);
|
||||
void onMulliganDialogRequested(int startSize, int handSize, int deckSize);
|
||||
void onDrawCardsDialogRequested(int defaultNumberTopCards, int deckSize);
|
||||
void onMoveTopCardsToDialogRequested(int defaultNumberTopCards,
|
||||
int maxCards,
|
||||
const QString &targetZone,
|
||||
const QString &zoneDisplayName,
|
||||
bool faceDown);
|
||||
void onMoveTopCardsUntilDialogRequested(MoveTopCardsUntilOptions options);
|
||||
void onMoveBottomCardsToDialogRequested(int defaultNumberBottomCards,
|
||||
int maxCards,
|
||||
const QString &targetZone,
|
||||
const QString &zoneDisplayName,
|
||||
bool faceDown);
|
||||
void onDrawBottomCardsDialogRequested(int defaultNumberBottomCards, int maxCards);
|
||||
void onRollDieDialogRequested();
|
||||
void onCreateRelatedFromRelationDialogRequested(const CardItem *sourceCard, const CardRelation *cardRelation);
|
||||
void onCreateTokenDialogRequested(const QStringList &predefinedTokens);
|
||||
void onMoveCardXCardsFromTopDialogRequested(int defaultNumberTopCardsToPlaceBelow, int deckSize);
|
||||
void onSetPTDialogRequested(const QString &oldPT);
|
||||
void onSetAnnotationDialogRequested(const QString &oldAnnotation);
|
||||
void onSetCardCounterDialogRequested(int counterId, const QString &oldValueForDlg);
|
||||
|
||||
private:
|
||||
PlayerGraphicsItem *player;
|
||||
PlayerActions *playerActions;
|
||||
|
||||
QWidget *dialogParent() const
|
||||
{
|
||||
if (auto *s = player->scene()) {
|
||||
if (auto *v = s->views().value(0)) {
|
||||
return v->window();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_PLAYER_DIALOGS_H
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
#include "player_event_handler.h"
|
||||
|
||||
#include "../../game_graphics/board/arrow_item.h"
|
||||
#include "../../game_graphics/board/card_item.h"
|
||||
#include "../../game_graphics/zones/view_zone.h"
|
||||
#include "../../interface/widgets/tabs/tab_game.h"
|
||||
#include "../board/arrow_data.h"
|
||||
#include "../board/arrow_item.h"
|
||||
#include "../board/card_item.h"
|
||||
#include "../board/card_list.h"
|
||||
#include "player_actions.h"
|
||||
#include "player_logic.h"
|
||||
|
|
|
|||
|
|
@ -1,282 +0,0 @@
|
|||
#include "player_graphics_item.h"
|
||||
|
||||
#include "../../game_graphics/zones/hand_zone.h"
|
||||
#include "../../game_graphics/zones/pile_zone.h"
|
||||
#include "../../game_graphics/zones/stack_zone.h"
|
||||
#include "../../game_graphics/zones/table_zone.h"
|
||||
#include "../../interface/widgets/tabs/tab_game.h"
|
||||
#include "../board/abstract_card_item.h"
|
||||
#include "../board/counter_general.h"
|
||||
#include "../hand_counter.h"
|
||||
#include "player_actions.h"
|
||||
#include "player_dialogs.h"
|
||||
|
||||
#include <QGraphicsView>
|
||||
|
||||
PlayerGraphicsItem::PlayerGraphicsItem(PlayerLogic *_player) : player(_player)
|
||||
{
|
||||
connect(&SettingsCache::instance(), &SettingsCache::horizontalHandChanged, this,
|
||||
&PlayerGraphicsItem::rearrangeZones);
|
||||
connect(&SettingsCache::instance(), &SettingsCache::handJustificationChanged, this,
|
||||
&PlayerGraphicsItem::rearrangeZones);
|
||||
connect(player, &PlayerLogic::rearrangeCounters, this, &PlayerGraphicsItem::rearrangeCounters);
|
||||
connect(player, &PlayerLogic::activeChanged, this, &PlayerGraphicsItem::onPlayerActiveChanged);
|
||||
connect(player, &PlayerLogic::concededChanged, this, [this](int, bool c) { setVisible(!c); });
|
||||
connect(player, &PlayerLogic::zoneIdChanged, this, [this](int id) { playerArea->setPlayerZoneId(id); });
|
||||
|
||||
connect(player, &PlayerLogic::counterAdded, this, &PlayerGraphicsItem::onCounterAdded);
|
||||
connect(player, &PlayerLogic::counterRemoved, this, &PlayerGraphicsItem::onCounterRemoved);
|
||||
|
||||
playerMenu = new PlayerMenu(this);
|
||||
|
||||
connect(playerMenu, &PlayerMenu::shortcutsActivated, this, [this]() {
|
||||
for (auto *ctr : counterWidgets) {
|
||||
ctr->setShortcutsActive();
|
||||
}
|
||||
});
|
||||
connect(playerMenu, &PlayerMenu::shortcutsDeactivated, this, [this]() {
|
||||
for (auto *ctr : counterWidgets) {
|
||||
ctr->setShortcutsInactive();
|
||||
}
|
||||
});
|
||||
connect(playerMenu, &PlayerMenu::retranslateRequested, this, [this]() {
|
||||
for (auto *ctr : counterWidgets) {
|
||||
ctr->retranslateUi();
|
||||
}
|
||||
});
|
||||
|
||||
playerDialogs = new PlayerDialogs(this, player->getPlayerActions());
|
||||
|
||||
connect(playerDialogs, &PlayerDialogs::requestDialogSemaphore, player, &PlayerLogic::setDialogSemaphore);
|
||||
|
||||
playerArea = new PlayerArea(this);
|
||||
|
||||
playerTarget = new PlayerTarget(player, playerArea);
|
||||
qreal avatarMargin =
|
||||
(counterAreaWidth + CardDimensions::HEIGHT_F + 15 - playerTarget->boundingRect().width()) / 2.0;
|
||||
playerTarget->setPos(QPointF(avatarMargin, avatarMargin));
|
||||
|
||||
initializeZones();
|
||||
|
||||
playerMenu->setMenusForGraphicItems();
|
||||
|
||||
connect(tableZoneGraphicsItem, &TableZone::sizeChanged, this, &PlayerGraphicsItem::updateBoundingRect);
|
||||
|
||||
updateBoundingRect();
|
||||
|
||||
rearrangeZones();
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void PlayerGraphicsItem::retranslateUi()
|
||||
{
|
||||
playerMenu->retranslateUi();
|
||||
|
||||
QMapIterator<QString, CardZoneLogic *> zoneIterator(player->getZones());
|
||||
while (zoneIterator.hasNext()) {
|
||||
emit zoneIterator.next().value()->retranslateUi();
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerGraphicsItem::onPlayerActiveChanged(bool _active)
|
||||
{
|
||||
tableZoneGraphicsItem->setActive(_active);
|
||||
}
|
||||
|
||||
void PlayerGraphicsItem::initializeZones()
|
||||
{
|
||||
deckZoneGraphicsItem = new PileZone(player->getDeckZone(), this);
|
||||
auto base = QPointF(counterAreaWidth + (CardDimensions::HEIGHT_F - CardDimensions::WIDTH_F + 15) / 2.0,
|
||||
10 + playerTarget->boundingRect().height() + 5 -
|
||||
(CardDimensions::HEIGHT_F - CardDimensions::WIDTH_F) / 2.0);
|
||||
deckZoneGraphicsItem->setPos(base);
|
||||
|
||||
qreal h = deckZoneGraphicsItem->boundingRect().width() + 5;
|
||||
|
||||
sideboardGraphicsItem = new PileZone(player->getSideboardZone(), this);
|
||||
player->getSideboardZone()->setGraphicsVisibility(false);
|
||||
|
||||
auto *handCounter = new HandCounter(playerArea);
|
||||
handCounter->setPos(base + QPointF(0, h + 10));
|
||||
qreal h2 = handCounter->boundingRect().height();
|
||||
|
||||
graveyardZoneGraphicsItem = new PileZone(player->getGraveZone(), this);
|
||||
graveyardZoneGraphicsItem->setPos(base + QPointF(0, h + h2 + 10));
|
||||
|
||||
rfgZoneGraphicsItem = new PileZone(player->getRfgZone(), this);
|
||||
rfgZoneGraphicsItem->setPos(base + QPointF(0, 2 * h + h2 + 10));
|
||||
|
||||
tableZoneGraphicsItem = new TableZone(player->getTableZone(), mirrored, this);
|
||||
connect(tableZoneGraphicsItem, &TableZone::sizeChanged, this, &PlayerGraphicsItem::updateBoundingRect);
|
||||
connect(this, &PlayerGraphicsItem::mirroredChanged, tableZoneGraphicsItem, &TableZone::setMirrored);
|
||||
|
||||
stackZoneGraphicsItem =
|
||||
new StackZone(player->getStackZone(), static_cast<int>(tableZoneGraphicsItem->boundingRect().height()), this);
|
||||
|
||||
handZoneGraphicsItem =
|
||||
new HandZone(player->getHandZone(), static_cast<int>(tableZoneGraphicsItem->boundingRect().height()), this);
|
||||
connect(player->getPlayerActions(), &PlayerActions::requestSortHand, handZoneGraphicsItem, &HandZone::sortHand);
|
||||
|
||||
connect(handZoneGraphicsItem->getLogic(), &HandZoneLogic::cardCountChanged, handCounter,
|
||||
&HandCounter::updateNumber);
|
||||
connect(handCounter, &HandCounter::showContextMenu, handZoneGraphicsItem, &HandZone::showContextMenu);
|
||||
}
|
||||
|
||||
QRectF PlayerGraphicsItem::boundingRect() const
|
||||
{
|
||||
return bRect;
|
||||
}
|
||||
|
||||
qreal PlayerGraphicsItem::getMinimumWidth() const
|
||||
{
|
||||
qreal result = tableZoneGraphicsItem->getMinimumWidth() + CardDimensions::HEIGHT_F + 15 + counterAreaWidth +
|
||||
stackZoneGraphicsItem->boundingRect().width();
|
||||
if (!SettingsCache::instance().getHorizontalHand()) {
|
||||
result += handZoneGraphicsItem->boundingRect().width();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void PlayerGraphicsItem::paint(QPainter * /*painter*/,
|
||||
const QStyleOptionGraphicsItem * /*option*/,
|
||||
QWidget * /*widget*/)
|
||||
{
|
||||
}
|
||||
|
||||
void PlayerGraphicsItem::processSceneSizeChange(int newPlayerWidth)
|
||||
{
|
||||
// Extend table (and hand, if horizontal) to accommodate the new player width.
|
||||
qreal tableWidth = newPlayerWidth - CardDimensions::HEIGHT_F - 15 - counterAreaWidth -
|
||||
stackZoneGraphicsItem->boundingRect().width();
|
||||
if (!SettingsCache::instance().getHorizontalHand()) {
|
||||
tableWidth -= handZoneGraphicsItem->boundingRect().width();
|
||||
}
|
||||
|
||||
tableZoneGraphicsItem->setWidth(tableWidth);
|
||||
handZoneGraphicsItem->setWidth(tableWidth + stackZoneGraphicsItem->boundingRect().width());
|
||||
}
|
||||
|
||||
void PlayerGraphicsItem::setMirrored(bool _mirrored)
|
||||
{
|
||||
if (mirrored != _mirrored) {
|
||||
mirrored = _mirrored;
|
||||
emit mirroredChanged(mirrored);
|
||||
rearrangeZones();
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerGraphicsItem::onCounterAdded(CounterState *state)
|
||||
{
|
||||
AbstractCounter *widget;
|
||||
if (state->getName() == "life") {
|
||||
widget = playerTarget->addCounter(state);
|
||||
} else {
|
||||
widget = new GeneralCounter(state, player, true, this);
|
||||
}
|
||||
counterWidgets.insert(state->getId(), widget);
|
||||
|
||||
if (playerMenu->getCountersMenu() && widget->getMenu()) {
|
||||
playerMenu->getCountersMenu()->addMenu(widget->getMenu());
|
||||
}
|
||||
|
||||
if (playerMenu->getShortcutsActive()) {
|
||||
widget->setShortcutsActive();
|
||||
}
|
||||
|
||||
rearrangeCounters();
|
||||
}
|
||||
|
||||
void PlayerGraphicsItem::onCounterRemoved(int counterId)
|
||||
{
|
||||
auto *widget = counterWidgets.take(counterId);
|
||||
if (!widget) {
|
||||
return;
|
||||
}
|
||||
if (playerMenu->getCountersMenu() && widget->getMenu()) {
|
||||
playerMenu->getCountersMenu()->removeAction(widget->getMenu()->menuAction());
|
||||
}
|
||||
widget->delCounter();
|
||||
rearrangeCounters();
|
||||
}
|
||||
|
||||
void PlayerGraphicsItem::rearrangeCounters()
|
||||
{
|
||||
qreal ySize = boundingRect().y() + 80;
|
||||
constexpr qreal padding = 5;
|
||||
for (auto *ctr : counterWidgets.values()) {
|
||||
if (!ctr->getShownInCounterArea()) {
|
||||
continue;
|
||||
}
|
||||
QRectF br = ctr->boundingRect();
|
||||
ctr->setPos((counterAreaWidth - br.width()) / 2, ySize);
|
||||
ySize += br.height() + padding;
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerGraphicsItem::rearrangeZones()
|
||||
{
|
||||
auto base = QPointF(CardDimensions::HEIGHT_F + counterAreaWidth + 15, 0);
|
||||
if (SettingsCache::instance().getHorizontalHand()) {
|
||||
if (mirrored) {
|
||||
if (player->getHandZone()->contentsKnown()) {
|
||||
handVisible = true;
|
||||
handZoneGraphicsItem->setPos(base);
|
||||
base += QPointF(0, handZoneGraphicsItem->boundingRect().height());
|
||||
} else {
|
||||
handVisible = false;
|
||||
}
|
||||
|
||||
stackZoneGraphicsItem->setPos(base);
|
||||
base += QPointF(stackZoneGraphicsItem->boundingRect().width(), 0);
|
||||
|
||||
tableZoneGraphicsItem->setPos(base);
|
||||
} else {
|
||||
stackZoneGraphicsItem->setPos(base);
|
||||
|
||||
tableZoneGraphicsItem->setPos(base.x() + stackZoneGraphicsItem->boundingRect().width(), 0);
|
||||
base += QPointF(0, tableZoneGraphicsItem->boundingRect().height());
|
||||
|
||||
if (player->getHandZone()->contentsKnown()) {
|
||||
handVisible = true;
|
||||
handZoneGraphicsItem->setPos(base);
|
||||
} else {
|
||||
handVisible = false;
|
||||
}
|
||||
}
|
||||
handZoneGraphicsItem->setWidth(tableZoneGraphicsItem->getWidth() +
|
||||
stackZoneGraphicsItem->boundingRect().width());
|
||||
} else {
|
||||
handVisible = true;
|
||||
|
||||
handZoneGraphicsItem->setPos(base);
|
||||
base += QPointF(handZoneGraphicsItem->boundingRect().width(), 0);
|
||||
|
||||
stackZoneGraphicsItem->setPos(base);
|
||||
base += QPointF(stackZoneGraphicsItem->boundingRect().width(), 0);
|
||||
|
||||
tableZoneGraphicsItem->setPos(base);
|
||||
}
|
||||
handZoneGraphicsItem->setVisible(handVisible);
|
||||
handZoneGraphicsItem->updateOrientation();
|
||||
tableZoneGraphicsItem->reorganizeCards();
|
||||
updateBoundingRect();
|
||||
rearrangeCounters();
|
||||
}
|
||||
|
||||
void PlayerGraphicsItem::updateBoundingRect()
|
||||
{
|
||||
prepareGeometryChange();
|
||||
qreal width = CardDimensions::HEIGHT_F + 15 + counterAreaWidth + stackZoneGraphicsItem->boundingRect().width();
|
||||
if (SettingsCache::instance().getHorizontalHand()) {
|
||||
qreal handHeight = handVisible ? handZoneGraphicsItem->boundingRect().height() : 0;
|
||||
bRect = QRectF(0, 0, width + tableZoneGraphicsItem->boundingRect().width(),
|
||||
tableZoneGraphicsItem->boundingRect().height() + handHeight);
|
||||
} else {
|
||||
bRect = QRectF(
|
||||
0, 0, width + handZoneGraphicsItem->boundingRect().width() + tableZoneGraphicsItem->boundingRect().width(),
|
||||
tableZoneGraphicsItem->boundingRect().height());
|
||||
}
|
||||
playerArea->setSize(CardDimensions::HEIGHT_F + counterAreaWidth + 15, bRect.height());
|
||||
|
||||
emit sizeChanged();
|
||||
}
|
||||
|
|
@ -1,146 +0,0 @@
|
|||
/**
|
||||
* @file player_graphics_item.h
|
||||
* @ingroup GameGraphicsPlayers
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef COCKATRICE_PLAYER_GRAPHICS_ITEM_H
|
||||
#define COCKATRICE_PLAYER_GRAPHICS_ITEM_H
|
||||
#include "../board/abstract_counter.h"
|
||||
#include "../game_scene.h"
|
||||
#include "player_logic.h"
|
||||
|
||||
#include <QGraphicsObject>
|
||||
|
||||
class HandZone;
|
||||
class PileZone;
|
||||
class PlayerDialogs;
|
||||
class PlayerTarget;
|
||||
class StackZone;
|
||||
class TableZone;
|
||||
class ZoneViewZone;
|
||||
|
||||
class PlayerGraphicsItem : public QGraphicsObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
Type = typeOther
|
||||
};
|
||||
int type() const override
|
||||
{
|
||||
return Type;
|
||||
}
|
||||
|
||||
static constexpr int counterAreaWidth = 55;
|
||||
|
||||
explicit PlayerGraphicsItem(PlayerLogic *player);
|
||||
void initializeZones();
|
||||
|
||||
[[nodiscard]] QRectF boundingRect() const override;
|
||||
qreal getMinimumWidth() const;
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||
void processSceneSizeChange(int newPlayerWidth);
|
||||
|
||||
void setMirrored(bool _mirrored);
|
||||
|
||||
bool getMirrored() const
|
||||
{
|
||||
return mirrored;
|
||||
}
|
||||
|
||||
GameScene *getGameScene() const
|
||||
{
|
||||
return static_cast<GameScene *>(scene());
|
||||
}
|
||||
|
||||
PlayerLogic *getLogic() const
|
||||
{
|
||||
return player;
|
||||
}
|
||||
|
||||
[[nodiscard]] PlayerMenu *getPlayerMenu() const
|
||||
{
|
||||
return playerMenu;
|
||||
}
|
||||
|
||||
PlayerArea *getPlayerArea() const
|
||||
{
|
||||
return playerArea;
|
||||
}
|
||||
|
||||
PlayerTarget *getPlayerTarget() const
|
||||
{
|
||||
return playerTarget;
|
||||
}
|
||||
|
||||
[[nodiscard]] PileZone *getDeckZoneGraphicsItem() const
|
||||
{
|
||||
return deckZoneGraphicsItem;
|
||||
}
|
||||
|
||||
[[nodiscard]] PileZone *getSideboardZoneGraphicsItem() const
|
||||
{
|
||||
return sideboardGraphicsItem;
|
||||
}
|
||||
|
||||
[[nodiscard]] PileZone *getGraveyardZoneGraphicsItem() const
|
||||
{
|
||||
return graveyardZoneGraphicsItem;
|
||||
}
|
||||
[[nodiscard]] PileZone *getRfgZoneGraphicsItem() const
|
||||
{
|
||||
return rfgZoneGraphicsItem;
|
||||
}
|
||||
[[nodiscard]] TableZone *getTableZoneGraphicsItem() const
|
||||
{
|
||||
return tableZoneGraphicsItem;
|
||||
}
|
||||
[[nodiscard]] StackZone *getStackZoneGraphicsItem() const
|
||||
{
|
||||
return stackZoneGraphicsItem;
|
||||
}
|
||||
[[nodiscard]] HandZone *getHandZoneGraphicsItem() const
|
||||
{
|
||||
return handZoneGraphicsItem;
|
||||
}
|
||||
|
||||
public slots:
|
||||
void onPlayerActiveChanged(bool _active);
|
||||
void onCounterAdded(CounterState *state);
|
||||
void onCounterRemoved(int counterId);
|
||||
void rearrangeCounters();
|
||||
void retranslateUi();
|
||||
|
||||
signals:
|
||||
void sizeChanged();
|
||||
void playerCountChanged();
|
||||
void mirroredChanged(bool isMirrored);
|
||||
void cardInfoRequested(const CardRef &cardRef);
|
||||
|
||||
private:
|
||||
PlayerLogic *player;
|
||||
PlayerMenu *playerMenu;
|
||||
PlayerDialogs *playerDialogs;
|
||||
PlayerArea *playerArea;
|
||||
PlayerTarget *playerTarget;
|
||||
QMap<int, AbstractCounter *> counterWidgets;
|
||||
PileZone *deckZoneGraphicsItem;
|
||||
PileZone *sideboardGraphicsItem;
|
||||
PileZone *graveyardZoneGraphicsItem;
|
||||
PileZone *rfgZoneGraphicsItem;
|
||||
TableZone *tableZoneGraphicsItem;
|
||||
StackZone *stackZoneGraphicsItem;
|
||||
HandZone *handZoneGraphicsItem;
|
||||
QRectF bRect;
|
||||
bool mirrored;
|
||||
bool handVisible = false;
|
||||
|
||||
private slots:
|
||||
void updateBoundingRect();
|
||||
void rearrangeZones();
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_PLAYER_GRAPHICS_ITEM_H
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
#ifndef COCKATRICE_PLAYER_INFO_H
|
||||
#define COCKATRICE_PLAYER_INFO_H
|
||||
|
||||
#include "player_target.h"
|
||||
#include "../../game_graphics/player/player_target.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <libcockatrice/protocol/pb/serverinfo_user.pb.h>
|
||||
|
|
|
|||
|
|
@ -1,236 +0,0 @@
|
|||
#include "player_list_widget.h"
|
||||
|
||||
#include "../../interface/pixel_map_generator.h"
|
||||
#include "../../interface/widgets/server/user/user_context_menu.h"
|
||||
#include "../../interface/widgets/server/user/user_list_manager.h"
|
||||
#include "../../interface/widgets/server/user/user_list_widget.h"
|
||||
#include "../../interface/widgets/tabs/tab_game.h"
|
||||
#include "../../interface/widgets/tabs/tab_supervisor.h"
|
||||
|
||||
#include <QHeaderView>
|
||||
#include <QMouseEvent>
|
||||
#include <libcockatrice/protocol/pb/command_kick_from_game.pb.h>
|
||||
#include <libcockatrice/protocol/pb/serverinfo_playerproperties.pb.h>
|
||||
#include <libcockatrice/protocol/pb/session_commands.pb.h>
|
||||
|
||||
PlayerListItemDelegate::PlayerListItemDelegate(QObject *const parent) : QStyledItemDelegate(parent)
|
||||
{
|
||||
}
|
||||
|
||||
bool PlayerListItemDelegate::editorEvent(QEvent *event,
|
||||
QAbstractItemModel *model,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index)
|
||||
{
|
||||
if ((event->type() == QEvent::MouseButtonPress) && index.isValid()) {
|
||||
auto *const mouseEvent = static_cast<QMouseEvent *>(event);
|
||||
if (mouseEvent->button() == Qt::RightButton) {
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
static_cast<PlayerListWidget *>(parent())->showContextMenu(mouseEvent->globalPosition().toPoint(), index);
|
||||
#else
|
||||
static_cast<PlayerListWidget *>(parent())->showContextMenu(mouseEvent->globalPos(), index);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return QStyledItemDelegate::editorEvent(event, model, option, index);
|
||||
}
|
||||
|
||||
PlayerListTWI::PlayerListTWI() : QTreeWidgetItem(Type)
|
||||
{
|
||||
}
|
||||
|
||||
bool PlayerListTWI::operator<(const QTreeWidgetItem &other) const
|
||||
{
|
||||
// Sort by spectator/player
|
||||
if (data(1, Qt::UserRole) != other.data(1, Qt::UserRole)) {
|
||||
return data(1, Qt::UserRole).toBool();
|
||||
}
|
||||
|
||||
// Sort by player ID
|
||||
return data(4, Qt::UserRole + 1).toInt() < other.data(4, Qt::UserRole + 1).toInt();
|
||||
}
|
||||
|
||||
PlayerListWidget::PlayerListWidget(TabSupervisor *_tabSupervisor,
|
||||
AbstractClient *_client,
|
||||
AbstractGame *_game,
|
||||
QWidget *parent)
|
||||
: QTreeWidget(parent), tabSupervisor(_tabSupervisor), client(_client), game(_game), gameStarted(false)
|
||||
{
|
||||
readyIcon = QPixmap("theme:icons/ready_start");
|
||||
notReadyIcon = QPixmap("theme:icons/not_ready_start");
|
||||
concededIcon = QPixmap("theme:icons/conceded");
|
||||
playerIcon = loadColorAdjustedPixmap("theme:icons/player");
|
||||
judgeIcon = loadColorAdjustedPixmap("theme:icons/scales");
|
||||
spectatorIcon = loadColorAdjustedPixmap("theme:icons/spectator");
|
||||
lockIcon = QPixmap("theme:icons/lock");
|
||||
|
||||
if (tabSupervisor) {
|
||||
itemDelegate = new PlayerListItemDelegate(this);
|
||||
setItemDelegate(itemDelegate);
|
||||
|
||||
userContextMenu = new UserContextMenu(tabSupervisor, this, game);
|
||||
connect(userContextMenu, &UserContextMenu::openMessageDialog, this, &PlayerListWidget::openMessageDialog);
|
||||
} else {
|
||||
userContextMenu = nullptr;
|
||||
}
|
||||
|
||||
setMinimumHeight(40);
|
||||
setIconSize(QSize(20, 15));
|
||||
setColumnCount(6);
|
||||
setColumnWidth(0, 20);
|
||||
setColumnWidth(1, 20);
|
||||
setColumnWidth(2, 20);
|
||||
setColumnWidth(3, 20);
|
||||
setColumnWidth(5, 20);
|
||||
setHeaderHidden(true);
|
||||
setRootIsDecorated(false);
|
||||
setUniformRowHeights(true);
|
||||
setItemsExpandable(false);
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void PlayerListWidget::retranslateUi()
|
||||
{
|
||||
}
|
||||
|
||||
void PlayerListWidget::addPlayer(const ServerInfo_PlayerProperties &player)
|
||||
{
|
||||
QTreeWidgetItem *newPlayer = new PlayerListTWI;
|
||||
players.insert(player.player_id(), newPlayer);
|
||||
updatePlayerProperties(player);
|
||||
addTopLevelItem(newPlayer);
|
||||
sortItems(1, Qt::AscendingOrder);
|
||||
resizeColumnToContents(4);
|
||||
resizeColumnToContents(5);
|
||||
}
|
||||
|
||||
void PlayerListWidget::updatePlayerProperties(const ServerInfo_PlayerProperties &prop, int playerId)
|
||||
{
|
||||
if (playerId == -1) {
|
||||
playerId = prop.player_id();
|
||||
}
|
||||
|
||||
QTreeWidgetItem *player = players.value(playerId, 0);
|
||||
if (!player) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool isSpectator = prop.has_spectator() && prop.spectator();
|
||||
if (prop.has_judge() || prop.has_spectator()) {
|
||||
if (prop.has_judge() && prop.judge()) {
|
||||
player->setIcon(1, judgeIcon);
|
||||
} else if (isSpectator) {
|
||||
player->setIcon(1, spectatorIcon);
|
||||
} else {
|
||||
player->setIcon(1, playerIcon);
|
||||
}
|
||||
player->setData(1, Qt::UserRole, !isSpectator);
|
||||
}
|
||||
|
||||
if (!isSpectator) {
|
||||
if (prop.has_conceded()) {
|
||||
player->setData(2, Qt::UserRole, prop.conceded());
|
||||
}
|
||||
if (prop.has_ready_start()) {
|
||||
player->setData(2, Qt::UserRole + 1, prop.ready_start());
|
||||
}
|
||||
if (prop.has_conceded() || prop.has_ready_start()) {
|
||||
player->setIcon(2, gameStarted ? (prop.conceded() ? concededIcon : QIcon())
|
||||
: (prop.ready_start() ? readyIcon : notReadyIcon));
|
||||
}
|
||||
}
|
||||
if (prop.has_user_info()) {
|
||||
player->setData(3, Qt::UserRole, prop.user_info().user_level());
|
||||
player->setIcon(3, UserLevelPixmapGenerator::generateIcon(
|
||||
12, UserLevelFlags(prop.user_info().user_level()), prop.user_info().pawn_colors(), false,
|
||||
QString::fromStdString(prop.user_info().privlevel())));
|
||||
player->setText(4, QString::fromStdString(prop.user_info().name()));
|
||||
const QString country = QString::fromStdString(prop.user_info().country());
|
||||
if (!country.isEmpty()) {
|
||||
player->setIcon(4, QIcon(CountryPixmapGenerator::generatePixmap(12, country)));
|
||||
}
|
||||
player->setData(4, Qt::UserRole, QString::fromStdString(prop.user_info().name()));
|
||||
}
|
||||
|
||||
if (prop.has_player_id()) {
|
||||
player->setData(4, Qt::UserRole + 1, prop.player_id());
|
||||
}
|
||||
|
||||
if (!isSpectator) {
|
||||
if (prop.has_deck_hash()) {
|
||||
player->setText(5, QString::fromStdString(prop.deck_hash()));
|
||||
}
|
||||
if (prop.has_sideboard_locked()) {
|
||||
player->setIcon(5, prop.sideboard_locked() ? lockIcon : QIcon());
|
||||
}
|
||||
}
|
||||
if (prop.has_ping_seconds()) {
|
||||
player->setIcon(0, QIcon(PingPixmapGenerator::generatePixmap(12, prop.ping_seconds(), 10)));
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerListWidget::removePlayer(int playerId)
|
||||
{
|
||||
QTreeWidgetItem *player = players.value(playerId, 0);
|
||||
if (!player) {
|
||||
return;
|
||||
}
|
||||
players.remove(playerId);
|
||||
delete takeTopLevelItem(indexOfTopLevelItem(player));
|
||||
}
|
||||
|
||||
void PlayerListWidget::setActivePlayer(int playerId)
|
||||
{
|
||||
QMapIterator<int, QTreeWidgetItem *> i(players);
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
QTreeWidgetItem *twi = i.value();
|
||||
if (i.key() == playerId) {
|
||||
twi->setBackground(4, QColor(150, 255, 150));
|
||||
twi->setForeground(4, QColor(0, 0, 0));
|
||||
} else {
|
||||
twi->setBackground(4, palette().base().color());
|
||||
twi->setForeground(4, palette().text().color());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerListWidget::setGameStarted(bool _gameStarted, bool resuming)
|
||||
{
|
||||
gameStarted = _gameStarted;
|
||||
QMapIterator<int, QTreeWidgetItem *> i(players);
|
||||
while (i.hasNext()) {
|
||||
QTreeWidgetItem *twi = i.next().value();
|
||||
|
||||
bool isPlayer = twi->data(1, Qt::UserRole).toBool();
|
||||
if (!isPlayer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (gameStarted) {
|
||||
if (resuming) {
|
||||
twi->setIcon(2, twi->data(2, Qt::UserRole).toBool() ? concededIcon : QIcon());
|
||||
} else {
|
||||
twi->setData(2, Qt::UserRole, false);
|
||||
twi->setIcon(2, QIcon());
|
||||
}
|
||||
} else {
|
||||
twi->setIcon(2, notReadyIcon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerListWidget::showContextMenu(const QPoint &pos, const QModelIndex &index)
|
||||
{
|
||||
if (!userContextMenu) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QString &userName = index.sibling(index.row(), 4).data(Qt::UserRole).toString();
|
||||
int playerId = index.sibling(index.row(), 4).data(Qt::UserRole + 1).toInt();
|
||||
UserLevelFlags userLevel(index.sibling(index.row(), 3).data(Qt::UserRole).toInt());
|
||||
QString deckHash = index.sibling(index.row(), 5).data().toString();
|
||||
|
||||
userContextMenu->showContextMenu(pos, userName, userLevel, true, playerId, deckHash);
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
/**
|
||||
* @file player_list_widget.h
|
||||
* @ingroup GameWidgets
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef PLAYERLISTWIDGET_H
|
||||
#define PLAYERLISTWIDGET_H
|
||||
|
||||
#include "player_logic.h"
|
||||
|
||||
#include <QIcon>
|
||||
#include <QMap>
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QTreeWidget>
|
||||
|
||||
class ServerInfo_PlayerProperties;
|
||||
class TabSupervisor;
|
||||
class AbstractClient;
|
||||
class AbstractGame;
|
||||
class UserContextMenu;
|
||||
|
||||
class PlayerListItemDelegate : public QStyledItemDelegate
|
||||
{
|
||||
public:
|
||||
explicit PlayerListItemDelegate(QObject *parent);
|
||||
bool editorEvent(QEvent *event,
|
||||
QAbstractItemModel *model,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) override;
|
||||
};
|
||||
|
||||
class PlayerListTWI : public QTreeWidgetItem
|
||||
{
|
||||
public:
|
||||
PlayerListTWI();
|
||||
bool operator<(const QTreeWidgetItem &other) const override;
|
||||
};
|
||||
|
||||
class PlayerListWidget : public QTreeWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
PlayerListItemDelegate *itemDelegate;
|
||||
QMap<int, QTreeWidgetItem *> players;
|
||||
TabSupervisor *tabSupervisor;
|
||||
AbstractClient *client;
|
||||
AbstractGame *game;
|
||||
UserContextMenu *userContextMenu;
|
||||
QIcon readyIcon, notReadyIcon, concededIcon, playerIcon, judgeIcon, spectatorIcon, lockIcon;
|
||||
bool gameStarted;
|
||||
signals:
|
||||
void openMessageDialog(const QString &userName, bool focus);
|
||||
|
||||
public:
|
||||
PlayerListWidget(TabSupervisor *_tabSupervisor,
|
||||
AbstractClient *_client,
|
||||
AbstractGame *_game,
|
||||
QWidget *parent = nullptr);
|
||||
void retranslateUi();
|
||||
void setActivePlayer(int playerId);
|
||||
void setGameStarted(bool _gameStarted, bool resuming);
|
||||
void showContextMenu(const QPoint &pos, const QModelIndex &index);
|
||||
|
||||
public slots:
|
||||
void addPlayer(const ServerInfo_PlayerProperties &player);
|
||||
void removePlayer(int playerId);
|
||||
void updatePlayerProperties(const ServerInfo_PlayerProperties &prop, int playerId = -1);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,18 +1,18 @@
|
|||
#include "player_logic.h"
|
||||
|
||||
#include "../../game_graphics/board/arrow_item.h"
|
||||
#include "../../game_graphics/board/card_item.h"
|
||||
#include "../../game_graphics/board/counter_general.h"
|
||||
#include "../../game_graphics/game_scene.h"
|
||||
#include "../../game_graphics/player/player_target.h"
|
||||
#include "../../game_graphics/zones/hand_zone.h"
|
||||
#include "../../game_graphics/zones/pile_zone.h"
|
||||
#include "../../game_graphics/zones/stack_zone.h"
|
||||
#include "../../game_graphics/zones/table_zone.h"
|
||||
#include "../../interface/theme_manager.h"
|
||||
#include "../../interface/widgets/tabs/tab_game.h"
|
||||
#include "../board/arrow_item.h"
|
||||
#include "../board/card_item.h"
|
||||
#include "../board/card_list.h"
|
||||
#include "../board/counter_general.h"
|
||||
#include "../game_scene.h"
|
||||
#include "player_actions.h"
|
||||
#include "player_target.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QMenu>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#ifndef PLAYER_H
|
||||
#define PLAYER_H
|
||||
|
||||
#include "../../game_graphics/player/player_area.h"
|
||||
#include "../../interface/widgets/menus/tearoff_menu.h"
|
||||
#include "../board/arrow_data.h"
|
||||
#include "../interface/deck_loader/loaded_deck.h"
|
||||
|
|
@ -14,10 +15,7 @@
|
|||
#include "../zones/pile_zone_logic.h"
|
||||
#include "../zones/stack_zone_logic.h"
|
||||
#include "../zones/table_zone_logic.h"
|
||||
#include "menu/player_menu.h"
|
||||
#include "player_area.h"
|
||||
#include "player_event_handler.h"
|
||||
#include "player_graphics_item.h"
|
||||
#include "player_info.h"
|
||||
|
||||
#include <QInputDialog>
|
||||
|
|
@ -54,6 +52,7 @@ class PlayerMenu;
|
|||
class QAction;
|
||||
class QMenu;
|
||||
class ServerInfo_Arrow;
|
||||
class ServerInfo_Card;
|
||||
class ServerInfo_Counter;
|
||||
class ServerInfo_Player;
|
||||
class ServerInfo_User;
|
||||
|
|
|
|||
|
|
@ -1,169 +0,0 @@
|
|||
#include "player_target.h"
|
||||
|
||||
#include "../../interface/pixel_map_generator.h"
|
||||
#include "player_logic.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QPainter>
|
||||
#include <QPixmapCache>
|
||||
#include <QtMath>
|
||||
#include <libcockatrice/protocol/pb/serverinfo_user.pb.h>
|
||||
|
||||
PlayerCounter::PlayerCounter(CounterState *state, PlayerLogic *player, QGraphicsItem *parent)
|
||||
: AbstractCounter(state, player, false, false, parent)
|
||||
{
|
||||
}
|
||||
|
||||
QRectF PlayerCounter::boundingRect() const
|
||||
{
|
||||
return {0, 0, 50, 30};
|
||||
}
|
||||
|
||||
void PlayerCounter::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
||||
{
|
||||
const int radius = 8;
|
||||
const qreal border = 1;
|
||||
QPainterPath path(QPointF(50 - border / 2, border / 2));
|
||||
path.lineTo(radius, border / 2);
|
||||
path.arcTo(border / 2, border / 2, 2 * radius, 2 * radius, 90, 90);
|
||||
path.lineTo(border / 2, 30 - border / 2);
|
||||
path.lineTo(50 - border / 2, 30 - border / 2);
|
||||
path.closeSubpath();
|
||||
|
||||
QPen pen(QColor(100, 100, 100));
|
||||
pen.setWidth(border);
|
||||
painter->setPen(pen);
|
||||
painter->setBrush(hovered ? QColor(50, 50, 50, 160) : QColor(0, 0, 0, 160));
|
||||
|
||||
painter->drawPath(path);
|
||||
|
||||
QRectF translatedRect = path.controlPointRect();
|
||||
QSize translatedSize = translatedRect.size().toSize();
|
||||
QFont font("Serif");
|
||||
font.setWeight(QFont::Bold);
|
||||
font.setPixelSize(qMax(qRound(translatedSize.height() / 1.3), 9));
|
||||
painter->setFont(font);
|
||||
painter->setPen(Qt::white);
|
||||
painter->drawText(translatedRect, Qt::AlignCenter, QString::number(value));
|
||||
}
|
||||
|
||||
PlayerTarget::PlayerTarget(PlayerLogic *_owner, QGraphicsItem *parentItem)
|
||||
: ArrowTarget(_owner, parentItem), playerCounter(nullptr)
|
||||
{
|
||||
setCacheMode(DeviceCoordinateCache);
|
||||
|
||||
const std::string &bmp = _owner->getPlayerInfo()->getUserInfo()->avatar_bmp();
|
||||
if (!fullPixmap.loadFromData((const uchar *)bmp.data(), static_cast<uint>(bmp.size()))) {
|
||||
fullPixmap = QPixmap();
|
||||
}
|
||||
}
|
||||
|
||||
PlayerTarget::~PlayerTarget()
|
||||
{
|
||||
// Explicit deletion is necessary in spite of parent/child relationship
|
||||
// as we need this object to be alive to receive the destroyed() signal.
|
||||
delete playerCounter;
|
||||
}
|
||||
|
||||
QRectF PlayerTarget::boundingRect() const
|
||||
{
|
||||
return {0, 0, 160, 64};
|
||||
}
|
||||
|
||||
void PlayerTarget::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
||||
{
|
||||
const ServerInfo_User *const info = owner->getPlayerInfo()->getUserInfo();
|
||||
|
||||
const qreal border = 2;
|
||||
|
||||
QRectF avatarBoundingRect = boundingRect().adjusted(border, border, -border, -border);
|
||||
QRectF translatedRect = painter->combinedTransform().mapRect(avatarBoundingRect);
|
||||
QSize translatedSize = translatedRect.size().toSize();
|
||||
QPixmap cachedPixmap;
|
||||
const QString cacheKey = "avatar" + QString::number(translatedSize.width()) + "_" +
|
||||
QString::number(info->user_level()) + "_" + QString::number(fullPixmap.cacheKey());
|
||||
if (!QPixmapCache::find(cacheKey, &cachedPixmap)) {
|
||||
cachedPixmap = QPixmap(translatedSize.width(), translatedSize.height());
|
||||
|
||||
QPainter tempPainter(&cachedPixmap);
|
||||
// pow(foo, 0.5) equals to sqrt(foo), but using sqrt(foo) in this context will produce a compile error with
|
||||
// MSVC++
|
||||
QRadialGradient grad(translatedRect.center(), qPow(translatedSize.width() * translatedSize.width() +
|
||||
translatedSize.height() * translatedSize.height(),
|
||||
0.5) /
|
||||
2);
|
||||
grad.setColorAt(1, Qt::black);
|
||||
grad.setColorAt(0, QColor(180, 180, 180));
|
||||
tempPainter.fillRect(QRectF(0, 0, translatedSize.width(), translatedSize.height()), grad);
|
||||
|
||||
if (fullPixmap.isNull()) {
|
||||
int sideLength = translatedSize.height();
|
||||
QPixmap tempPixmap = UserLevelPixmapGenerator::generatePixmap(
|
||||
sideLength, UserLevelFlags(info->user_level()), info->pawn_colors(), false,
|
||||
QString::fromStdString(info->privlevel()));
|
||||
int x = (translatedSize.width() - sideLength) / 2;
|
||||
int y = 0;
|
||||
tempPainter.drawPixmap(x, y, tempPixmap);
|
||||
} else {
|
||||
QPixmap tempPixmap = fullPixmap.scaled(translatedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
int x = (translatedSize.width() - tempPixmap.width()) / 2;
|
||||
int y = (translatedSize.height() - tempPixmap.height()) / 2;
|
||||
tempPainter.drawPixmap(x, y, tempPixmap);
|
||||
}
|
||||
|
||||
QPixmapCache::insert(cacheKey, cachedPixmap);
|
||||
}
|
||||
|
||||
painter->save();
|
||||
resetPainterTransform(painter);
|
||||
painter->translate((translatedSize.width() - cachedPixmap.width()) / 2.0, 0);
|
||||
painter->drawPixmap(translatedRect, cachedPixmap, cachedPixmap.rect());
|
||||
painter->restore();
|
||||
|
||||
QRectF nameRect = QRectF(0, boundingRect().height() - 20, 110, 20);
|
||||
painter->fillRect(nameRect, QColor(0, 0, 0, 160));
|
||||
QRectF translatedNameRect = painter->combinedTransform().mapRect(nameRect);
|
||||
|
||||
painter->save();
|
||||
resetPainterTransform(painter);
|
||||
|
||||
QString name = QString::fromStdString(info->name());
|
||||
if (name.size() > 13) {
|
||||
name = name.mid(0, 10) + "...";
|
||||
}
|
||||
|
||||
QFont font;
|
||||
font.setPixelSize(qMax(qRound(translatedNameRect.height() / 1.5), 9));
|
||||
painter->setFont(font);
|
||||
painter->setPen(Qt::white);
|
||||
painter->drawText(translatedNameRect, Qt::AlignVCenter | Qt::AlignLeft, " " + name);
|
||||
painter->restore();
|
||||
|
||||
QPen pen(QColor(100, 100, 100));
|
||||
pen.setWidth(border);
|
||||
pen.setJoinStyle(Qt::RoundJoin);
|
||||
painter->setPen(pen);
|
||||
painter->drawRect(boundingRect().adjusted(border / 2, border / 2, -border / 2, -border / 2));
|
||||
|
||||
if (getBeingPointedAt()) {
|
||||
painter->fillRect(boundingRect(), QBrush(QColor(255, 0, 0, 100)));
|
||||
}
|
||||
}
|
||||
|
||||
AbstractCounter *PlayerTarget::addCounter(CounterState *state)
|
||||
{
|
||||
if (playerCounter) {
|
||||
disconnect(playerCounter, nullptr, this, nullptr);
|
||||
playerCounter->delCounter();
|
||||
}
|
||||
playerCounter = new PlayerCounter(state, owner, this);
|
||||
playerCounter->setPos(boundingRect().width() - playerCounter->boundingRect().width(),
|
||||
boundingRect().height() - playerCounter->boundingRect().height());
|
||||
connect(playerCounter, &PlayerCounter::destroyed, this, &PlayerTarget::counterDeleted);
|
||||
return playerCounter;
|
||||
}
|
||||
|
||||
void PlayerTarget::counterDeleted()
|
||||
{
|
||||
playerCounter = nullptr;
|
||||
}
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
/**
|
||||
* @file player_target.h
|
||||
* @ingroup GameGraphicsPlayers
|
||||
*/
|
||||
//! \todo Document this file.
|
||||
|
||||
#ifndef PLAYERTARGET_H
|
||||
#define PLAYERTARGET_H
|
||||
|
||||
#include "../../game_graphics/board/graphics_item_type.h"
|
||||
#include "../board/abstract_counter.h"
|
||||
#include "../board/arrow_target.h"
|
||||
|
||||
#include <QPixmap>
|
||||
|
||||
class PlayerLogic;
|
||||
|
||||
class PlayerCounter : public AbstractCounter
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PlayerCounter(CounterState *state, PlayerLogic *player, QGraphicsItem *parent);
|
||||
QRectF boundingRect() const override;
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||
};
|
||||
|
||||
class PlayerTarget : public ArrowTarget
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
QPixmap fullPixmap;
|
||||
PlayerCounter *playerCounter;
|
||||
public slots:
|
||||
void counterDeleted();
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
Type = typePlayerTarget
|
||||
};
|
||||
int type() const override
|
||||
{
|
||||
return Type;
|
||||
}
|
||||
|
||||
explicit PlayerTarget(PlayerLogic *_player = nullptr, QGraphicsItem *parentItem = nullptr);
|
||||
~PlayerTarget() override;
|
||||
QRectF boundingRect() const override;
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||
|
||||
AbstractCounter *addCounter(CounterState *state);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
#include "../interface/widgets/tabs/tab_game.h"
|
||||
|
||||
Replay::Replay(TabGame *_tab, GameReplay *_replay) : AbstractGame(_tab)
|
||||
Replay::Replay(QObject *_parent, GameReplay *_replay, bool isLocalGame) : AbstractGame(_parent)
|
||||
{
|
||||
gameState = new GameState(this, 0, -1, tab->getTabSupervisor()->getIsLocalGame(), {}, false, false, -1, false);
|
||||
gameState = new GameState(this, 0, -1, isLocalGame, {}, false, false, -1, false);
|
||||
connect(gameMetaInfo, &GameMetaInfo::startedChanged, gameState, &GameState::onStartedChanged);
|
||||
playerManager = new PlayerManager(this, -1, false, true);
|
||||
loadReplay(_replay);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class Replay : public AbstractGame
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Replay(TabGame *_tab, GameReplay *_replay);
|
||||
explicit Replay(QObject *_parent, GameReplay *_replay, bool isLocalGame);
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_REPLAY_H
|
||||
|
|
|
|||
|
|
@ -1,133 +0,0 @@
|
|||
/**
|
||||
* @file z_value_layer_manager.h
|
||||
* @ingroup GameGraphics
|
||||
* @brief Semantic Z-value layer management for game scene rendering.
|
||||
*
|
||||
* This file provides a structured approach to Z-value allocation in the game scene.
|
||||
* Z-values in Qt determine stacking order - higher values render on top of lower values.
|
||||
*
|
||||
* ## Layer Architecture
|
||||
*
|
||||
* The game scene is organized into three conceptual layers:
|
||||
*
|
||||
* 1. **Zone Layer (0-999)**: Zone backgrounds, containers, and static elements
|
||||
* - Zone backgrounds (0.5-1.0)
|
||||
* - Cards within zones (1.0 base + index)
|
||||
*
|
||||
* 2. **Card Layer (1-40,000,000)**: Dynamic card rendering on the table zone
|
||||
* - Cards use formula: (actualY + CardDimensions::HEIGHT) * 100000 + (actualX + 1) * 100
|
||||
* - Maximum card Z-value: ~40,000,000 (with 3 rows, actualY <= ~289)
|
||||
*
|
||||
* 3. **Overlay Layer (2,000,000,000+)**: UI elements that must appear above all cards
|
||||
* - Hovered cards (+1)
|
||||
* - Arrows (+3)
|
||||
* - Zone views (+4)
|
||||
* - Drag items (+5, +6)
|
||||
* - Top UI elements (+7)
|
||||
*
|
||||
* ## Design Rationale
|
||||
*
|
||||
* The large gap between card Z-values (max ~40M) and overlay base (2B) provides
|
||||
* safety margin for future table zone expansions while ensuring overlays always
|
||||
* render above cards regardless of table position.
|
||||
*
|
||||
* ## Usage
|
||||
*
|
||||
* Prefer using the semantic constants from ZValues namespace:
|
||||
* @code
|
||||
* card->setZValue(ZValues::HOVERED_CARD);
|
||||
* arrow->setZValue(ZValues::ARROWS);
|
||||
* @endcode
|
||||
*
|
||||
* Use validation functions to verify card Z-values during development:
|
||||
* @code
|
||||
* Q_ASSERT(ZValueLayerManager::isValidCardZValue(cardZ));
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
#ifndef Z_VALUE_LAYER_MANAGER_H
|
||||
#define Z_VALUE_LAYER_MANAGER_H
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
/**
|
||||
* @namespace ZValueLayerManager
|
||||
* @brief Utilities for Z-value validation and layer management.
|
||||
*/
|
||||
namespace ZValueLayerManager
|
||||
{
|
||||
|
||||
/**
|
||||
* @enum Layer
|
||||
* @brief Semantic layer identifiers for Z-value allocation.
|
||||
*
|
||||
* These represent conceptual rendering layers, not actual Z-values.
|
||||
* Use the corresponding ZValues constants for actual rendering.
|
||||
*/
|
||||
enum class Layer
|
||||
{
|
||||
Zone, ///< Zone-level elements like backgrounds and containers.
|
||||
Card, ///< Cards rendered in zones (uses sequential Z-values).
|
||||
Overlay ///< Temporary UI elements like hovered cards and drag items.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Maximum Z-value a card can have on the table zone.
|
||||
*
|
||||
* Based on table zone formula: (actualY + CardDimensions::HEIGHT) * 100000 + (actualX + 1) * 100
|
||||
* With maximum 3 rows and CardDimensions::HEIGHT = 102, actualY <= ~289.
|
||||
* Maximum: (289 + 102) * 100000 + 100 * 100 = 39,110,000
|
||||
*
|
||||
* We use 40,000,000 as a safe upper bound with margin.
|
||||
*/
|
||||
constexpr qreal CARD_Z_VALUE_MAX = 40000000.0;
|
||||
|
||||
/**
|
||||
* @brief Base Z-value for overlay elements.
|
||||
*
|
||||
* Must exceed CARD_Z_VALUE_MAX to ensure overlays render above all cards.
|
||||
* The 50x margin (2B vs 40M) provides safety for future expansion.
|
||||
*/
|
||||
constexpr qreal OVERLAY_BASE = 2000000000.0;
|
||||
|
||||
/**
|
||||
* @brief Validates that a Z-value is within the valid card range.
|
||||
*
|
||||
* Cards should have Z-values between CARD_BASE (1.0) and CARD_Z_VALUE_MAX.
|
||||
* Values outside this range may interfere with overlay rendering.
|
||||
*
|
||||
* @param zValue The Z-value to validate
|
||||
* @return true if the Z-value is valid for a card
|
||||
*/
|
||||
[[nodiscard]] constexpr bool isValidCardZValue(qreal zValue)
|
||||
{
|
||||
return zValue >= 1.0 && zValue <= CARD_Z_VALUE_MAX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Validates that a Z-value is in the overlay layer.
|
||||
*
|
||||
* Overlay elements should have Z-values at or above OVERLAY_BASE.
|
||||
*
|
||||
* @param zValue The Z-value to validate
|
||||
* @return true if the Z-value is valid for an overlay element
|
||||
*/
|
||||
[[nodiscard]] constexpr bool isOverlayZValue(qreal zValue)
|
||||
{
|
||||
return zValue >= OVERLAY_BASE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the Z-value for a specific overlay element.
|
||||
*
|
||||
* @param offset Offset from OVERLAY_BASE (0-7 for current elements)
|
||||
* @return The absolute Z-value for the overlay element
|
||||
*/
|
||||
[[nodiscard]] constexpr qreal overlayZValue(qreal offset)
|
||||
{
|
||||
return OVERLAY_BASE + offset;
|
||||
}
|
||||
|
||||
} // namespace ZValueLayerManager
|
||||
|
||||
#endif // Z_VALUE_LAYER_MANAGER_H
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
#ifndef Z_VALUES_H
|
||||
#define Z_VALUES_H
|
||||
|
||||
#include "card_dimensions.h"
|
||||
#include "z_value_layer_manager.h"
|
||||
|
||||
/**
|
||||
* @file z_values.h
|
||||
* @ingroup GameGraphics
|
||||
* @brief Centralized Z-value constants for rendering layer order.
|
||||
*
|
||||
* Z-values in Qt determine stacking order. Higher values render on top.
|
||||
* These constants define the visual layering hierarchy for the game scene.
|
||||
*
|
||||
* ## Layer Architecture
|
||||
*
|
||||
* See z_value_layer_manager.h for detailed documentation on the three-layer
|
||||
* architecture (Zone, Card, Overlay) and the rationale for Z-value choices.
|
||||
*
|
||||
* ## Quick Reference
|
||||
*
|
||||
* | Layer | Z-Value Range | Purpose |
|
||||
* |----------|------------------|-----------------------------------|
|
||||
* | Zone | 0.5 - 1.0 | Zone backgrounds, containers |
|
||||
* | Card | 1.0 - 40,000,000 | Cards on table (position-based) |
|
||||
* | Overlay | 2,000,000,000+ | UI elements above all cards |
|
||||
*/
|
||||
|
||||
namespace ZValues
|
||||
{
|
||||
|
||||
// Expose base for callers that need it
|
||||
constexpr qreal OVERLAY_BASE = ZValueLayerManager::OVERLAY_BASE;
|
||||
|
||||
// Overlay layer Z-values for items that should appear above normal cards
|
||||
constexpr qreal HOVERED_CARD = ZValueLayerManager::overlayZValue(1.0);
|
||||
constexpr qreal ARROWS = ZValueLayerManager::overlayZValue(3.0);
|
||||
constexpr qreal ZONE_VIEW_WIDGET = ZValueLayerManager::overlayZValue(4.0);
|
||||
constexpr qreal DRAG_ITEM = ZValueLayerManager::overlayZValue(5.0);
|
||||
constexpr qreal DRAG_ITEM_CHILD = ZValueLayerManager::overlayZValue(6.0);
|
||||
constexpr qreal TOP_UI = ZValueLayerManager::overlayZValue(7.0);
|
||||
|
||||
/**
|
||||
* @brief Compute Z-value for child drag items based on hotspot position.
|
||||
*
|
||||
* When dragging multiple cards together, each child card needs a unique Z-value
|
||||
* to prevent Z-fighting (flickering/flashing). The Z-values are derived from
|
||||
* their position when grabbed to conserve original stacking. The formula encodes
|
||||
* 2D coordinates into a single value where X has higher weight, ensuring
|
||||
* deterministic visual stacking.
|
||||
*
|
||||
* @param hotSpotX The X coordinate of the grab position
|
||||
* @param hotSpotY The Y coordinate of the grab position
|
||||
* @return Unique Z-value for the child drag item
|
||||
*/
|
||||
[[nodiscard]] constexpr qreal childDragZValue(qreal hotSpotX, qreal hotSpotY)
|
||||
{
|
||||
return DRAG_ITEM_CHILD + hotSpotX * 1000000 + hotSpotY * 1000 + 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compute Z-value for cards on the table zone based on position.
|
||||
*
|
||||
* Cards lower on the table (higher Y) render above cards higher up,
|
||||
* and cards to the right (higher X) render above cards to the left.
|
||||
* This creates natural visual stacking for overlapping cards.
|
||||
*
|
||||
* @param x The X coordinate of the card position
|
||||
* @param y The Y coordinate of the card position
|
||||
* @return Z-value for the card's table position
|
||||
*/
|
||||
[[nodiscard]] constexpr qreal tableCardZValue(qreal x, qreal y)
|
||||
{
|
||||
return (y + CardDimensions::HEIGHT_F) * 100000.0 + (x + 1) * 100.0;
|
||||
}
|
||||
|
||||
// Card layering (general architecture, not command-zone specific)
|
||||
constexpr qreal CARD_BASE = 1.0;
|
||||
constexpr qreal CARD_MAX = ZValueLayerManager::CARD_Z_VALUE_MAX;
|
||||
|
||||
} // namespace ZValues
|
||||
|
||||
#endif // Z_VALUES_H
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#include "card_zone_logic.h"
|
||||
|
||||
#include "../../game_graphics/board/card_item.h"
|
||||
#include "../../game_graphics/zones/view_zone.h"
|
||||
#include "../board/card_item.h"
|
||||
#include "../player/player_actions.h"
|
||||
#include "../player/player_logic.h"
|
||||
#include "view_zone_logic.h"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include "hand_zone_logic.h"
|
||||
|
||||
#include "../board/card_item.h"
|
||||
#include "../../game_graphics/board/card_item.h"
|
||||
#include "card_zone_algorithms.h"
|
||||
|
||||
HandZoneLogic::HandZoneLogic(PlayerLogic *_player,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include "pile_zone_logic.h"
|
||||
|
||||
#include "../board/card_item.h"
|
||||
#include "../../game_graphics/board/card_item.h"
|
||||
|
||||
PileZoneLogic::PileZoneLogic(PlayerLogic *_player,
|
||||
const QString &_name,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include "stack_zone_logic.h"
|
||||
|
||||
#include "../board/card_item.h"
|
||||
#include "../../game_graphics/board/card_item.h"
|
||||
#include "card_zone_algorithms.h"
|
||||
|
||||
StackZoneLogic::StackZoneLogic(PlayerLogic *_player,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include "table_zone_logic.h"
|
||||
|
||||
#include "../board/card_item.h"
|
||||
#include "../../game_graphics/board/card_item.h"
|
||||
|
||||
TableZoneLogic::TableZoneLogic(PlayerLogic *_player,
|
||||
const QString &_name,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include "view_zone_logic.h"
|
||||
|
||||
#include "../../client/settings/cache_settings.h"
|
||||
#include "../board/card_item.h"
|
||||
#include "../../game_graphics/board/card_item.h"
|
||||
|
||||
/**
|
||||
* @param _player the player that the cards are revealed to.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue