From 14991e1f9e5e3780c0e03ed347e17588788ca310 Mon Sep 17 00:00:00 2001 From: BruebachL <44814898+BruebachL@users.noreply.github.com> Date: Sat, 27 Sep 2025 00:31:30 +0200 Subject: [PATCH] [GameScene] Refactor and doxygen (#6180) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Clean up game scene code. Took 18 minutes * Doxygen. Took 18 minutes Took 5 seconds Took 10 minutes * Move some methods. Took 6 minutes * Restore the original warning, I guess. Took 3 minutes * Accidentally some methods. Took 5 minutes --------- Co-authored-by: Lukas BrĂ¼bach --- cockatrice/src/game/game_scene.cpp | 417 +++++++++++++++++++++-------- cockatrice/src/game/game_scene.h | 165 ++++++++++-- 2 files changed, 448 insertions(+), 134 deletions(-) diff --git a/cockatrice/src/game/game_scene.cpp b/cockatrice/src/game/game_scene.cpp index f0e82532b..4316e67bf 100644 --- a/cockatrice/src/game/game_scene.cpp +++ b/cockatrice/src/game/game_scene.cpp @@ -15,7 +15,17 @@ #include #include #include +#include +/** + * @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) { @@ -39,23 +49,40 @@ GameScene::~GameScene() } } +/** + * @brief Updates localized text in all zone views. + */ void GameScene::retranslateUi() { - for (int i = 0; i < zoneViews.size(); ++i) - zoneViews[i]->retranslateUi(); + for (ZoneViewWidget *view : zoneViews) + view->retranslateUi(); } +/** + * @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(Player *player) { qCInfo(GameScenePlayerAdditionRemovalLog) << "GameScene::addPlayer name=" << player->getPlayerInfo()->getName(); + players << player->getGraphicsItem(); addItem(player->getGraphicsItem()); connect(player->getGraphicsItem(), &PlayerGraphicsItem::sizeChanged, this, &GameScene::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(Player *player) { qCInfo(GameScenePlayerAdditionRemovalLog) << "GameScene::removePlayer name=" << player->getPlayerInfo()->getName(); + for (ZoneViewWidget *zone : zoneViews) { if (zone->getPlayer() == player) { zone->close(); @@ -66,90 +93,307 @@ void GameScene::removePlayer(Player *player) 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() { - playersByColumn.clear(); - - // Create the list of players playing, noting the first player's index. - QList playersPlaying; 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 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 GameScene::collectActivePlayers(int &firstPlayerIndex) const +{ + QList activePlayers; + firstPlayerIndex = 0; bool firstPlayerFound = false; - QListIterator playersIter(players); - while (playersIter.hasNext()) { - Player *p = playersIter.next()->getPlayer(); + + for (auto *pgItem : players) { + Player *p = pgItem->getPlayer(); if (p && !p->getConceded()) { - playersPlaying.append(p); + activePlayers.append(p); if (!firstPlayerFound && p->getPlayerInfo()->getLocal()) { - firstPlayerIndex = playersPlaying.size() - 1; + firstPlayerIndex = activePlayers.size() - 1; firstPlayerFound = true; } } } + return activePlayers; +} - // Rotate the players playing list so that first player is first, then - // adjust by the additional rotation setting. - if (!playersPlaying.isEmpty()) { +/** + * @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 GameScene::rotatePlayers(const QList &activePlayers, int firstPlayerIndex) const +{ + QList rotated = activePlayers; + if (!rotated.isEmpty()) { int totalRotation = firstPlayerIndex + playerRotation; while (totalRotation < 0) - totalRotation += playersPlaying.size(); - for (int i = 0; i < totalRotation; ++i) { - playersPlaying.append(playersPlaying.takeFirst()); - } + totalRotation += rotated.size(); + for (int i = 0; i < totalRotation; ++i) + rotated.append(rotated.takeFirst()); } + return rotated; +} - const int playersCount = playersPlaying.size(); - const int columns = playersCount < SettingsCache::instance().getMinPlayersForMultiColumnLayout() ? 1 : 2; - const int rows = qCeil((qreal)playersCount / columns); +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 &playersPlaying, int columns) +{ + playersByColumn.clear(); + + int rows = qCeil((qreal)playersPlaying.size() / columns); qreal sceneHeight = 0, sceneWidth = -playerAreaSpacing; QList columnWidth; - QListIterator playersPlayingIter(playersPlaying); + QListIterator playersIter(playersPlaying); for (int col = 0; col < columns; ++col) { playersByColumn.append(QList()); columnWidth.append(0); qreal thisColumnHeight = -playerAreaSpacing; - const int rowsInColumn = rows - (playersCount % columns) * col; // only correct for max. 2 cols + int rowsInColumn = rows - (playersPlaying.size() % columns) * col; // Adjust rows for uneven columns + for (int j = 0; j < rowsInColumn; ++j) { - Player *player = playersPlayingIter.next(); + Player *player = playersIter.next(); if (col == 0) playersByColumn[col].prepend(player->getGraphicsItem()); else playersByColumn[col].append(player->getGraphicsItem()); - thisColumnHeight += player->getGraphicsItem()->boundingRect().height() + playerAreaSpacing; - if (player->getGraphicsItem()->boundingRect().width() > columnWidth[col]) - columnWidth[col] = player->getGraphicsItem()->boundingRect().width(); + + auto *pgItem = player->getGraphicsItem(); + thisColumnHeight += pgItem->boundingRect().height() + playerAreaSpacing; + columnWidth[col] = std::max(columnWidth[col], (int)pgItem->boundingRect().width()); } - if (thisColumnHeight > sceneHeight) - sceneHeight = thisColumnHeight; + + sceneHeight = std::max(sceneHeight, thisColumnHeight); sceneWidth += columnWidth[col] + playerAreaSpacing; } - phasesToolbar->setHeight(sceneHeight); 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); + player->setMirrored(row != rows - 1); // Mirror all except bottom-most y += player->boundingRect().height() + playerAreaSpacing; } x += columnWidth[col] + playerAreaSpacing; } - setSceneRect(sceneRect().x(), sceneRect().y(), sceneWidth, sceneHeight); - processViewSizeChange(viewSize); + 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 GameScene::calculateMinWidthByColumn() const +{ + QList 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 &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; + } +} + +// ---------- 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)) + hoveredCard->setHovered(false); + if (newCard && (newCard != hoveredCard)) + newCard->setHovered(true); + hoveredCard = newCard; +} + +CardZone *GameScene::findTopmostZone(const QList &items) +{ + for (QGraphicsItem *item : items) + if (auto *zone = qgraphicsitem_cast(item)) + return zone; + return nullptr; +} + +CardItem *GameScene::findTopmostCardInZone(const QList &items, CardZone *zone) +{ + CardItem *maxZCard = nullptr; + qreal maxZ = -1; + + for (QGraphicsItem *item : items) { + CardItem *card = qgraphicsitem_cast(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(Player *player, const QString &zoneName, int numberCards, bool isReversed) { for (auto &view : zoneViews) { @@ -162,18 +406,26 @@ void GameScene::toggleZoneView(Player *player, const QString &zoneName, int numb 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 == "grave") { + + if (zoneName == "grave") item->setPos(360, 100); - } else if (zoneName == "rfg") { + else if (zoneName == "rfg") item->setPos(380, 120); - } else { + 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(Player *player, CardZoneLogic *zone, const QList &cardList, @@ -186,24 +438,36 @@ void GameScene::addRevealedZoneView(Player *player, 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(); @@ -214,82 +478,7 @@ QTransform GameScene::getViewportTransform() const return views().at(0)->viewportTransform(); } -void GameScene::processViewSizeChange(const QSize &newSize) -{ - viewSize = newSize; - - qreal newRatio = ((qreal)newSize.width()) / newSize.height(); - qreal minWidth = 0; - QList minWidthByColumn; - for (int col = 0; col < playersByColumn.size(); ++col) { - minWidthByColumn.append(0); - for (int row = 0; row < playersByColumn[col].size(); ++row) { - qreal w = playersByColumn[col][row]->getMinimumWidth(); - if (w > minWidthByColumn[col]) - minWidthByColumn[col] = w; - } - minWidth += minWidthByColumn[col]; - } - minWidth += phasesToolbar->getWidth(); - - qreal minRatio = minWidth / sceneRect().height(); - qreal newWidth; - if (minRatio > newRatio) { - // Aspect ratio is dominated by table width. - newWidth = minWidth; - } else { - // Aspect ratio is dominated by window dimensions. - newWidth = newRatio * sceneRect().height(); - } - setSceneRect(0, 0, newWidth, sceneRect().height()); - - qreal extraWidthPerColumn = (newWidth - minWidth) / playersByColumn.size(); - qreal newx = phasesToolbar->getWidth(); - for (int col = 0; col < playersByColumn.size(); ++col) { - for (int row = 0; row < playersByColumn[col].size(); ++row) { - playersByColumn[col][row]->processSceneSizeChange(minWidthByColumn[col] + extraWidthPerColumn); - playersByColumn[col][row]->setPos(newx, playersByColumn[col][row]->y()); - } - newx += minWidthByColumn[col] + extraWidthPerColumn; - } -} - -void GameScene::updateHover(const QPointF &scenePos) -{ - QList itemList = - items(scenePos, Qt::IntersectsItemBoundingRect, Qt::DescendingOrder, getViewTransform()); - - // Search for the topmost zone and ignore all cards not belonging to that zone. - CardZone *zone = 0; - for (int i = 0; i < itemList.size(); ++i) - if ((zone = qgraphicsitem_cast(itemList[i]))) - break; - - CardItem *maxZCard = 0; - if (zone) { - qreal maxZ = -1; - for (int i = 0; i < itemList.size(); ++i) { - CardItem *card = qgraphicsitem_cast(itemList[i]); - 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; - } - } - } - if (hoveredCard && (maxZCard != hoveredCard)) - hoveredCard->setHovered(false); - if (maxZCard && (maxZCard != hoveredCard)) - maxZCard->setHovered(true); - hoveredCard = maxZCard; -} +// ---------- Event Handling ---------- bool GameScene::event(QEvent *event) { @@ -325,6 +514,8 @@ void GameScene::unregisterAnimationItem(AbstractCardItem *card) animationTimer->stop(); } +// ---------- Rubber Band ---------- + void GameScene::startRubberBand(const QPointF &selectionOrigin) { emit sigStartRubberBand(selectionOrigin); diff --git a/cockatrice/src/game/game_scene.h b/cockatrice/src/game/game_scene.h index 32721d0b0..0ee3b1a81 100644 --- a/cockatrice/src/game/game_scene.h +++ b/cockatrice/src/game/game_scene.h @@ -22,54 +22,177 @@ class ServerInfo_Card; class PhasesToolbar; class QBasicTimer; +/** + * @class GameScene + * @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; + static const int playerAreaSpacing = 5; ///< Space between player areas - PhasesToolbar *phasesToolbar; - QList players; - QList> playersByColumn; - QList zoneViews; - QSize viewSize; - QPointer hoveredCard; - QBasicTimer *animationTimer; - QSet cardsToAnimate; - int playerRotation; + PhasesToolbar *phasesToolbar; ///< Toolbar showing game phases + QList players; ///< All player graphics items + QList> playersByColumn; ///< Players organized by column + QList zoneViews; ///< Active zone view widgets + QSize viewSize; ///< Current view size + QPointer hoveredCard; ///< Currently hovered card + QBasicTimer *animationTimer; ///< Timer for card animations + QSet 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); public: + /** + * @brief Constructs the GameScene. + * @param _phasesToolbar Toolbar widget for phases. + * @param parent Optional parent QObject. + */ explicit GameScene(PhasesToolbar *_phasesToolbar, QObject *parent = nullptr); - ~GameScene() override; - void retranslateUi(); - void processViewSizeChange(const QSize &newSize); - QTransform getViewTransform() const; - QTransform getViewportTransform() const; + /** Destructor, cleans up timer and zone views. */ + ~GameScene() override; + + /** Updates UI text for all zone views. */ + void retranslateUi(); + + /** + * @brief Adds a player to the scene and stores their graphics item. + * @param player Player to add. + */ + void addPlayer(Player *player); + + /** + * @brief Removes a player from the scene. + * @param player Player to remove. + */ + void removePlayer(Player *player); + + /** + * @brief Adjusts the global rotation offset for player layout. + * @param rotationAdjustment Number of positions to rotate. + */ + void adjustPlayerRotation(int rotationAdjustment); + + /** 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 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 rotatePlayers(const QList &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 &playersPlaying, int columns); + + /** + * @brief Computes the minimum width for each column based on player minimum widths. + * @return List of minimum widths per column. + */ + QList 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 &minWidthByColumn, qreal newWidth); + + /** Finds the topmost card zone under the cursor. */ + static CardZone *findTopmostZone(const QList &items); + + /** Finds the topmost card in a given zone, considering attachments and Z-order. */ + static CardItem *findTopmostCardInZone(const QList &items, CardZone *zone); + + /** Updates hovered card highlighting. */ + void updateHoveredCard(CardItem *newCard); + + /** Registers a card for animation updates. */ + void registerAnimationItem(AbstractCardItem *card); + + /** Unregisters a card from animation updates. */ + void unregisterAnimationItem(AbstractCardItem *card); void startRubberBand(const QPointF &selectionOrigin); void resizeRubberBand(const QPointF &cursorPoint); void stopRubberBand(); - void registerAnimationItem(AbstractCardItem *item); - void unregisterAnimationItem(AbstractCardItem *card); public slots: + /** Toggles a zone view for a player. */ void toggleZoneView(Player *player, const QString &zoneName, int numberCards, bool isReversed = false); + + /** Adds a revealed zone view (for shown cards). */ void addRevealedZoneView(Player *player, CardZoneLogic *zone, const QList &cardList, bool withWritePermission); + + /** Removes a zone view widget from the scene. */ void removeZoneView(ZoneViewWidget *item); - void addPlayer(Player *player); - void removePlayer(Player *player); + + /** Closes all zone views. */ void clearViews(); + + /** Closes the most recently added zone view. */ void closeMostRecentZoneView(); - void adjustPlayerRotation(int rotationAdjustment); - void rearrange(); + QTransform getViewTransform() const; + QTransform getViewportTransform() const; protected: + /** Handles hover updates. */ bool event(QEvent *event) override; + + /** Handles animation timer updates. */ void timerEvent(QTimerEvent *event) override; + signals: void sigStartRubberBand(const QPointF &selectionOrigin); void sigResizeRubberBand(const QPointF &cursorPoint);