Comments.

Took 14 minutes

Took 8 seconds
This commit is contained in:
Lukas Brübach 2026-08-20 08:56:25 +02:00
parent 80d44da729
commit daaee6ac82
9 changed files with 83 additions and 55 deletions

View file

@ -252,17 +252,27 @@ void GameScene::adjustPlayerRotation(int rotationAdjustment)
*/ */
void GameScene::rearrange() void GameScene::rearrange()
{ {
int firstPlayerIndex = 0; if (rearranging) {
auto playersPlaying = collectActivePlayers(firstPlayerIndex); needsReArrange = true;
playersPlaying = rotatePlayers(playersPlaying, firstPlayerIndex); return;
}
rearranging = true;
do {
needsReArrange = false;
int columns = determineColumnCount(playersPlaying.size()); int firstPlayerIndex = 0;
QSizeF sceneSize = computeSceneSizeAndPlayerLayout(playersPlaying, columns); auto playersPlaying = collectActivePlayers(firstPlayerIndex);
playersPlaying = rotatePlayers(playersPlaying, firstPlayerIndex);
phasesToolbar->setHeight(sceneSize.height()); int columns = determineColumnCount(playersPlaying.size());
setSceneRect(0, 0, sceneSize.width(), sceneSize.height()); QSizeF sceneSize = computeSceneSizeAndPlayerLayout(playersPlaying, columns);
processViewSizeChange(viewSize); phasesToolbar->setHeight(sceneSize.height());
setSceneRect(0, 0, sceneSize.width(), sceneSize.height());
processViewSizeChange(viewSize);
} while (needsReArrange);
rearranging = false;
} }
// ---------- View Size ---------- // ---------- View Size ----------

View file

