mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-07-08 09:03:57 -07:00
- Sync command zone visibility in the PlayerGraphicsItem constructor in case processPlayerInfo runs before the signal is connected.
- Emit CommandZone::effectiveHeightChanged() when a minimized zone's height changes so the stack zone repositions.
187 lines
5.9 KiB
C++
187 lines
5.9 KiB
C++
#include "command_zone.h"
|
|
|
|
#include "../../client/settings/cache_settings.h"
|
|
#include "../../game/player/player_actions.h"
|
|
#include "../../game/player/player_logic.h"
|
|
#include "../../interface/theme_manager.h"
|
|
#include "../board/abstract_counter.h"
|
|
#include "../board/card_drag_item.h"
|
|
#include "../board/card_item.h"
|
|
#include "../board/commander_tax_counter.h"
|
|
#include "../z_values.h"
|
|
|
|
#include <QGraphicsSceneMouseEvent>
|
|
#include <QPainter>
|
|
#include <libcockatrice/protocol/pb/command_move_card.pb.h>
|
|
#include <libcockatrice/utility/counter_ids.h>
|
|
|
|
CommandZone::CommandZone(CommandZoneLogic *_logic, int _zoneHeight, QGraphicsItem *parent)
|
|
: SelectZone(_logic, parent), zoneHeight(_zoneHeight)
|
|
{
|
|
connect(themeManager, &ThemeManager::themeChanged, this, &CommandZone::updateBg);
|
|
updateBg();
|
|
setCacheMode(DeviceCoordinateCache);
|
|
setupClipContainer(ZValues::CARD_BASE);
|
|
}
|
|
|
|
void CommandZone::updateBg()
|
|
{
|
|
update();
|
|
}
|
|
|
|
QRectF CommandZone::boundingRect() const
|
|
{
|
|
return {0, 0, ZoneSizes::COMMAND_ZONE_WIDTH, currentHeight()};
|
|
}
|
|
|
|
qreal CommandZone::currentHeight() const
|
|
{
|
|
return minimized ? qMax(zoneHeight * MINIMIZED_HEIGHT_RATIO, static_cast<double>(minimumHeight)) : zoneHeight;
|
|
}
|
|
|
|
void CommandZone::setMinimumHeight(int height)
|
|
{
|
|
if (minimumHeight == height) {
|
|
return;
|
|
}
|
|
// Only meaningful while minimized, where currentHeight() depends on minimumHeight.
|
|
const qreal oldEffectiveHeight = currentHeight();
|
|
minimumHeight = height;
|
|
prepareGeometryChange();
|
|
updateClipRect();
|
|
reorganizeCards();
|
|
update();
|
|
// Do NOT emit minimizedChanged: the minimized STATE is unchanged, and that signal
|
|
// feeds rearrangeZones -> rearrangeCounters -> setMinimumHeight (infinite loop).
|
|
// effectiveHeightChanged repositions neighbouring zones and converges instead: the
|
|
// rearrange re-enters setMinimumHeight with the same height and early-returns above.
|
|
if (!qFuzzyCompare(currentHeight(), oldEffectiveHeight)) {
|
|
emit effectiveHeightChanged();
|
|
}
|
|
}
|
|
|
|
bool CommandZone::isMinimized() const
|
|
{
|
|
return minimized;
|
|
}
|
|
|
|
void CommandZone::toggleMinimized()
|
|
{
|
|
minimized = !minimized;
|
|
|
|
prepareGeometryChange();
|
|
updateClipRect();
|
|
reorganizeCards();
|
|
update();
|
|
|
|
emit minimizedChanged(minimized);
|
|
}
|
|
|
|
void CommandZone::paint(QPainter *painter,
|
|
[[maybe_unused]] const QStyleOptionGraphicsItem *option,
|
|
[[maybe_unused]] QWidget *widget)
|
|
{
|
|
QBrush brush = themeManager->getExtraBgBrush(ThemeManager::Command, getLogic()->getPlayer()->getZoneId());
|
|
|
|
QPointF scenePos = mapToScene(QPointF(0, 0));
|
|
painter->setBrushOrigin(-scenePos);
|
|
|
|
painter->fillRect(boundingRect(), brush);
|
|
}
|
|
|
|
void CommandZone::handleDropEvent(const QList<CardDragItem *> &dragItems,
|
|
CardZoneLogic *startZone,
|
|
const QPoint &dropPoint)
|
|
{
|
|
if (startZone == nullptr || startZone->getPlayer() == nullptr || dragItems.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
int index = calcDropIndexFromY(dropPoint.y(), MIN_CARD_VISIBLE);
|
|
|
|
// Same-zone no-op: don't move a card onto itself
|
|
const auto &cards = getLogic()->getCards();
|
|
if (!cards.isEmpty() && index < cards.size() && startZone == getLogic() &&
|
|
cards.at(index)->getId() == dragItems.at(0)->getId()) {
|
|
return;
|
|
}
|
|
|
|
Command_MoveCard cmd;
|
|
cmd.set_start_player_id(startZone->getPlayer()->getPlayerInfo()->getId());
|
|
cmd.set_start_zone(startZone->getName().toStdString());
|
|
cmd.set_target_player_id(getLogic()->getPlayer()->getPlayerInfo()->getId());
|
|
cmd.set_target_zone(getLogic()->getName().toStdString());
|
|
cmd.set_x(index);
|
|
cmd.set_y(0);
|
|
|
|
for (const CardDragItem *item : dragItems) {
|
|
if (item) {
|
|
auto *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
|
cardToMove->set_card_id(item->getId());
|
|
if (item->isForceFaceDown()) {
|
|
cardToMove->set_face_down(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
getLogic()->getPlayer()->getPlayerActions()->sendGameCommand(cmd);
|
|
}
|
|
|
|
void CommandZone::reorganizeCards()
|
|
{
|
|
restoreStaleEscapedCards();
|
|
updateClipRect();
|
|
|
|
const auto &cards = getLogic()->getCards();
|
|
if (cards.isEmpty()) {
|
|
update();
|
|
return;
|
|
}
|
|
|
|
auto params = buildStackParams(MIN_CARD_VISIBLE);
|
|
params.allowBottomOverflow = true;
|
|
layoutCardsVertically(params);
|
|
update();
|
|
}
|
|
|
|
void CommandZone::registerTaxCounter(AbstractCounter *counter)
|
|
{
|
|
if (!counter || taxCounters.contains(counter)) {
|
|
return;
|
|
}
|
|
taxCounters.append(counter);
|
|
connect(counter, &QObject::destroyed, this, [this, counter]() { taxCounters.removeOne(counter); });
|
|
}
|
|
|
|
void CommandZone::rearrangeTaxCounters()
|
|
{
|
|
int activeTaxCounterCount = 0;
|
|
|
|
for (AbstractCounter *ctr : taxCounters) {
|
|
qreal y = TaxCounterSizes::TAX_COUNTER_MARGIN +
|
|
activeTaxCounterCount * (TaxCounterSizes::TAX_COUNTER_SIZE + TaxCounterSizes::TAX_COUNTER_MARGIN);
|
|
ctr->setPos(TaxCounterSizes::TAX_COUNTER_MARGIN, y);
|
|
ctr->setZValue(ZValues::TAX_COUNTERS);
|
|
// Visibility is owned solely by AbstractCounter::setActive() (the counter's own flag),
|
|
// which Qt AND-s with this CommandZone's visibility via child-visibility propagation
|
|
// (tax counters are graphics children of the zone). This function only handles layout,
|
|
// so it stacks and measures by isActive() alone.
|
|
if (ctr->isActive()) {
|
|
++activeTaxCounterCount;
|
|
}
|
|
}
|
|
|
|
int minHeight = activeTaxCounterCount * (TaxCounterSizes::TAX_COUNTER_SIZE + TaxCounterSizes::TAX_COUNTER_MARGIN) +
|
|
TaxCounterSizes::TAX_COUNTER_MARGIN;
|
|
setMinimumHeight(minHeight);
|
|
}
|
|
|
|
void CommandZone::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
|
|
{
|
|
if (event->button() == Qt::LeftButton) {
|
|
toggleMinimized();
|
|
event->accept();
|
|
} else {
|
|
SelectZone::mouseDoubleClickEvent(event);
|
|
}
|
|
}
|