(&QComboBox::currentIndexChanged), this,
- &GeneralSettingsPage::cardLanguageBoxChanged);
-
auto *languageGrid = new QGridLayout;
languageGrid->addWidget(&languageLabel, 0, 0);
languageGrid->addWidget(&languageBox, 0, 1);
- languageGrid->addWidget(&cardLanguageLabel, 1, 0);
- languageGrid->addWidget(&cardLanguageBox, 1, 1);
- languageGrid->addWidget(&cardLanguageNoteLabel, 2, 1);
- languageGrid->addWidget(&advertiseTranslationPageLabel, 3, 1, Qt::AlignRight);
-
- cardLanguageNoteLabel.setWordWrap(true);
- cardLanguageNoteLabel.setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
+ languageGrid->addWidget(&advertiseTranslationPageLabel, 1, 1, Qt::AlignRight);
languageGroupBox = new QGroupBox;
languageGroupBox->setLayout(languageGrid);
@@ -435,52 +412,6 @@ void GeneralSettingsPage::languageBoxChanged(int index)
SettingsCache::instance().personal().setLang(languageBox.itemData(index).toString());
}
-void GeneralSettingsPage::cardLanguageBoxChanged(int index)
-{
- const QString lang = cardLanguageBox.itemData(index).toString();
- SettingsCache::instance().cardsDisplay().setCardLang(lang);
-
- // Switching to a non-default language only takes effect after the card
- // database is re-imported with that language selected; English data is always
- // present, so switching back to English needs no prompt.
- if (lang == "en") {
- return;
- }
-
- // The binary cache does not track the language its entries were imported in,
- // and the downloaded pictures were fetched with English art names, so both are
- // stale until Oracle re-imports the database in the new language: drop them.
- QFile::remove(SettingsCache::instance().getCardDatabasePath() + ".cache");
- CardPictureLoader::clearNetworkCache();
- CardPictureLoader::clearPixmapCache();
-
- // Art is resolved by the translated card name for non-English languages, so the
- // matching Scryfall URL is added to the top of the download list. It stays
- // visible in the deck editor settings, where it can be removed or reordered.
- const bool localizedUrlAdded = SettingsCache::instance().downloads().addLocalizedScryfallUrl();
-
- QString message = tr("The card database only contains English card data. To see cards in %1, "
- "Oracle must run once with this language selected and re-import the card "
- "database.
"
- "The cached database and the downloaded card pictures have been cleared, so a "
- "re-import is picked up without stale entries.
")
- .arg(cardLanguageBox.itemText(index));
- if (localizedUrlAdded) {
- message += tr("The Scryfall URL that resolves card art by translated name was added to the top of your "
- "download list. You can remove or reorder it any time.
");
- }
- message += tr("Run Oracle now?
");
-
- const QMessageBox::StandardButton answer = QMessageBox::question(
- this, tr("Card text & images language changed"), message, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
-
- // The answer only controls whether Oracle starts right away; the caches stay
- // cleared so the next import or launch rebuilds them in the new language.
- if (answer == QMessageBox::Yes) {
- emit cardDatabaseUpdateRequested();
- }
-}
-
void GeneralSettingsPage::updateStartupServerControlsVisibility()
{
const int index = startupTabSelector.currentIndex();
@@ -498,10 +429,6 @@ void GeneralSettingsPage::retranslateUi()
languageGroupBox->setTitle(tr("Language settings"));
languageLabel.setText(tr("Language:"));
- cardLanguageBox.setItemText(0, tr("English"));
- cardLanguageLabel.setText(tr("Card text & images language:"));
- cardLanguageNoteLabel.setText(
- tr("Foreign card names, text and art apply after you update the card database (Oracle)."));
advertiseTranslationPageLabel.setText(
QString("%2").arg(WIKI_TRANSLATION_FAQ).arg(tr("How to help with translations")));
diff --git a/cockatrice/src/interface/widgets/settings_page/general_settings_page.h b/cockatrice/src/interface/widgets/settings_page/general_settings_page.h
index 7afba158f..e0c1a47bf 100644
--- a/cockatrice/src/interface/widgets/settings_page/general_settings_page.h
+++ b/cockatrice/src/interface/widgets/settings_page/general_settings_page.h
@@ -23,10 +23,6 @@ public:
static QStringList findQmFiles();
static QString languageName(const QString &lang);
-signals:
- /// Request to re-import the card database with the newly selected card language
- void cardDatabaseUpdateRequested();
-
private slots:
void deckPathButtonClicked();
void filtersPathButtonClicked();
@@ -37,7 +33,6 @@ private slots:
void tokenDatabasePathButtonClicked();
void resetAllPathsClicked();
void languageBoxChanged(int index);
- void cardLanguageBoxChanged(int index);
void updateStartupServerControlsVisibility();
private:
@@ -51,10 +46,6 @@ private:
QComboBox languageBox;
QLabel advertiseTranslationPageLabel;
- QLabel cardLanguageLabel;
- QComboBox cardLanguageBox;
- QLabel cardLanguageNoteLabel;
-
QLabel updateReleaseChannelLabel;
QComboBox updateReleaseChannelBox;
QCheckBox startupUpdateCheckCheckBox;
diff --git a/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.cpp b/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.cpp
index 657ef3dbe..66b68d823 100644
--- a/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.cpp
+++ b/cockatrice/src/interface/widgets/tabs/api/archidekt/display/archidekt_api_response_deck_display_widget.cpp
@@ -1,6 +1,5 @@
#include "archidekt_api_response_deck_display_widget.h"
-#include "../../../../../../client/settings/cache_settings.h"
#include "../../../../../deck_loader/card_node_function.h"
#include "../../../../../deck_loader/deck_loader.h"
#include "../../../../cards/card_size_widget.h"
@@ -11,7 +10,6 @@
#include
#include
-#include
ArchidektApiResponseDeckDisplayWidget::ArchidektApiResponseDeckDisplayWidget(QWidget *parent,
ArchidektApiResponseDeck _response,
@@ -122,9 +120,6 @@ ArchidektApiResponseDeckDisplayWidget::ArchidektApiResponseDeckDisplayWidget(QWi
}
model = new DeckListModel(this);
- model->setDisplayLanguage(SettingsCache::instance().cardsDisplay().getCardLang());
- connect(&SettingsCache::instance().cardsDisplay(), &CardsDisplaySettings::cardLangChanged, model,
- [this](const QString &lang) { model->setDisplayLanguage(lang); });
connect(model, &DeckListModel::modelReset, this, &ArchidektApiResponseDeckDisplayWidget::decklistModelReset);
auto decklist = QSharedPointer(new DeckList);
diff --git a/cockatrice/src/interface/widgets/tabs/tab_server.cpp b/cockatrice/src/interface/widgets/tabs/tab_server.cpp
index fca32094c..13a77e957 100644
--- a/cockatrice/src/interface/widgets/tabs/tab_server.cpp
+++ b/cockatrice/src/interface/widgets/tabs/tab_server.cpp
@@ -13,7 +13,6 @@
#include
#include
#include
-#include
#include
#include
@@ -186,37 +185,25 @@ void TabServer::processServerMessageEvent(const Event_ServerMessage &event)
void TabServer::joinRoom(int id, bool setCurrent)
{
TabRoom *room = tabSupervisor->getRoomTabs().value(id);
- if (room) {
- if (setCurrent) {
- tabSupervisor->setCurrentWidget((QWidget *)room);
- }
+ if (!room) {
+ Command_JoinRoom cmd;
+ cmd.set_room_id(id);
+
+ PendingCommand *pend = client->prepareSessionCommand(cmd);
+ pend->setExtraData(setCurrent);
+ connect(pend, &PendingCommand::finished, this,
+ [this, id](const Response &r, const CommandContainer &c, const QVariant &v) {
+ joinRoomFinished(r, c, v, id);
+ });
+
+ client->sendCommand(pend);
+
return;
}
- auto pendingIt = pendingRoomJoins.find(id);
- if (pendingIt != pendingRoomJoins.end()) {
- // A join for this room is already in flight: the room tab opens when its response
- // arrives. Fold the new request into the pending one so that, for example, clicking
- // a room the selector is auto-joining does not send a second Command_JoinRoom - the
- // server would reject that duplicate with RespContextError.
- if (setCurrent) {
- pendingIt.value() = true;
- }
- return;
+ if (setCurrent) {
+ tabSupervisor->setCurrentWidget((QWidget *)room);
}
-
- pendingRoomJoins.insert(id, setCurrent);
-
- Command_JoinRoom cmd;
- cmd.set_room_id(id);
-
- PendingCommand *pend = client->prepareSessionCommand(cmd);
- pend->setExtraData(setCurrent);
- connect(
- pend, &PendingCommand::finished, this,
- [this, id](const Response &r, const CommandContainer &c, const QVariant &v) { joinRoomFinished(r, c, v, id); });
-
- client->sendCommand(pend);
}
void TabServer::joinRoomFinished(const Response &r,
@@ -224,72 +211,34 @@ void TabServer::joinRoomFinished(const Response &r,
const QVariant &extraData,
int roomId)
{
- const bool setCurrent = pendingRoomJoins.value(roomId, extraData.toBool());
- pendingRoomJoins.remove(roomId);
- const bool healedJoin = healedRoomJoins.contains(roomId);
- healedRoomJoins.remove(roomId);
-
switch (r.response_code()) {
case Response::RespOk:
break;
case Response::RespNameNotFound:
- if (setCurrent) {
- QMessageBox::critical(this, tr("Error"),
- tr("Failed to join the server room: it doesn't exist on the server."));
- }
+ QMessageBox::critical(this, tr("Error"),
+ tr("Failed to join the server room: it doesn't exist on the server."));
emit roomJoinFailed(roomId);
return;
case Response::RespContextError:
- if (healedJoin) {
- // The rejoin below was already answered and the server still rejects the join, so
- // the stale-membership heal cannot help: surface the error. The guard was already
- // released above so a later user-initiated join may try a fresh heal.
- if (setCurrent) {
- QMessageBox::critical(
- this, tr("Error"),
- tr("The server thinks you are in the server room but your client is unable to display it. "
- "Try restarting your client."));
- }
- emit roomJoinFailed(roomId);
- return;
- }
- // The server already had us registered in the room even though no tab was open,
- // usually because two join attempts for the same room overlapped. Leaving and
- // rejoining makes the server reply with a fresh RespOk so the tab is displayed
- // without requiring a client restart. The guard above covers exactly the rejoin that
- // leaveAndRejoinRoom triggers, so a server that keeps replying with RespContextError
- // gets one heal attempt per join instead of an endless recursion.
- healedRoomJoins.insert(roomId);
- leaveAndRejoinRoom(roomId, setCurrent);
+ QMessageBox::critical(
+ this, tr("Error"),
+ tr("The server thinks you are in the server room but your client is unable to display it. "
+ "Try restarting your client."));
+ emit roomJoinFailed(roomId);
return;
case Response::RespUserLevelTooLow:
- if (setCurrent) {
- QMessageBox::critical(this, tr("Error"),
- tr("You do not have the required permission to join this server room."));
- }
+ QMessageBox::critical(this, tr("Error"),
+ tr("You do not have the required permission to join this server room."));
emit roomJoinFailed(roomId);
return;
default:
- if (setCurrent) {
- QMessageBox::critical(
- this, tr("Error"),
- tr("Failed to join the server room due to an unknown error: %1.").arg(r.response_code()));
- }
+ QMessageBox::critical(
+ this, tr("Error"),
+ tr("Failed to join the server room due to an unknown error: %1.").arg(r.response_code()));
emit roomJoinFailed(roomId);
return;
}
const Response_JoinRoom &resp = r.GetExtension(Response_JoinRoom::ext);
- emit roomJoined(resp.room_info(), setCurrent);
-}
-
-void TabServer::leaveAndRejoinRoom(int roomId, bool setCurrent)
-{
- // Clear the stale room membership server-side. The leave is sent before the rejoin below,
- // so the server no longer considers us a member by the time the join arrives. The leave
- // response is intentionally not awaited: commands are processed in send order on the
- // connection, and a failed leave (RespNotInRoom) only means the membership was already gone.
- client->sendCommand(client->prepareRoomCommand(Command_LeaveRoom(), roomId));
-
- joinRoom(roomId, setCurrent);
+ emit roomJoined(resp.room_info(), extraData.toBool());
}
diff --git a/cockatrice/src/interface/widgets/tabs/tab_server.h b/cockatrice/src/interface/widgets/tabs/tab_server.h
index 121ff814d..c10b7945b 100644
--- a/cockatrice/src/interface/widgets/tabs/tab_server.h
+++ b/cockatrice/src/interface/widgets/tabs/tab_server.h
@@ -10,8 +10,6 @@
#include "tab.h"
#include
-#include
-#include
#include
#include
@@ -60,17 +58,10 @@ private slots:
int roomId);
private:
- void leaveAndRejoinRoom(int roomId, bool setCurrent);
-
AbstractClient *client;
RoomSelector *roomSelector;
QTextBrowser *serverInfoBox;
bool shouldEmitUpdate = false;
- /** Room ids with a join command in flight, mapped to whether the tab should be focused once it opens. */
- QHash pendingRoomJoins;
- /** Room ids for which a stale-membership heal (leave + rejoin) is currently in flight. Released as soon as the
- * rejoin has been answered, so a heal is attempted at most once per join. */
- QSet healedRoomJoins;
public:
TabServer(TabSupervisor *_tabSupervisor, AbstractClient *_client);
diff --git a/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp b/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp
index ccb687ff3..462aa420b 100644
--- a/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp
+++ b/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp
@@ -1451,11 +1451,6 @@ bool TabSupervisor::getAdminLocked() const
return tabAdmin->getLocked();
}
-bool TabSupervisor::canOverrideGameRestrictions() const
-{
- return !getAdminLocked() || (userInfo->user_level() & ServerInfo_User::IsJudge);
-}
-
void TabSupervisor::processNotifyUserEvent(const Event_NotifyUser &event)
{
diff --git a/cockatrice/src/interface/widgets/tabs/tab_supervisor.h b/cockatrice/src/interface/widgets/tabs/tab_supervisor.h
index adde7f971..aec1d7418 100644
--- a/cockatrice/src/interface/widgets/tabs/tab_supervisor.h
+++ b/cockatrice/src/interface/widgets/tabs/tab_supervisor.h
@@ -171,7 +171,6 @@ public:
[[nodiscard]] QList getGameInviteLinksForRoom(int roomId) const;
void sendInviteToUser(const QString &userName, const QString &inviteText);
[[nodiscard]] bool getAdminLocked() const;
- [[nodiscard]] bool canOverrideGameRestrictions() const;
void closeEvent(QCloseEvent *event) override;
bool switchToGameTabIfAlreadyExists(const int gameId);
static void actShowPopup(const QString &message);
diff --git a/cockatrice/src/interface/window_main.cpp b/cockatrice/src/interface/window_main.cpp
index 722df90ef..3daaeb8d3 100644
--- a/cockatrice/src/interface/window_main.cpp
+++ b/cockatrice/src/interface/window_main.cpp
@@ -33,7 +33,6 @@
#include "../interface/widgets/dialogs/dlg_update.h"
#include "../interface/widgets/dialogs/dlg_view_log.h"
#include "../interface/widgets/onboarding/first_run_wizard.h"
-#include "../interface/widgets/settings_page/general_settings_page.h"
#include "../interface/widgets/tabs/tab_game.h"
#include "../interface/widgets/tabs/tab_server.h"
#include "../interface/widgets/tabs/tab_supervisor.h"
@@ -247,8 +246,6 @@ void MainWindow::actFullScreen(bool checked)
void MainWindow::actSettings()
{
DlgSettings dlg(this);
- auto *generalPage = qobject_cast(dlg.page(DlgSettings::GeneralPage));
- connect(generalPage, &GeneralSettingsPage::cardDatabaseUpdateRequested, this, &MainWindow::actCheckCardUpdates);
dlg.exec();
}
diff --git a/cockatrice/themes/CMakeLists.txt b/cockatrice/themes/CMakeLists.txt
index 70344d95a..577977551 100644
--- a/cockatrice/themes/CMakeLists.txt
+++ b/cockatrice/themes/CMakeLists.txt
@@ -2,7 +2,7 @@
#
# add themes subfolders
-set(defthemes Fabric Fusion Leather Plasma VelvetMarble System)
+set(defthemes Default Fabric Fusion Leather Plasma VelvetMarble)
if(UNIX)
if(APPLE)
diff --git a/cockatrice/themes/System/palette-default-dark.toml b/cockatrice/themes/Default/palette-default-dark.toml
similarity index 96%
rename from cockatrice/themes/System/palette-default-dark.toml
rename to cockatrice/themes/Default/palette-default-dark.toml
index e101935b4..3ee174a2f 100644
--- a/cockatrice/themes/System/palette-default-dark.toml
+++ b/cockatrice/themes/Default/palette-default-dark.toml
@@ -61,7 +61,3 @@ ToolTipBase = #ffffffdc
ToolTipText = #ff000000
PlaceholderText = #6effffff
-
-[AppColors]
-AccentStrong = #ff148c3c
-AccentSoft = #ff78c850
diff --git a/cockatrice/themes/System/theme.cfg b/cockatrice/themes/Default/theme.cfg
similarity index 73%
rename from cockatrice/themes/System/theme.cfg
rename to cockatrice/themes/Default/theme.cfg
index 4b756a5e8..d2016a238 100644
--- a/cockatrice/themes/System/theme.cfg
+++ b/cockatrice/themes/Default/theme.cfg
@@ -2,4 +2,4 @@
ColorScheme = Light
[Style]
-Name = System
+Name = Default
diff --git a/cockatrice/themes/Fabric/backgrounds/home-dark.png b/cockatrice/themes/Fabric/backgrounds/home-dark.png
deleted file mode 100644
index 8d9514626..000000000
Binary files a/cockatrice/themes/Fabric/backgrounds/home-dark.png and /dev/null differ
diff --git a/cockatrice/themes/Fabric/backgrounds/home-light.png b/cockatrice/themes/Fabric/backgrounds/home-light.png
deleted file mode 100644
index 78f51a686..000000000
Binary files a/cockatrice/themes/Fabric/backgrounds/home-light.png and /dev/null differ
diff --git a/cockatrice/themes/Fabric/palette-default-dark.toml b/cockatrice/themes/Fabric/palette-default-dark.toml
deleted file mode 100644
index cad18921a..000000000
--- a/cockatrice/themes/Fabric/palette-default-dark.toml
+++ /dev/null
@@ -1,74 +0,0 @@
-# Fabric — dark identity palette (navy-cloth chrome)
-[Palette]
-WindowText = #e8ecf2
-Button = #2b374a
-Light = #3a4759
-Midlight = #333f50
-Dark = #141a23
-Mid = #252c38
-Text = #e8ecf2
-BrightText = #8ec2ff
-ButtonText = #f2f4f8
-Base = #222c3d
-Window = #18202e
-Shadow = #0b0f15
-Highlight = #4a82e6
-HighlightedText = #ffffff
-Link = #7fb0f2
-LinkVisited = #a98ad9
-AlternateBase = #1d2636
-ToolTipBase = #2b3546
-ToolTipText = #f2f4f8
-PlaceholderText = #6ee8ecf2
-Accent = #4a82e6
-
-[Palette.Disabled]
-WindowText = #9d9d9d
-Button = #18202e
-Light = #3a4759
-Midlight = #333f50
-Dark = #141a23
-Mid = #252c38
-Text = #9d9d9d
-BrightText = #8ec2ff
-ButtonText = #787878
-Base = #18202e
-Window = #18202e
-Shadow = #0b0f15
-Highlight = #222d40
-HighlightedText = #9d9d9d
-Link = #308cc6
-LinkVisited = #b450ff
-AlternateBase = #1d2636
-ToolTipBase = #2b3546
-ToolTipText = #f2f4f8
-PlaceholderText = #6ee8ecf2
-Accent = #9d9d9d
-
-[Palette.Inactive]
-WindowText = #e8ecf2
-Button = #2b374a
-Light = #3a4759
-Midlight = #333f50
-Dark = #141a23
-Mid = #252c38
-Text = #e8ecf2
-BrightText = #8ec2ff
-ButtonText = #f2f4f8
-Base = #222c3d
-Window = #18202e
-Shadow = #0b0f15
-Highlight = #222d40
-HighlightedText = #ffffff
-Link = #7fb0f2
-LinkVisited = #a98ad9
-AlternateBase = #1d2636
-ToolTipBase = #2b3546
-ToolTipText = #f2f4f8
-PlaceholderText = #6ee8ecf2
-Accent = #4a82e6
-
-[AppColors]
-AccentStrong = #3a6fd6
-AccentSoft = #8fb8f2
-
diff --git a/cockatrice/themes/Fabric/palette-default-light.toml b/cockatrice/themes/Fabric/palette-default-light.toml
deleted file mode 100644
index f5151af3e..000000000
--- a/cockatrice/themes/Fabric/palette-default-light.toml
+++ /dev/null
@@ -1,74 +0,0 @@
-# Fabric — light identity palette (navy-cloth chrome)
-[Palette]
-WindowText = #1c2330
-Button = #c8d6ea
-Light = #ffffff
-Midlight = #b9c6dc
-Dark = #8fa0bd
-Mid = #a3b3cd
-Text = #1c2330
-BrightText = #1d4fa0
-ButtonText = #141c29
-Base = #f6f8fc
-Window = #dbe3ef
-Shadow = #5a6a85
-Highlight = #2f6fd6
-HighlightedText = #ffffff
-Link = #2555b0
-LinkVisited = #6a4bb8
-AlternateBase = #e9eef7
-ToolTipBase = #e9eff8
-ToolTipText = #141c29
-PlaceholderText = #7a1c2330
-Accent = #2f6fd6
-
-[Palette.Disabled]
-WindowText = #787878
-Button = #dbe3ef
-Light = #ffffff
-Midlight = #b9c6dc
-Dark = #8fa0bd
-Mid = #a3b3cd
-Text = #787878
-BrightText = #1d4fa0
-ButtonText = #969696
-Base = #dbe3ef
-Window = #dbe3ef
-Shadow = #5a6a85
-Highlight = #cdd8e9
-HighlightedText = #787878
-Link = #0000ff
-LinkVisited = #ff00ff
-AlternateBase = #e9eef7
-ToolTipBase = #e9eff8
-ToolTipText = #141c29
-PlaceholderText = #7a1c2330
-Accent = #787878
-
-[Palette.Inactive]
-WindowText = #1c2330
-Button = #c8d6ea
-Light = #ffffff
-Midlight = #b9c6dc
-Dark = #8fa0bd
-Mid = #a3b3cd
-Text = #1c2330
-BrightText = #1d4fa0
-ButtonText = #141c29
-Base = #f6f8fc
-Window = #dbe3ef
-Shadow = #5a6a85
-Highlight = #cdd8e9
-HighlightedText = #000000
-Link = #2555b0
-LinkVisited = #6a4bb8
-AlternateBase = #e9eef7
-ToolTipBase = #e9eff8
-ToolTipText = #141c29
-PlaceholderText = #7a1c2330
-Accent = #2f6fd6
-
-[AppColors]
-AccentStrong = #3a6fd6
-AccentSoft = #8fb8f2
-
diff --git a/cockatrice/themes/Fabric/theme.cfg b/cockatrice/themes/Fabric/theme.cfg
deleted file mode 100644
index 55b916e71..000000000
--- a/cockatrice/themes/Fabric/theme.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-[Appearance]
-ColorScheme = System
-
-[Style]
-Name = Fusion
\ No newline at end of file
diff --git a/cockatrice/themes/Fabric/zones/handzone-light.png b/cockatrice/themes/Fabric/zones/handzone-light.png
deleted file mode 100644
index a87f9e292..000000000
Binary files a/cockatrice/themes/Fabric/zones/handzone-light.png and /dev/null differ
diff --git a/cockatrice/themes/Fabric/zones/handzone.png b/cockatrice/themes/Fabric/zones/handzone.png
index a5b72286c..25d22b070 100644
Binary files a/cockatrice/themes/Fabric/zones/handzone.png and b/cockatrice/themes/Fabric/zones/handzone.png differ
diff --git a/cockatrice/themes/Fabric/zones/playerzone-light.png b/cockatrice/themes/Fabric/zones/playerzone-light.png
deleted file mode 100644
index 05da3ea9b..000000000
Binary files a/cockatrice/themes/Fabric/zones/playerzone-light.png and /dev/null differ
diff --git a/cockatrice/themes/Fabric/zones/playerzone.png b/cockatrice/themes/Fabric/zones/playerzone.png
index 7fa977249..728fccdfa 100644
Binary files a/cockatrice/themes/Fabric/zones/playerzone.png and b/cockatrice/themes/Fabric/zones/playerzone.png differ
diff --git a/cockatrice/themes/Fabric/zones/stackzone-light.png b/cockatrice/themes/Fabric/zones/stackzone-light.png
deleted file mode 100644
index dcd6dc045..000000000
Binary files a/cockatrice/themes/Fabric/zones/stackzone-light.png and /dev/null differ
diff --git a/cockatrice/themes/Fabric/zones/stackzone.png b/cockatrice/themes/Fabric/zones/stackzone.png
index 9046aa049..89e2080f8 100644
Binary files a/cockatrice/themes/Fabric/zones/stackzone.png and b/cockatrice/themes/Fabric/zones/stackzone.png differ
diff --git a/cockatrice/themes/Fabric/zones/tablezone-light.png b/cockatrice/themes/Fabric/zones/tablezone-light.png
deleted file mode 100644
index cb297e7e1..000000000
Binary files a/cockatrice/themes/Fabric/zones/tablezone-light.png and /dev/null differ
diff --git a/cockatrice/themes/Fabric/zones/tablezone.png b/cockatrice/themes/Fabric/zones/tablezone.png
index 8048a4cc1..6a2ce68e1 100644
Binary files a/cockatrice/themes/Fabric/zones/tablezone.png and b/cockatrice/themes/Fabric/zones/tablezone.png differ
diff --git a/cockatrice/themes/Fusion/palette-default-dark.toml b/cockatrice/themes/Fusion/palette-default-dark.toml
index b180e9b63..c1d83a4cd 100644
--- a/cockatrice/themes/Fusion/palette-default-dark.toml
+++ b/cockatrice/themes/Fusion/palette-default-dark.toml
@@ -11,15 +11,15 @@ ButtonText = #ffffffff
Base = #ff2d2d2d
Window = #ff1e1e1e
Shadow = #ff000000
-Highlight = #ff139740
+Highlight = #ff148c3c
HighlightedText = #ffffffff
-Link = #ffc9fd62
-LinkVisited = #ff9ad43e
+Link = #ff00f652
+LinkVisited = #ff00d346
AlternateBase = #ff353535
ToolTipBase = #ff3c3c3c
ToolTipText = #ffd4d4d4
PlaceholderText = #80ffffff
-Accent = #ffc9fd62
+Accent = #ff00d346
[Palette.Disabled]
WindowText = #ff9d9d9d
@@ -34,7 +34,7 @@ ButtonText = #ff9d9d9d
Base = #ff1e1e1e
Window = #ff1e1e1e
Shadow = #ff000000
-Highlight = #ff139740
+Highlight = #ff148c3c
HighlightedText = #ffffffff
Link = #ff308cc6
LinkVisited = #ffff00ff
@@ -59,15 +59,11 @@ Window = #ff1e1e1e
Shadow = #ff000000
Highlight = #ff1e1e1e
HighlightedText = #ffffffff
-Link = #ffc9fd62
-LinkVisited = #ff9ad43e
+Link = #ff00f652
+LinkVisited = #ff00d346
AlternateBase = #ff353535
ToolTipBase = #ff3c3c3c
ToolTipText = #ffd4d4d4
PlaceholderText = #80ffffff
Accent = #ff1e1e1e
-
-[AppColors]
-AccentStrong = #ff139740
-AccentSoft = #ffc9fd62
diff --git a/cockatrice/themes/Fusion/palette-default-light.toml b/cockatrice/themes/Fusion/palette-default-light.toml
index 5a1163a2b..86c41be78 100644
--- a/cockatrice/themes/Fusion/palette-default-light.toml
+++ b/cockatrice/themes/Fusion/palette-default-light.toml
@@ -11,15 +11,15 @@ ButtonText = #ff000000
Base = #ffffffff
Window = #fff0f0f0
Shadow = #ff696969
-Highlight = #ff139740
+Highlight = #ff148c3c
HighlightedText = #ffffffff
-Link = #ff0e6b31
-LinkVisited = #ff0a521f
+Link = #ff0d5f28
+LinkVisited = #ff08401b
AlternateBase = #ffe9e7e3
ToolTipBase = #ffffffdc
ToolTipText = #ff000000
PlaceholderText = #80000000
-Accent = #ff139740
+Accent = #ff107532
[Palette.Disabled]
WindowText = #ff787878
@@ -34,7 +34,7 @@ ButtonText = #ff787878
Base = #fff0f0f0
Window = #fff0f0f0
Shadow = #ff000000
-Highlight = #ff139740
+Highlight = #ff148c3c
HighlightedText = #ffffffff
Link = #ff0000ff
LinkVisited = #ffff00ff
@@ -59,15 +59,11 @@ Window = #fff0f0f0
Shadow = #ff696969
Highlight = #fff0f0f0
HighlightedText = #ff000000
-Link = #ff0e6b31
-LinkVisited = #ff0a521f
+Link = #ff0d5f28
+LinkVisited = #ff08401b
AlternateBase = #ffe9e7e3
ToolTipBase = #ffffffdc
ToolTipText = #ff000000
PlaceholderText = #80000000
Accent = #fff0f0f0
-
-[AppColors]
-AccentStrong = #ff139740
-AccentSoft = #ffc9fd62
diff --git a/cockatrice/themes/Leather/backgrounds/home-dark.png b/cockatrice/themes/Leather/backgrounds/home-dark.png
deleted file mode 100644
index 20d16a27f..000000000
Binary files a/cockatrice/themes/Leather/backgrounds/home-dark.png and /dev/null differ
diff --git a/cockatrice/themes/Leather/backgrounds/home-light.png b/cockatrice/themes/Leather/backgrounds/home-light.png
deleted file mode 100644
index ee1da361d..000000000
Binary files a/cockatrice/themes/Leather/backgrounds/home-light.png and /dev/null differ
diff --git a/cockatrice/themes/Leather/palette-default-dark.toml b/cockatrice/themes/Leather/palette-default-dark.toml
deleted file mode 100644
index b0db0e90a..000000000
--- a/cockatrice/themes/Leather/palette-default-dark.toml
+++ /dev/null
@@ -1,74 +0,0 @@
-# Leather — dark identity palette (black-brown chrome with brass accents)
-[Palette]
-WindowText = #eee9e2
-Button = #332d26
-Light = #4a4239
-Midlight = #3d3730
-Dark = #131009
-Mid = #26221c
-Text = #eee9e2
-BrightText = #e3c27e
-ButtonText = #f5f1ea
-Base = #26221d
-Window = #1d1a16
-Shadow = #0d0b07
-Highlight = #4a5f8f
-HighlightedText = #ffffff
-Link = #cfa263
-LinkVisited = #9a7db8
-AlternateBase = #211d19
-ToolTipBase = #37302a
-ToolTipText = #f5f1ea
-PlaceholderText = #6eeee9e2
-Accent = #c9995a
-
-[Palette.Disabled]
-WindowText = #9d9d9d
-Button = #1d1a16
-Light = #4a4239
-Midlight = #3d3730
-Dark = #131009
-Mid = #26221c
-Text = #9d9d9d
-BrightText = #e3c27e
-ButtonText = #787878
-Base = #1d1a16
-Window = #1d1a16
-Shadow = #0d0b07
-Highlight = #2d2822
-HighlightedText = #9d9d9d
-Link = #308cc6
-LinkVisited = #b450ff
-AlternateBase = #211d19
-ToolTipBase = #37302a
-ToolTipText = #f5f1ea
-PlaceholderText = #6eeee9e2
-Accent = #9d9d9d
-
-[Palette.Inactive]
-WindowText = #eee9e2
-Button = #332d26
-Light = #4a4239
-Midlight = #3d3730
-Dark = #131009
-Mid = #26221c
-Text = #eee9e2
-BrightText = #e3c27e
-ButtonText = #f5f1ea
-Base = #26221d
-Window = #1d1a16
-Shadow = #0d0b07
-Highlight = #2d2822
-HighlightedText = #ffffff
-Link = #cfa263
-LinkVisited = #9a7db8
-AlternateBase = #211d19
-ToolTipBase = #37302a
-ToolTipText = #f5f1ea
-PlaceholderText = #6eeee9e2
-Accent = #c9995a
-
-[AppColors]
-AccentStrong = #b7823b
-AccentSoft = #e4c58f
-
diff --git a/cockatrice/themes/Leather/palette-default-light.toml b/cockatrice/themes/Leather/palette-default-light.toml
deleted file mode 100644
index ff122db76..000000000
--- a/cockatrice/themes/Leather/palette-default-light.toml
+++ /dev/null
@@ -1,74 +0,0 @@
-# Leather — light identity palette (black-brown chrome with brass accents)
-[Palette]
-WindowText = #2a2114
-Button = #dfcbb0
-Light = #ffffff
-Midlight = #c6b08c
-Dark = #a18a64
-Mid = #b29a74
-Text = #2a2114
-BrightText = #7a531c
-ButtonText = #1f1710
-Base = #fdf8ee
-Window = #f0e2cb
-Shadow = #5d4d33
-Highlight = #34508c
-HighlightedText = #ffffff
-Link = #8a5e1e
-LinkVisited = #6b5190
-AlternateBase = #f5ebd7
-ToolTipBase = #fff7e8
-ToolTipText = #1f1710
-PlaceholderText = #7a2a2114
-Accent = #a5712f
-
-[Palette.Disabled]
-WindowText = #787878
-Button = #f0e2cb
-Light = #ffffff
-Midlight = #c6b08c
-Dark = #a18a64
-Mid = #b29a74
-Text = #787878
-BrightText = #7a531c
-ButtonText = #969696
-Base = #f0e2cb
-Window = #f0e2cb
-Shadow = #5d4d33
-Highlight = #ecd9bb
-HighlightedText = #787878
-Link = #0000ff
-LinkVisited = #ff00ff
-AlternateBase = #f5ebd7
-ToolTipBase = #fff7e8
-ToolTipText = #1f1710
-PlaceholderText = #7a2a2114
-Accent = #787878
-
-[Palette.Inactive]
-WindowText = #2a2114
-Button = #dfcbb0
-Light = #ffffff
-Midlight = #c6b08c
-Dark = #a18a64
-Mid = #b29a74
-Text = #2a2114
-BrightText = #7a531c
-ButtonText = #1f1710
-Base = #fdf8ee
-Window = #f0e2cb
-Shadow = #5d4d33
-Highlight = #ecd9bb
-HighlightedText = #000000
-Link = #8a5e1e
-LinkVisited = #6b5190
-AlternateBase = #f5ebd7
-ToolTipBase = #fff7e8
-ToolTipText = #1f1710
-PlaceholderText = #7a2a2114
-Accent = #a5712f
-
-[AppColors]
-AccentStrong = #b7823b
-AccentSoft = #e4c58f
-
diff --git a/cockatrice/themes/Leather/theme.cfg b/cockatrice/themes/Leather/theme.cfg
deleted file mode 100644
index 55b916e71..000000000
--- a/cockatrice/themes/Leather/theme.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-[Appearance]
-ColorScheme = System
-
-[Style]
-Name = Fusion
\ No newline at end of file
diff --git a/cockatrice/themes/Leather/zones/handzone-light.png b/cockatrice/themes/Leather/zones/handzone-light.png
deleted file mode 100644
index b2c9bba34..000000000
Binary files a/cockatrice/themes/Leather/zones/handzone-light.png and /dev/null differ
diff --git a/cockatrice/themes/Leather/zones/handzone.png b/cockatrice/themes/Leather/zones/handzone.png
index 5f803df74..aba879683 100644
Binary files a/cockatrice/themes/Leather/zones/handzone.png and b/cockatrice/themes/Leather/zones/handzone.png differ
diff --git a/cockatrice/themes/Leather/zones/playerzone-light.png b/cockatrice/themes/Leather/zones/playerzone-light.png
deleted file mode 100644
index a26f96a5e..000000000
Binary files a/cockatrice/themes/Leather/zones/playerzone-light.png and /dev/null differ
diff --git a/cockatrice/themes/Leather/zones/playerzone.png b/cockatrice/themes/Leather/zones/playerzone.png
index cccbb3fd3..4f42ee41d 100644
Binary files a/cockatrice/themes/Leather/zones/playerzone.png and b/cockatrice/themes/Leather/zones/playerzone.png differ
diff --git a/cockatrice/themes/Leather/zones/stackzone-light.png b/cockatrice/themes/Leather/zones/stackzone-light.png
deleted file mode 100644
index 117c738f7..000000000
Binary files a/cockatrice/themes/Leather/zones/stackzone-light.png and /dev/null differ
diff --git a/cockatrice/themes/Leather/zones/stackzone.png b/cockatrice/themes/Leather/zones/stackzone.png
index d9cff892b..c02e2284a 100644
Binary files a/cockatrice/themes/Leather/zones/stackzone.png and b/cockatrice/themes/Leather/zones/stackzone.png differ
diff --git a/cockatrice/themes/Leather/zones/tablezone-light.png b/cockatrice/themes/Leather/zones/tablezone-light.png
deleted file mode 100644
index 912cbfb94..000000000
Binary files a/cockatrice/themes/Leather/zones/tablezone-light.png and /dev/null differ
diff --git a/cockatrice/themes/Leather/zones/tablezone.png b/cockatrice/themes/Leather/zones/tablezone.png
index 8af4c853d..152f4f7e9 100644
Binary files a/cockatrice/themes/Leather/zones/tablezone.png and b/cockatrice/themes/Leather/zones/tablezone.png differ
diff --git a/cockatrice/themes/Plasma/backgrounds/home-dark.png b/cockatrice/themes/Plasma/backgrounds/home-dark.png
deleted file mode 100644
index ce1469e2b..000000000
Binary files a/cockatrice/themes/Plasma/backgrounds/home-dark.png and /dev/null differ
diff --git a/cockatrice/themes/Plasma/backgrounds/home-light.png b/cockatrice/themes/Plasma/backgrounds/home-light.png
deleted file mode 100644
index 2e9000bd6..000000000
Binary files a/cockatrice/themes/Plasma/backgrounds/home-light.png and /dev/null differ
diff --git a/cockatrice/themes/Plasma/palette-default-dark.toml b/cockatrice/themes/Plasma/palette-default-dark.toml
deleted file mode 100644
index 222456f4f..000000000
--- a/cockatrice/themes/Plasma/palette-default-dark.toml
+++ /dev/null
@@ -1,74 +0,0 @@
-# Plasma — dark identity palette (electric violet chrome with cyan sparks)
-[Palette]
-WindowText = #eeebff
-Button = #2a2440
-Light = #453d63
-Midlight = #383252
-Dark = #0e0c16
-Mid = #211e31
-Text = #eeebff
-BrightText = #7fd7ff
-ButtonText = #f6f4ff
-Base = #1e1a2e
-Window = #151220
-Shadow = #08070e
-Highlight = #6a4df0
-HighlightedText = #ffffff
-Link = #37c7e8
-LinkVisited = #9b7aff
-AlternateBase = #1a1726
-ToolTipBase = #2c2745
-ToolTipText = #f6f4ff
-PlaceholderText = #6eeeebff
-Accent = #6a4df0
-
-[Palette.Disabled]
-WindowText = #9d9d9d
-Button = #151220
-Light = #453d63
-Midlight = #383252
-Dark = #0e0c16
-Mid = #211e31
-Text = #9d9d9d
-BrightText = #7fd7ff
-ButtonText = #787878
-Base = #151220
-Window = #151220
-Shadow = #08070e
-Highlight = #211c32
-HighlightedText = #9d9d9d
-Link = #308cc6
-LinkVisited = #b450ff
-AlternateBase = #1a1726
-ToolTipBase = #2c2745
-ToolTipText = #f6f4ff
-PlaceholderText = #6eeeebff
-Accent = #9d9d9d
-
-[Palette.Inactive]
-WindowText = #eeebff
-Button = #2a2440
-Light = #453d63
-Midlight = #383252
-Dark = #0e0c16
-Mid = #211e31
-Text = #eeebff
-BrightText = #7fd7ff
-ButtonText = #f6f4ff
-Base = #1e1a2e
-Window = #151220
-Shadow = #08070e
-Highlight = #211c32
-HighlightedText = #ffffff
-Link = #37c7e8
-LinkVisited = #9b7aff
-AlternateBase = #1a1726
-ToolTipBase = #2c2745
-ToolTipText = #f6f4ff
-PlaceholderText = #6eeeebff
-Accent = #6a4df0
-
-[AppColors]
-AccentStrong = #5b3ee0
-AccentSoft = #a28bf7
-
diff --git a/cockatrice/themes/Plasma/palette-default-light.toml b/cockatrice/themes/Plasma/palette-default-light.toml
deleted file mode 100644
index d54db31d2..000000000
--- a/cockatrice/themes/Plasma/palette-default-light.toml
+++ /dev/null
@@ -1,74 +0,0 @@
-# Plasma — light identity palette (electric violet chrome with cyan sparks)
-[Palette]
-WindowText = #1d1830
-Button = #cfc6f0
-Light = #ffffff
-Midlight = #b7adde
-Dark = #9589c8
-Mid = #a49ad2
-Text = #1d1830
-BrightText = #10406e
-ButtonText = #120d26
-Base = #f9f7ff
-Window = #e3dcf7
-Shadow = #554c85
-Highlight = #5a3ee2
-HighlightedText = #ffffff
-Link = #0f8fb5
-LinkVisited = #6a45d6
-AlternateBase = #ece8fa
-ToolTipBase = #f5f3ff
-ToolTipText = #120d26
-PlaceholderText = #7a1d1830
-Accent = #5a3ee2
-
-[Palette.Disabled]
-WindowText = #787878
-Button = #e3dcf7
-Light = #ffffff
-Midlight = #b7adde
-Dark = #9589c8
-Mid = #a49ad2
-Text = #787878
-BrightText = #10406e
-ButtonText = #969696
-Base = #e3dcf7
-Window = #e3dcf7
-Shadow = #554c85
-Highlight = #d6ccf3
-HighlightedText = #787878
-Link = #0000ff
-LinkVisited = #ff00ff
-AlternateBase = #ece8fa
-ToolTipBase = #f5f3ff
-ToolTipText = #120d26
-PlaceholderText = #7a1d1830
-Accent = #787878
-
-[Palette.Inactive]
-WindowText = #1d1830
-Button = #cfc6f0
-Light = #ffffff
-Midlight = #b7adde
-Dark = #9589c8
-Mid = #a49ad2
-Text = #1d1830
-BrightText = #10406e
-ButtonText = #120d26
-Base = #f9f7ff
-Window = #e3dcf7
-Shadow = #554c85
-Highlight = #d6ccf3
-HighlightedText = #000000
-Link = #0f8fb5
-LinkVisited = #6a45d6
-AlternateBase = #ece8fa
-ToolTipBase = #f5f3ff
-ToolTipText = #120d26
-PlaceholderText = #7a1d1830
-Accent = #5a3ee2
-
-[AppColors]
-AccentStrong = #5b3ee0
-AccentSoft = #a28bf7
-
diff --git a/cockatrice/themes/Plasma/theme.cfg b/cockatrice/themes/Plasma/theme.cfg
deleted file mode 100644
index 55b916e71..000000000
--- a/cockatrice/themes/Plasma/theme.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-[Appearance]
-ColorScheme = System
-
-[Style]
-Name = Fusion
\ No newline at end of file
diff --git a/cockatrice/themes/Plasma/zones/handzone-light.png b/cockatrice/themes/Plasma/zones/handzone-light.png
deleted file mode 100644
index 89fa7e6d4..000000000
Binary files a/cockatrice/themes/Plasma/zones/handzone-light.png and /dev/null differ
diff --git a/cockatrice/themes/Plasma/zones/handzone.png b/cockatrice/themes/Plasma/zones/handzone.png
index 82debb405..543571d8a 100644
Binary files a/cockatrice/themes/Plasma/zones/handzone.png and b/cockatrice/themes/Plasma/zones/handzone.png differ
diff --git a/cockatrice/themes/Plasma/zones/playerzone-light.png b/cockatrice/themes/Plasma/zones/playerzone-light.png
deleted file mode 100644
index 9034818f2..000000000
Binary files a/cockatrice/themes/Plasma/zones/playerzone-light.png and /dev/null differ
diff --git a/cockatrice/themes/Plasma/zones/playerzone.png b/cockatrice/themes/Plasma/zones/playerzone.png
index 4623524f6..eebcd1f84 100644
Binary files a/cockatrice/themes/Plasma/zones/playerzone.png and b/cockatrice/themes/Plasma/zones/playerzone.png differ
diff --git a/cockatrice/themes/Plasma/zones/stackzone-light.png b/cockatrice/themes/Plasma/zones/stackzone-light.png
deleted file mode 100644
index 2607b3389..000000000
Binary files a/cockatrice/themes/Plasma/zones/stackzone-light.png and /dev/null differ
diff --git a/cockatrice/themes/Plasma/zones/stackzone.png b/cockatrice/themes/Plasma/zones/stackzone.png
index 144d991f3..1845c7091 100644
Binary files a/cockatrice/themes/Plasma/zones/stackzone.png and b/cockatrice/themes/Plasma/zones/stackzone.png differ
diff --git a/cockatrice/themes/Plasma/zones/tablezone-light.png b/cockatrice/themes/Plasma/zones/tablezone-light.png
deleted file mode 100644
index dcf2ef95e..000000000
Binary files a/cockatrice/themes/Plasma/zones/tablezone-light.png and /dev/null differ
diff --git a/cockatrice/themes/Plasma/zones/tablezone.png b/cockatrice/themes/Plasma/zones/tablezone.png
index 4dc36ec2d..8f998d4bb 100644
Binary files a/cockatrice/themes/Plasma/zones/tablezone.png and b/cockatrice/themes/Plasma/zones/tablezone.png differ
diff --git a/cockatrice/themes/System/palette-default-light.toml b/cockatrice/themes/System/palette-default-light.toml
deleted file mode 100644
index 14c215cdf..000000000
--- a/cockatrice/themes/System/palette-default-light.toml
+++ /dev/null
@@ -1,67 +0,0 @@
-[Palette]
-WindowText = #ff000000
-Button = #fff0f0f0
-Light = #ffffffff
-Midlight = #ffe3e3e3
-Dark = #ffa0a0a0
-Mid = #ffa0a0a0
-Text = #ff000000
-BrightText = #ffffffff
-ButtonText = #ff000000
-Base = #ffffffff
-Window = #fff0f0f0
-Shadow = #ff696969
-HighlightedText = #ffffffff
-Link = #ff0d5f28
-LinkVisited = #ff08401b
-AlternateBase = #ffe9e7e3
-ToolTipBase = #ffffffdc
-ToolTipText = #ff000000
-PlaceholderText = #80000000
-
-[Palette.Disabled]
-WindowText = #ff787878
-Button = #fff0f0f0
-Light = #ffffffff
-Midlight = #fff7f7f7
-Dark = #ffa0a0a0
-Mid = #ffa0a0a0
-Text = #ff787878
-BrightText = #ffffffff
-ButtonText = #ff787878
-Base = #fff0f0f0
-Window = #fff0f0f0
-Shadow = #ff000000
-HighlightedText = #ffffffff
-Link = #ff0000ff
-LinkVisited = #ffff00ff
-AlternateBase = #fff7f7f7
-ToolTipBase = #ffffffdc
-ToolTipText = #ff000000
-PlaceholderText = #80000000
-
-[Palette.Inactive]
-WindowText = #ff000000
-Button = #fff0f0f0
-Light = #ffffffff
-Midlight = #ffe3e3e3
-Dark = #ffa0a0a0
-Mid = #ffa0a0a0
-Text = #ff000000
-BrightText = #ffffffff
-ButtonText = #ff000000
-Base = #ffffffff
-Window = #fff0f0f0
-Shadow = #ff696969
-HighlightedText = #ff000000
-Link = #ff0d5f28
-LinkVisited = #ff08401b
-AlternateBase = #ffe9e7e3
-ToolTipBase = #ffffffdc
-ToolTipText = #ff000000
-PlaceholderText = #80000000
-
-
-[AppColors]
-AccentStrong = #ff148c3c
-AccentSoft = #ff78c850
\ No newline at end of file
diff --git a/cockatrice/themes/VelvetMarble/backgrounds/home-dark.png b/cockatrice/themes/VelvetMarble/backgrounds/home-dark.png
deleted file mode 100644
index 34738090f..000000000
Binary files a/cockatrice/themes/VelvetMarble/backgrounds/home-dark.png and /dev/null differ
diff --git a/cockatrice/themes/VelvetMarble/backgrounds/home-light.png b/cockatrice/themes/VelvetMarble/backgrounds/home-light.png
deleted file mode 100644
index de783e086..000000000
Binary files a/cockatrice/themes/VelvetMarble/backgrounds/home-light.png and /dev/null differ
diff --git a/cockatrice/themes/VelvetMarble/palette-default-dark.toml b/cockatrice/themes/VelvetMarble/palette-default-dark.toml
deleted file mode 100644
index 496943931..000000000
--- a/cockatrice/themes/VelvetMarble/palette-default-dark.toml
+++ /dev/null
@@ -1,74 +0,0 @@
-# VelvetMarble — dark identity palette (charcoal-velvet chrome with slate marble)
-[Palette]
-WindowText = #e8eaee
-Button = #262a31
-Light = #3a3f47
-Midlight = #31363d
-Dark = #0e1013
-Mid = #1f2329
-Text = #e8eaee
-BrightText = #c3d8f2
-ButtonText = #f2f3f6
-Base = #1b1e23
-Window = #131519
-Shadow = #08090b
-Highlight = #8fa6c0
-HighlightedText = #101318
-Link = #a9c6e8
-LinkVisited = #b9a8d9
-AlternateBase = #171a1f
-ToolTipBase = #2d323a
-ToolTipText = #f2f3f6
-PlaceholderText = #6ee8eaee
-Accent = #8fa6c0
-
-[Palette.Disabled]
-WindowText = #9d9d9d
-Button = #131519
-Light = #3a3f47
-Midlight = #31363d
-Dark = #0e1013
-Mid = #1f2329
-Text = #9d9d9d
-BrightText = #c3d8f2
-ButtonText = #787878
-Base = #131519
-Window = #131519
-Shadow = #08090b
-Highlight = #1f2229
-HighlightedText = #9d9d9d
-Link = #308cc6
-LinkVisited = #b450ff
-AlternateBase = #171a1f
-ToolTipBase = #2d323a
-ToolTipText = #f2f3f6
-PlaceholderText = #6ee8eaee
-Accent = #9d9d9d
-
-[Palette.Inactive]
-WindowText = #e8eaee
-Button = #262a31
-Light = #3a3f47
-Midlight = #31363d
-Dark = #0e1013
-Mid = #1f2329
-Text = #e8eaee
-BrightText = #c3d8f2
-ButtonText = #f2f3f6
-Base = #1b1e23
-Window = #131519
-Shadow = #08090b
-Highlight = #1f2229
-HighlightedText = #ffffff
-Link = #a9c6e8
-LinkVisited = #b9a8d9
-AlternateBase = #171a1f
-ToolTipBase = #2d323a
-ToolTipText = #f2f3f6
-PlaceholderText = #6ee8eaee
-Accent = #8fa6c0
-
-[AppColors]
-AccentStrong = #54687e
-AccentSoft = #9db0c4
-
diff --git a/cockatrice/themes/VelvetMarble/palette-default-light.toml b/cockatrice/themes/VelvetMarble/palette-default-light.toml
deleted file mode 100644
index 5323fd320..000000000
--- a/cockatrice/themes/VelvetMarble/palette-default-light.toml
+++ /dev/null
@@ -1,74 +0,0 @@
-# VelvetMarble — light identity palette (charcoal-velvet chrome with slate marble)
-[Palette]
-WindowText = #1b1d21
-Button = #c7d1dd
-Light = #ffffff
-Midlight = #b3becb
-Dark = #93a0b1
-Mid = #a1adbc
-Text = #1b1d21
-BrightText = #26465f
-ButtonText = #121418
-Base = #f7f9fb
-Window = #d9e0ea
-Shadow = #57626f
-Highlight = #54687e
-HighlightedText = #ffffff
-Link = #2e4d6b
-LinkVisited = #5d4a78
-AlternateBase = #e6ebf2
-ToolTipBase = #f2f4f6
-ToolTipText = #121418
-PlaceholderText = #7a1b1d21
-Accent = #54687e
-
-[Palette.Disabled]
-WindowText = #787878
-Button = #d9e0ea
-Light = #ffffff
-Midlight = #b3becb
-Dark = #93a0b1
-Mid = #a1adbc
-Text = #787878
-BrightText = #26465f
-ButtonText = #969696
-Base = #d9e0ea
-Window = #d9e0ea
-Shadow = #57626f
-Highlight = #ccd5e3
-HighlightedText = #787878
-Link = #0000ff
-LinkVisited = #ff00ff
-AlternateBase = #e6ebf2
-ToolTipBase = #f2f4f6
-ToolTipText = #121418
-PlaceholderText = #7a1b1d21
-Accent = #787878
-
-[Palette.Inactive]
-WindowText = #1b1d21
-Button = #c7d1dd
-Light = #ffffff
-Midlight = #b3becb
-Dark = #93a0b1
-Mid = #a1adbc
-Text = #1b1d21
-BrightText = #26465f
-ButtonText = #121418
-Base = #f7f9fb
-Window = #d9e0ea
-Shadow = #57626f
-Highlight = #ccd5e3
-HighlightedText = #000000
-Link = #2e4d6b
-LinkVisited = #5d4a78
-AlternateBase = #e6ebf2
-ToolTipBase = #f2f4f6
-ToolTipText = #121418
-PlaceholderText = #7a1b1d21
-Accent = #54687e
-
-[AppColors]
-AccentStrong = #54687e
-AccentSoft = #9db0c4
-
diff --git a/cockatrice/themes/VelvetMarble/theme.cfg b/cockatrice/themes/VelvetMarble/theme.cfg
deleted file mode 100644
index 55b916e71..000000000
--- a/cockatrice/themes/VelvetMarble/theme.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-[Appearance]
-ColorScheme = System
-
-[Style]
-Name = Fusion
\ No newline at end of file
diff --git a/cockatrice/themes/VelvetMarble/zones/handzone-light.png b/cockatrice/themes/VelvetMarble/zones/handzone-light.png
deleted file mode 100644
index b21e78e61..000000000
Binary files a/cockatrice/themes/VelvetMarble/zones/handzone-light.png and /dev/null differ
diff --git a/cockatrice/themes/VelvetMarble/zones/handzone.jpg b/cockatrice/themes/VelvetMarble/zones/handzone.jpg
new file mode 100644
index 000000000..2ec9b37fe
Binary files /dev/null and b/cockatrice/themes/VelvetMarble/zones/handzone.jpg differ
diff --git a/cockatrice/themes/VelvetMarble/zones/handzone.png b/cockatrice/themes/VelvetMarble/zones/handzone.png
deleted file mode 100644
index 3e2b7ebea..000000000
Binary files a/cockatrice/themes/VelvetMarble/zones/handzone.png and /dev/null differ
diff --git a/cockatrice/themes/VelvetMarble/zones/playerzone-light.png b/cockatrice/themes/VelvetMarble/zones/playerzone-light.png
deleted file mode 100644
index 630aac6eb..000000000
Binary files a/cockatrice/themes/VelvetMarble/zones/playerzone-light.png and /dev/null differ
diff --git a/cockatrice/themes/VelvetMarble/zones/playerzone.jpg b/cockatrice/themes/VelvetMarble/zones/playerzone.jpg
new file mode 100644
index 000000000..dd13cab78
Binary files /dev/null and b/cockatrice/themes/VelvetMarble/zones/playerzone.jpg differ
diff --git a/cockatrice/themes/VelvetMarble/zones/playerzone.png b/cockatrice/themes/VelvetMarble/zones/playerzone.png
deleted file mode 100644
index dcf21ba38..000000000
Binary files a/cockatrice/themes/VelvetMarble/zones/playerzone.png and /dev/null differ
diff --git a/cockatrice/themes/VelvetMarble/zones/stackzone-light.png b/cockatrice/themes/VelvetMarble/zones/stackzone-light.png
deleted file mode 100644
index 62027827c..000000000
Binary files a/cockatrice/themes/VelvetMarble/zones/stackzone-light.png and /dev/null differ
diff --git a/cockatrice/themes/VelvetMarble/zones/stackzone.jpg b/cockatrice/themes/VelvetMarble/zones/stackzone.jpg
new file mode 100644
index 000000000..b63aa0902
Binary files /dev/null and b/cockatrice/themes/VelvetMarble/zones/stackzone.jpg differ
diff --git a/cockatrice/themes/VelvetMarble/zones/stackzone.png b/cockatrice/themes/VelvetMarble/zones/stackzone.png
deleted file mode 100644
index a47f7bf9d..000000000
Binary files a/cockatrice/themes/VelvetMarble/zones/stackzone.png and /dev/null differ
diff --git a/cockatrice/themes/VelvetMarble/zones/tablezone-light.png b/cockatrice/themes/VelvetMarble/zones/tablezone-light.png
deleted file mode 100644
index 5a9014f9d..000000000
Binary files a/cockatrice/themes/VelvetMarble/zones/tablezone-light.png and /dev/null differ
diff --git a/cockatrice/themes/VelvetMarble/zones/tablezone.jpg b/cockatrice/themes/VelvetMarble/zones/tablezone.jpg
new file mode 100644
index 000000000..9f511491a
Binary files /dev/null and b/cockatrice/themes/VelvetMarble/zones/tablezone.jpg differ
diff --git a/cockatrice/themes/VelvetMarble/zones/tablezone.png b/cockatrice/themes/VelvetMarble/zones/tablezone.png
deleted file mode 100644
index 1523d0821..000000000
Binary files a/cockatrice/themes/VelvetMarble/zones/tablezone.png and /dev/null differ
diff --git a/doc/carddatabase_v4/cards.xsd b/doc/carddatabase_v4/cards.xsd
index 82aed32ab..59ca3e560 100644
--- a/doc/carddatabase_v4/cards.xsd
+++ b/doc/carddatabase_v4/cards.xsd
@@ -35,13 +35,6 @@
-
-
-
-
-
-
-
@@ -56,13 +49,6 @@
-
-
-
-
-
-
-
diff --git a/libcockatrice_card/CMakeLists.txt b/libcockatrice_card/CMakeLists.txt
index 15388ecfc..081e6fd05 100644
--- a/libcockatrice_card/CMakeLists.txt
+++ b/libcockatrice_card/CMakeLists.txt
@@ -5,7 +5,6 @@ set(CMAKE_AUTORCC ON)
set(HEADERS
libcockatrice/card/card_info.h
libcockatrice/card/card_info_comparator.h
- libcockatrice/card/card_localization.h
libcockatrice/card/lazy_properties_hash.h
libcockatrice/card/database/card_database.h
libcockatrice/card/database/card_database_loader.h
@@ -28,7 +27,6 @@ add_library(
${MOC_SOURCES}
libcockatrice/card/card_info.cpp
libcockatrice/card/card_info_comparator.cpp
- libcockatrice/card/card_localization.cpp
libcockatrice/card/lazy_properties_hash.cpp
libcockatrice/card/database/card_database.cpp
libcockatrice/card/database/card_database_cache.cpp
diff --git a/libcockatrice_card/libcockatrice/card/card_info.cpp b/libcockatrice_card/libcockatrice/card/card_info.cpp
index 56c737793..786e17950 100644
--- a/libcockatrice_card/libcockatrice/card/card_info.cpp
+++ b/libcockatrice_card/libcockatrice/card/card_info.cpp
@@ -40,11 +40,8 @@ CardInfo::CardInfo(const QString &_name,
const QList &_relatedCards,
const QList &_reverseRelatedCards,
SetToPrintingsMap _sets,
- const UiAttributes _uiAttributes,
- QMap _localizedNames,
- QMap _localizedTexts)
- : name(_name), text(_text), isToken(_isToken), localizedNames(std::move(_localizedNames)),
- localizedTexts(std::move(_localizedTexts)), properties(LazyPropertiesHash(_properties)),
+ const UiAttributes _uiAttributes)
+ : name(_name), text(_text), isToken(_isToken), properties(LazyPropertiesHash(_properties)),
relatedCards(_relatedCards), reverseRelatedCards(_reverseRelatedCards), setsToPrintings(std::move(_sets)),
uiAttributes(_uiAttributes)
{
@@ -62,11 +59,8 @@ CardInfo::CardInfo(const QString &_name,
SetToPrintingsMap _sets,
const UiAttributes _uiAttributes,
QString _simpleName,
- QSet _altNames,
- QMap _localizedNames,
- QMap _localizedTexts)
+ QSet _altNames)
: name(_name), simpleName(std::move(_simpleName)), text(_text), isToken(_isToken),
- localizedNames(std::move(_localizedNames)), localizedTexts(std::move(_localizedTexts)),
properties(LazyPropertiesHash(_propertiesBlob)), relatedCards(_relatedCards),
reverseRelatedCards(_reverseRelatedCards), setsToPrintings(std::move(_sets)), uiAttributes(_uiAttributes),
altNames(std::move(_altNames))
@@ -89,12 +83,10 @@ CardInfoPtr CardInfo::newInstance(const QString &_name,
const QList &_relatedCards,
const QList &_reverseRelatedCards,
SetToPrintingsMap _sets,
- const UiAttributes _uiAttributes,
- QMap _localizedNames,
- QMap _localizedTexts)
+ const UiAttributes _uiAttributes)
{
- CardInfoPtr ptr(new CardInfo(_name, _text, _isToken, _properties, _relatedCards, _reverseRelatedCards, _sets,
- _uiAttributes, std::move(_localizedNames), std::move(_localizedTexts)));
+ CardInfoPtr ptr(
+ new CardInfo(_name, _text, _isToken, _properties, _relatedCards, _reverseRelatedCards, _sets, _uiAttributes));
ptr->setSmartPointer(ptr);
for (const auto &printings : _sets) {
@@ -117,13 +109,11 @@ CardInfoPtr CardInfo::newInstance(const QString &_name,
const UiAttributes _uiAttributes,
QString _simpleName,
QSet _altNames,
- bool _appendToSets,
- QMap _localizedNames,
- QMap _localizedTexts)
+ bool _appendToSets)
{
CardInfoPtr ptr(new CardInfo(_name, _text, _isToken, std::move(_propertiesBlob), _relatedCards,
_reverseRelatedCards, _sets, _uiAttributes, std::move(_simpleName),
- std::move(_altNames), std::move(_localizedNames), std::move(_localizedTexts)));
+ std::move(_altNames)));
ptr->setSmartPointer(ptr);
if (_appendToSets) {
diff --git a/libcockatrice_card/libcockatrice/card/card_info.h b/libcockatrice_card/libcockatrice/card/card_info.h
index 17894cec5..392dc3849 100644
--- a/libcockatrice_card/libcockatrice/card/card_info.h
+++ b/libcockatrice_card/libcockatrice/card/card_info.h
@@ -77,9 +77,6 @@ private:
QString text; ///< Text description or rules text of the card.
bool isToken; ///< Whether this card is a token or not.
- QMap localizedNames; ///< Localized card names, keyed by language code.
- QMap localizedTexts; ///< Localized rules text, keyed by language code.
-
LazyPropertiesHash properties; ///< Key-value store of dynamic card properties.
QList relatedCards; ///< Forward references to related cards.
@@ -103,8 +100,6 @@ public:
* @param _reverseRelatedCards Backward references to related cards.
* @param _sets Map of set names to printing information.
* @param _uiAttributes Attributes that affect display and game logic
- * @param _localizedNames Localized card names, keyed by language code.
- * @param _localizedTexts Localized rules text, keyed by language code.
*/
explicit CardInfo(const QString &_name,
const QString &_text,
@@ -113,9 +108,7 @@ public:
const QList &_relatedCards,
const QList &_reverseRelatedCards,
SetToPrintingsMap _sets,
- UiAttributes _uiAttributes,
- QMap _localizedNames = {},
- QMap _localizedTexts = {});
+ UiAttributes _uiAttributes);
/**
* @brief Constructs a CardInfo from a cache snapshot with precomputed derived
@@ -137,8 +130,6 @@ public:
* @param _uiAttributes Attributes that affect display and game logic.
* @param _simpleName Precomputed simplified name.
* @param _altNames Precomputed alternate names.
- * @param _localizedNames Localized card names, keyed by language code.
- * @param _localizedTexts Localized rules text, keyed by language code.
*/
explicit CardInfo(const QString &_name,
const QString &_text,
@@ -149,9 +140,7 @@ public:
SetToPrintingsMap _sets,
UiAttributes _uiAttributes,
QString _simpleName,
- QSet _altNames,
- QMap _localizedNames = {},
- QMap _localizedTexts = {});
+ QSet _altNames);
/**
* @brief Copy constructor for CardInfo.
@@ -162,8 +151,7 @@ public:
*/
CardInfo(const CardInfo &other)
: QObject(other.parent()), name(other.name), simpleName(other.simpleName), text(other.text),
- isToken(other.isToken), localizedNames(other.localizedNames), localizedTexts(other.localizedTexts),
- properties(other.properties), relatedCards(other.relatedCards),
+ isToken(other.isToken), properties(other.properties), relatedCards(other.relatedCards),
reverseRelatedCards(other.reverseRelatedCards), reverseRelatedCardsToMe(other.reverseRelatedCardsToMe),
setsToPrintings(other.setsToPrintings), uiAttributes(other.uiAttributes), setsNames(other.setsNames),
altNames(other.altNames)
@@ -191,8 +179,6 @@ public:
* @param _reverseRelatedCards Reverse relationships.
* @param _sets Printing information per set.
* @param _uiAttributes Attributes that affect display and game logic
- * @param _localizedNames Localized card names, keyed by language code.
- * @param _localizedTexts Localized rules text, keyed by language code.
* @return Shared pointer to the new CardInfo instance.
*/
static CardInfoPtr newInstance(const QString &_name,
@@ -202,9 +188,7 @@ public:
const QList &_relatedCards,
const QList &_reverseRelatedCards,
SetToPrintingsMap _sets,
- UiAttributes _uiAttributes,
- QMap _localizedNames = {},
- QMap _localizedTexts = {});
+ UiAttributes _uiAttributes);
/**
* @brief Creates a new instance from a cache snapshot with precomputed
@@ -224,8 +208,6 @@ public:
* its CardSets. Pass false when building cards in parallel so the
* (non-thread-safe) set membership is populated in a later
* single-threaded pass.
- * @param _localizedNames Localized card names, keyed by language code.
- * @param _localizedTexts Localized rules text, keyed by language code.
* @return Shared pointer to the new CardInfo instance.
*/
static CardInfoPtr newInstance(const QString &_name,
@@ -238,9 +220,7 @@ public:
UiAttributes _uiAttributes,
QString _simpleName,
QSet _altNames,
- bool _appendToSets = true,
- QMap _localizedNames = {},
- QMap _localizedTexts = {});
+ bool _appendToSets = true);
/**
* @brief Clones the current CardInfo instance.
@@ -290,96 +270,6 @@ public:
text = _text;
emit cardInfoChanged(smartThis);
}
-
- /**
- * @brief Returns the card name in the given language, falling back to the
- * English name when no localization is available.
- *
- * @param lang Language code (e.g. "de", "ja", "zhs").
- * @return The localized name, or the English name as fallback.
- */
- [[nodiscard]] const QString &getLocalizedName(const QString &lang) const
- {
- const auto it = localizedNames.constFind(lang);
- return it != localizedNames.constEnd() ? it.value() : name;
- }
-
- /**
- * @brief Returns the rules text in the given language, falling back to the
- * English text when no localization is available.
- *
- * @param lang Language code (e.g. "de", "ja", "zhs").
- * @return The localized text, or the English text as fallback.
- */
- [[nodiscard]] const QString &getLocalizedText(const QString &lang) const
- {
- const auto it = localizedTexts.constFind(lang);
- return it != localizedTexts.constEnd() ? it.value() : text;
- }
-
- /**
- * @brief Returns the localized card names keyed by language code.
- *
- * Only languages that have an entry are present; there is no English
- * fallback in this map.
- */
- [[nodiscard]] const QMap &getLocalizedNames() const
- {
- return localizedNames;
- }
-
- /**
- * @brief Returns the localized rules text keyed by language code.
- *
- * Only languages that have an entry are present; there is no English
- * fallback in this map.
- */
- [[nodiscard]] const QMap &getLocalizedTexts() const
- {
- return localizedTexts;
- }
-
- /**
- * @brief Sets the card name for the given language.
- *
- * @param lang Language code.
- * @param _localizedName The localized card name.
- */
- void setLocalizedName(const QString &lang, const QString &_localizedName)
- {
- if (localizedNames.value(lang) == _localizedName) {
- return;
- }
- localizedNames.insert(lang, _localizedName);
- emit cardInfoChanged(smartThis);
- }
-
- /**
- * @brief Sets the rules text for the given language.
- *
- * @param lang Language code.
- * @param _localizedText The localized rules text.
- */
- void setLocalizedText(const QString &lang, const QString &_localizedText)
- {
- if (localizedTexts.value(lang) == _localizedText) {
- return;
- }
- localizedTexts.insert(lang, _localizedText);
- emit cardInfoChanged(smartThis);
- }
-
- /**
- * @brief Returns the language codes for which this card has a localized
- * name or rules text.
- */
- [[nodiscard]] QStringList localizationLanguages() const
- {
- QStringList languages = localizedNames.keys();
- languages.append(localizedTexts.keys());
- languages.removeDuplicates();
- return languages;
- }
[[nodiscard]] bool getIsToken() const
{
return isToken;
diff --git a/libcockatrice_card/libcockatrice/card/card_localization.cpp b/libcockatrice_card/libcockatrice/card/card_localization.cpp
deleted file mode 100644
index 03c6c659b..000000000
--- a/libcockatrice_card/libcockatrice/card/card_localization.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-#include "card_localization.h"
-
-#include
-#include
-#include
-
-namespace CardLocalization
-{
-const QStringList &supportedLanguages()
-{
- static const QStringList languages = {"cs", "de", "es", "fr", "it", "ja", "ko", "pt", "ru", "zhs", "zht", "he"};
- return languages;
-}
-
-QString languageDisplayName(const QString &lang)
-{
- static const QHash displayNames = {
- {"cs", "Česky (Czech)"},
- {"de", "Deutsch (German)"},
- {"es", "Español (Spanish)"},
- {"fr", "Français (French)"},
- {"it", "Italiano (Italian)"},
- {"ja", "日本語 (Japanese)"},
- {"ko", "한국어 (Korean)"},
- {"pt", "Português (Portuguese)"},
- {"ru", "Русский (Russian)"},
- {"he", "עברית (Hebrew)"},
- {"zhs", "简体中文 (Chinese Simplified)"},
- {"zht", "繁體中文 (Chinese Traditional)"},
- };
- const QString displayName = displayNames.value(lang);
- if (!displayName.isEmpty()) {
- return displayName;
- }
- const QString nativeName = QLocale(lang).nativeLanguageName();
- return nativeName.isEmpty() ? lang : nativeName;
-}
-} // namespace CardLocalization
\ No newline at end of file
diff --git a/libcockatrice_card/libcockatrice/card/card_localization.h b/libcockatrice_card/libcockatrice/card/card_localization.h
deleted file mode 100644
index a9c8d28ea..000000000
--- a/libcockatrice_card/libcockatrice/card/card_localization.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef CARD_LOCALIZATION_H
-#define CARD_LOCALIZATION_H
-
-#include
-#include
-
-/**
- * @namespace CardLocalization
- * @ingroup Cards
- *
- * @brief Shared language metadata for localized card text and images.
- *
- * Lists the language codes Cockatrice can display localized card data for and
- * provides human-readable names. The list is shared between Oracle (which
- * imports the selected language's card data) and the client settings UI (which
- * offers the language choice).
- */
-namespace CardLocalization
-{
-/**
- * @brief Language codes for which localized card data can be imported/displayed.
- *
- * Matches the languages Scryfall can serve localized card images for. "en" is
- * always available as the default/fallback and is not listed here.
- *
- * @return The list of supported language codes.
- */
-[[nodiscard]] const QStringList &supportedLanguages();
-
-/**
- * @brief Human-readable name for a language code.
- *
- * Follows the same "native name (English name)" format the UI language list
- * uses (e.g. "日本語 (Japanese)"), so the English fallback is always visible.
- *
- * @param lang Language code (e.g. "de", "ja", "zhs").
- * @return The language's native name with its English name in parentheses, or
- * the code itself if it cannot be resolved.
- */
-[[nodiscard]] QString languageDisplayName(const QString &lang);
-} // namespace CardLocalization
-
-#endif // CARD_LOCALIZATION_H
\ No newline at end of file
diff --git a/libcockatrice_card/libcockatrice/card/database/card_database_cache.cpp b/libcockatrice_card/libcockatrice/card/database/card_database_cache.cpp
index 3165ff871..2b27f50f8 100644
--- a/libcockatrice_card/libcockatrice/card/database/card_database_cache.cpp
+++ b/libcockatrice_card/libcockatrice/card/database/card_database_cache.cpp
@@ -17,7 +17,7 @@
namespace
{
constexpr quint32 CACHE_MAGIC = 0x43445243; // "CDRC"
-constexpr quint32 CACHE_VERSION = 3;
+constexpr quint32 CACHE_VERSION = 2;
// ---- Primitives -----------------------------------------------------------
@@ -71,35 +71,6 @@ QDate readDate(QDataStream &in)
return d;
}
-void writeStringMap(QDataStream &out, const QMap &map)
-{
- out << static_cast(map.size());
- for (auto it = map.constBegin(); it != map.constEnd(); ++it) {
- writeString(out, it.key());
- writeString(out, it.value());
- }
-}
-
-QMap readStringMap(QDataStream &in)
-{
- QMap map;
- quint32 count = 0;
- in >> count;
- if (in.status() != QDataStream::Ok) {
- return map;
- }
- for (quint32 i = 0; i < count; ++i) {
- QString key = readString(in);
- QString value = readString(in);
- if (in.status() != QDataStream::Ok) {
- map.clear();
- return map;
- }
- map.insert(key, value);
- }
- return map;
-}
-
// ---- CardRelation ----------------------------------------------------------
void writeRelation(QDataStream &out, const CardRelation *rel)
@@ -224,10 +195,6 @@ void writeCard(QDataStream &out, const CardInfoPtr &card)
for (const CardRelation *rel : reverse) {
writeRelation(out, rel);
}
-
- // localized card data
- writeStringMap(out, card->getLocalizedNames());
- writeStringMap(out, card->getLocalizedTexts());
}
CardInfoPtr readCard(QDataStream &in, const SetNameMap &sets)
@@ -301,19 +268,8 @@ CardInfoPtr readCard(QDataStream &in, const SetNameMap &sets)
reverse.append(readRelation(in));
}
- const QMap localizedNames = readStringMap(in);
- if (in.status() != QDataStream::Ok) {
- return nullptr;
- }
- const QMap localizedTexts = readStringMap(in);
- if (in.status() != QDataStream::Ok) {
- return nullptr;
- }
-
- CardInfoPtr card = CardInfo::newInstance(name, text, isToken, propertiesBlob, related, reverse, cardSets, ui,
- simpleName, altNames, false, localizedNames, localizedTexts);
-
- return card;
+ return CardInfo::newInstance(name, text, isToken, propertiesBlob, related, reverse, cardSets, ui, simpleName,
+ altNames, false);
}
// ---- FormatRules -----------------------------------------------------------
diff --git a/libcockatrice_card/libcockatrice/card/database/parser/cockatrice_xml_4.cpp b/libcockatrice_card/libcockatrice/card/database/parser/cockatrice_xml_4.cpp
index 19e972a7a..ec460d685 100644
--- a/libcockatrice_card/libcockatrice/card/database/parser/cockatrice_xml_4.cpp
+++ b/libcockatrice_card/libcockatrice/card/database/parser/cockatrice_xml_4.cpp
@@ -273,8 +273,6 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml)
QString name = QString("");
QString text = QString("");
QHash properties;
- QMap localizedNames;
- QMap localizedTexts;
QList relatedCards, reverseRelatedCards;
auto _sets = SetToPrintingsMap();
int tableRow = 0;
@@ -300,44 +298,6 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml)
// generic properties
} else if (xmlName == "prop") {
properties = loadCardPropertiesFromXml(xml);
- // localized card data
- } else if (xmlName == "localizations") {
- while (!xml.atEnd()) {
- if (xml.readNextStartElement()) {
- const QString elementName = xml.name().toString();
- if (elementName == "localization") {
- const QString lang = xml.attributes().value("lang").toString();
- QString localizedName;
- QString localizedText;
- while (!xml.atEnd()) {
- if (xml.readNext() == QXmlStreamReader::EndElement) {
- break;
- }
- if (xml.isStartElement()) {
- const QString childName = xml.name().toString();
- QString value = xml.readElementText(QXmlStreamReader::IncludeChildElements);
- if (childName == "name") {
- localizedName = value;
- } else if (childName == "text") {
- localizedText = value;
- }
- }
- }
- if (!lang.isEmpty()) {
- if (!localizedName.isEmpty()) {
- localizedNames.insert(lang, localizedName);
- }
- if (!localizedText.isEmpty()) {
- localizedTexts.insert(lang, localizedText);
- }
- }
- } else {
- xml.skipCurrentElement();
- }
- } else {
- break;
- }
- }
// positioning info
} else if (xmlName == "tablerow") {
tableRow = xml.readElementText(QXmlStreamReader::IncludeChildElements).toInt();
@@ -439,9 +399,8 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml)
.landscapeOrientation = landscapeOrientation,
.tableRow = tableRow,
.upsideDownArt = upsideDown};
- CardInfoPtr newCard =
- CardInfo::newInstance(name, text, isToken, properties, relatedCards, reverseRelatedCards, _sets,
- attributes, std::move(localizedNames), std::move(localizedTexts));
+ CardInfoPtr newCard = CardInfo::newInstance(name, text, isToken, properties, relatedCards,
+ reverseRelatedCards, _sets, attributes);
if (targetData) {
// Mirror CardDatabase::addCard: if a card with this name already
// exists, merge the new printings into it instead of replacing.
@@ -558,26 +517,6 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfoPtr &in
}
xml.writeEndElement();
- // localized card data
- const QStringList localizedLanguages = info->localizationLanguages();
- if (!localizedLanguages.isEmpty()) {
- xml.writeStartElement("localizations");
- const QMap &localizedNames = info->getLocalizedNames();
- const QMap &localizedTexts = info->getLocalizedTexts();
- for (const QString &lang : localizedLanguages) {
- xml.writeStartElement("localization");
- xml.writeAttribute("lang", lang);
- if (localizedNames.contains(lang)) {
- xml.writeTextElement("name", localizedNames.value(lang));
- }
- if (localizedTexts.contains(lang)) {
- xml.writeTextElement("text", localizedTexts.value(lang));
- }
- xml.writeEndElement();
- }
- xml.writeEndElement();
- }
-
// sets
for (const auto &printings : info->getSets()) {
for (const PrintingInfo &set : printings) {
diff --git a/libcockatrice_deck_list/CMakeLists.txt b/libcockatrice_deck_list/CMakeLists.txt
index 0c487466c..c7a54a390 100644
--- a/libcockatrice_deck_list/CMakeLists.txt
+++ b/libcockatrice_deck_list/CMakeLists.txt
@@ -11,7 +11,6 @@ set(HEADERS
libcockatrice/deck_list/deck_list_history_manager.h
libcockatrice/deck_list/deck_list_node_tree.h
libcockatrice/deck_list/deck_list_memento.h
- libcockatrice/deck_list/deck_list_plain_text_parser.h
libcockatrice/deck_list/playmat_resolver.h
libcockatrice/deck_list/sideboard_plan.h
)
@@ -28,7 +27,6 @@ add_library(
libcockatrice/deck_list/deck_list.cpp
libcockatrice/deck_list/deck_list_history_manager.cpp
libcockatrice/deck_list/deck_list_node_tree.cpp
- libcockatrice/deck_list/deck_list_plain_text_parser.cpp
libcockatrice/deck_list/playmat_resolver.cpp
libcockatrice/deck_list/sideboard_plan.cpp
)
diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.cpp b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.cpp
index 90f63c09d..1a3876cd3 100644
--- a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.cpp
+++ b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.cpp
@@ -1,7 +1,6 @@
#include "deck_list.h"
#include "deck_list_memento.h"
-#include "deck_list_plain_text_parser.h"
#include "tree/abstract_deck_list_node.h"
#include "tree/deck_list_card_node.h"
#include "tree/inner_deck_list_node.h"
@@ -9,138 +8,26 @@
#include
#include
#include
+#include
#include
#include
#include
+#if QT_VERSION < 0x050600
+// qHash on QRegularExpression was added in 5.6, FIX IT
+uint qHash(const QRegularExpression &key, uint seed) noexcept
+{
+ return qHash(key.pattern(), seed); // call qHash on pattern QString instead
+}
+#endif
+
static const QString CURRENT_SIDEBOARD_PLAN_KEY = "";
-/**
- * @brief Parses a floating point XML attribute into a clamped playmat parameter.
- *
- * Falls back to @p fallback when the attribute is missing or malformed, so
- * malformed deck files cannot produce degenerate art rectangles (e.g. a zoom
- * of 0 dividing by zero).
- *
- * @param valueString Raw attribute text.
- * @param fallback Value used when the text cannot be parsed.
- * @param min Lower clamp bound.
- * @param max Upper clamp bound.
- * @return The parsed value clamped to [min, max], or @p fallback.
- */
-static double parseClampedParam(const QString &valueString, double fallback, double min, double max)
-{
- bool ok = false;
- const double value = valueString.toDouble(&ok);
- if (!ok) {
- return fallback;
- }
- return qBound(min, value, max);
-}
-
-/**
- * @brief Reads a `bannerCard` element from the XML stream.
- *
- * @param xml Reader positioned at the element.
- * @return The referenced card.
- */
-static CardRef readBannerCard(QXmlStreamReader *xml)
-{
- QString providerId = xml->attributes().value("providerId").toString();
- QString cardName = xml->readElementText();
- return {cardName, providerId};
-}
-
-/**
- * @brief Reads a `playmatCard` element from the XML stream.
- *
- * Attribute values are read before readElementText consumes the element, and
- * the params are clamped to the same ranges as the settings dialog and the
- * remote player-properties path so malformed deck files cannot produce
- * degenerate art rectangles (e.g. a zoom of 0 dividing by zero).
- *
- * @param xml Reader positioned at the element.
- * @return The referenced card plus its clamped positioning parameters.
- */
-static PlaymatInfo readPlaymatCard(QXmlStreamReader *xml)
-{
- QString providerId = xml->attributes().value("providerId").toString();
- QString marginLStr = xml->attributes().value("marginPctL").toString();
- QString marginRStr = xml->attributes().value("marginPctR").toString();
- QString vOffStr = xml->attributes().value("verticalOffset").toString();
- QString zoomStr = xml->attributes().value("zoom").toString();
- QString cardName = xml->readElementText();
-
- return {
- .card = {cardName, providerId},
- .params = {.marginPctL = parseClampedParam(marginLStr, 0.07, 0.0, 0.95),
- .marginPctR = parseClampedParam(marginRStr, 0.07, 0.0, 0.95),
- .verticalOffset = parseClampedParam(vOffStr, 0.33, 0.0, 1.0),
- .zoom = parseClampedParam(zoomStr, 1.0, 0.1, 4.0)},
- };
-}
-
bool DeckList::Metadata::isEmpty() const
{
return name.isEmpty() && comments.isEmpty() && bannerCard.isEmpty() && tags.isEmpty() && playmat.card.isEmpty();
}
-bool DeckList::Metadata::readElement(QXmlStreamReader *xml, const QString &childName)
-{
- if (childName == "lastLoadedTimestamp") {
- lastLoadedTimestamp = xml->readElementText();
- } else if (childName == "deckname") {
- name = xml->readElementText();
- } else if (childName == "format") {
- gameFormat = xml->readElementText();
- } else if (childName == "comments") {
- comments = xml->readElementText();
- } else if (childName == "bannerCard") {
- bannerCard = readBannerCard(xml);
- } else if (childName == "playmatCard") {
- playmat = readPlaymatCard(xml);
- } else if (childName == "tags") {
- tags.clear(); // Clear existing tags
- while (xml->readNextStartElement()) {
- if (xml->name().toString() == "tag") {
- tags.append(xml->readElementText());
- }
- }
- } else {
- return false;
- }
- return true;
-}
-
-void DeckList::Metadata::write(QXmlStreamWriter *xml) const
-{
- xml->writeTextElement("lastLoadedTimestamp", lastLoadedTimestamp);
- xml->writeTextElement("deckname", name);
- xml->writeTextElement("format", gameFormat);
- xml->writeStartElement("bannerCard");
- xml->writeAttribute("providerId", bannerCard.providerId);
- xml->writeCharacters(bannerCard.name);
- xml->writeEndElement();
- if (!playmat.card.isEmpty()) {
- xml->writeStartElement("playmatCard");
- xml->writeAttribute("providerId", playmat.card.providerId);
- xml->writeAttribute("marginPctL", QString::number(playmat.params.marginPctL, 'f', 4));
- xml->writeAttribute("marginPctR", QString::number(playmat.params.marginPctR, 'f', 4));
- xml->writeAttribute("verticalOffset", QString::number(playmat.params.verticalOffset, 'f', 4));
- xml->writeAttribute("zoom", QString::number(playmat.params.zoom, 'f', 4));
- xml->writeCharacters(playmat.card.name);
- xml->writeEndElement();
- }
- xml->writeTextElement("comments", comments);
-
- // Write tags
- xml->writeStartElement("tags");
- for (const QString &tag : tags) {
- xml->writeTextElement("tag", tag);
- }
- xml->writeEndElement();
-}
-
DeckList::DeckList()
{
}
@@ -175,10 +62,56 @@ bool DeckList::readElement(QXmlStreamReader *xml)
{
const QString childName = xml->name().toString();
if (xml->isStartElement()) {
- if (metadata.readElement(xml, childName)) {
- return true;
- }
- if (childName == "zone") {
+ if (childName == "lastLoadedTimestamp") {
+ metadata.lastLoadedTimestamp = xml->readElementText();
+ } else if (childName == "deckname") {
+ metadata.name = xml->readElementText();
+ } else if (childName == "format") {
+ metadata.gameFormat = xml->readElementText();
+ } else if (childName == "comments") {
+ metadata.comments = xml->readElementText();
+ } else if (childName == "bannerCard") {
+ QString providerId = xml->attributes().value("providerId").toString();
+ QString cardName = xml->readElementText();
+ metadata.bannerCard = {cardName, providerId};
+ } else if (childName == "playmatCard") {
+ QString providerId = xml->attributes().value("providerId").toString();
+ bool ok;
+ QString marginLStr = xml->attributes().value("marginPctL").toString();
+ QString marginRStr = xml->attributes().value("marginPctR").toString();
+ QString vOffStr = xml->attributes().value("verticalOffset").toString();
+ QString zoomStr = xml->attributes().value("zoom").toString();
+ QString cardName = xml->readElementText();
+ PlaymatInfo playmat;
+ playmat.card = {cardName, providerId};
+ // Clamp to the same ranges as the settings dialog and the remote
+ // player-properties path so malformed deck files cannot produce
+ // degenerate art rectangles (e.g. a zoom of 0 dividing by zero).
+ playmat.params.marginPctL = qBound(0.0, marginLStr.toDouble(&ok), 0.95);
+ if (!ok) {
+ playmat.params.marginPctL = 0.07;
+ }
+ playmat.params.marginPctR = qBound(0.0, marginRStr.toDouble(&ok), 0.95);
+ if (!ok) {
+ playmat.params.marginPctR = 0.07;
+ }
+ playmat.params.verticalOffset = qBound(0.0, vOffStr.toDouble(&ok), 1.0);
+ if (!ok) {
+ playmat.params.verticalOffset = 0.33;
+ }
+ playmat.params.zoom = qBound(0.1, zoomStr.toDouble(&ok), 4.0);
+ if (!ok) {
+ playmat.params.zoom = 1.0;
+ }
+ metadata.playmat = playmat;
+ } else if (childName == "tags") {
+ metadata.tags.clear(); // Clear existing tags
+ while (xml->readNextStartElement()) {
+ if (xml->name().toString() == "tag") {
+ metadata.tags.append(xml->readElementText());
+ }
+ }
+ } else if (childName == "zone") {
tree.readZoneElement(xml);
} else if (childName == "sideboard_plan") {
SideboardPlan newSideboardPlan;
@@ -192,12 +125,41 @@ bool DeckList::readElement(QXmlStreamReader *xml)
return true;
}
+static void writeMetadata(QXmlStreamWriter *xml, const DeckList::Metadata &metadata)
+{
+ xml->writeTextElement("lastLoadedTimestamp", metadata.lastLoadedTimestamp);
+ xml->writeTextElement("deckname", metadata.name);
+ xml->writeTextElement("format", metadata.gameFormat);
+ xml->writeStartElement("bannerCard");
+ xml->writeAttribute("providerId", metadata.bannerCard.providerId);
+ xml->writeCharacters(metadata.bannerCard.name);
+ xml->writeEndElement();
+ if (!metadata.playmat.card.isEmpty()) {
+ xml->writeStartElement("playmatCard");
+ xml->writeAttribute("providerId", metadata.playmat.card.providerId);
+ xml->writeAttribute("marginPctL", QString::number(metadata.playmat.params.marginPctL, 'f', 4));
+ xml->writeAttribute("marginPctR", QString::number(metadata.playmat.params.marginPctR, 'f', 4));
+ xml->writeAttribute("verticalOffset", QString::number(metadata.playmat.params.verticalOffset, 'f', 4));
+ xml->writeAttribute("zoom", QString::number(metadata.playmat.params.zoom, 'f', 4));
+ xml->writeCharacters(metadata.playmat.card.name);
+ xml->writeEndElement();
+ }
+ xml->writeTextElement("comments", metadata.comments);
+
+ // Write tags
+ xml->writeStartElement("tags");
+ for (const QString &tag : metadata.tags) {
+ xml->writeTextElement("tag", tag);
+ }
+ xml->writeEndElement();
+}
+
void DeckList::write(QXmlStreamWriter *xml) const
{
xml->writeStartElement("cockatrice_deck");
xml->writeAttribute("version", "1");
- metadata.write(xml);
+ writeMetadata(xml, metadata);
// Write zones
tree.write(xml);
@@ -210,27 +172,6 @@ void DeckList::write(QXmlStreamWriter *xml) const
xml->writeEndElement(); // Close "cockatrice_deck"
}
-bool DeckList::seekToNextElement(QXmlStreamReader *xml)
-{
- while (!xml->atEnd()) {
- xml->readNext();
- if (xml->isStartElement()) {
- return true;
- }
- }
- return false;
-}
-
-void DeckList::readDeckBody(QXmlStreamReader *xml)
-{
- while (!xml->atEnd()) {
- xml->readNext();
- if (!readElement(xml)) {
- break;
- }
- }
-}
-
bool DeckList::loadFromXml(QXmlStreamReader *xml)
{
if (xml->error()) {
@@ -239,11 +180,19 @@ bool DeckList::loadFromXml(QXmlStreamReader *xml)
}
cleanList();
- while (seekToNextElement(xml)) {
- if (xml->name().toString() != "cockatrice_deck") {
- return false;
+ while (!xml->atEnd()) {
+ xml->readNext();
+ if (xml->isStartElement()) {
+ if (xml->name().toString() != "cockatrice_deck") {
+ return false;
+ }
+ while (!xml->atEnd()) {
+ xml->readNext();
+ if (!readElement(xml)) {
+ break;
+ }
+ }
}
- readDeckBody(xml);
}
refreshDeckHash();
if (xml->error()) {
@@ -299,12 +248,160 @@ bool DeckList::loadFromStream_Plain(QTextStream &in,
bool preserveMetadata,
const std::function &cardNameNormalizer)
{
- if (!preserveMetadata) {
- metadata = {};
+ const QRegularExpression reCardLine(R"(^\s*[\w\[\(\{].*$)", QRegularExpression::UseUnicodePropertiesOption);
+ const QRegularExpression reEmpty("^\\s*$");
+ const QRegularExpression reComment(R"([\w\[\(\{].*$)", QRegularExpression::UseUnicodePropertiesOption);
+ const QRegularExpression reSBMark("^\\s*sb:\\s*(.+)", QRegularExpression::CaseInsensitiveOption);
+ const QRegularExpression reSBComment("^sideboard\\b.*$", QRegularExpression::CaseInsensitiveOption);
+ const QRegularExpression reDeckComment("^((main)?deck(list)?|mainboard)\\b",
+ QRegularExpression::CaseInsensitiveOption);
+
+ // Regex for advanced card parsing
+ const QRegularExpression reMultiplier(R"(^[xX\(\[]*(\d+)[xX\*\)\]]* ?(.+))");
+
+ // Regex for extracting set code and collector number with attached symbols
+ const QRegularExpression reHyphenFormat(R"(\((\w{3,})\)\s+(\w{3,})-(\d+[^\w\s]*))");
+ const QRegularExpression reRegularFormat(R"(\((\w{3,})\)\s+(\d+[^\w\s]*))");
+
+ cleanList(preserveMetadata);
+
+ auto inputs = in.readAll().trimmed().split('\n');
+ auto max_line = inputs.size();
+
+ // Start at the first empty line before the first card line
+ auto deckStart = inputs.indexOf(reCardLine);
+ if (deckStart == -1) {
+ if (inputs.indexOf(reComment) == -1) {
+ return false; // Input is empty
+ }
+ deckStart = max_line;
+ } else {
+ deckStart = inputs.lastIndexOf(reEmpty, deckStart);
+ if (deckStart == -1) {
+ deckStart = 0;
+ }
}
- bool ok = DeckListPlainText::parse(in, cardNameNormalizer, metadata, tree);
+
+ // find sideboard position, if marks are used this won't be needed
+ int sBStart = -1;
+ if (inputs.indexOf(reSBMark, deckStart) == -1) {
+ sBStart = inputs.indexOf(reSBComment, deckStart);
+ if (sBStart == -1) {
+ sBStart = inputs.indexOf(reEmpty, deckStart + 1);
+ if (sBStart == -1) {
+ sBStart = max_line;
+ }
+ auto nextCard = inputs.indexOf(reCardLine, sBStart + 1);
+ if (inputs.indexOf(reEmpty, nextCard + 1) != -1) {
+ sBStart = max_line;
+ }
+ }
+ }
+
+ int index = 0;
+ QRegularExpressionMatch match;
+
+ // Parse name and comments
+ while (index < deckStart) {
+ const auto ¤t = inputs.at(index++);
+ if (!current.contains(reEmpty)) {
+ match = reComment.match(current);
+ metadata.name = match.captured();
+ break;
+ }
+ }
+ while (index < deckStart) {
+ const auto ¤t = inputs.at(index++);
+ if (!current.contains(reEmpty)) {
+ match = reComment.match(current);
+ metadata.comments += match.captured() + '\n';
+ }
+ }
+ metadata.comments.chop(1);
+
+ // Discard empty lines
+ while (index < max_line && inputs.at(index).contains(reEmpty)) {
+ ++index;
+ }
+
+ // Discard line if it starts with deck or mainboard, all cards until the sideboard starts are in the mainboard
+ if (inputs.at(index).contains(reDeckComment)) {
+ ++index;
+ }
+
+ // Parse decklist
+ for (; index < max_line; ++index) {
+ // check if line is a card
+ match = reCardLine.match(inputs.at(index));
+ if (!match.hasMatch()) {
+ continue;
+ }
+
+ QString cardName = match.captured().simplified();
+ bool sideboard = false;
+
+ // Sideboard detection
+ if (sBStart < 0) {
+ match = reSBMark.match(cardName);
+ if (match.hasMatch()) {
+ sideboard = true;
+ cardName = match.captured(1);
+ }
+ } else {
+ if (index == sBStart) {
+ continue;
+ }
+ sideboard = index > sBStart;
+ }
+
+ // Extract set code, collector number, and foil
+ QString setCode;
+ QString collectorNumber;
+ bool isFoil = false;
+
+ // Check for foil status at the end of the card name
+ if (cardName.endsWith("*F*", Qt::CaseInsensitive)) {
+ isFoil = true;
+ cardName.chop(3); // Remove the "*F*" from the card name
+ }
+ Q_UNUSED(isFoil);
+
+ // Attempt to match the hyphen-separated format (PLST-2094)
+ match = reHyphenFormat.match(cardName);
+ if (match.hasMatch()) {
+ setCode = match.captured(2).toUpper();
+ collectorNumber = match.captured(3);
+ cardName = cardName.left(match.capturedStart()).trimmed();
+ } else {
+ // Attempt to match the regular format (PLST) 2094
+ match = reRegularFormat.match(cardName);
+ if (match.hasMatch()) {
+ setCode = match.captured(1).toUpper();
+ collectorNumber = match.captured(2);
+ cardName = cardName.left(match.capturedStart()).trimmed();
+ }
+ }
+
+ // check if a specific amount is mentioned
+ int amount = 1;
+ match = reMultiplier.match(cardName);
+ if (match.hasMatch()) {
+ amount = match.captured(1).toInt();
+ cardName = match.captured(2);
+ }
+
+ // Normalize the card name
+ cardName = cardNameNormalizer(cardName);
+
+ // Determine the zone (mainboard/sideboard)
+ QString zoneName = sideboard ? DECK_ZONE_SIDE : DECK_ZONE_MAIN;
+
+ // make new entry in decklist
+ tree.addCard(cardName, amount, zoneName, -1, setCode, collectorNumber);
+ }
+
refreshDeckHash();
- return ok;
+ return true;
}
bool DeckList::loadFromFile_Plain(QIODevice *device, const std::function &cardNameNormalizer)
diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.h b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.h
index 199d3a9a8..475d99560 100644
--- a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.h
+++ b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.h
@@ -76,23 +76,6 @@ public:
* @brief Checks if all values (except for lastLoadedTimestamp) in the metadata is empty.
*/
bool isEmpty() const;
-
- /**
- * @brief Reads a single deck metadata element from a Cockatrice deck XML stream.
- *
- * @param xml Reader positioned at the element.
- * @param childName Name of the current element.
- * @return true if a metadata element was consumed, false if @p childName is
- * not a metadata element.
- */
- bool readElement(QXmlStreamReader *xml, const QString &childName);
-
- /**
- * @brief Writes the deck metadata section of a Cockatrice deck XML file.
- *
- * @param xml Writer to append the metadata elements to.
- */
- void write(QXmlStreamWriter *xml) const;
};
private:
@@ -106,22 +89,6 @@ private:
*/
mutable QString cachedDeckHash;
- /** @name XML load helpers */
- ///@{
- /**
- * @brief Advances to the next element in the XML stream.
- * @param xml Reader to advance past non-element tokens.
- * @return true when a start element was reached, false at end of stream.
- */
- bool seekToNextElement(QXmlStreamReader *xml);
-
- /**
- * @brief Reads the contents of a `cockatrice_deck` element into this deck.
- * @param xml Reader positioned at the deck element, stopped at its end.
- */
- void readDeckBody(QXmlStreamReader *xml);
- ///@}
-
public:
/** @name Metadata setters */
///@{
diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list_history_manager.cpp b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list_history_manager.cpp
index b6d0687b4..acf4707ab 100644
--- a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list_history_manager.cpp
+++ b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list_history_manager.cpp
@@ -14,32 +14,42 @@ void DeckListHistoryManager::clear()
emit undoRedoStateChanged();
}
-void DeckListHistoryManager::restoreAndSwap(QStack &source,
- QStack &target,
- DeckList *deck)
+void DeckListHistoryManager::undo(DeckList *deck)
{
- if (source.isEmpty()) {
+ if (undoStack.isEmpty()) {
return;
}
- // The reason is read before the source is popped.
- const QString reason = source.top().getReason();
+ // Peek at the memento we are going to restore
+ const DeckListMemento &mementoToRestore = undoStack.top();
- // Save the current state so the opposite direction can return to it.
- target.push(deck->createMemento(reason));
+ // Save current state for redo
+ DeckListMemento currentState = deck->createMemento(mementoToRestore.getReason());
+ redoStack.push(currentState);
- // Apply the state we are moving to.
- deck->restoreMemento(source.pop());
+ // Pop the last state from undo stack and restore it
+ DeckListMemento memento = undoStack.pop();
+ deck->restoreMemento(memento);
emit undoRedoStateChanged();
}
-void DeckListHistoryManager::undo(DeckList *deck)
-{
- restoreAndSwap(undoStack, redoStack, deck);
-}
-
void DeckListHistoryManager::redo(DeckList *deck)
{
- restoreAndSwap(redoStack, undoStack, deck);
+ if (redoStack.isEmpty()) {
+ return;
+ }
+
+ // Peek at the memento we are going to restore
+ const DeckListMemento &mementoToRestore = redoStack.top();
+
+ // Save current state for undo
+ DeckListMemento currentState = deck->createMemento(mementoToRestore.getReason());
+ undoStack.push(currentState);
+
+ // Pop the next state from redo stack and restore it
+ DeckListMemento memento = redoStack.pop();
+ deck->restoreMemento(memento);
+
+ emit undoRedoStateChanged();
}
diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list_history_manager.h b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list_history_manager.h
index 6acdb199e..e6bd27e2d 100644
--- a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list_history_manager.h
+++ b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list_history_manager.h
@@ -47,13 +47,6 @@ public:
}
private:
- /**
- * @brief Moves one state from @p source to @p target, applying it to @p deck.
- *
- * Used by both undo (undoStack -> redoStack) and redo (redoStack -> undoStack).
- */
- void restoreAndSwap(QStack &source, QStack &target, DeckList *deck);
-
QStack undoStack;
QStack redoStack;
};
diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list_node_tree.cpp b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list_node_tree.cpp
index 66f228d19..91fe1874b 100644
--- a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list_node_tree.cpp
+++ b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list_node_tree.cpp
@@ -7,84 +7,6 @@
static constexpr int MAX_DECK_SIZE = 1e5;
-namespace
-{
-
-/**
- * @brief Expands card nodes into one lowercase name entry per copy.
- *
- * @param nodes The card nodes to expand.
- * @param prefix Optional prefix prepended to every entry (e.g. "SB:" for the sideboard).
- * @return One entry per copy, in node order.
- */
-QStringList cardNodesToCopies(const QList &nodes, const QString &prefix = {})
-{
- QStringList result;
- for (auto node : nodes) {
- for (int i = 0; i < node->getNumber(); ++i) {
- result.append(prefix + node->getName().toLower());
- }
- }
- return result;
-}
-
-/**
- * @brief Packs the first five bytes of a SHA-1 digest into a compact base-32 number.
- *
- * The bytes are placed in most-significant-byte-first order (byte 0 shifted by 32,
- * byte 4 unshifted) so decks that only differ in their low-order hash bytes still
- * produce distinct identifiers.
- *
- * @return The 8-character base-32 representation of the packed number.
- */
-QString encodeDeckHash(const QByteArray &digest)
-{
- quint64 number = 0;
- for (int i = 0; i < 5; ++i) {
- number |= static_cast(static_cast(digest[i])) << (32 - 8 * i);
- }
- return QString::number(number, 32).rightJustified(8, '0');
-}
-
-/**
- * @brief Collects every card node in @p node's subtree, in tree order.
- *
- * @return The collected card nodes.
- */
-QList collectCardsRecursive(const InnerDecklistNode *node)
-{
- QList result;
- for (int i = 0; i < node->size(); i++) {
- if (auto *card = dynamic_cast(node->at(i))) {
- result.append(card);
- } else if (auto *inner = dynamic_cast(node->at(i))) {
- result.append(collectCardsRecursive(inner));
- }
- }
- return result;
-}
-
-/**
- * @brief Invokes @p func on every card in @p node's subtree.
- *
- * Cards nested in custom zones are reported with their top-level @p boardZone
- * so that callers can classify cards by board (main/side/maybeboard/tokens).
- */
-void forEachCardInNode(InnerDecklistNode *boardZone,
- InnerDecklistNode *node,
- const std::function &func)
-{
- for (int i = 0; i < node->size(); i++) {
- if (auto *card = dynamic_cast(node->at(i))) {
- func(boardZone, card);
- } else if (auto *inner = dynamic_cast(node->at(i))) {
- forEachCardInNode(boardZone, inner, func);
- }
- }
-}
-
-} // namespace
-
DecklistNodeTree::DecklistNodeTree() : root(new InnerDecklistNode())
{
}
@@ -121,8 +43,19 @@ QList DecklistNodeTree::getCardNodes(const QSet result;
+ std::function