mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-10-26 17:41:15 -05:00
[Game] Raise rubber band above count label and collapse multi-selection on click (#7451)
* [Game] Raise rubber band above count label and collapse multi-selection on click Raise rubber band on start and collapse multi-selection to clicked card when left-clicking an already-selected card with no modifiers. * [Game] Collapse multi-selection on release instead of press Collapsing at press time dropped the selection before the drag started, which broke dragging multiple cards. Keep the selection on press and collapse it on release when the pointer stayed within the drag distance. * [Game] Defer selection collapse until the double-click window passes A release without drag collapsed the multi-selection immediately, so a double-click that followed (playSelected acts on scene()->selectedItems()) only ever saw the single clicked card. When the card handles double-clicks on the selection, arm the collapse on a single-shot timer for QApplication::doubleClickInterval() instead and cancel it from the double-click handler; a new press disarms the other cards and a selection-count guard covers rubber-band/ctrl changes meanwhile. * [Game] Keep sideboard multi-selection on double-click DeckViewCard overrides doubleClickActsOnSelection to preserve the selection, restoring master behavior where double-clicking moves all selected cards between main and side. DeckView cancels any pending collapse before reading the selection. * [Game] Remove duplicated inline selection-collapse declarations * [Game] Fix DeckView collapse call visibility and multi-selection collapse Make cancelPendingSelectionCollapse() public so DeckView can call it on selected DeckViewCards. Always arm the deferred collapse on release instead of skipping cards whose double-click acts on the selection; the double-click-interval timer plus the cancel calls in CardItem::mouseDoubleClickEvent and DeckView::mouseDoubleClickEvent already preserve the selection for double-clicks. --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#include "libcockatrice/card/printing/exact_card.h"
|
||||
#include "libcockatrice/utility/card_ref.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QBrush>
|
||||
#include <QChar>
|
||||
#include <QCursor>
|
||||
@@ -28,6 +29,7 @@
|
||||
#include <QPixmap>
|
||||
#include <QPointF>
|
||||
#include <QRectF>
|
||||
#include <QTimer>
|
||||
#include <QTransform>
|
||||
#include <QVariant>
|
||||
#include <QtGlobal>
|
||||
@@ -42,7 +44,7 @@ class QSizeF;
|
||||
|
||||
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)
|
||||
bgColor(Qt::transparent), isHovered(false), realZValue(0), pendingSelectionCollapse(false)
|
||||
{
|
||||
setCursor(Qt::OpenHandCursor);
|
||||
setFlag(ItemIsSelectable);
|
||||
@@ -344,6 +346,16 @@ void AbstractCardItem::setFaceDown(bool _facedown)
|
||||
|
||||
void AbstractCardItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
cancelPendingSelectionCollapse();
|
||||
if (scene() != nullptr) {
|
||||
// A new press starts a new gesture: no card may collapse the selection out from under it afterwards.
|
||||
for (QGraphicsItem *selectedItem : scene()->selectedItems()) {
|
||||
auto *selectedCard = qgraphicsitem_cast<AbstractCardItem *>(selectedItem);
|
||||
if (selectedCard != nullptr && selectedCard != this) {
|
||||
selectedCard->cancelPendingSelectionCollapse();
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((event->modifiers() & Qt::AltModifier) && event->button() == Qt::LeftButton) {
|
||||
emit cardShiftClicked(cardRef.name);
|
||||
} else if ((event->modifiers() & Qt::ControlModifier)) {
|
||||
@@ -351,6 +363,10 @@ void AbstractCardItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
} else if (!isSelected()) {
|
||||
scene()->clearSelection();
|
||||
setSelected(true);
|
||||
} else if (event->button() == Qt::LeftButton && scene()->selectedItems().count() > 1) {
|
||||
// Part of a multi-selection; collapse only if this turns out to be a click rather than a drag,
|
||||
// so that dragging the whole selection keeps it intact.
|
||||
pendingSelectionCollapse = true;
|
||||
}
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
setCursor(Qt::ClosedHandCursor);
|
||||
@@ -362,6 +378,32 @@ void AbstractCardItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
|
||||
void AbstractCardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
if (pendingSelectionCollapse) {
|
||||
pendingSelectionCollapse = false;
|
||||
bool dragged = (event->screenPos() - event->buttonDownScreenPos(event->button())).manhattanLength() >=
|
||||
2 * QApplication::startDragDistance();
|
||||
if (!dragged) {
|
||||
if (doubleClickActsOnSelection()) {
|
||||
// A double-click may still arrive and must act on the whole multi-selection, so collapse only
|
||||
// once the double-click window has passed without one. The generation guard (and the receiver
|
||||
// context) drops the collapse if the item is gone, deselected, or a double-click cancelled it;
|
||||
// the count guard drops it if the selection changed meanwhile (rubber band, ctrl-toggle).
|
||||
const int generation = ++selectionCollapseGeneration;
|
||||
const int armedSelectionCount = scene()->selectedItems().count();
|
||||
QTimer::singleShot(QApplication::doubleClickInterval(), this, [this, generation, armedSelectionCount] {
|
||||
if (generation == selectionCollapseGeneration && scene() != nullptr && isSelected() &&
|
||||
scene()->selectedItems().count() == armedSelectionCount && armedSelectionCount > 1) {
|
||||
scene()->clearSelection();
|
||||
setSelected(true);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
scene()->clearSelection();
|
||||
setSelected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (event->button() == Qt::MiddleButton) {
|
||||
emit deleteCardInfoPopup(cardRef.name);
|
||||
}
|
||||
@@ -370,6 +412,17 @@ void AbstractCardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void AbstractCardItem::cancelPendingSelectionCollapse()
|
||||
{
|
||||
pendingSelectionCollapse = false;
|
||||
++selectionCollapseGeneration;
|
||||
}
|
||||
|
||||
bool AbstractCardItem::doubleClickActsOnSelection() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void AbstractCardItem::processHoverEvent()
|
||||
{
|
||||
emit hovered(this);
|
||||
|
||||
@@ -41,6 +41,8 @@ protected:
|
||||
private:
|
||||
bool isHovered;
|
||||
qreal realZValue;
|
||||
bool pendingSelectionCollapse;
|
||||
int selectionCollapseGeneration = 0; ///< Guards the deferred collapse timer against stale firings
|
||||
private slots:
|
||||
void pixmapUpdated();
|
||||
|
||||
@@ -130,6 +132,8 @@ public:
|
||||
}
|
||||
void setFaceDown(bool _facedown);
|
||||
void processHoverEvent();
|
||||
/** @brief Drop a pending collapse and disarm any deferred collapse timer. */
|
||||
void cancelPendingSelectionCollapse();
|
||||
void deleteCardInfoPopup()
|
||||
{
|
||||
emit deleteCardInfoPopup(cardRef.name);
|
||||
@@ -144,6 +148,16 @@ protected:
|
||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override;
|
||||
void cacheBgColor();
|
||||
/**
|
||||
* @brief Whether a double-click on this item acts on the whole selection.
|
||||
*
|
||||
* When true, a release without drag defers the multi-selection collapse
|
||||
* until the double-click window passes, so a following double-click still
|
||||
* sees every selected card. Subclasses that handle double-clicks on the
|
||||
* selection must return true here and call
|
||||
* cancelPendingSelectionCollapse() from their double-click handler.
|
||||
*/
|
||||
virtual bool doubleClickActsOnSelection() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -518,6 +518,9 @@ void CardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||
|
||||
void CardItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
// The preceding release deferred its multi-selection collapse for exactly this: the double-click plays
|
||||
// every selected card, so the collapse must not run.
|
||||
cancelPendingSelectionCollapse();
|
||||
if ((event->modifiers() != Qt::AltModifier) && (event->buttons() == Qt::LeftButton) &&
|
||||
(SettingsCache::instance().userInterface().getDoubleClickToPlay())) {
|
||||
handleClickedToPlay(event->modifiers().testFlag(Qt::ShiftModifier));
|
||||
@@ -525,6 +528,11 @@ void CardItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
|
||||
event->accept();
|
||||
}
|
||||
|
||||
bool CardItem::doubleClickActsOnSelection() const
|
||||
{
|
||||
return SettingsCache::instance().userInterface().getDoubleClickToPlay();
|
||||
}
|
||||
|
||||
bool CardItem::animationEvent()
|
||||
{
|
||||
int rotation = ROTATION_DEGREES_PER_FRAME;
|
||||
|
||||
@@ -175,6 +175,7 @@ protected:
|
||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
|
||||
bool doubleClickActsOnSelection() const override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -182,6 +182,15 @@ void DeckView::mouseDoubleClickEvent(QMouseEvent *event)
|
||||
QList<MoveCard_ToZone> result;
|
||||
QList<QGraphicsItem *> sel = scene()->selectedItems();
|
||||
|
||||
// The double-click goes to the view, not the card, so cancel any pending
|
||||
// selection collapse on the cards before reading the selection.
|
||||
for (auto *item : sel) {
|
||||
if (auto *c = dynamic_cast<DeckViewCard *>(item)) {
|
||||
c->cancelPendingSelectionCollapse();
|
||||
}
|
||||
}
|
||||
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());
|
||||
|
||||
@@ -49,6 +49,10 @@ public:
|
||||
{
|
||||
return originZone;
|
||||
}
|
||||
bool doubleClickActsOnSelection() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
|
||||
@@ -127,6 +127,7 @@ void GameView::startRubberBand(const QPointF &_selectionOrigin)
|
||||
selectionOrigin = _selectionOrigin;
|
||||
previousBandRect = QRect();
|
||||
rubberBand->setGeometry(QRect(mapFromScene(selectionOrigin), QSize(0, 0)));
|
||||
rubberBand->raise();
|
||||
rubberBand->show();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user