diff --git a/cockatrice/src/game/game_scene.cpp b/cockatrice/src/game/game_scene.cpp index d9e403f11..e85ff6663 100644 --- a/cockatrice/src/game/game_scene.cpp +++ b/cockatrice/src/game/game_scene.cpp @@ -129,102 +129,6 @@ void GameScene::rearrange() processViewSizeChange(viewSize); } -// ---------- 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) { - ZoneViewZone *temp = view->getZone(); - if (temp->getLogic()->getName() == zoneName && temp->getLogic()->getPlayer() == player && - qobject_cast(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 == "grave") - item->setPos(360, 100); - else if (zoneName == "rfg") - 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(Player *player, - CardZoneLogic *zone, - const QList &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(); -} - // ---------- View Size ---------- /** @@ -249,70 +153,6 @@ void GameScene::processViewSizeChange(const QSize &newSize) resizeColumnsAndPlayers(minWidthByColumn, newWidth); } -// ---------- 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); -} - -// ---------- Event Handling ---------- - -bool GameScene::event(QEvent *event) -{ - if (event->type() == QEvent::GraphicsSceneMouseMove) - updateHover(static_cast(event)->scenePos()); - - return QGraphicsScene::event(event); -} - -void GameScene::timerEvent(QTimerEvent * /*event*/) -{ - QMutableSetIterator 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(card)); - if (!animationTimer->isActive()) - animationTimer->start(10, this); -} - -void GameScene::unregisterAnimationItem(AbstractCardItem *card) -{ - cardsToAnimate.remove(static_cast(card)); - if (cardsToAnimate.isEmpty()) - animationTimer->stop(); -} - -// ---------- Rubber Band ---------- - -void GameScene::startRubberBand(const QPointF &selectionOrigin) -{ - emit sigStartRubberBand(selectionOrigin); -} - -void GameScene::resizeRubberBand(const QPointF &cursorPoint) -{ - emit sigResizeRubberBand(cursorPoint); -} - -void GameScene::stopRubberBand() -{ - emit sigStopRubberBand(); -} - // ---------- Player Layout Helpers ---------- /** @@ -488,6 +328,26 @@ void GameScene::resizeColumnsAndPlayers(const QList &minWidthByColumn, qr } } +// ---------- 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) @@ -520,11 +380,151 @@ CardItem *GameScene::findTopmostCardInZone(const QList &items, return maxZCard; } -void GameScene::updateHoveredCard(CardItem *newCard) +// ---------- 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) { - if (hoveredCard && (newCard != hoveredCard)) - hoveredCard->setHovered(false); - if (newCard && (newCard != hoveredCard)) - newCard->setHovered(true); - hoveredCard = newCard; + for (auto &view : zoneViews) { + ZoneViewZone *temp = view->getZone(); + if (temp->getLogic()->getName() == zoneName && temp->getLogic()->getPlayer() == player && + qobject_cast(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 == "grave") + item->setPos(360, 100); + else if (zoneName == "rfg") + 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(Player *player, + CardZoneLogic *zone, + const QList &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(event)->scenePos()); + + return QGraphicsScene::event(event); +} + +void GameScene::timerEvent(QTimerEvent * /*event*/) +{ + QMutableSetIterator 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(card)); + if (!animationTimer->isActive()) + animationTimer->start(10, this); +} + +void GameScene::unregisterAnimationItem(AbstractCardItem *card) +{ + cardsToAnimate.remove(static_cast(card)); + if (cardsToAnimate.isEmpty()) + animationTimer->stop(); +} + +// ---------- Rubber Band ---------- + +void GameScene::startRubberBand(const QPointF &selectionOrigin) +{ + emit sigStartRubberBand(selectionOrigin); +} + +void GameScene::resizeRubberBand(const QPointF &cursorPoint) +{ + emit sigResizeRubberBand(cursorPoint); +} + +void GameScene::stopRubberBand() +{ + emit sigStopRubberBand(); } diff --git a/cockatrice/src/game/game_scene.h b/cockatrice/src/game/game_scene.h index f7ccf19fd..dcc0541c6 100644 --- a/cockatrice/src/game/game_scene.h +++ b/cockatrice/src/game/game_scene.h @@ -1,11 +1,3 @@ -/** - * @file game_scene.h - * @brief Represents the main game scene, managing players, zones, animations, and layout. - * - * The GameScene handles the graphical arrangement of players, cards, and zones. - * It calculates positions based on the number of players, columns, and rotations. - */ - #ifndef GAMESCENE_H #define GAMESCENE_H @@ -64,44 +56,58 @@ private: 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); + + /** Destructor, cleans up timer and zone views. */ ~GameScene() override; /** Updates UI text for all zone views. */ void retranslateUi(); - /** Processes changes in the view size and adjusts layout accordingly. */ - void processViewSizeChange(const QSize &newSize); - - /** Returns the current transform of the main view. */ - QTransform getViewTransform() const; - - /** Returns the viewport transform of the main view. */ - QTransform getViewportTransform() const; - - /** Starts a selection rubber band. */ - void startRubberBand(const QPointF &selectionOrigin); - - /** Resizes the rubber band to follow the cursor. */ - void resizeRubberBand(const QPointF &cursorPoint); - - /** Stops the rubber band selection. */ - void stopRubberBand(); + /** + * @brief Adds a player to the scene and stores their graphics item. + * @param player Player to add. + */ + void addPlayer(Player *player); /** - * @brief Collects active players who have not conceded. - * @param firstPlayerIndex Output parameter indicating the first local player index. + * @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. - * - * This is used to determine player order and layout. */ QList collectActivePlayers(int &firstPlayerIndex) const; /** - * @brief Rotates the list of players based on first player and rotation offset. + * @brief Rotates the list of players for layout. * @param players Original list of players. - * @param firstPlayerIndex Index of the first local player. - * @return Rotated list of players. + * @param firstPlayerIndex Index of first local player. + * @return Rotated list. */ QList rotatePlayers(const QList &players, int firstPlayerIndex) const; @@ -113,36 +119,31 @@ public: static int determineColumnCount(int playerCount); /** - * @brief Computes the total scene size and arranges players. + * @brief Computes layout positions and scene size based on players and columns. * @param playersPlaying List of active players. - * @param columns Number of columns to arrange players into. + * @param columns Number of columns to split into. * @return Calculated scene size. - * - * This function: - * - Splits players into columns and rows. - * - Calculates maximum column width and scene height. - * - Positions players within columns with spacing. - * - Mirrors player graphics when appropriate. */ QSizeF computeSceneSizeAndPlayerLayout(const QList &playersPlaying, int columns); - /** Calculates minimum width required for each column based on player minimum widths. */ + /** + * @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 the new scene width based on window size and minimum required width. - * @param newSize New view size. - * @param minWidth Minimum scene width needed to fit all players. - * @return New scene width after layout calculations. + * @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 positions players horizontally within the scene. - * @param minWidthByColumn Minimum width of each column. - * @param newWidth Total scene width to distribute. - * - * Extra width is evenly distributed across columns to fill available space. + * @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); @@ -156,16 +157,16 @@ public: void updateHoveredCard(CardItem *newCard); /** Registers a card for animation updates. */ - void registerAnimationItem(AbstractCardItem *item); + void registerAnimationItem(AbstractCardItem *card); /** Unregisters a card from animation updates. */ void unregisterAnimationItem(AbstractCardItem *card); public slots: - /** Toggles the display of a player's zone view. */ + /** Toggles a zone view for a player. */ void toggleZoneView(Player *player, const QString &zoneName, int numberCards, bool isReversed = false); - /** Adds a zone view showing revealed cards. */ + /** Adds a revealed zone view (for shown cards). */ void addRevealedZoneView(Player *player, CardZoneLogic *zone, const QList &cardList, @@ -174,27 +175,18 @@ public slots: /** Removes a zone view widget from the scene. */ void removeZoneView(ZoneViewWidget *item); - /** Adds a player to the scene and connects signals for layout updates. */ - void addPlayer(Player *player); - - /** Removes a player from the scene and updates layout. */ - void removePlayer(Player *player); - - /** Closes all active zone views. */ + /** Closes all zone views. */ void clearViews(); - /** Closes the most recently opened zone view. */ + /** Closes the most recently added zone view. */ void closeMostRecentZoneView(); - /** Adjusts player layout rotation and recomputes positions. */ - void adjustPlayerRotation(int rotationAdjustment); - - /** Recomputes the scene layout. */ - void rearrange(); - protected: - bool event(QEvent *event) override; ///< Handles hover updates. - void timerEvent(QTimerEvent *event) override; ///< Handles animations. + /** Handles hover updates. */ + bool event(QEvent *event) override; + + /** Handles animation timer updates. */ + void timerEvent(QTimerEvent *event) override; signals: void sigStartRubberBand(const QPointF &selectionOrigin);