mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-13 13:30:00 -08:00
Revert "Feature/continuumatrice product migration"
This commit is contained in:
parent
533d2f04c1
commit
e49d053838
150 changed files with 2599 additions and 5304 deletions
|
|
@ -13,7 +13,6 @@
|
|||
#include "libcockatrice/protocol/pb/event_server_shutdown.pb.h"
|
||||
|
||||
#include <QChar>
|
||||
#include <QCoreApplication>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QLineEdit>
|
||||
|
|
@ -218,7 +217,7 @@ void ConnectionController::onServerShutdownEvent(const Event_ServerShutdown &eve
|
|||
"games will be lost.\nReason for shutdown: %1",
|
||||
"", event.minutes())
|
||||
.arg(QString::fromStdString(event.reason())));
|
||||
serverShutdownMessageBox.setIconPixmap(themePixmap(QStringLiteral("continuumatrice")).scaled(64, 64));
|
||||
serverShutdownMessageBox.setIconPixmap(themePixmap(QStringLiteral("cockatrice")).scaled(64, 64));
|
||||
serverShutdownMessageBox.setText(tr("Scheduled server shutdown"));
|
||||
serverShutdownMessageBox.setWindowModality(Qt::ApplicationModal);
|
||||
serverShutdownMessageBox.setVisible(true);
|
||||
|
|
@ -334,7 +333,7 @@ void ConnectionController::onLoginError(int r,
|
|||
|
||||
case Response::RespContextError: {
|
||||
QMessageBox::critical(dialogParent, tr("Error"),
|
||||
tr("An internal error has occurred, please close and reopen Continuumatrice before "
|
||||
tr("An internal error has occurred, please close and reopen Cockatrice before "
|
||||
"trying again.\nIf the error persists, ensure you are running the latest "
|
||||
"version of the software and if needed contact the software developers."));
|
||||
break;
|
||||
|
|
@ -490,14 +489,14 @@ void ConnectionController::onProtocolVersionMismatch(int localVersion, int remot
|
|||
{
|
||||
if (localVersion > remoteVersion) {
|
||||
QMessageBox::critical(dialogParent, tr("Error"),
|
||||
tr("You are trying to connect to an obsolete server. Please downgrade your Continuumatrice "
|
||||
tr("You are trying to connect to an obsolete server. Please downgrade your Cockatrice "
|
||||
"version or connect to a suitable server.\n"
|
||||
"Local version is %1, remote version is %2.")
|
||||
.arg(localVersion)
|
||||
.arg(remoteVersion));
|
||||
} else {
|
||||
QMessageBox::critical(dialogParent, tr("Error"),
|
||||
tr("Your Continuumatrice client is obsolete. Please update your Continuumatrice version.\n"
|
||||
tr("Your Cockatrice client is obsolete. Please update your Cockatrice version.\n"
|
||||
"Local version is %1, remote version is %2.")
|
||||
.arg(localVersion)
|
||||
.arg(remoteVersion));
|
||||
|
|
@ -632,7 +631,7 @@ void ConnectionController::onPromptForgotPasswordChallenge()
|
|||
|
||||
void ConnectionController::updateWindowTitle()
|
||||
{
|
||||
const QString appName = QCoreApplication::applicationName();
|
||||
const QString appName = QStringLiteral("Cockatrice");
|
||||
QString title;
|
||||
|
||||
switch (remoteClient->getStatus()) {
|
||||
|
|
@ -654,7 +653,7 @@ void ConnectionController::updateWindowTitle()
|
|||
break;
|
||||
}
|
||||
case StatusLoggedIn: {
|
||||
title = appName + " - " + remoteClient->getUserName() + "@" + remoteClient->peerName();
|
||||
title = remoteClient->getUserName() + "@" + remoteClient->peerName();
|
||||
break;
|
||||
}
|
||||
case StatusRequestingForgotPassword:
|
||||
|
|
|
|||
|
|
@ -30,13 +30,13 @@
|
|||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#define STABLERELEASE_URL "https://api.github.com/repos/Continuum-Universes-Studio/Continuumatrice/releases/latest"
|
||||
#define STABLEMANUALDOWNLOAD_URL "https://github.com/Continuum-Universes-Studio/Continuumatrice/releases/latest"
|
||||
#define STABLETAG_URL "https://api.github.com/repos/Continuum-Universes-Studio/Continuumatrice/git/refs/tags/"
|
||||
#define STABLERELEASE_URL "https://api.github.com/repos/Cockatrice/Cockatrice/releases/latest"
|
||||
#define STABLEMANUALDOWNLOAD_URL "https://github.com/Cockatrice/Cockatrice/releases/latest"
|
||||
#define STABLETAG_URL "https://api.github.com/repos/Cockatrice/Cockatrice/git/refs/tags/"
|
||||
|
||||
#define BETARELEASE_URL "https://api.github.com/repos/Continuum-Universes-Studio/Continuumatrice/releases"
|
||||
#define BETAMANUALDOWNLOAD_URL "https://github.com/Continuum-Universes-Studio/Continuumatrice/releases/"
|
||||
#define BETARELEASE_CHANGESURL "https://github.com/Continuum-Universes-Studio/Continuumatrice/compare/%1...%2"
|
||||
#define BETARELEASE_URL "https://api.github.com/repos/Cockatrice/Cockatrice/releases"
|
||||
#define BETAMANUALDOWNLOAD_URL "https://github.com/Cockatrice/Cockatrice/releases/"
|
||||
#define BETARELEASE_CHANGESURL "https://github.com/Cockatrice/Cockatrice/compare/%1...%2"
|
||||
|
||||
#define GIT_SHORT_HASH_LEN 7
|
||||
|
||||
|
|
|
|||
|
|
@ -256,17 +256,6 @@ void SettingsCache::loadPaths()
|
|||
|
||||
computePath("customSets", dataPath + "/customsets/");
|
||||
computeFilePath("cardDatabase", dataPath + "/cards.xml");
|
||||
|
||||
// On a new Continuumatrice profile create an empty, valid XML v4 database.
|
||||
// Never download MTG data or copy the user's Cockatrice card database.
|
||||
const QString initialCardDb = dataPath + "/cards.xml";
|
||||
if (!QFile::exists(initialCardDb)) {
|
||||
if (!QFile::copy(QStringLiteral(":/resources/continuumatrice-empty-carddatabase.xml"), initialCardDb)) {
|
||||
qCWarning(SettingsCacheLog) << "Could not create Continuumatrice starter database:" << initialCardDb;
|
||||
} else {
|
||||
QFile::setPermissions(initialCardDb, QFile::ReadOwner | QFile::WriteOwner);
|
||||
}
|
||||
}
|
||||
computeFilePath("tokenDatabase", dataPath + "/tokens.xml");
|
||||
computeFilePath("spoilerDatabase", dataPath + "/spoiler.xml");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ QStringMap &SoundEngine::getAvailableThemes()
|
|||
#elif defined(Q_OS_WIN)
|
||||
"/sounds"
|
||||
#else // linux
|
||||
"/../share/continuumatrice/sounds"
|
||||
"/../share/cockatrice/sounds"
|
||||
#endif
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,186 +0,0 @@
|
|||
#include "essence_pool_item.h"
|
||||
|
||||
#include "../../interface/pixel_map_generator.h"
|
||||
|
||||
#include <QFont>
|
||||
#include <QGraphicsSceneHoverEvent>
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QInputDialog>
|
||||
#include <QPainter>
|
||||
#include <QPen>
|
||||
#include <QRectF>
|
||||
#include <QSize>
|
||||
#include <QWidget>
|
||||
#include <libcockatrice/game/board/counter_state.h>
|
||||
#include <libcockatrice/game/player/player_actions.h>
|
||||
#include <libcockatrice/game/player/player_info.h>
|
||||
#include <libcockatrice/game/player/player_logic.h>
|
||||
#include <libcockatrice/utility/essence_counter.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
EssencePoolItem::EssencePoolItem(PlayerLogic *_player, QGraphicsItem *parent)
|
||||
: QGraphicsObject(parent), player(_player)
|
||||
{
|
||||
setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton);
|
||||
setAcceptHoverEvents(true);
|
||||
setZValue(5);
|
||||
|
||||
connect(player, &PlayerLogic::counterAdded, this, &EssencePoolItem::attachCounter);
|
||||
connect(player, &PlayerLogic::counterRemoved, this, &EssencePoolItem::detachCounter);
|
||||
|
||||
// Reconnect and late view construction must paint the full snapshot,
|
||||
// even when the counterAdded events happened before this item existed.
|
||||
for (CounterState *state : player->getCounters()) {
|
||||
attachCounter(state);
|
||||
}
|
||||
setToolTip(tr("Essence pool — left click +1, right click -1, Shift+left to set"));
|
||||
}
|
||||
|
||||
QRectF EssencePoolItem::boundingRect() const
|
||||
{
|
||||
return QRectF(0, 0, Width, Height);
|
||||
}
|
||||
|
||||
void EssencePoolItem::attachCounter(CounterState *state)
|
||||
{
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
const QChar code = EssenceCounter::codeFromName(state->getName());
|
||||
if (code.isNull()) {
|
||||
return;
|
||||
}
|
||||
counters.insert(code, state);
|
||||
connect(state, &CounterState::valueChanged, this, [this](int, int, bool) { update(); });
|
||||
update();
|
||||
}
|
||||
|
||||
void EssencePoolItem::detachCounter(int id)
|
||||
{
|
||||
for (auto it = counters.begin(); it != counters.end();) {
|
||||
if (it.value() && it.value()->getId() == id) {
|
||||
it = counters.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
CounterState *EssencePoolItem::stateFor(QChar code) const
|
||||
{
|
||||
return counters.value(code).data();
|
||||
}
|
||||
|
||||
QChar EssencePoolItem::codeAt(const QPointF &position) const
|
||||
{
|
||||
const qreal x = position.x() - Padding;
|
||||
const qreal y = position.y() - HeaderHeight;
|
||||
if (x < 0 || y < 0 || x >= Columns * CellWidth || y >= 4 * CellHeight) {
|
||||
return QChar();
|
||||
}
|
||||
const int col = static_cast<int>(x) / CellWidth;
|
||||
const int row = static_cast<int>(y) / CellHeight;
|
||||
const int index = row * Columns + col;
|
||||
const QString &codes = EssenceCounter::symbols();
|
||||
return index >= 0 && index < codes.size() ? codes.at(index) : QChar();
|
||||
}
|
||||
|
||||
void EssencePoolItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
|
||||
{
|
||||
painter->save();
|
||||
painter->setRenderHint(QPainter::Antialiasing, true);
|
||||
painter->setPen(QPen(QColor(118, 125, 158), 1));
|
||||
painter->setBrush(QColor(16, 19, 31, 232));
|
||||
painter->drawRoundedRect(boundingRect().adjusted(0.5, 0.5, -0.5, -0.5), 7, 7);
|
||||
|
||||
QFont titleFont = painter->font();
|
||||
titleFont.setBold(true);
|
||||
titleFont.setPixelSize(15);
|
||||
painter->setFont(titleFont);
|
||||
painter->setPen(QColor(236, 238, 248));
|
||||
painter->drawText(QRectF(8, 3, Width - 16, 24), Qt::AlignCenter, tr("ESSENCE POOL"));
|
||||
|
||||
QFont countFont = painter->font();
|
||||
countFont.setBold(true);
|
||||
countFont.setPixelSize(14);
|
||||
painter->setFont(countFont);
|
||||
|
||||
const QString &codes = EssenceCounter::symbols();
|
||||
for (int i = 0; i < codes.size(); ++i) {
|
||||
const QChar code = codes.at(i);
|
||||
const int col = i % Columns;
|
||||
const int row = i / Columns;
|
||||
const qreal x = Padding + col * CellWidth;
|
||||
const qreal y = HeaderHeight + row * CellHeight;
|
||||
const QRectF tile(x, y, CellWidth - 3, CellHeight - 3);
|
||||
|
||||
painter->setPen(QPen(QColor(85, 91, 119), 1));
|
||||
painter->setBrush(QColor(43, 47, 67, 228));
|
||||
painter->drawRoundedRect(tile, 5, 5);
|
||||
|
||||
const QPixmap icon = ManaSymbolPixmapGenerator::generatePixmap(QString(code), QSize(32, 32));
|
||||
if (!icon.isNull()) {
|
||||
painter->drawPixmap(QPointF(x + 9, y + 2), icon);
|
||||
} else {
|
||||
painter->setPen(Qt::white);
|
||||
painter->drawText(QRectF(x, y + 2, CellWidth - 3, 30), Qt::AlignCenter, QString(code));
|
||||
}
|
||||
|
||||
CounterState *state = stateFor(code);
|
||||
const int count = state ? state->getValue() : 0;
|
||||
painter->setPen(count > 0 ? QColor(255, 244, 191) : QColor(178, 182, 200));
|
||||
painter->drawText(QRectF(x, y + 33, CellWidth - 3, 18),
|
||||
Qt::AlignCenter, QString::number(count));
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
void EssencePoolItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
const QChar code = codeAt(event->pos());
|
||||
CounterState *state = stateFor(code);
|
||||
if (!state || !player->getPlayerInfo()->getLocalOrJudge()) {
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
PlayerActions *actions = player->getPlayerActions();
|
||||
if (event->button() == Qt::LeftButton && (event->modifiers() & Qt::ShiftModifier)) {
|
||||
const QString label = code == QChar('N') ? tr("Colorless (N)") :
|
||||
code == QChar('J') ? tr("Jasper (J)") : tr("Essence %1").arg(code);
|
||||
bool accepted = false;
|
||||
QWidget *parent = event->widget() ? event->widget()->window() : nullptr;
|
||||
const int value = QInputDialog::getInt(parent, tr("Set Essence"),
|
||||
tr("Available %1:").arg(label),
|
||||
state->getValue(), 0, std::numeric_limits<int>::max(), 1, &accepted);
|
||||
if (accepted) {
|
||||
actions->actSetCounter(state->getId(), value);
|
||||
}
|
||||
} else if (event->button() == Qt::LeftButton) {
|
||||
actions->actIncrementCounter(state->getId(), 1);
|
||||
} else if (event->button() == Qt::RightButton) {
|
||||
if (state->getValue() > 0) {
|
||||
actions->actIncrementCounter(state->getId(), -1);
|
||||
}
|
||||
} else {
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void EssencePoolItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
|
||||
{
|
||||
const QChar code = codeAt(event->pos());
|
||||
CounterState *state = stateFor(code);
|
||||
if (!state) {
|
||||
setToolTip(tr("Essence pool — all types start at zero"));
|
||||
return;
|
||||
}
|
||||
const QString name = code == QChar('N') ? tr("Colorless Essence") :
|
||||
code == QChar('J') ? tr("Jasper Essence") : tr("Essence %1").arg(code);
|
||||
setToolTip(tr("%1: %2 available\nLeft +1 | Right -1 | Shift+Left: Set")
|
||||
.arg(name).arg(state->getValue()));
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
#ifndef CONTINUUMATRICE_ESSENCE_POOL_ITEM_H
|
||||
#define CONTINUUMATRICE_ESSENCE_POOL_ITEM_H
|
||||
|
||||
#include <QGraphicsObject>
|
||||
#include <QHash>
|
||||
#include <QPointer>
|
||||
|
||||
class CounterState;
|
||||
class PlayerLogic;
|
||||
class QGraphicsSceneMouseEvent;
|
||||
class QGraphicsSceneHoverEvent;
|
||||
class QPainter;
|
||||
class QStyleOptionGraphicsItem;
|
||||
class QWidget;
|
||||
|
||||
/**
|
||||
* An interactive, sixteen-type Essence resource pool attached to a player
|
||||
* battlefield. All values are read from the existing server-owned CounterState
|
||||
* objects; this graphics item does NOT own mutable match resource balances.
|
||||
*
|
||||
* Left click +1, right click -1, Shift+left to set an exact nonnegative amount.
|
||||
* Only the owning player or a game judge can modify the pool.
|
||||
*/
|
||||
class EssencePoolItem final : public QGraphicsObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static constexpr int Width = 224;
|
||||
static constexpr int Height = 258;
|
||||
|
||||
explicit EssencePoolItem(PlayerLogic *player, QGraphicsItem *parent = nullptr);
|
||||
|
||||
QRectF boundingRect() const override;
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
void hoverMoveEvent(QGraphicsSceneHoverEvent *event) override;
|
||||
|
||||
private:
|
||||
static constexpr int Columns = 4;
|
||||
static constexpr int Padding = 8;
|
||||
static constexpr int CellWidth = 52;
|
||||
static constexpr int CellHeight = 54;
|
||||
static constexpr int HeaderHeight = 29;
|
||||
|
||||
[[nodiscard]] QChar codeAt(const QPointF &position) const;
|
||||
[[nodiscard]] CounterState *stateFor(QChar code) const;
|
||||
void attachCounter(CounterState *state);
|
||||
void detachCounter(int id);
|
||||
|
||||
PlayerLogic *player;
|
||||
QHash<QChar, QPointer<CounterState>> counters;
|
||||
};
|
||||
|
||||
#endif // CONTINUUMATRICE_ESSENCE_POOL_ITEM_H
|
||||
|
|
@ -20,7 +20,6 @@
|
|||
#include "libcockatrice/utility/card_ref.h"
|
||||
#include "menu/player_menu.h"
|
||||
#include "player_area.h"
|
||||
#include "essence_pool_item.h"
|
||||
#include "player_dialogs.h"
|
||||
#include "player_target.h"
|
||||
|
||||
|
|
@ -41,7 +40,6 @@
|
|||
#include <libcockatrice/game/player/player_actions.h>
|
||||
#include <libcockatrice/game/player/player_info.h>
|
||||
#include <libcockatrice/game/player/player_logic.h>
|
||||
#include <libcockatrice/utility/essence_counter.h>
|
||||
#include <libcockatrice/game/zones/card_zone_logic.h>
|
||||
#include <libcockatrice/game/zones/hand_zone_logic.h>
|
||||
#include <libcockatrice/game/zones/pile_zone_logic.h>
|
||||
|
|
@ -53,10 +51,7 @@
|
|||
|
||||
namespace
|
||||
{
|
||||
// Reserve a third, compact column for the synchronized 4x4 Essence pool.
|
||||
// This keeps the 16 resource balances visible without obscuring the table.
|
||||
constexpr qreal EXTRA_PILE_COLUMN_WIDTH =
|
||||
CardDimensions::HEIGHT_F + 24 + EssencePoolItem::Width + 16;
|
||||
constexpr qreal EXTRA_PILE_COLUMN_WIDTH = CardDimensions::HEIGHT_F + 24;
|
||||
} // namespace
|
||||
|
||||
PlayerGraphicsItem::PlayerGraphicsItem(PlayerLogic *_player) : player(_player)
|
||||
|
|
@ -108,13 +103,6 @@ PlayerGraphicsItem::PlayerGraphicsItem(PlayerLogic *_player) : player(_player)
|
|||
|
||||
initializeZones();
|
||||
|
||||
// Board-owned renderer only. All Essence balances live in player runtime
|
||||
// CounterState and are sent/validated by the server.
|
||||
essencePool = new EssencePoolItem(player, this);
|
||||
const qreal essenceLeft = CardDimensions::HEIGHT_F + counterAreaWidth + 15 + 8 +
|
||||
CardDimensions::HEIGHT_F + 14;
|
||||
essencePool->setPos(essenceLeft, 14);
|
||||
|
||||
connect(player, &PlayerLogic::addViewCustomZoneActionToCustomZoneMenu, this,
|
||||
&PlayerGraphicsItem::onCustomZoneAdded);
|
||||
|
||||
|
|
@ -322,11 +310,6 @@ void PlayerGraphicsItem::setMirrored(bool _mirrored)
|
|||
|
||||
void PlayerGraphicsItem::onCounterAdded(CounterState *state)
|
||||
{
|
||||
// The Essence pool owns its own compact 4x4 display. Never add sixteen
|
||||
// full-size generic counters down the narrow life-counter column.
|
||||
if (EssenceCounter::isEssenceCounter(state->getName())) {
|
||||
return;
|
||||
}
|
||||
AbstractCounter *widget;
|
||||
if (state->getName() == "life") {
|
||||
widget = playerTarget->addCounter(state);
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ class TableZone;
|
|||
class AbstractCounter;
|
||||
class CardZone;
|
||||
class CounterState;
|
||||
class EssencePoolItem;
|
||||
class PlayerArea;
|
||||
class PlayerLogic;
|
||||
struct CardRef;
|
||||
|
|
@ -161,7 +160,6 @@ private:
|
|||
PlayerDialogs *playerDialogs;
|
||||
PlayerArea *playerArea;
|
||||
PlayerTarget *playerTarget;
|
||||
EssencePoolItem *essencePool = nullptr;
|
||||
QMap<int, AbstractCounter *> counterWidgets;
|
||||
QMap<QString, CardZone *> zoneGraphicsItems;
|
||||
PileZone *deckZoneGraphicsItem;
|
||||
|
|
|
|||
|
|
@ -251,11 +251,9 @@ void TableZone::paintBattlefieldRows(QPainter *painter)
|
|||
*/
|
||||
void TableZone::reloadBattlefieldAppearance()
|
||||
{
|
||||
// Canonical default battlefield palette. Theme battlefield.ini can override
|
||||
// these with #RRGGBB (opaque) or #AARRGGBB (alpha) values.
|
||||
frontZoneColor = QColor(QStringLiteral("#dc143c"));
|
||||
supportZoneColor = QColor(QStringLiteral("#c3b091"));
|
||||
commandZoneColor = QColor(QStringLiteral("#0a0e3f"));
|
||||
frontZoneColor = QColor(142, 52, 61, 128);
|
||||
supportZoneColor = QColor(40, 105, 129, 128);
|
||||
commandZoneColor = QColor(94, 66, 140, 128);
|
||||
|
||||
const QString themePath = themeManager->getCurrentThemePath();
|
||||
if (!themePath.isEmpty()) {
|
||||
|
|
|
|||
|
|
@ -25,14 +25,14 @@ InstallerCloseServer::InstallerCloseServer(QObject *parent) : QObject(parent)
|
|||
|
||||
QString InstallerCloseServer::socketNameForUser(qint64 processId, const QString &userName)
|
||||
{
|
||||
return QStringLiteral("ContinuumatriceInstallerClose-%1-%2").arg(processId).arg(userName);
|
||||
return QStringLiteral("CockatriceInstallerClose-%1-%2").arg(processId).arg(userName);
|
||||
}
|
||||
|
||||
QString InstallerCloseServer::socketName(qint64 processId)
|
||||
{
|
||||
// The same scoping helper the single-instance socket uses, so the probe only has to
|
||||
// reproduce one rule (USER, then USERNAME, then the home directory name).
|
||||
return scopedLocalServerName(QStringLiteral("ContinuumatriceInstallerClose-%1").arg(processId));
|
||||
return scopedLocalServerName(QStringLiteral("CockatriceInstallerClose-%1").arg(processId));
|
||||
}
|
||||
|
||||
bool InstallerCloseServer::listen()
|
||||
|
|
|
|||
|
|
@ -1,55 +0,0 @@
|
|||
#ifndef CONTINUUMATRICE_ESSENCE_CHART_COLORS_H
|
||||
#define CONTINUUMATRICE_ESSENCE_CHART_COLORS_H
|
||||
|
||||
#include <QColor>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QPair>
|
||||
#include <QSet>
|
||||
#include <QString>
|
||||
#include <libcockatrice/card/essence_types.h>
|
||||
|
||||
// CHART-ONLY presentation palette, NOT canon Essence colors or affiliations.
|
||||
// Each type must remain distinguishable without inventing lore. N is colorless.
|
||||
namespace EssenceCharts
|
||||
{
|
||||
inline QColor colorFor(const QString &code)
|
||||
{
|
||||
if (code == QStringLiteral("N")) {
|
||||
return QColor(145, 149, 156);
|
||||
}
|
||||
const int index = Essence::symbols().indexOf(code);
|
||||
if (index < 0) {
|
||||
// These charts are also reused for card types/categories. Retain
|
||||
// distinct readable visualization colors without assigning Essence lore.
|
||||
const QColor recognizedColor(code);
|
||||
if (recognizedColor.isValid()) {
|
||||
return recognizedColor;
|
||||
}
|
||||
return QColor::fromHsv(static_cast<int>(qHash(code) % 360u), 110, 195);
|
||||
}
|
||||
return QColor::fromHsv((index * 137) % 360, 125, 210);
|
||||
}
|
||||
|
||||
inline QList<QPair<QString, int>> ordered(const QMap<QString, int> &values)
|
||||
{
|
||||
QList<QPair<QString, int>> result;
|
||||
QSet<QString> used;
|
||||
for (const QChar code : Essence::symbols()) {
|
||||
const QString key(code);
|
||||
auto it = values.constFind(key);
|
||||
if (it != values.cend()) {
|
||||
result.append({it.key(), it.value()});
|
||||
used.insert(key);
|
||||
}
|
||||
}
|
||||
for (auto it = values.cbegin(); it != values.cend(); ++it) {
|
||||
if (!used.contains(it.key())) {
|
||||
result.append({it.key(), it.value()});
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} // namespace EssenceCharts
|
||||
|
||||
#endif // CONTINUUMATRICE_ESSENCE_CHART_COLORS_H
|
||||
|
|
@ -44,7 +44,7 @@ void IntentUrlParser::handle(const QString &urlStr)
|
|||
{
|
||||
QUrl url(urlStr);
|
||||
|
||||
if (url.scheme() != "continuumatrice") {
|
||||
if (url.scheme() != "cockatrice") {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ struct PendingIntentChain
|
|||
};
|
||||
|
||||
/**
|
||||
* @brief Parses continuumatrice:// links and runs them as serialized intent chains.
|
||||
* @brief Parses cockatrice:// links and runs them as serialized intent chains.
|
||||
*
|
||||
* Links are parsed by action (joingame/opendeck) and translated into an intent
|
||||
* chain. Chains are queued and run one at a time: a document can hand multiple
|
||||
|
|
|
|||
|
|
@ -488,10 +488,7 @@ const QPixmap &ManaSymbolPixmapGenerator::masterIcon(const QString &symbol)
|
|||
return it.value();
|
||||
}
|
||||
|
||||
// Essence uses its own artwork namespace, including codes shared with MTG.
|
||||
// Theme overrides are supported through icons/essence/<symbol>.svg/png.
|
||||
const QString asset = themeManager->assetPath(QStringLiteral("icons/essence/") + symbol);
|
||||
QImageReader reader(QStringLiteral("theme:") + asset);
|
||||
QImageReader reader("theme:icons/mana/" + symbol);
|
||||
QSize sourceSize = reader.size();
|
||||
if (!sourceSize.isEmpty()) {
|
||||
sourceSize.scale(QSize(MASTER_ICON_SIZE, MASTER_ICON_SIZE), Qt::KeepAspectRatio);
|
||||
|
|
|
|||
|
|
@ -294,7 +294,7 @@ QString ThemeManager::assetPath(QStringView prefix) const
|
|||
// on Windows where UAC VirtualStore can make a system dir appear writable).
|
||||
bool ThemeManager::isDirReallyWritable(const QString &dirPath)
|
||||
{
|
||||
const QString probe = QDir(dirPath).absoluteFilePath(".continuumatrice_write_test");
|
||||
const QString probe = QDir(dirPath).absoluteFilePath(".cockatrice_write_test");
|
||||
QFile f(probe);
|
||||
if (!f.open(QIODevice::WriteOnly)) {
|
||||
return false;
|
||||
|
|
@ -326,7 +326,7 @@ static QString systemThemesBasePath()
|
|||
#elif defined(Q_OS_WIN)
|
||||
base += "/themes";
|
||||
#else // linux
|
||||
base += "/../share/continuumatrice/themes";
|
||||
base += "/../share/cockatrice/themes";
|
||||
#endif
|
||||
return base;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
#include "../../../../client/settings/cache_settings.h"
|
||||
#include "libcockatrice/card/card_info.h"
|
||||
#include <libcockatrice/card/essence_types.h>
|
||||
#include "mana_symbol_widget.h"
|
||||
|
||||
#include <QChar>
|
||||
|
|
@ -42,9 +41,9 @@ ColorIdentityWidget::ColorIdentityWidget(QWidget *parent, const CardInfoPtr &car
|
|||
|
||||
void ColorIdentityWidget::populateManaSymbolWidgets()
|
||||
{
|
||||
// Continuum Universes supports fourteen named Essence codes plus N (colorless).
|
||||
const QString &allEssences = Essence::symbols();
|
||||
QStringList symbols = parseColorIdentity(colorIdentity);
|
||||
// Define the full WUBRG set (White, Blue, Black, Red, Green)
|
||||
QString fullColorIdentity = "WUBRG";
|
||||
QStringList symbols = parseColorIdentity(colorIdentity); // Parse mana cost string
|
||||
|
||||
// clear old layout
|
||||
QtUtils::clearLayoutRec(layout);
|
||||
|
|
@ -56,8 +55,7 @@ void ColorIdentityWidget::populateManaSymbolWidgets()
|
|||
|
||||
// populate mana symbols
|
||||
if (SettingsCache::instance().visualDeckStorage().getVisualDeckStorageDrawUnusedColorIdentities()) {
|
||||
for (const QChar code : allEssences) {
|
||||
const QString symbol(code);
|
||||
for (const QString symbol : fullColorIdentity) {
|
||||
auto *manaSymbol = new ManaSymbolWidget(this, symbol, symbols.contains(symbol));
|
||||
layout->addWidget(manaSymbol);
|
||||
}
|
||||
|
|
@ -122,11 +120,28 @@ void ColorIdentityWidget::resizeEvent(QResizeEvent *event)
|
|||
}
|
||||
}
|
||||
|
||||
QStringList ColorIdentityWidget::parseColorIdentity(const QString &essenceIdentity)
|
||||
QStringList ColorIdentityWidget::parseColorIdentity(const QString &manaString)
|
||||
{
|
||||
QStringList symbols;
|
||||
for (const QChar code : Essence::normalizeIdentity(essenceIdentity)) {
|
||||
symbols.append(QString(code));
|
||||
|
||||
// Handle split costs (e.g., "3U // 4UU")
|
||||
QStringList splitCosts = manaString.split(" // ");
|
||||
for (const QString &part : splitCosts) {
|
||||
QRegularExpression regex(R"(\{([^}]+)\}|(\d+)|([WUBRGCSPX]))");
|
||||
QRegularExpressionMatchIterator matches = regex.globalMatch(part);
|
||||
while (matches.hasNext()) {
|
||||
QRegularExpressionMatch match = matches.next();
|
||||
if (match.captured(1).isEmpty()) { // If no `{}` group was captured, check other groups
|
||||
if (!match.captured(2).isEmpty()) {
|
||||
symbols.append(match.captured(2)); // Number match
|
||||
} else {
|
||||
symbols.append(match.captured(3)); // Single mana letter match
|
||||
}
|
||||
} else {
|
||||
symbols.append(match.captured(1)); // `{}` enclosed match
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return symbols;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#include "deck_color_identity.h"
|
||||
|
||||
#include "libcockatrice/card/card_info.h"
|
||||
#include <libcockatrice/card/essence_types.h>
|
||||
|
||||
#include <QChar>
|
||||
#include <QList>
|
||||
|
|
@ -18,7 +17,7 @@ QString getDeckColorIdentity(const DeckList &deck, const CardDatabaseQuerier *db
|
|||
return {};
|
||||
}
|
||||
|
||||
QSet<QChar> colorSet; // Unique Essence symbols (including N for colorless).
|
||||
QSet<QChar> colorSet; // A set to collect unique color symbols (e.g., W, U, B, R, G)
|
||||
|
||||
for (const QString &cardName : cardList) {
|
||||
CardInfoPtr currentCard = db->getCardInfo(cardName);
|
||||
|
|
@ -30,9 +29,10 @@ QString getDeckColorIdentity(const DeckList &deck, const CardDatabaseQuerier *db
|
|||
}
|
||||
}
|
||||
|
||||
// Canonical Essence order is shared by the database and all widgets.
|
||||
// Ensure the color identity is in WUBRG order
|
||||
QString colorIdentity;
|
||||
for (const QChar &color : Essence::symbols()) {
|
||||
const QString wubrgOrder = "WUBRG";
|
||||
for (const QChar &color : wubrgOrder) {
|
||||
if (colorSet.contains(color)) {
|
||||
colorIdentity.append(color);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,9 +7,8 @@ class CardDatabaseQuerier;
|
|||
class DeckList;
|
||||
|
||||
/**
|
||||
* @brief Computes the Essence identity of a deck from the defined Essence
|
||||
* symbols (M,S,O,G,E,A,Q,C,J,B,R,L,V,T,P,N) of cards in main/sideboard.
|
||||
* N denotes colorless.
|
||||
* @brief Computes the color identity of a deck (e.g. "WUBRG") from the color
|
||||
* symbols of all cards in the main deck and sideboard, ordered WUBRG.
|
||||
*
|
||||
* Shared as a free function so the deck storage previews and the deck share
|
||||
* dialog compute identities identically.
|
||||
|
|
|
|||
|
|
@ -1,157 +0,0 @@
|
|||
#include "essence_filter_picker.h"
|
||||
|
||||
#include "../../../pixel_map_generator.h"
|
||||
|
||||
#include <QFontMetrics>
|
||||
#include <QGridLayout>
|
||||
#include <QIcon>
|
||||
#include <QLabel>
|
||||
#include <QMenu>
|
||||
#include <QPushButton>
|
||||
#include <QSignalBlocker>
|
||||
#include <QSize>
|
||||
#include <QSizePolicy>
|
||||
#include <QStringList>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
#include <QWidgetAction>
|
||||
#include <libcockatrice/card/essence_types.h>
|
||||
|
||||
EssenceFilterPicker::EssenceFilterPicker(QWidget *parent) : QToolButton(parent)
|
||||
{
|
||||
setPopupMode(QToolButton::InstantPopup);
|
||||
setToolButtonStyle(Qt::ToolButtonTextOnly); // Keep the summary visible even without a button icon.
|
||||
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
// Force a stable toolbar footprint independent of popup and font sizing.
|
||||
// Modes and all 16 Essence icons are contained inside the popup.
|
||||
setFixedWidth(qMax(156, fontMetrics().horizontalAdvance(tr("Essence: Any")) + 42));
|
||||
|
||||
popupMenu = new QMenu(this);
|
||||
auto *panel = new QWidget(popupMenu);
|
||||
panelLayout = new QVBoxLayout(panel);
|
||||
panelLayout->setContentsMargins(10, 10, 10, 10);
|
||||
panelLayout->setSpacing(7);
|
||||
|
||||
auto *heading = new QLabel(tr("Filter by Essence"), panel);
|
||||
panelLayout->addWidget(heading);
|
||||
|
||||
auto *grid = new QGridLayout();
|
||||
grid->setSpacing(5);
|
||||
|
||||
int index = 0;
|
||||
for (const QChar essence : Essence::symbols()) {
|
||||
const QString symbol(essence);
|
||||
auto *button = new QToolButton(panel);
|
||||
button->setCheckable(true);
|
||||
button->setAutoRaise(false);
|
||||
button->setFixedSize(42, 42);
|
||||
button->setIcon(QIcon(ManaSymbolPixmapGenerator::generatePixmap(symbol, QSize(32, 32))));
|
||||
button->setIconSize(QSize(30, 30));
|
||||
if (essence == QChar('N')) {
|
||||
button->setToolTip(tr("N — Colorless Essence"));
|
||||
button->setAccessibleName(tr("Colorless Essence N"));
|
||||
} else if (essence == QChar('J')) {
|
||||
button->setToolTip(tr("J — Jasper Essence"));
|
||||
button->setAccessibleName(tr("Jasper Essence J"));
|
||||
} else {
|
||||
button->setToolTip(tr("Essence %1").arg(symbol));
|
||||
button->setAccessibleName(tr("Essence %1").arg(symbol));
|
||||
}
|
||||
button->setProperty("essenceCode", symbol);
|
||||
connect(button, &QToolButton::toggled, this, [this, essence](bool checked) {
|
||||
updateSummary();
|
||||
emit essenceToggled(essence, checked);
|
||||
});
|
||||
|
||||
// Sixteen Essences form a compact 4x4 grid.
|
||||
grid->addWidget(button, index / 4, index % 4);
|
||||
buttons.insert(essence, button);
|
||||
++index;
|
||||
}
|
||||
panelLayout->addLayout(grid);
|
||||
|
||||
auto *clearButton = new QPushButton(tr("Clear Essence selection"), panel);
|
||||
connect(clearButton, &QPushButton::clicked, this, [this]() {
|
||||
// Clear as ONE model operation, so Exact Match and Include/Exclude
|
||||
// don't retain stale "not this Essence" predicates.
|
||||
for (const QChar essence : Essence::symbols()) {
|
||||
if (auto *button = buttons.value(essence); button && button->isChecked()) {
|
||||
const QSignalBlocker blocker(button);
|
||||
button->setChecked(false);
|
||||
}
|
||||
}
|
||||
updateSummary();
|
||||
emit selectionCleared();
|
||||
});
|
||||
panelLayout->addWidget(clearButton);
|
||||
|
||||
auto *panelAction = new QWidgetAction(popupMenu);
|
||||
panelAction->setDefaultWidget(panel);
|
||||
popupMenu->addAction(panelAction);
|
||||
setMenu(popupMenu);
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void EssenceFilterPicker::addPopupControl(QWidget *control)
|
||||
{
|
||||
if (!control || !panelLayout) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Insert above the Clear button, keeping the entire configuration in one
|
||||
// popup rather than competing for horizontal space in the main toolbar.
|
||||
panelLayout->insertWidget(panelLayout->count() - 1, control);
|
||||
}
|
||||
|
||||
QSet<QChar> EssenceFilterPicker::activeEssences() const
|
||||
{
|
||||
QSet<QChar> active;
|
||||
for (auto it = buttons.cbegin(); it != buttons.cend(); ++it) {
|
||||
if (it.value()->isChecked()) {
|
||||
active.insert(it.key());
|
||||
}
|
||||
}
|
||||
return active;
|
||||
}
|
||||
|
||||
void EssenceFilterPicker::setEssenceActive(QChar essence, bool active)
|
||||
{
|
||||
auto *button = buttons.value(essence);
|
||||
if (!button || button->isChecked() == active) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Restoring external filter state must not rewrite the filter model.
|
||||
const QSignalBlocker blocker(button);
|
||||
button->setChecked(active);
|
||||
updateSummary();
|
||||
}
|
||||
|
||||
void EssenceFilterPicker::retranslateUi()
|
||||
{
|
||||
updateSummary();
|
||||
}
|
||||
|
||||
void EssenceFilterPicker::updateSummary()
|
||||
{
|
||||
QStringList selected;
|
||||
const QSet<QChar> active = activeEssences();
|
||||
for (const QChar essence : Essence::symbols()) {
|
||||
if (active.contains(essence)) {
|
||||
selected.append(QString(essence));
|
||||
}
|
||||
}
|
||||
|
||||
if (selected.isEmpty()) {
|
||||
setText(tr("Essence: Any"));
|
||||
setToolTip(tr("Filter by Essence (none selected)"));
|
||||
} else if (selected.size() == 1) {
|
||||
setText(tr("Essence: %1").arg(selected.first()));
|
||||
setToolTip(tr("Selected Essence: %1").arg(selected.first()));
|
||||
} else {
|
||||
// Keep the toolbar label short; the tooltip lists the exact types.
|
||||
setText(tr("Essence (%1)").arg(selected.size()));
|
||||
setToolTip(tr("Selected Essence: %1").arg(selected.join(QStringLiteral(", "))));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
#ifndef CONTINUUMATRICE_ESSENCE_FILTER_PICKER_H
|
||||
#define CONTINUUMATRICE_ESSENCE_FILTER_PICKER_H
|
||||
|
||||
#include <QChar>
|
||||
#include <QHash>
|
||||
#include <QSet>
|
||||
#include <QToolButton>
|
||||
|
||||
class QMenu;
|
||||
class QVBoxLayout;
|
||||
class QWidget;
|
||||
|
||||
/**
|
||||
* Compact, reusable multi-select Essence picker for the deck and card database
|
||||
* toolbars. The menu contains all fifteen Essence symbols in a 5x3 icon grid.
|
||||
* Clicking a symbol does not close the popup; programmatic synchronization
|
||||
* does not emit a user-selection signal.
|
||||
*/
|
||||
class EssenceFilterPicker final : public QToolButton
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit EssenceFilterPicker(QWidget *parent = nullptr);
|
||||
|
||||
[[nodiscard]] QSet<QChar> activeEssences() const;
|
||||
void setEssenceActive(QChar essence, bool active);
|
||||
// Put the host's filtering mode selector inside this popup too:
|
||||
// neither toolbar should require a separate cramped control.
|
||||
void addPopupControl(QWidget *control);
|
||||
void retranslateUi();
|
||||
|
||||
signals:
|
||||
void essenceToggled(QChar essence, bool active);
|
||||
// A clear request removes ALL Essence filters, including exclusions,
|
||||
// rather than creating fifteen negative filters in Exact/Exclude mode.
|
||||
void selectionCleared();
|
||||
|
||||
private:
|
||||
void updateSummary();
|
||||
|
||||
QHash<QChar, QToolButton *> buttons;
|
||||
QMenu *popupMenu = nullptr;
|
||||
QVBoxLayout *panelLayout = nullptr;
|
||||
};
|
||||
|
||||
#endif // CONTINUUMATRICE_ESSENCE_FILTER_PICKER_H
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
#include "mana_cost_widget.h"
|
||||
|
||||
#include "libcockatrice/card/card_info.h"
|
||||
#include <libcockatrice/card/essence_types.h>
|
||||
#include "mana_symbol_widget.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
|
|
@ -52,7 +51,28 @@ void ManaCostWidget::resizeEvent(QResizeEvent *event)
|
|||
}
|
||||
}
|
||||
|
||||
QStringList ManaCostWidget::parseManaCost(const QString &essenceCost)
|
||||
QStringList ManaCostWidget::parseManaCost(const QString &cmc)
|
||||
{
|
||||
return Essence::parseCost(essenceCost);
|
||||
QStringList symbols;
|
||||
|
||||
// Handle split costs (e.g., "3U // 4UU")
|
||||
QStringList splitCosts = cmc.split(" // ");
|
||||
for (const QString &part : splitCosts) {
|
||||
QRegularExpression regex(R"(\{([^}]+)\}|(\d+)|([WUBRGCSPX]))");
|
||||
QRegularExpressionMatchIterator matches = regex.globalMatch(part);
|
||||
while (matches.hasNext()) {
|
||||
QRegularExpressionMatch match = matches.next();
|
||||
if (match.captured(1).isEmpty()) { // If no `{}` group was captured, check other groups
|
||||
if (!match.captured(2).isEmpty()) {
|
||||
symbols.append(match.captured(2)); // Number match
|
||||
} else {
|
||||
symbols.append(match.captured(3)); // Single mana letter match
|
||||
}
|
||||
} else {
|
||||
symbols.append(match.captured(1)); // `{}` enclosed match
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return symbols;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,14 +57,14 @@ ManaBaseConfigDialog::ManaBaseConfigDialog(DeckListStatisticsAnalyzer *analyzer,
|
|||
|
||||
void ManaBaseConfigDialog::retranslateUi()
|
||||
{
|
||||
setWindowTitle(tr("Essence Production Configuration"));
|
||||
setWindowTitle(tr("Mana Base Configuration"));
|
||||
|
||||
displayTypeLabel->setText(tr("Display type:"));
|
||||
|
||||
displayType->clear();
|
||||
displayType->addItems({tr("pie"), tr("bar"), tr("combinedBar")});
|
||||
|
||||
filterLabel->setText(tr("Filter Essence types (optional):"));
|
||||
filterLabel->setText(tr("Filter Colors (optional):"));
|
||||
|
||||
buttons->button(QDialogButtonBox::Ok)->setText(tr("OK"));
|
||||
buttons->button(QDialogButtonBox::Cancel)->setText(tr("Cancel"));
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
#include "mana_base_widget.h"
|
||||
|
||||
#include "../../../../essence_chart_colors.h"
|
||||
#include "../../../general/display/charts/bars/bar_widget.h"
|
||||
#include "../../../general/display/charts/bars/color_bar.h"
|
||||
#include "../../../general/display/charts/pies/color_pie.h"
|
||||
|
|
@ -31,7 +30,7 @@ namespace
|
|||
{
|
||||
|
||||
AnalyticsPanelWidgetRegistrar registerManaBase{
|
||||
"manaBase", ManaBaseWidget::tr("Essence Production"),
|
||||
"manaBase", ManaBaseWidget::tr("Mana Base"),
|
||||
[](QWidget *parent, DeckListStatisticsAnalyzer *analyzer) { return new ManaBaseWidget(parent, analyzer); }};
|
||||
|
||||
} // anonymous namespace
|
||||
|
|
@ -84,12 +83,16 @@ void ManaBaseWidget::updateDisplay()
|
|||
|
||||
// Choose display mode
|
||||
if (config.displayType == "bar") {
|
||||
const QList<QPair<QString, int>> sortedColors = EssenceCharts::ordered(mapSorted);
|
||||
const QList<QPair<QString, int>> sortedColors = GameSpecificColors::MTG::sortManaMapWUBRGCFirst(mapSorted);
|
||||
static const QHash<QString, QColor> colorMap = {
|
||||
{"W", QColor(248, 231, 185)}, {"U", QColor(14, 104, 171)}, {"B", QColor(21, 11, 0)},
|
||||
{"R", QColor(211, 32, 42)}, {"G", QColor(0, 115, 62)}, {"C", QColor(150, 150, 150)},
|
||||
};
|
||||
|
||||
for (const auto &[color, count] : sortedColors) {
|
||||
QString label = QString("%1 %2 (%3)").arg(color).arg(count).arg(cardCount.value(color));
|
||||
|
||||
BarWidget *bar = new BarWidget(label, count, highest, EssenceCharts::colorFor(color), this);
|
||||
BarWidget *bar = new BarWidget(label, count, highest, colorMap.value(color, Qt::gray), this);
|
||||
|
||||
barLayout->addWidget(bar);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include "mana_curve_category_widget.h"
|
||||
|
||||
#include "../../../general/display/charts/bars/bar_chart_widget.h"
|
||||
#include "../../../../essence_chart_colors.h"
|
||||
#include "libcockatrice/utility/color.h"
|
||||
#include "libcockatrice/utility/qt_utils.h"
|
||||
#include "mana_curve_config.h"
|
||||
|
||||
|
|
@ -110,7 +110,7 @@ void ManaCurveCategoryWidget::updateDisplay(int minCmc,
|
|||
|
||||
QVector<BarSegment> segments;
|
||||
if (val > 0) {
|
||||
segments.push_back({cat, val, cards, EssenceCharts::colorFor(cat)});
|
||||
segments.push_back({cat, val, cards, GameSpecificColors::MTG::colorHelper(cat)});
|
||||
}
|
||||
|
||||
catBars.push_back({QString::number(cmc), segments});
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ void ManaCurveConfigDialog::retranslateUi()
|
|||
{
|
||||
labelGroupBy->setText(tr("Group By:"));
|
||||
groupBy->setItemText(0, tr("type"));
|
||||
groupBy->setItemText(1, tr("Essence"));
|
||||
groupBy->setItemText(1, tr("color"));
|
||||
groupBy->setItemText(2, tr("subtype"));
|
||||
groupBy->setItemText(3, tr("power"));
|
||||
groupBy->setItemText(4, tr("toughness"));
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include "mana_curve_total_widget.h"
|
||||
|
||||
#include "../../../general/display/charts/bars/bar_chart_widget.h"
|
||||
#include "../../../../essence_chart_colors.h"
|
||||
#include "libcockatrice/utility/color.h"
|
||||
#include "mana_curve_config.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
|
|
@ -71,7 +71,7 @@ void ManaCurveTotalWidget::updateDisplay(const QString &categoryName,
|
|||
cards = catIt->value(cmc);
|
||||
}
|
||||
|
||||
segments.push_back({category, value, cards, EssenceCharts::colorFor(category)});
|
||||
segments.push_back({category, value, cards, GameSpecificColors::MTG::colorHelper(category)});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace
|
|||
{
|
||||
|
||||
AnalyticsPanelWidgetRegistrar registerManaCurve{
|
||||
"manaCurve", ManaCurveWidget::tr("Essence Curve"),
|
||||
"manaCurve", ManaCurveWidget::tr("Mana Curve"),
|
||||
[](QWidget *parent, DeckListStatisticsAnalyzer *analyzer) { return new ManaCurveWidget(parent, analyzer); }};
|
||||
|
||||
} // anonymous namespace
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ void ManaDevotionConfigDialog::retranslateUi()
|
|||
displayType->setItemText(1, tr("bar"));
|
||||
displayType->setItemText(2, tr("combinedBar"));
|
||||
|
||||
labelFilters->setText(tr("Filter Essence types (optional):"));
|
||||
labelFilters->setText(tr("Filter Colors (optional):"));
|
||||
}
|
||||
|
||||
void ManaDevotionConfigDialog::accept()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
#include "mana_devotion_widget.h"
|
||||
|
||||
#include "../../../../essence_chart_colors.h"
|
||||
#include "../../../general/display/charts/bars/bar_widget.h"
|
||||
#include "../../../general/display/charts/bars/color_bar.h"
|
||||
#include "../../../general/display/charts/pies/color_pie.h"
|
||||
|
|
@ -30,7 +29,7 @@ namespace
|
|||
{
|
||||
|
||||
AnalyticsPanelWidgetRegistrar registerManaDevotion{
|
||||
"manaDevotion", ManaDevotionWidget::tr("Essence Cost Symbols"),
|
||||
"manaDevotion", ManaDevotionWidget::tr("Mana Devotion"),
|
||||
[](QWidget *parent, DeckListStatisticsAnalyzer *analyzer) { return new ManaDevotionWidget(parent, analyzer); }};
|
||||
|
||||
} // anonymous namespace
|
||||
|
|
@ -83,13 +82,18 @@ void ManaDevotionWidget::updateDisplay()
|
|||
mapSorted.insert(QString(it.key()), it.value());
|
||||
}
|
||||
|
||||
// Color map
|
||||
QHash<QChar, QColor> colors = {{'W', QColor(248, 231, 185)}, {'U', QColor(14, 104, 171)},
|
||||
{'B', QColor(21, 11, 0)}, {'R', QColor(211, 32, 42)},
|
||||
{'G', QColor(0, 115, 62)}, {'C', QColor(150, 150, 150)}};
|
||||
|
||||
// Choose display mode
|
||||
if (config.displayType == "bar") {
|
||||
// One BarWidget per devotion color
|
||||
for (auto c : devoMap.keys()) {
|
||||
QString label = QString("%1 %2 (%3)").arg(c).arg(devoMap[c]).arg(cardCount.value(QString(c)));
|
||||
|
||||
BarWidget *bar = new BarWidget(label, devoMap[c], highest, EssenceCharts::colorFor(QString(c)), this);
|
||||
BarWidget *bar = new BarWidget(label, devoMap[c], highest, colors.value(c, Qt::gray), this);
|
||||
|
||||
barLayout->addWidget(bar);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,18 +10,11 @@
|
|||
#include <QListWidgetItem>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <libcockatrice/card/essence_types.h>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
class QWidget;
|
||||
|
||||
static const QStringList kEssences = [] {
|
||||
QStringList codes;
|
||||
for (const QChar symbol : Essence::symbols()) {
|
||||
codes.append(QString(symbol));
|
||||
}
|
||||
return codes;
|
||||
}();
|
||||
static const QStringList kColors = {"W", "U", "B", "R", "G", "C"};
|
||||
|
||||
ManaDistributionConfigDialog::ManaDistributionConfigDialog(DeckListStatisticsAnalyzer *analyzer, QWidget *parent)
|
||||
: QDialog(parent), analyzer(analyzer)
|
||||
|
|
@ -40,7 +33,7 @@ ManaDistributionConfigDialog::ManaDistributionConfigDialog(DeckListStatisticsAna
|
|||
|
||||
filterList = new QListWidget(this);
|
||||
filterList->setSelectionMode(QAbstractItemView::MultiSelection);
|
||||
filterList->addItems(kEssences); // dynamic/fixed, no translation needed
|
||||
filterList->addItems(kColors); // dynamic/fixed, no translation needed
|
||||
lay->addWidget(filterList);
|
||||
|
||||
showColorRows = new QCheckBox(this);
|
||||
|
|
@ -63,9 +56,9 @@ void ManaDistributionConfigDialog::retranslateUi()
|
|||
displayType->setItemText(0, tr("pie"));
|
||||
displayType->setItemText(1, tr("bar"));
|
||||
|
||||
labelFilters->setText(tr("Essence types:"));
|
||||
labelFilters->setText(tr("Colors:"));
|
||||
|
||||
showColorRows->setText(tr("Show per-Essence rows"));
|
||||
showColorRows->setText(tr("Show per-color rows"));
|
||||
|
||||
// QDialogButtonBox buttons are automatically translated
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,5 +48,5 @@ void ManaDistributionSingleDisplayWidget::setDevotion(int pips, int cards, int p
|
|||
void ManaDistributionSingleDisplayWidget::setProduction(int pips, int cards, int percent)
|
||||
{
|
||||
productionBar->setValue(percent);
|
||||
productionLabel->setText(QString(tr("%1 Essence (%2 cards)")).arg(pips).arg(cards));
|
||||
productionLabel->setText(QString(tr("%1 mana (%2 cards)")).arg(pips).arg(cards));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,25 +14,18 @@
|
|||
#include <QList>
|
||||
#include <QSharedPointer>
|
||||
#include <QStringList>
|
||||
#include <libcockatrice/card/essence_types.h>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
namespace
|
||||
{
|
||||
AnalyticsPanelWidgetRegistrar registerManaDistribution{
|
||||
"manaProdDevotion", ManaDistributionWidget::tr("Essence Production + Costs"),
|
||||
"manaProdDevotion", ManaDistributionWidget::tr("Mana Production + Devotion"),
|
||||
[](QWidget *parent, DeckListStatisticsAnalyzer *analyzer) { return new ManaDistributionWidget(parent, analyzer); }};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
static const QStringList kEssences = [] {
|
||||
QStringList codes;
|
||||
for (const QChar symbol : Essence::symbols()) {
|
||||
codes.append(QString(symbol));
|
||||
}
|
||||
return codes;
|
||||
}();
|
||||
static const QStringList kColors = {"W", "U", "B", "R", "G", "C"};
|
||||
|
||||
ManaDistributionWidget::ManaDistributionWidget(QWidget *parent, DeckListStatisticsAnalyzer *analyzer)
|
||||
: AbstractAnalyticsPanelWidget(parent, analyzer)
|
||||
|
|
@ -56,7 +49,7 @@ ManaDistributionWidget::ManaDistributionWidget(QWidget *parent, DeckListStatisti
|
|||
row = new QHBoxLayout();
|
||||
containerLayout->addLayout(row);
|
||||
|
||||
for (const QString &c : kEssences) {
|
||||
for (const QString &c : kColors) {
|
||||
auto *w = new ManaDistributionSingleDisplayWidget(c, this);
|
||||
row->addWidget(w);
|
||||
rows[c] = w;
|
||||
|
|
@ -72,7 +65,7 @@ void ManaDistributionWidget::updateDisplay()
|
|||
const auto &prodPips = analyzer->getProductionPipCount();
|
||||
const auto &prodCards = analyzer->getProductionCardCount();
|
||||
|
||||
QStringList filtered = config.filters.isEmpty() ? kEssences : config.filters;
|
||||
QStringList filtered = config.filters.isEmpty() ? kColors : config.filters;
|
||||
|
||||
QMap<QString, int> devMap, prodMap;
|
||||
for (const QString &c : filtered) {
|
||||
|
|
@ -96,7 +89,7 @@ void ManaDistributionWidget::updateDisplay()
|
|||
productionBarTop->setColors(prodMap);
|
||||
}
|
||||
|
||||
for (const QString &c : kEssences) {
|
||||
for (const QString &c : kColors) {
|
||||
auto *w = rows.value(c);
|
||||
|
||||
if (!w) {
|
||||
|
|
@ -133,7 +126,7 @@ void ManaDistributionWidget::updateDisplay()
|
|||
QDialog *ManaDistributionWidget::createConfigDialog(QWidget *parent)
|
||||
{
|
||||
auto *dlg = new ManaDistributionConfigDialog(analyzer, parent);
|
||||
dlg->setWindowTitle(tr("Essence Distribution Settings"));
|
||||
dlg->setWindowTitle(tr("Mana Distribution Settings"));
|
||||
dlg->setFromConfig(config);
|
||||
|
||||
connect(dlg, &QDialog::accepted, [this, dlg]() {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
#include "deck_list_model.h"
|
||||
#include "libcockatrice/card/card_info.h"
|
||||
#include <libcockatrice/card/essence_types.h>
|
||||
#include "libcockatrice/card/database/card_database_querier.h"
|
||||
#include "libcockatrice/deck_list/tree/deck_list_card_node.h"
|
||||
#include "libcockatrice/deck_list/tree/inner_deck_list_node.h"
|
||||
|
|
@ -128,39 +127,68 @@ void DeckListStatisticsAnalyzer::analyze()
|
|||
|
||||
QHash<QString, int> DeckListStatisticsAnalyzer::determineManaProduction(const QString &rulesText)
|
||||
{
|
||||
QHash<QString, int> result;
|
||||
for (const QChar code : Essence::symbols()) {
|
||||
result.insert(QString(code), 0);
|
||||
}
|
||||
QHash<QString, int> manaCounts = {{"W", 0}, {"U", 0}, {"B", 0}, {"R", 0}, {"G", 0}, {"C", 0}};
|
||||
|
||||
// Explicit Essence grants only. Inferring additional resources from MTG
|
||||
// tap/mana rules would invent Continuum Universes gameplay semantics.
|
||||
// E.g. "Add {M}" / "add {N}" both work.
|
||||
static const QRegularExpression grantedEssence(
|
||||
QStringLiteral(R"(\badd\s*\{([MSOGEAQCJBRLVTPN])\})"),
|
||||
QRegularExpression::CaseInsensitiveOption);
|
||||
QString text = rulesText.toLower(); // Normalize case for matching
|
||||
|
||||
auto matches = grantedEssence.globalMatch(rulesText);
|
||||
while (matches.hasNext()) {
|
||||
const QString code = matches.next().captured(1).toUpper();
|
||||
result[code]++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unordered_map<char, int> DeckListStatisticsAnalyzer::countManaSymbols(const QString &essenceCost)
|
||||
{
|
||||
std::unordered_map<char, int> result;
|
||||
for (const QChar code : Essence::symbols()) {
|
||||
result.emplace(code.toLatin1(), 0);
|
||||
}
|
||||
|
||||
for (const QString &token : Essence::parseCost(essenceCost)) {
|
||||
if (token.size() == 1 && Essence::isSymbol(token.at(0))) {
|
||||
result[token.at(0).toLatin1()]++;
|
||||
// Quick keyword-based checks for any color and colorless mana
|
||||
if (text.contains("{t}: add one mana of any color") || text.contains("add one mana of any color")) {
|
||||
for (const auto &color : {QStringLiteral("W"), QStringLiteral("U"), QStringLiteral("B"), QStringLiteral("R"),
|
||||
QStringLiteral("G")}) {
|
||||
manaCounts[color]++;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
if (text.contains("{t}: add {c}") || text.contains("add one colorless mana")) {
|
||||
manaCounts["C"]++;
|
||||
}
|
||||
|
||||
// Optimized regex for specific mana symbols
|
||||
static const QRegularExpression specificColorRegex(R"(\{T\}:\s*Add\s*\{([WUBRG])\})");
|
||||
QRegularExpressionMatch match = specificColorRegex.match(rulesText);
|
||||
if (match.hasMatch()) {
|
||||
manaCounts[match.captured(1)]++;
|
||||
}
|
||||
|
||||
return manaCounts;
|
||||
}
|
||||
|
||||
std::unordered_map<char, int> DeckListStatisticsAnalyzer::countManaSymbols(const QString &manaString)
|
||||
{
|
||||
std::unordered_map<char, int> manaCounts = {{'W', 0}, {'U', 0}, {'B', 0}, {'R', 0}, {'G', 0}};
|
||||
|
||||
int len = manaString.length();
|
||||
for (int i = 0; i < len; ++i) {
|
||||
if (manaString[i] == '{') {
|
||||
++i; // Move past '{'
|
||||
if (i < len && manaCounts.find(manaString[i].toLatin1()) != manaCounts.end()) {
|
||||
char mana1 = manaString[i].toLatin1();
|
||||
++i; // Move to next character
|
||||
if (i < len && manaString[i] == '/') {
|
||||
++i; // Move past '/'
|
||||
if (i < len && manaCounts.find(manaString[i].toLatin1()) != manaCounts.end()) {
|
||||
char mana2 = manaString[i].toLatin1();
|
||||
manaCounts[mana1]++;
|
||||
manaCounts[mana2]++;
|
||||
} else {
|
||||
// Handle cases like "{W/}" where second part is invalid
|
||||
manaCounts[mana1]++;
|
||||
}
|
||||
} else {
|
||||
manaCounts[mana1]++;
|
||||
}
|
||||
}
|
||||
// Ensure we always skip to the closing '}'
|
||||
while (i < len && manaString[i] != '}') {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
// Check if the character is a standalone mana symbol (not inside {})
|
||||
else if (manaCounts.find(manaString[i].toLatin1()) != manaCounts.end()) {
|
||||
manaCounts[manaString[i].toLatin1()]++;
|
||||
}
|
||||
}
|
||||
|
||||
return manaCounts;
|
||||
}
|
||||
|
||||
// Hypergeometric probability: P(X=k)
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ private:
|
|||
std::unordered_map<int, int> manaCurveMap;
|
||||
std::unordered_map<char, int> manaDevotionMap;
|
||||
|
||||
QHash<QString, int> devotionPipCount; // Counts for the fifteen Continuum Universes Essence codes
|
||||
QHash<QString, int> devotionPipCount; // W/U/B/R/G total symbols
|
||||
QHash<QString, int> devotionCardCount; // how many cards provide devotion
|
||||
|
||||
QHash<QString, int> productionPipCount; // mana produced by cards
|
||||
|
|
|
|||
|
|
@ -36,9 +36,9 @@
|
|||
|
||||
// Executable that, when it sits next to the downloaded update installer, is installed instead of
|
||||
// it. A packager shipping a custom build - or someone testing one - can drop the file there and
|
||||
// have Continuumatrice run it rather than the official installer, without the release channel having to
|
||||
// have Cockatrice run it rather than the official installer, without the release channel having to
|
||||
// host an installer for that build. It is a drop-in and is run with the same arguments.
|
||||
static const QString UPDATE_INSTALLER_OVERRIDE = "Continuumatrice-Update-Override.exe";
|
||||
static const QString UPDATE_INSTALLER_OVERRIDE = "Cockatrice-Update-Override.exe";
|
||||
|
||||
DlgUpdate::DlgUpdate(QWidget *parent) : QDialog(parent)
|
||||
{
|
||||
|
|
@ -87,7 +87,7 @@ DlgUpdate::DlgUpdate(QWidget *parent) : QDialog(parent)
|
|||
if (!QSslSocket::supportsSsl()) {
|
||||
enableUpdateButton(false);
|
||||
QMessageBox::critical(this, tr("Error"),
|
||||
tr("Continuumatrice was not built with SSL support, therefore you cannot download updates "
|
||||
tr("Cockatrice was not built with SSL support, therefore you cannot download updates "
|
||||
"automatically! \nPlease visit the download page to update manually."));
|
||||
}
|
||||
|
||||
|
|
@ -161,7 +161,7 @@ void DlgUpdate::finishedUpdateCheck(bool needToUpdate, bool isCompatible, Releas
|
|||
// downloader themselves if there's a compatible build
|
||||
QMessageBox::information(
|
||||
window(), tr("No Update Available"),
|
||||
tr("Continuumatrice is up to date!") + "<br><br>" +
|
||||
tr("Cockatrice is up to date!") + "<br><br>" +
|
||||
tr("You are already running the latest version available in the chosen release channel.") + "<br>" +
|
||||
"<b>" + tr("Current version") + QString(":</b> %1<br>").arg(VERSION_STRING) + "<b>" +
|
||||
tr("Selected release channel") +
|
||||
|
|
@ -171,7 +171,7 @@ void DlgUpdate::finishedUpdateCheck(bool needToUpdate, bool isCompatible, Releas
|
|||
|
||||
publishDate = release->getPublishDate().toString(QLocale().dateFormat(QLocale::LongFormat));
|
||||
if (isCompatible) {
|
||||
const QString message = tr("A new version of Continuumatrice is available!") + "<br><br>" + "<b>" +
|
||||
const QString message = tr("A new version of Cockatrice is available!") + "<br><br>" + "<b>" +
|
||||
tr("New version") + QString(":</b> %1<br>").arg(release->getName()) + "<b>" +
|
||||
tr("Released") +
|
||||
QString(":</b> %1 (<a href=\"%2\">").arg(publishDate, release->getDescriptionUrl()) +
|
||||
|
|
@ -185,7 +185,7 @@ void DlgUpdate::finishedUpdateCheck(bool needToUpdate, bool isCompatible, Releas
|
|||
} else {
|
||||
QMessageBox::information(
|
||||
window(), tr("Update Available"),
|
||||
tr("A new version of Continuumatrice is available!") + "<br><br>" + "<b>" + tr("New version") +
|
||||
tr("A new version of Cockatrice is available!") + "<br><br>" + "<b>" + tr("New version") +
|
||||
QString(":</b> %1<br>").arg(release->getName()) + "<b>" + tr("Released") +
|
||||
QString(":</b> %1 (<a href=\"%2\">").arg(publishDate, release->getDescriptionUrl()) + tr("Changelog") +
|
||||
"</a>)<br><br>" +
|
||||
|
|
@ -235,7 +235,7 @@ void DlgUpdate::warnInstallerIsWaiting()
|
|||
// would therefore swallow the installer's one and only request for the rest of its wait.
|
||||
auto *notification = new QMessageBox(QMessageBox::Warning, tr("Update"),
|
||||
tr("The update installer is already running and waits about a "
|
||||
"minute for Continuumatrice to close. Continuumatrice is still busy, so "
|
||||
"minute for Cockatrice to close. Cockatrice is still busy, so "
|
||||
"save your work and close it before then. Otherwise the "
|
||||
"installer gives up and the update is cancelled."),
|
||||
QMessageBox::Ok, parentWidget());
|
||||
|
|
@ -293,9 +293,9 @@ void DlgUpdate::downloadSuccessful(const QUrl &filepath)
|
|||
process.setArguments({"/R", QString("/D=%1").arg(appDir)});
|
||||
#endif
|
||||
|
||||
// Try to open the installer. If it opens, quit Continuumatrice
|
||||
// Try to open the installer. If it opens, quit Cockatrice
|
||||
if (process.startDetached()) {
|
||||
qCInfo(DlgUpdateLog) << "Opened update installer successfully - closing Continuumatrice";
|
||||
qCInfo(DlgUpdateLog) << "Opened update installer successfully - closing Cockatrice";
|
||||
// Close the main window synchronously so file locks are released before the NSIS installer
|
||||
// (already launched) starts replacing files. This also flushes settings and shuts down the
|
||||
// tabs, but only when the close is actually accepted: MainWindow may veto it for a running
|
||||
|
|
@ -324,8 +324,8 @@ void DlgUpdate::downloadSuccessful(const QUrl &filepath)
|
|||
} else {
|
||||
setLabel(tr("Error"));
|
||||
QMessageBox::critical(this, tr("Update Error"),
|
||||
tr("Continuumatrice is unable to open the installer.") + "<br><br>" +
|
||||
tr("Try to update manually by closing Continuumatrice and running the installer.") +
|
||||
tr("Cockatrice is unable to open the installer.") + "<br><br>" +
|
||||
tr("Try to update manually by closing Cockatrice and running the installer.") +
|
||||
"<br>" + tr("Download location") + QString(": %1").arg(filepath.toLocalFile()));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include "color_bar.h"
|
||||
|
||||
#include "../../../../../essence_chart_colors.h"
|
||||
#include "libcockatrice/utility/color.h"
|
||||
|
||||
#include <QBrush>
|
||||
#include <QLinearGradient>
|
||||
|
|
@ -19,14 +19,14 @@
|
|||
#include <utility>
|
||||
|
||||
ColorBar::ColorBar(const QMap<QString, int> &_colors, QWidget *parent)
|
||||
: QWidget(parent), colors(EssenceCharts::ordered(_colors))
|
||||
: QWidget(parent), colors(GameSpecificColors::MTG::sortManaMapWUBRGCFirst(_colors))
|
||||
{
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
void ColorBar::setColors(const QMap<QString, int> &_colors)
|
||||
{
|
||||
colors = EssenceCharts::ordered(_colors);
|
||||
colors = GameSpecificColors::MTG::sortManaMapWUBRGCFirst(_colors);
|
||||
update();
|
||||
}
|
||||
|
||||
|
|
@ -150,5 +150,19 @@ QString ColorBar::tooltipForPosition(int x) const
|
|||
|
||||
QColor ColorBar::colorFromName(const QString &name) const
|
||||
{
|
||||
return EssenceCharts::colorFor(name);
|
||||
}
|
||||
static QMap<QString, QColor> map = {
|
||||
{"R", QColor(220, 30, 30)}, {"G", QColor(40, 170, 40)}, {"U", QColor(40, 90, 200)},
|
||||
{"W", QColor(235, 235, 230)}, {"B", QColor(30, 30, 30)},
|
||||
};
|
||||
|
||||
if (map.contains(name)) {
|
||||
return map[name];
|
||||
}
|
||||
|
||||
QColor c(name);
|
||||
if (!c.isValid()) {
|
||||
c = Qt::gray;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#include "color_pie.h"
|
||||
|
||||
#include "../../../../../essence_chart_colors.h"
|
||||
#include "libcockatrice/utility/color.h"
|
||||
|
||||
#include <QBrush>
|
||||
#include <QFontMetrics>
|
||||
|
|
@ -20,14 +20,14 @@
|
|||
#include <utility>
|
||||
|
||||
ColorPie::ColorPie(const QMap<QString, int> &_colors, QWidget *parent)
|
||||
: QWidget(parent), colors(EssenceCharts::ordered(_colors))
|
||||
: QWidget(parent), colors(GameSpecificColors::MTG::sortManaMapWUBRGCFirst(_colors))
|
||||
{
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
void ColorPie::setColors(const QMap<QString, int> &_colors)
|
||||
{
|
||||
colors = EssenceCharts::ordered(_colors);
|
||||
colors = GameSpecificColors::MTG::sortManaMapWUBRGCFirst(_colors);
|
||||
update();
|
||||
}
|
||||
|
||||
|
|
@ -184,5 +184,19 @@ QString ColorPie::tooltipForPoint(const QPoint &pt) const
|
|||
|
||||
QColor ColorPie::colorFromName(const QString &name) const
|
||||
{
|
||||
return EssenceCharts::colorFor(name);
|
||||
}
|
||||
static QMap<QString, QColor> map = {
|
||||
{"R", QColor(220, 30, 30)}, {"G", QColor(40, 170, 40)}, {"U", QColor(40, 90, 200)},
|
||||
{"W", QColor(235, 235, 230)}, {"B", QColor(30, 30, 30)},
|
||||
};
|
||||
|
||||
if (map.contains(name)) {
|
||||
return map[name];
|
||||
}
|
||||
|
||||
QColor c(name);
|
||||
if (!c.isValid()) {
|
||||
c = Qt::gray;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
|
@ -213,7 +213,7 @@ void FirstRunWizard::changeEvent(QEvent *event)
|
|||
|
||||
void FirstRunWizard::retranslateUi()
|
||||
{
|
||||
setWindowTitle(tr("Welcome to Continuumatrice"));
|
||||
setWindowTitle(tr("Welcome to Cockatrice"));
|
||||
backButton->setText(tr("Back"));
|
||||
skipButton->setText(tr("Skip"));
|
||||
for (FirstRunWizardPage *page : std::as_const(pages)) {
|
||||
|
|
|
|||
|
|
@ -1511,7 +1511,7 @@ void TabSupervisor::processNotifyUserEvent(const Event_NotifyUser &event)
|
|||
QMessageBox::information(
|
||||
this, tr("Unknown Event"),
|
||||
tr("The server has sent you a message that your client does not understand.\nThis message might mean "
|
||||
"there is a new version of Continuumatrice available or this server is running a custom or pre-release "
|
||||
"there is a new version of Cockatrice available or this server is running a custom or pre-release "
|
||||
"version.\n\nTo update your client, go to Help -> Check for Updates."));
|
||||
break;
|
||||
case Event_NotifyUser::IDLEWARNING:
|
||||
|
|
|
|||
|
|
@ -1,44 +1,48 @@
|
|||
#include "visual_database_display_color_filter_widget.h"
|
||||
|
||||
#include "../cards/additional_info/essence_filter_picker.h"
|
||||
#include "../cards/additional_info/mana_symbol_widget.h"
|
||||
#include "filter_tree_model.h"
|
||||
#include "libcockatrice/filters/filter_card.h"
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QComboBox>
|
||||
#include <QDebug>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPersistentModelIndex>
|
||||
#include <QSharedPointer>
|
||||
#include <QSizePolicy>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
#include <libcockatrice/card/essence_types.h>
|
||||
#include <QtGlobal>
|
||||
#include <libcockatrice/filters/filter_tree.h>
|
||||
|
||||
/**
|
||||
* This widget provides a graphical control element for the CardFilter::Attr::AttrColor filters applied to the filter
|
||||
* model.
|
||||
* @param parent The Qt Widget that this widget will parent to
|
||||
* @param _filterModel The filter model that this widget will manipulate
|
||||
*/
|
||||
VisualDatabaseDisplayColorFilterWidget::VisualDatabaseDisplayColorFilterWidget(QWidget *parent,
|
||||
FilterTreeModel *_filterModel)
|
||||
: QWidget(parent), filterModel(_filterModel), layout(new QHBoxLayout(this))
|
||||
{
|
||||
setLayout(layout);
|
||||
layout->setSpacing(3);
|
||||
layout->setSpacing(5);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
// Share the same compact Essence selection UI as Visual Deck Storage.
|
||||
// A 15-icon horizontal row cannot fit the database filter toolbar.
|
||||
essencePicker = new EssenceFilterPicker(this);
|
||||
layout->addWidget(essencePicker);
|
||||
// FlowWidget measures THIS parent widget, not its nested button. Give it
|
||||
// an explicit size hint that cannot clip the picker.
|
||||
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
||||
setMinimumWidth(essencePicker->width());
|
||||
QString fullColorIdentity = "WUBRG";
|
||||
for (const QChar &color : fullColorIdentity) {
|
||||
auto *manaSymbol = new ManaSymbolWidget(this, color, false, true);
|
||||
manaSymbol->setFixedWidth(25);
|
||||
|
||||
connect(essencePicker, &EssenceFilterPicker::essenceToggled, this,
|
||||
&VisualDatabaseDisplayColorFilterWidget::handleColorToggled);
|
||||
layout->addWidget(manaSymbol);
|
||||
|
||||
connect(essencePicker, &EssenceFilterPicker::selectionCleared, this, [this]() {
|
||||
filterModel->clearFiltersOfType(CardFilter::Attr::AttrColor);
|
||||
});
|
||||
// Connect the color toggled signal
|
||||
connect(manaSymbol, &ManaSymbolWidget::colorToggled, this,
|
||||
&VisualDatabaseDisplayColorFilterWidget::handleColorToggled);
|
||||
}
|
||||
|
||||
modeComboBox = new QComboBox(this);
|
||||
essencePicker->addPopupControl(modeComboBox);
|
||||
layout->addWidget(modeComboBox);
|
||||
|
||||
connect(modeComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||
&VisualDatabaseDisplayColorFilterWidget::updateFilterMode);
|
||||
|
|
@ -46,83 +50,108 @@ VisualDatabaseDisplayColorFilterWidget::VisualDatabaseDisplayColorFilterWidget(Q
|
|||
connect(filterModel, &FilterTreeModel::layoutChanged, this,
|
||||
[this]() { syncDebouncer.call([this] { syncWithFilterModel(); }); });
|
||||
|
||||
// Call retranslateUi to set the initial text
|
||||
retranslateUi();
|
||||
syncWithFilterModel();
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayColorFilterWidget::retranslateUi()
|
||||
{
|
||||
essencePicker->retranslateUi();
|
||||
|
||||
modeComboBox->blockSignals(true);
|
||||
modeComboBox->clear();
|
||||
|
||||
modeComboBox->addItem(tr("Exact match"), QVariant::fromValue(FilterMode::ExactMatch));
|
||||
modeComboBox->addItem(tr("Includes"), QVariant::fromValue(FilterMode::Includes));
|
||||
modeComboBox->addItem(tr("Include / Exclude"), QVariant::fromValue(FilterMode::IncludeExclude));
|
||||
modeComboBox->setToolTip(tr("How selected and unselected Essence types are combined in the filter"));
|
||||
|
||||
modeComboBox->setToolTip(tr("How selected and unselected colors are combined in the filter"));
|
||||
|
||||
// Restore current mode
|
||||
const int index = modeComboBox->findData(QVariant::fromValue(currentMode));
|
||||
if (index >= 0) {
|
||||
modeComboBox->setCurrentIndex(index);
|
||||
}
|
||||
|
||||
modeComboBox->blockSignals(false);
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayColorFilterWidget::handleColorToggled(QChar essence, bool active)
|
||||
void VisualDatabaseDisplayColorFilterWidget::handleColorToggled(QChar color, bool active)
|
||||
{
|
||||
if (active) {
|
||||
addFilter(essence);
|
||||
addFilter(color);
|
||||
} else {
|
||||
removeFilter(essence);
|
||||
removeFilter(color);
|
||||
}
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayColorFilterWidget::addFilter(QChar essence)
|
||||
void VisualDatabaseDisplayColorFilterWidget::addFilter(QChar color)
|
||||
{
|
||||
QString essenceString(essence);
|
||||
const QList<const CardFilter *> filters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor);
|
||||
for (const CardFilter *filter : filters) {
|
||||
if (filter->term() == essenceString) {
|
||||
filterModel->removeFilter(filter);
|
||||
QString colorString = color;
|
||||
QString typeStr;
|
||||
|
||||
// Remove previous filters
|
||||
|
||||
QList<const CardFilter *> allColorFilters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor);
|
||||
QList<const CardFilter *> matchingFilters;
|
||||
|
||||
for (const CardFilter *filter : allColorFilters) {
|
||||
if (filter->term() == color) {
|
||||
matchingFilters.append(filter);
|
||||
}
|
||||
}
|
||||
|
||||
for (const CardFilter *filter : matchingFilters) {
|
||||
filterModel->removeFilter(filter);
|
||||
}
|
||||
|
||||
// Add actual filter
|
||||
|
||||
switch (currentMode) {
|
||||
case FilterMode::ExactMatch:
|
||||
filterModel->addFilter(
|
||||
new CardFilter(essenceString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrColor));
|
||||
filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeAnd, CardFilter::Attr::AttrColor));
|
||||
break;
|
||||
|
||||
case FilterMode::Includes:
|
||||
filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeOr, CardFilter::Attr::AttrColor));
|
||||
break;
|
||||
|
||||
case FilterMode::IncludeExclude:
|
||||
filterModel->addFilter(
|
||||
new CardFilter(essenceString, CardFilter::Type::TypeOr, CardFilter::Attr::AttrColor));
|
||||
filterModel->addFilter(new CardFilter(colorString, CardFilter::Type::TypeOr, CardFilter::Attr::AttrColor));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayColorFilterWidget::removeFilter(QChar essence)
|
||||
void VisualDatabaseDisplayColorFilterWidget::removeFilter(QChar color)
|
||||
{
|
||||
QString essenceString(essence);
|
||||
const QList<const CardFilter *> filters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor);
|
||||
for (const CardFilter *filter : filters) {
|
||||
if (filter->term() == essenceString) {
|
||||
filterModel->removeFilter(filter);
|
||||
QString colorString = color;
|
||||
|
||||
// Remove inclusion filters
|
||||
QList<const CardFilter *> allColorFilters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor);
|
||||
QList<const CardFilter *> matchingFilters;
|
||||
|
||||
for (const CardFilter *filter : allColorFilters) {
|
||||
if (filter->term() == color) {
|
||||
matchingFilters.append(filter);
|
||||
}
|
||||
}
|
||||
|
||||
// The empty selection means "Any Essence", not "exclude everything".
|
||||
if (essencePicker->activeEssences().isEmpty()) {
|
||||
filterModel->clearFiltersOfType(CardFilter::Attr::AttrColor);
|
||||
return;
|
||||
for (const CardFilter *filter : matchingFilters) {
|
||||
filterModel->removeFilter(filter);
|
||||
}
|
||||
|
||||
// Add exclusion filters if the mode demands it
|
||||
switch (currentMode) {
|
||||
case FilterMode::ExactMatch:
|
||||
filterModel->addFilter(
|
||||
new CardFilter(colorString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColor));
|
||||
break;
|
||||
|
||||
case FilterMode::IncludeExclude:
|
||||
filterModel->addFilter(
|
||||
new CardFilter(essenceString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColor));
|
||||
new CardFilter(colorString, CardFilter::Type::TypeAndNot, CardFilter::Attr::AttrColor));
|
||||
break;
|
||||
|
||||
case FilterMode::Includes:
|
||||
// No exclusion in Includes mode
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -141,12 +170,10 @@ void VisualDatabaseDisplayColorFilterWidget::updateFilterMode()
|
|||
|
||||
filterModel->clearFiltersOfType(CardFilter::Attr::AttrColor);
|
||||
|
||||
const QSet<QChar> selected = essencePicker->activeEssences();
|
||||
// No selections should never generate 15 mutually excluding filters.
|
||||
if (!selected.isEmpty()) {
|
||||
for (const QChar essence : Essence::symbols()) {
|
||||
handleColorToggled(essence, selected.contains(essence));
|
||||
}
|
||||
const QList<ManaSymbolWidget *> manaSymbolWidgets = findChildren<ManaSymbolWidget *>();
|
||||
|
||||
for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) {
|
||||
handleColorToggled(manaSymbolWidget->getSymbolChar(), manaSymbolWidget->isColorActive());
|
||||
}
|
||||
|
||||
filterModel->blockSignals(false);
|
||||
|
|
@ -157,44 +184,79 @@ void VisualDatabaseDisplayColorFilterWidget::updateFilterMode()
|
|||
emit filterModeChanged(currentMode);
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayColorFilterWidget::setEssenceActive(QChar essence, bool active)
|
||||
void VisualDatabaseDisplayColorFilterWidget::setManaSymbolActive(QChar color, bool active)
|
||||
{
|
||||
essencePicker->setEssenceActive(essence, active);
|
||||
QList<ManaSymbolWidget *> manaSymbolWidgets = findChildren<ManaSymbolWidget *>();
|
||||
|
||||
for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) {
|
||||
if (manaSymbolWidget->getSymbolChar() == color) {
|
||||
manaSymbolWidget->setColorActive(active);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QList<QChar> VisualDatabaseDisplayColorFilterWidget::getActiveColors()
|
||||
{
|
||||
QList<QChar> result;
|
||||
const QSet<QChar> selected = essencePicker->activeEssences();
|
||||
for (const QChar essence : Essence::symbols()) {
|
||||
if (selected.contains(essence)) {
|
||||
result.append(essence);
|
||||
QList<QChar> activeColors;
|
||||
QList<ManaSymbolWidget *> manaSymbolWidgets = findChildren<ManaSymbolWidget *>();
|
||||
|
||||
for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) {
|
||||
if (manaSymbolWidget->isColorActive()) {
|
||||
activeColors.append(manaSymbolWidget->getSymbolChar());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
return activeColors;
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayColorFilterWidget::syncWithFilterModel()
|
||||
{
|
||||
const QList<const CardFilter *> filters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor);
|
||||
QList<const CardFilter *> allColorFilters = filterModel->getFiltersOfType(CardFilter::Attr::AttrColor);
|
||||
|
||||
for (const QChar essence : Essence::symbols()) {
|
||||
bool selected = false;
|
||||
for (const CardFilter *filter : filters) {
|
||||
if (filter->term() != QString(essence)) {
|
||||
continue;
|
||||
}
|
||||
if (currentMode == FilterMode::ExactMatch) {
|
||||
selected = filter->type() == CardFilter::Type::TypeAnd;
|
||||
} else {
|
||||
selected = filter->type() == CardFilter::Type::TypeOr;
|
||||
}
|
||||
if (selected) {
|
||||
break;
|
||||
QList<ManaSymbolWidget *> manaSymbolWidgets = findChildren<ManaSymbolWidget *>();
|
||||
|
||||
for (ManaSymbolWidget *manaSymbolWidget : manaSymbolWidgets) {
|
||||
bool found = false;
|
||||
for (const CardFilter *filter : allColorFilters) {
|
||||
if (manaSymbolWidget->getSymbolChar() == filter->term()) {
|
||||
switch (currentMode) {
|
||||
case FilterMode::ExactMatch:
|
||||
switch (filter->type()) {
|
||||
case CardFilter::Type::TypeAnd:
|
||||
setManaSymbolActive(filter->term().at(0), true);
|
||||
break;
|
||||
default:
|
||||
setManaSymbolActive(filter->term().at(0), false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FilterMode::Includes:
|
||||
switch (filter->type()) {
|
||||
case CardFilter::Type::TypeOr:
|
||||
setManaSymbolActive(filter->term().at(0), true);
|
||||
break;
|
||||
default:
|
||||
setManaSymbolActive(filter->term().at(0), false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FilterMode::IncludeExclude:
|
||||
switch (filter->type()) {
|
||||
case CardFilter::Type::TypeOr:
|
||||
setManaSymbolActive(filter->term().at(0), true);
|
||||
break;
|
||||
default:
|
||||
setManaSymbolActive(filter->term().at(0), false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
// Signals are blocked inside the picker; loading saved filters must
|
||||
// not mutate the FilterTreeModel again.
|
||||
setEssenceActive(essence, selected);
|
||||
|
||||
if (!found) {
|
||||
setManaSymbolActive(manaSymbolWidget->getSymbolChar(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
class FilterTreeModel;
|
||||
class QComboBox;
|
||||
class QHBoxLayout;
|
||||
class EssenceFilterPicker;
|
||||
|
||||
class VisualDatabaseDisplayColorFilterCircleWidget : public QWidget
|
||||
{
|
||||
|
|
@ -64,7 +63,7 @@ private slots:
|
|||
void addFilter(QChar color);
|
||||
void removeFilter(QChar color);
|
||||
void updateFilterMode();
|
||||
void setEssenceActive(QChar essence, bool active);
|
||||
void setManaSymbolActive(QChar color, bool active);
|
||||
QList<QChar> getActiveColors();
|
||||
void syncWithFilterModel();
|
||||
|
||||
|
|
@ -72,7 +71,6 @@ private:
|
|||
FilterTreeModel *filterModel;
|
||||
QHBoxLayout *layout;
|
||||
QComboBox *modeComboBox;
|
||||
EssenceFilterPicker *essencePicker = nullptr;
|
||||
FilterMode currentMode = FilterMode::Includes; // Default mode
|
||||
QtUtils::Debouncer syncDebouncer{100};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
#include "deck_preview_color_identity_filter_widget.h"
|
||||
|
||||
#include "../../cards/additional_info/essence_filter_picker.h"
|
||||
#include "../../cards/additional_info/mana_symbol_widget.h"
|
||||
#include "../visual_deck_storage_sort_filter_proxy_model.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QSizePolicy>
|
||||
#include <QSet>
|
||||
#include <QSharedPointer>
|
||||
#include <QString>
|
||||
|
||||
DeckPreviewColorIdentityFilterWidget::DeckPreviewColorIdentityFilterWidget(QWidget *parent)
|
||||
|
|
@ -16,30 +16,34 @@ DeckPreviewColorIdentityFilterWidget::DeckPreviewColorIdentityFilterWidget(QWidg
|
|||
layout->setSpacing(5);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
// Fifteen Essence codes don't fit as inline buttons beside sorting and
|
||||
// search. The popup keeps all codes selectable without expanding the row.
|
||||
essencePicker = new EssenceFilterPicker(this);
|
||||
layout->addWidget(essencePicker);
|
||||
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
||||
setMinimumWidth(essencePicker->width());
|
||||
QString fullColorIdentity = "WUBRG";
|
||||
for (const QChar &color : fullColorIdentity) {
|
||||
auto *manaSymbol = new ManaSymbolWidget(this, color, false, true);
|
||||
manaSymbol->setFixedWidth(25);
|
||||
|
||||
connect(essencePicker, &EssenceFilterPicker::essenceToggled, this,
|
||||
[this](QChar /*essence*/, bool /*active*/) { emit activeColorsChanged(); });
|
||||
connect(essencePicker, &EssenceFilterPicker::selectionCleared, this,
|
||||
[this]() { emit activeColorsChanged(); });
|
||||
layout->addWidget(manaSymbol);
|
||||
|
||||
// Initialize the activeColors map
|
||||
activeColors[color] = false;
|
||||
|
||||
// Connect the color toggled signal
|
||||
connect(manaSymbol, &ManaSymbolWidget::colorToggled, this,
|
||||
&DeckPreviewColorIdentityFilterWidget::handleColorToggled);
|
||||
}
|
||||
|
||||
toggleButton = new QPushButton(this);
|
||||
essencePicker->addPopupControl(toggleButton);
|
||||
layout->addWidget(toggleButton);
|
||||
|
||||
// Connect the button's clicked signal
|
||||
connect(toggleButton, &QPushButton::clicked, this, &DeckPreviewColorIdentityFilterWidget::updateFilterMode);
|
||||
|
||||
// Call retranslateUi to set the initial text
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void DeckPreviewColorIdentityFilterWidget::retranslateUi()
|
||||
{
|
||||
essencePicker->retranslateUi();
|
||||
|
||||
// Preserve existing Exact / Includes / Excludes filter semantics.
|
||||
// Set the toggle button text based on the current mode
|
||||
switch (filterMode) {
|
||||
case VisualDeckStorageSortFilterProxyModel::FilterMode::ExactMatch:
|
||||
toggleButton->setText(tr("Mode: Exact Match"));
|
||||
|
|
@ -51,21 +55,32 @@ void DeckPreviewColorIdentityFilterWidget::retranslateUi()
|
|||
toggleButton->setText(tr("Mode: Excludes"));
|
||||
break;
|
||||
}
|
||||
toggleButton->setToolTip(tr("Essence filter mode (exact match, includes, or excludes)"));
|
||||
toggleButton->setToolTip(tr("Color identity filter mode (AND/OR/NOT conjunctions of filters)"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The colors that are currently toggled on.
|
||||
*/
|
||||
QSet<QChar> DeckPreviewColorIdentityFilterWidget::getActiveColors() const
|
||||
{
|
||||
return essencePicker->activeEssences();
|
||||
QSet<QChar> activeColorSet;
|
||||
for (auto it = activeColors.constBegin(); it != activeColors.constEnd(); ++it) {
|
||||
if (it.value()) {
|
||||
activeColorSet.insert(it.key());
|
||||
}
|
||||
}
|
||||
return activeColorSet;
|
||||
}
|
||||
|
||||
void DeckPreviewColorIdentityFilterWidget::handleColorToggled(QChar /*essence*/, bool /*active*/)
|
||||
void DeckPreviewColorIdentityFilterWidget::handleColorToggled(QChar color, bool active)
|
||||
{
|
||||
activeColors[color] = active;
|
||||
emit activeColorsChanged();
|
||||
}
|
||||
|
||||
void DeckPreviewColorIdentityFilterWidget::updateFilterMode()
|
||||
{
|
||||
// Cycle through the modes
|
||||
switch (filterMode) {
|
||||
case VisualDeckStorageSortFilterProxyModel::FilterMode::ExactMatch:
|
||||
filterMode = VisualDeckStorageSortFilterProxyModel::FilterMode::Includes;
|
||||
|
|
@ -78,6 +93,6 @@ void DeckPreviewColorIdentityFilterWidget::updateFilterMode()
|
|||
break;
|
||||
}
|
||||
|
||||
retranslateUi();
|
||||
retranslateUi(); // Update the button text
|
||||
emit filterModeChanged(filterMode);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@
|
|||
#include "../visual_deck_storage_sort_filter_proxy_model.h"
|
||||
|
||||
#include <QChar>
|
||||
#include <QMap>
|
||||
#include <QSet>
|
||||
#include <QWidget>
|
||||
#include <qtmetamacros.h>
|
||||
|
||||
class QHBoxLayout;
|
||||
class QPushButton;
|
||||
class EssenceFilterPicker;
|
||||
|
||||
class DeckPreviewColorIdentityFilterWidget : public QWidget
|
||||
{
|
||||
|
|
@ -57,7 +57,7 @@ private slots:
|
|||
private:
|
||||
QHBoxLayout *layout;
|
||||
QPushButton *toggleButton;
|
||||
EssenceFilterPicker *essencePicker = nullptr;
|
||||
QMap<QChar, bool> activeColors;
|
||||
VisualDeckStorageSortFilterProxyModel::FilterMode filterMode = VisualDeckStorageSortFilterProxyModel::Includes;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -120,17 +120,17 @@
|
|||
|
||||
class LocalServerInterface;
|
||||
|
||||
#define GITHUB_PAGES_URL "https://github.com/Continuum-Universes-Studio/Continuumatrice"
|
||||
#define GITHUB_PAGES_URL "https://cockatrice.github.io"
|
||||
#define GITHUB_CONTRIBUTORS_URL "https://github.com/Cockatrice/Cockatrice/graphs/contributors"
|
||||
#define GITHUB_CONTRIBUTE_URL "https://github.com/Cockatrice/Cockatrice#"
|
||||
#define GITHUB_TRANSIFEX_TRANSLATORS_URL "https://github.com/Cockatrice/Cockatrice/wiki/Translator-Hall-of-Fame"
|
||||
#define GITHUB_TRANSLATOR_FAQ_URL "https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ"
|
||||
#define GITHUB_ISSUES_URL "https://github.com/Continuum-Universes-Studio/Continuumatrice/issues"
|
||||
#define GITHUB_ISSUES_URL "https://github.com/Cockatrice/Cockatrice/issues"
|
||||
#define GITHUB_TROUBLESHOOTING_URL "https://github.com/Cockatrice/Cockatrice/wiki/Troubleshooting"
|
||||
#define GITHUB_FAQ_URL "https://github.com/Cockatrice/Cockatrice/wiki/Frequently-Asked-Questions"
|
||||
|
||||
const QString MainWindow::appName = "Continuumatrice";
|
||||
const QStringList MainWindow::fileNameFilters = QStringList() << QObject::tr("Continuumatrice card database (*.xml)")
|
||||
const QString MainWindow::appName = "Cockatrice";
|
||||
const QStringList MainWindow::fileNameFilters = QStringList() << QObject::tr("Cockatrice card database (*.xml)")
|
||||
<< QObject::tr("All files (*.*)");
|
||||
inline Q_LOGGING_CATEGORY(MainWindowLog, "main_window");
|
||||
|
||||
|
|
@ -231,7 +231,7 @@ void MainWindow::actWatchReplay()
|
|||
{
|
||||
QFileDialog dlg(this, tr("Load replay"));
|
||||
dlg.setDirectory(SettingsCache::instance().paths().getReplaysPath());
|
||||
dlg.setNameFilters(QStringList() << QObject::tr("Continuumatrice replays (*.cor)"));
|
||||
dlg.setNameFilters(QStringList() << QObject::tr("Cockatrice replays (*.cor)"));
|
||||
if (!dlg.exec()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -292,24 +292,27 @@ void MainWindow::actExit()
|
|||
void MainWindow::actAbout()
|
||||
{
|
||||
QMessageBox mb(
|
||||
QMessageBox::NoIcon, tr("About Continuumatrice"),
|
||||
QStringLiteral("<font size=\"8\"><b>Continuumatrice</b></font><br>") +
|
||||
tr("Continuum Universes Studio") + QStringLiteral(" — ") + tr("Version") +
|
||||
QStringLiteral(" ") + QString(VERSION_STRING) +
|
||||
QStringLiteral("<br><br>") +
|
||||
tr("Continuumatrice is a standalone Continuum Universes card-game client.") +
|
||||
QStringLiteral("<br><a href='https://github.com/Continuum-Universes-Studio/Continuumatrice'>") +
|
||||
tr("Source code and issues") + QStringLiteral("</a><br><br>") +
|
||||
tr("Based on the open-source Cockatrice project. The original developers and contributors "
|
||||
"retain credit for their work, and the applicable open-source license remains in force.") +
|
||||
QStringLiteral("<br><a href='https://github.com/Cockatrice/Cockatrice'>") +
|
||||
tr("Upstream Cockatrice project") + QStringLiteral("</a>"),
|
||||
QMessageBox::NoIcon, tr("About Cockatrice"),
|
||||
QString("<font size=\"8\"><b>Cockatrice</b></font> (" + QString::fromStdString(BUILD_ARCHITECTURE) + ")<br>" +
|
||||
tr("Version") + QString(" %1").arg(VERSION_STRING) + "<br><br><b><a href='" + GITHUB_PAGES_URL + "'>" +
|
||||
tr("Cockatrice Webpage") + "</a></b><br>" + "<br><b>" + tr("Project Manager:") +
|
||||
"</b><br>Zach Halpern<br><br>" + "<b>" + tr("Past Project Managers:") +
|
||||
"</b><br>Gavin Bisesi<br>Max-Wilhelm Bruker<br>Marcus Schütz<br><br>" + "<b>" + tr("Developers:") +
|
||||
"</b><br>" + "<a href='" + GITHUB_CONTRIBUTORS_URL + "'>" + tr("Our Developers") + "</a><br>" +
|
||||
"<a href='" + GITHUB_CONTRIBUTE_URL + "'>" + tr("Help Develop!") + "</a><br><br>" + "<b>" +
|
||||
tr("Translators:") + "</b><br>" + "<a href='" + GITHUB_TRANSIFEX_TRANSLATORS_URL + "'>" +
|
||||
tr("Our Translators") + "</a><br>" + "<a href='" + GITHUB_TRANSLATOR_FAQ_URL + "'>" +
|
||||
tr("Help Translate!") + "</a><br><br>" + "<b>" + tr("Support:") + "</b><br>" + "<a href='" +
|
||||
GITHUB_ISSUES_URL + "'>" + tr("Report an Issue") + "</a><br>" + "<a href='" +
|
||||
GITHUB_TROUBLESHOOTING_URL + "'>" + tr("Troubleshooting") + "</a><br>" + "<a href='" + GITHUB_FAQ_URL +
|
||||
"'>" + tr("F.A.Q.") + "</a><br>"),
|
||||
QMessageBox::Ok, this);
|
||||
mb.setIconPixmap(
|
||||
themePixmap(QStringLiteral("continuumatrice")).scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
themePixmap(QStringLiteral("cockatrice")).scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
mb.setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
mb.exec();
|
||||
}
|
||||
|
||||
void MainWindow::actTips()
|
||||
{
|
||||
if (tip != nullptr) {
|
||||
|
|
@ -366,7 +369,7 @@ void MainWindow::retranslateUi()
|
|||
#if defined(__APPLE__) /* For OSX */
|
||||
cockatriceMenu->setTitle(tr("A&ctions"));
|
||||
#else
|
||||
cockatriceMenu->setTitle(tr("&Continuumatrice"));
|
||||
cockatriceMenu->setTitle(tr("&Cockatrice"));
|
||||
#endif
|
||||
|
||||
dbMenu->setTitle(tr("C&ard Database"));
|
||||
|
|
@ -380,13 +383,11 @@ void MainWindow::retranslateUi()
|
|||
tabsMenu->setTitle(tr("Tabs"));
|
||||
|
||||
helpMenu->setTitle(tr("&Help"));
|
||||
aAbout->setText(tr("&About Continuumatrice"));
|
||||
aAbout->setText(tr("&About Cockatrice"));
|
||||
aTips->setText(tr("&Tip of the Day"));
|
||||
aUpdate->setText(tr("Check for Client Updates"));
|
||||
aCheckCardUpdates->setText(tr("Legacy MTG Oracle importer (disabled)"));
|
||||
aCheckCardUpdates->setEnabled(false);
|
||||
aCheckCardUpdatesBackground->setText(tr("Automatic MTG card updates (disabled)"));
|
||||
aCheckCardUpdatesBackground->setEnabled(false);
|
||||
aCheckCardUpdates->setText(tr("Check for Card Updates..."));
|
||||
aCheckCardUpdatesBackground->setText(tr("Check for Card Updates (Automatic)"));
|
||||
aStatusBar->setText(tr("Show Status Bar"));
|
||||
aViewLog->setText(tr("View &Debug Log"));
|
||||
aOpenSettingsFolder->setText(tr("Open Settings Folder"));
|
||||
|
|
@ -650,23 +651,20 @@ void MainWindow::startupConfigCheck()
|
|||
startLocalGame(options);
|
||||
}
|
||||
|
||||
// The fork has independent release channels. Until a Continuumatrice
|
||||
// release is published, do not auto-check or run upstream Cockatrice updates.
|
||||
SettingsCache::instance().updates().setCheckUpdatesOnStartup(false);
|
||||
if (SettingsCache::instance().updates().getCheckUpdatesOnStartup()) {
|
||||
actCheckClientUpdates();
|
||||
}
|
||||
|
||||
actCheckCommanderBracketDefinitionUpdates();
|
||||
|
||||
// No MTG Commander-bracket network requests in Continuumatrice.
|
||||
if (isCleanInstall) {
|
||||
// no config found, 99% new clean install
|
||||
qCInfo(WindowMainStartupVersionLog)
|
||||
<< "Startup: old client version empty, assuming first start after clean install";
|
||||
SettingsCache::instance().downloads().resetToDefaultURLs(); // Empty in Continuumatrice: no MTG providers
|
||||
SettingsCache::instance().downloads().resetToDefaultURLs(); // populate the download urls
|
||||
SettingsCache::instance().network().setClientVersion(VERSION_STRING);
|
||||
// No upstream Cockatrice first-run wizard, Magic importer, or default
|
||||
// server discovery. Cards are loaded from this application's own XML.
|
||||
QMessageBox::information(this, tr("Welcome to Continuumatrice"),
|
||||
tr("Continuumatrice uses its own card database. "
|
||||
"Add your card XML files using Card Database > Add custom sets/cards "
|
||||
"or place them in the Continuumatrice customsets directory."));
|
||||
actCheckServerUpdates();
|
||||
runFirstRunWizard(true);
|
||||
|
||||
if (QString(VERSION_STRING).contains("custom", Qt::CaseInsensitive)) {
|
||||
SettingsCache::instance().updates().setCheckUpdatesOnStartup(false);
|
||||
|
|
@ -679,7 +677,7 @@ void MainWindow::startupConfigCheck()
|
|||
<< "Startup: old client version" << SettingsCache::instance().network().getClientVersion()
|
||||
<< "differs, assuming first start after update";
|
||||
if (SettingsCache::instance().updates().getNotifyAboutNewVersion()) {
|
||||
// Do not automatically launch the upstream Magic-card Oracle importer.
|
||||
alertForcedOracleRun(VERSION_STRING, true);
|
||||
}
|
||||
|
||||
qCInfo(WindowMainStartupShortcutsLog) << "Migrating shortcuts after update detected.";
|
||||
|
|
@ -706,8 +704,35 @@ void MainWindow::startupConfigCheck()
|
|||
// previous config from this version found
|
||||
qCInfo(WindowMainStartupVersionLog) << "Startup: found config with current version";
|
||||
|
||||
// No automatic upstream card database downloads in Continuumatrice.
|
||||
if (SettingsCache::instance().updates().getCardUpdateCheckRequired()) {
|
||||
if (SettingsCache::instance().updates().getStartupCardUpdateCheckPromptForUpdate()) {
|
||||
auto startupCardCheckDialog = new DlgStartupCardCheck(this);
|
||||
|
||||
if (startupCardCheckDialog->exec() == QDialog::Accepted) {
|
||||
switch (startupCardCheckDialog->group->checkedId()) {
|
||||
case 0: // foreground
|
||||
actCheckCardUpdates();
|
||||
break;
|
||||
case 1: // background
|
||||
actCheckCardUpdatesBackground();
|
||||
break;
|
||||
case 2: // background + always
|
||||
SettingsCache::instance().updates().setStartupCardUpdateCheckPromptForUpdate(false);
|
||||
SettingsCache::instance().updates().setStartupCardUpdateCheckAlwaysUpdate(true);
|
||||
actCheckCardUpdatesBackground();
|
||||
break;
|
||||
case 3: // don't prompt again + don't run
|
||||
SettingsCache::instance().updates().setStartupCardUpdateCheckPromptForUpdate(false);
|
||||
SettingsCache::instance().updates().setStartupCardUpdateCheckAlwaysUpdate(false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (SettingsCache::instance().updates().getStartupCardUpdateCheckAlwaysUpdate()) {
|
||||
actCheckCardUpdatesBackground();
|
||||
}
|
||||
}
|
||||
|
||||
// Run the tips dialog only on subsequent startups.
|
||||
// On the first run after an install/update the startup is already crowded enough
|
||||
|
|
@ -835,12 +860,12 @@ void MainWindow::alertForcedOracleRun(const QString &version, bool isUpdate)
|
|||
{
|
||||
if (isUpdate) {
|
||||
QMessageBox::information(this, tr("New Version"),
|
||||
tr("Congratulations on updating to Continuumatrice %1!\n"
|
||||
tr("Congratulations on updating to Cockatrice %1!\n"
|
||||
"Oracle will now launch to update your card database.")
|
||||
.arg(version));
|
||||
} else {
|
||||
QMessageBox::information(this, tr("Continuumatrice installed"),
|
||||
tr("Congratulations on installing Continuumatrice %1!\n"
|
||||
QMessageBox::information(this, tr("Cockatrice installed"),
|
||||
tr("Congratulations on installing Cockatrice %1!\n"
|
||||
"Oracle will now launch to install the initial card database.")
|
||||
.arg(version));
|
||||
}
|
||||
|
|
@ -1085,7 +1110,7 @@ void MainWindow::cardDatabaseLoadingFailed()
|
|||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle(tr("Card database"));
|
||||
msgBox.setIcon(QMessageBox::Question);
|
||||
msgBox.setText(tr("Continuumatrice is unable to load the card database.\n"
|
||||
msgBox.setText(tr("Cockatrice is unable to load the card database.\n"
|
||||
"Do you want to update your card database now?\n"
|
||||
"If unsure or first time user, choose \"Yes\""));
|
||||
|
||||
|
|
@ -1168,7 +1193,7 @@ void MainWindow::cardDatabaseAllNewSetsEnabled()
|
|||
}
|
||||
QMessageBox::information(
|
||||
this, tr("Welcome"),
|
||||
tr("This is the first time you've loaded this card database in Continuumatrice.\nAll the sets in the "
|
||||
tr("Hi! It seems like you're running this version of Cockatrice for the first time.\nAll the sets in the "
|
||||
"card "
|
||||
"database have been enabled.\nRead more about changing the set order or disabling specific sets and "
|
||||
"consequent effects in the \"Manage Sets\" dialog."));
|
||||
|
|
@ -1182,28 +1207,16 @@ void MainWindow::cardDatabaseAllNewSetsEnabled()
|
|||
/* CARD UPDATER */
|
||||
void MainWindow::actCheckCardUpdates()
|
||||
{
|
||||
QMessageBox::information(this, tr("Continuumatrice card data"),
|
||||
tr("The upstream Oracle importer downloads Magic card data and is disabled "
|
||||
"in Continuumatrice. Import Continuum Universes XML cards using "
|
||||
"Card Database > Add custom sets/cards instead."));
|
||||
createCardUpdateProcess();
|
||||
}
|
||||
|
||||
void MainWindow::actCheckCardUpdatesBackground()
|
||||
{
|
||||
// Never run the upstream Oracle MTG importer unattended.
|
||||
qCInfo(CardDatabaseUpdateLog) << "The legacy Magic Oracle importer is disabled in Continuumatrice";
|
||||
createCardUpdateProcess(true);
|
||||
}
|
||||
|
||||
void MainWindow::createCardUpdateProcess(bool background)
|
||||
{
|
||||
Q_UNUSED(background);
|
||||
// Direct callers must also be unable to launch the upstream MTG importer.
|
||||
QMessageBox::information(this, tr("Importer unavailable"),
|
||||
tr("Continuumatrice does not run the upstream Magic Oracle importer. "
|
||||
"Import Continuum Universes XML sets directly."));
|
||||
return;
|
||||
|
||||
// Legacy importer implementation retained for upstream reference only.
|
||||
if (cardUpdateProcess) {
|
||||
qCDebug(CardDatabaseUpdateLog) << "A card database update is already running; asking it to come to the front";
|
||||
if (requestCardUpdateRaise()) {
|
||||
|
|
@ -1296,7 +1309,7 @@ void MainWindow::createCardUpdateProcess(bool background)
|
|||
statusBar()->showMessage(tr("Card database update running."));
|
||||
if (trayIcon && SettingsCache::instance().updates().getCardDatabaseUpdateTrayNotification()) {
|
||||
trayIcon->showMessage(tr("Card database update started"),
|
||||
tr("Continuumatrice is updating the card database in the background."));
|
||||
tr("Cockatrice is updating the card database in the background."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1438,7 +1451,7 @@ void MainWindow::cardUpdateFinished(int exitCode, QProcess::ExitStatus exitStatu
|
|||
|
||||
bool MainWindow::requestCardUpdateRaise()
|
||||
{
|
||||
const QString serverName = scopedLocalServerName(QStringLiteral("ContinuumatriceOracleRaise"));
|
||||
const QString serverName = scopedLocalServerName(QStringLiteral("CockatriceOracleRaise"));
|
||||
QLocalSocket socket;
|
||||
socket.connectToServer(serverName);
|
||||
if (!socket.waitForConnected(250)) {
|
||||
|
|
@ -1456,7 +1469,7 @@ void MainWindow::announceCardUpdateRunning()
|
|||
statusBar()->showMessage(tr("Card database update running."));
|
||||
} else if (trayIcon && SettingsCache::instance().updates().getCardDatabaseUpdateTrayNotification()) {
|
||||
trayIcon->showMessage(tr("Card database update running"),
|
||||
tr("Continuumatrice is updating the card database in the background."));
|
||||
tr("Cockatrice is updating the card database in the background."));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1472,8 +1485,9 @@ void MainWindow::notifyCardUpdateFinishedFromTray(bool success)
|
|||
|
||||
void MainWindow::actCheckServerUpdates()
|
||||
{
|
||||
// Upstream Cockatrice public servers are not Continuumatrice game servers.
|
||||
qCInfo(MainWindowLog) << "Upstream public server discovery disabled in Continuumatrice.";
|
||||
auto hps = new HandlePublicServers(this);
|
||||
hps->downloadPublicServers();
|
||||
connect(hps, &HandlePublicServers::sigPublicServersDownloadedSuccessfully, [=]() { hps->deleteLater(); });
|
||||
}
|
||||
|
||||
void MainWindow::actCheckClientUpdates()
|
||||
|
|
@ -1493,8 +1507,12 @@ void MainWindow::checkClientUpdatesFinished(bool needToUpdate, bool /* isCompati
|
|||
|
||||
void MainWindow::actCheckCommanderBracketDefinitionUpdates()
|
||||
{
|
||||
// Commander brackets are a Magic: The Gathering system, not Continuum Universes.
|
||||
qCInfo(MainWindowLog) << "Upstream Commander bracket updates disabled in Continuumatrice.";
|
||||
auto *handler = new HandleCommanderBrackets(this);
|
||||
|
||||
connect(handler, &HandleCommanderBrackets::sigBracketDefinitionsDownloaded, this,
|
||||
[]() { qDebug() << "Bracket definitions loaded"; });
|
||||
|
||||
handler->downloadBracketDefinitions();
|
||||
}
|
||||
|
||||
void MainWindow::refreshShortcuts()
|
||||
|
|
|
|||
|
|
@ -224,11 +224,11 @@ public:
|
|||
explicit MainWindow(QWidget *parent = nullptr);
|
||||
void setConnectTo(QString url)
|
||||
{
|
||||
connectTo = QUrl(QString("continuumatrice://%1").arg(url));
|
||||
connectTo = QUrl(QString("cockatrice://%1").arg(url));
|
||||
}
|
||||
// When set, the window's own startup connection (--connect or auto-connect
|
||||
// on first activation) is skipped. Used for activation launches: the intent
|
||||
// chain triggered by a continuumatrice:// URL owns the connection, and letting
|
||||
// chain triggered by a cockatrice:// URL owns the connection, and letting
|
||||
// auto-connect race against it caused two connectToServer calls to tear
|
||||
// each other down. onUrlChainFinished() clears this and retries the startup
|
||||
// connection when the link's chain ended without connecting.
|
||||
|
|
|
|||
|
|
@ -69,7 +69,6 @@
|
|||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
#include <libcockatrice/rng/rng_sfmt.h>
|
||||
#include <libcockatrice/settings/card_database_settings.h>
|
||||
#include <libcockatrice/settings/download_settings.h>
|
||||
#include <libcockatrice/settings/interface_settings.h>
|
||||
#include <libcockatrice/settings/network_settings.h>
|
||||
#include <libcockatrice/settings/personal_settings.h>
|
||||
|
|
@ -85,7 +84,7 @@ SoundEngine *soundEngine;
|
|||
QSystemTrayIcon *trayIcon;
|
||||
ThemeManager *themeManager;
|
||||
|
||||
const QString translationPrefix = "cockatrice"; // Keep inherited translation catalogue until retranslated.
|
||||
const QString translationPrefix = "cockatrice";
|
||||
QString translationPath;
|
||||
|
||||
static void CockatriceLogger(QtMsgType type, const QMessageLogContext &ctx, const QString &message)
|
||||
|
|
@ -138,9 +137,9 @@ QString const generateClientID()
|
|||
static QString redactActivationUrl(const QString &url)
|
||||
{
|
||||
// Activation URLs carry secrets in their query string (e.g. the deck share
|
||||
// token); log only the scheme and the action (continuumatrice://opendeck), never
|
||||
// token); log only the scheme and the action (cockatrice://opendeck), never
|
||||
// the parameters.
|
||||
if (!url.startsWith(QStringLiteral("continuumatrice://"))) {
|
||||
if (!url.startsWith(QStringLiteral("cockatrice://"))) {
|
||||
return url;
|
||||
}
|
||||
const QUrl parsed(url);
|
||||
|
|
@ -220,7 +219,7 @@ int main(int argc, char *argv[])
|
|||
QApplication app(argc, argv);
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
UrlSchemeEventFilter cockatriceFilter(QStringList{QStringLiteral("continuumatrice")});
|
||||
UrlSchemeEventFilter cockatriceFilter(QStringList{QStringLiteral("cockatrice")});
|
||||
|
||||
QStringList pendingMacUrls;
|
||||
|
||||
|
|
@ -258,7 +257,7 @@ int main(int argc, char *argv[])
|
|||
// Declared before crash-reporter init: the startup attach below needs the log tail while the
|
||||
// file still holds the crashed session's lines.
|
||||
const QString persistentLogPath =
|
||||
SettingsCache::instance().getSettingsPath() + QStringLiteral("logs/continuumatrice.log");
|
||||
SettingsCache::instance().getSettingsPath() + QStringLiteral("logs/cockatrice.log");
|
||||
Logger::getInstance().setPersistentLogPath(persistentLogPath);
|
||||
|
||||
// Crash reporting: init the SDK early so a crash anywhere below is captured into the
|
||||
|
|
@ -334,7 +333,7 @@ int main(int argc, char *argv[])
|
|||
#elif defined(Q_OS_WIN)
|
||||
translationPath = qApp->applicationDirPath() + "/translations";
|
||||
#else // linux
|
||||
translationPath = qApp->applicationDirPath() + "/../share/continuumatrice/translations";
|
||||
translationPath = qApp->applicationDirPath() + "/../share/cockatrice/translations";
|
||||
#endif
|
||||
|
||||
// Command-line parser
|
||||
|
|
@ -417,24 +416,6 @@ int main(int argc, char *argv[])
|
|||
CardDatabaseManager::setCardDatabasePathProvider(&SettingsCache::instance());
|
||||
CardDatabaseManager::setCardSetPriorityController(&SettingsCache::instance().cardDatabase());
|
||||
|
||||
// Existing early fork profiles may still contain the upstream Scryfall /
|
||||
// Gatherer defaults saved by older builds. Migrate only known MTG provider
|
||||
// URLs, leaving user-authored Continuum Universes endpoints untouched.
|
||||
auto &downloadSettings = SettingsCache::instance().downloads();
|
||||
const QStringList savedImageUrls = downloadSettings.getAllURLs();
|
||||
QStringList compatibleImageUrls;
|
||||
for (const QString &url : savedImageUrls) {
|
||||
if (!url.contains(QStringLiteral("scryfall.com"), Qt::CaseInsensitive) &&
|
||||
!url.contains(QStringLiteral("scryfall.io"), Qt::CaseInsensitive) &&
|
||||
!url.contains(QStringLiteral("gatherer.wizards.com"), Qt::CaseInsensitive)) {
|
||||
compatibleImageUrls.append(url);
|
||||
}
|
||||
}
|
||||
if (compatibleImageUrls != savedImageUrls) {
|
||||
downloadSettings.setDownloadUrls(compatibleImageUrls);
|
||||
qCInfo(MainLog) << "Removed inherited MTG image sources from Continuumatrice profile.";
|
||||
}
|
||||
|
||||
qCInfo(MainLog) << "Starting main program";
|
||||
|
||||
// Front-load the card database before constructing the main window. The
|
||||
|
|
@ -467,7 +448,7 @@ int main(int argc, char *argv[])
|
|||
// auto-connect must not race against it (two connectToServer calls tear
|
||||
// each other down via doDisconnectFromServer).
|
||||
bool hasUrlActivation = std::any_of(startupFiles.begin(), startupFiles.end(), [](const QString &file) {
|
||||
return file.startsWith(QStringLiteral("continuumatrice://"));
|
||||
return file.startsWith(QStringLiteral("cockatrice://"));
|
||||
});
|
||||
#ifdef Q_OS_MAC
|
||||
// On macOS the launch can arrive through the URL scheme instead of as a
|
||||
|
|
@ -475,12 +456,12 @@ int main(int argc, char *argv[])
|
|||
// window would auto-connect into the link's own connection attempt.
|
||||
hasUrlActivation = hasUrlActivation ||
|
||||
std::any_of(pendingMacUrls.cbegin(), pendingMacUrls.cend(),
|
||||
[](const QString &url) { return url.startsWith(QStringLiteral("continuumatrice://")); });
|
||||
[](const QString &url) { return url.startsWith(QStringLiteral("cockatrice://")); });
|
||||
#endif
|
||||
ui.setSkipStartupAutoConnect(hasUrlActivation);
|
||||
|
||||
auto handleActivation = [&ui](const QString &file) {
|
||||
if (file.startsWith("continuumatrice://")) {
|
||||
if (file.startsWith("cockatrice://")) {
|
||||
qCInfo(MainLog) << "Handling URL activation:" << redactActivationUrl(file);
|
||||
// Route through the window's persistent url parser: it serializes
|
||||
// link chains so activations handed over while another chain is
|
||||
|
|
@ -506,12 +487,12 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
qCInfo(MainLog) << "MainWindow constructor finished";
|
||||
|
||||
ui.setWindowIcon(themePixmap(QStringLiteral("continuumatrice")));
|
||||
ui.setWindowIcon(themePixmap(QStringLiteral("cockatrice")));
|
||||
// Base name of the desktop file installed next to the binary, without the ".desktop"
|
||||
// extension. Wayland reads the window icon from it, and xdg-desktop-portal looks up
|
||||
// org.freedesktop.host.portal.Registry by this app ID, so it has to match the file name
|
||||
// exactly, down to the case.
|
||||
QGuiApplication::setDesktopFileName("continuumatrice");
|
||||
QGuiApplication::setDesktopFileName("cockatrice");
|
||||
|
||||
SettingsCache::instance().network().setClientID(generateClientID());
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue