diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml
index 6ca634389..b631f32d3 100644
--- a/.github/workflows/desktop-build.yml
+++ b/.github/workflows/desktop-build.yml
@@ -152,7 +152,7 @@ jobs:
env:
CACHE: ${{ github.workspace }}/.cache/${{ matrix.distro }}${{ matrix.version }} # directory for caching docker image and ccache
CCACHE_EVICTION_AGE: 7d
- CCACHE_SIZE: 600M # space of all repo is 10Gi: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
+ CCACHE_SIZE: 550M # space of all repo is 10Gi: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
CMAKE_GENERATOR: 'Ninja'
NAME: ${{ matrix.distro }}${{ matrix.version }}
@@ -342,7 +342,7 @@ jobs:
timeout-minutes: 100
env:
CCACHE_DIR: ${{ github.workspace }}/.cache/
- CCACHE_SIZE: 600M # space of all repo is 10Gi: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
+ CCACHE_SIZE: 550M # space of all repo is 10Gi: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
steps:
- name: "Checkout"
diff --git a/README.md b/README.md
index 5935bb540..f22df461f 100644
--- a/README.md
+++ b/README.md
@@ -149,15 +149,15 @@ You can then
The following flags (with their non-default values) can be passed to `cmake`:
-| Flag | Description |
-| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
-| `-DWITH_SERVER=1` | Build Servatrice server |
-| `-DWITH_CLIENT=0` | Don't build Cockatrice client |
-| `-DWITH_ORACLE=0` | Don't build Oracle card database tool |
-| `-DCMAKE_BUILD_TYPE=Debug` | Compile in debug mode
Enables extra logging output, debug symbols, and much more verbose compiler warnings |
-| `-DWARNING_AS_ERROR=0` | Don't treat compilation warnings as errors in debug mode |
-| `-DUPDATE_TRANSLATIONS=1` | Configure `make` to update the translation .ts files for new strings in the source code
**Note:** `make clean` will remove the .ts files |
-| `-DTEST=1` | Enable regression tests
**Note:** `make test` to run tests, *googletest* will be downloaded if not available |
+| Flag | Description |
+| --- | --- |
+| `-DWITH_SERVER=1` | Build Servatrice server |
+| `-DWITH_CLIENT=0` | Don't build Cockatrice client |
+| `-DWITH_ORACLE=0` | Don't build Oracle card database tool |
+| `-DCMAKE_BUILD_TYPE=Debug` | Compile in debug mode
Enables extra logging output, debug symbols, and much more verbose compiler warnings |
+| `-DWARNING_AS_ERROR=0` | Don't treat compilation warnings as errors in debug mode |
+| `-DUPDATE_TRANSLATIONS=1` | Configure `make` to update the translation .ts files for new strings in the source code
**Note:** `make clean` will remove the .ts files |
+| `-DTEST=1` | Enable regression tests
**Note:** `make test` to run tests, *googletest* will be downloaded if not available |
# Run
diff --git a/cmake/FindQtRuntime.cmake b/cmake/FindQtRuntime.cmake
index 971c9094d..0259d12e1 100644
--- a/cmake/FindQtRuntime.cmake
+++ b/cmake/FindQtRuntime.cmake
@@ -28,7 +28,7 @@ if(WITH_CLIENT)
)
endif()
if(WITH_ORACLE)
- set(_ORACLE_NEEDED Concurrent Network Svg Widgets Xml)
+ set(_ORACLE_NEEDED Concurrent Network Svg Widgets)
endif()
if(TEST)
# Union of Qt modules required across all test targets (independent of application targets).
diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt
index cfc684d5f..524497098 100644
--- a/cockatrice/CMakeLists.txt
+++ b/cockatrice/CMakeLists.txt
@@ -173,7 +173,6 @@ set(cockatrice_SOURCES
src/interface/widgets/cards/additional_info/mana_cost_widget.cpp
src/interface/widgets/cards/additional_info/mana_symbol_widget.cpp
src/interface/widgets/cards/art_crop_attribution.cpp
- src/interface/widgets/cards/card_art_utils.cpp
src/interface/widgets/cards/card_group_display_widgets/card_group_display_widget.cpp
src/interface/widgets/cards/card_group_display_widgets/flat_card_group_display_widget.cpp
src/interface/widgets/cards/card_group_display_widgets/overlapped_card_group_display_widget.cpp
@@ -389,7 +388,6 @@ set(cockatrice_SOURCES
src/interface/widgets/tabs/tab_card_art_rules.cpp
src/interface/widgets/tabs/tab_deck_editor.cpp
src/interface/widgets/tabs/tab_deck_storage.cpp
- src/interface/widgets/tabs/tab_developer.cpp
src/interface/widgets/tabs/tab_game.cpp
src/interface/widgets/tabs/tab_home.cpp
src/interface/widgets/tabs/tab_logs.cpp
@@ -410,7 +408,6 @@ set(cockatrice_SOURCES
src/interface/widgets/tabs/api/commander_spellbook/commander_bracket_widget.cpp
src/interface/widgets/tabs/api/commander_spellbook/handle_commander_brackets.cpp
src/interface/widgets/onboarding/banner_shader_config.h
- src/interface/widgets/onboarding/brand_colors.h
src/interface/widgets/onboarding/first_run_wizard.cpp
src/interface/widgets/onboarding/first_run_wizard.h
src/interface/widgets/onboarding/first_run_wizard_page.cpp
@@ -540,7 +537,6 @@ qt6_add_shaders(
"src/interface/widgets/onboarding/shaders"
FILES
src/interface/widgets/onboarding/shaders/brand_banner.frag
- src/interface/widgets/onboarding/shaders/brand_plate.frag
)
qt6_add_resources(
diff --git a/cockatrice/cockatrice.qrc b/cockatrice/cockatrice.qrc
index 14cf15b2f..e21bdb0be 100644
--- a/cockatrice/cockatrice.qrc
+++ b/cockatrice/cockatrice.qrc
@@ -63,8 +63,6 @@
resources/icons/mana/W.svg
resources/backgrounds/home.png
- resources/backgrounds/home-dark.png
- resources/backgrounds/home-light.png
resources/backgrounds/card_triplet.svg
resources/backgrounds/placeholder_printing_selector.svg
@@ -365,8 +363,6 @@
resources/usericons/pawn_single.svg
resources/usericons/pawn_double.svg
- resources/usericons/pawn_dev_single.svg
- resources/usericons/pawn_dev_double.svg
resources/usericons/pawn_donator_single.svg
resources/usericons/pawn_donator_double.svg
resources/usericons/pawn_judge_single.svg
diff --git a/cockatrice/resources/backgrounds/home-dark.png b/cockatrice/resources/backgrounds/home-dark.png
deleted file mode 100644
index 68f48e2c2..000000000
Binary files a/cockatrice/resources/backgrounds/home-dark.png and /dev/null differ
diff --git a/cockatrice/resources/backgrounds/home-light.png b/cockatrice/resources/backgrounds/home-light.png
deleted file mode 100644
index eaaaba932..000000000
Binary files a/cockatrice/resources/backgrounds/home-light.png and /dev/null differ
diff --git a/cockatrice/resources/backgrounds/home.png b/cockatrice/resources/backgrounds/home.png
index eaaaba932..68f48e2c2 100644
Binary files a/cockatrice/resources/backgrounds/home.png and b/cockatrice/resources/backgrounds/home.png differ
diff --git a/cockatrice/resources/usericons/pawn_dev_double.svg b/cockatrice/resources/usericons/pawn_dev_double.svg
deleted file mode 100644
index 57ed5c2da..000000000
--- a/cockatrice/resources/usericons/pawn_dev_double.svg
+++ /dev/null
@@ -1,343 +0,0 @@
-
-
-
-
diff --git a/cockatrice/resources/usericons/pawn_dev_single.svg b/cockatrice/resources/usericons/pawn_dev_single.svg
deleted file mode 100644
index f7c4e7018..000000000
--- a/cockatrice/resources/usericons/pawn_dev_single.svg
+++ /dev/null
@@ -1,211 +0,0 @@
-
-
-
-
diff --git a/cockatrice/src/client/network/connection_controller/remote_connection_controller.cpp b/cockatrice/src/client/network/connection_controller/remote_connection_controller.cpp
index c1598bd25..890a621c8 100644
--- a/cockatrice/src/client/network/connection_controller/remote_connection_controller.cpp
+++ b/cockatrice/src/client/network/connection_controller/remote_connection_controller.cpp
@@ -1,6 +1,5 @@
#include "remote_connection_controller.h"
-#include "../../../interface/pixel_map_generator.h"
#include "../../settings/cache_settings.h"
#include "../interface/widgets/dialogs/dlg_connect.h"
#include "../interface/widgets/dialogs/dlg_forgot_password_challenge.h"
@@ -181,7 +180,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("cockatrice")).scaled(64, 64));
+ serverShutdownMessageBox.setIconPixmap(QPixmap("theme:cockatrice").scaled(64, 64));
serverShutdownMessageBox.setText(tr("Scheduled server shutdown"));
serverShutdownMessageBox.setWindowModality(Qt::ApplicationModal);
serverShutdownMessageBox.setVisible(true);
diff --git a/cockatrice/src/client/sound_engine.cpp b/cockatrice/src/client/sound_engine.cpp
index 96cafa3d3..18de2264d 100644
--- a/cockatrice/src/client/sound_engine.cpp
+++ b/cockatrice/src/client/sound_engine.cpp
@@ -94,7 +94,7 @@ QStringMap &SoundEngine::getAvailableThemes()
QDir dir;
availableThemes.clear();
- // Load themes from user profile dir
+ // load themes from user profile dir
dir.setPath(SettingsCache::instance().getDataPath() + "/sounds");
@@ -104,7 +104,7 @@ QStringMap &SoundEngine::getAvailableThemes()
}
}
- // Load themes from Cockatrice system dir
+ // load themes from cockatrice system dir
dir.setPath(qApp->applicationDirPath() +
#ifdef Q_OS_MAC
"/../Resources/sounds"
diff --git a/cockatrice/src/filters/filter_builder.cpp b/cockatrice/src/filters/filter_builder.cpp
index f109fbcd3..785f753e7 100644
--- a/cockatrice/src/filters/filter_builder.cpp
+++ b/cockatrice/src/filters/filter_builder.cpp
@@ -1,6 +1,5 @@
#include "filter_builder.h"
-#include "../interface/pixel_map_generator.h"
#include "../interface/widgets/utility/custom_line_edit.h"
#include
@@ -22,7 +21,7 @@ FilterBuilder::FilterBuilder(QWidget *parent) : QWidget(parent)
typeCombo->addItem(CardFilter::typeName(static_cast(i)), QVariant(i));
}
- QPushButton *ok = new QPushButton(themePixmap(QStringLiteral("icons/increment")), QString());
+ QPushButton *ok = new QPushButton(QPixmap("theme:icons/increment"), QString());
ok->setObjectName("ok");
ok->setMaximumSize(20, 20);
diff --git a/cockatrice/src/game/board/counter_state.cpp b/cockatrice/src/game/board/counter_state.cpp
index 0970e4272..6da18b662 100644
--- a/cockatrice/src/game/board/counter_state.cpp
+++ b/cockatrice/src/game/board/counter_state.cpp
@@ -13,12 +13,12 @@ CounterState *CounterState::fromProto(const ServerInfo_Counter &counter, QObject
convertColorToQColor(counter.counter_color()), counter.radius(), counter.count(), parent);
}
-void CounterState::setValue(int newValue, bool skipDamageAnimation)
+void CounterState::setValue(int newValue)
{
if (newValue == value) {
return;
}
int old = value;
value = newValue;
- emit valueChanged(old, newValue, skipDamageAnimation);
+ emit valueChanged(old, newValue);
}
\ No newline at end of file
diff --git a/cockatrice/src/game/board/counter_state.h b/cockatrice/src/game/board/counter_state.h
index 4c7b34473..0f2f16b55 100644
--- a/cockatrice/src/game/board/counter_state.h
+++ b/cockatrice/src/game/board/counter_state.h
@@ -35,23 +35,10 @@ public:
return value;
}
- /**
- * @brief Set the counter value.
- * @param newValue The new value.
- * @param skipDamageAnimation When true, valueChanged is emitted with skipDamageAnimation=true, letting views
- * suppress damage-related feedback (e.g. battlefield shimmer, life counter flash) for values set during replay
- * rewinds.
- */
- void setValue(int newValue, bool skipDamageAnimation = false);
+ void setValue(int newValue);
signals:
- /**
- * @brief Emitted whenever the value changes.
- * @param oldValue The previous value.
- * @param newValue The new value.
- * @param skipDamageAnimation True when the change should not trigger damage/life-change feedback in views.
- */
- void valueChanged(int oldValue, int newValue, bool skipDamageAnimation);
+ void valueChanged(int oldValue, int newValue);
private:
int id;
diff --git a/cockatrice/src/game/game_event_handler.cpp b/cockatrice/src/game/game_event_handler.cpp
index f146cdbb4..bc68d4d7c 100644
--- a/cockatrice/src/game/game_event_handler.cpp
+++ b/cockatrice/src/game/game_event_handler.cpp
@@ -430,13 +430,12 @@ void GameEventHandler::eventJoin(const Event_Join &event, int /*eventPlayerId*/,
QString playerName = QString::fromStdString(playerInfo.user_info().name());
emit addPlayerToAutoCompleteList(playerName);
- PlayerManager *playerManager = game->getPlayerManager();
- if (playerManager->getPlayers().contains(playerId) || playerManager->getSpectators().contains(playerId)) {
+ if (game->getPlayerManager()->getPlayers().contains(playerId)) {
return;
}
if (playerInfo.spectator()) {
- playerManager->addSpectator(playerId, playerInfo);
+ game->getPlayerManager()->addSpectator(playerId, playerInfo);
emit logJoinSpectator(playerName);
emit spectatorJoined(playerInfo);
} else {
diff --git a/cockatrice/src/game/player/event_processing_options.h b/cockatrice/src/game/player/event_processing_options.h
index 06238d77e..4c7663789 100644
--- a/cockatrice/src/game/player/event_processing_options.h
+++ b/cockatrice/src/game/player/event_processing_options.h
@@ -13,8 +13,7 @@
enum EventProcessingOption
{
SKIP_REVEAL_WINDOW = 0x0001,
- SKIP_TAP_ANIMATION = 0x0002,
- SKIP_DAMAGE_ANIMATION = 0x0004
+ SKIP_TAP_ANIMATION = 0x0002
};
// Wrap it in a QFlags typedef
diff --git a/cockatrice/src/game/player/player_event_handler.cpp b/cockatrice/src/game/player/player_event_handler.cpp
index 277b8b1d4..bc48298f7 100644
--- a/cockatrice/src/game/player/player_event_handler.cpp
+++ b/cockatrice/src/game/player/player_event_handler.cpp
@@ -262,15 +262,14 @@ void PlayerEventHandler::eventCreateCounter(const Event_CreateCounter &event)
player->addCounter(event.counter_info());
}
-void PlayerEventHandler::eventSetCounter(const Event_SetCounter &event, EventProcessingOptions options)
+void PlayerEventHandler::eventSetCounter(const Event_SetCounter &event)
{
CounterState *ctr = player->getCounters().value(event.counter_id(), nullptr);
if (!ctr) {
return;
}
int oldValue = ctr->getValue();
- const bool skipDamageAnimation = options.testFlag(SKIP_DAMAGE_ANIMATION);
- ctr->setValue(event.value(), skipDamageAnimation);
+ ctr->setValue(event.value());
emit logSetCounter(player, ctr->getName(), event.value(), oldValue);
}
@@ -626,7 +625,7 @@ void PlayerEventHandler::processGameEvent(GameEvent::GameEventType type,
eventCreateCounter(event.GetExtension(Event_CreateCounter::ext));
break;
case GameEvent::SET_COUNTER:
- eventSetCounter(event.GetExtension(Event_SetCounter::ext), options);
+ eventSetCounter(event.GetExtension(Event_SetCounter::ext));
break;
case GameEvent::DEL_COUNTER:
eventDelCounter(event.GetExtension(Event_DelCounter::ext));
diff --git a/cockatrice/src/game/player/player_event_handler.h b/cockatrice/src/game/player/player_event_handler.h
index 300cacd08..48ad85e88 100644
--- a/cockatrice/src/game/player/player_event_handler.h
+++ b/cockatrice/src/game/player/player_event_handler.h
@@ -153,7 +153,7 @@ public:
void eventCreateCounter(const Event_CreateCounter &event);
/// Set a player-level counter value.
- void eventSetCounter(const Event_SetCounter &event, EventProcessingOptions options);
+ void eventSetCounter(const Event_SetCounter &event);
/// Delete a player-level counter.
void eventDelCounter(const Event_DelCounter &event);
diff --git a/cockatrice/src/game/player/player_logic.cpp b/cockatrice/src/game/player/player_logic.cpp
index 143df5c57..45ba09aac 100644
--- a/cockatrice/src/game/player/player_logic.cpp
+++ b/cockatrice/src/game/player/player_logic.cpp
@@ -175,15 +175,7 @@ void PlayerLogic::processPlayerInfo(const ServerInfo_Player &info)
const ServerInfo_Card &cardInfo = zoneInfo.card_list(j);
auto *card = new CardItem(this);
card->processCardInfo(cardInfo);
- // Zones without coordinates (hand, piles, stack) preserve the order
- // they arrive in on the server in the positions of their cards list.
- // The x coordinate of such cards is always 0, so inserting at it
- // would reverse the list on reconnect. Append instead.
- if (zoneInfo.with_coords()) {
- zone->addCard(card, false, cardInfo.x(), cardInfo.y());
- } else {
- zone->addCard(card, false, -1);
- }
+ zone->addCard(card, false, cardInfo.x(), cardInfo.y());
}
}
if (zoneInfo.has_always_reveal_top_card()) {
diff --git a/cockatrice/src/game/player/player_manager.cpp b/cockatrice/src/game/player/player_manager.cpp
index 8486efbeb..6772d3ff1 100644
--- a/cockatrice/src/game/player/player_manager.cpp
+++ b/cockatrice/src/game/player/player_manager.cpp
@@ -75,14 +75,6 @@ PlayerLogic *PlayerManager::getPlayer(int playerId) const
return player;
}
-void PlayerManager::clearSpectators()
-{
- const QList spectatorIds = spectators.keys();
- for (int spectatorId : spectatorIds) {
- removeSpectator(spectatorId);
- }
-}
-
void PlayerManager::onPlayerConceded(int playerId, bool conceded)
{
// Everything else cares about this
diff --git a/cockatrice/src/game/player/player_manager.h b/cockatrice/src/game/player/player_manager.h
index 504e65396..2f8b87af8 100644
--- a/cockatrice/src/game/player/player_manager.h
+++ b/cockatrice/src/game/player/player_manager.h
@@ -100,9 +100,6 @@ public:
emit spectatorRemoved(spectatorId, spectatorInfo);
}
- /** @brief Remove all spectators, emitting the removal signal for each. */
- void clearSpectators();
-
[[nodiscard]] AbstractGame *getGame() const
{
return game;
diff --git a/cockatrice/src/game_graphics/board/abstract_card_item.cpp b/cockatrice/src/game_graphics/board/abstract_card_item.cpp
index 3969b7d03..1410d0c80 100644
--- a/cockatrice/src/game_graphics/board/abstract_card_item.cpp
+++ b/cockatrice/src/game_graphics/board/abstract_card_item.cpp
@@ -1,7 +1,6 @@
#include "abstract_card_item.h"
#include "../../client/settings/cache_settings.h"
-#include "../../interface/card_localization.h"
#include "../../interface/card_picture_loader/card_picture_loader.h"
#include "../game_scene.h"
#include "../z_values.h"
@@ -27,8 +26,6 @@ AbstractCardItem::AbstractCardItem(QGraphicsItem *parent, const CardRef &cardRef
connect(&SettingsCache::instance().cardsDisplay(), &CardsDisplaySettings::displayCardNamesChanged, this,
[this] { update(); });
- connect(&SettingsCache::instance().cardsDisplay(), &CardsDisplaySettings::cardLangChanged, this,
- [this] { update(); });
refreshCardInfo();
connect(&SettingsCache::instance().cardsDisplay(), &CardsDisplaySettings::roundCardCornersChanged, this,
@@ -174,7 +171,7 @@ void AbstractCardItem::paintPicture(QPainter *painter, const QSizeF &translatedS
if (SettingsCache::instance().debug().getShowCardId()) {
prefix = "#" + QString::number(id) + " ";
}
- nameStr = prefix + CardLocalization::displayName(getCardInfo());
+ nameStr = prefix + cardRef.name;
}
painter->drawText(QRectF(3 * scaleFactor, 3 * scaleFactor, translatedSize.width() - 6 * scaleFactor,
translatedSize.height() - 6 * scaleFactor),
diff --git a/cockatrice/src/game_graphics/board/abstract_counter.cpp b/cockatrice/src/game_graphics/board/abstract_counter.cpp
index 4ba04804f..e63117e13 100644
--- a/cockatrice/src/game_graphics/board/abstract_counter.cpp
+++ b/cockatrice/src/game_graphics/board/abstract_counter.cpp
@@ -29,9 +29,9 @@ AbstractCounter::AbstractCounter(CounterState *state,
{
setAcceptHoverEvents(true);
- connect(state, &CounterState::valueChanged, this, [this](int oldValue, int newValue, bool skipDamageAnimation) {
+ connect(state, &CounterState::valueChanged, this, [this](int oldValue, int newValue) {
value = newValue;
- onValueChanged(oldValue, newValue, skipDamageAnimation);
+ onValueChanged(oldValue, newValue);
update();
});
@@ -230,7 +230,7 @@ void AbstractCounterDialog::changeValue(int diff)
setTextValue(QString::number(curValue));
}
-void AbstractCounter::onValueChanged(int /*oldValue*/, int /*newValue*/, bool /*skipDamageAnimation*/)
+void AbstractCounter::onValueChanged(int /*oldValue*/, int /*newValue*/)
{
// Default: no feedback. Subclasses such as PlayerCounter override this to
// flash the counter on meaningful changes (life gain/loss).
diff --git a/cockatrice/src/game_graphics/board/abstract_counter.h b/cockatrice/src/game_graphics/board/abstract_counter.h
index 67b5b4074..9ddcc6d58 100644
--- a/cockatrice/src/game_graphics/board/abstract_counter.h
+++ b/cockatrice/src/game_graphics/board/abstract_counter.h
@@ -39,9 +39,8 @@ protected:
* @brief Hook for subclasses that need per-value-change feedback (e.g. life-total flash).
*
* Called whenever the counter's value changes, before the item repaints.
- * @param skipDamageAnimation True when damage-related feedback should be suppressed (replay rewinds).
*/
- virtual void onValueChanged(int oldValue, int newValue, bool skipDamageAnimation);
+ virtual void onValueChanged(int oldValue, int newValue);
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
diff --git a/cockatrice/src/game_graphics/board/card_item.cpp b/cockatrice/src/game_graphics/board/card_item.cpp
index c2dc455cc..c40c8c214 100644
--- a/cockatrice/src/game_graphics/board/card_item.cpp
+++ b/cockatrice/src/game_graphics/board/card_item.cpp
@@ -316,7 +316,7 @@ void CardItem::drawAttachArrow()
for (const auto &item : scene()->selectedItems()) {
CardItem *card = qgraphicsitem_cast(item);
- if (card == nullptr || card == this) {
+ if (card == nullptr) {
continue;
}
if (card->getZone() != state->getZone()) {
diff --git a/cockatrice/src/game_graphics/game_scene.cpp b/cockatrice/src/game_graphics/game_scene.cpp
index 17af7618b..457f1b3f7 100644
--- a/cockatrice/src/game_graphics/game_scene.cpp
+++ b/cockatrice/src/game_graphics/game_scene.cpp
@@ -221,12 +221,7 @@ void GameScene::removePlayer(PlayerLogic *player)
clearArrowsForPlayer(player->getPlayerInfo()->getId());
- // Closing a view removes it from zoneViews synchronously, so iterate over a
- // copy: otherwise a player with several open views (e.g. library and hand)
- // only has the first one closed here and the remaining views are left
- // pointing at a player that is about to be deleted.
- const QList zoneViewCopy = zoneViews;
- for (ZoneViewWidget *zone : zoneViewCopy) {
+ for (ZoneViewWidget *zone : zoneViews) {
if (zone->getPlayer() == player) {
zone->close();
}
@@ -669,10 +664,7 @@ CardItem *GameScene::findTopmostCardInZone(const QList &items,
*/
void GameScene::toggleZoneView(PlayerLogic *player, const QString &zoneName, int numberCards, bool isReversed)
{
- // Closing a view removes it from zoneViews synchronously, so iterate over a
- // copy to make sure every already-open matching view is closed.
- const QList zoneViewCopy = zoneViews;
- for (auto *view : zoneViewCopy) {
+ for (auto &view : zoneViews) {
ZoneViewZone *temp = view->getZone();
if (temp->getLogic()->getName() == zoneName && temp->getLogic()->getPlayer() == player &&
qobject_cast(temp->getLogic())->getNumberCards() == numberCards) {
diff --git a/cockatrice/src/game_graphics/hand_counter.cpp b/cockatrice/src/game_graphics/hand_counter.cpp
index 8dcbcfdaa..35989ff38 100644
--- a/cockatrice/src/game_graphics/hand_counter.cpp
+++ b/cockatrice/src/game_graphics/hand_counter.cpp
@@ -1,6 +1,5 @@
#include "hand_counter.h"
-#include "../interface/pixel_map_generator.h"
#include "zones/card_zone.h"
#include
@@ -33,8 +32,7 @@ void HandCounter::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*op
QSize translatedSize = painter->combinedTransform().mapRect(boundingRect()).size().toSize();
QPixmap cachedPixmap;
if (!QPixmapCache::find("handCounter" + QString::number(translatedSize.width()), &cachedPixmap)) {
- cachedPixmap =
- themePixmap(QStringLiteral("hand")).scaled(translatedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
+ cachedPixmap = QPixmap("theme:hand").scaled(translatedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
QPixmapCache::insert("handCounter" + QString::number(translatedSize.width()), cachedPixmap);
}
resetPainterTransform(painter);
diff --git a/cockatrice/src/game_graphics/player/player_graphics_item.cpp b/cockatrice/src/game_graphics/player/player_graphics_item.cpp
index 122ab83be..8bf2703e1 100644
--- a/cockatrice/src/game_graphics/player/player_graphics_item.cpp
+++ b/cockatrice/src/game_graphics/player/player_graphics_item.cpp
@@ -3,7 +3,6 @@
#include "../../game/player/player_actions.h"
#include "../../interface/card_picture_loader/card_picture_loader.h"
#include "../../interface/widgets/cards/art_crop_attribution.h"
-#include "../../interface/widgets/cards/card_art_utils.h"
#include "../../interface/widgets/playmat/playmat_utils.h"
#include "../../interface/widgets/tabs/tab_game.h"
#include "../board/abstract_card_item.h"
@@ -252,8 +251,8 @@ void PlayerGraphicsItem::onCounterAdded(CounterState *state)
AbstractCounter *widget;
if (state->getName() == "life") {
widget = playerTarget->addCounter(state);
- connect(state, &CounterState::valueChanged, this, [this](int oldValue, int newValue, bool skipDamageAnimation) {
- if (newValue < oldValue && !skipDamageAnimation) {
+ connect(state, &CounterState::valueChanged, this, [this](int oldValue, int newValue) {
+ if (newValue < oldValue) {
tableZoneGraphicsItem->triggerDamageShimmer();
}
});
@@ -443,7 +442,7 @@ void PlayerGraphicsItem::updatePlaymat()
hasPlaymat = true;
emit playmatChanged(true);
}
- playmatPixmap = CardArtUtils::rotateSidewaysLayoutArt(fullRes, card);
+ playmatPixmap = fullRes;
update();
}
diff --git a/cockatrice/src/game_graphics/player/player_list_widget.cpp b/cockatrice/src/game_graphics/player/player_list_widget.cpp
index a7ec2e4a9..4268e1019 100644
--- a/cockatrice/src/game_graphics/player/player_list_widget.cpp
+++ b/cockatrice/src/game_graphics/player/player_list_widget.cpp
@@ -53,13 +53,13 @@ PlayerListWidget::PlayerListWidget(TabSupervisor *_tabSupervisor,
QWidget *parent)
: QTreeWidget(parent), tabSupervisor(_tabSupervisor), client(_client), game(_game), gameStarted(false)
{
- readyIcon = themePixmap(QStringLiteral("icons/ready_start"));
- notReadyIcon = themePixmap(QStringLiteral("icons/not_ready_start"));
- concededIcon = themePixmap(QStringLiteral("icons/conceded"));
+ readyIcon = QPixmap("theme:icons/ready_start");
+ notReadyIcon = QPixmap("theme:icons/not_ready_start");
+ concededIcon = QPixmap("theme:icons/conceded");
playerIcon = loadColorAdjustedPixmap("theme:icons/player");
judgeIcon = loadColorAdjustedPixmap("theme:icons/scales");
spectatorIcon = loadColorAdjustedPixmap("theme:icons/spectator");
- lockIcon = themePixmap(QStringLiteral("icons/lock"));
+ lockIcon = QPixmap("theme:icons/lock");
if (tabSupervisor) {
itemDelegate = new PlayerListItemDelegate(this);
@@ -92,11 +92,6 @@ void PlayerListWidget::retranslateUi()
void PlayerListWidget::addPlayer(const ServerInfo_PlayerProperties &player)
{
- if (players.contains(player.player_id())) {
- updatePlayerProperties(player);
- return;
- }
-
QTreeWidgetItem *newPlayer = new PlayerListTWI;
players.insert(player.player_id(), newPlayer);
updatePlayerProperties(player);
@@ -181,17 +176,6 @@ void PlayerListWidget::removePlayer(int playerId)
delete takeTopLevelItem(indexOfTopLevelItem(player));
}
-void PlayerListWidget::clearSpectators()
-{
- const QList playerIds = players.keys();
- for (int playerId : playerIds) {
- QTreeWidgetItem *player = players.value(playerId, 0);
- if (player && !player->data(1, Qt::UserRole).toBool()) {
- removePlayer(playerId);
- }
- }
-}
-
void PlayerListWidget::setActivePlayer(int playerId)
{
QMapIterator i(players);
diff --git a/cockatrice/src/game_graphics/player/player_list_widget.h b/cockatrice/src/game_graphics/player/player_list_widget.h
index f2f0be5fd..a53cfa989 100644
--- a/cockatrice/src/game_graphics/player/player_list_widget.h
+++ b/cockatrice/src/game_graphics/player/player_list_widget.h
@@ -66,7 +66,6 @@ public slots:
void addPlayer(const ServerInfo_PlayerProperties &player);
void removePlayer(int playerId);
void updatePlayerProperties(const ServerInfo_PlayerProperties &prop, int playerId = -1);
- void clearSpectators();
};
#endif
diff --git a/cockatrice/src/game_graphics/player/player_target.cpp b/cockatrice/src/game_graphics/player/player_target.cpp
index d6c28370d..910ee9c17 100644
--- a/cockatrice/src/game_graphics/player/player_target.cpp
+++ b/cockatrice/src/game_graphics/player/player_target.cpp
@@ -69,7 +69,7 @@ void PlayerCounter::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*
}
}
-void PlayerCounter::onValueChanged(int oldValue, int newValue, bool skipDamageAnimation)
+void PlayerCounter::onValueChanged(int oldValue, int newValue)
{
flashDelta = newValue - oldValue;
if (flashDelta == 0) {
@@ -81,11 +81,6 @@ void PlayerCounter::onValueChanged(int oldValue, int newValue, bool skipDamageAn
return;
}
- if (skipDamageAnimation) {
- flashAlpha = 0.0;
- return;
- }
-
flashAlpha = 1.0;
flashClock.start();
if (scene()) {
@@ -137,18 +132,8 @@ void PlayerTarget::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*o
QRectF translatedRect = painter->combinedTransform().mapRect(avatarBoundingRect);
QSize translatedSize = translatedRect.size().toSize();
QPixmap cachedPixmap;
- // The key must cover everything the generated pawn depends on: the rendered
- // size, the user level, and the pixmap being drawn. fullPixmap.cacheKey() is
- // 0 for every null pixmap, so the default-pawn branch additionally needs the
- // pawn's privlevel (lowercased, matching UserLevelPixmapGenerator) and colors
- // in the key — otherwise two players without a custom avatar (and the same
- // user level) would share one cached pawn.
const QString cacheKey = "avatar" + QString::number(translatedSize.width()) + "_" +
- QString::number(translatedSize.height()) + "_" + QString::number(info->user_level()) +
- "_" + QString::number(fullPixmap.cacheKey()) + "_" +
- QString::fromStdString(info->privlevel()).toLower() + "_" +
- QString::fromStdString(info->pawn_colors().left_side()) + "_" +
- QString::fromStdString(info->pawn_colors().right_side());
+ QString::number(info->user_level()) + "_" + QString::number(fullPixmap.cacheKey());
if (!QPixmapCache::find(cacheKey, &cachedPixmap)) {
cachedPixmap = QPixmap(translatedSize.width(), translatedSize.height());
diff --git a/cockatrice/src/game_graphics/player/player_target.h b/cockatrice/src/game_graphics/player/player_target.h
index 1d06c6274..af0e9c8b7 100644
--- a/cockatrice/src/game_graphics/player/player_target.h
+++ b/cockatrice/src/game_graphics/player/player_target.h
@@ -21,7 +21,7 @@ class PlayerCounter : public AbstractCounter, public IAnimatedItem
{
Q_OBJECT
protected:
- void onValueChanged(int oldValue, int newValue, bool skipDamageAnimation) override;
+ void onValueChanged(int oldValue, int newValue) override;
private:
static constexpr qreal flashDurationMs = 450.0;
diff --git a/cockatrice/src/game_graphics/zones/view_zone_widget.cpp b/cockatrice/src/game_graphics/zones/view_zone_widget.cpp
index c13b79fea..17118e80d 100644
--- a/cockatrice/src/game_graphics/zones/view_zone_widget.cpp
+++ b/cockatrice/src/game_graphics/zones/view_zone_widget.cpp
@@ -62,7 +62,7 @@ ZoneViewWidget::ZoneViewWidget(PlayerLogic *_player,
searchEdit.setPlaceholderText(tr("Search by card name (or search expressions)"));
searchEdit.setClearButtonEnabled(true);
searchEdit.addAction(loadColorAdjustedPixmap("theme:icons/search"), QLineEdit::LeadingPosition);
- auto help = searchEdit.addAction(themePixmap(QStringLiteral("icons/info")), QLineEdit::TrailingPosition);
+ auto help = searchEdit.addAction(QPixmap("theme:icons/info"), QLineEdit::TrailingPosition);
connect(help, &QAction::triggered, this, [this] { createSearchSyntaxHelpWindow(&searchEdit); });
@@ -549,7 +549,7 @@ void ZoneViewWidget::initStyleOption(QStyleOption *option) const
{
QStyleOptionTitleBar *titleBar = qstyleoption_cast(option);
if (titleBar) {
- titleBar->icon = themePixmap(QStringLiteral("cockatrice"));
+ titleBar->icon = QPixmap("theme:cockatrice");
}
}
diff --git a/cockatrice/src/interface/card_localization.h b/cockatrice/src/interface/card_localization.h
deleted file mode 100644
index 0bfe4a764..000000000
--- a/cockatrice/src/interface/card_localization.h
+++ /dev/null
@@ -1,59 +0,0 @@
-#ifndef COCKATRICE_CARD_LOCALIZATION_H
-#define COCKATRICE_CARD_LOCALIZATION_H
-
-#include "../client/settings/cache_settings.h"
-
-#include
-#include
-#include
-
-namespace CardLocalization
-{
-/**
- * @brief The language code selected for localized card text and images.
- */
-inline QString displayLang()
-{
- return SettingsCache::instance().cardsDisplay().getCardLang();
-}
-
-/**
- * @brief Card name in the configured display language, falling back to English.
- * @param card The card to display.
- * @return The localized name, or an empty string for a null card.
- */
-inline QString displayName(const CardInfoPtr &card)
-{
- return card.isNull() ? QString() : card->getLocalizedName(displayLang());
-}
-
-/**
- * @brief Card rules text in the configured display language, falling back to English.
- * @param card The card to display.
- * @return The localized text, or an empty string for a null card.
- */
-inline QString displayText(const CardInfoPtr &card)
-{
- return card.isNull() ? QString() : card->getLocalizedText(displayLang());
-}
-
-/**
- * @brief Card name in the configured display language, falling back to English.
- * @param card The card to display.
- */
-inline QString displayName(const CardInfo &card)
-{
- return card.getLocalizedName(displayLang());
-}
-
-/**
- * @brief Card rules text in the configured display language, falling back to English.
- * @param card The card to display.
- */
-inline QString displayText(const CardInfo &card)
-{
- return card.getLocalizedText(displayLang());
-}
-} // namespace CardLocalization
-
-#endif // COCKATRICE_CARD_LOCALIZATION_H
\ No newline at end of file
diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader.cpp b/cockatrice/src/interface/card_picture_loader/card_picture_loader.cpp
index b8a54761a..2f46e7941 100644
--- a/cockatrice/src/interface/card_picture_loader/card_picture_loader.cpp
+++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader.cpp
@@ -1,14 +1,13 @@
#include "card_picture_loader.h"
#include "../../client/settings/cache_settings.h"
-#include "../pixel_map_generator.h"
#include "card_picture_loader_cache_method.h"
#include "card_picture_loader_local_schemes.h"
#include
#include
#include
-#include
+#include
#include
#include
#include
@@ -20,7 +19,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -38,10 +36,8 @@ CardPictureLoader::CardPictureLoader() : QObject(nullptr)
&CardPictureLoader::picsPathChanged);
connect(&SettingsCache::instance().downloads(), &DownloadSettings::picDownloadChanged, this,
&CardPictureLoader::picDownloadChanged);
- connect(&SettingsCache::instance().cardsDisplay(), &CardsDisplaySettings::cardLangChanged, this,
- &CardPictureLoader::cardLangChanged);
- qRegisterMetaType("ExactCard");
+ qRegisterMetaType();
connect(worker, &CardPictureLoaderWorker::imageLoaded, this, &CardPictureLoader::imageLoaded);
statusBar = new CardPictureLoaderStatusBar(nullptr);
@@ -66,7 +62,7 @@ void CardPictureLoader::getCardBackPixmap(QPixmap &pixmap, QSize size)
QString backCacheKey = "_trice_card_back_" + QString::number(size.width()) + "x" + QString::number(size.height());
if (!QPixmapCache::find(backCacheKey, &pixmap)) {
qCDebug(CardPictureLoaderLog) << "PictureLoader: cache miss for" << backCacheKey;
- QPixmap tmpPixmap = themePixmap(QStringLiteral("cardback"));
+ QPixmap tmpPixmap("theme:cardback");
if (tmpPixmap.isNull()) {
qCWarning(CardPictureLoaderLog) << "Failed to load 'theme:cardback'! Using fallback pixmap.";
@@ -87,7 +83,7 @@ void CardPictureLoader::getCardBackLoadingInProgressPixmap(QPixmap &pixmap, QSiz
"_trice_card_back_inprogress_" + QString::number(size.width()) + "x" + QString::number(size.height());
if (!QPixmapCache::find(backCacheKey, &pixmap)) {
qCDebug(CardPictureLoaderCardBackCacheFailLog) << "PictureLoader: cache miss for" << backCacheKey;
- QPixmap tmpPixmap = themePixmap(QStringLiteral("cardback"));
+ QPixmap tmpPixmap("theme:cardback");
if (tmpPixmap.isNull()) {
qCWarning(CardPictureLoaderLog) << "Failed to load 'theme:cardback' for in-progress state! Using fallback.";
@@ -109,7 +105,7 @@ void CardPictureLoader::getCardBackLoadingFailedPixmap(QPixmap &pixmap, QSize si
"_trice_card_back_failed_" + QString::number(size.width()) + "x" + QString::number(size.height());
if (!QPixmapCache::find(backCacheKey, &pixmap)) {
qCDebug(CardPictureLoaderCardBackCacheFailLog) << "PictureLoader: cache miss for" << backCacheKey;
- QPixmap tmpPixmap = themePixmap(QStringLiteral("cardback"));
+ QPixmap tmpPixmap("theme:cardback");
if (tmpPixmap.isNull()) {
qCWarning(CardPictureLoaderLog) << "Failed to load 'theme:cardback' for failed state! Using fallback.";
@@ -142,8 +138,7 @@ void CardPictureLoader::getPixmap(QPixmap &pixmap, const ExactCard &card, QSize
QPixmap bigPixmap;
if (QPixmapCache::find(key, &bigPixmap)) {
if (bigPixmap.isNull()) {
- // Leave the pixmap null so callers fall back to a solid color
- // instead of showing the card back.
+ getCardBackLoadingFailedPixmap(pixmap, size);
QDateTime failedAtTime = getInstance().failedAt.value(key);
if (!failedAtTime.isValid() ||
failedAtTime.addSecs(RETRY_FAILED_CARDS_SECS) < QDateTime::currentDateTime()) {
@@ -209,49 +204,7 @@ void CardPictureLoader::imageLoaded(const ExactCard &card, const QImage &image)
card.emitPixmapUpdated();
}
-void CardPictureLoader::deleteAllLocalOverrides(const ExactCard &card)
-{
- const QString picsRoot = SettingsCache::instance().paths().getPicsPath();
- if (picsRoot.isEmpty() || !card) {
- return;
- }
-
- QDir baseDir(picsRoot);
- if (!baseDir.cd("downloadedPics")) {
- return;
- }
-
- const QString name = card.getInfo().getCorrectedName();
-
- QString set, collector, uuid;
- auto printing = card.getPrinting();
- if (printing.getSet()) {
- set = printing.getSet()->getCorrectedShortName();
- collector = printing.getProperty("num");
- uuid = printing.getUuid();
- }
-
- for (const auto &scheme : CardPictureLoaderLocalSchemes::exportSchemes()) {
- QString rel = CardPictureLoaderLocalSchemes::expandPattern(scheme.pattern, name, set, collector, uuid);
-
- if (rel.isEmpty()) {
- continue;
- }
-
- rel += ".png";
- rel = QDir::cleanPath(rel);
-
- QString fullPath = baseDir.filePath(rel);
-
- if (QFile::exists(fullPath)) {
- QFile::remove(fullPath);
- }
- }
-}
-
-void CardPictureLoader::saveCardImageToLocalStorage(const ExactCard &card,
- const QPixmap &pixmap,
- const bool allowOverwrite)
+void CardPictureLoader::saveCardImageToLocalStorage(const ExactCard &card, const QPixmap &pixmap)
{
if (pixmap.isNull() || !card) {
return;
@@ -311,9 +264,8 @@ void CardPictureLoader::saveCardImageToLocalStorage(const ExactCard &card,
QFileInfo outInfo(baseDir.filePath(relativePath));
- // Automatic cache writes (FILESYSTEM_CACHE) must never clobber an explicit user override.
- // Only the explicit override paths pass allowOverwrite == true.
- if (!allowOverwrite && outInfo.exists()) {
+ // Do not overwrite existing files
+ if (outInfo.exists()) {
return;
}
@@ -334,122 +286,6 @@ void CardPictureLoader::saveCardImageToLocalStorage(const ExactCard &card,
}
}
-void CardPictureLoader::installPrintingOverrideOnLoad(const ExactCard &originalCard, const ExactCard &overrideCard)
-{
- // Overriding a card with itself is the reset case, not a real override: every code path below
- // would re-enter itself through emitPixmapUpdated(). Reject it outright.
- if (originalCard == overrideCard) {
- return;
- }
-
- CardInfoPtr cardPtr = overrideCard.getCardPtr();
- if (!cardPtr) {
- return;
- }
-
- // Heap-allocate so the lambda can capture it before the connection is made
- auto *connectionHandle = new QMetaObject::Connection;
-
- *connectionHandle =
- connect(cardPtr.data(), &CardInfo::pixmapUpdated, cardPtr.data(),
- [originalCard, overrideCard, connectionHandle, this](const PrintingInfo &printing) {
- // All printings share the same CardInfo, so ignore updates triggered by any
- // other printing (e.g., the original card re-loading from disk).
- if (printing != overrideCard.getPrinting()) {
- return;
- }
-
- QPixmap pixmap;
- if (QPixmapCache::find(overrideCard.getPixmapCacheKey(), &pixmap) && !pixmap.isNull()) {
- // The override art has resolved — persist it and reflect it immediately.
- // Retire the connection before emitting so the refresh can't re-enter.
- saveCardImageToLocalStorage(originalCard, pixmap, /*allowOverwrite=*/true);
-
- QObject::disconnect(*connectionHandle);
- delete connectionHandle;
-
- QPixmapCache::clear();
- originalCard.emitPixmapUpdated();
- return;
- }
-
- // The art could not be resolved. Keep the connection armed so a late resolution
- // still lands, and surface a visible refusal instead of a silent no-op. An
- // override already on disk is left untouched and simply re-displayed.
- QPixmapCache::clear();
- if (!hasLocalOverrides(originalCard)) {
- QPixmap refusedPixmap;
- getCardBackLoadingFailedPixmap(refusedPixmap, QSize(480, 672));
- QPixmapCache::insert(originalCard.getPixmapCacheKey(), refusedPixmap);
- }
- originalCard.emitPixmapUpdated();
- });
-
- // Now enqueue; if the image is already loading (deduplicated in the worker),
- // the signal will still fire when it completes
- CardPictureLoader::getInstance().worker->enqueueImageLoad(overrideCard);
-}
-
-void CardPictureLoader::installPrintingOverride(const ExactCard &originalCard, const ExactCard &overrideCard)
-{
- // Same guard as installPrintingOverrideOnLoad: self-override is the reset case.
- if (originalCard == overrideCard) {
- return;
- }
-
- QPixmap pixmap;
- const QString key = overrideCard.getPixmapCacheKey();
-
- if (QPixmapCache::find(key, &pixmap) && !pixmap.isNull()) {
- // Already cached — save immediately; the caller refreshes the card.
- saveCardImageToLocalStorage(originalCard, pixmap, /*allowOverwrite=*/true);
- return;
- }
-
- // Cache miss or previously failed load — enqueue load and wait for the signal.
- installPrintingOverrideOnLoad(originalCard, overrideCard);
-}
-
-bool CardPictureLoader::hasLocalOverrides(const ExactCard &card)
-{
- const QString picsRoot = SettingsCache::instance().paths().getPicsPath();
- if (picsRoot.isEmpty() || !card) {
- return false;
- }
-
- QDir baseDir(picsRoot);
- if (!baseDir.cd("downloadedPics")) {
- return false;
- }
-
- const QString name = card.getInfo().getCorrectedName();
-
- QString set, collector, uuid;
- const PrintingInfo printing = card.getPrinting();
- if (printing.getSet()) {
- set = printing.getSet()->getCorrectedShortName();
- collector = printing.getProperty("num");
- uuid = printing.getUuid();
- }
-
- for (const auto &scheme : CardPictureLoaderLocalSchemes::exportSchemes()) {
- QString rel = CardPictureLoaderLocalSchemes::expandPattern(scheme.pattern, name, set, collector, uuid);
-
- if (rel.isEmpty()) {
- continue;
- }
-
- rel += ".png";
- rel = QDir::cleanPath(rel);
-
- if (QFile::exists(baseDir.filePath(rel))) {
- return true;
- }
- }
-
- return false;
-}
-
void CardPictureLoader::clearPixmapCache()
{
QPixmapCache::clear();
@@ -489,11 +325,31 @@ void CardPictureLoader::picsPathChanged()
QPixmapCache::clear();
}
-void CardPictureLoader::cardLangChanged()
+bool CardPictureLoader::hasCustomArt()
{
- // Localized images are fetched via a different URL, but the in-memory
- // pixmap cache is keyed by card name/uuid, so drop everything cached
- // (including failure timestamps) to force a reload in the new language.
- QPixmapCache::clear();
- failedAt.clear();
+ auto picsPath = SettingsCache::instance().paths().getPicsPath();
+ QDirIterator it(picsPath, QDir::Dirs | QDir::NoDotAndDotDot);
+
+ // Check if there is at least one non-directory file in the pics path, other
+ // than in the "downloadedPics" subdirectory.
+ while (it.hasNext()) {
+#if (QT_VERSION >= QT_VERSION_CHECK(6, 3, 0))
+ QFileInfo dir(it.nextFileInfo());
+#else
+ // nextFileInfo() is only available in Qt 6.3+, for previous versions, we build
+ // the QFileInfo from a QString which requires more system calls.
+ QFileInfo dir(it.next());
+#endif
+
+ if (it.fileName() == "downloadedPics") {
+ continue;
+ }
+
+ QDirIterator subIt(it.filePath(), QDir::Files, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
+ if (subIt.hasNext()) {
+ return true;
+ }
+ }
+
+ return false;
}
diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader.h b/cockatrice/src/interface/card_picture_loader/card_picture_loader.h
index 0a4934e6d..5c3ac84a3 100644
--- a/cockatrice/src/interface/card_picture_loader/card_picture_loader.h
+++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader.h
@@ -97,17 +97,10 @@ public:
static void cacheCardPixmaps(const QList &cards);
/**
- * @brief Check if a local override image already exists for the card.
- * @param card The card to check.
- * @return True if the card has at least one locally stored override image.
+ * @brief Check if the user has custom card art in the picsPath directory.
+ * @return True if any custom art exists.
*/
- static bool hasLocalOverrides(const ExactCard &card);
-
- /**
- * @brief Removes all locally stored override images for the card.
- * @param card The card to remove the override images of.
- */
- static void deleteAllLocalOverrides(const ExactCard &card);
+ static bool hasCustomArt();
/**
* @brief Clears the in-memory QPixmap cache for all cards.
@@ -127,9 +120,7 @@ public slots:
* @param image Loaded QImage.
*/
void imageLoaded(const ExactCard &card, const QImage &image);
- void saveCardImageToLocalStorage(const ExactCard &card, const QPixmap &pixmap, bool allowOverwrite = false);
- void installPrintingOverride(const ExactCard &originalCard, const ExactCard &overrideCard);
- void installPrintingOverrideOnLoad(const ExactCard &originalCard, const ExactCard &overrideCard);
+ void saveCardImageToLocalStorage(const ExactCard &card, const QPixmap &pixmap);
private slots:
/**
@@ -143,12 +134,6 @@ private slots:
* Clears the QPixmap cache to reload images.
*/
void picsPathChanged();
-
- /**
- * @brief Triggered when the card language setting changes.
- * Clears the in-memory picture caches so images reload in the new language.
- */
- void cardLangChanged();
};
#endif
diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader_local.cpp b/cockatrice/src/interface/card_picture_loader/card_picture_loader_local.cpp
index c82fca403..39621839a 100644
--- a/cockatrice/src/interface/card_picture_loader/card_picture_loader_local.cpp
+++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader_local.cpp
@@ -94,10 +94,6 @@ QImage CardPictureLoaderLocal::tryLoadCardImageFromDisk(const QString &setName,
candidatePaths << picsPath + "/downloadedPics/" + setName + "/" + nameVariant;
}
- // Non-set-folder export schemes (e.g., Name_Set_Collector) write straight into
- // downloadedPics/; check there as a fallback so local overrides round-trip.
- candidatePaths << picsPath + "/downloadedPics/" + nameVariant;
-
for (const QString &path : candidatePaths) {
QFileInfo fileInfo(path);
QDir dir = fileInfo.dir();
@@ -109,8 +105,7 @@ QImage CardPictureLoaderLocal::tryLoadCardImageFromDisk(const QString &setName,
QStringList files = dir.entryList(QDir::Files);
for (const QString &file : files) {
- QFileInfo fi(file);
- if (fi.completeBaseName() != baseName) {
+ if (!file.startsWith(baseName)) {
continue;
}
diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker.cpp b/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker.cpp
index 34092f361..d288236d2 100644
--- a/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker.cpp
+++ b/cockatrice/src/interface/card_picture_loader/card_picture_loader_worker.cpp
@@ -84,8 +84,8 @@ void CardPictureLoaderWorker::queueRequest(const QUrl &url, CardPictureLoaderWor
SettingsCache::instance().cacheStorage().getCardPictureLoaderCacheMethod()) ==
CardPictureLoaderCacheMethod::CacheMethod::NETWORK_CACHE &&
cache->metaData(url).isValid()) {
- // A request that will be served from the disk cache never touches the network and therefore
- // doesn't use up any of the rate limit, so it gets to skip the queue.
+ // If we hit a cached url, we get to make the request for free, since it won't contribute towards the
+ // rate-limit
makeRequest(url, worker);
return;
}
@@ -107,13 +107,10 @@ QNetworkReply *CardPictureLoaderWorker::makeRequest(const QUrl &url, CardPicture
req.setHeader(QNetworkRequest::UserAgentHeader, QString("Cockatrice %1").arg(VERSION_STRING));
req.setRawHeader("Accept", "image/avif,image/webp,image/apng,image/,/*;q=0.8");
- // Cached entries are served straight from the disk cache even when picture downloads are
- // enabled: re-fetching an already-cached image would burn the rate limit for nothing. Only a
- // genuine cache miss goes to the network, and only when downloads are enabled.
- bool useNetworkCache = static_cast(
- SettingsCache::instance().cacheStorage().getCardPictureLoaderCacheMethod()) ==
- CardPictureLoaderCacheMethod::CacheMethod::NETWORK_CACHE &&
- (cache->metaData(url).isValid() || !picDownload);
+ bool useNetworkCache =
+ !picDownload && static_cast(
+ SettingsCache::instance().cacheStorage().getCardPictureLoaderCacheMethod()) ==
+ CardPictureLoaderCacheMethod::CacheMethod::NETWORK_CACHE;
req.setAttribute(QNetworkRequest::CacheLoadControlAttribute,
useNetworkCache ? QNetworkRequest::AlwaysCache : QNetworkRequest::AlwaysNetwork);
diff --git a/cockatrice/src/interface/card_picture_loader/card_picture_to_load.cpp b/cockatrice/src/interface/card_picture_loader/card_picture_to_load.cpp
index 7cb502e92..5f4ff0bbd 100644
--- a/cockatrice/src/interface/card_picture_loader/card_picture_to_load.cpp
+++ b/cockatrice/src/interface/card_picture_loader/card_picture_to_load.cpp
@@ -94,8 +94,7 @@ void CardPictureToLoad::populateSetUrls()
}
}
- const QStringList orderedTemplates = urlTemplates;
- for (const QString &urlTemplate : orderedTemplates) {
+ for (const QString &urlTemplate : urlTemplates) {
QString transformedUrl = transformUrl(urlTemplate);
if (!transformedUrl.isEmpty()) {
@@ -283,15 +282,8 @@ QString CardPictureToLoad::transformUrl(const QString &urlTemplate) const
}
// language setting
- const QString cardLang = SettingsCache::instance().cardsDisplay().getCardLang();
- transformMap["!sflang!"] = cardLang;
-
- // The localized printing's own id is unknown, so Scryfall must resolve it by
- // its translated name (see populateSetUrls); expose that name for the
- // `/cards/named` template.
- if (cardLang != "en") {
- transformMap["!localizedName!"] = card.getInfo().getLocalizedName(cardLang);
- }
+ transformMap["!sflang!"] = QString(QCoreApplication::translate(
+ "PictureLoader", "en", "code for scryfall's language property, not available for all languages"));
QString transformedUrl = urlTemplate;
for (const QString &prop : transformMap.keys()) {
diff --git a/cockatrice/src/interface/deck_loader/deck_file_format.h b/cockatrice/src/interface/deck_loader/deck_file_format.h
index 3a25797ec..995de32c0 100644
--- a/cockatrice/src/interface/deck_loader/deck_file_format.h
+++ b/cockatrice/src/interface/deck_loader/deck_file_format.h
@@ -17,7 +17,7 @@ enum Format
PlainText,
/**
- * This is Cockatrice's native deck file format, and supports deck metadata such as banner cards and tags.
+ * This is cockatrice's native deck file format, and supports deck metadata such as banner cards and tags.
* Stored as .cod files.
*/
Cockatrice
diff --git a/cockatrice/src/interface/deck_loader/deck_loader.cpp b/cockatrice/src/interface/deck_loader/deck_loader.cpp
index f29b4eed2..f03339da8 100644
--- a/cockatrice/src/interface/deck_loader/deck_loader.cpp
+++ b/cockatrice/src/interface/deck_loader/deck_loader.cpp
@@ -50,7 +50,7 @@ DeckLoader::loadFromFile(const QString &fileName, DeckFileFormat::Format fmt, bo
result = deckList.loadFromFile_Native(&file);
if (!result) {
qCInfo(DeckLoaderLog) << "Failed to load " << fileName
- << "as Cockatrice format; retrying as plain format";
+ << "as cockatrice format; retrying as plain format";
file.seek(0);
result = deckList.loadFromFile_Plain(&file, CardNameNormalizer());
fmt = DeckFileFormat::PlainText;
diff --git a/cockatrice/src/interface/deck_loader/deck_loader.h b/cockatrice/src/interface/deck_loader/deck_loader.h
index be0df311d..b851c6895 100644
--- a/cockatrice/src/interface/deck_loader/deck_loader.h
+++ b/cockatrice/src/interface/deck_loader/deck_loader.h
@@ -131,7 +131,7 @@ public:
static void printDeckList(QPrinter *printer, const DeckList &deckList);
/**
- * Converts the given deck's file to the Cockatrice file format.
+ * Converts the given deck's file to the cockatrice file format.
* Uses the lastLoadInfo in the LoadedDeck to determine the current name of the file and where to save to.
* @param deck The deck to convert. Should have valid lastLoadInfo. Will update the lastLoadInfo.
* @return Whether the conversion succeeded.
diff --git a/cockatrice/src/interface/intents/intent.cpp b/cockatrice/src/interface/intents/intent.cpp
index db0d13b2c..aa06fd81b 100644
--- a/cockatrice/src/interface/intents/intent.cpp
+++ b/cockatrice/src/interface/intents/intent.cpp
@@ -28,7 +28,6 @@ void Intent::runDependency(Intent *dependency)
this->execute();
});
connect(dependency, &Intent::failed, this, &Intent::failed);
- connect(dependency, &Intent::cancelled, this, &Intent::cancelled);
dependency->execute();
}
diff --git a/cockatrice/src/interface/intents/intent_login.cpp b/cockatrice/src/interface/intents/intent_login.cpp
index d3431bb07..344ef4e00 100644
--- a/cockatrice/src/interface/intents/intent_login.cpp
+++ b/cockatrice/src/interface/intents/intent_login.cpp
@@ -6,9 +6,7 @@
#include
-IntentGetLoginCredentials::IntentGetLoginCredentials(ContextConnectToServer *_context,
- bool _promptForMissingCredentials)
- : Intent(), context(_context), promptForMissingCredentials(_promptForMissingCredentials)
+IntentGetLoginCredentials::IntentGetLoginCredentials(ContextConnectToServer *_context) : Intent(), context(_context)
{
}
@@ -34,14 +32,6 @@ void IntentGetLoginCredentials::onPreconditionSatisfied()
void IntentGetLoginCredentials::onPreconditionNotSatisfied()
{
- // MainWindow::applyStartupDestination runs this intent on every launch for
- // users whose startup tab is Server / Server Room; keep that path quiet, as
- // it was before the link-driven sign-in dialog existed.
- if (!promptForMissingCredentials) {
- emitFailed(tr("No saved credentials for this server"));
- return;
- }
-
// No credentials saved for the target server: ask the user for them. They
// opt into saving them so later links to the same server connect directly.
const QString serverText = context->hostname + ":" + context->port;
diff --git a/cockatrice/src/interface/intents/intent_login.h b/cockatrice/src/interface/intents/intent_login.h
index 8ffd91a0a..c7fec92b7 100644
--- a/cockatrice/src/interface/intents/intent_login.h
+++ b/cockatrice/src/interface/intents/intent_login.h
@@ -9,10 +9,7 @@ class IntentGetLoginCredentials : public Intent
Q_OBJECT
public:
- // When promptForMissingCredentials is false (the default) a server without
- // saved credentials fails silently; only intent chains from cockatrice://
- // links opt into the interactive sign-in dialog.
- explicit IntentGetLoginCredentials(ContextConnectToServer *_context, bool _promptForMissingCredentials = false);
+ IntentGetLoginCredentials(ContextConnectToServer *_context);
protected:
bool checkPrecondition() const override;
@@ -21,7 +18,6 @@ protected:
private:
ContextConnectToServer *context;
- bool promptForMissingCredentials;
};
#endif // COCKATRICE_INTENT_LOGIN_H
diff --git a/cockatrice/src/interface/intents/intent_open_shared_deck.cpp b/cockatrice/src/interface/intents/intent_open_shared_deck.cpp
index 9ecb4520d..c7d4f5469 100644
--- a/cockatrice/src/interface/intents/intent_open_shared_deck.cpp
+++ b/cockatrice/src/interface/intents/intent_open_shared_deck.cpp
@@ -43,11 +43,7 @@ bool IntentOpenSharedDeck::checkPrecondition() const
void IntentOpenSharedDeck::onPreconditionSatisfied()
{
// Resolve the share token to its items first; a share can contain more than
- // one deck, and each item is downloaded by id. Time the round trip like the
- // downloads, so a silent server cannot hang the chain forever.
- listPhase = true;
- downloadTimer->start();
-
+ // one deck, and each item is downloaded by id.
Command_DeckShareList cmd;
cmd.set_token(context->shareToken.toStdString());
@@ -63,9 +59,6 @@ void IntentOpenSharedDeck::onPreconditionNotSatisfied()
void IntentOpenSharedDeck::listShareFinished(const Response &response, const CommandContainer & /* commandContainer */)
{
- downloadTimer->stop();
- listPhase = false;
-
if (response.response_code() != Response::RespOk) {
emitFailed(tr("The shared deck could not be found or has expired"));
return;
@@ -184,12 +177,6 @@ void IntentOpenSharedDeck::onItemFailure(const QString &reason)
void IntentOpenSharedDeck::onDownloadTimeout()
{
- // The list phase has no preview dialog yet to report progress into; fail the
- // whole intent instead of letting the shared deck hang in limbo.
- if (listPhase) {
- emitFailed(tr("Timed out while loading the shared deck"));
- return;
- }
onItemFailure(tr("Timed out while downloading the shared deck"));
}
@@ -200,4 +187,4 @@ void IntentOpenSharedDeck::finishAll()
tabSupervisor->openDeckInNewTab(deck);
}
emitFinished();
-}
+}
\ No newline at end of file
diff --git a/cockatrice/src/interface/intents/intent_open_shared_deck.h b/cockatrice/src/interface/intents/intent_open_shared_deck.h
index 87812bdea..ac8d443b8 100644
--- a/cockatrice/src/interface/intents/intent_open_shared_deck.h
+++ b/cockatrice/src/interface/intents/intent_open_shared_deck.h
@@ -51,10 +51,9 @@ private:
QMap itemNames;
QList pendingItemIds;
QList loadedDecks;
- bool listPhase = true;
int currentItemId = 0;
int totalItems = 0;
int completedItems = 0;
};
-#endif // COCKATRICE_INTENT_OPEN_SHARED_DECK_H
+#endif // COCKATRICE_INTENT_OPEN_SHARED_DECK_H
\ No newline at end of file
diff --git a/cockatrice/src/interface/intents/url_parser.cpp b/cockatrice/src/interface/intents/url_parser.cpp
index 120e72b2a..ee5e084dd 100644
--- a/cockatrice/src/interface/intents/url_parser.cpp
+++ b/cockatrice/src/interface/intents/url_parser.cpp
@@ -40,7 +40,7 @@ void IntentUrlParser::handle(const QString &urlStr)
qCDebug(UrlParserLog) << "Parsing intent URL, action:" << action;
- PendingIntentChain chain;
+ QList chain;
Intent *firstIntent = nullptr;
if (action == "joingame") {
firstIntent = createJoinGameIntent(query, chain);
@@ -64,7 +64,7 @@ void IntentUrlParser::handle(const QString &urlStr)
startNextChain();
}
-Intent *IntentUrlParser::createJoinGameIntent(const QUrlQuery &query, PendingIntentChain &chain)
+Intent *IntentUrlParser::createJoinGameIntent(const QUrlQuery &query, QList &chain)
{
auto showError = [this](const QString &message) { QMessageBox::warning(mainWindow, tr("Open game"), message); };
@@ -116,15 +116,14 @@ Intent *IntentUrlParser::createJoinGameIntent(const QUrlQuery &query, PendingInt
// chain finishes (or fails) it deletes the whole tree.
auto joinGameIntent = new IntentJoinServerGame(mainWindow->getTabSupervisor(), client, std::move(ctx));
joinGameIntent->setParent(this);
- chain.intents.append(joinGameIntent);
+ chain.append(joinGameIntent);
connect(joinGameIntent, &Intent::failed, this, [showError](const QString &reason) { showError(reason); });
Intent *firstIntent = joinGameIntent;
if (!isConnectedTo(serverContext->hostname, serverContext->port)) {
- auto getLoginCredentialsIntent =
- new IntentGetLoginCredentials(serverContext, /*promptForMissingCredentials=*/true);
+ auto getLoginCredentialsIntent = new IntentGetLoginCredentials(serverContext);
getLoginCredentialsIntent->setParent(joinGameIntent);
- chain.intents.insert(0, getLoginCredentialsIntent);
+ chain.insert(0, getLoginCredentialsIntent);
connect(getLoginCredentialsIntent, &Intent::finished, joinGameIntent, &Intent::execute);
connect(getLoginCredentialsIntent, &Intent::failed, joinGameIntent, &Intent::failed);
@@ -170,7 +169,7 @@ QString IntentUrlParser::generateJoinGameMessage(const ContextJoinGame &context,
: tr("Join game \"%1\" (#%2) on %3?").arg(gameDescription, gameIdStr, server);
}
-Intent *IntentUrlParser::createOpenDeckIntent(const QUrlQuery &query, PendingIntentChain &chain)
+Intent *IntentUrlParser::createOpenDeckIntent(const QUrlQuery &query, QList &chain)
{
auto showError = [this](const QString &message) {
QMessageBox::warning(mainWindow, tr("Open shared deck"), message);
@@ -204,45 +203,27 @@ Intent *IntentUrlParser::createOpenDeckIntent(const QUrlQuery &query, PendingInt
RemoteClient *client = mainWindow->getRemoteClient();
- // The open deck download needs a connection to the link's server. Ask before
- // taking the session anywhere it isn't already, naming the host we would
- // connect to. Remember the link's target when it moves us away from a live
- // session so a failed or cancelled chain can restore the session it left.
- const bool alreadyConnected = isConnectedTo(ctx->serverContext.hostname, ctx->serverContext.port);
- if (!alreadyConnected) {
+ // When the link would move us away from a live session, ask first — the
+ // open deck download needs the connection the user already has. Remember
+ // the current session so a failed or cancelled chain can restore it.
+ const bool migrating =
+ client->getStatus() == StatusLoggedIn && !isConnectedTo(ctx->serverContext.hostname, ctx->serverContext.port);
+ if (migrating) {
const QString target = QStringLiteral("%1:%2").arg(ctx->serverContext.hostname, ctx->serverContext.port);
-
- if (client->getStatus() == StatusLoggedIn) {
- const QString current =
- QStringLiteral("%1:%2").arg(client->serverName(), QString::number(client->serverPort()));
- const QMessageBox::StandardButton answer = QMessageBox::question(
- mainWindow, tr("Open shared deck"),
- tr("Opening this share link connects you to %1 instead of %2.\n\nContinue?").arg(target, current),
- QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
- if (answer != QMessageBox::Yes) {
- return nullptr;
- }
- chain.migrationTargetHost = ctx->serverContext.hostname;
- chain.migrationTargetPort = ctx->serverContext.port;
- chain.pendingRestore = true;
- } else {
- // Fresh connection is harmless to wander away from, but a server the
- // client has never been configured for deserves a harder warning (no
- // by default) so a stray link cannot silently steer the client there.
- const bool knownHost = SettingsCache::instance().servers().findHostIndex(ctx->serverContext.hostname) >= 0;
- const QMessageBox::StandardButton answer =
- knownHost
- ? QMessageBox::question(mainWindow, tr("Open shared deck"),
- tr("Opening this share link connects you to %1.\n\nContinue?").arg(target))
- : QMessageBox::warning(mainWindow, tr("Open shared deck"),
- tr("Opening this share link connects you to %1, a server you have "
- "never connected to before.\n\nContinue?")
- .arg(target),
- QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
- if (answer != QMessageBox::Yes) {
- return nullptr;
- }
+ const QString current =
+ QStringLiteral("%1:%2").arg(client->serverName(), QString::number(client->serverPort()));
+ const QMessageBox::StandardButton answer = QMessageBox::question(
+ mainWindow, tr("Open shared deck"),
+ tr("Opening this share link connects you to %1 instead of %2.\n\nContinue?").arg(target, current),
+ QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
+ if (answer != QMessageBox::Yes) {
+ return nullptr;
}
+ migrationTargetHost = ctx->serverContext.hostname;
+ migrationTargetPort = ctx->serverContext.port;
+ previousServerHost = client->serverName();
+ previousServerPort = QString::number(client->serverPort());
+ pendingRestore = true;
}
ContextConnectToServer *serverContext = &ctx->serverContext;
@@ -252,15 +233,14 @@ Intent *IntentUrlParser::createOpenDeckIntent(const QUrlQuery &query, PendingInt
auto openDeckIntent =
new IntentOpenSharedDeck(mainWindow->getTabSupervisor(), client, CardDatabaseManager::query(), std::move(ctx));
openDeckIntent->setParent(this);
- chain.intents.append(openDeckIntent);
+ chain.append(openDeckIntent);
connect(openDeckIntent, &Intent::failed, this, [showError](const QString &reason) { showError(reason); });
Intent *firstIntent = openDeckIntent;
if (!isConnectedTo(serverContext->hostname, serverContext->port)) {
- auto getLoginCredentialsIntent =
- new IntentGetLoginCredentials(serverContext, /*promptForMissingCredentials=*/true);
+ auto getLoginCredentialsIntent = new IntentGetLoginCredentials(serverContext);
getLoginCredentialsIntent->setParent(openDeckIntent);
- chain.intents.insert(0, getLoginCredentialsIntent);
+ chain.insert(0, getLoginCredentialsIntent);
connect(getLoginCredentialsIntent, &Intent::finished, openDeckIntent, &Intent::execute);
connect(getLoginCredentialsIntent, &Intent::failed, openDeckIntent, &Intent::failed);
@@ -287,52 +267,38 @@ void IntentUrlParser::startNextChain()
return;
}
chainRunning = true;
+ currentChainSucceeded = false;
- PendingIntentChain &chain = pendingChains.first();
- if (chain.intents.isEmpty()) {
- pendingChains.removeFirst();
+ const QList chain = pendingChains.takeFirst();
+ if (chain.isEmpty()) {
chainRunning = false;
- startNextChain();
return;
}
- // Snapshot the session this chain moves away from now that it actually
- // runs. Chains are parsed while earlier ones are still queued, so a capture
- // at parse time would follow whichever server the chain before it settled
- // on, not the one the user is really on when this link is handled.
- if (chain.pendingRestore) {
- RemoteClient *client = mainWindow->getRemoteClient();
- chain.previousServerHost = client->serverName();
- chain.previousServerPort = QString::number(client->serverPort());
- }
-
// Only the last intent completes the chain; its terminal signal ends the
// whole run. Cancellation of an intermediate intent (e.g. declined login
// prompt) is forwarded onto the last intent in the chain builders above.
- Intent *finalIntent = chain.intents.last();
- connect(finalIntent, &Intent::finished, this, [this]() { chainEnded(true); });
- connect(finalIntent, &Intent::failed, this, [this]() { chainEnded(false); });
- connect(finalIntent, &Intent::cancelled, this, [this]() { chainEnded(false); });
- // Backstop: if the final intent is destroyed without emitting a terminal
- // signal (e.g. a network error dropped it while running), end the chain so
- // later links are not queued and dropped for the rest of the session.
- chainBackstopConnection = connect(finalIntent, &QObject::destroyed, this, &IntentUrlParser::onChainIntentDestroyed);
+ Intent *finalIntent = chain.last();
+ connect(finalIntent, &Intent::finished, this, [this]() {
+ currentChainSucceeded = true;
+ chainEnded();
+ });
+ connect(finalIntent, &Intent::failed, this, &IntentUrlParser::chainEnded);
+ connect(finalIntent, &Intent::cancelled, this, &IntentUrlParser::chainEnded);
- chain.intents.first()->execute();
+ chain.first()->execute();
}
-void IntentUrlParser::chainEnded(bool chainSucceeded)
+void IntentUrlParser::chainEnded()
{
chainRunning = false;
- QObject::disconnect(chainBackstopConnection);
-
- const PendingIntentChain chain = pendingChains.takeFirst();
// Only a failed or cancelled chain restores the session the link migrated
// away from; a successful one leaves the user where they are.
- if (chain.pendingRestore && !chainSucceeded) {
- restorePreviousServer(chain);
+ if (pendingRestore && !currentChainSucceeded) {
+ restorePreviousServer();
}
+ pendingRestore = false;
startNextChain();
@@ -343,18 +309,9 @@ void IntentUrlParser::chainEnded(bool chainSucceeded)
}
}
-void IntentUrlParser::onChainIntentDestroyed()
+void IntentUrlParser::restorePreviousServer()
{
- if (!chainRunning) {
- return;
- }
- qCWarning(UrlParserLog) << "Share-link intent destroyed without a terminal signal; ending its chain";
- chainEnded(false);
-}
-
-void IntentUrlParser::restorePreviousServer(const PendingIntentChain &chain)
-{
- if (chain.previousServerHost.isEmpty()) {
+ if (previousServerHost.isEmpty()) {
return;
}
@@ -367,47 +324,46 @@ void IntentUrlParser::restorePreviousServer(const PendingIntentChain &chain)
// deciding mid-connect would strand the user offline from their previous
// server.
if (status == StatusDisconnected || status == StatusLoggedIn) {
- restoreToPreviousServer(chain);
+ restoreToPreviousServer();
return;
}
auto waitConnection = std::make_shared();
- *waitConnection = connect(client, &RemoteClient::statusChanged, this, [this, chain, client, waitConnection]() {
+ *waitConnection = connect(client, &RemoteClient::statusChanged, this, [this, client, waitConnection]() {
const ClientStatus settled = client->getStatus();
if (settled == StatusDisconnected || settled == StatusLoggedIn) {
QObject::disconnect(*waitConnection);
- restoreToPreviousServer(chain);
+ restoreToPreviousServer();
}
});
}
-void IntentUrlParser::restoreToPreviousServer(const PendingIntentChain &chain)
+void IntentUrlParser::restoreToPreviousServer()
{
RemoteClient *client = mainWindow->getRemoteClient();
// Back on the previous server already → nothing to undo.
- if (client->serverName().compare(chain.previousServerHost, Qt::CaseInsensitive) == 0 &&
- QString::number(client->serverPort()) == chain.previousServerPort) {
+ if (client->serverName().compare(previousServerHost, Qt::CaseInsensitive) == 0 &&
+ QString::number(client->serverPort()) == previousServerPort) {
return;
}
// When logged in somewhere, only intervene if that somewhere is the server
// the link moved us to; if the user went elsewhere on their own, leave them.
if (client->getStatus() == StatusLoggedIn) {
- const bool onMigrationTarget =
- client->serverName().compare(chain.migrationTargetHost, Qt::CaseInsensitive) == 0 &&
- QString::number(client->serverPort()) == chain.migrationTargetPort;
+ const bool onMigrationTarget = client->serverName().compare(migrationTargetHost, Qt::CaseInsensitive) == 0 &&
+ QString::number(client->serverPort()) == migrationTargetPort;
if (!onMigrationTarget) {
return;
}
ServersSettings &servers = SettingsCache::instance().servers();
- const int index = servers.findServerIndex(chain.previousServerHost, chain.previousServerPort);
- if (index >= 0 && servers.hasLoginData(chain.previousServerHost, chain.previousServerPort)) {
+ const int index = servers.findServerIndex(previousServerHost, previousServerPort);
+ if (index >= 0 && servers.hasLoginData(previousServerHost, previousServerPort)) {
const QString username =
servers.getValue(QString("username%1").arg(index), "server", "server_details").toString();
const QString password =
servers.getValue(QString("password%1").arg(index), "server", "server_details").toString();
- client->connectToServer(chain.previousServerHost, chain.previousServerPort.toUInt(), username, password);
+ client->connectToServer(previousServerHost, previousServerPort.toUInt(), username, password);
return;
}
client->disconnectFromServer();
@@ -421,12 +377,12 @@ void IntentUrlParser::restoreToPreviousServer(const PendingIntentChain &chain)
// The link's connection attempt failed: reconnect to the previous server
// when credentials are saved, otherwise stay offline.
ServersSettings &servers = SettingsCache::instance().servers();
- const int index = servers.findServerIndex(chain.previousServerHost, chain.previousServerPort);
- if (index >= 0 && servers.hasLoginData(chain.previousServerHost, chain.previousServerPort)) {
+ const int index = servers.findServerIndex(previousServerHost, previousServerPort);
+ if (index >= 0 && servers.hasLoginData(previousServerHost, previousServerPort)) {
const QString username =
servers.getValue(QString("username%1").arg(index), "server", "server_details").toString();
const QString password =
servers.getValue(QString("password%1").arg(index), "server", "server_details").toString();
- client->connectToServer(chain.previousServerHost, chain.previousServerPort.toUInt(), username, password);
+ client->connectToServer(previousServerHost, previousServerPort.toUInt(), username, password);
}
}
diff --git a/cockatrice/src/interface/intents/url_parser.h b/cockatrice/src/interface/intents/url_parser.h
index ea29fed53..7464caf4f 100644
--- a/cockatrice/src/interface/intents/url_parser.h
+++ b/cockatrice/src/interface/intents/url_parser.h
@@ -1,6 +1,5 @@
#ifndef COCKATRICE_URL_PARSER_H
#define COCKATRICE_URL_PARSER_H
-
#include
#include
#include
@@ -9,29 +8,6 @@ class Intent;
class MainWindow;
struct ContextJoinGame;
-/**
- * @brief One queued intent chain with the session-migration bookkeeping for it.
- *
- * The restore fields are per-chain on purpose: chains are parsed while earlier
- * ones are still queued, so parser-wide state would let one chain's failure
- * consume the restore data another chain recorded.
- */
-struct PendingIntentChain
-{
- QList intents;
-
- // Snapshot of the session in place when this chain started running, so a
- // queued chain follows whichever server the chain before it settled on.
- QString previousServerHost;
- QString previousServerPort;
-
- // Recorded at parse time when the user confirmed migrating away from a live
- // session to the host/port named by the link.
- QString migrationTargetHost;
- QString migrationTargetPort;
- bool pendingRestore = false;
-};
-
/**
* @brief Parses cockatrice:// links and runs them as serialized intent chains.
*
@@ -54,22 +30,28 @@ signals:
void urlChainFinished(bool connected);
private:
- Intent *createJoinGameIntent(const QUrlQuery &query, PendingIntentChain &chain);
- Intent *createOpenDeckIntent(const QUrlQuery &query, PendingIntentChain &chain);
+ Intent *createJoinGameIntent(const QUrlQuery &query, QList &chain);
+ Intent *createOpenDeckIntent(const QUrlQuery &query, QList &chain);
QString generateJoinGameMessage(const ContextJoinGame &context, const QString &gameDescription);
[[nodiscard]] bool isConnectedTo(const QString &hostname, const QString &port) const;
void startNextChain();
- void chainEnded(bool chainSucceeded);
- void onChainIntentDestroyed();
- void restorePreviousServer(const PendingIntentChain &chain);
- void restoreToPreviousServer(const PendingIntentChain &chain);
+ void chainEnded();
+ void restorePreviousServer();
+ void restoreToPreviousServer();
MainWindow *mainWindow;
- QList pendingChains;
+ QList> pendingChains;
bool chainRunning = false;
- // Disconnects the destroyed-signal backstop once a chain ends, so an old
- // intent's deferred deletion cannot end the chain that runs after it.
- QMetaObject::Connection chainBackstopConnection;
+ bool currentChainSucceeded = false;
+
+ // Set when an open-deck link migrates the session to another server. If the
+ // chain then fails or is cancelled while still on that server, the previous
+ // session is restored (reconnect if credentials are saved, else disconnect).
+ QString migrationTargetHost;
+ QString migrationTargetPort;
+ QString previousServerHost;
+ QString previousServerPort;
+ bool pendingRestore = false;
};
#endif // COCKATRICE_URL_PARSER_H
diff --git a/cockatrice/src/interface/palette_editor/palette_editor_dialog.cpp b/cockatrice/src/interface/palette_editor/palette_editor_dialog.cpp
index d5a168708..9cde72c01 100644
--- a/cockatrice/src/interface/palette_editor/palette_editor_dialog.cpp
+++ b/cockatrice/src/interface/palette_editor/palette_editor_dialog.cpp
@@ -1,5 +1,6 @@
#include "palette_editor_dialog.h"
+#include "../../client/settings/cache_settings.h"
#include "../theme_manager.h"
#include "palette_generator.h"
#include "palette_grid_widget.h"
@@ -10,11 +11,31 @@
#include
#include
#include
+#include
#include
+#include
#include
+#include
#include
#include
+#include
#include
+#include
+
+// Probe whether a directory is truly writable by trying to create and remove a
+// temporary file. QFileInfo::isWritable() on a directory is unreliable (notably
+// on Windows where UAC VirtualStore can make a system dir appear writable).
+static bool isDirReallyWritable(const QString &dirPath)
+{
+ const QString probe = QDir(dirPath).absoluteFilePath(".cockatrice_write_test");
+ QFile f(probe);
+ if (!f.open(QIODevice::WriteOnly)) {
+ return false;
+ }
+ f.close();
+ f.remove();
+ return true;
+}
PaletteEditorDialog::PaletteEditorDialog(const QString &_themeDirPath, const QString &_themeName, QWidget *parent)
: QDialog(parent), themeDirPath(_themeDirPath), themeName(_themeName)
@@ -25,7 +46,14 @@ PaletteEditorDialog::PaletteEditorDialog(const QString &_themeDirPath, const QSt
// Resolve a writable directory for saving. Built-in (Default / Fusion) and
// other read-only theme directories must be customised in the user-writable
// themes directory; otherwise the write would fail or be lost on upgrade.
- saveDir = ThemeManager::writableThemeDir(themeName);
+ if (!themeDirPath.isEmpty() && isDirReallyWritable(themeDirPath)) {
+ saveDir = themeDirPath;
+ } else {
+ saveDir = QDir(SettingsCache::instance().paths().getThemesPath()).absoluteFilePath(themeName);
+ if (!QDir().mkpath(saveDir)) {
+ qWarning() << "Failed to create palette save directory:" << saveDir;
+ }
+ }
// Load both scheme configs upfront so switching is instant
loadSchemes();
@@ -186,7 +214,7 @@ void PaletteEditorDialog::retranslateUi()
resetBtn->setToolTip(tr("Discard unsaved edits and restore the last saved palette"));
saveBtn->setToolTip(tr("Write palette-%1.toml and reload the theme").arg(loadedScheme.toLower()));
- if (saveDir.isEmpty() || !ThemeManager::isDirReallyWritable(saveDir)) {
+ if (saveDir.isEmpty() || !isDirReallyWritable(saveDir)) {
saveBtn->setEnabled(false);
saveBtn->setToolTip(tr("Cannot save: this theme has no writable directory"));
}
@@ -269,7 +297,7 @@ void PaletteEditorDialog::onSave()
if (it.key() == loadedScheme) {
continue;
}
- if (it.value() == savedConfig.value(it.key())) {
+ if (it.value().colors == savedConfig.value(it.key()).colors) {
continue;
}
if (!ThemeManager::commitPalette(saveDir, it.key(), it.value())) {
@@ -280,7 +308,7 @@ void PaletteEditorDialog::onSave()
}
// Commit the active scheme last so the global colour scheme matches.
- if (workingConfig[loadedScheme] != savedConfig.value(loadedScheme)) {
+ if (workingConfig[loadedScheme].colors != savedConfig.value(loadedScheme).colors) {
if (!ThemeManager::commitPalette(saveDir, loadedScheme, workingConfig[loadedScheme])) {
QMessageBox::warning(this, tr("Save failed"),
tr("Could not write %1 to:\n%2").arg(PaletteConfig::fileName(loadedScheme), saveDir));
diff --git a/cockatrice/src/interface/palette_editor/palette_generator.cpp b/cockatrice/src/interface/palette_editor/palette_generator.cpp
index 822e57250..d30dd14f1 100644
--- a/cockatrice/src/interface/palette_editor/palette_generator.cpp
+++ b/cockatrice/src/interface/palette_editor/palette_generator.cpp
@@ -150,17 +150,6 @@ PaletteConfig fromAccent(const QColor &accent, int intensity, const QString &sch
cfg.colors[CG::Disabled][CR::HighlightedText] = disText;
cfg.colors[CG::Inactive][CR::HighlightedText] = dark ? Qt::white : Qt::black;
- // Accent: same primary hue as Highlight, so palettes derived from a
- // QuickSetup accent always carry a matching Accent role.
-#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
- set3(CR::Accent, hl, disText, hl);
-#endif
-
- // Application role colors: Strong tracks the primary accent, while Soft is
- // the lightened, desaturated companion used for button-gradient highlights.
- cfg.appColors[AppColor::AccentStrong] = hl;
- cfg.appColors[AppColor::AccentSoft] = hsl(accent.lightness() + 60, qRound(accent.hslSaturation() * 70 / 100.0));
-
// BrightText
QColor bright;
if (achromatic) {
diff --git a/cockatrice/src/interface/palette_editor/palette_grid_widget.cpp b/cockatrice/src/interface/palette_editor/palette_grid_widget.cpp
index 97d28b731..67294cd98 100644
--- a/cockatrice/src/interface/palette_editor/palette_grid_widget.cpp
+++ b/cockatrice/src/interface/palette_editor/palette_grid_widget.cpp
@@ -1,7 +1,5 @@
#include "palette_grid_widget.h"
-#include "../theme_manager.h"
-
#include
#include
#include
@@ -47,11 +45,6 @@ static const QMap ROLE_DESCRIPTIONS = {
{QPalette::Shadow, QT_TR_NOOP("Very dark shadow colour")},
};
-static const QMap APP_ROLE_DESCRIPTIONS = {
- {AppColor::AccentStrong, QT_TR_NOOP("Vivid primary accent (e.g. home-tab button gradient start)")},
- {AppColor::AccentSoft, QT_TR_NOOP("Lightened, desaturated accent (e.g. home-tab button gradient end)")},
-};
-
PaletteGridWidget::PaletteGridWidget(QWidget *parent) : QWidget(parent)
{
scroll = new QScrollArea(this);
@@ -129,46 +122,6 @@ void PaletteGridWidget::buildGrid(QWidget *host)
grid->addWidget(btn, row + 1, col + 1, Qt::AlignHCenter | Qt::AlignVCenter);
}
}
-
- // Application color section: one ColorButton per role below the role grid.
- // These are not tied to a color group, so a single button spans the row.
- QMetaEnum appEnum = QMetaEnum::fromType();
-
- const int appHeaderRow = roles.size() + 1;
-
- auto *appHeader = new QLabel(tr("App colors"), host);
- appHeader->setToolTip(tr("Application-specific colors layered on top of the Qt palette"));
- QFont appHeaderFont = appHeader->font();
- appHeaderFont.setBold(true);
- appHeader->setFont(appHeaderFont);
- appHeader->setAutoFillBackground(true);
- appHeader->setContentsMargins(4, 4, 4, 4);
- grid->addWidget(appHeader, appHeaderRow, 0, 1, 4);
- headerLabels.append(appHeader);
-
- for (int i = 0; i < appEnum.keyCount(); ++i) {
- auto role = static_cast(appEnum.value(i));
- const int row = appHeaderRow + 1 + i;
-
- if (i % 2 == 0) {
- for (int col = 0; col < 4; ++col) {
- auto *shade = new QWidget(host);
- shade->setAutoFillBackground(true);
- grid->addWidget(shade, row, col);
- rowShadeWidgets.push_back(shade);
- }
- }
-
- auto *label = new QLabel(QString(appEnum.valueToKey(role)), host);
- label->setToolTip(APP_ROLE_DESCRIPTIONS.value(role, {}));
- label->setContentsMargins(4, 2, 8, 2);
- grid->addWidget(label, row, 0);
-
- auto *btn = new ColorButton(host);
- connect(btn, &ColorButton::colorChanged, this, [this] { emit paletteChanged(); });
- appColorButtons[role] = btn;
- grid->addWidget(btn, row, 1, Qt::AlignHCenter | Qt::AlignVCenter);
- }
}
void PaletteGridWidget::changeEvent(QEvent *e)
@@ -213,16 +166,6 @@ void PaletteGridWidget::loadPalette(const PaletteConfig &cfg)
colorButtons[group][role]->setColor(color);
}
}
-
- QMetaEnum appEnum = QMetaEnum::fromType();
- for (int i = 0; i < appEnum.keyCount(); ++i) {
- auto role = static_cast(appEnum.value(i));
- QColor color = cfg.appColors.value(role);
- if (!color.isValid()) {
- color = themeManager->appColor(role);
- }
- appColorButtons[role]->setColor(color);
- }
}
PaletteConfig PaletteGridWidget::currentPaletteConfig() const
@@ -233,12 +176,5 @@ PaletteConfig PaletteGridWidget::currentPaletteConfig() const
cfg.colors[group][role] = colorButtons[group][role]->getColor();
}
}
-
- QMetaEnum appEnum = QMetaEnum::fromType();
- for (int i = 0; i < appEnum.keyCount(); ++i) {
- auto role = static_cast(appEnum.value(i));
- cfg.appColors[role] = appColorButtons[role]->getColor();
- }
-
return cfg;
}
\ No newline at end of file
diff --git a/cockatrice/src/interface/palette_editor/palette_grid_widget.h b/cockatrice/src/interface/palette_editor/palette_grid_widget.h
index 77cbf1c62..1a665971a 100644
--- a/cockatrice/src/interface/palette_editor/palette_grid_widget.h
+++ b/cockatrice/src/interface/palette_editor/palette_grid_widget.h
@@ -31,7 +31,6 @@ private:
void refreshChromePalettes();
QMap> colorButtons;
- QMap appColorButtons;
QScrollArea *scroll;
QWidget *gridHost;
QVBoxLayout *layout;
diff --git a/cockatrice/src/interface/pixel_map_generator.cpp b/cockatrice/src/interface/pixel_map_generator.cpp
index b70dc576f..9b8c4bcdc 100644
--- a/cockatrice/src/interface/pixel_map_generator.cpp
+++ b/cockatrice/src/interface/pixel_map_generator.cpp
@@ -1,7 +1,5 @@
#include "pixel_map_generator.h"
-#include "theme_manager.h"
-
#include
#include
#include
@@ -84,13 +82,7 @@ static QPixmap loadSvg(const QString &svgPath, const QSize &size, bool expandOnl
/**
* Try to load path image from non-SVG formats, otherwise fall back to SVG.
* This is to allow custom themes to support non-SVG format type overrides, since SVG requires custom loading.
- *
- * The path may already carry the resolved file extension (e.g. via
- * ThemeManager::assetPath); such paths are loaded directly. Otherwise a
- * format-agnostic lookup probes png, jpg and finally svg.
- *
- * @param path The path to the file, with no file extension unless the caller
- * already resolved it. File formats will be automatically detected.
+ * @param path The path to the file, with no file extension. File formats will be automatically detected.
* @param size The desired size of the pixmap.
* @param expandOnly If true, then keep the size of the initial pixmap to at least the size (Only relevant if SVG).
*
@@ -98,19 +90,6 @@ static QPixmap loadSvg(const QString &svgPath, const QSize &size, bool expandOnl
*/
static QPixmap tryLoadImage(const QString &path, const QSize &size, bool expandOnly = false)
{
- if (path.endsWith(QLatin1String(".svg"), Qt::CaseInsensitive)) {
- return loadSvg(path, size, expandOnly);
- }
- if (path.endsWith(QLatin1String(".png"), Qt::CaseInsensitive) ||
- path.endsWith(QLatin1String(".jpg"), Qt::CaseInsensitive) ||
- path.endsWith(QLatin1String(".jpeg"), Qt::CaseInsensitive)) {
- QPixmap pix(path);
- if (!pix.isNull()) {
- return pix.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
- }
- return {};
- }
-
const auto formats = {"png", "jpg"};
QPixmap returnPixmap;
@@ -132,8 +111,7 @@ QPixmap PhasePixmapGenerator::generatePixmap(int height, QString name)
return pmCache.value(key);
}
- QPixmap pixmap = tryLoadImage(QStringLiteral("theme:") + themeManager->assetPath(QStringLiteral("phases/") + name),
- QSize(height, height));
+ QPixmap pixmap = tryLoadImage("theme:phases/" + name, QSize(height, height));
pmCache.insert(key, pixmap);
return pixmap;
@@ -361,10 +339,6 @@ static QString getIconType(const bool isBuddy, const UserLevelFlags &userLevelFl
return "pawn_judge";
}
- if (userLevelFlags.testFlag(ServerInfo_User::IsDeveloper)) {
- return "pawn_dev";
- }
-
if (!privLevel.isEmpty() && privLevel.toLower() != "none") {
return QString("pawn_%1").arg(privLevel.toLower());
}
@@ -422,8 +396,7 @@ QPixmap LockPixmapGenerator::generatePixmap(int height)
return pmCache.value(key);
}
- QPixmap pixmap = tryLoadImage(QStringLiteral("theme:") + themeManager->assetPath(QStringLiteral("icons/lock")),
- QSize(height, height), true);
+ QPixmap pixmap = tryLoadImage("theme:icons/lock", QSize(height, height), true);
pmCache.insert(key, pixmap);
return pixmap;
}
@@ -438,8 +411,7 @@ QPixmap DropdownIconPixmapGenerator::generatePixmap(int height, bool expanded)
}
QString name = expanded ? "dropdown_expanded" : "dropdown_collapsed";
- QPixmap pixmap = tryLoadImage(QStringLiteral("theme:") + themeManager->assetPath(QStringLiteral("icons/") + name),
- QSize(height, height), true);
+ QPixmap pixmap = tryLoadImage("theme:icons/" + name, QSize(height, height), true);
pmCache.insert(key, pixmap);
return pixmap;
@@ -500,13 +472,6 @@ QHash ManaSymbolPixmapGenerator::scaledCache;
QPixmap loadColorAdjustedPixmap(const QString &name)
{
- // Prefer an authored scheme-qualified variant when one exists for this asset.
- const QString variant = themeManager->schemeVariantPath(QStringView(name).mid(QStringLiteral("theme:").size()));
- if (!variant.isEmpty()) {
- return QPixmap(QStringLiteral("theme:") + variant);
- }
-
- // Legacy fallback: runtime-invert for dark mode when no authored variant.
if (qApp->palette().windowText().color().lightness() > 200) {
QImage img(name);
img.invertPixels();
@@ -517,21 +482,3 @@ QPixmap loadColorAdjustedPixmap(const QString &name)
return QPixmap(name);
}
}
-
-QPixmap themePixmap(QStringView prefix)
-{
- const QString resolved = themeManager->assetPath(prefix);
- return QPixmap(QStringLiteral("theme:") + resolved);
-}
-
-void clearPixmapGeneratorCaches()
-{
- PhasePixmapGenerator::clear();
- CounterPixmapGenerator::clear();
- PingPixmapGenerator::clear();
- CountryPixmapGenerator::clear();
- UserLevelPixmapGenerator::clear();
- LockPixmapGenerator::clear();
- DropdownIconPixmapGenerator::clear();
- ManaSymbolPixmapGenerator::clear();
-}
diff --git a/cockatrice/src/interface/pixel_map_generator.h b/cockatrice/src/interface/pixel_map_generator.h
index b6e822fd9..17720166a 100644
--- a/cockatrice/src/interface/pixel_map_generator.h
+++ b/cockatrice/src/interface/pixel_map_generator.h
@@ -156,15 +156,4 @@ public:
QPixmap loadColorAdjustedPixmap(const QString &name);
-// Loads a "theme:" asset (with no file extension in prefix), preferring the
-// scheme-qualified variant (prefix-dark / prefix-light, resolved via
-// ThemeManager::assetPath) and falling back to the plain asset. Callers load
-// the returned path directly. Use for scheme-sensitive pixmaps like
-// backgrounds, the card back, and the app logo.
-QPixmap themePixmap(QStringView prefix);
-
-// Clears every PixmapGenerator's static cache so scheme variants are
-// re-resolved when the active theme or color scheme changes.
-void clearPixmapGeneratorCaches();
-
#endif
diff --git a/cockatrice/src/interface/theme_config.cpp b/cockatrice/src/interface/theme_config.cpp
index 8293a82cf..3c43c467d 100644
--- a/cockatrice/src/interface/theme_config.cpp
+++ b/cockatrice/src/interface/theme_config.cpp
@@ -16,7 +16,7 @@ QString ThemeConfig::toIni() const
out += "[Appearance]\n";
out += QString("ColorScheme = %1\n").arg(colorScheme.isEmpty() ? "System" : colorScheme);
out += "\n[Style]\n";
- out += QString("Name = %1\n").arg(styleName.isEmpty() ? "System" : styleName);
+ out += QString("Name = %1\n").arg(styleName.isEmpty() ? "Default" : styleName);
return out;
}
@@ -96,7 +96,7 @@ bool ThemeConfig::save(const QString &themeDirPath) const
bool PaletteConfig::hasPalette() const
{
- return !colors.isEmpty() || !appColors.isEmpty();
+ return !colors.isEmpty();
}
QString PaletteConfig::toToml() const
@@ -133,24 +133,6 @@ QString PaletteConfig::toToml() const
out += "\n";
}
- if (!appColors.isEmpty()) {
- QMetaEnum appEnum = QMetaEnum::fromType();
-
- out += "[AppColors]\n";
-
- for (auto it = appColors.cbegin(); it != appColors.cend(); ++it) {
- const char *roleName = appEnum.valueToKey(it.key());
-
- if (!roleName) {
- continue;
- }
-
- out += QString("%1 = %2\n").arg(QString(roleName), -20).arg(it.value().name(QColor::HexArgb));
- }
-
- out += "\n";
- }
-
return out;
}
@@ -170,7 +152,6 @@ PaletteConfig PaletteConfig::fromFile(const QString &filePath)
}
QMetaEnum roleEnum = QMetaEnum::fromType();
- QMetaEnum appEnum = QMetaEnum::fromType();
QString currentSection;
QPalette::ColorGroup currentGroup = QPalette::Active;
@@ -221,26 +202,6 @@ PaletteConfig PaletteConfig::fromFile(const QString &filePath)
}
}
- QColor color(value);
-
- if (!color.isValid()) {
- continue;
- }
-
- if (currentSection.compare("AppColors", Qt::CaseInsensitive) == 0) {
- if (key.startsWith("AppColor::")) {
- key = key.mid(10);
- }
-
- int appRoleInt = appEnum.keyToValue(key.toUtf8().constData());
-
- if (appRoleInt >= 0) {
- cfg.appColors[static_cast(appRoleInt)] = color;
- }
-
- continue;
- }
-
if (!currentSection.startsWith("Palette", Qt::CaseInsensitive)) {
continue;
}
@@ -255,7 +216,11 @@ PaletteConfig PaletteConfig::fromFile(const QString &filePath)
continue;
}
- cfg.colors[currentGroup][static_cast(roleInt)] = color;
+ QColor color(value);
+
+ if (color.isValid()) {
+ cfg.colors[currentGroup][static_cast(roleInt)] = color;
+ }
}
return cfg;
diff --git a/cockatrice/src/interface/theme_config.h b/cockatrice/src/interface/theme_config.h
index 567aeccda..07bf55b7a 100644
--- a/cockatrice/src/interface/theme_config.h
+++ b/cockatrice/src/interface/theme_config.h
@@ -3,25 +3,9 @@
#include
#include
-#include
#include
#include
-// Application-specific color roles, layered on top of the fixed QPalette role
-// set. Stored in the same palette-.toml under an [AppColors] section
-// and editable from the palette editor, so theme authors can control colors
-// beyond what Qt's palette can express.
-namespace AppColor
-{
-Q_NAMESPACE
-enum Role
-{
- AccentStrong,
- AccentSoft,
-};
-Q_ENUM_NS(Role)
-} // namespace AppColor
-
struct ThemeConfig
{
QString colorScheme;
@@ -37,16 +21,7 @@ struct ThemeConfig
struct PaletteConfig
{
QMap> colors;
- QMap appColors;
- bool operator==(const PaletteConfig &rhs) const
- {
- return colors == rhs.colors && appColors == rhs.appColors;
- }
- bool operator!=(const PaletteConfig &rhs) const
- {
- return !(*this == rhs);
- }
bool hasPalette() const;
QString toToml() const;
diff --git a/cockatrice/src/interface/theme_manager.cpp b/cockatrice/src/interface/theme_manager.cpp
index d86ed77f9..e6b4b3c7f 100644
--- a/cockatrice/src/interface/theme_manager.cpp
+++ b/cockatrice/src/interface/theme_manager.cpp
@@ -1,13 +1,10 @@
#include "theme_manager.h"
#include "../../client/settings/cache_settings.h"
-#include "pixel_map_generator.h"
#include
#include
#include
-#include
-#include
#include
#include
#include
@@ -22,7 +19,7 @@
#include
#include
-#define SYSTEM_THEME_NAME "System"
+#define NONE_THEME_NAME "Default"
#define FUSION_THEME_NAME "Fusion"
#define STYLE_CSS_NAME "style.css"
#define HANDZONE_BG_NAME "handzone"
@@ -96,7 +93,7 @@ struct PaletteColorInfo
static QString usableDefaultStyle(const QString &style)
{
// The Windows 11 native style is broken: when the OS default
- // ("System" theme selection) would use it, fall back to the Vista style.
+ // ("Default" theme selection) would use it, fall back to the Vista style.
// Explicitly choosing "windows11" in a theme is still honored.
return style.compare("windows11", Qt::CaseInsensitive) == 0 ? QStringLiteral("windowsvista") : style;
}
@@ -119,16 +116,10 @@ ThemeManager::ThemeManager(QObject *parent) : QObject(parent)
void ThemeManager::ensureThemeDirectoryExists()
{
- auto &settings = SettingsCache::instance();
-
- // Migrate the old "Default" theme name to "System"
- if (settings.getThemeName() == "Default") {
- settings.setThemeName(SYSTEM_THEME_NAME);
- }
-
- if (settings.getThemeName().isEmpty() || !getAvailableThemes().contains(settings.getThemeName())) {
+ if (SettingsCache::instance().getThemeName().isEmpty() ||
+ !getAvailableThemes().contains(SettingsCache::instance().getThemeName())) {
qCInfo(ThemeManagerLog) << "Theme name not set, setting default value";
- settings.setThemeName(FUSION_THEME_NAME);
+ SettingsCache::instance().setThemeName(NONE_THEME_NAME);
}
}
@@ -149,74 +140,11 @@ bool ThemeManager::isDarkMode(const QString &themeDirPath) const
}
}
-QString ThemeManager::schemeVariantPath(QStringView prefix) const
+bool ThemeManager::isBuiltInTheme()
{
- static const QStringList formats = {QStringLiteral(".png"), QStringLiteral(".jpg"), QStringLiteral(".jpeg"),
- QStringLiteral(".svg")};
- const QString scheme = isDarkMode(currentThemePath) ? QStringLiteral("dark") : QStringLiteral("light");
- const QString variantStem = prefix.toString() + QLatin1Char('-') + scheme;
+ const auto themeName = SettingsCache::instance().getThemeName();
- for (const QString &format : formats) {
- if (QFileInfo::exists(QStringLiteral("theme:") + variantStem + format)) {
- return variantStem + format;
- }
- }
- return QString();
-}
-
-QString ThemeManager::assetPath(QStringView prefix) const
-{
- // Probe order mirrors tryLoadImage: a theme may override the default SVG
- // with a raster of the same stem, so raster wins over SVG within a stem.
- static const QStringList formats = {QStringLiteral(".png"), QStringLiteral(".jpg"), QStringLiteral(".jpeg"),
- QStringLiteral(".svg")};
-
- auto findExisting = [](const QString &stem) {
- for (const QString &format : formats) {
- if (QFileInfo::exists(QStringLiteral("theme:") + stem + format)) {
- return stem + format;
- }
- }
- return QString();
- };
-
- // Prefer the scheme-qualified variant when it exists, else the plain
- // asset as the super fallback. Both return the resolved path including
- // its file extension so callers can load it directly.
- const QString variant = schemeVariantPath(prefix);
- if (!variant.isEmpty()) {
- return variant;
- }
- const QString resolvedPlain = findExisting(prefix.toString());
- return resolvedPlain.isEmpty() ? prefix.toString() : resolvedPlain;
-}
-
-// Probe whether a directory is truly writable by trying to create and remove a
-// temporary file. QFileInfo::isWritable() on a directory is unreliable (notably
-// on Windows where UAC VirtualStore can make a system dir appear writable).
-bool ThemeManager::isDirReallyWritable(const QString &dirPath)
-{
- const QString probe = QDir(dirPath).absoluteFilePath(".cockatrice_write_test");
- QFile f(probe);
- if (!f.open(QIODevice::WriteOnly)) {
- return false;
- }
- f.close();
- f.remove();
- return true;
-}
-
-QString ThemeManager::writableThemeDir(const QString &themeName)
-{
- // All theme writes go to the user themes directory regardless of whether
- // the resolved (system) theme directory happens to be writable. Even when a
- // write would succeed in-place, routing it to the user directory keeps the
- // install intact and guarantees changes survive upgrades.
- const QString dirPath = QDir(SettingsCache::instance().paths().getThemesPath()).absoluteFilePath(themeName);
- if (!QDir().mkpath(dirPath)) {
- qWarning() << "Failed to create theme save directory:" << dirPath;
- }
- return dirPath;
+ return themeName == NONE_THEME_NAME || themeName == FUSION_THEME_NAME;
}
// System (read-only) themes location, relative to the application binary.
@@ -241,7 +169,9 @@ QStringMap &ThemeManager::getAvailableThemes()
// load themes from user profile dir
dir.setPath(SettingsCache::instance().paths().getThemesPath());
- availableThemes.insert(SYSTEM_THEME_NAME, dir.absoluteFilePath("System"));
+ // add default value
+ availableThemes.insert(NONE_THEME_NAME, dir.absoluteFilePath("Default"));
+
availableThemes.insert(FUSION_THEME_NAME, dir.absoluteFilePath("Fusion"));
for (QString themeName : dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name)) {
@@ -250,7 +180,7 @@ QStringMap &ThemeManager::getAvailableThemes()
}
}
- // Load themes from Cockatrice system dir
+ // load themes from cockatrice system dir
dir.setPath(systemThemesBasePath());
for (QString themeName : dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name)) {
@@ -265,7 +195,7 @@ QStringMap &ThemeManager::getAvailableThemes()
QBrush ThemeManager::loadBrush(QString fileName, QColor fallbackColor)
{
QBrush brush;
- QPixmap tmp = QPixmap("theme:" + assetPath(QStringLiteral("zones/") + fileName));
+ QPixmap tmp = QPixmap("theme:zones/" + fileName);
if (tmp.isNull()) {
brush.setColor(fallbackColor);
brush.setStyle(Qt::SolidPattern);
@@ -279,7 +209,7 @@ QBrush ThemeManager::loadBrush(QString fileName, QColor fallbackColor)
QBrush ThemeManager::loadExtraBrush(QString fileName, QBrush &fallbackBrush)
{
QBrush brush;
- QPixmap tmp = QPixmap("theme:" + assetPath(QStringLiteral("zones/") + fileName));
+ QPixmap tmp = QPixmap("theme:zones/" + fileName);
if (tmp.isNull()) {
brush = fallbackBrush;
@@ -357,7 +287,7 @@ bool ThemeManager::commitPalette(const QString &themeDirPath, const QString &col
void ThemeManager::setColorScheme(const QString &scheme)
{
- const QString dirPath = writableThemeDir(SettingsCache::instance().getThemeName());
+ const QString dirPath = getAvailableThemes().value(SettingsCache::instance().getThemeName());
ThemeConfig cfg = ThemeConfig::fromThemeDir(dirPath);
cfg.colorScheme = scheme;
@@ -368,7 +298,7 @@ void ThemeManager::setColorScheme(const QString &scheme)
void ThemeManager::setStyleName(const QString &styleName)
{
- const QString dirPath = writableThemeDir(SettingsCache::instance().getThemeName());
+ const QString dirPath = getAvailableThemes().value(SettingsCache::instance().getThemeName());
ThemeConfig cfg = ThemeConfig::fromThemeDir(dirPath);
cfg.styleName = styleName;
@@ -399,7 +329,7 @@ void ThemeManager::applyStyleAndPalette(const QString &themeName,
Q_UNUSED(activeScheme)
#endif
QString styleName = themeCfg.styleName;
- if (styleName.isEmpty() || styleName.compare("System", Qt::CaseInsensitive) == 0) {
+ if (styleName.isEmpty() || styleName.compare("Default", Qt::CaseInsensitive) == 0) {
if (themeName == FUSION_THEME_NAME) {
styleName = "Fusion";
} else {
@@ -442,8 +372,6 @@ void ThemeManager::applyStyleAndPalette(const QString &themeName,
qApp->setPalette(base);
qApp->setStyle(style);
- currentAppColors = palCfg.appColors;
-
// Force every widget to re-polish and repaint immediately rather than
// waiting for natural expose events, which produces a patchwork of old
// and new colours during a live preview.
@@ -456,35 +384,6 @@ void ThemeManager::applyStyleAndPalette(const QString &themeName,
style->polish(widget);
widget->update();
}
-
- emit paletteChanged();
-}
-
-QColor ThemeManager::appColor(AppColor::Role role) const
-{
- const auto it = currentAppColors.constFind(role);
- if (it != currentAppColors.constEnd()) {
- return it.value();
- }
-
- // QPalette::Accent was introduced in Qt 6.6 and several shipped palettes
- // set it to a value barely distinguishable from Window, so it is not a
- // reliable accent source. The selection highlight is the stable accent
- // (Accent defaults to Highlight when unset), and deriving from it
- // unconditionally keeps every Qt version rendering identically.
- const QColor accent = qApp->palette().color(QPalette::Active, QPalette::Highlight);
-
- if (role == AppColor::AccentSoft) {
- constexpr int SOFT_SATURATION_PERCENT = 70;
- constexpr int SOFT_LIGHTNESS_OFFSET = 60;
-
- // Light end of the gradient: same hue, softened and lightened
- return QColor::fromHsl(qMax(0, accent.hslHue()),
- qBound(0, qRound(accent.hslSaturation() * SOFT_SATURATION_PERCENT / 100.0), 255),
- qBound(0, accent.lightness() + SOFT_LIGHTNESS_OFFSET, 255));
- }
-
- return accent;
}
void ThemeManager::themeChangedSlot()
@@ -494,19 +393,9 @@ void ThemeManager::themeChangedSlot()
currentThemePath = dirPath;
QDir dir(dirPath);
- // CSS — prefer the scheme-qualified stylesheet (style-dark.css /
- // style-light.css) when present, else the plain style.css as fallback.
- if (!dirPath.isEmpty()) {
- const QString scheme = isDarkMode(dirPath) ? QStringLiteral("dark") : QStringLiteral("light");
- const QString schemeCss = QFileInfo(QStringLiteral(STYLE_CSS_NAME)).completeBaseName() + QLatin1Char('-') +
- scheme + QStringLiteral(".css");
- if (dir.exists(schemeCss)) {
- qApp->setStyleSheet("file:///" + dir.absoluteFilePath(schemeCss));
- } else if (dir.exists(STYLE_CSS_NAME)) {
- qApp->setStyleSheet("file:///" + dir.absoluteFilePath(STYLE_CSS_NAME));
- } else {
- qApp->setStyleSheet("");
- }
+ // CSS
+ if (!dirPath.isEmpty() && dir.exists(STYLE_CSS_NAME)) {
+ qApp->setStyleSheet("file:///" + dir.absoluteFilePath(STYLE_CSS_NAME));
} else {
qApp->setStyleSheet("");
}
@@ -521,19 +410,8 @@ void ThemeManager::themeChangedSlot()
// ── Load palette: custom first, then theme default ────────────────────
PaletteConfig palette = PaletteConfig::fromScheme(dirPath, activeScheme);
- const PaletteConfig themeDefault = ThemeManager::loadDefaultPaletteConfig(dirPath, themeName, activeScheme);
- if (palette.hasPalette()) {
- // A custom palette written before [AppColors] existed carries no app
- // colors; merge the theme's shipped defaults so the identity colors
- // survive (hasPalette() counts an app-colors-only file as a palette,
- // so those are kept wholesale and never reach here empty).
- for (auto it = themeDefault.appColors.cbegin(); it != themeDefault.appColors.cend(); ++it) {
- if (!palette.appColors.contains(it.key())) {
- palette.appColors.insert(it.key(), it.value());
- }
- }
- } else {
- palette = themeDefault;
+ if (!palette.hasPalette()) {
+ palette = ThemeManager::loadDefaultPaletteConfig(dirPath, themeName, activeScheme);
}
applyStyleAndPalette(themeName, themeCfg, palette, activeScheme);
@@ -568,7 +446,6 @@ void ThemeManager::themeChangedSlot()
}
QPixmapCache::clear();
- clearPixmapGeneratorCaches();
emit themeChanged();
}
diff --git a/cockatrice/src/interface/theme_manager.h b/cockatrice/src/interface/theme_manager.h
index aadb38ee9..79a1b6470 100644
--- a/cockatrice/src/interface/theme_manager.h
+++ b/cockatrice/src/interface/theme_manager.h
@@ -50,7 +50,6 @@ private:
QString currentThemePath;
std::array brushes;
QStringMap availableThemes;
- QMap currentAppColors;
/*
Internal cache for multiple backgrounds
*/
@@ -66,16 +65,7 @@ protected:
const QString &activeScheme);
public:
- // Resolves the directory to write theme changes to for the given theme
- // name. The resolved theme dir (user or system) is used when writable;
- // read-only system themes fall back to the user themes directory, creating
- // it if needed, so customisations never get lost on upgrade.
- static QString writableThemeDir(const QString &themeName);
- // Probe whether a directory is truly writable by trying to create and remove
- // a temporary file. QFileInfo::isWritable() on a directory is unreliable
- // (notably on Windows where UAC VirtualStore can make a system dir appear
- // writable).
- static bool isDirReallyWritable(const QString &dirPath);
+ bool isBuiltInTheme();
// Explicit color scheme of the theme: theme.cfg's ColorScheme setting
// (Dark/Light), falling back to the OS color scheme when it is "System".
bool isDarkMode(const QString &themeDirPath) const;
@@ -97,20 +87,6 @@ public:
// Load/save per-scheme palette colors
static PaletteConfig loadPaletteConfig(const QString &themeDirPath, const QString &colorScheme);
static bool savePaletteConfig(const QString &themeDirPath, const QString &colorScheme, const PaletteConfig &cfg);
- // Resolve prefix to a scheme-qualified "theme:" path. Existence is probed
- // internally across the formats themes may ship (.png/.jpg/.svg), so
- // callers load the returned path directly. Prefers "-"
- // when a file exists at that stem, otherwise the plain "" as the
- // super fallback. The resolved scheme covers explicit light/dark as well
- // as OS-resolved "system". Returns the path with its file extension when a
- // match is found; unqualified assets keep working unchanged.
- QString assetPath(QStringView prefix) const;
- // Like assetPath, but resolves only the scheme-qualified variant
- // ("-.") and returns an empty string when no
- // variant exists — it never falls back to the plain "" asset.
- // Callers that must distinguish "no authored variant" (e.g. to keep a
- // legacy runtime fallback alive) should use this instead of assetPath.
- QString schemeVariantPath(QStringView prefix) const;
// Load the theme's shipped default palette, falling back to the system
// theme directory when it is absent from the resolved (user) directory.
static PaletteConfig
@@ -125,17 +101,12 @@ public:
void reloadCurrentTheme();
void previewPalette(const PaletteConfig &cfg, const QString &scheme);
- // Resolves an application color role: the theme's stored [AppColors] value
- // when present, otherwise a palette-accent-derived fallback.
- QColor appColor(AppColor::Role role) const;
-
QBrush &getBgBrush(Role zone);
QBrush getExtraBgBrush(Role zone, int zoneId = 0);
protected slots:
void themeChangedSlot();
signals:
void themeChanged();
- void paletteChanged();
};
extern ThemeManager *themeManager;
diff --git a/cockatrice/src/interface/widgets/cards/card_art_utils.cpp b/cockatrice/src/interface/widgets/cards/card_art_utils.cpp
deleted file mode 100644
index b26b73593..000000000
--- a/cockatrice/src/interface/widgets/cards/card_art_utils.cpp
+++ /dev/null
@@ -1,18 +0,0 @@
-#include "card_art_utils.h"
-
-#include
-#include
-
-namespace CardArtUtils
-{
-QPixmap rotateSidewaysLayoutArt(const QPixmap &art, const ExactCard &card)
-{
- if (!card.getInfo().getUiAttributes().landscapeOrientation) {
- return art;
- }
-
- QTransform transform;
- transform.rotate(90);
- return art.transformed(transform, Qt::SmoothTransformation);
-}
-} // namespace CardArtUtils
\ No newline at end of file
diff --git a/cockatrice/src/interface/widgets/cards/card_art_utils.h b/cockatrice/src/interface/widgets/cards/card_art_utils.h
deleted file mode 100644
index 5c331a12c..000000000
--- a/cockatrice/src/interface/widgets/cards/card_art_utils.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef CARD_ART_UTILS_H
-#define CARD_ART_UTILS_H
-
-#include
-
-class ExactCard;
-
-namespace CardArtUtils
-{
-/**
- * @brief Rotates a card's art upright when its layout shows sideways.
- *
- * Sideways-layout cards (planes, sieges/battles, split cards) store their
- * landscape artwork rotated 90° inside a portrait frame. Art-crop displays,
- * playmat art, and the card-info picture must show such art upright before
- * sampling or painting. Portrait cards are returned unchanged.
- *
- * @param art The card pixmap to orient.
- * @param card The card describing the art orientation.
- * @return @p art rotated 90° clockwise for sideways-layout cards, else @p art.
- */
-QPixmap rotateSidewaysLayoutArt(const QPixmap &art, const ExactCard &card);
-} // namespace CardArtUtils
-
-#endif // CARD_ART_UTILS_H
\ No newline at end of file
diff --git a/cockatrice/src/interface/widgets/cards/card_info_picture_widget.cpp b/cockatrice/src/interface/widgets/cards/card_info_picture_widget.cpp
index 2dd21e78a..79ae087d7 100644
--- a/cockatrice/src/interface/widgets/cards/card_info_picture_widget.cpp
+++ b/cockatrice/src/interface/widgets/cards/card_info_picture_widget.cpp
@@ -5,7 +5,6 @@
#include "../../../interface/card_picture_loader/card_picture_loader.h"
#include "../../../interface/widgets/tabs/tab_supervisor.h"
#include "../../window_main.h"
-#include "card_art_utils.h"
#include
#include
@@ -74,8 +73,6 @@ CardInfoPictureWidget::CardInfoPictureWidget(QWidget *parent, const bool _hoverT
update();
});
- connect(&SettingsCache::instance().cardsDisplay(), &CardsDisplaySettings::cardLangChanged, this,
- &CardInfoPictureWidget::updatePixmap);
}
/**
@@ -196,7 +193,12 @@ void CardInfoPictureWidget::paintEvent(QPaintEvent *event)
QPixmap transformedPixmap = resizedPixmap; // Default pixmap
if (SettingsCache::instance().cardsDisplay().getAutoRotateSidewaysLayoutCards()) {
- transformedPixmap = CardArtUtils::rotateSidewaysLayoutArt(resizedPixmap, exactCard);
+ if (exactCard.getInfo().getUiAttributes().landscapeOrientation) {
+ // Rotate pixmap 90 degrees to the left
+ QTransform transform;
+ transform.rotate(90);
+ transformedPixmap = resizedPixmap.transformed(transform, Qt::SmoothTransformation);
+ }
}
// Handle DPI scaling
diff --git a/cockatrice/src/interface/widgets/cards/card_info_text_widget.cpp b/cockatrice/src/interface/widgets/cards/card_info_text_widget.cpp
index e98c3c02a..c6af5320b 100644
--- a/cockatrice/src/interface/widgets/cards/card_info_text_widget.cpp
+++ b/cockatrice/src/interface/widgets/cards/card_info_text_widget.cpp
@@ -1,7 +1,6 @@
#include "card_info_text_widget.h"
#include "../../../game_graphics/board/card_item.h"
-#include "../../card_localization.h"
#include
#include
@@ -11,7 +10,7 @@
#include
#include
-CardInfoTextWidget::CardInfoTextWidget(QWidget *parent) : QFrame(parent)
+CardInfoTextWidget::CardInfoTextWidget(QWidget *parent) : QFrame(parent), info(nullptr)
{
propsLabel = new QLabel;
propsLabel->setOpenExternalLinks(false);
@@ -40,12 +39,6 @@ CardInfoTextWidget::CardInfoTextWidget(QWidget *parent) : QFrame(parent)
grid->setRowStretch(1, 1);
retranslateUi();
-
- connect(&SettingsCache::instance().cardsDisplay(), &CardsDisplaySettings::cardLangChanged, this, [this] {
- if (currentCard) {
- setCard(currentCard);
- }
- });
}
void CardInfoTextWidget::setTexts(const QString &propsText, const QString &textText)
@@ -67,7 +60,7 @@ void CardInfoTextWidget::setCard(const ExactCard &exactCard)
QString text = "";
text += QString("| %1 | | %2 |
")
- .arg(tr("Name:"), CardLocalization::displayName(card).toHtmlEscaped());
+ .arg(tr("Name:"), card->getName().toHtmlEscaped());
if (!exactCard.getPrinting().isEmpty()) {
QString setShort = exactCard.getPrinting().getSet()->getShortName().toHtmlEscaped();
@@ -101,8 +94,7 @@ void CardInfoTextWidget::setCard(const ExactCard &exactCard)
}
text += "
";
- setTexts(text, CardLocalization::displayText(card));
- currentCard = exactCard;
+ setTexts(text, card->getText());
}
void CardInfoTextWidget::setInvalidCardName(const QString &cardName)
diff --git a/cockatrice/src/interface/widgets/cards/card_info_text_widget.h b/cockatrice/src/interface/widgets/cards/card_info_text_widget.h
index 683be5ab5..a9c29da37 100644
--- a/cockatrice/src/interface/widgets/cards/card_info_text_widget.h
+++ b/cockatrice/src/interface/widgets/cards/card_info_text_widget.h
@@ -23,7 +23,7 @@ private:
QLabel *propsLabel;
QScrollArea *propsScroll;
QTextEdit *textLabel;
- ExactCard currentCard; ///< Last card set, re-rendered when the card language changes.
+ CardInfoPtr info;
void setTexts(const QString &propsText, const QString &textText);
public:
diff --git a/cockatrice/src/interface/widgets/deck_analytics/abstract_analytics_panel_widget.cpp b/cockatrice/src/interface/widgets/deck_analytics/abstract_analytics_panel_widget.cpp
index 483fc71b0..089abc5c8 100644
--- a/cockatrice/src/interface/widgets/deck_analytics/abstract_analytics_panel_widget.cpp
+++ b/cockatrice/src/interface/widgets/deck_analytics/abstract_analytics_panel_widget.cpp
@@ -1,6 +1,5 @@
#include "abstract_analytics_panel_widget.h"
-#include "../../pixel_map_generator.h"
#include "deck_list_statistics_analyzer.h"
#include
@@ -21,7 +20,7 @@ AbstractAnalyticsPanelWidget::AbstractAnalyticsPanelWidget(QWidget *parent, Deck
// config button
configureButton = new QPushButton(this);
- configureButton->setIcon(themePixmap(QStringLiteral("icons/cogwheel")));
+ configureButton->setIcon(QPixmap("theme:icons/cogwheel"));
configureButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
connect(configureButton, &QPushButton::clicked, this, &AbstractAnalyticsPanelWidget::applyConfigFromDialog);
bannerAndSettingsLayout->addWidget(configureButton, 0);
diff --git a/cockatrice/src/interface/widgets/deck_editor/deck_editor_database_display_widget.cpp b/cockatrice/src/interface/widgets/deck_editor/deck_editor_database_display_widget.cpp
index c8bdacf0d..9da821813 100644
--- a/cockatrice/src/interface/widgets/deck_editor/deck_editor_database_display_widget.cpp
+++ b/cockatrice/src/interface/widgets/deck_editor/deck_editor_database_display_widget.cpp
@@ -28,7 +28,7 @@ DeckEditorDatabaseDisplayWidget::DeckEditorDatabaseDisplayWidget(QWidget *parent
searchEdit->setPlaceholderText(tr("Search by card name (or search expressions)"));
searchEdit->setClearButtonEnabled(true);
searchEdit->addAction(loadColorAdjustedPixmap("theme:icons/search"), QLineEdit::LeadingPosition);
- auto help = searchEdit->addAction(themePixmap(QStringLiteral("icons/info")), QLineEdit::TrailingPosition);
+ auto help = searchEdit->addAction(QPixmap("theme:icons/info"), QLineEdit::TrailingPosition);
setFocusProxy(searchEdit);
setFocusPolicy(Qt::ClickFocus);
@@ -59,13 +59,13 @@ DeckEditorDatabaseDisplayWidget::DeckEditorDatabaseDisplayWidget(QWidget *parent
&DeckEditorDatabaseDisplayWidget::onRelatedCardClicked);
aAddCard = new QAction(QString(), this);
- aAddCard->setIcon(themePixmap(QStringLiteral("icons/arrow_right_green")));
+ aAddCard->setIcon(QPixmap("theme:icons/arrow_right_green"));
connect(aAddCard, &QAction::triggered, this, &DeckEditorDatabaseDisplayWidget::actAddCardToMainDeck);
auto *tbAddCard = new QToolButton(this);
tbAddCard->setDefaultAction(aAddCard);
aAddCardToSideboard = new QAction(QString(), this);
- aAddCardToSideboard->setIcon(themePixmap(QStringLiteral("icons/arrow_right_blue")));
+ aAddCardToSideboard->setIcon(QPixmap("theme:icons/arrow_right_blue"));
connect(aAddCardToSideboard, &QAction::triggered, this, &DeckEditorDatabaseDisplayWidget::actAddCardToSideboard);
auto *tbAddCardToSideboard = new QToolButton(this);
tbAddCardToSideboard->setDefaultAction(aAddCardToSideboard);
diff --git a/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.cpp b/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
index b0b31074c..e2175a358 100644
--- a/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
+++ b/cockatrice/src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
@@ -2,7 +2,6 @@
#include "../../../client/settings/cache_settings.h"
#include "../../../client/settings/shortcuts_settings.h"
-#include "../../pixel_map_generator.h"
#include "../playmat/playmat_settings_dialog.h"
#include "../settings_page/user_interface_settings_page.h"
#include "../tabs/api/commander_spellbook/commander_bracket_widget.h"
@@ -193,25 +192,25 @@ void DeckEditorDeckDockWidget::createDeckDock()
&DeckEditorDeckDockWidget::applyActiveGroupCriteria);
aIncrement = new QAction(QString(), this);
- aIncrement->setIcon(themePixmap(QStringLiteral("icons/increment")));
+ aIncrement->setIcon(QPixmap("theme:icons/increment"));
connect(aIncrement, &QAction::triggered, this, &DeckEditorDeckDockWidget::actIncrementSelection);
auto *tbIncrement = new QToolButton(this);
tbIncrement->setDefaultAction(aIncrement);
aDecrement = new QAction(QString(), this);
- aDecrement->setIcon(themePixmap(QStringLiteral("icons/decrement")));
+ aDecrement->setIcon(QPixmap("theme:icons/decrement"));
connect(aDecrement, &QAction::triggered, this, &DeckEditorDeckDockWidget::actDecrementSelection);
auto *tbDecrement = new QToolButton(this);
tbDecrement->setDefaultAction(aDecrement);
aRemoveCard = new QAction(QString(), this);
- aRemoveCard->setIcon(themePixmap(QStringLiteral("icons/remove_row")));
+ aRemoveCard->setIcon(QPixmap("theme:icons/remove_row"));
connect(aRemoveCard, &QAction::triggered, this, &DeckEditorDeckDockWidget::actRemoveCard);
auto *tbRemoveCard = new QToolButton(this);
tbRemoveCard->setDefaultAction(aRemoveCard);
aSwapCard = new QAction(QString(), this);
- aSwapCard->setIcon(themePixmap(QStringLiteral("icons/swap")));
+ aSwapCard->setIcon(QPixmap("theme:icons/swap"));
connect(aSwapCard, &QAction::triggered, this, &DeckEditorDeckDockWidget::actSwapSelection);
auto *tbSwapCard = new QToolButton(this);
tbSwapCard->setDefaultAction(aSwapCard);
@@ -345,9 +344,7 @@ ExactCard DeckEditorDeckDockWidget::getCurrentCard()
if (!current.isValid()) {
return {};
}
- // The display role holds the localized card name; the edit role always carries the
- // canonical English name needed to look the card up in the database.
- const QString cardName = current.siblingAtColumn(DeckListModelColumns::CARD_NAME).data(Qt::EditRole).toString();
+ const QString cardName = current.siblingAtColumn(DeckListModelColumns::CARD_NAME).data().toString();
const QString cardProviderID = current.siblingAtColumn(DeckListModelColumns::CARD_PROVIDER_ID).data().toString();
const QModelIndex gparent = current.parent().parent();
diff --git a/cockatrice/src/interface/widgets/deck_editor/deck_editor_filter_dock_widget.cpp b/cockatrice/src/interface/widgets/deck_editor/deck_editor_filter_dock_widget.cpp
index c6b6e4416..2d4fb60e8 100644
--- a/cockatrice/src/interface/widgets/deck_editor/deck_editor_filter_dock_widget.cpp
+++ b/cockatrice/src/interface/widgets/deck_editor/deck_editor_filter_dock_widget.cpp
@@ -4,7 +4,6 @@
#include "../../../client/settings/shortcuts_settings.h"
#include "../../../filters/filter_builder.h"
#include "../../../filters/filter_tree_model.h"
-#include "../../pixel_map_generator.h"
#include
#include
@@ -43,11 +42,11 @@ void DeckEditorFilterDockWidget::createFiltersDock()
connect(filterBuilder, &FilterBuilder::add, filterModel, &FilterTreeModel::addFilter);
aClearFilterOne = new QAction(QString(), this);
- aClearFilterOne->setIcon(themePixmap(QStringLiteral("icons/decrement")));
+ aClearFilterOne->setIcon(QPixmap("theme:icons/decrement"));
connect(aClearFilterOne, &QAction::triggered, this, &DeckEditorFilterDockWidget::actClearFilterOne);
aClearFilterAll = new QAction(QString(), this);
- aClearFilterAll->setIcon(themePixmap(QStringLiteral("icons/clearsearch")));
+ aClearFilterAll->setIcon(QPixmap("theme:icons/clearsearch"));
connect(aClearFilterAll, &QAction::triggered, this, &DeckEditorFilterDockWidget::actClearFilterAll);
auto *filterDelOne = new QToolButton();
diff --git a/cockatrice/src/interface/widgets/deck_editor/deck_list_history_manager_widget.cpp b/cockatrice/src/interface/widgets/deck_editor/deck_list_history_manager_widget.cpp
index c93f12b34..cef459752 100644
--- a/cockatrice/src/interface/widgets/deck_editor/deck_list_history_manager_widget.cpp
+++ b/cockatrice/src/interface/widgets/deck_editor/deck_list_history_manager_widget.cpp
@@ -1,6 +1,5 @@
#include "deck_list_history_manager_widget.h"
-#include "../../pixel_map_generator.h"
#include "deck_state_manager.h"
DeckListHistoryManagerWidget::DeckListHistoryManagerWidget(DeckStateManager *_deckStateManager,
@@ -11,7 +10,7 @@ DeckListHistoryManagerWidget::DeckListHistoryManagerWidget(DeckStateManager *_de
layout = new QHBoxLayout(this);
aUndo = new QAction(QString(), this);
- aUndo->setIcon(themePixmap(QStringLiteral("icons/arrow_undo")));
+ aUndo->setIcon(QPixmap("theme:icons/arrow_undo"));
aUndo->setShortcut(QKeySequence::Undo);
aUndo->setShortcutContext(Qt::ApplicationShortcut);
connect(aUndo, &QAction::triggered, this, &DeckListHistoryManagerWidget::doUndo);
@@ -20,7 +19,7 @@ DeckListHistoryManagerWidget::DeckListHistoryManagerWidget(DeckStateManager *_de
undoButton->setDefaultAction(aUndo);
aRedo = new QAction(QString(), this);
- aRedo->setIcon(themePixmap(QStringLiteral("icons/arrow_redo")));
+ aRedo->setIcon(QPixmap("theme:icons/arrow_redo"));
aRedo->setShortcut(QKeySequence::Redo);
aRedo->setShortcutContext(Qt::ApplicationShortcut);
connect(aRedo, &QAction::triggered, this, &DeckListHistoryManagerWidget::doRedo);
@@ -32,7 +31,7 @@ DeckListHistoryManagerWidget::DeckListHistoryManagerWidget(DeckStateManager *_de
layout->addWidget(redoButton);
historyButton = new SettingsButtonWidget(this);
- historyButton->setButtonIcon(themePixmap(QStringLiteral("icons/arrow_history")));
+ historyButton->setButtonIcon(QPixmap("theme:icons/arrow_history"));
historyLabel = new QLabel(this);
diff --git a/cockatrice/src/interface/widgets/deck_editor/deck_state_manager.cpp b/cockatrice/src/interface/widgets/deck_editor/deck_state_manager.cpp
index cfe989e9f..e563729a4 100644
--- a/cockatrice/src/interface/widgets/deck_editor/deck_state_manager.cpp
+++ b/cockatrice/src/interface/widgets/deck_editor/deck_state_manager.cpp
@@ -1,20 +1,13 @@
#include "deck_state_manager.h"
-#include "../../../client/settings/cache_settings.h"
-
#include
#include
#include
-#include
DeckStateManager::DeckStateManager(QObject *parent)
: QObject(parent), deckList(QSharedPointer(new DeckList)),
deckListModel(new DeckListModel(this, deckList)), historyManager(new DeckListHistoryManager(this))
{
- deckListModel->setDisplayLanguage(SettingsCache::instance().cardsDisplay().getCardLang());
- connect(&SettingsCache::instance().cardsDisplay(), &CardsDisplaySettings::cardLangChanged, deckListModel,
- [this](const QString &lang) { deckListModel->setDisplayLanguage(lang); });
-
connect(historyManager, &DeckListHistoryManager::undoRedoStateChanged, this, [this] {
setModified(true);
emit historyChanged();
@@ -267,10 +260,7 @@ bool DeckStateManager::swapCardAtIndex(const QModelIndex &idx)
return false;
}
- // The display role holds the localized card name; the edit role always carries the
- // canonical English name needed to look the card up in the database.
- QString displayCardName = idx.siblingAtColumn(DeckListModelColumns::CARD_NAME).data().toString();
- QString cardName = idx.siblingAtColumn(DeckListModelColumns::CARD_NAME).data(Qt::EditRole).toString();
+ QString cardName = idx.siblingAtColumn(DeckListModelColumns::CARD_NAME).data().toString();
QString providerId = idx.siblingAtColumn(DeckListModelColumns::CARD_PROVIDER_ID).data().toString();
QModelIndex gparent = idx.parent().parent();
@@ -287,7 +277,7 @@ bool DeckStateManager::swapCardAtIndex(const QModelIndex &idx)
QString reason = tr("Moved to %1 1 × \"%2\" (%3)") //
.arg(otherZoneName)
- .arg(displayCardName)
+ .arg(cardName)
.arg(providerId);
return modifyDeck(reason, [&idx, &cardName, &providerId, &otherZoneName](auto model) {
@@ -301,8 +291,9 @@ bool DeckStateManager::removeCardAtIndex(const QModelIndex &idx)
return false;
}
- QString reason =
- tr("Removed \"%1\" (all copies)").arg(idx.siblingAtColumn(DeckListModelColumns::CARD_NAME).data().toString());
+ QString cardName = idx.siblingAtColumn(DeckListModelColumns::CARD_NAME).data().toString();
+
+ QString reason = tr("Removed \"%1\" (all copies)").arg(cardName);
return modifyDeck(reason, [&idx](auto model) { return model->removeRow(idx.row(), idx.parent()); });
}
diff --git a/cockatrice/src/interface/widgets/deck_share/deck_share_utils.cpp b/cockatrice/src/interface/widgets/deck_share/deck_share_utils.cpp
index 4343f0aab..14c568303 100644
--- a/cockatrice/src/interface/widgets/deck_share/deck_share_utils.cpp
+++ b/cockatrice/src/interface/widgets/deck_share/deck_share_utils.cpp
@@ -2,30 +2,16 @@
#include
#include
-#include
#include
-#include
-#include
#include
-#include
-#include
namespace DeckShareUtils
{
QString buildShareLink(const AbstractClient *client, const QString &token)
{
- QUrl url;
- url.setScheme(QStringLiteral("cockatrice"));
- url.setHost(QStringLiteral("opendeck"));
-
- QUrlQuery query;
- query.addQueryItem(QStringLiteral("share"), token);
- query.addQueryItem(QStringLiteral("hostname"), client->serverName());
- query.addQueryItem(QStringLiteral("port"), QString::number(client->serverPort()));
- url.setQuery(query);
-
- return url.toString(QUrl::FullyEncoded);
+ return QString("cockatrice://opendeck?share=%1&hostname=%2&port=%3")
+ .arg(token, client->serverName(), QString::number(client->serverPort()));
}
QString copyShareLinkToClipboard(const QString &link)
@@ -36,24 +22,7 @@ QString copyShareLinkToClipboard(const QString &link)
QString formatShareExpiry(const QDateTime &expiry)
{
- return QLocale().toString(expiry.toLocalTime(), QLocale::ShortFormat);
+ return expiry.toLocalTime().toString();
}
-ShareResponse handleShareResponse(const AbstractClient *client, const Response &response)
-{
- const Response_DeckShareCreate &resp = response.GetExtension(Response_DeckShareCreate::ext);
- const QString token = QString::fromStdString(resp.token());
-
- const QString link = buildShareLink(client, token);
- copyShareLinkToClipboard(link);
-
-#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
- const QDateTime expiry = QDateTime::fromSecsSinceEpoch(resp.expires_at(), QTimeZone::UTC);
-#else
- const QDateTime expiry = QDateTime::fromSecsSinceEpoch(resp.expires_at(), Qt::UTC);
-#endif
-
- return {link, expiry};
-}
-
-} // namespace DeckShareUtils
+} // namespace DeckShareUtils
\ No newline at end of file
diff --git a/cockatrice/src/interface/widgets/deck_share/deck_share_utils.h b/cockatrice/src/interface/widgets/deck_share/deck_share_utils.h
index c9f7afa8b..0034233fe 100644
--- a/cockatrice/src/interface/widgets/deck_share/deck_share_utils.h
+++ b/cockatrice/src/interface/widgets/deck_share/deck_share_utils.h
@@ -11,7 +11,6 @@
#include
class AbstractClient;
-class Response;
/**
* @brief Shared helpers for creating temporary deck shares.
@@ -19,15 +18,6 @@ class Response;
namespace DeckShareUtils
{
-/**
- * @brief The outcome of a successful share-create response.
- */
-struct ShareResponse
-{
- QString link; ///< The share link that was copied to the clipboard.
- QDateTime expiry; ///< When the share expires (UTC).
-};
-
/**
* @brief Builds the cockatrice:// link for a freshly created deck share.
* @param client Used to embed the target server's hostname and port.
@@ -46,14 +36,6 @@ QString copyShareLinkToClipboard(const QString &link);
*/
QString formatShareExpiry(const QDateTime &expiry);
-/**
- * @brief Handles a successful Response_DeckShareCreate: builds the share link,
- * copies it to the clipboard, and derives the share expiry.
- * @param client Used to embed the target server's hostname and port.
- * @param response The successful response carrying the share token and expiry.
- */
-ShareResponse handleShareResponse(const AbstractClient *client, const Response &response);
-
} // namespace DeckShareUtils
-#endif // DECK_SHARE_UTILS_H
+#endif // DECK_SHARE_UTILS_H
\ No newline at end of file
diff --git a/cockatrice/src/interface/widgets/deck_share/share_bar_widget.cpp b/cockatrice/src/interface/widgets/deck_share/share_bar_widget.cpp
index 5aca343ca..3fe5917dc 100644
--- a/cockatrice/src/interface/widgets/deck_share/share_bar_widget.cpp
+++ b/cockatrice/src/interface/widgets/deck_share/share_bar_widget.cpp
@@ -43,6 +43,7 @@ void ShareBarWidget::retranslateUi()
nameEdit->setPlaceholderText(tr("Share name"));
cancelButton->setText(tr("Cancel"));
createButton->setText(tr("Create share link"));
+ hintLabel->setText(tr("Click deck tiles to select the decks you want to share."));
}
QString ShareBarWidget::name() const
@@ -74,4 +75,4 @@ void ShareBarWidget::setCreateEnabled(bool enabled)
void ShareBarWidget::focusName()
{
nameEdit->setFocus();
-}
+}
\ No newline at end of file
diff --git a/cockatrice/src/interface/widgets/deck_share/share_bar_widget.h b/cockatrice/src/interface/widgets/deck_share/share_bar_widget.h
index ede9fb41b..f3b902da8 100644
--- a/cockatrice/src/interface/widgets/deck_share/share_bar_widget.h
+++ b/cockatrice/src/interface/widgets/deck_share/share_bar_widget.h
@@ -60,4 +60,4 @@ private:
QPushButton *createButton;
};
-#endif // SHARE_BAR_WIDGET_H
+#endif // SHARE_BAR_WIDGET_H
\ No newline at end of file
diff --git a/cockatrice/src/interface/widgets/deck_share/shared_deck_preview_widget.cpp b/cockatrice/src/interface/widgets/deck_share/shared_deck_preview_widget.cpp
index ef77df9ec..d52fa456b 100644
--- a/cockatrice/src/interface/widgets/deck_share/shared_deck_preview_widget.cpp
+++ b/cockatrice/src/interface/widgets/deck_share/shared_deck_preview_widget.cpp
@@ -136,4 +136,4 @@ void SharedDeckPreviewWidget::keyPressEvent(QKeyEvent *event)
return;
}
QWidget::keyPressEvent(event);
-}
+}
\ No newline at end of file
diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_connect.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_connect.cpp
index 700012d45..aa8a916f8 100644
--- a/cockatrice/src/interface/widgets/dialogs/dlg_connect.cpp
+++ b/cockatrice/src/interface/widgets/dialogs/dlg_connect.cpp
@@ -1,7 +1,6 @@
#include "dlg_connect.h"
#include "../../../client/settings/cache_settings.h"
-#include "../../pixel_map_generator.h"
#include
#include
@@ -22,7 +21,7 @@ DlgConnect::DlgConnect(QWidget *parent) : QDialog(parent)
previousHosts = new QComboBox(this);
btnDeleteServer = new QPushButton(this);
- btnDeleteServer->setIcon(themePixmap(QStringLiteral("icons/remove_row")));
+ btnDeleteServer->setIcon(QPixmap("theme:icons/remove_row"));
btnDeleteServer->setToolTip(tr("Delete the currently selected saved server"));
btnDeleteServer->setFixedWidth(30);
@@ -30,7 +29,7 @@ DlgConnect::DlgConnect(QWidget *parent) : QDialog(parent)
hps = new HandlePublicServers(this);
btnRefreshServers = new QPushButton(this);
- btnRefreshServers->setIcon(themePixmap(QStringLiteral("icons/sync")));
+ btnRefreshServers->setIcon(QPixmap("theme:icons/sync"));
btnRefreshServers->setToolTip(tr("Refresh the server list with known public servers"));
btnRefreshServers->setFixedWidth(30);
@@ -100,7 +99,7 @@ DlgConnect::DlgConnect(QWidget *parent) : QDialog(parent)
updateDisplayInfo(previousHosts->currentText());
btnForgotPassword = new QPushButton(this);
- btnForgotPassword->setIcon(themePixmap(QStringLiteral("icons/forgot_password")));
+ btnForgotPassword->setIcon(QPixmap("theme:icons/forgot_password"));
btnForgotPassword->setToolTip(tr("Reset Password"));
btnForgotPassword->setFixedWidth(30);
connect(btnForgotPassword, &QPushButton::released, this, &DlgConnect::actForgotPassword);
diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_edit_tokens.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_edit_tokens.cpp
index a56aa8e35..f249976c2 100644
--- a/cockatrice/src/interface/widgets/dialogs/dlg_edit_tokens.cpp
+++ b/cockatrice/src/interface/widgets/dialogs/dlg_edit_tokens.cpp
@@ -1,6 +1,5 @@
#include "dlg_edit_tokens.h"
-#include "../../pixel_map_generator.h"
#include "../interface/widgets/utility/get_text_with_max.h"
#include
@@ -91,10 +90,10 @@ DlgEditTokens::DlgEditTokens(QWidget *parent) : QDialog(parent), currentCard(nul
&DlgEditTokens::tokenSelectionChanged);
QAction *aAddToken = new QAction(tr("Add token"), this);
- aAddToken->setIcon(themePixmap(QStringLiteral("icons/increment")));
+ aAddToken->setIcon(QPixmap("theme:icons/increment"));
connect(aAddToken, &QAction::triggered, this, &DlgEditTokens::actAddToken);
QAction *aRemoveToken = new QAction(tr("Remove token"), this);
- aRemoveToken->setIcon(themePixmap(QStringLiteral("icons/decrement")));
+ aRemoveToken->setIcon(QPixmap("theme:icons/decrement"));
connect(aRemoveToken, &QAction::triggered, this, &DlgEditTokens::actRemoveToken);
auto *databaseToolBar = new QToolBar;
diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_login_prompt.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_login_prompt.cpp
index 86647ef26..fbc07b7e0 100644
--- a/cockatrice/src/interface/widgets/dialogs/dlg_login_prompt.cpp
+++ b/cockatrice/src/interface/widgets/dialogs/dlg_login_prompt.cpp
@@ -47,4 +47,4 @@ QString DlgLoginPrompt::password() const
bool DlgLoginPrompt::savePassword() const
{
return savePasswordCheckBox->isChecked();
-}
+}
\ No newline at end of file
diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_login_prompt.h b/cockatrice/src/interface/widgets/dialogs/dlg_login_prompt.h
index e47924058..47d8586c4 100644
--- a/cockatrice/src/interface/widgets/dialogs/dlg_login_prompt.h
+++ b/cockatrice/src/interface/widgets/dialogs/dlg_login_prompt.h
@@ -37,4 +37,4 @@ private:
QCheckBox *savePasswordCheckBox;
};
-#endif // DLG_LOGIN_PROMPT_H
+#endif // DLG_LOGIN_PROMPT_H
\ No newline at end of file
diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_manage_sets.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_manage_sets.cpp
index 556c270be..7c107eb2f 100644
--- a/cockatrice/src/interface/widgets/dialogs/dlg_manage_sets.cpp
+++ b/cockatrice/src/interface/widgets/dialogs/dlg_manage_sets.cpp
@@ -1,7 +1,6 @@
#include "dlg_manage_sets.h"
#include "../../../client/settings/cache_settings.h"
-#include "../../pixel_map_generator.h"
#include "../interface/card_picture_loader/card_picture_loader.h"
#include "../interface/widgets/utility/custom_line_edit.h"
@@ -36,28 +35,28 @@ WndSets::WndSets(QWidget *parent) : QMainWindow(parent)
setsEditToolBar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
aTop = new QAction(QString(), this);
- aTop->setIcon(themePixmap(QStringLiteral("icons/arrow_top_green")));
+ aTop->setIcon(QPixmap("theme:icons/arrow_top_green"));
aTop->setToolTip(tr("Move selected set to the top"));
aTop->setEnabled(false);
connect(aTop, &QAction::triggered, this, &WndSets::actTop);
setsEditToolBar->addAction(aTop);
aUp = new QAction(QString(), this);
- aUp->setIcon(themePixmap(QStringLiteral("icons/arrow_up_green")));
+ aUp->setIcon(QPixmap("theme:icons/arrow_up_green"));
aUp->setToolTip(tr("Move selected set up"));
aUp->setEnabled(false);
connect(aUp, &QAction::triggered, this, &WndSets::actUp);
setsEditToolBar->addAction(aUp);
aDown = new QAction(QString(), this);
- aDown->setIcon(themePixmap(QStringLiteral("icons/arrow_down_green")));
+ aDown->setIcon(QPixmap("theme:icons/arrow_down_green"));
aDown->setToolTip(tr("Move selected set down"));
aDown->setEnabled(false);
connect(aDown, &QAction::triggered, this, &WndSets::actDown);
setsEditToolBar->addAction(aDown);
aBottom = new QAction(QString(), this);
- aBottom->setIcon(themePixmap(QStringLiteral("icons/arrow_bottom_green")));
+ aBottom->setIcon(QPixmap("theme:icons/arrow_bottom_green"));
aBottom->setToolTip(tr("Move selected set to the bottom"));
aBottom->setEnabled(false);
connect(aBottom, &QAction::triggered, this, &WndSets::actBottom);
@@ -67,7 +66,7 @@ WndSets::WndSets(QWidget *parent) : QMainWindow(parent)
searchField = new LineEditUnfocusable;
searchField->setObjectName("searchEdit");
searchField->setPlaceholderText(tr("Search by set name, code, type, or release date"));
- searchField->addAction(themePixmap(QStringLiteral("icons/search")), LineEditUnfocusable::LeadingPosition);
+ searchField->addAction(QPixmap("theme:icons/search"), LineEditUnfocusable::LeadingPosition);
searchField->setClearButtonEnabled(true);
setFocusProxy(searchField);
diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_register.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_register.cpp
index 6d022861c..6ae8c9adb 100644
--- a/cockatrice/src/interface/widgets/dialogs/dlg_register.cpp
+++ b/cockatrice/src/interface/widgets/dialogs/dlg_register.cpp
@@ -1,7 +1,6 @@
#include "dlg_register.h"
#include "../../../client/settings/cache_settings.h"
-#include "../../pixel_map_generator.h"
#include "../server/handle_public_servers.h"
#include "../server/user/user_info_connection.h"
@@ -25,7 +24,7 @@ DlgRegister::DlgRegister(QWidget *parent) : QDialog(parent)
previousHosts = new QComboBox(this);
btnDeleteServer = new QPushButton(this);
- btnDeleteServer->setIcon(themePixmap(QStringLiteral("icons/remove_row")));
+ btnDeleteServer->setIcon(QPixmap("theme:icons/remove_row"));
btnDeleteServer->setToolTip(tr("Delete the currently selected saved server"));
btnDeleteServer->setFixedWidth(30);
@@ -33,7 +32,7 @@ DlgRegister::DlgRegister(QWidget *parent) : QDialog(parent)
hps = new HandlePublicServers(this);
btnRefreshServers = new QPushButton(this);
- btnRefreshServers->setIcon(themePixmap(QStringLiteral("icons/sync")));
+ btnRefreshServers->setIcon(QPixmap("theme:icons/sync"));
btnRefreshServers->setToolTip(tr("Refresh the server list with known public servers"));
btnRefreshServers->setFixedWidth(30);
diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp
index 581920dbc..883cfcd03 100644
--- a/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp
+++ b/cockatrice/src/interface/widgets/dialogs/dlg_settings.cpp
@@ -6,7 +6,6 @@
#include "dlg_settings.h"
#include "../../../client/settings/cache_settings.h"
-#include "../../pixel_map_generator.h"
#include "../main.h"
#include "../settings_page/appearance_settings_page.h"
#include "../settings_page/deck_editor_settings_page.h"
@@ -97,7 +96,7 @@ void DlgSettings::setupUi()
// Search bar
searchEdit = new QLineEdit;
searchEdit->setClearButtonEnabled(true);
- searchEdit->addAction(themePixmap(QStringLiteral("icons/search")), QLineEdit::LeadingPosition);
+ searchEdit->addAction(QPixmap("theme:icons/search"), QLineEdit::LeadingPosition);
searchEdit->installEventFilter(this);
connect(searchEdit, &QLineEdit::textChanged, this, &DlgSettings::onSearchTextChanged);
@@ -133,7 +132,7 @@ void DlgSettings::setupUi()
pagesWidget->addWidget(makeScrollable(userInterfacePage));
pagesWidget->addWidget(makeScrollable(deckEditorPage));
pagesWidget->addWidget(makeScrollable(storagePage));
- pagesWidget->addWidget(makeScrollable(messagesPage));
+ pagesWidget->addWidget(messagesPage);
pagesWidget->addWidget(soundPage);
pagesWidget->addWidget(shortcutsPage);
@@ -416,11 +415,6 @@ void DlgSettings::setTab(int index)
}
}
-AbstractSettingsPage *DlgSettings::page(SettingsPage which) const
-{
- return pages.value(static_cast(which));
-}
-
void DlgSettings::updateLanguage()
{
qApp->removeTranslator(translator); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
@@ -483,13 +477,13 @@ void DlgSettings::closeEvent(QCloseEvent *event)
case Invalid:
loadErrorMessage = tr("Your card database is invalid.\n\n"
"Cockatrice may not function correctly with an invalid database\n\n"
- "You may need to rerun Oracle to update your card database.\n\n"
+ "You may need to rerun oracle to update your card database.\n\n"
"Would you like to change your database location setting?");
break;
case VersionTooOld:
loadErrorMessage = tr("Your card database version is too old.\n\n"
"This can cause problems loading card information or images\n\n"
- "Usually this can be fixed by rerunning Oracle to to update your card database.\n\n"
+ "Usually this can be fixed by rerunning oracle to to update your card database.\n\n"
"Would you like to change your database location setting?");
break;
case NotLoaded:
diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_settings.h b/cockatrice/src/interface/widgets/dialogs/dlg_settings.h
index 845c0b4d6..b700f7af9 100644
--- a/cockatrice/src/interface/widgets/dialogs/dlg_settings.h
+++ b/cockatrice/src/interface/widgets/dialogs/dlg_settings.h
@@ -54,7 +54,6 @@ public:
explicit DlgSettings(QWidget *parent = nullptr);
void setTab(int index);
- AbstractSettingsPage *page(SettingsPage which) const;
private slots:
void onTabClicked(int index);
diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_share_deck.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_share_deck.cpp
index 897d32062..032407e38 100644
--- a/cockatrice/src/interface/widgets/dialogs/dlg_share_deck.cpp
+++ b/cockatrice/src/interface/widgets/dialogs/dlg_share_deck.cpp
@@ -1,6 +1,5 @@
#include "dlg_share_deck.h"
-#include "../../../client/settings/cache_settings.h"
#include "../cards/additional_info/deck_color_identity.h"
#include "../deck_share/deck_share_utils.h"
@@ -9,7 +8,7 @@
#include
#include
#include
-#include
+#include
#include
#include
#include
@@ -18,10 +17,9 @@
#include
#include
#include
-#include
DlgShareDeck::DlgShareDeck(AbstractClient *_client, const QSharedPointer &_deck, QWidget *_parent)
- : QDialog(_parent), client(_client), deck(_deck), shareTimeoutTimer(new QTimer(this))
+ : QDialog(_parent), client(_client), deck(_deck)
{
setWindowTitle(tr("Share deck"));
@@ -41,12 +39,6 @@ DlgShareDeck::DlgShareDeck(AbstractClient *_client, const QSharedPointerbuttonBox = buttonBox;
layout->addWidget(buttonBox);
-
- shareTimeoutTimer->setSingleShot(true);
- shareTimeoutTimer->setInterval(
- static_cast((static_cast(SettingsCache::instance().network().getTimeOut()) + 1) *
- SettingsCache::instance().network().getKeepAlive() * 1000));
- connect(shareTimeoutTimer, &QTimer::timeout, this, &DlgShareDeck::onShareTimeout);
}
void DlgShareDeck::actShare()
@@ -66,12 +58,10 @@ void DlgShareDeck::actShare()
PendingCommand *pend = client->prepareSessionCommand(cmd);
connect(pend, &PendingCommand::finished, this, &DlgShareDeck::shareFinished);
client->sendCommand(pend);
- shareTimeoutTimer->start();
}
void DlgShareDeck::shareFinished(const Response &response, const CommandContainer & /*commandContainer*/)
{
- shareTimeoutTimer->stop();
if (response.response_code() != Response::RespOk) {
buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
QMessageBox::critical(this, tr("Share deck"),
@@ -80,17 +70,20 @@ void DlgShareDeck::shareFinished(const Response &response, const CommandContaine
return;
}
- const DeckShareUtils::ShareResponse share = DeckShareUtils::handleShareResponse(client, response);
+ const Response_DeckShareCreate &resp = response.GetExtension(Response_DeckShareCreate::ext);
+ const QString token = QString::fromStdString(resp.token());
+#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
+ const QDateTime expiry = QDateTime::fromSecsSinceEpoch(resp.expires_at(), QTimeZone::UTC);
+#else
+ const QDateTime expiry = QDateTime::fromSecsSinceEpoch(resp.expires_at(), Qt::UTC);
+#endif
+
+ const QString link = DeckShareUtils::buildShareLink(client, token);
+ DeckShareUtils::copyShareLinkToClipboard(link);
QMessageBox::information(this, tr("Share deck"),
tr("Share link created and copied to the clipboard:\n\n%1\n\n"
"The share expires on %2.")
- .arg(share.link, DeckShareUtils::formatShareExpiry(share.expiry)));
+ .arg(link, DeckShareUtils::formatShareExpiry(expiry)));
accept();
-}
-
-void DlgShareDeck::onShareTimeout()
-{
- buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
- QMessageBox::warning(this, tr("Share deck"), tr("The server did not respond in time. Try again."));
-}
+}
\ No newline at end of file
diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_share_deck.h b/cockatrice/src/interface/widgets/dialogs/dlg_share_deck.h
index 162fa3677..0e8046bcd 100644
--- a/cockatrice/src/interface/widgets/dialogs/dlg_share_deck.h
+++ b/cockatrice/src/interface/widgets/dialogs/dlg_share_deck.h
@@ -15,7 +15,6 @@ class CommandContainer;
class DeckList;
class QDialogButtonBox;
class QLineEdit;
-class QTimer;
class Response;
/**
@@ -33,14 +32,12 @@ public:
private slots:
void actShare();
void shareFinished(const Response &response, const CommandContainer &commandContainer);
- void onShareTimeout();
private:
AbstractClient *client;
QSharedPointer deck;
QLineEdit *nameEdit;
QDialogButtonBox *buttonBox;
- QTimer *shareTimeoutTimer;
};
-#endif // DLG_SHARE_DECK_H
+#endif // DLG_SHARE_DECK_H
\ No newline at end of file
diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_shared_decks_preview.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_shared_decks_preview.cpp
index e84602cd6..6576a3844 100644
--- a/cockatrice/src/interface/widgets/dialogs/dlg_shared_decks_preview.cpp
+++ b/cockatrice/src/interface/widgets/dialogs/dlg_shared_decks_preview.cpp
@@ -175,4 +175,4 @@ void DlgSharedDecksPreview::closeEvent(QCloseEvent *event)
{
onCancel();
QDialog::closeEvent(event);
-}
+}
\ No newline at end of file
diff --git a/cockatrice/src/interface/widgets/general/home_tab_button_color.h b/cockatrice/src/interface/widgets/general/home_tab_button_color.h
index b45bd7a92..1550b57e7 100644
--- a/cockatrice/src/interface/widgets/general/home_tab_button_color.h
+++ b/cockatrice/src/interface/widgets/general/home_tab_button_color.h
@@ -11,8 +11,8 @@ namespace HomeTabButtonColor
*/
enum Source
{
- FromThemeColors, ///< Use the theme's identity accent colors
- FromBackground, ///< Extract colour from the background image
+ Automatic, ///< Extract color from background, or use theme color if no background
+ FromBackground, ///< Always extract color from background
};
struct Entry
@@ -23,7 +23,7 @@ struct Entry
inline QList all()
{
- static QList entries = {{FromThemeColors, QT_TR_NOOP("From theme colors")},
+ static QList entries = {{Automatic, QT_TR_NOOP("Automatic")},
{FromBackground, QT_TR_NOOP("Extract from background")}};
return entries;
@@ -33,12 +33,12 @@ inline QList all()
* Safely converts an int into the corresponding Source.
*
* @param value The int value
- * @return The Source. Returns Source::FromThemeColors if the value is not within range
+ * @return The Source. Returns Source::Automatic if the value is not within range
*/
inline Source intToSource(int value)
{
if (value > FromBackground) {
- return FromThemeColors; // default
+ return Automatic; // default
}
return static_cast(value);
diff --git a/cockatrice/src/interface/widgets/general/home_widget.cpp b/cockatrice/src/interface/widgets/general/home_widget.cpp
index 648d315f9..10fcdcb43 100644
--- a/cockatrice/src/interface/widgets/general/home_widget.cpp
+++ b/cockatrice/src/interface/widgets/general/home_widget.cpp
@@ -2,7 +2,6 @@
#include "../../../client/settings/cache_settings.h"
#include "../../../interface/widgets/tabs/tab_supervisor.h"
-#include "../../pixel_map_generator.h"
#include "../../theme_manager.h"
#include "../../window_main.h"
#include "../cards/art_crop_attribution.h"
@@ -11,8 +10,6 @@
#include "home_tab_button_color.h"
#include
-#include
-#include
#include
#include
#include
@@ -23,7 +20,7 @@
#include
HomeWidget::HomeWidget(QWidget *parent, TabSupervisor *_tabSupervisor)
- : QWidget(parent), tabSupervisor(_tabSupervisor), background(themePixmap(QStringLiteral("backgrounds/home")))
+ : QWidget(parent), tabSupervisor(_tabSupervisor), background("theme:backgrounds/home"), overlay("theme:cockatrice")
{
layout = new QGridLayout(this);
@@ -55,27 +52,16 @@ HomeWidget::HomeWidget(QWidget *parent, TabSupervisor *_tabSupervisor)
// Lambda is cleaner to read than overloading this
connect(&SettingsCache::instance().appearance(), &AppearanceSettings::homeTabDisplayCardNameChanged, this,
[this] { repaint(); });
- connect(&SettingsCache::instance().appearance(), &AppearanceSettings::homeTabBackgroundDimChanged, this,
- [this] { repaint(); });
connect(&SettingsCache::instance(), &SettingsCache::themeChanged, this,
&HomeWidget::initializeBackgroundFromSource);
connect(&SettingsCache::instance(), &SettingsCache::themeChanged, this,
&HomeWidget::updateButtonsToBackgroundColor);
- // Scheme flips (light/dark/system with an OS switch) fire on themeManager,
- // not on SettingsCache::themeChanged, so re-resolve the variant background.
- connect(themeManager, &ThemeManager::themeChanged, this, &HomeWidget::initializeBackgroundFromSource);
- connect(themeManager, &ThemeManager::paletteChanged, this, &HomeWidget::updateButtonsToBackgroundColor);
- connect(themeManager, &ThemeManager::paletteChanged, this, &HomeWidget::updateLogoOverlay);
connect(&SettingsCache::instance().appearance(), &AppearanceSettings::homeTabButtonColorChanged, this,
&HomeWidget::updateButtonsToBackgroundColor);
}
void HomeWidget::initializeBackgroundFromSource()
{
- // The featured logo is theme/scheme-derived too; reload it alongside the
- // background so a theme or appearance switch doesn't leave it stale.
- updateLogoOverlay();
-
if (CardDatabaseManager::getInstance()->getLoadStatus() != LoadStatus::Ok) {
connect(CardDatabaseManager::getInstance(), &CardDatabase::cardDatabaseLoadingFinished, this,
&HomeWidget::initializeBackgroundFromSource);
@@ -88,7 +74,7 @@ void HomeWidget::initializeBackgroundFromSource()
switch (backgroundSourceType) {
case BackgroundSources::Theme:
cardChangeTimer->stop();
- background = themePixmap(QStringLiteral("backgrounds/home"));
+ background = QPixmap("theme:backgrounds/home");
backgroundSourceDeck = DeckList();
backgroundSourceCard->setCard(ExactCard());
updateButtonsToBackgroundColor();
@@ -114,24 +100,32 @@ void HomeWidget::loadBackgroundSourceDeck()
backgroundSourceDeck = deckOpt.has_value() ? deckOpt.value().deckList : DeckList();
}
-static QPair paletteDerivedButtonColors()
+static bool isDefaultBackgroundAndTheme()
{
- return {themeManager->appColor(AppColor::AccentStrong), themeManager->appColor(AppColor::AccentSoft)};
+ QString sourceId = SettingsCache::instance().appearance().getHomeTabBackgroundSource();
+ return themeManager->isBuiltInTheme() && BackgroundSources::fromId(sourceId) == BackgroundSources::Theme;
}
QPair HomeWidget::determineButtonColor() const
{
+ static QPair defaultColor = {QColor::fromRgb(20, 140, 60), QColor::fromRgb(120, 200, 80)};
+
auto colorSource =
HomeTabButtonColor::intToSource(SettingsCache::instance().appearance().getHomeTabButtonColorSourceIndex());
switch (colorSource) {
- case HomeTabButtonColor::FromThemeColors:
- return paletteDerivedButtonColors();
+ case HomeTabButtonColor::Automatic: {
+ if (isDefaultBackgroundAndTheme()) {
+ return defaultColor;
+ } else {
+ return extractDominantColors(background);
+ }
+ }
case HomeTabButtonColor::FromBackground:
return extractDominantColors(background);
}
- return paletteDerivedButtonColors();
+ return defaultColor;
}
void HomeWidget::setRandomCard(ExactCard &newCard)
@@ -235,10 +229,10 @@ QGroupBox *HomeWidget::createButtons()
QVBoxLayout *boxLayout = new QVBoxLayout;
boxLayout->setAlignment(Qt::AlignHCenter);
- logoLabel = new QLabel;
+ QLabel *logoLabel = new QLabel;
+ logoLabel->setPixmap(overlay.scaledToWidth(200, Qt::SmoothTransformation));
logoLabel->setAlignment(Qt::AlignCenter);
boxLayout->addWidget(logoLabel);
- updateLogoOverlay();
boxLayout->addSpacing(25);
connectButton = new HomeStyledButton("Connect/Play", gradientColors);
@@ -366,15 +360,13 @@ void HomeWidget::paintEvent(QPaintEvent *event)
painter.drawPixmap(topLeft, toDraw);
}
- if (SettingsCache::instance().appearance().getHomeTabBackgroundDim()) {
- // Draw translucent black overlay with rounded corners
- QRectF overlayRect(5, 5, width() - 10, height() - 10);
- QPainterPath roundedRectPath;
- roundedRectPath.addRoundedRect(overlayRect, 20, 20);
+ // Draw translucent black overlay with rounded corners
+ QRectF overlayRect(5, 5, width() - 10, height() - 10);
+ QPainterPath roundedRectPath;
+ roundedRectPath.addRoundedRect(overlayRect, 20, 20);
- QColor semiTransparentBlack(0, 0, 0, static_cast(255 * 0.33));
- painter.fillPath(roundedRectPath, semiTransparentBlack);
- }
+ QColor semiTransparentBlack(0, 0, 0, static_cast(255 * 0.33));
+ painter.fillPath(roundedRectPath, semiTransparentBlack);
// Card name overlay (above the attribution, bottom-right)
QString cardName;
@@ -439,56 +431,3 @@ void HomeWidget::paintEvent(QPaintEvent *event)
QWidget::paintEvent(event);
}
-
-void HomeWidget::updateLogoOverlay()
-{
- // Emulate cockatrice.svg in Qt rather than rendering the baked-in SVG.
- // The SVG has no separate plate: the gradient fills the bird's silhouette
- // paths (light #c9fd62/AccentSoft at the top-left, dark #139740/AccentStrong
- // toward the bottom-right — the SVG's linearGradient4265-7-8 stops along
- // its userSpaceOnUse axis), and the white highlight path
- // (cockatrice-logo-white) sits on top. So we paint that gradient clipped to
- // the full logo silhouette (the full-color logo's alpha), then overlay the
- // white mark. Colours stay fully theme-driven and independent of the static
- // greens baked into the SVG.
- const QColor strong = themeManager->appColor(AppColor::AccentStrong);
- const QColor soft = themeManager->appColor(AppColor::AccentSoft);
-
- const QPixmap silhouette = themePixmap(QStringLiteral("cockatrice")).scaledToWidth(200, Qt::SmoothTransformation);
- const QPixmap whiteMark =
- themePixmap(QStringLiteral("cockatrice-logo-white")).scaledToWidth(200, Qt::SmoothTransformation);
- if (silhouette.isNull() || whiteMark.isNull()) {
- return;
- }
-
- QPixmap composite(silhouette.size());
- composite.fill(Qt::transparent);
-
- {
- QPainter painter(&composite);
- painter.setRenderHint(QPainter::Antialiasing);
- painter.setRenderHint(QPainter::SmoothPixmapTransform);
-
- // Recreate cockatrice.svg's own gradient geometry (linearGradient
- // 4265-7-8, userSpaceOnUse): light AccentSoft at S=(-8.097,-97.746),
- // dark AccentStrong at E=(162.455,295.208), on the SVG's 300x300
- // canvas. Scale those coordinates to this composite's size.
- const qreal scale = composite.width() / 300.0;
- QLinearGradient gradient(QPointF(-8.097, -97.746) * scale, QPointF(162.455, 295.208) * scale);
- gradient.setColorAt(0.0, soft);
- gradient.setColorAt(1.0, strong);
- painter.fillRect(composite.rect(), gradient);
-
- // Clip the gradient to the full logo silhouette exactly as the SVG's
- // gradient paths are confined to the bird.
- painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
- painter.drawPixmap(0, 0, silhouette);
-
- painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
- painter.drawPixmap(0, 0, whiteMark);
- }
-
- if (logoLabel) {
- logoLabel->setPixmap(composite);
- }
-}
diff --git a/cockatrice/src/interface/widgets/general/home_widget.h b/cockatrice/src/interface/widgets/general/home_widget.h
index 1cadc4a67..9df0d7b6a 100644
--- a/cockatrice/src/interface/widgets/general/home_widget.h
+++ b/cockatrice/src/interface/widgets/general/home_widget.h
@@ -15,9 +15,6 @@
#include
#include
-class QGridLayout;
-class QLabel;
-
class HomeWidget : public QWidget
{
@@ -44,14 +41,13 @@ private:
QPixmap background;
CardInfoPictureArtCropWidget *backgroundSourceCard = nullptr;
DeckList backgroundSourceDeck;
- QLabel *logoLabel = nullptr;
+ QPixmap overlay;
QPair gradientColors;
HomeStyledButton *connectButton;
void setRandomCard(ExactCard &newCard);
void loadBackgroundSourceDeck();
QPair determineButtonColor() const;
- void updateLogoOverlay();
};
#endif // HOME_WIDGET_H
diff --git a/cockatrice/src/interface/widgets/general/layout_containers/flow_widget.cpp b/cockatrice/src/interface/widgets/general/layout_containers/flow_widget.cpp
index 05dcf3e8e..6e04fed5a 100644
--- a/cockatrice/src/interface/widgets/general/layout_containers/flow_widget.cpp
+++ b/cockatrice/src/interface/widgets/general/layout_containers/flow_widget.cpp
@@ -81,15 +81,10 @@ FlowWidget::FlowWidget(QWidget *parent,
/**
* @brief Adds a widget to the flow layout within the FlowWidget.
*
- * The widget is filtered for arrow-key events so keyboard navigation between
- * the flow items keeps working even when the flow sits inside a QScrollArea,
- * which swallows arrow keys before they can reach FlowWidget::keyPressEvent.
- *
* @param widget_to_add The widget to add to the flow layout.
*/
-void FlowWidget::addWidget(QWidget *widget_to_add)
+void FlowWidget::addWidget(QWidget *widget_to_add) const
{
- widget_to_add->installEventFilter(this);
flowLayout->addWidget(widget_to_add);
}
@@ -184,23 +179,6 @@ QLayoutItem *FlowWidget::itemAt(int index) const
}
void FlowWidget::keyPressEvent(QKeyEvent *event)
-{
- if (moveFocus(event)) {
- event->accept();
- return;
- }
- QWidget::keyPressEvent(event);
-}
-
-bool FlowWidget::eventFilter(QObject *watched, QEvent *event)
-{
- if (event->type() == QEvent::KeyPress && moveFocus(static_cast(event))) {
- return true;
- }
- return QWidget::eventFilter(watched, event);
-}
-
-bool FlowWidget::moveFocus(QKeyEvent *event)
{
// Keyboard navigation between the flow items: arrow keys move focus just
// like clicking the sibling tiles would. Only items that can take keyboard
@@ -208,7 +186,8 @@ bool FlowWidget::moveFocus(QKeyEvent *event)
const bool moveForward = event->key() == Qt::Key_Right || event->key() == Qt::Key_Down;
const bool moveBackward = event->key() == Qt::Key_Left || event->key() == Qt::Key_Up;
if (!moveForward && !moveBackward) {
- return false;
+ QWidget::keyPressEvent(event);
+ return;
}
QList focusableItems;
@@ -220,7 +199,8 @@ bool FlowWidget::moveFocus(QKeyEvent *event)
}
if (focusableItems.isEmpty()) {
- return false;
+ QWidget::keyPressEvent(event);
+ return;
}
int currentIndex = -1;
@@ -240,7 +220,6 @@ bool FlowWidget::moveFocus(QKeyEvent *event)
}
focusableItems.value(nextIndex)->setFocus();
event->accept();
- return true;
}
int FlowWidget::count() const
diff --git a/cockatrice/src/interface/widgets/general/layout_containers/flow_widget.h b/cockatrice/src/interface/widgets/general/layout_containers/flow_widget.h
index bdcb1e590..3f3a2be2b 100644
--- a/cockatrice/src/interface/widgets/general/layout_containers/flow_widget.h
+++ b/cockatrice/src/interface/widgets/general/layout_containers/flow_widget.h
@@ -29,7 +29,7 @@ public:
Qt::ScrollBarPolicy horizontalPolicy,
Qt::ScrollBarPolicy verticalPolicy);
- void addWidget(QWidget *widget_to_add);
+ void addWidget(QWidget *widget_to_add) const;
void insertWidgetAtIndex(QWidget *toInsert, int index);
void removeWidget(QWidget *widgetToRemove) const;
void clearLayout();
@@ -44,15 +44,10 @@ public slots:
void setSpacing(int hSpacing, int vSpacing);
protected:
- bool eventFilter(QObject *watched, QEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
void keyPressEvent(QKeyEvent *event) override;
private:
- /// @brief Moves keyboard focus to an adjacent flow item for an arrow-key event.
- /// @return True when the event was an arrow key and was handled.
- bool moveFocus(QKeyEvent *event);
-
Qt::Orientation flowDirection;
QHBoxLayout *mainLayout;
FlowLayout *flowLayout;
diff --git a/cockatrice/src/interface/widgets/onboarding/banner_shader_config.h b/cockatrice/src/interface/widgets/onboarding/banner_shader_config.h
index 6008044ff..32f3e89c0 100644
--- a/cockatrice/src/interface/widgets/onboarding/banner_shader_config.h
+++ b/cockatrice/src/interface/widgets/onboarding/banner_shader_config.h
@@ -38,10 +38,6 @@ class BannerShaderConfig : public QObject
Q_PROPERTY(QColor colorA READ colorA WRITE setColorA NOTIFY colorAChanged)
Q_PROPERTY(QColor colorB READ colorB WRITE setColorB NOTIFY colorBChanged)
Q_PROPERTY(QColor accent READ accent WRITE setAccent NOTIFY accentChanged)
- Q_PROPERTY(QColor glowColor READ glowColor WRITE setGlowColor NOTIFY glowColorChanged)
- Q_PROPERTY(QColor brandStrong READ brandStrong WRITE setBrandStrong NOTIFY brandStrongChanged)
- Q_PROPERTY(QColor brandSoft READ brandSoft WRITE setBrandSoft NOTIFY brandSoftChanged)
- Q_PROPERTY(qreal vignetteMin READ vignetteMin WRITE setVignetteMin NOTIFY vignetteMinChanged)
Q_PROPERTY(bool logoVisible READ logoVisible WRITE setLogoVisible NOTIFY logoVisibleChanged)
Q_PROPERTY(qreal logoGlow READ logoGlow WRITE setLogoGlow NOTIFY logoGlowChanged)
@@ -189,54 +185,6 @@ public:
}
}
- QColor glowColor() const
- {
- return m_glowColor;
- }
- void setGlowColor(const QColor &c)
- {
- if (c != m_glowColor) {
- m_glowColor = c;
- emit glowColorChanged();
- }
- }
-
- QColor brandStrong() const
- {
- return m_brandStrong;
- }
- void setBrandStrong(const QColor &c)
- {
- if (c != m_brandStrong) {
- m_brandStrong = c;
- emit brandStrongChanged();
- }
- }
-
- QColor brandSoft() const
- {
- return m_brandSoft;
- }
- void setBrandSoft(const QColor &c)
- {
- if (c != m_brandSoft) {
- m_brandSoft = c;
- emit brandSoftChanged();
- }
- }
-
- qreal vignetteMin() const
- {
- return m_vignetteMin;
- }
- void setVignetteMin(qreal v)
- {
- if (v != m_vignetteMin) {
- m_vignetteMin = v;
- emit vignetteMinChanged();
- }
- }
-
bool logoVisible() const
{
return m_logoVisible;
@@ -274,10 +222,6 @@ signals:
void colorAChanged();
void colorBChanged();
void accentChanged();
- void glowColorChanged();
- void brandStrongChanged();
- void brandSoftChanged();
- void vignetteMinChanged();
void logoVisibleChanged();
void logoGlowChanged();
@@ -295,16 +239,9 @@ private:
bool m_frontIsA = true;
- // Curated fallback seed values -- BannerHost overwrites these with
- // palette-derived colours (see shader_banner_widget.cpp) before the first
- // paint, so they only matter as a safe pre-first-apply default.
QColor m_colorA{0x1A, 0x1A, 0x20};
QColor m_colorB{0x0E, 0x0E, 0x12};
QColor m_accent{0x8B, 0xDD, 0x6B};
- QColor m_glowColor{Qt::white};
- QColor m_brandStrong{0x13, 0x97, 0x40};
- QColor m_brandSoft{0xC9, 0xFD, 0x62};
- qreal m_vignetteMin = 0.62;
bool m_logoVisible = false;
qreal m_logoGlow = 1.0;
diff --git a/cockatrice/src/interface/widgets/onboarding/brand_colors.h b/cockatrice/src/interface/widgets/onboarding/brand_colors.h
deleted file mode 100644
index bf173270b..000000000
--- a/cockatrice/src/interface/widgets/onboarding/brand_colors.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef BRAND_COLORS_H
-#define BRAND_COLORS_H
-
-#include
-
-/** @brief Cockatrice brand green.
- *
- * Single source of truth for the onboarding brand accent: it backs the
- * banner's shader-accent uniform as the curated fallback when the active
- * palette resolves no usable Highlight, and it preseads the wizard's
- * QuickSetupPanel so a freshly generated palette keeps the brand identity
- * until the user picks their own look. */
-inline const QColor kCockatriceBrandGreen(0x8B, 0xDD, 0x6B);
-
-#endif // BRAND_COLORS_H
\ No newline at end of file
diff --git a/cockatrice/src/interface/widgets/onboarding/first_run_wizard.cpp b/cockatrice/src/interface/widgets/onboarding/first_run_wizard.cpp
index 4af02fe4f..618ac6f26 100644
--- a/cockatrice/src/interface/widgets/onboarding/first_run_wizard.cpp
+++ b/cockatrice/src/interface/widgets/onboarding/first_run_wizard.cpp
@@ -182,13 +182,6 @@ void FirstRunWizard::onCardDatabaseUpdateFinished(bool success)
}
}
-void FirstRunWizard::onCardDatabaseUpdateProgress(const QString &stage, qint64 done, qint64 total)
-{
- if (cardDatabasePage) {
- cardDatabasePage->onUpdateProgress(stage, done, total);
- }
-}
-
void FirstRunWizard::finish()
{
accept();
diff --git a/cockatrice/src/interface/widgets/onboarding/first_run_wizard.h b/cockatrice/src/interface/widgets/onboarding/first_run_wizard.h
index 21d7b6e06..2c186ef95 100644
--- a/cockatrice/src/interface/widgets/onboarding/first_run_wizard.h
+++ b/cockatrice/src/interface/widgets/onboarding/first_run_wizard.h
@@ -37,9 +37,6 @@ public slots:
/** @brief Forwarded from MainWindow once the background card database update process exits. */
void onCardDatabaseUpdateFinished(bool success);
- /** @brief Forwarded from MainWindow while the background card database update process runs. */
- void onCardDatabaseUpdateProgress(const QString &stage, qint64 done, qint64 total);
-
protected:
void closeEvent(QCloseEvent *event) override;
void changeEvent(QEvent *event) override;
diff --git a/cockatrice/src/interface/widgets/onboarding/pages/card_database_setup_page.cpp b/cockatrice/src/interface/widgets/onboarding/pages/card_database_setup_page.cpp
index 50e8ff63d..12116de7a 100644
--- a/cockatrice/src/interface/widgets/onboarding/pages/card_database_setup_page.cpp
+++ b/cockatrice/src/interface/widgets/onboarding/pages/card_database_setup_page.cpp
@@ -15,7 +15,6 @@
#include
#include
#include
-#include
#include
#include
@@ -180,25 +179,6 @@ void CardDatabaseSetupPage::onUpdateFinished(bool success)
}
}
-void CardDatabaseSetupPage::onUpdateProgress(const QString &stage, qint64 done, qint64 total)
-{
- if (state != State::Running) {
- return;
- }
- progressBar->setRange(0, total > 0 ? static_cast(qMin(total, INT_MAX)) : 0);
- progressBar->setValue(static_cast(qMin(done, INT_MAX)));
- if (total > 0) {
- const int percent = static_cast((100.0 * done) / total);
- if (stage == QLatin1String("download")) {
- statusLabel->setText(tr("Downloading the card database (%1%)…").arg(percent));
- } else if (stage == QLatin1String("scan")) {
- statusLabel->setText(tr("Parsing the card database (%1%)…").arg(percent));
- } else if (stage == QLatin1String("import")) {
- statusLabel->setText(tr("Importing cards (%1%)…").arg(percent));
- }
- }
-}
-
QString CardDatabaseSetupPage::nextButtonText() const
{
return state == State::NotStarted ? tr("Download") : QString();
diff --git a/cockatrice/src/interface/widgets/onboarding/pages/card_database_setup_page.h b/cockatrice/src/interface/widgets/onboarding/pages/card_database_setup_page.h
index 870e759ea..0461d11d5 100644
--- a/cockatrice/src/interface/widgets/onboarding/pages/card_database_setup_page.h
+++ b/cockatrice/src/interface/widgets/onboarding/pages/card_database_setup_page.h
@@ -30,7 +30,6 @@ public:
void retranslateUi() override;
void onUpdateFinished(bool success);
- void onUpdateProgress(const QString &stage, qint64 done, qint64 total);
signals:
void updateRequested();
diff --git a/cockatrice/src/interface/widgets/onboarding/pages/theme_setup_page.cpp b/cockatrice/src/interface/widgets/onboarding/pages/theme_setup_page.cpp
index 797fe4425..3293b19ac 100644
--- a/cockatrice/src/interface/widgets/onboarding/pages/theme_setup_page.cpp
+++ b/cockatrice/src/interface/widgets/onboarding/pages/theme_setup_page.cpp
@@ -14,31 +14,10 @@
#include
#include
#include
-#include
#include
#include
#include
-namespace
-{
-/** @brief A theme's shipped identity accent, immune to any user- or auto-
- * generated palette that may currently be masking appColor(). */
-QColor themeIdentityAccent(const QString &themeDirPath, const QString &themeName)
-{
- for (const QString &scheme : {QStringLiteral("Light"), QStringLiteral("Dark")}) {
- const PaletteConfig cfg = ThemeManager::loadDefaultPaletteConfig(themeDirPath, themeName, scheme);
- if (cfg.appColors.contains(AppColor::AccentStrong)) {
- return cfg.appColors.value(AppColor::AccentStrong);
- }
- const QColor highlight = cfg.colors.value(QPalette::Active).value(QPalette::Highlight);
- if (highlight.isValid()) {
- return highlight;
- }
- }
- return {};
-}
-} // namespace
-
ThemeSetupPage::ThemeSetupPage(QWidget *parent) : FirstRunWizardPage(parent)
{
themeCombo = new QComboBox(this);
@@ -51,15 +30,6 @@ ThemeSetupPage::ThemeSetupPage(QWidget *parent) : FirstRunWizardPage(parent)
quickSetupPanel = new QuickSetupPanel(this);
- // Seed the picker from the current theme's own identity accent rather than
- // a hardcoded brand green: Plasma seeds violet, Fusion green, etc., and it
- // is immune to stale generated palettes that may mask appColor(). This was
- // initially a brand-green workaround from before Fusion became the default.
- // setAccentColor blocks signals, so this never triggers a generation.
- lastSeededTheme = SettingsCache::instance().getThemeName();
- quickSetupPanel->setAccentColor(
- themeIdentityAccent(themeManager->getAvailableThemes().value(lastSeededTheme), lastSeededTheme));
-
connect(themeCombo, QOverload::of(&QComboBox::currentIndexChanged), this, &ThemeSetupPage::onThemeChanged);
connect(schemeCombo, QOverload::of(&QComboBox::currentIndexChanged), this, &ThemeSetupPage::onSchemeChanged);
connect(quickSetupPanel, &QuickSetupPanel::valueChanged, this, &ThemeSetupPage::onGenerateFromAccent);
@@ -77,8 +47,7 @@ ThemeSetupPage::ThemeSetupPage(QWidget *parent) : FirstRunWizardPage(parent)
// Mirrors AppearanceSettingsPage's identical listener for the combo-sync
// half of this.
connect(themeManager, &ThemeManager::themeChanged, this, [this] {
- const QString newTheme = SettingsCache::instance().getThemeName();
- const QString newDir = themeManager->getAvailableThemes().value(newTheme);
+ const QString newDir = themeManager->getAvailableThemes().value(SettingsCache::instance().getThemeName());
const ThemeConfig cfg = ThemeConfig::fromThemeDir(newDir);
const QString current = cfg.colorScheme;
@@ -87,14 +56,6 @@ ThemeSetupPage::ThemeSetupPage(QWidget *parent) : FirstRunWizardPage(parent)
schemeCombo->setCurrentIndex(idx >= 0 ? idx : 0);
schemeCombo->blockSignals(false);
- // Keep the picker's accent in step with the theme's own identity; the
- // swatch seeded at construction would otherwise stay stale (e.g. green
- // from a previous theme) when the user toggles themes.
- if (newTheme != lastSeededTheme) {
- lastSeededTheme = newTheme;
- quickSetupPanel->setAccentColor(themeIdentityAccent(newDir, newTheme));
- }
-
maybeAutoGeneratePalette();
});
@@ -197,14 +158,8 @@ void ThemeSetupPage::maybeAutoGeneratePalette()
const QString dirPath = themeManager->getAvailableThemes().value(SettingsCache::instance().getThemeName());
const QString scheme = resolvedScheme();
- // The theme dir may resolve to the user profile even for built-in themes
- // (getAvailableThemes gives the user copy precedence), so consult the
- // shipped palette too -- both via loadDefaultPaletteConfig's system fallback.
- // Without it, scheme flips regenerate a fresh palette from the picker accent
- // and clobber the curated colours the theme explicitly ships.
if (PaletteConfig::fromScheme(dirPath, scheme).hasPalette() ||
- ThemeManager::loadDefaultPaletteConfig(dirPath, SettingsCache::instance().getThemeName(), scheme)
- .hasPalette()) {
+ PaletteConfig::fromDefault(dirPath, scheme).hasPalette()) {
return; // theme already has something real to show -- leave it alone
}
diff --git a/cockatrice/src/interface/widgets/onboarding/pages/theme_setup_page.h b/cockatrice/src/interface/widgets/onboarding/pages/theme_setup_page.h
index 16a3c9a5d..d1f84c1b9 100644
--- a/cockatrice/src/interface/widgets/onboarding/pages/theme_setup_page.h
+++ b/cockatrice/src/interface/widgets/onboarding/pages/theme_setup_page.h
@@ -53,9 +53,6 @@ private:
QComboBox *homeTabBackgroundCombo;
bool paletteDirty = false;
-
- /// Theme whose identity accent currently seeds the picker.
- QString lastSeededTheme;
};
#endif // THEME_SETUP_PAGE_H
diff --git a/cockatrice/src/interface/widgets/onboarding/qml/BrandBanner.qml b/cockatrice/src/interface/widgets/onboarding/qml/BrandBanner.qml
index d94e15280..f1a385cad 100644
--- a/cockatrice/src/interface/widgets/onboarding/qml/BrandBanner.qml
+++ b/cockatrice/src/interface/widgets/onboarding/qml/BrandBanner.qml
@@ -16,8 +16,6 @@ Item {
property vector4d uColorA: Qt.vector4d(bannerConfig.colorA.r, bannerConfig.colorA.g, bannerConfig.colorA.b, 1.0)
property vector4d uColorB: Qt.vector4d(bannerConfig.colorB.r, bannerConfig.colorB.g, bannerConfig.colorB.b, 1.0)
property vector4d uAccent: Qt.vector4d(bannerConfig.accent.r, bannerConfig.accent.g, bannerConfig.accent.b, 1.0)
- property vector4d uGlowColor: Qt.vector4d(bannerConfig.glowColor.r, bannerConfig.glowColor.g, bannerConfig.glowColor.b, 1.0)
- property real uVignetteMin: bannerConfig.vignetteMin
property real uLogoGlow: bannerConfig.logoGlow
fragmentShader: "qrc:/onboarding/shaders/brand_banner.frag.qsb"
}
@@ -35,62 +33,30 @@ Item {
property vector4d uColorA: Qt.vector4d(bannerConfig.colorA.r, bannerConfig.colorA.g, bannerConfig.colorA.b, 1.0)
property vector4d uColorB: Qt.vector4d(bannerConfig.colorB.r, bannerConfig.colorB.g, bannerConfig.colorB.b, 1.0)
property vector4d uAccent: Qt.vector4d(bannerConfig.accent.r, bannerConfig.accent.g, bannerConfig.accent.b, 1.0)
- property vector4d uGlowColor: Qt.vector4d(bannerConfig.glowColor.r, bannerConfig.glowColor.g, bannerConfig.glowColor.b, 1.0)
- property real uVignetteMin: bannerConfig.vignetteMin
property real uLogoGlow: bannerConfig.logoGlow
fragmentShader: "qrc:/onboarding/shaders/brand_banner.frag.qsb"
}
- // The white logo sits at full opacity on top of the static gradient plate —
- // no glow, no breathing. The plate matches home_widget's QPainter composite.
- Item {
- id: logoHost
- visible: bannerConfig.logoVisible
+ // The hero logo itself — breathes cleanly over a 0.5–1.0 opacity range
+ Image {
+ id: logo
anchors.centerIn: parent
+ visible: bannerConfig.logoVisible
+ source: "qrc:/resources/cockatrice-logo-white.svg"
width: root.height * 0.6
- height: width
+ height: width * (sourceSize.height > 0 ? sourceSize.height / Math.max(sourceSize.width, 1) : 1)
+ fillMode: Image.PreserveAspectFit
+ smooth: true
+ opacity: 0.5 + 0.5 * bannerConfig.logoGlow
+ sourceSize: Qt.size(256, 256)
- // The full-color logo renders beneath the white mark and is consumed as
- // a texture (layer.enabled) by the plate shader's silhouette mask, so
- // the gradient is clipped to the bird exactly as the SVG's gradient
- // paths are. It is never drawn to the screen itself.
- Image {
- id: silhouetteMask
- anchors.fill: parent
- source: "qrc:/resources/cockatrice.svg"
- sourceSize: Qt.size(256, 256)
- fillMode: Image.PreserveAspectFit
- smooth: true
- visible: false
- layer.enabled: true
- layer.smooth: true
- }
+ Behavior on opacity { NumberAnimation { duration: 300; easing.type: Easing.InOutSine } }
- // The logo's gradient plate, drawn behind the mark: a linear
- // AccentSoft (light) -> AccentStrong (dark) sheet along the same
- // top-left -> bottom-right userSpaceOnUse axis the baked-in SVG used,
- // clipped to the bird silhouette via uSilhouette. The white highlight
- // path above is theme independent. Sized to the logo itself — no
- // rounded badge, matching home_widget's QPainter composite. Static.
- // Small ShaderEffect, Qt 6.4-safe.
- ShaderEffect {
- id: brandPlate
- anchors.fill: parent
- property vector4d uStrong: Qt.vector4d(bannerConfig.brandStrong.r, bannerConfig.brandStrong.g,
- bannerConfig.brandStrong.b, 1.0)
- property vector4d uSoft: Qt.vector4d(bannerConfig.brandSoft.r, bannerConfig.brandSoft.g,
- bannerConfig.brandSoft.b, 1.0)
- property var uSilhouette: silhouetteMask
- fragmentShader: "qrc:/onboarding/shaders/brand_plate.frag.qsb"
- }
-
- Image {
- id: logoImage
- anchors.fill: parent
- source: "qrc:/resources/cockatrice-logo-white.svg"
- sourceSize: Qt.size(256, 256)
- fillMode: Image.PreserveAspectFit
- smooth: true
+ transform: Scale {
+ origin.x: logo.width / 2
+ origin.y: logo.height / 2
+ xScale: 0.94 + 0.06 * bannerConfig.logoGlow
+ yScale: 0.94 + 0.06 * bannerConfig.logoGlow
}
}
-}
\ No newline at end of file
+}
diff --git a/cockatrice/src/interface/widgets/onboarding/shader_banner_widget.cpp b/cockatrice/src/interface/widgets/onboarding/shader_banner_widget.cpp
index 0b9f65783..fd1fb2a98 100644
--- a/cockatrice/src/interface/widgets/onboarding/shader_banner_widget.cpp
+++ b/cockatrice/src/interface/widgets/onboarding/shader_banner_widget.cpp
@@ -1,10 +1,7 @@
#include "shader_banner_widget.h"
-#include "../../theme_manager.h"
#include "banner_shader_config.h"
-#include "brand_colors.h"
-#include
#include
#include
#include
@@ -14,98 +11,11 @@
namespace
{
-// Curated near-black stage -- used only when the active palette resolves no
-// usable window colour. Matches the banner's original design (dark and quiet
-// so the accent stands out) and satisfies design-plans §2.1's "identity
-// survives a bare palette".
-constexpr QRgb kFallbackColorA = 0x1A1A20;
-constexpr QRgb kFallbackColorB = 0x0E0E12;
-
-struct SuggestedColors
-{
- QColor colorA;
- QColor colorB;
- QColor accent;
- QColor glowColor;
- QColor brandStrong;
- QColor brandSoft;
- qreal vignetteMin = 0.62;
-};
-
-SuggestedColors suggestedBannerColors()
-{
- const QPalette &pal = qApp->palette();
- const QColor window = pal.color(QPalette::Active, QPalette::Window);
- // Identity accent: the theme's [AppColors] AccentStrong, which appColor()
- // resolves to QPalette::Highlight when a theme doesn't pin AccentStrong.
- // Reading bare Highlight ignored curated accent tokens (Plasma's violet
- // vs Default's green) whenever a palette didn't set the role itself.
- const QColor accentStrong = themeManager->appColor(AppColor::AccentStrong);
- if (!window.isValid() || !accentStrong.isValid()) {
- return {QColor(kFallbackColorA),
- QColor(kFallbackColorB),
- kCockatriceBrandGreen,
- QColor(Qt::white),
- kCockatriceBrandGreen,
- QColor(0xC9, 0xFD, 0x62),
- 0.62};
- }
-
- // The theme's brand pair: AccentStrong is the deep green, AccentSoft the
- // lime. These two appColors form the logo's "surrounding gradient" (deep
- // core grading out to the soft, brand-toned glow) on both the banner and
- // the home screen.
- const QColor brandStrong = accentStrong;
- const QColor brandSoft = themeManager->appColor(AppColor::AccentSoft);
-
- // Dress the stage for the scheme so the banner never fights the
- // surrounding window in either mode. Dark palettes keep the original
- // quiet near-black stage (lightness 29 → 16) with the theme's window
- // hue; light palettes get a pastel "frosted accent" treatment built from
- // the accent hue instead of a plain near-white copy: a coloured wash that
- // clearly belongs to the theme.
- const qreal luma = 0.299 * window.red() + 0.587 * window.green() + 0.114 * window.blue();
- const bool lightStage = luma > 115.0;
- if (lightStage) {
- const int hue = accentStrong.hslHue();
- // Achromatic accents (grey) get a neutral near-white stage instead.
- const int stageSat = hue < 0 ? 0 : 64;
- const int hueSafe = hue < 0 ? 0 : hue;
- // Depth is what stops a light stage reading as a washed-out near-white
- // copy of the page behind the banner: deepen the lower pastel band and
- // raise saturation so the hue is clearly present while staying frosted.
- auto pastel = [hueSafe, stageSat](int lightness) { return QColor::fromHsl(hueSafe, stageSat, lightness); };
- auto pastelLower = [hueSafe](int lightness) { return QColor::fromHsl(hueSafe, 76, lightness); };
- // Brightness-lifted accent for additive glows: the raw accent on a
- // light stage must be mid-bright to read instead of washing out, so
- // lift lightness and saturation together.
- const int accentLightness = qBound(158, accentStrong.lightness() + 82, 198);
- const int accentSaturation = hue < 0 ? 0 : qMax(accentStrong.hslSaturation(), 180);
- const QColor liftedAccent =
- hue < 0 ? accentStrong : QColor::fromHsl(hueSafe, accentSaturation, accentLightness);
- // The centre glow (and logo tint in QML) uses the deep accent itself:
- // a coloured halo/fill behind the logo instead of a white or black one.
- return {pastel(214), pastelLower(186), liftedAccent, accentStrong, brandStrong, brandSoft, 0.80};
- }
-
- // Dark stage: force the window hue down to the banner's curated darkness,
- // scaling saturation away so chromatic palettes tint it without going
- // muddy. The accent is the bright, brand-driven tone (hue from the accent
- // itself, never the -- often grey -- window), and it drives both the
- // embers/fog and the logo glow so the mark tints like the light stage.
- auto stage = [&window](int lightness) {
- const int hue = window.hslHue();
- const int saturation = hue < 0 ? 0 : qBound(0, qRound(window.hslSaturation() * (lightness / 40.0)), 255);
- return QColor::fromHsl(hue, saturation, lightness);
- };
- const int accentHue = accentStrong.hslHue();
- const int accentHueSafe = accentHue < 0 ? 0 : accentHue;
- const int accentLightness = qBound(150, accentStrong.lightness() + 70, 185);
- const int accentSaturation = accentHue < 0 ? 0 : qMax(accentStrong.hslSaturation(), 160);
- const QColor accent =
- accentHue < 0 ? accentStrong : QColor::fromHsl(accentHueSafe, accentSaturation, accentLightness);
- return {stage(29), stage(16), accent, accent, brandStrong, brandSoft, 0.62};
-}
+// Near-black base palette -- the background is dark and quiet so the green
+// accent stands out.
+constexpr QRgb kColorA = 0x1A1A20;
+constexpr QRgb kColorB = 0x0E0E12;
+constexpr QRgb kAccent = 0x8BDD6B;
} // namespace
class GradientFallbackWidget : public QWidget
@@ -113,27 +23,15 @@ class GradientFallbackWidget : public QWidget
public:
using QWidget::QWidget;
- void setColors(const QColor &a, const QColor &b)
- {
- if (a != colorA || b != colorB) {
- colorA = a;
- colorB = b;
- }
- }
-
protected:
void paintEvent(QPaintEvent *) override
{
QPainter painter(this);
QLinearGradient gradient(0, 0, width(), height());
- gradient.setColorAt(0.0, colorA);
- gradient.setColorAt(1.0, colorB);
+ gradient.setColorAt(0.0, QColor(kColorA));
+ gradient.setColorAt(1.0, QColor(kColorB));
painter.fillRect(rect(), gradient);
}
-
-private:
- QColor colorA{QColor(kFallbackColorA)};
- QColor colorB{QColor(kFallbackColorB)};
};
BannerHost::BannerHost(QWidget *parent) : QWidget(parent)
@@ -164,9 +62,6 @@ BannerHost::BannerHost(QWidget *parent) : QWidget(parent)
connect(&clock, &QTimer::timeout, this, &BannerHost::tick);
clock.setInterval(16); // ~60fps; the shader itself is cheap, this is just a wall clock
- connect(themeManager, &ThemeManager::themeChanged, this, &BannerHost::applyThemeColors);
- applyThemeColors();
-
applyMotifPreset(currentMotif);
updateAspect();
}
@@ -228,9 +123,9 @@ void BannerHost::applyMotifPreset(Motif motif)
const Preset p = presetFor(motif);
- config->setColorA(bannerColorA);
- config->setColorB(bannerColorB);
- config->setAccent(bannerAccent);
+ config->setColorA(QColor(kColorA));
+ config->setColorB(QColor(kColorB));
+ config->setAccent(QColor(kAccent));
config->setLogoVisible(motif == Motif::Welcome);
if (isFirstApply) {
@@ -288,34 +183,8 @@ void BannerHost::hideEvent(QHideEvent *event)
clock.stop();
}
-void BannerHost::applyThemeColors()
-{
- const SuggestedColors colors = suggestedBannerColors();
- bannerColorA = colors.colorA;
- bannerColorB = colors.colorB;
- bannerAccent = colors.accent;
-
- if (usingFallback) {
- fallback->setColors(bannerColorA, bannerColorB);
- fallback->update();
- } else if (config) {
- config->setColorA(bannerColorA);
- config->setColorB(bannerColorB);
- config->setAccent(bannerAccent);
- config->setGlowColor(colors.glowColor);
- config->setBrandStrong(colors.brandStrong);
- config->setBrandSoft(colors.brandSoft);
- config->setVignetteMin(colors.vignetteMin);
- }
-}
-
void BannerHost::tick()
{
- // Palette previews (e.g. accent drags in the wizard's QuickSetupPanel)
- // apply qApp->palette() without firing themeChanged, so re-derive here;
- // BannerShaderConfig's setters are equality-guarded, so this is a no-op
- // unless the colours actually changed.
- applyThemeColors();
if (config) {
qreal t = elapsed.elapsed() / 1000.0;
config->setTime(t);
diff --git a/cockatrice/src/interface/widgets/onboarding/shader_banner_widget.h b/cockatrice/src/interface/widgets/onboarding/shader_banner_widget.h
index ac47b1141..2e230ad7f 100644
--- a/cockatrice/src/interface/widgets/onboarding/shader_banner_widget.h
+++ b/cockatrice/src/interface/widgets/onboarding/shader_banner_widget.h
@@ -1,7 +1,6 @@
#ifndef SHADER_BANNER_WIDGET_H
#define SHADER_BANNER_WIDGET_H
-#include
#include
#include
#include
@@ -54,7 +53,6 @@ protected:
private slots:
void tick();
void onSceneGraphFailed();
- void applyThemeColors();
private:
struct Preset
@@ -75,12 +73,6 @@ private:
BannerShaderConfig *config = nullptr;
GradientFallbackWidget *fallback = nullptr;
- // Palette-derived banner colours -- the theme's window hue forced down to
- // the banner's curated darkness, plus the theme's Highlight as accent.
- QColor bannerColorA;
- QColor bannerColorB;
- QColor bannerAccent;
-
QTimer clock;
QElapsedTimer elapsed;
Motif currentMotif = Motif::Welcome;
diff --git a/cockatrice/src/interface/widgets/onboarding/shaders/brand_banner.frag b/cockatrice/src/interface/widgets/onboarding/shaders/brand_banner.frag
index 2bf6d0abf..508bd4bc4 100644
--- a/cockatrice/src/interface/widgets/onboarding/shaders/brand_banner.frag
+++ b/cockatrice/src/interface/widgets/onboarding/shaders/brand_banner.frag
@@ -28,8 +28,6 @@ layout(std140, binding = 0) uniform buf
vec4 uColorA;
vec4 uColorB;
vec4 uAccent;
- vec4 uGlowColor;
- float uVignetteMin;
float uLogoGlow;
};
@@ -121,7 +119,7 @@ vec3 backgroundField(vec2 uv, float time)
// Accent-coloured fog layer: flowNoise peaks above 0.6 contribute accent
float fog = flowNoise(uv * 0.8 + vec2(100.0, 50.0), time * 0.02);
- col += uAccent.rgb * max(fog - 0.6, 0.0) * 0.14;
+ col += uAccent.rgb * max(fog - 0.6, 0.0) * 0.10;
return col;
}
@@ -138,17 +136,14 @@ vec3 motifWelcome(vec2 uv, vec3 bg, float t)
vec2 center = vec2(asp * 0.5, 0.5);
float cDist = length(ac - center);
- // Centre bloom at logo position; intensity scales with uLogoGlow. The
- // QML brandGlow halo now supplies the primary logo surround (the two
- // brand appColors), so this shader bloom is deliberately kept as a subtle
- // ambience rather than a competing glow.
+ // Centre bloom at logo position; intensity scales with uLogoGlow
float centreLight = bloom(cDist, 0.08 * asp, 0.40 * asp);
- col += uGlowColor.rgb * centreLight * 0.20 * uLogoGlow;
+ col += centreLight * 0.20 * uLogoGlow;
// Flow-noise shimmer gated by Gaussian mask at centre
float shimmer = flowNoise(ac * 0.8 + vec2(55.0, 33.0), t * 0.05) * 0.5 + 0.5;
float shimmerMask = exp(-(cDist * cDist) / (0.18 * asp * 0.18 * asp));
- col += uGlowColor.rgb * shimmer * shimmerMask * 0.04 * uLogoGlow;
+ col += shimmer * shimmerMask * 0.04 * uLogoGlow;
// 48 ember particles: hash-seeded position, speed, size, brightness.
// Embers within a distance threshold of centre are deflected into an
@@ -167,8 +162,8 @@ vec3 motifWelcome(vec2 uv, vec3 bg, float t)
float pX = baseX * asp + sin(t * driftFreq + fi * 1.7) * driftAmp * asp;
float pY = fract(baseY + t * riseSpeed);
- float size = 0.010 + hash21(vec2(fi * 2.9, uSeed * 4.7)) * 0.014;
- float bright = 0.18 + hash21(vec2(fi * 6.1, uSeed * 0.9)) * 0.32;
+ float size = 0.006 + hash21(vec2(fi * 2.9, uSeed * 4.7)) * 0.012;
+ float bright = 0.15 + hash21(vec2(fi * 6.1, uSeed * 0.9)) * 0.30;
// Fade out near top/bottom edges
float edgeFade = smoothstep(0.0, 0.12, pY) * smoothstep(1.0, 0.88, pY);
@@ -237,7 +232,7 @@ vec3 motifCardDatabase(vec2 uv, vec3 bg, float t)
// Semi-transparent dark fill
float fill = smoothstep(0.015, -0.005, d);
- col = mix(col, uColorB.rgb * 0.60, fill * 0.62);
+ col = mix(col, uColorB.rgb * 0.55, fill * 0.50);
// Accent outline
float edge = smoothstep(0.035, 0.0, abs(d));
@@ -314,7 +309,7 @@ vec3 motifAccount(vec2 uv, vec3 bg, float t)
// Node glow via bloom; intensity modulated by pulse
float dist = length(ac - pos);
- col += uAccent.rgb * bloom(dist, 0.018, 0.08) * mix(0.30, 0.55, pulse);
+ col += uAccent.rgb * bloom(dist, 0.018, 0.08) * mix(0.20, 0.45, pulse);
}
// Edges: connect nodes within a radius threshold
@@ -328,19 +323,19 @@ vec3 motifAccount(vec2 uv, vec3 bg, float t)
vec2 ba = nodePos[j] - nodePos[i];
float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);
float lineDist = length(pa - ba * h);
- col += uAccent.rgb * smoothstep(0.010, 0.0, lineDist) * strength * 0.14;
+ col += uAccent.rgb * smoothstep(0.010, 0.0, lineDist) * strength * 0.10;
}
}
}
// Central bloom at banner centre
float cDist = length(ac - center);
- col += uAccent.rgb * bloom(cDist, 0.04, 0.25) * 0.20;
+ col += uAccent.rgb * bloom(cDist, 0.04, 0.25) * 0.12;
// Periodic expanding ring from centre
float ripplePhase = t * 0.4;
float rippleDist = abs(cDist - fract(ripplePhase) * asp * 0.7);
- col += uAccent.rgb * smoothstep(0.02, 0.0, rippleDist) * 0.14;
+ col += uAccent.rgb * smoothstep(0.02, 0.0, rippleDist) * 0.10;
return col;
}
@@ -461,8 +456,6 @@ void main()
else if (uMode < 4.5) col = motifPreferences(uv, bg, t);
else col = motifFinish(uv, bg, t);
- // Corner vignette; uVignetteMin is scheme-driven (0.62 on dark stages,
- // gentler on light ones so near-white corners don't go muddy grey).
- col *= mix(uVignetteMin, 1.0, vignette(uv));
+ col *= mix(0.62, 1.0, vignette(uv));
fragColor = vec4(col, 1.0) * qt_Opacity;
}
diff --git a/cockatrice/src/interface/widgets/onboarding/shaders/brand_plate.frag b/cockatrice/src/interface/widgets/onboarding/shaders/brand_plate.frag
deleted file mode 100644
index 43b798c9f..000000000
--- a/cockatrice/src/interface/widgets/onboarding/shaders/brand_plate.frag
+++ /dev/null
@@ -1,42 +0,0 @@
-#version 440
-
-// The logo's gradient plate, drawn by us rather than the baked-in SVG: a
-// linear blend between the two brand appColors (light AccentSoft at the
-// top-left grading to dark AccentStrong at the bottom-right, mirroring
-// cockatrice.svg's linearGradient4265-7-8 userSpaceOnUse axis), clipped to
-// the bird's full silhouette via the full-color logo's alpha (uSilhouette).
-// The white highlight path (cockatrice-logo-white) is overlaid in QML on top,
-// exactly as the SVG stacks its white path over the gradient paths. Fully
-// static: no glow, no breathing — the plate just sits there like the home
-// widget's QPainter composite.
-
-layout(location = 0) in vec2 qt_TexCoord0;
-layout(location = 0) out vec4 fragColor;
-
-layout(std140, binding = 0) uniform buf
-{
- mat4 qt_Matrix;
- float qt_Opacity;
- vec4 uStrong;
- vec4 uSoft;
-};
-
-// The full-color logo's alpha channel acts as the silhouette mask: the
-// gradient only appears inside the bird, exactly like the SVG's gradient paths.
-layout(binding = 1) uniform sampler2D uSilhouette;
-
-void main()
-{
- // Recreate cockatrice.svg's own gradient geometry (linearGradient4265-7-8,
- // userSpaceOnUse): light AccentSoft at the start point S=(-8.097,-97.746),
- // dark AccentStrong at the end E=(162.455,295.208), on the SVG's 300x300
- // canvas. Normalized to UV space, V=E-S=(0.5685,1.3098), so
- // t = dot(uv - S_norm, V)/|V|^2 with S_norm=(-0.0270,-0.3258).
- float t = clamp(dot(qt_TexCoord0 - vec2(-0.02699, -0.32582), vec2(0.56851, 1.30985)) / 2.03891, 0.0, 1.0);
- vec3 color = mix(uSoft.rgb, uStrong.rgb, t);
-
- // Anti-aliased silhouette clip from the full-color logo's alpha.
- float alpha = texture(uSilhouette, qt_TexCoord0).a;
-
- fragColor = vec4(color * alpha, alpha) * qt_Opacity;
-}
\ No newline at end of file
diff --git a/cockatrice/src/interface/widgets/playmat/playmat_settings_dialog.cpp b/cockatrice/src/interface/widgets/playmat/playmat_settings_dialog.cpp
index 9459c5ea9..57706cf93 100644
--- a/cockatrice/src/interface/widgets/playmat/playmat_settings_dialog.cpp
+++ b/cockatrice/src/interface/widgets/playmat/playmat_settings_dialog.cpp
@@ -2,7 +2,6 @@
#include "../../card_picture_loader/card_picture_loader.h"
#include "../cards/art_crop_attribution.h"
-#include "../cards/card_art_utils.h"
#include "../utility/completer_utils.h"
#include "card_database_display_model.h"
#include "card_database_model.h"
@@ -277,7 +276,7 @@ void PlaymatSettingsDialog::reloadPreview()
return;
}
- currentPixmap = CardArtUtils::rotateSidewaysLayoutArt(fullRes, card);
+ currentPixmap = fullRes;
preview->setPixmap(currentPixmap);
preview->setParams(currentParams);
preview->setAttribution(buildArtAttribution(card));
diff --git a/cockatrice/src/interface/widgets/printing_selector/printing_selector_card_overlay_widget.cpp b/cockatrice/src/interface/widgets/printing_selector/printing_selector_card_overlay_widget.cpp
index e8816847e..0b77ca185 100644
--- a/cockatrice/src/interface/widgets/printing_selector/printing_selector_card_overlay_widget.cpp
+++ b/cockatrice/src/interface/widgets/printing_selector/printing_selector_card_overlay_widget.cpp
@@ -1,19 +1,13 @@
#include "printing_selector_card_overlay_widget.h"
#include "../../../client/settings/cache_settings.h"
-#include "../../card_picture_loader/card_picture_loader.h"
#include "../cards/card_info_picture_widget.h"
#include "printing_selector_card_display_widget.h"
-#include
-#include
#include
#include
#include
-#include
#include
-#include
-#include
#include
#include
#include
@@ -21,49 +15,6 @@
#include
#include
-namespace
-{
-/**
- * @brief Places the preview beside the highlighted action inside the given screen.
- *
- * Side-aware: hugs the side of the action that has room, aligned with its row, then
- * clamps every edge so the preview always lands fully on-screen on first show.
- */
-QPoint
-previewPositionNear(const QRect &actionRect, const QSize &labelSize, const QRect &screenGeometry, int previewOffset)
-{
- const bool rightFits = actionRect.right() + previewOffset + labelSize.width() <= screenGeometry.right();
- const bool leftFits = actionRect.left() - previewOffset - labelSize.width() >= screenGeometry.left();
-
- int x;
- if (rightFits) {
- x = actionRect.right() + previewOffset;
- } else if (leftFits) {
- x = actionRect.left() - previewOffset - labelSize.width();
- } else {
- x = actionRect.left();
- }
- x = qMax(screenGeometry.left(), x);
- x = qMin(screenGeometry.right() - labelSize.width() + 1, x);
-
- const bool belowFits = actionRect.bottom() + previewOffset + labelSize.height() <= screenGeometry.bottom();
- const bool aboveFits = actionRect.top() - previewOffset - labelSize.height() >= screenGeometry.top();
-
- int y;
- if (belowFits) {
- y = actionRect.bottom() + previewOffset;
- } else if (aboveFits) {
- y = actionRect.top() - previewOffset - labelSize.height();
- } else {
- y = actionRect.top();
- }
- y = qMax(screenGeometry.top(), y);
- y = qMin(screenGeometry.bottom() - labelSize.height() + 1, y);
-
- return {x, y};
-}
-} // namespace
-
/**
* @brief Constructs a PrintingSelectorCardOverlayWidget for displaying a card overlay.
*
@@ -99,31 +50,6 @@ PrintingSelectorCardOverlayWidget::PrintingSelectorCardOverlayWidget(QWidget *pa
initializePinBadge();
- // Parent the preview to this overlay so it is destroyed with it (Qt::ToolTip keeps
- // it a frameless, non-activating top-level window despite the parent).
- cardOverridePreviewLabel = new QLabel(this, Qt::ToolTip);
- cardOverridePreviewLabel->setWindowFlag(Qt::FramelessWindowHint);
- cardOverridePreviewLabel->setAttribute(Qt::WA_ShowWithoutActivating);
- cardOverridePreviewLabel->setScaledContents(true);
- cardOverridePreviewLabel->hide();
-
- // While the preview is visible, keep it honest: when the hovered printing's art
- // resolves (all alternate printings share the root card's CardInfo), redraw it in place.
- if (rootCard.getCardPtr()) {
- connect(rootCard.getCardPtr().data(), &CardInfo::pixmapUpdated, this, [this] {
- if (cardOverridePreviewLabel->isVisible()) {
- refreshPreview();
- }
- });
- }
-
- // Alt-Tab / app-inactive must not strand the floating preview.
- connect(qApp, &QGuiApplication::applicationStateChanged, this, [this](Qt::ApplicationState state) {
- if (state != Qt::ApplicationActive) {
- hidePreview();
- }
- });
-
// Update when this overlay emits cardPreferenceChanged or when size/scale changes
connect(this, &PrintingSelectorCardOverlayWidget::cardPreferenceChanged, this,
&PrintingSelectorCardOverlayWidget::updatePinBadgeVisibility);
@@ -259,23 +185,19 @@ void PrintingSelectorCardOverlayWidget::leaveEvent(QEvent *event)
}
/**
- * @brief Creates and shows the card-overlay context menu.
+ * @brief Creates and shows a custom context menu when the right mouse button is clicked.
*
- * The menu includes the card art preference (Pin/Unpin Printing), the Image Overrides
- * submenu (Load Custom Image, Clear Custom Image, and one entry per alternate printing with a
- * live preview), and the Show Related cards submenu.
+ * The context menu includes an option to show related cards, which displays a submenu with actions
+ * for each related card. When an action is triggered, the card information is updated, and the
+ * printing selector is shown.
*
- * @param point The local position the menu should pop at.
+ * @param point The position of the mouse when the right-click occurred.
*/
void PrintingSelectorCardOverlayWidget::customMenu(QPoint point)
{
QMenu menu;
- hidePreview(); // Clear any preview state left over from a previous menu run.
-
- // Submenus are owned by the stack-allocated top-level menu (addMenu() does not
- // transfer ownership).
- auto *preferenceMenu = new QMenu(tr("Preference"), &menu);
+ auto *preferenceMenu = new QMenu(tr("Preference"));
menu.addMenu(preferenceMenu);
const auto &preferredProviderId =
@@ -297,66 +219,8 @@ void PrintingSelectorCardOverlayWidget::customMenu(QPoint point)
});
}
- menu.addSeparator();
-
- auto *overrideMenu = new QMenu(tr("Image Overrides"), &menu);
-
- auto *loadCustomAction = overrideMenu->addAction(tr("Load Custom Image..."));
- auto *clearOverrideAction = overrideMenu->addAction(tr("Clear Custom Image"));
-
- // Nothing to clear on a card that has no local override yet.
- clearOverrideAction->setEnabled(CardPictureLoader::hasLocalOverrides(rootCard));
-
- overrideMenu->addSeparator();
-
- const auto &allSets = rootCard.getInfo().getSets();
-
- for (const auto &set : allSets) {
- for (const auto &printing : set) {
- if (printing == rootCard.getPrinting()) {
- continue;
- }
-
- // The submenu is already scoped to this card, so the rows lead with set +
- // collector; only printings with a distinct display name add their own name.
- const CardSetPtr cardSet = printing.getSet();
- if (!cardSet) {
- continue;
- }
-
- QString label = tr("%1 %2").arg(cardSet->getCorrectedShortName(), printing.getProperty("num"));
-
- auto *action = overrideMenu->addAction(label);
-
- ExactCard overrideCard(rootCard.getCardPtr(), printing);
- action->setData(QVariant::fromValue(overrideCard));
-
- connect(action, &QAction::triggered, this, [this, overrideCard]() {
- CardPictureLoader::getInstance().installPrintingOverride(rootCard, overrideCard);
- QPixmapCache::clear();
- rootCard.emitPixmapUpdated(); // refresh the overlay art in place, like the other paths
- });
- }
- }
-
- connect(clearOverrideAction, &QAction::triggered, this, [this]() {
- CardPictureLoader::deleteAllLocalOverrides(rootCard);
- QPixmapCache::clear();
- rootCard.emitPixmapUpdated(); // force UI refresh
- });
-
- connect(loadCustomAction, &QAction::triggered, this, &PrintingSelectorCardOverlayWidget::loadCustomImage);
-
- connect(overrideMenu, &QMenu::hovered, this, &PrintingSelectorCardOverlayWidget::showPreviewForAction);
- connect(overrideMenu, &QMenu::aboutToHide, this, &PrintingSelectorCardOverlayWidget::hidePreview);
- connect(overrideMenu, &QMenu::triggered, this, &PrintingSelectorCardOverlayWidget::hidePreview);
-
- menu.addMenu(overrideMenu);
-
- menu.addSeparator();
-
// filling out the related cards submenu
- auto *relatedMenu = new QMenu(tr("Show Related cards"), &menu);
+ auto *relatedMenu = new QMenu(tr("Show Related cards"));
menu.addMenu(relatedMenu);
auto relatedCards = rootCard.getInfo().getAllRelatedCards();
if (relatedCards.isEmpty()) {
@@ -371,11 +235,7 @@ void PrintingSelectorCardOverlayWidget::customMenu(QPoint point)
});
}
}
- // The preview anchors itself to this popup's global geometry while it is open, so the
- // pointer must stay valid for the whole exec() and be dropped before the stack unwinds.
- previewSourceMenu = overrideMenu;
menu.exec(this->mapToGlobal(point));
- previewSourceMenu = nullptr;
}
/**
@@ -431,136 +291,3 @@ void PrintingSelectorCardOverlayWidget::initializePinBadge()
pinBadge->setVisible(false);
pinBadge->raise();
}
-
-/**
- * @brief Asks for an image file and installs it as the card's custom art.
- *
- * Unreadable files answer with a visible warning instead of a silent no-op.
- */
-void PrintingSelectorCardOverlayWidget::loadCustomImage()
-{
- QString filePath = QFileDialog::getOpenFileName(this, tr("Select Card Image"), QString(),
- tr("Images (*.png *.jpg *.jpeg *.webp)"));
-
- if (filePath.isEmpty()) {
- return;
- }
-
- QPixmap pixmap(filePath);
- if (pixmap.isNull()) {
- // No silent paths: a file that cannot be read answers visibly instead of a no-op.
- QMessageBox::warning(this, tr("Load Custom Image"), tr("The selected file could not be read as an image."));
- return;
- }
-
- CardPictureLoader::getInstance().saveCardImageToLocalStorage(rootCard, pixmap, true);
-
- QPixmapCache::clear();
- rootCard.emitPixmapUpdated();
-}
-
-/**
- * @brief Shows the hover preview for a highlighted printing entry in the Image Overrides submenu.
- *
- * QMenu::hovered fires on keyboard highlight too, so the preview appears when arrows walk
- * onto a printing entry, not only under the mouse.
- *
- * Non-printing entries (e.g., Load Custom Image, Clear Custom Image) hide the preview.
- *
- * @param action The action that was highlighted.
- */
-void PrintingSelectorCardOverlayWidget::showPreviewForAction(QAction *action)
-{
- if (!action) {
- hidePreview();
- return;
- }
-
- const QVariant data = action->data();
-
- if (!data.canConvert()) {
- hidePreview();
- return;
- }
-
- const ExactCard previewCard = qvariant_cast(data);
- if (previewCard.isEmpty()) {
- hidePreview();
- return;
- }
-
- hoveredOverrideCard = previewCard;
- hoveredOverrideAction = action;
- refreshPreview();
-}
-
-/**
- * @brief Renders the hover preview for the currently highlighted printing.
- *
- * The preview shows the loading placeholder while the art is pending and swaps in the real
- * art when it resolves. The label is positioned against its already-resized geometry so the
- * first-ever show at the screen's edges stays fully on-screen.
- */
-void PrintingSelectorCardOverlayWidget::refreshPreview()
-{
- if (hoveredOverrideCard.isEmpty()) {
- hidePreview();
- return;
- }
-
- constexpr QSize previewSize(240, 336);
- constexpr int previewOffset = 20;
-
- QPixmap pixmap;
- CardPictureLoader::getPixmap(pixmap, hoveredOverrideCard, previewSize);
-
- if (pixmap.isNull()) {
- // Keep the preview honest while loading: show the loading placeholder instead of a void.
- // Fetch at the logical size and let the label scale it, so the placeholder matches the
- // real art's footprint rather than doubling on HiDPI displays.
- CardPictureLoader::getCardBackLoadingInProgressPixmap(pixmap, previewSize);
- }
-
- cardOverridePreviewLabel->setPixmap(pixmap);
- // QPixmap::size() is physical pixels; the label layout must use the device-independent size
- // so the preview keeps a constant footprint across DPI settings (QScreen geometry is logical).
- const QSize labelSize = pixmap.deviceIndependentSize().toSize();
- cardOverridePreviewLabel->resize(labelSize);
-
- // Anchor the preview to the walked submenu popup rather than QCursor::pos(), which is idle
- // under keyboard-only operation: a keyboard-highlighted row must preview at the same place as
- // a hovered one. The mouse path is unchanged in effect — the popup sits under the cursor, so
- // the preview stays beside the row in both modalities.
- const QMenu *popup = previewSourceMenu;
- if (!popup || !popup->isVisible() || !hoveredOverrideAction) {
- hidePreview();
- return;
- }
-
- const QRect popupGeometry = popup->geometry();
- const QRect actionRectLocal = popup->actionGeometry(hoveredOverrideAction);
- const QRect actionRect(popupGeometry.topLeft() + actionRectLocal.topLeft(), actionRectLocal.size());
-
- QScreen *screen = QGuiApplication::screenAt(popupGeometry.center());
- if (!screen) {
- hidePreview();
- return;
- }
- const QRect &screenGeometry = screen->geometry();
-
- cardOverridePreviewLabel->move(previewPositionNear(actionRect, labelSize, screenGeometry, previewOffset));
- cardOverridePreviewLabel->show();
-}
-
-/**
- * @brief Hides the hover preview and forgets the currently highlighted printing.
- */
-void PrintingSelectorCardOverlayWidget::hidePreview()
-{
- hoveredOverrideCard = ExactCard();
- hoveredOverrideAction = nullptr;
-
- if (cardOverridePreviewLabel) {
- cardOverridePreviewLabel->hide();
- }
-}
diff --git a/cockatrice/src/interface/widgets/printing_selector/printing_selector_card_overlay_widget.h b/cockatrice/src/interface/widgets/printing_selector/printing_selector_card_overlay_widget.h
index fbcfa9230..228393c9c 100644
--- a/cockatrice/src/interface/widgets/printing_selector/printing_selector_card_overlay_widget.h
+++ b/cockatrice/src/interface/widgets/printing_selector/printing_selector_card_overlay_widget.h
@@ -13,9 +13,6 @@
#include
-class QAction;
-class QMenu;
-
class PrintingSelectorCardOverlayWidget : public QWidget
{
Q_OBJECT
@@ -46,19 +43,11 @@ private slots:
private:
void initializePinBadge();
- void loadCustomImage();
- void showPreviewForAction(QAction *action);
- void refreshPreview();
- void hidePreview();
CardInfoPictureWidget *cardInfoPicture;
AllZonesCardAmountWidget *allZonesCardAmountWidget;
QLabel *pinBadge = nullptr;
AbstractTabDeckEditor *deckEditor;
ExactCard rootCard;
- QLabel *cardOverridePreviewLabel = nullptr;
- ExactCard hoveredOverrideCard;
- QMenu *previewSourceMenu = nullptr;
- QAction *hoveredOverrideAction = nullptr;
};
#endif // PRINTING_SELECTOR_CARD_OVERLAY_WIDGET_H
diff --git a/cockatrice/src/interface/widgets/quick_settings/settings_button_widget.cpp b/cockatrice/src/interface/widgets/quick_settings/settings_button_widget.cpp
index 881c3e3ac..9c433ab5a 100644
--- a/cockatrice/src/interface/widgets/quick_settings/settings_button_widget.cpp
+++ b/cockatrice/src/interface/widgets/quick_settings/settings_button_widget.cpp
@@ -1,7 +1,5 @@
#include "settings_button_widget.h"
-#include "../../pixel_map_generator.h"
-
#include
#include
#include
@@ -10,7 +8,7 @@
SettingsButtonWidget::SettingsButtonWidget(QWidget *parent)
: QWidget(parent), button(new QToolButton(this)), popup(new SettingsPopupWidget(nullptr))
{
- button->setIcon(themePixmap(QStringLiteral("icons/cogwheel")));
+ button->setIcon(QPixmap("theme:icons/cogwheel"));
button->setCheckable(true);
button->setFixedSize(32, 32);
connect(button, &QToolButton::clicked, this, &SettingsButtonWidget::togglePopup);
diff --git a/cockatrice/src/interface/widgets/replay/replay_manager.cpp b/cockatrice/src/interface/widgets/replay/replay_manager.cpp
index c51b96b6c..a2c1e0ff0 100644
--- a/cockatrice/src/interface/widgets/replay/replay_manager.cpp
+++ b/cockatrice/src/interface/widgets/replay/replay_manager.cpp
@@ -142,10 +142,8 @@ void ReplayManager::processNewEvents(PlaybackMode playbackMode)
}
// backwards skip => always skip tap animation
- // backwards skip => always skip damage animation (battlefield shimmer / life counter flash)
if (playbackMode == BACKWARD_SKIP) {
options |= SKIP_TAP_ANIMATION;
- options |= SKIP_DAMAGE_ANIMATION;
}
emit eventReplayed(replay->event_list(currentEvent), options);
diff --git a/cockatrice/src/interface/widgets/replay/replay_widget.cpp b/cockatrice/src/interface/widgets/replay/replay_widget.cpp
index c92771f8c..6c85d950e 100644
--- a/cockatrice/src/interface/widgets/replay/replay_widget.cpp
+++ b/cockatrice/src/interface/widgets/replay/replay_widget.cpp
@@ -2,7 +2,6 @@
#include "../../../client/settings/cache_settings.h"
#include "../../../client/settings/shortcuts_settings.h"
-#include "../../pixel_map_generator.h"
#include "../interface/widgets/tabs/tab_game.h"
#include "replay_manager.h"
#include "replay_quick_settings_widget.h"
@@ -51,15 +50,15 @@ ReplayWidget::ReplayWidget(QWidget *parent, GameReplay *replay)
replayPlayButton = new QToolButton;
replayPlayButton->setIconSize(QSize(32, 32));
QIcon playButtonIcon = QIcon();
- playButtonIcon.addPixmap(themePixmap(QStringLiteral("replay/start")), QIcon::Normal, QIcon::Off);
- playButtonIcon.addPixmap(themePixmap(QStringLiteral("replay/pause")), QIcon::Normal, QIcon::On);
+ playButtonIcon.addPixmap(QPixmap("theme:replay/start"), QIcon::Normal, QIcon::Off);
+ playButtonIcon.addPixmap(QPixmap("theme:replay/pause"), QIcon::Normal, QIcon::On);
replayPlayButton->setIcon(playButtonIcon);
replayPlayButton->setCheckable(true);
connect(replayPlayButton, &QToolButton::toggled, this, &ReplayWidget::replayPlayButtonToggled);
replayFastForwardButton = new QToolButton;
replayFastForwardButton->setIconSize(QSize(32, 32));
- replayFastForwardButton->setIcon(themePixmap(QStringLiteral("replay/fastforward")));
+ replayFastForwardButton->setIcon(QPixmap("theme:replay/fastforward"));
replayFastForwardButton->setCheckable(true);
connect(replayFastForwardButton, &QToolButton::toggled, this, &ReplayWidget::updateTimeScaleFactor);
diff --git a/cockatrice/src/interface/widgets/server/game_selector.cpp b/cockatrice/src/interface/widgets/server/game_selector.cpp
index a8bf54e91..f41002247 100644
--- a/cockatrice/src/interface/widgets/server/game_selector.cpp
+++ b/cockatrice/src/interface/widgets/server/game_selector.cpp
@@ -1,6 +1,5 @@
#include "game_selector.h"
-#include "../../pixel_map_generator.h"
#include "../interface/widgets/dialogs/dlg_create_game.h"
#include "../interface/widgets/dialogs/dlg_filter_games.h"
#include "../interface/widgets/tabs/tab_account.h"
@@ -96,10 +95,10 @@ GameSelector::GameSelector(AbstractClient *_client,
}
filterButton = new QPushButton;
- filterButton->setIcon(themePixmap(QStringLiteral("icons/search")));
+ filterButton->setIcon(QPixmap("theme:icons/search"));
connect(filterButton, &QPushButton::clicked, this, &GameSelector::actSetFilter);
clearFilterButton = new QPushButton;
- clearFilterButton->setIcon(themePixmap(QStringLiteral("icons/clearsearch")));
+ clearFilterButton->setIcon(QPixmap("theme:icons/clearsearch"));
bool filtersSetToDefault = showFilters && gameListProxyModel->areFilterParametersSetToDefaults();
clearFilterButton->setEnabled(!filtersSetToDefault);
connect(clearFilterButton, &QPushButton::clicked, this, &GameSelector::actClearFilter);
diff --git a/cockatrice/src/interface/widgets/server/remote/remote_replay_list_tree_widget.cpp b/cockatrice/src/interface/widgets/server/remote/remote_replay_list_tree_widget.cpp
index d62bf81aa..1f034b767 100644
--- a/cockatrice/src/interface/widgets/server/remote/remote_replay_list_tree_widget.cpp
+++ b/cockatrice/src/interface/widgets/server/remote/remote_replay_list_tree_widget.cpp
@@ -1,7 +1,5 @@
#include "remote_replay_list_tree_widget.h"
-#include "../../../pixel_map_generator.h"
-
#include
#include
#include
@@ -39,7 +37,7 @@ RemoteReplayList_TreeModel::RemoteReplayList_TreeModel(AbstractClient *_client,
QFileIconProvider fip;
dirIcon = fip.icon(QFileIconProvider::Folder);
fileIcon = fip.icon(QFileIconProvider::File);
- lockIcon = themePixmap(QStringLiteral("icons/lock"));
+ lockIcon = QPixmap("theme:icons/lock");
}
RemoteReplayList_TreeModel::~RemoteReplayList_TreeModel()
diff --git a/cockatrice/src/interface/widgets/server/user/user_card_art_provider.cpp b/cockatrice/src/interface/widgets/server/user/user_card_art_provider.cpp
index 2ba745715..3a1876fa1 100644
--- a/cockatrice/src/interface/widgets/server/user/user_card_art_provider.cpp
+++ b/cockatrice/src/interface/widgets/server/user/user_card_art_provider.cpp
@@ -1,7 +1,6 @@
#include "user_card_art_provider.h"
#include "../../../card_picture_loader/card_picture_loader.h"
-#include "../../cards/card_art_utils.h"
#include
#include
@@ -53,25 +52,16 @@ void UserCardArtProvider::requestCardArt(const QString &userName, const QString
processQueue();
}
-QPixmap UserCardArtProvider::cropCardArt(const QPixmap &fullRes, const ExactCard &card)
+QPixmap UserCardArtProvider::cropCardArt(const QPixmap &fullRes)
{
- QPixmap source = fullRes;
-
- // Sideways-layout cards (plane, siege/battle, split) store their landscape
- // artwork rotated 90° inside a portrait frame. Rotate it upright first so
- // the crop below lands on the horizontal art, mirroring the way
- // CardInfoPictureWidget displays these cards.
- const bool landscape = card.getInfo().getUiAttributes().landscapeOrientation;
- source = CardArtUtils::rotateSidewaysLayoutArt(source, card);
-
- const QSize sz = source.size();
+ const QSize sz = fullRes.size();
const int marginX = sz.width() * 0.07;
- const int topMargin = landscape ? sz.height() * 0.05 : sz.height() * 0.11;
- const int bottomMargin = landscape ? sz.height() * 0.42 : sz.height() * 0.45;
+ const int topMargin = sz.height() * 0.11;
+ const int bottomMargin = sz.height() * 0.45;
- const QRect artRect(marginX, topMargin, sz.width() - 2 * marginX, sz.height() - topMargin - bottomMargin);
+ const QRect foilRect(marginX, topMargin, sz.width() - 2 * marginX, sz.height() - topMargin - bottomMargin);
- return source.copy(artRect.intersected(source.rect()));
+ return fullRes.copy(foilRect.intersected(fullRes.rect()));
}
void UserCardArtProvider::insertIntoCache(const QString &key, const QPixmap &pixmap)
@@ -121,7 +111,7 @@ void UserCardArtProvider::processQueue()
// Synchronous hit (already loaded/on disk)
if (!fullRes.isNull()) {
- insertIntoCache(key, cropCardArt(fullRes, card));
+ insertIntoCache(key, cropCardArt(fullRes));
pending.remove(key);
emit cardArtUpdated(userName);
@@ -145,7 +135,7 @@ void UserCardArtProvider::processQueue()
CardPictureLoader::getPixmap(fullRes, card, QSize(745, 1040));
if (!fullRes.isNull()) {
- self->insertIntoCache(key, self->cropCardArt(fullRes, card));
+ self->insertIntoCache(key, self->cropCardArt(fullRes));
}
self->pending.remove(key);
diff --git a/cockatrice/src/interface/widgets/server/user/user_card_art_provider.h b/cockatrice/src/interface/widgets/server/user/user_card_art_provider.h
index e8283a891..2592237c4 100644
--- a/cockatrice/src/interface/widgets/server/user/user_card_art_provider.h
+++ b/cockatrice/src/interface/widgets/server/user/user_card_art_provider.h
@@ -6,7 +6,6 @@
#include
#include
#include
-#include
class UserCardArtProvider : public QObject
{
@@ -17,7 +16,7 @@ public:
void requestCardArt(const QString &userName, const QString &cardName, const QString &providerId);
const QMap &cache() const;
- static QPixmap cropCardArt(const QPixmap &fullRes, const ExactCard &card);
+ static QPixmap cropCardArt(const QPixmap &fullRes);
signals:
void cardArtUpdated(const QString &userName);
diff --git a/cockatrice/src/interface/widgets/server/user/user_card_settings_dialog.cpp b/cockatrice/src/interface/widgets/server/user/user_card_settings_dialog.cpp
index d49e3d540..532112964 100644
--- a/cockatrice/src/interface/widgets/server/user/user_card_settings_dialog.cpp
+++ b/cockatrice/src/interface/widgets/server/user/user_card_settings_dialog.cpp
@@ -560,7 +560,7 @@ void UserCardArtSettingsDialog::reloadPreview()
return;
}
- currentPixmap = UserCardArtProvider::cropCardArt(fullRes, card);
+ currentPixmap = UserCardArtProvider::cropCardArt(fullRes);
preview->setPixmap(currentPixmap);
preview->setParams(currentParams);
diff --git a/cockatrice/src/interface/widgets/server/user/user_context_menu.cpp b/cockatrice/src/interface/widgets/server/user/user_context_menu.cpp
index 0d2267a63..8d5d423f6 100644
--- a/cockatrice/src/interface/widgets/server/user/user_context_menu.cpp
+++ b/cockatrice/src/interface/widgets/server/user/user_context_menu.cpp
@@ -51,8 +51,6 @@ UserContextMenu::UserContextMenu(TabSupervisor *_tabSupervisor, QWidget *parent,
aDemoteFromMod = new QAction(QString(), this);
aPromoteToJudge = new QAction(QString(), this);
aDemoteFromJudge = new QAction(QString(), this);
- aPromoteToDeveloper = new QAction(QString(), this);
- aDemoteFromDeveloper = new QAction(QString(), this);
aGetAdminNotes = new QAction(QString(), this);
aInvestigateUser = new QAction(QString(), this);
@@ -78,8 +76,6 @@ void UserContextMenu::retranslateUi()
aDemoteFromMod->setText(tr("Dem&ote user from moderator"));
aPromoteToJudge->setText(tr("Promote user to &judge"));
aDemoteFromJudge->setText(tr("Demote user from judge"));
- aPromoteToDeveloper->setText(tr("Promote user to &developer"));
- aDemoteFromDeveloper->setText(tr("Demote user from de&veloper"));
aGetAdminNotes->setText(tr("View admin notes"));
aInvestigateUser->setText(tr("Investigate user"));
}
@@ -272,7 +268,7 @@ void UserContextMenu::adjustMod_processUserResponse(const Response &resp, const
const Command_AdjustMod &cmd = commandContainer.admin_command(0).GetExtension(Command_AdjustMod::ext);
if (resp.response_code() == Response::RespOk) {
- if (cmd.should_be_mod() || cmd.should_be_judge() || cmd.should_be_developer()) {
+ if (cmd.should_be_mod() || cmd.should_be_judge()) {
QMessageBox::information(static_cast(parent()), tr("Success"),
tr("Successfully promoted user."));
} else {
@@ -280,7 +276,7 @@ void UserContextMenu::adjustMod_processUserResponse(const Response &resp, const
}
} else {
- if (cmd.should_be_mod() || cmd.should_be_judge() || cmd.should_be_developer()) {
+ if (cmd.should_be_mod() || cmd.should_be_judge()) {
QMessageBox::information(static_cast(parent()), tr("Failed"), tr("Failed to promote user."));
} else {
QMessageBox::information(static_cast(parent()), tr("Failed"), tr("Failed to demote user."));
@@ -441,18 +437,9 @@ void UserContextMenu::showContextMenu(const QPoint &pos,
(tabSupervisor->getUserInfo()->user_level() & ServerInfo_User::IsAdmin)) {
menu->addAction(aPromoteToJudge);
}
-
- if (userLevel.testFlag(ServerInfo_User::IsDeveloper) &&
- (tabSupervisor->getUserInfo()->user_level() & ServerInfo_User::IsAdmin)) {
- menu->addAction(aDemoteFromDeveloper);
-
- } else if (userLevel.testFlag(ServerInfo_User::IsRegistered) &&
- (tabSupervisor->getUserInfo()->user_level() & ServerInfo_User::IsAdmin)) {
- menu->addAction(aPromoteToDeveloper);
- }
}
aDetails->setEnabled(true);
- aChat->setEnabled(anotherUser && online && !userListProxy->isUserIgnored(userName));
+ aChat->setEnabled(anotherUser && online);
aShowGames->setEnabled(online);
aReport->setEnabled(anotherUser);
aAddToBuddyList->setEnabled(anotherUser);
@@ -468,10 +455,6 @@ void UserContextMenu::showContextMenu(const QPoint &pos,
aInvestigateUser->setEnabled(anotherUser);
aPromoteToMod->setEnabled(anotherUser);
aDemoteFromMod->setEnabled(anotherUser);
- aPromoteToJudge->setEnabled(anotherUser);
- aDemoteFromJudge->setEnabled(anotherUser);
- aPromoteToDeveloper->setEnabled(anotherUser);
- aDemoteFromDeveloper->setEnabled(anotherUser);
QAction *actionClicked = menu->exec(pos);
if (actionClicked == nullptr) {
@@ -506,8 +489,6 @@ void UserContextMenu::showContextMenu(const QPoint &pos,
execAdjustMod(userName, actionClicked == aPromoteToMod);
} else if (actionClicked == aPromoteToJudge || actionClicked == aDemoteFromJudge) {
execAdjustJudge(userName, actionClicked == aPromoteToJudge);
- } else if (actionClicked == aPromoteToDeveloper || actionClicked == aDemoteFromDeveloper) {
- execAdjustDeveloper(userName, actionClicked == aPromoteToDeveloper);
} else if (actionClicked == aBanHistory) {
execBanHistory(userName);
} else if (actionClicked == aWarnUser) {
@@ -625,15 +606,7 @@ void UserContextMenu::execAddToIgnore(const QString &userName)
Command_AddToList cmd;
cmd.set_list("ignore");
cmd.set_user_name(userName.toStdString());
- PendingCommand *pend = client->prepareSessionCommand(cmd);
- connect(pend, &PendingCommand::finished, this,
- [this, userName](const Response &response, const CommandContainer &, const QVariant &) {
- if (response.response_code() == Response::RespOk) {
- QMessageBox::information(static_cast(parent()), tr("Ignore list"),
- tr("%1 has been added to your ignore list.").arg(userName));
- }
- });
- client->sendCommand(pend);
+ client->sendCommand(client->prepareSessionCommand(cmd));
}
void UserContextMenu::execRemoveFromIgnore(const QString &userName)
@@ -725,14 +698,4 @@ void UserContextMenu::execAdjustJudge(const QString &userName, bool shouldBeJudg
PendingCommand *pend = client->prepareAdminCommand(cmd);
connect(pend, &PendingCommand::finished, this, &UserContextMenu::adjustMod_processUserResponse);
client->sendCommand(pend);
-}
-
-void UserContextMenu::execAdjustDeveloper(const QString &userName, bool shouldBeDeveloper)
-{
- Command_AdjustMod cmd;
- cmd.set_user_name(userName.toStdString());
- cmd.set_should_be_developer(shouldBeDeveloper);
- PendingCommand *pend = client->prepareAdminCommand(cmd);
- connect(pend, &PendingCommand::finished, this, &UserContextMenu::adjustMod_processUserResponse);
- client->sendCommand(pend);
-}
+}
\ No newline at end of file
diff --git a/cockatrice/src/interface/widgets/server/user/user_context_menu.h b/cockatrice/src/interface/widgets/server/user/user_context_menu.h
index 6abbc057a..f1ce931f8 100644
--- a/cockatrice/src/interface/widgets/server/user/user_context_menu.h
+++ b/cockatrice/src/interface/widgets/server/user/user_context_menu.h
@@ -45,7 +45,6 @@ private:
QAction *aBan, *aBanHistory;
QAction *aPromoteToMod, *aDemoteFromMod;
QAction *aPromoteToJudge, *aDemoteFromJudge;
- QAction *aPromoteToDeveloper, *aDemoteFromDeveloper;
QAction *aWarnUser, *aWarnHistory;
QAction *aGetAdminNotes;
std::function()> gameInviteLinkProvider;
@@ -124,7 +123,6 @@ public:
void execInvestigateUser(const QString &userName);
void execAdjustMod(const QString &userName, bool shouldBeMod);
void execAdjustJudge(const QString &userName, bool shouldBeJudge);
- void execAdjustDeveloper(const QString &userName, bool shouldBeDeveloper);
private:
void execInvite(const QString &userName, const GameInviteOption &option);
diff --git a/cockatrice/src/interface/widgets/server/user/user_info_box.cpp b/cockatrice/src/interface/widgets/server/user/user_info_box.cpp
index 3d89cecf5..875bdfb05 100644
--- a/cockatrice/src/interface/widgets/server/user/user_info_box.cpp
+++ b/cockatrice/src/interface/widgets/server/user/user_info_box.cpp
@@ -122,8 +122,6 @@ void UserInfoBox::updateInfo(const ServerInfo_User &user)
QString userLevelText;
if (userLevel.testFlag(ServerInfo_User::IsAdmin)) {
userLevelText = tr("Administrator");
- } else if (userLevel.testFlag(ServerInfo_User::IsDeveloper)) {
- userLevelText = tr("Developer");
} else if (userLevel.testFlag(ServerInfo_User::IsModerator)) {
userLevelText = tr("Moderator");
} else if (userLevel.testFlag(ServerInfo_User::IsRegistered)) {
diff --git a/cockatrice/src/interface/widgets/server/user/user_info_popup.cpp b/cockatrice/src/interface/widgets/server/user/user_info_popup.cpp
index 8be76eea0..fb610e814 100644
--- a/cockatrice/src/interface/widgets/server/user/user_info_popup.cpp
+++ b/cockatrice/src/interface/widgets/server/user/user_info_popup.cpp
@@ -245,9 +245,6 @@ void UserInfoHeaderWidget::paintEvent(QPaintEvent *)
if (level.testFlag(ServerInfo_User::IsAdmin)) {
return QColor(245, 158, 11);
}
- if (level.testFlag(ServerInfo_User::IsDeveloper)) {
- return QColor(185, 28, 28);
- }
if (level.testFlag(ServerInfo_User::IsModerator)) {
return QColor(59, 130, 246);
}
@@ -303,8 +300,6 @@ void UserInfoHeaderWidget::paintEvent(QPaintEvent *)
} badge;
if (level.testFlag(ServerInfo_User::IsAdmin)) {
badge = {"ADMIN", QColor(245, 158, 11)};
- } else if (level.testFlag(ServerInfo_User::IsDeveloper)) {
- badge = {"DEV", QColor(185, 28, 28)};
} else if (level.testFlag(ServerInfo_User::IsModerator)) {
badge = {"MOD", QColor(59, 130, 246)};
} else if (level.testFlag(ServerInfo_User::IsJudge)) {
diff --git a/cockatrice/src/interface/widgets/server/user/user_list_painter.cpp b/cockatrice/src/interface/widgets/server/user/user_list_painter.cpp
index 34a3d6ae1..5c65b090d 100644
--- a/cockatrice/src/interface/widgets/server/user/user_list_painter.cpp
+++ b/cockatrice/src/interface/widgets/server/user/user_list_painter.cpp
@@ -49,8 +49,6 @@ QColor UserListPainter::getAccentColor(const UserLevelFlags &userLevel, bool onl
if (userLevel.testFlag(ServerInfo_User::IsAdmin)) {
accentColor = QColor(245, 158, 11);
- } else if (userLevel.testFlag(ServerInfo_User::IsDeveloper)) {
- accentColor = QColor(185, 28, 28);
} else if (userLevel.testFlag(ServerInfo_User::IsModerator)) {
accentColor = QColor(59, 130, 246);
} else if (userLevel.testFlag(ServerInfo_User::IsJudge)) {
@@ -301,8 +299,6 @@ QList UserListPainter::buildBadges(const UserLevelFlags
if (userLevel.testFlag(ServerInfo_User::IsAdmin)) {
badges << Badge{"ADMIN", QColor(245, 158, 11)};
- } else if (userLevel.testFlag(ServerInfo_User::IsDeveloper)) {
- badges << Badge{"DEV", QColor(185, 28, 28)};
} else if (userLevel.testFlag(ServerInfo_User::IsModerator)) {
badges << Badge{"MOD", QColor(59, 130, 246)};
} else if (userLevel.testFlag(ServerInfo_User::IsJudge)) {
@@ -389,9 +385,9 @@ void UserListPainter::paint(QPainter *painter,
const QString userName = QString::fromStdString(userInfo.name());
const QString privLevel = QString::fromStdString(userInfo.privlevel());
const QColor accentColor = getAccentColor(userLevel, online);
- const bool hasRole =
- userLevel.testFlag(ServerInfo_User::IsAdmin) || userLevel.testFlag(ServerInfo_User::IsDeveloper) ||
- userLevel.testFlag(ServerInfo_User::IsModerator) || userLevel.testFlag(ServerInfo_User::IsJudge);
+ const bool hasRole = userLevel.testFlag(ServerInfo_User::IsAdmin) ||
+ userLevel.testFlag(ServerInfo_User::IsModerator) ||
+ userLevel.testFlag(ServerInfo_User::IsJudge);
const QRectF cardRect = QRectF(rect).adjusted(3, 2, -3, -2);
const int cardRight = getCardRight(option, rect);
diff --git a/cockatrice/src/interface/widgets/server/user/user_list_widget.cpp b/cockatrice/src/interface/widgets/server/user/user_list_widget.cpp
index 1bb7c5288..a8c99c979 100644
--- a/cockatrice/src/interface/widgets/server/user/user_list_widget.cpp
+++ b/cockatrice/src/interface/widgets/server/user/user_list_widget.cpp
@@ -234,11 +234,9 @@ bool UserListTWI::operator<(const QTreeWidgetItem &other) const
const auto &lhsUserLevelFlags = UserLevelFlags(data(0, Qt::UserRole).toInt());
const auto &rhsUserLevelFlags = UserLevelFlags(other.data(0, Qt::UserRole).toInt());
- // Admins, Developers & Mods need no additional comparison checks, just to see if they're an admin, a developer
- // or a moderator
+ // Admins & Mods need no additional comparison checks, just to see if they're an admin or a moderator
static const QList userLevelWithNoOtherPrefOrder = {
- ServerInfo_User_UserLevelFlag_IsAdmin, ServerInfo_User_UserLevelFlag_IsDeveloper,
- ServerInfo_User_UserLevelFlag_IsModerator};
+ ServerInfo_User_UserLevelFlag_IsAdmin, ServerInfo_User_UserLevelFlag_IsModerator};
for (const auto &userLevelEntry : userLevelWithNoOtherPrefOrder) {
if (lhsUserLevelFlags.testFlag(userLevelEntry) &&
lhsUserLevelFlags.testFlag(userLevelEntry) == rhsUserLevelFlags.testFlag(userLevelEntry)) {
diff --git a/cockatrice/src/interface/widgets/settings_page/appearance_settings_page.cpp b/cockatrice/src/interface/widgets/settings_page/appearance_settings_page.cpp
index f161f0f19..c8494f095 100644
--- a/cockatrice/src/interface/widgets/settings_page/appearance_settings_page.cpp
+++ b/cockatrice/src/interface/widgets/settings_page/appearance_settings_page.cpp
@@ -59,8 +59,8 @@ AppearanceSettingsPage::AppearanceSettingsPage()
connect(&schemeCombo, &QComboBox::currentIndexChanged, this,
[this] { themeManager->setColorScheme(schemeCombo.currentData().toString()); });
- // Qt widget style; "System" lets the application decide
- styleCombo.addItem(tr("System"), QStringLiteral("System"));
+ // Qt widget style; "Default" lets the application decide
+ styleCombo.addItem(tr("Default"), QStringLiteral("Default"));
for (const QString &key : QStyleFactory::keys()) {
styleCombo.addItem(key, key);
}
@@ -132,10 +132,6 @@ AppearanceSettingsPage::AppearanceSettingsPage()
connect(&homeTabDisplayCardNameCheckBox, &QCheckBox::QT_STATE_CHANGED, &settings.appearance(),
&AppearanceSettings::setHomeTabDisplayCardName);
- homeTabBackgroundDimCheckBox.setChecked(settings.appearance().getHomeTabBackgroundDim());
- connect(&homeTabBackgroundDimCheckBox, &QCheckBox::QT_STATE_CHANGED, &settings.appearance(),
- &AppearanceSettings::setHomeTabBackgroundDim);
-
for (const auto &entry : HomeTabButtonColor::all()) {
homeTabButtonColorSourceBox.addItem(QObject::tr(entry.trKey));
}
@@ -154,7 +150,6 @@ AppearanceSettingsPage::AppearanceSettingsPage()
homeTabGrid->addWidget(&homeTabDisplayCardNameCheckBox, 2, 0, 1, 2);
homeTabGrid->addWidget(&homeTabButtonColorSourceLabel, 3, 0);
homeTabGrid->addWidget(&homeTabButtonColorSourceBox, 3, 1);
- homeTabGrid->addWidget(&homeTabBackgroundDimCheckBox, 4, 0, 1, 2);
homeTabGroupBox = new QGroupBox;
homeTabGroupBox->setLayout(homeTabGrid);
@@ -513,12 +508,9 @@ void AppearanceSettingsPage::retranslateUi()
homeTabBackgroundShuffleFrequencyLabel.setText(tr("Home tab background shuffle frequency:"));
homeTabBackgroundShuffleFrequencySpinBox.setSpecialValueText(tr("Disabled"));
homeTabDisplayCardNameCheckBox.setText(tr("Display card name of background in bottom right"));
- homeTabBackgroundDimCheckBox.setText(tr("Dim the home tab background"));
- homeTabBackgroundDimCheckBox.setToolTip(
- tr("Draw a translucent overlay over the home tab background so buttons and text stand out"));
homeTabButtonColorSourceLabel.setText(tr("Home tab button color:"));
homeTabButtonColorSourceBox.setToolTip(
- tr("Use the theme's identity accent colors, or extract colors from the background image"));
+ tr("Automatic: extract from background if present, otherwise use theme default"));
playmatGroupBox->setTitle(tr("Playmat settings"));
playmatVisibilityLabel.setText(tr("Playmat visibility:"));
diff --git a/cockatrice/src/interface/widgets/settings_page/appearance_settings_page.h b/cockatrice/src/interface/widgets/settings_page/appearance_settings_page.h
index bec4cd72f..8db71ff8f 100644
--- a/cockatrice/src/interface/widgets/settings_page/appearance_settings_page.h
+++ b/cockatrice/src/interface/widgets/settings_page/appearance_settings_page.h
@@ -41,7 +41,6 @@ private:
QLabel homeTabBackgroundShuffleFrequencyLabel;
QSpinBox homeTabBackgroundShuffleFrequencySpinBox;
QCheckBox homeTabDisplayCardNameCheckBox;
- QCheckBox homeTabBackgroundDimCheckBox;
QLabel homeTabButtonColorSourceLabel;
QComboBox homeTabButtonColorSourceBox;
diff --git a/cockatrice/src/interface/widgets/settings_page/deck_editor_settings_page.cpp b/cockatrice/src/interface/widgets/settings_page/deck_editor_settings_page.cpp
index f3eac05b8..f425afe60 100644
--- a/cockatrice/src/interface/widgets/settings_page/deck_editor_settings_page.cpp
+++ b/cockatrice/src/interface/widgets/settings_page/deck_editor_settings_page.cpp
@@ -1,7 +1,6 @@
#include "deck_editor_settings_page.h"
#include "../../../client/settings/cache_settings.h"
-#include "../../pixel_map_generator.h"
#include "update/card_spoiler/spoiler_background_updater.h"
#include
@@ -54,15 +53,15 @@ DeckEditorSettingsPage::DeckEditorSettingsPage()
urlList->addItems(SettingsCache::instance().downloads().getAllURLs());
aAdd = new QAction(this);
- aAdd->setIcon(themePixmap(QStringLiteral("icons/increment")));
+ aAdd->setIcon(QPixmap("theme:icons/increment"));
connect(aAdd, &QAction::triggered, this, &DeckEditorSettingsPage::actAddURL);
aEdit = new QAction(this);
- aEdit->setIcon(themePixmap(QStringLiteral("icons/pencil")));
+ aEdit->setIcon(QPixmap("theme:icons/pencil"));
connect(aEdit, &QAction::triggered, this, &DeckEditorSettingsPage::actEditURL);
aRemove = new QAction(this);
- aRemove->setIcon(themePixmap(QStringLiteral("icons/decrement")));
+ aRemove->setIcon(QPixmap("theme:icons/decrement"));
connect(aRemove, &QAction::triggered, this, &DeckEditorSettingsPage::actRemoveURL);
auto *urlToolBar = new QToolBar;
diff --git a/cockatrice/src/interface/widgets/settings_page/general_settings_page.cpp b/cockatrice/src/interface/widgets/settings_page/general_settings_page.cpp
index 36436f8a3..62b06fb60 100644
--- a/cockatrice/src/interface/widgets/settings_page/general_settings_page.cpp
+++ b/cockatrice/src/interface/widgets/settings_page/general_settings_page.cpp
@@ -1,21 +1,15 @@
#include "general_settings_page.h"
#include "../../../client/settings/cache_settings.h"
-#include "../interface/card_picture_loader/card_picture_loader.h"
#include "../main.h"
#include "../server/user/user_info_connection.h"
#include "update/client/release_channel.h"
#include
-#include
#include