[Game] Playmats (#7101)

* [Game] Playmats

Took 19 seconds

Took 1 minute

* [Playmats] Add fixed override and configurable fallbacks to settings.

Took 29 minutes

Took 43 seconds

* Add main to test.

Took 1 minute

Took 29 seconds

* Move settings to own group

Took 11 minutes

* Some attempts to refresh macOS compositor

Took 2 minutes

* Try something else

Took 17 minutes

* Don't manipulate live list

Took 11 minutes

* Change things about resolution, address comments.

Took 45 minutes

Took 12 minutes

* Comments.

Took 14 minutes

Took 8 seconds

* Re-order settings menu location

Took 2 minutes

* Rename PlaymatResolution to Info and add enums

Took 8 minutes

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
BruebachL 2026-08-21 10:40:49 +02:00 committed by GitHub
parent 74a454552a
commit 9eafd90a91
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
52 changed files with 1931 additions and 28 deletions

View file

@ -0,0 +1,277 @@
#include "playmat_settings_dialog.h"
#include "../../card_picture_loader/card_picture_loader.h"
#include "../cards/art_crop_attribution.h"
#include "../utility/completer_utils.h"
#include "card_database_display_model.h"
#include "card_database_model.h"
#include "playmat_preview_widget.h"
#include <QComboBox>
#include <QCompleter>
#include <QDialogButtonBox>
#include <QDoubleSpinBox>
#include <QFormLayout>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QPainter>
#include <QPainterPath>
#include <QPushButton>
#include <QVBoxLayout>
#include <libcockatrice/card/database/card_database_manager.h>
PlaymatSettingsDialog::PlaymatSettingsDialog(const CardRef &initialCard,
const PlaymatParams &initialParams,
QWidget *parent)
: QDialog(parent), currentCard(initialCard), currentParams(initialParams)
{
setMinimumWidth(500);
setupUi();
// Seed UI from initial values
if (!initialCard.name.isEmpty()) {
searchBar->setText(initialCard.name);
onCardNameChanged(initialCard.name);
// onCardNameChanged leaves the printing combo on the first printing in
// the database, which would silently change the deck's stored playmat
// card on accept. Restore the stored printing when it resolves locally.
const int storedPrintingIndex = providerComboBox->findData(initialCard.providerId);
if (storedPrintingIndex != -1) {
providerComboBox->setCurrentIndex(storedPrintingIndex);
} else {
// Stored printing not in the local database: keep it rather than
// silently substituting the first printing.
currentCard.providerId = initialCard.providerId;
reloadPreview();
}
}
marginLSpin->setValue(initialParams.marginPctL);
marginRSpin->setValue(initialParams.marginPctR);
verticalOffsetSpin->setValue(initialParams.verticalOffset);
zoomSpin->setValue(initialParams.zoom);
retranslateUi();
}
CardRef PlaymatSettingsDialog::card() const
{
return currentCard;
}
PlaymatParams PlaymatSettingsDialog::params() const
{
return currentParams;
}
QDoubleSpinBox *PlaymatSettingsDialog::makeSpinBox(double min, double max, double value, double step)
{
auto *spin = new QDoubleSpinBox;
spin->setRange(min, max);
spin->setSingleStep(step);
spin->setDecimals(3);
spin->setValue(value);
return spin;
}
void PlaymatSettingsDialog::initializeSearchBar()
{
searchBar = new QLineEdit;
cardDatabaseModel = new CardDatabaseModel(CardDatabaseManager::getInstance(), false, this);
cardDatabaseDisplayModel = new CardDatabaseDisplayModel(this);
cardDatabaseDisplayModel->setSourceModel(cardDatabaseModel);
const CardCompleterSetup cardSetup = createCardCompleter(cardDatabaseDisplayModel, this, 15);
searchModel = cardSetup.searchModel;
proxyModel = cardSetup.proxyModel;
completer = cardSetup.completer;
searchBar->setCompleter(completer);
connectCardCompleterSearch(searchBar, cardSetup);
connect(completer, static_cast<void (QCompleter::*)(const QString &)>(&QCompleter::activated), this,
[this](const QString &completion) {
if (searchBar->text() != completion) {
searchBar->setText(completion);
searchBar->setCursorPosition(searchBar->text().length());
}
onCardNameChanged(completion);
});
connect(searchBar, &QLineEdit::returnPressed, this, [this]() { onCardNameChanged(searchBar->text()); });
}
void PlaymatSettingsDialog::setupUi()
{
initializeSearchBar();
providerComboBox = new QComboBox;
connect(providerComboBox, &QComboBox::currentIndexChanged, this, [this]() {
currentCard.providerId = providerComboBox->currentData().toString();
reloadPreview();
onParamChanged();
});
marginLSpin = makeSpinBox(0.0, 0.95, currentParams.marginPctL, 0.01);
marginRSpin = makeSpinBox(0.0, 0.95, currentParams.marginPctR, 0.01);
verticalOffsetSpin = makeSpinBox(0.0, 1.0, currentParams.verticalOffset, 0.01);
zoomSpin = makeSpinBox(0.1, 4.0, currentParams.zoom, 0.05);
auto *form = new QFormLayout;
cardNameLabel = new QLabel;
printingLabel = new QLabel;
leftMarginLabel = new QLabel;
rightMarginLabel = new QLabel;
verticalOffsetLabel = new QLabel;
zoomLabel = new QLabel;
form->addRow(cardNameLabel, searchBar);
form->addRow(printingLabel, providerComboBox);
form->addRow(leftMarginLabel, marginLSpin);
form->addRow(rightMarginLabel, marginRSpin);
form->addRow(verticalOffsetLabel, verticalOffsetSpin);
form->addRow(zoomLabel, zoomSpin);
controlsGroup = new QGroupBox;
controlsGroup->setLayout(form);
preview = new PlaymatPreviewWidget;
auto *previewLayout = new QVBoxLayout;
previewLayout->addWidget(preview);
previewGroup = new QGroupBox;
previewGroup->setLayout(previewLayout);
auto *buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
removeButton = new QPushButton;
buttons->addButton(removeButton, QDialogButtonBox::ResetRole);
connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
connect(removeButton, &QPushButton::clicked, this, [this]() {
currentCard = CardRef{}; // empty signals removal
accept();
});
auto *root = new QVBoxLayout;
root->addWidget(controlsGroup);
root->addWidget(previewGroup);
root->addWidget(buttons);
setLayout(root);
connect(marginLSpin, &QDoubleSpinBox::valueChanged, this, &PlaymatSettingsDialog::onParamChanged);
connect(marginRSpin, &QDoubleSpinBox::valueChanged, this, &PlaymatSettingsDialog::onParamChanged);
connect(verticalOffsetSpin, &QDoubleSpinBox::valueChanged, this, &PlaymatSettingsDialog::onParamChanged);
connect(zoomSpin, &QDoubleSpinBox::valueChanged, this, &PlaymatSettingsDialog::onParamChanged);
}
void PlaymatSettingsDialog::populateProviderCombo(const QString &cardName)
{
providerComboBox->clear();
auto card = CardDatabaseManager::query()->getCard({cardName});
const auto &sets = card.getInfo().getSets();
for (const auto &printings : sets) {
for (const auto &p : printings) {
QString setName = p.getSet()->getLongName();
QString collector = p.getProperty("num");
QString uuid = p.getUuid();
QString label = setName;
if (!collector.isEmpty()) {
label += " #" + collector;
}
providerComboBox->addItem(label, uuid);
}
}
}
void PlaymatSettingsDialog::onCardNameChanged(const QString &name)
{
if (name.isEmpty()) {
currentPixmap = QPixmap();
preview->setPixmap(currentPixmap);
return;
}
const ExactCard card = CardDatabaseManager::query()->getCard({name});
if (!card) {
currentPixmap = QPixmap();
preview->setPixmap(currentPixmap);
providerComboBox->clear();
return;
}
currentCard.name = name;
populateProviderCombo(name);
if (providerComboBox->count() == 0) {
currentPixmap = QPixmap();
preview->setPixmap(currentPixmap);
currentCard.providerId.clear();
return;
}
currentCard.providerId = providerComboBox->currentData().toString();
reloadPreview();
}
void PlaymatSettingsDialog::reloadPreview()
{
if (currentCard.name.isEmpty()) {
return;
}
ExactCard card = CardDatabaseManager::query()->getCard({currentCard.name, currentCard.providerId});
if (!card) {
return;
}
disconnect(pixmapUpdatedConnection);
QPixmap fullRes;
CardPictureLoader::getPixmap(fullRes, card, QSize(745, 1040));
if (fullRes.isNull()) {
CardInfo *cardInfo = card.getCardPtr().data();
if (cardInfo) {
pixmapUpdatedConnection = connect(cardInfo, &CardInfo::pixmapUpdated, this, [this]() { reloadPreview(); });
}
return;
}
currentPixmap = fullRes;
preview->setPixmap(currentPixmap);
preview->setParams(currentParams);
preview->setAttribution(buildArtAttribution(card));
}
void PlaymatSettingsDialog::onParamChanged()
{
currentParams.marginPctL = marginLSpin->value();
currentParams.marginPctR = marginRSpin->value();
currentParams.verticalOffset = verticalOffsetSpin->value();
currentParams.zoom = zoomSpin->value();
preview->setParams(currentParams);
}
void PlaymatSettingsDialog::retranslateUi()
{
setWindowTitle(tr("Playmat Settings"));
searchBar->setPlaceholderText(tr("Type a card name..."));
cardNameLabel->setText(tr("Card name:"));
printingLabel->setText(tr("Printing:"));
leftMarginLabel->setText(tr("Left margin (%):"));
rightMarginLabel->setText(tr("Right margin (%):"));
verticalOffsetLabel->setText(tr("Vertical offset:"));
zoomLabel->setText(tr("Zoom:"));
controlsGroup->setTitle(tr("Parameters"));
previewGroup->setTitle(tr("Preview"));
removeButton->setText(tr("Remove Playmat"));
}