* Improve drag & drop behavior This patch tweaks the drag & drop behavior (in particular, the grid placement) to be more intuitive. More precisely, with this patch the drag & drop will: - Only use the "hot spot" (i.e. position of the cursor on the card) for zones where the card is actually displayed around the cursor (in particular, not on the table where the card snaps to the grid). - Use better boundaries computed with respect to the center of the card (rather than its top left corner) for determining which grid cell a card should go to - Align behavior of the preview and the actual effect when overflow of the 3-card stacks occurs - Avoid visual glitches where the cursor ends up outside of the card or at incorrect offsets when moving the mouse too fast (which translates to overflows of the hot spot computation) * Address review comments - Use simpler computation for restricting hotSpot range - Prevent dropping cards onto full 3-card slots
112 lines
3.7 KiB
C++
112 lines
3.7 KiB
C++
#include "carddragitem.h"
|
|
|
|
#include "carditem.h"
|
|
#include "cardzone.h"
|
|
#include "gamescene.h"
|
|
#include "tablezone.h"
|
|
#include "zoneviewzone.h"
|
|
|
|
#include <QCursor>
|
|
#include <QGraphicsSceneMouseEvent>
|
|
#include <QPainter>
|
|
|
|
CardDragItem::CardDragItem(CardItem *_item,
|
|
int _id,
|
|
const QPointF &_hotSpot,
|
|
bool _faceDown,
|
|
AbstractCardDragItem *parentDrag)
|
|
: AbstractCardDragItem(_item, _hotSpot, parentDrag), id(_id), faceDown(_faceDown), 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;
|
|
if (!cursorZone)
|
|
return;
|
|
currentZone = cursorZone;
|
|
|
|
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;
|
|
CardZone *startZone = static_cast<CardItem *>(item)->getZone();
|
|
if (currentZone && !(static_cast<CardItem *>(item)->getAttachedTo() && (startZone == currentZone)) && !occupied) {
|
|
dragItemList.append(this);
|
|
for (int i = 0; i < childDrags.size(); i++) {
|
|
CardDragItem *c = static_cast<CardDragItem *>(childDrags[i]);
|
|
if (!(static_cast<CardItem *>(c->item)->getAttachedTo() && (startZone == currentZone)) && !c->occupied)
|
|
dragItemList.append(c);
|
|
sc->removeItem(c);
|
|
}
|
|
}
|
|
|
|
if (currentZone)
|
|
currentZone->handleDropEvent(dragItemList, startZone, (sp - currentZone->scenePos()).toPoint());
|
|
|
|
event->accept();
|
|
}
|