@ -55,6 +55,8 @@ private:
QBasicTimer *animationTimer; ///< Timer for scene animations QBasicTimer *animationTimer; ///< Timer for scene animations
QHash<QObject *, IAnimatedItem *> animatedItems; ///< Items currently animating QHash<QObject *, IAnimatedItem *> animatedItems; ///< Items currently animating
int playerRotation; ///< Rotation offset for player layout int playerRotation; ///< Rotation offset for player layout
bool rearranging = false; ///< Guard against re-entrant rearrange
bool needsReArrange = false; ///< Pending rearrange requested during a pass
/** /**
* @brief Updates which card is currently hovered based on scene coordinates. * @brief Updates which card is currently hovered based on scene coordinates.

View file

@ -114,6 +114,7 @@ void GameView::startRubberBand(const QPointF &_selectionOrigin)
} }
selectionOrigin = _selectionOrigin; selectionOrigin = _selectionOrigin;
previousBandRect = QRect();
rubberBand->setGeometry(QRect(mapFromScene(selectionOrigin), QSize(0, 0))); rubberBand->setGeometry(QRect(mapFromScene(selectionOrigin), QSize(0, 0)));
rubberBand->show(); rubberBand->show();
} }
@ -131,11 +132,13 @@ void GameView::resizeRubberBand(const QPointF &cursorPoint, int selectedCount)
rubberBand->setGeometry(rect); rubberBand->setGeometry(rect);
if (viewport()) { if (viewport()) {
// Repaint the whole viewport rather than just the band's old area: the // Repaint the union of the previous and current band rects: the vacated
// vacated strip of a child widget is not reliably invalidated on all // strip of a child widget is not reliably invalidated on all platforms
// platforms (notably macOS), leaving stale pixels — including black // (notably macOS), leaving stale pixels under the selection.
// scene background where the playmat should show — under the selection. QRect dirty = previousBandRect.isNull() ? rect : previousBandRect.united(rect);
viewport()->update(); dirty.adjust(-1, -1, 1, 1);
viewport()->update(dirty);
previousBandRect = rect;
} }
if (!SettingsCache::instance().userInterface().getShowDragSelectionCount()) { if (!SettingsCache::instance().userInterface().getShowDragSelectionCount()) {
@ -179,12 +182,12 @@ void GameView::stopRubberBand()
return; return;
} }
// Same rationale as resizeRubberBand: make sure the whole viewport is // Same rationale as resizeRubberBand: repaint the last known band area
// repainted once the band is gone, since some platforms skip the exposed // since hiding a child widget doesn't reliably invalidate its region.
// region update of a hidden child widget.
rubberBand->hide(); rubberBand->hide();
if (viewport()) { if (viewport() && !previousBandRect.isNull()) {
viewport()->update(); viewport()->update(previousBandRect.adjusted(-1, -1, 1, 1));
previousBandRect = QRect();
} }
dragCountLabel->hide(); dragCountLabel->hide();
} }

View file

@ -27,6 +27,7 @@ private:
QWidget *tallyContainer; QWidget *tallyContainer;
QGridLayout *tallyLayout; QGridLayout *tallyLayout;
QPointF selectionOrigin; QPointF selectionOrigin;
QRect previousBandRect; ///< Last rubber-band rect for targeted repaint
QList<TallyRow> cachedTallyRows; ///< Cached entries to avoid redundant rebuilds QList<TallyRow> cachedTallyRows; ///< Cached entries to avoid redundant rebuilds
QSize rebuildTallyLabels(const QList<TallyRow> &entries); QSize rebuildTallyLabels(const QList<TallyRow> &entries);

View file

@ -18,6 +18,7 @@
#include <QGraphicsView> #include <QGraphicsView>
#include <libcockatrice/card/database/card_database_manager.h> #include <libcockatrice/card/database/card_database_manager.h>
#include <libcockatrice/deck_list/deck_list.h> #include <libcockatrice/deck_list/deck_list.h>
#include <libcockatrice/deck_list/playmat_resolver.h>
#include <libcockatrice/settings/interface_settings.h> #include <libcockatrice/settings/interface_settings.h>
PlayerGraphicsItem::PlayerGraphicsItem(PlayerLogic *_player) : player(_player) PlayerGraphicsItem::PlayerGraphicsItem(PlayerLogic *_player) : player(_player)
@ -376,6 +377,12 @@ void PlayerGraphicsItem::updatePlaymat()
return; return;
} }
// "Show own playmat only" — hide playmats for remote players
if (visibility == 1 && !player->getPlayerInfo()->getLocal()) {
clearPlaymat();
return;
}
CardRef playmatCard; CardRef playmatCard;
PlaymatParams params; PlaymatParams params;
@ -383,8 +390,40 @@ void PlayerGraphicsItem::updatePlaymat()
// Prefer the server-confirmed playmat (updated by Command_SetPlaymat). // Prefer the server-confirmed playmat (updated by Command_SetPlaymat).
playmatCard = player->getRemotePlaymatCard(); playmatCard = player->getRemotePlaymatCard();
params = player->getRemotePlaymatParams(); params = player->getRemotePlaymatParams();
} else if (player->getPlayerInfo()->getLocal()) {
// Local player without a server broadcast yet: apply the full
// settings-based resolution chain (mode, fallback list, behavior).
const auto &settings = SettingsCache::instance().userInterface();
const DeckList &deck = player->getDeck();
const auto fallbackBehavior = static_cast<PlaymatFallbackMode>(settings.getPlaymatFallbackBehavior());
switch (settings.getPlaymatMode()) {
case 0: { // Override deck playmat — always use collection
DeckList emptyDeck;
const PlaymatResolution resolved =
resolveEffectivePlaymat(emptyDeck, {}, settings.getPlaymatFallbackList(), fallbackBehavior, 0);
playmatCard = resolved.card;
params = resolved.params;
break;
}
case 1: { // Fallback if deck has none — deck > collection > none
const PlaymatResolution resolved =
resolveEffectivePlaymat(deck, {}, settings.getPlaymatFallbackList(), fallbackBehavior, 0);
playmatCard = resolved.card;
params = resolved.params;
break;
}
case 2: { // Deck only, ignore collection
const PlaymatResolution &deckPlaymat = deck.getPlaymat();
if (!deckPlaymat.card.isEmpty()) {
playmatCard = deckPlaymat.card;
params = deckPlaymat.params;
}
break;
}
}
} else { } else {
// Fall back to the locally baked-in deck playmat. // Opponent without a server broadcast: use the deck-embedded playmat.
const DeckList &deck = player->getDeck(); const DeckList &deck = player->getDeck();
const PlaymatResolution &deckPlaymat = deck.getPlaymat(); const PlaymatResolution &deckPlaymat = deck.getPlaymat();
if (!deckPlaymat.card.isEmpty()) { if (!deckPlaymat.card.isEmpty()) {

View file

@ -466,13 +466,6 @@ void DeckEditorDeckDockWidget::openPlaymatSettings()
deckStateManager->setPlaymat({newCard, newParams}); deckStateManager->setPlaymat({newCard, newParams});
} }
// "Also set as my default playmat": make this the fixed user-level
// fallback, so decks without a playmat of their own use it.
if (dialog.useAsDefault() && !newCard.isEmpty()) {
auto &interfaceSettings = SettingsCache::instance().userInterface();
interfaceSettings.setPlaymatFallbackList({{newCard, newParams}});
interfaceSettings.setPlaymatFallbackBehavior(0); // PlaymatFallbackMode::Fixed
}
updatePlaymatLabel(); updatePlaymatLabel();
} }
} }

View file

@ -7,7 +7,6 @@
#include "card_database_model.h" #include "card_database_model.h"
#include "playmat_preview_widget.h" #include "playmat_preview_widget.h"
#include <QCheckBox>
#include <QComboBox> #include <QComboBox>
#include <QCompleter> #include <QCompleter>
#include <QDialogButtonBox> #include <QDialogButtonBox>
@ -67,11 +66,6 @@ PlaymatParams PlaymatSettingsDialog::params() const
return currentParams; return currentParams;
} }
bool PlaymatSettingsDialog::useAsDefault() const
{
return useAsDefaultCheckBox->isChecked();
}
QDoubleSpinBox *PlaymatSettingsDialog::makeSpinBox(double min, double max, double value, double step) QDoubleSpinBox *PlaymatSettingsDialog::makeSpinBox(double min, double max, double value, double step)
{ {
auto *spin = new QDoubleSpinBox; auto *spin = new QDoubleSpinBox;
@ -143,9 +137,6 @@ void PlaymatSettingsDialog::setupUi()
controlsGroup = new QGroupBox; controlsGroup = new QGroupBox;
controlsGroup->setLayout(form); controlsGroup->setLayout(form);
useAsDefaultCheckBox = new QCheckBox;
useAsDefaultCheckBox->setEnabled(false);
preview = new PlaymatPreviewWidget; preview = new PlaymatPreviewWidget;
auto *previewLayout = new QVBoxLayout; auto *previewLayout = new QVBoxLayout;
@ -166,7 +157,6 @@ void PlaymatSettingsDialog::setupUi()
auto *root = new QVBoxLayout; auto *root = new QVBoxLayout;
root->addWidget(controlsGroup); root->addWidget(controlsGroup);
root->addWidget(useAsDefaultCheckBox);
root->addWidget(previewGroup); root->addWidget(previewGroup);
root->addWidget(buttons); root->addWidget(buttons);
setLayout(root); setLayout(root);
@ -206,8 +196,6 @@ void PlaymatSettingsDialog::onCardNameChanged(const QString &name)
if (name.isEmpty()) { if (name.isEmpty()) {
currentPixmap = QPixmap(); currentPixmap = QPixmap();
preview->setPixmap(currentPixmap); preview->setPixmap(currentPixmap);
useAsDefaultCheckBox->setChecked(false);
useAsDefaultCheckBox->setEnabled(false);
return; return;
} }
@ -216,13 +204,10 @@ void PlaymatSettingsDialog::onCardNameChanged(const QString &name)
currentPixmap = QPixmap(); currentPixmap = QPixmap();
preview->setPixmap(currentPixmap); preview->setPixmap(currentPixmap);
providerComboBox->clear(); providerComboBox->clear();
useAsDefaultCheckBox->setChecked(false);
useAsDefaultCheckBox->setEnabled(false);
return; return;
} }
currentCard.name = name; currentCard.name = name;
useAsDefaultCheckBox->setEnabled(true);
populateProviderCombo(name); populateProviderCombo(name);
@ -287,7 +272,6 @@ void PlaymatSettingsDialog::retranslateUi()
verticalOffsetLabel->setText(tr("Vertical offset:")); verticalOffsetLabel->setText(tr("Vertical offset:"));
zoomLabel->setText(tr("Zoom:")); zoomLabel->setText(tr("Zoom:"));
controlsGroup->setTitle(tr("Parameters")); controlsGroup->setTitle(tr("Parameters"));
useAsDefaultCheckBox->setText(tr("Also set as my default playmat (for decks without one)"));
previewGroup->setTitle(tr("Preview")); previewGroup->setTitle(tr("Preview"));
removeButton->setText(tr("Remove Playmat")); removeButton->setText(tr("Remove Playmat"));
} }

View file

@ -5,7 +5,6 @@
#include <QPixmap> #include <QPixmap>
#include <libcockatrice/deck_list/deck_list.h> #include <libcockatrice/deck_list/deck_list.h>
class QCheckBox;
class QComboBox; class QComboBox;
class QCompleter; class QCompleter;
class QDoubleSpinBox; class QDoubleSpinBox;
@ -39,12 +38,6 @@ public:
CardRef card() const; CardRef card() const;
PlaymatParams params() const; PlaymatParams params() const;
/**
* @brief Whether the user also wants the configured playmat saved as the
* user-level default (fallback for decks without one).
*/
bool useAsDefault() const;
private slots: private slots:
void onCardNameChanged(const QString &name); void onCardNameChanged(const QString &name);
void reloadPreview(); void reloadPreview();
@ -68,8 +61,6 @@ private:
QMetaObject::Connection pixmapUpdatedConnection; QMetaObject::Connection pixmapUpdatedConnection;
QCheckBox *useAsDefaultCheckBox;
QLabel *cardNameLabel; QLabel *cardNameLabel;
QLabel *printingLabel; QLabel *printingLabel;
QLabel *leftMarginLabel; QLabel *leftMarginLabel;

View file

@ -253,8 +253,8 @@ Server_Player::cmdDeckSelect(const Command_DeckSelect &cmd, ResponseContainer &r
event.mutable_player_properties()->set_deck_hash(deck->getDeckHash().toStdString()); event.mutable_player_properties()->set_deck_hash(deck->getDeckHash().toStdString());
const auto &playmat = deck->getPlaymat(); const auto &playmat = deck->getPlaymat();
auto *playmatParams = event.mutable_player_properties()->mutable_playmat_params(); auto *playmatParams = event.mutable_player_properties()->mutable_playmat_params();
playmatParams->set_card_name(playmat.card.name.toStdString()); playmatParams->set_card_name(playmat.card.name.left(MAX_NAME_LENGTH).toStdString());
playmatParams->set_card_provider_id(playmat.card.providerId.toStdString()); playmatParams->set_card_provider_id(playmat.card.providerId.left(MAX_NAME_LENGTH).toStdString());
playmatParams->set_margin_pct_l(playmat.params.marginPctL); playmatParams->set_margin_pct_l(playmat.params.marginPctL);
playmatParams->set_margin_pct_r(playmat.params.marginPctR); playmatParams->set_margin_pct_r(playmat.params.marginPctR);
playmatParams->set_vertical_offset(playmat.params.verticalOffset); playmatParams->set_vertical_offset(playmat.params.verticalOffset);
@ -613,9 +613,14 @@ Server_Player::cmdSetPlaymat(const Command_SetPlaymat &cmd, ResponseContainer &r
} }
const auto &pp = cmd.playmat_params(); const auto &pp = cmd.playmat_params();
const auto rawName = QString::fromStdString(pp.card_name());
const auto rawProviderId = QString::fromStdString(pp.card_provider_id());
if (rawName.length() > MAX_NAME_LENGTH || rawProviderId.length() > MAX_NAME_LENGTH) {
return Response::RespInvalidData;
}
PlaymatResolution playmat; PlaymatResolution playmat;
playmat.card.name = QString::fromStdString(pp.card_name()); playmat.card.name = rawName;
playmat.card.providerId = QString::fromStdString(pp.card_provider_id()); playmat.card.providerId = rawProviderId;
playmat.params.marginPctL = qBound(0.0, pp.margin_pct_l(), 0.95); playmat.params.marginPctL = qBound(0.0, pp.margin_pct_l(), 0.95);
playmat.params.marginPctR = qBound(0.0, pp.margin_pct_r(), 0.95); playmat.params.marginPctR = qBound(0.0, pp.margin_pct_r(), 0.95);
playmat.params.verticalOffset = qBound(0.0, pp.vertical_offset(), 1.0); playmat.params.verticalOffset = qBound(0.0, pp.vertical_offset(), 1.0);