diff --git a/CMakeLists.txt b/CMakeLists.txt index 35eb8111b..4006ead2f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,8 +5,8 @@ # This file sets all the variables shared between the projects # like the installation path, compilation flags etc.. -# 3.16 required for Qt6 and target_precompile_headers() -cmake_minimum_required(VERSION 3.16) +# cmake 3.16 is required if using qt6 +cmake_minimum_required(VERSION 3.10) # Use compiler cache (ccache) option(USE_CCACHE "Cache the build results with ccache" OFF) @@ -184,9 +184,6 @@ elseif(CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${FLAG}") endif() endforeach() - - # Reduce compiler I/O by using pipes between stages instead of temp files - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pipe") else() # other: osx/llvm, bsd/llvm set(CMAKE_CXX_FLAGS_RELEASE "-O2") @@ -195,9 +192,6 @@ else() else() set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -Wall -Wextra") endif() - - # Reduce compiler I/O by using pipes between stages instead of temp files - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pipe") endif() # GNU systems need to define the Mersenne exponent for the RNG to compile w/o warning diff --git a/cockatrice/src/game_graphics/game_scene.cpp b/cockatrice/src/game_graphics/game_scene.cpp index 457f1b3f7..87af4c73c 100644 --- a/cockatrice/src/game_graphics/game_scene.cpp +++ b/cockatrice/src/game_graphics/game_scene.cpp @@ -44,16 +44,11 @@ GameScene::GameScene(PhasesToolbar *_phasesToolbar, QObject *parent) GameScene::~GameScene() { - // Sever all destroyed->removeAnimatedItem connections before the members below - // are destroyed: the base QGraphicsScene destructor destroys the remaining items, - // and their destroyed() signals must not reach slots that reference members that - // no longer exist. The connection handle overload is used because the string-based - // disconnect(nullptr, nullptr, this, nullptr) is invalid (the sender must never be - // nullptr) and would otherwise fail to sever these pointer-to-member connections. - for (auto it = animationItemConnections.constBegin(); it != animationItemConnections.constEnd(); ++it) { - QObject::disconnect(*it); - } - animationItemConnections.clear(); + // Sever all incoming connections (animated item destroy-tracking) before the + // members below are destroyed: the base QGraphicsScene destructor destroys the + // remaining items, and their destroyed() signals must not reach slots that + // reference members that no longer exist. + QObject::disconnect(nullptr, nullptr, this, nullptr); delete animationTimer; animationTimer = nullptr; @@ -782,15 +777,8 @@ void GameScene::registerAnimationItem(IAnimatedItem *item) if (!object) { return; } - // Guard against duplicate connections using the connection map, not - // animatedItems: the animation timer removes entries from animatedItems when an - // animation completes, but the destroyed->removeAnimatedItem connection must - // persist until the object is destroyed. Relying on animatedItems here would let - // a re-registered item (e.g. a life counter that flashes repeatedly) accumulate - // duplicate destroyed connections, the older ones of which would survive teardown. - if (!animationItemConnections.contains(object)) { - animationItemConnections.insert(object, - connect(object, &QObject::destroyed, this, &GameScene::removeAnimatedItem)); + if (!animatedItems.contains(object)) { + connect(object, &QObject::destroyed, this, &GameScene::removeAnimatedItem); } animatedItems.insert(object, item); if (animationTimer && !animationTimer->isActive()) { @@ -809,7 +797,6 @@ void GameScene::unregisterAnimationItem(IAnimatedItem *item) void GameScene::removeAnimatedItem(QObject *item) { animatedItems.remove(item); - animationItemConnections.remove(item); if (animationTimer && animatedItems.isEmpty()) { animationTimer->stop(); } diff --git a/cockatrice/src/game_graphics/game_scene.h b/cockatrice/src/game_graphics/game_scene.h index 859d7a6eb..c12696189 100644 --- a/cockatrice/src/game_graphics/game_scene.h +++ b/cockatrice/src/game_graphics/game_scene.h @@ -54,11 +54,9 @@ private: QPointer hoveredCard; ///< Currently hovered card QBasicTimer *animationTimer; ///< Timer for scene animations QHash animatedItems; ///< Items currently animating - QHash - animationItemConnections; ///< destroyed->removeAnimatedItem handles per animated item - int playerRotation; ///< Rotation offset for player layout - bool rearranging = false; ///< Guard against re-entrant rearrange - bool needsReArrange = false; ///< Pending rearrange requested during a pass + int playerRotation; ///< Rotation offset for player layout + bool rearranging = false; ///< Guard against re-entrant rearrange + bool needsReArrange = false; ///< Pending rearrange requested during a pass /** * @brief Updates which card is currently hovered based on scene coordinates. diff --git a/cockatrice/src/game_graphics/zones/hand_zone.cpp b/cockatrice/src/game_graphics/zones/hand_zone.cpp index 1a8f7a910..b52a4955a 100644 --- a/cockatrice/src/game_graphics/zones/hand_zone.cpp +++ b/cockatrice/src/game_graphics/zones/hand_zone.cpp @@ -41,8 +41,7 @@ void HandZone::handleDropEvent(const QList &dragItems, } } } else { - bool sameZone = startZone == getLogic(); - x = calcDropIndexFromY(dropPoint.y(), !sameZone); + x = calcDropIndexFromY(dropPoint.y()); } Command_MoveCard cmd; diff --git a/cockatrice/src/game_graphics/zones/select_zone.cpp b/cockatrice/src/game_graphics/zones/select_zone.cpp index 470c70fcf..c58c41b92 100644 --- a/cockatrice/src/game_graphics/zones/select_zone.cpp +++ b/cockatrice/src/game_graphics/zones/select_zone.cpp @@ -83,7 +83,7 @@ SelectZone::StackLayoutParams SelectZone::buildStackParams(qreal minOffset) cons return {cardCount, boundingRect().height(), cardHeight, offset, minOffset}; } -int SelectZone::calcDropIndexFromY(qreal dropY, bool allowCountExpand, qreal minOffset) const +int SelectZone::calcDropIndexFromY(qreal dropY, qreal minOffset) const { const auto &cards = getLogic()->getCards(); if (cards.isEmpty()) { @@ -94,8 +94,7 @@ int SelectZone::calcDropIndexFromY(qreal dropY, bool allowCountExpand, qreal min if (effectiveOffset <= 0.0) { return 0; } - int max = allowCountExpand ? params.cardCount : params.cardCount - 1; - return qBound(0, qRound((dropY - start) / effectiveOffset), max); + return qBound(0, qRound((dropY - start) / effectiveOffset), params.cardCount - 1); } void SelectZone::restoreStaleEscapedCards() diff --git a/cockatrice/src/game_graphics/zones/select_zone.h b/cockatrice/src/game_graphics/zones/select_zone.h index b5d3ca37a..7408f29b6 100644 --- a/cockatrice/src/game_graphics/zones/select_zone.h +++ b/cockatrice/src/game_graphics/zones/select_zone.h @@ -104,12 +104,8 @@ protected: /** * @brief Computes the card index at a given y-coordinate within the zone's vertical layout. * Returns 0 if the zone has no cards or the offset is zero. - * - * @param dropY The y-coordinate that the card was dropped at - * @param allowCountExpand If false, clamps the index at the number of cards minus 1 - * @param minOffset Minimum offset to preserve */ - int calcDropIndexFromY(qreal dropY, bool allowCountExpand, qreal minOffset = 0.0) const; + int calcDropIndexFromY(qreal dropY, qreal minOffset = 0.0) const; /** * @brief Positions cards vertically with alternating left/right x-offsets. diff --git a/cockatrice/src/game_graphics/zones/stack_zone.cpp b/cockatrice/src/game_graphics/zones/stack_zone.cpp index ff62097c7..e9b14f13d 100644 --- a/cockatrice/src/game_graphics/zones/stack_zone.cpp +++ b/cockatrice/src/game_graphics/zones/stack_zone.cpp @@ -57,14 +57,18 @@ void StackZone::handleDropEvent(const QList &dragItems, return; } - bool sameZone = startZone == getLogic(); - int index = calcDropIndexFromY(dropPoint.y(), !sameZone, MIN_CARD_VISIBLE); - if (sameZone) { + const auto &cards = getLogic()->getCards(); + int index; + if (startZone == getLogic()) { + // Reordering within the zone: use drop position + index = calcDropIndexFromY(dropPoint.y(), MIN_CARD_VISIBLE); // Same-zone no-op: don't move a card onto itself - const auto &cards = getLogic()->getCards(); if (!cards.isEmpty() && cards.at(index)->getId() == dragItems.at(0)->getId()) { return; } + } else { + // Coming from another zone: append at end (top of stack, rendered on top) + index = static_cast(cards.size()); } Command_MoveCard cmd; 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 c8494f095..881c54167 100644 --- a/cockatrice/src/interface/widgets/settings_page/appearance_settings_page.cpp +++ b/cockatrice/src/interface/widgets/settings_page/appearance_settings_page.cpp @@ -154,48 +154,6 @@ AppearanceSettingsPage::AppearanceSettingsPage() homeTabGroupBox = new QGroupBox; homeTabGroupBox->setLayout(homeTabGrid); - // Playmat settings - playmatVisibilityCombo.addItem(tr("Show all playmats"), PlaymatVisibilityAll); - playmatVisibilityCombo.addItem(tr("Show own playmat only"), PlaymatVisibilityOwnOnly); - playmatVisibilityCombo.addItem(tr("Don't use playmats"), PlaymatVisibilityNone); - int visIdx = playmatVisibilityCombo.findData(settings.userInterface().getPlaymatVisibility()); - if (visIdx >= 0) { - playmatVisibilityCombo.setCurrentIndex(visIdx); - } - connect(&playmatVisibilityCombo, qOverload(&QComboBox::currentIndexChanged), this, [this](int index) { - SettingsCache::instance().userInterface().setPlaymatVisibility(playmatVisibilityCombo.itemData(index).toInt()); - }); - playmatVisibilityLabel.setBuddy(&playmatVisibilityCombo); - - // Playmat mode: Override / Fallback / Deck-only - playmatModeCombo.addItem(tr("Override deck playmat"), PlaymatModeOverrideDeck); - playmatModeCombo.addItem(tr("Fallback if deck has none"), PlaymatModeFallback); - playmatModeCombo.addItem(tr("Deck only, ignore collection"), PlaymatModeDeckOnly); - int modeIdx = playmatModeCombo.findData(settings.userInterface().getPlaymatMode()); - if (modeIdx >= 0) { - playmatModeCombo.setCurrentIndex(modeIdx); - } - connect(&playmatModeCombo, qOverload(&QComboBox::currentIndexChanged), this, [this](int index) { - SettingsCache::instance().userInterface().setPlaymatMode(playmatModeCombo.itemData(index).toInt()); - }); - playmatModeLabel.setBuddy(&playmatModeCombo); - - // User-level playmat settings: fallback collection. - connect(&playmatDefaultEditButton, &QPushButton::clicked, this, - &AppearanceSettingsPage::openPlaymatCollectionDialog); - - auto *playmatGrid = new QGridLayout; - playmatGrid->addWidget(&playmatVisibilityLabel, 0, 0, 1, 1); - playmatGrid->addWidget(&playmatVisibilityCombo, 0, 1, 1, 1); - playmatGrid->addWidget(&playmatModeLabel, 1, 0, 1, 1); - playmatGrid->addWidget(&playmatModeCombo, 1, 1, 1, 1); - playmatGrid->addWidget(&playmatDefaultLabel, 2, 0, 1, 1); - playmatGrid->addWidget(&playmatDefaultEditButton, 2, 1, 1, 1); - - playmatGroupBox = new QGroupBox; - playmatGroupBox->setLayout(playmatGrid); - - // Styling settings styleUserListCheckBox.setChecked(settings.appearance().getStyleUserList()); connect(&styleUserListCheckBox, &QCheckBox::QT_STATE_CHANGED, &settings.appearance(), &AppearanceSettings::setStyleUserList); @@ -301,6 +259,7 @@ AppearanceSettingsPage::AppearanceSettingsPage() cardLayoutGroupBox->setLayout(cardLayoutGrid); // Card counter colors + auto *cardCounterColorsLayout = new QGridLayout; cardCounterColorsLayout->setColumnStretch(1, 1); cardCounterColorsLayout->setColumnStretch(3, 1); @@ -380,6 +339,47 @@ AppearanceSettingsPage::AppearanceSettingsPage() tableGroupBox = new QGroupBox; tableGroupBox->setLayout(tableGrid); + // Playmat settings + playmatVisibilityCombo.addItem(tr("Show all playmats"), PlaymatVisibilityAll); + playmatVisibilityCombo.addItem(tr("Show own playmat only"), PlaymatVisibilityOwnOnly); + playmatVisibilityCombo.addItem(tr("Don't use playmats"), PlaymatVisibilityNone); + int visIdx = playmatVisibilityCombo.findData(settings.userInterface().getPlaymatVisibility()); + if (visIdx >= 0) { + playmatVisibilityCombo.setCurrentIndex(visIdx); + } + connect(&playmatVisibilityCombo, qOverload(&QComboBox::currentIndexChanged), this, [this](int index) { + SettingsCache::instance().userInterface().setPlaymatVisibility(playmatVisibilityCombo.itemData(index).toInt()); + }); + playmatVisibilityLabel.setBuddy(&playmatVisibilityCombo); + + // Playmat mode: Override / Fallback / Deck-only + playmatModeCombo.addItem(tr("Override deck playmat"), PlaymatModeOverrideDeck); + playmatModeCombo.addItem(tr("Fallback if deck has none"), PlaymatModeFallback); + playmatModeCombo.addItem(tr("Deck only, ignore collection"), PlaymatModeDeckOnly); + int modeIdx = playmatModeCombo.findData(settings.userInterface().getPlaymatMode()); + if (modeIdx >= 0) { + playmatModeCombo.setCurrentIndex(modeIdx); + } + connect(&playmatModeCombo, qOverload(&QComboBox::currentIndexChanged), this, [this](int index) { + SettingsCache::instance().userInterface().setPlaymatMode(playmatModeCombo.itemData(index).toInt()); + }); + playmatModeLabel.setBuddy(&playmatModeCombo); + + // User-level playmat settings: fallback collection. + connect(&playmatDefaultEditButton, &QPushButton::clicked, this, + &AppearanceSettingsPage::openPlaymatCollectionDialog); + + auto *playmatGrid = new QGridLayout; + playmatGrid->addWidget(&playmatVisibilityLabel, 0, 0, 1, 1); + playmatGrid->addWidget(&playmatVisibilityCombo, 0, 1, 1, 1); + playmatGrid->addWidget(&playmatModeLabel, 1, 0, 1, 1); + playmatGrid->addWidget(&playmatModeCombo, 1, 1, 1, 1); + playmatGrid->addWidget(&playmatDefaultLabel, 2, 0, 1, 1); + playmatGrid->addWidget(&playmatDefaultEditButton, 2, 1, 1, 1); + + playmatGroupBox = new QGroupBox; + playmatGroupBox->setLayout(playmatGrid); + // putting it all together auto *mainLayout = new QVBoxLayout; mainLayout->addWidget(themeGroupBox); @@ -512,12 +512,6 @@ void AppearanceSettingsPage::retranslateUi() homeTabButtonColorSourceBox.setToolTip( tr("Automatic: extract from background if present, otherwise use theme default")); - playmatGroupBox->setTitle(tr("Playmat settings")); - playmatVisibilityLabel.setText(tr("Playmat visibility:")); - playmatModeLabel.setText(tr("Default collection behavior:")); - playmatDefaultLabel.setText(tr("Default playmat collection:")); - playmatDefaultEditButton.setText(tr("Edit...")); - stylingGroupBox->setTitle(tr("Styling settings")); styleUserListCheckBox.setText(tr("Style user list")); @@ -560,4 +554,9 @@ void AppearanceSettingsPage::retranslateUi() tableGroupBox->setTitle(tr("Table grid layout")); invertVerticalCoordinateCheckBox.setText(tr("Invert vertical coordinate")); minPlayersForMultiColumnLayoutLabel.setText(tr("Minimum player count for multi-column layout:")); + playmatGroupBox->setTitle(tr("Playmat settings")); + playmatVisibilityLabel.setText(tr("Playmat visibility:")); + playmatModeLabel.setText(tr("Default collection behavior:")); + playmatDefaultLabel.setText(tr("Default playmat collection:")); + playmatDefaultEditButton.setText(tr("Edit...")); } 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 8db71ff8f..6b0369694 100644 --- a/cockatrice/src/interface/widgets/settings_page/appearance_settings_page.h +++ b/cockatrice/src/interface/widgets/settings_page/appearance_settings_page.h @@ -44,55 +44,46 @@ private: QLabel homeTabButtonColorSourceLabel; QComboBox homeTabButtonColorSourceBox; - QLabel playmatVisibilityLabel; - QComboBox playmatVisibilityCombo; - QLabel playmatModeLabel; - QComboBox playmatModeCombo; - QLabel playmatDefaultLabel; - QPushButton playmatDefaultEditButton; - QCheckBox styleUserListCheckBox; - QCheckBox showShortcutsCheckBox; QCheckBox showGameSelectorFilterToolbarCheckBox; - + QLabel minPlayersForMultiColumnLayoutLabel; + QLabel maxFontSizeForCardsLabel; QCheckBox overrideAllCardArtWithPersonalPreferenceCheckBox; QCheckBox bumpSetsWithCardsInDeckToTopCheckBox; - QCheckBox displayCardNamesCheckBox; QCheckBox autoRotateSidewaysLayoutCardsCheckBox; QCheckBox cardScalingCheckBox; QCheckBox roundCardCornersCheckBox; - QLabel maxFontSizeForCardsLabel; - QSpinBox maxFontSizeForCardsEdit; - QLabel verticalCardOverlapPercentLabel; QSpinBox verticalCardOverlapPercentBox; QLabel cardViewInitialRowsMaxLabel; QSpinBox cardViewInitialRowsMaxBox; QLabel cardViewExpandedRowsMaxLabel; QSpinBox cardViewExpandedRowsMaxBox; - - QList cardCounterNames; - QCheckBox horizontalHandCheckBox; QCheckBox leftJustifiedHandCheckBox; - QCheckBox invertVerticalCoordinateCheckBox; - QLabel minPlayersForMultiColumnLayoutLabel; - QSpinBox minPlayersForMultiColumnLayoutEdit; - + QLabel playmatVisibilityLabel; + QComboBox playmatVisibilityCombo; + QLabel playmatModeLabel; + QComboBox playmatModeCombo; + QLabel playmatDefaultLabel; + QPushButton playmatDefaultEditButton; QGroupBox *themeGroupBox; QGroupBox *homeTabGroupBox; - QGroupBox *playmatGroupBox; QGroupBox *stylingGroupBox; QGroupBox *menuGroupBox; QGroupBox *printingsGroupBox; QGroupBox *cardsGroupBox; QGroupBox *cardLayoutGroupBox; - QGroupBox *cardCountersGroupBox; QGroupBox *handGroupBox; + QGroupBox *playmatGroupBox; QGroupBox *tableGroupBox; + QGroupBox *cardCountersGroupBox; + QList cardCounterNames; + QSpinBox minPlayersForMultiColumnLayoutEdit; + QSpinBox maxFontSizeForCardsEdit; public: AppearanceSettingsPage(); 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 62b06fb60..a293660f9 100644 --- a/cockatrice/src/interface/widgets/settings_page/general_settings_page.cpp +++ b/cockatrice/src/interface/widgets/settings_page/general_settings_page.cpp @@ -425,28 +425,29 @@ void GeneralSettingsPage::updateStartupServerControlsVisibility() void GeneralSettingsPage::retranslateUi() { - const auto &settings = SettingsCache::instance(); - languageGroupBox->setTitle(tr("Language settings")); languageLabel.setText(tr("Language:")); - advertiseTranslationPageLabel.setText( - QString("%2").arg(WIKI_TRANSLATION_FAQ).arg(tr("How to help with translations"))); versionGroupBox->setTitle(tr("Version settings")); + cardDatabaseGroupBox->setTitle(tr("Card database")); + startupGroupBox->setTitle(tr("Startup settings")); + + if (SettingsCache::instance().getIsPortableBuild()) { + pathsGroupBox->setTitle(tr("Paths (editing disabled in portable mode)")); + } else { + pathsGroupBox->setTitle(tr("Paths")); + } + advertiseTranslationPageLabel.setText( + QString("%2").arg(WIKI_TRANSLATION_FAQ).arg(tr("How to help with translations"))); + deckPathLabel.setText(tr("Decks directory:")); + filtersPathLabel.setText(tr("Filters directory:")); + replaysPathLabel.setText(tr("Replays directory:")); + picsPathLabel.setText(tr("Pictures directory:")); + cardDatabasePathLabel.setText(tr("Card database:")); + customCardDatabasePathLabel.setText(tr("Custom database directory:")); + tokenDatabasePathLabel.setText(tr("Token database:")); updateReleaseChannelLabel.setText(tr("Update channel")); startupUpdateCheckCheckBox.setText(tr("Check for client updates on startup")); - updateNotificationCheckBox.setText(tr("Notify if a feature supported by the server is missing in my client")); - newVersionOracleCheckBox.setText(tr("Automatically run Oracle when running a new version of Cockatrice")); - - // We can't change the strings after they're put into the QComboBox, so this is our workaround - int oldIndex = updateReleaseChannelBox.currentIndex(); - updateReleaseChannelBox.clear(); - for (ReleaseChannel *chan : settings.getUpdateReleaseChannels()) { - updateReleaseChannelBox.addItem(tr(chan->getName().toUtf8())); - } - updateReleaseChannelBox.setCurrentIndex(oldIndex); - - cardDatabaseGroupBox->setTitle(tr("Card database")); startupCardUpdateCheckBehaviorLabel.setText(tr("Check for card database updates on startup")); startupCardUpdateCheckBehaviorSelector.setItemText(startupCardUpdateCheckBehaviorIndexNone, tr("Don't check")); startupCardUpdateCheckBehaviorSelector.setItemText(startupCardUpdateCheckBehaviorIndexPrompt, @@ -455,13 +456,8 @@ void GeneralSettingsPage::retranslateUi() tr("Always update in the background")); cardUpdateCheckIntervalLabel.setText(tr("Check for card database updates every")); cardUpdateCheckIntervalSpinBox.setSuffix(tr(" days")); - - QDate lastCheckDate = settings.updates().getLastCardUpdateCheck(); - int daysAgo = lastCheckDate.daysTo(QDate::currentDate()); - lastCardUpdateCheckDateLabel.setText( - tr("Last update check on %1 (%2 days ago)").arg(lastCheckDate.toString()).arg(daysAgo)); - - startupGroupBox->setTitle(tr("Startup settings")); + updateNotificationCheckBox.setText(tr("Notify if a feature supported by the server is missing in my client")); + newVersionOracleCheckBox.setText(tr("Automatically run Oracle when running a new version of Cockatrice")); showTipsOnStartup.setText(tr("Show tips on startup")); startupTabLabel.setText(tr("Startup tab:")); startupTabSelector.setItemText(StartupTab::StartupTabHome, tr("Home")); @@ -477,18 +473,21 @@ void GeneralSettingsPage::retranslateUi() startupServerLabel.setText(tr("Server:")); startupRoomLabel.setText(tr("Room:")); startupRoomNameEdit->setPlaceholderText(tr("Room name")); - - if (settings.getIsPortableBuild()) { - pathsGroupBox->setTitle(tr("Paths (editing disabled in portable mode)")); - } else { - pathsGroupBox->setTitle(tr("Paths")); - } - deckPathLabel.setText(tr("Decks directory:")); - filtersPathLabel.setText(tr("Filters directory:")); - replaysPathLabel.setText(tr("Replays directory:")); - picsPathLabel.setText(tr("Pictures directory:")); - cardDatabasePathLabel.setText(tr("Card database:")); - customCardDatabasePathLabel.setText(tr("Custom database directory:")); - tokenDatabasePathLabel.setText(tr("Token database:")); resetAllPathsButton->setText(tr("Reset all paths")); -} + + const auto &settings = SettingsCache::instance(); + + QDate lastCheckDate = settings.updates().getLastCardUpdateCheck(); + int daysAgo = lastCheckDate.daysTo(QDate::currentDate()); + + lastCardUpdateCheckDateLabel.setText( + tr("Last update check on %1 (%2 days ago)").arg(lastCheckDate.toString()).arg(daysAgo)); + + // We can't change the strings after they're put into the QComboBox, so this is our workaround + int oldIndex = updateReleaseChannelBox.currentIndex(); + updateReleaseChannelBox.clear(); + for (ReleaseChannel *chan : settings.getUpdateReleaseChannels()) { + updateReleaseChannelBox.addItem(tr(chan->getName().toUtf8())); + } + updateReleaseChannelBox.setCurrentIndex(oldIndex); +} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/settings_page/general_settings_page.h b/cockatrice/src/interface/widgets/settings_page/general_settings_page.h index e0c1a47bf..8dd7e8798 100644 --- a/cockatrice/src/interface/widgets/settings_page/general_settings_page.h +++ b/cockatrice/src/interface/widgets/settings_page/general_settings_page.h @@ -42,37 +42,6 @@ private: QGroupBox *startupGroupBox; QGroupBox *pathsGroupBox; - QLabel languageLabel; - QComboBox languageBox; - QLabel advertiseTranslationPageLabel; - - QLabel updateReleaseChannelLabel; - QComboBox updateReleaseChannelBox; - QCheckBox startupUpdateCheckCheckBox; - QCheckBox updateNotificationCheckBox; - QCheckBox newVersionOracleCheckBox; - - QLabel startupCardUpdateCheckBehaviorLabel; - QComboBox startupCardUpdateCheckBehaviorSelector; - QLabel cardUpdateCheckIntervalLabel; - QSpinBox cardUpdateCheckIntervalSpinBox; - QLabel lastCardUpdateCheckDateLabel; - - QCheckBox showTipsOnStartup; - QLabel startupTabLabel; - QComboBox startupTabSelector; - QLabel startupServerLabel; - QComboBox startupServerSelector; - QLabel startupRoomLabel; - QLineEdit *startupRoomNameEdit; - - QLabel deckPathLabel; - QLabel filtersPathLabel; - QLabel replaysPathLabel; - QLabel picsPathLabel; - QLabel cardDatabasePathLabel; - QLabel customCardDatabasePathLabel; - QLabel tokenDatabasePathLabel; QLineEdit *deckPathEdit; QLineEdit *filtersPathEdit; QLineEdit *replaysPathEdit; @@ -82,6 +51,33 @@ private: QLineEdit *tokenDatabasePathEdit; QPushButton *resetAllPathsButton; QLabel *allPathsResetLabel; + QComboBox languageBox; + QCheckBox startupUpdateCheckCheckBox; + QLabel startupCardUpdateCheckBehaviorLabel; + QComboBox startupCardUpdateCheckBehaviorSelector; + QLabel cardUpdateCheckIntervalLabel; + QSpinBox cardUpdateCheckIntervalSpinBox; + QLabel lastCardUpdateCheckDateLabel; + QCheckBox updateNotificationCheckBox; + QCheckBox newVersionOracleCheckBox; + QComboBox updateReleaseChannelBox; + QLabel languageLabel; + QLabel deckPathLabel; + QLabel filtersPathLabel; + QLabel replaysPathLabel; + QLabel picsPathLabel; + QLabel cardDatabasePathLabel; + QLabel customCardDatabasePathLabel; + QLabel tokenDatabasePathLabel; + QLabel updateReleaseChannelLabel; + QLabel advertiseTranslationPageLabel; + QCheckBox showTipsOnStartup; + QLabel startupTabLabel; + QComboBox startupTabSelector; + QLabel startupServerLabel; + QComboBox startupServerSelector; + QLabel startupRoomLabel; + QLineEdit *startupRoomNameEdit; }; #endif // COCKATRICE_GENERAL_SETTINGS_PAGE_H diff --git a/cockatrice/src/interface/widgets/settings_page/user_interface_settings_page.cpp b/cockatrice/src/interface/widgets/settings_page/user_interface_settings_page.cpp index 2c6e062da..182e75aac 100644 --- a/cockatrice/src/interface/widgets/settings_page/user_interface_settings_page.cpp +++ b/cockatrice/src/interface/widgets/settings_page/user_interface_settings_page.cpp @@ -20,7 +20,26 @@ enum visualDeckStoragePromptForConversionIndex UserInterfaceSettingsPage::UserInterfaceSettingsPage() { - // general settings + // general settings and notification settings + notificationsEnabledCheckBox.setChecked(SettingsCache::instance().userInterface().getNotificationsEnabled()); + connect(¬ificationsEnabledCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance().userInterface(), + &InterfaceSettings::setNotificationsEnabled); + connect(¬ificationsEnabledCheckBox, &QCheckBox::QT_STATE_CHANGED, this, + &UserInterfaceSettingsPage::setNotificationEnabled); + + specNotificationsEnabledCheckBox.setChecked( + SettingsCache::instance().userInterface().getSpectatorNotificationsEnabled()); + specNotificationsEnabledCheckBox.setEnabled(SettingsCache::instance().userInterface().getNotificationsEnabled()); + connect(&specNotificationsEnabledCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance().userInterface(), + &InterfaceSettings::setSpectatorNotificationsEnabled); + + buddyConnectNotificationsEnabledCheckBox.setChecked( + SettingsCache::instance().userInterface().getBuddyConnectNotificationsEnabled()); + buddyConnectNotificationsEnabledCheckBox.setEnabled( + SettingsCache::instance().userInterface().getNotificationsEnabled()); + connect(&buddyConnectNotificationsEnabledCheckBox, &QCheckBox::QT_STATE_CHANGED, + &SettingsCache::instance().userInterface(), &InterfaceSettings::setBuddyConnectNotificationsEnabled); + doubleClickToPlayCheckBox.setChecked(SettingsCache::instance().userInterface().getDoubleClickToPlay()); connect(&doubleClickToPlayCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance().userInterface(), &InterfaceSettings::setDoubleClickToPlay); @@ -84,26 +103,6 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage() generalGroupBox = new QGroupBox; generalGroupBox->setLayout(generalGrid); - // notification settings - notificationsEnabledCheckBox.setChecked(SettingsCache::instance().userInterface().getNotificationsEnabled()); - connect(¬ificationsEnabledCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance().userInterface(), - &InterfaceSettings::setNotificationsEnabled); - connect(¬ificationsEnabledCheckBox, &QCheckBox::QT_STATE_CHANGED, this, - &UserInterfaceSettingsPage::setNotificationEnabled); - - specNotificationsEnabledCheckBox.setChecked( - SettingsCache::instance().userInterface().getSpectatorNotificationsEnabled()); - specNotificationsEnabledCheckBox.setEnabled(SettingsCache::instance().userInterface().getNotificationsEnabled()); - connect(&specNotificationsEnabledCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance().userInterface(), - &InterfaceSettings::setSpectatorNotificationsEnabled); - - buddyConnectNotificationsEnabledCheckBox.setChecked( - SettingsCache::instance().userInterface().getBuddyConnectNotificationsEnabled()); - buddyConnectNotificationsEnabledCheckBox.setEnabled( - SettingsCache::instance().userInterface().getNotificationsEnabled()); - connect(&buddyConnectNotificationsEnabledCheckBox, &QCheckBox::QT_STATE_CHANGED, - &SettingsCache::instance().userInterface(), &InterfaceSettings::setBuddyConnectNotificationsEnabled); - auto *notificationsGrid = new QGridLayout; notificationsGrid->addWidget(¬ificationsEnabledCheckBox, 0, 0); notificationsGrid->addWidget(&specNotificationsEnabledCheckBox, 1, 0); @@ -356,7 +355,6 @@ void UserInterfaceSettingsPage::retranslateUi() notificationsEnabledCheckBox.setText(tr("Enable notifications in taskbar")); specNotificationsEnabledCheckBox.setText(tr("Notify in the taskbar for game events while you are spectating")); buddyConnectNotificationsEnabledCheckBox.setText(tr("Notify in the taskbar when users in your buddy list connect")); - animationGroupBox->setTitle(tr("Animation settings")); enableAllAnimationsButton.setText(tr("&Enable all animations")); disableAllAnimationsButton.setText(tr("&Disable all animations")); @@ -364,7 +362,6 @@ void UserInterfaceSettingsPage::retranslateUi() arrowDrawAnimationCheckBox.setText(tr("&Arrow draw animation")); lifeCounterAnimationsCheckBox.setText(tr("Life counter flash")); battlefieldFlashCheckBox.setText(tr("Battlefield flash on damage")); - deckEditorGroupBox->setTitle(tr("Deck editor/storage settings")); openDeckInNewTabCheckBox.setText(tr("Open deck in new tab by default")); visualDeckStorageInGameCheckBox.setText(tr("Use visual deck storage in game lobby")); @@ -400,8 +397,8 @@ void UserInterfaceSettingsPage::retranslateUi() 0, CommanderBracketNames::CommanderSpellbookBracketNames); commanderSpellbookIntegrationBracketNamingSelector.setItemText( 1, CommanderBracketNames::OfficialCommanderBracketNames); - commanderSpellbookIntegrationUseOfficialBracketNamesExplainer.setToolTip(CommanderBracketNames::Explainer); + commanderSpellbookIntegrationUseOfficialBracketNamesExplainer.setToolTip(CommanderBracketNames::Explainer); replayGroupBox->setTitle(tr("Replay settings")); rewindBufferingMsLabel.setText(tr("Buffer time for backwards skip via shortcut:")); rewindBufferingMsBox.setSuffix(" ms"); diff --git a/cockatrice/src/interface/widgets/settings_page/user_interface_settings_page.h b/cockatrice/src/interface/widgets/settings_page/user_interface_settings_page.h index e8a30fb1f..0dc4cf4e8 100644 --- a/cockatrice/src/interface/widgets/settings_page/user_interface_settings_page.h +++ b/cockatrice/src/interface/widgets/settings_page/user_interface_settings_page.h @@ -23,6 +23,9 @@ private slots: void updateCommanderSpellbookUiState(); private: + QCheckBox notificationsEnabledCheckBox; + QCheckBox specNotificationsEnabledCheckBox; + QCheckBox buddyConnectNotificationsEnabledCheckBox; QCheckBox doubleClickToPlayCheckBox; QCheckBox clickPlaysAllSelectedCheckBox; QCheckBox playToStackCheckBox; @@ -34,18 +37,12 @@ private: QCheckBox showTotalSelectionCountCheckBox; QCheckBox useTearOffMenusCheckBox; QCheckBox keepGameChatFocusCheckBox; - - QCheckBox notificationsEnabledCheckBox; - QCheckBox specNotificationsEnabledCheckBox; - QCheckBox buddyConnectNotificationsEnabledCheckBox; - QPushButton enableAllAnimationsButton; QPushButton disableAllAnimationsButton; QCheckBox tapAnimationCheckBox; QCheckBox arrowDrawAnimationCheckBox; QCheckBox lifeCounterAnimationsCheckBox; QCheckBox battlefieldFlashCheckBox; - QCheckBox openDeckInNewTabCheckBox; QLabel visualDeckStoragePromptForConversionLabel; QComboBox visualDeckStoragePromptForConversionSelector; @@ -60,10 +57,8 @@ private: QLabel commanderSpellbookIntegrationUseOfficialBracketNamesLabel; QToolButton commanderSpellbookIntegrationUseOfficialBracketNamesExplainer; QComboBox commanderSpellbookIntegrationBracketNamingSelector; - QLabel rewindBufferingMsLabel; QSpinBox rewindBufferingMsBox; - QGroupBox *generalGroupBox; QGroupBox *notificationsGroupBox; QGroupBox *animationGroupBox; diff --git a/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp b/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp index ed0ddaf06..b0dac3e7c 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp +++ b/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp @@ -116,10 +116,9 @@ void CloseButton::paintEvent(QPaintEvent * /*event*/) } TabSupervisor::TabSupervisor(AbstractClient *_client, QMenu *tabsMenu, QWidget *parent) - : QTabWidget(parent), userInfo(nullptr), client(_client), tabsMenu(tabsMenu), tabHome(nullptr), - tabVisualDeckStorage(nullptr), tabServer(nullptr), tabAccount(nullptr), tabDeckStorage(nullptr), - tabReplays(nullptr), tabAdmin(nullptr), tabCardArtRules(nullptr), tabLog(nullptr), tabReport(nullptr), - tabModeration(nullptr), isLocalGame(false) + : QTabWidget(parent), userInfo(nullptr), client(_client), tabsMenu(tabsMenu), tabVisualDeckStorage(nullptr), + tabServer(nullptr), tabAccount(nullptr), tabDeckStorage(nullptr), tabReplays(nullptr), tabAdmin(nullptr), + tabLog(nullptr), tabReport(nullptr), tabModeration(nullptr), isLocalGame(false) { setElideMode(Qt::ElideRight); setMovable(true); @@ -246,7 +245,6 @@ void TabSupervisor::retranslateUi() aTabLog->setText(tr("Logs")); aTabReport->setText(tr("Report Queue")); aTabModeration->setText(tr("Moderation")); - aTabCardArtRules->setText(tr("Card Art Rules")); // tabs QList tabs; @@ -258,7 +256,6 @@ void TabSupervisor::retranslateUi() tabs.append(tabLog); tabs.append(tabReport); tabs.append(tabModeration); - tabs.append(tabCardArtRules); QMapIterator roomIterator(roomTabs); while (roomIterator.hasNext()) { tabs.append(roomIterator.next().value()); @@ -523,9 +520,7 @@ void TabSupervisor::start(const ServerInfo_User &_userInfo) if (SettingsCache::instance().tabs().getTabModerationOpen()) { openTabModeration(); } - if (SettingsCache::instance().tabs().getTabCardArtRulesOpen()) { - openTabCardArtRules(); - } + openTabCardArtRules(); } retranslateUi(); @@ -587,9 +582,6 @@ void TabSupervisor::stop() if (tabModeration) { tabModeration->close(); } - if (tabCardArtRules) { - tabCardArtRules->close(); - } } QList tabsToDelete; @@ -783,7 +775,6 @@ void TabSupervisor::openTabAdmin() void TabSupervisor::actTabCardArtRules(bool checked) { - SettingsCache::instance().tabs().setTabCardArtRulesOpen(checked); if (checked && !tabCardArtRules) { openTabCardArtRules(); setCurrentWidget(tabCardArtRules); diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp b/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp index 22d73b604..fbaabf90f 100644 --- a/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp +++ b/cockatrice/src/interface/widgets/visual_deck_storage/visual_deck_storage_folder_display_widget.cpp @@ -125,7 +125,9 @@ void VisualDeckStorageFolderDisplayWidget::continueDeckPass() } const bool matches = index.data(VisualDeckStorageRoles::FilterMatchRole).toBool(); - deckPreviewWidget->setVisible(matches); + if (matches == deckPreviewWidget->isHidden()) { + deckPreviewWidget->setVisible(matches); + } if (matches) { ++visibleDeckCount; } diff --git a/libcockatrice_interfaces/libcockatrice/interfaces/interface_tabs_settings_provider.h b/libcockatrice_interfaces/libcockatrice/interfaces/interface_tabs_settings_provider.h index 054c4cd72..a81616cb0 100644 --- a/libcockatrice_interfaces/libcockatrice/interfaces/interface_tabs_settings_provider.h +++ b/libcockatrice_interfaces/libcockatrice/interfaces/interface_tabs_settings_provider.h @@ -21,7 +21,6 @@ public: [[nodiscard]] virtual bool getTabLogOpen() const = 0; [[nodiscard]] virtual bool getTabReportOpen() const = 0; [[nodiscard]] virtual bool getTabModerationOpen() const = 0; - [[nodiscard]] virtual bool getTabCardArtRulesOpen() const = 0; }; #endif // COCKATRICE_INTERFACE_TABS_SETTINGS_PROVIDER_H diff --git a/libcockatrice_protocol/libcockatrice/protocol/pb/CMakeLists.txt b/libcockatrice_protocol/libcockatrice/protocol/pb/CMakeLists.txt index f22828f46..3a193ae3c 100644 --- a/libcockatrice_protocol/libcockatrice/protocol/pb/CMakeLists.txt +++ b/libcockatrice_protocol/libcockatrice/protocol/pb/CMakeLists.txt @@ -90,6 +90,7 @@ set(PROTO_FILES event_game_log_notice.proto event_game_say.proto event_game_state_changed.proto + event_game_state_changed.proto event_join.proto event_join_room.proto event_kicked.proto diff --git a/libcockatrice_settings/libcockatrice/settings/tabs_settings.cpp b/libcockatrice_settings/libcockatrice/settings/tabs_settings.cpp index cf5bfd81a..85a1424a6 100644 --- a/libcockatrice_settings/libcockatrice/settings/tabs_settings.cpp +++ b/libcockatrice_settings/libcockatrice/settings/tabs_settings.cpp @@ -106,11 +106,6 @@ bool TabsSettings::getTabModerationOpen() const return getValue("moderation", QString(), QString(), false).toBool(); } -bool TabsSettings::getTabCardArtRulesOpen() const -{ - return getValue("cardArtRules", QString(), QString(), false).toBool(); -} - void TabsSettings::setTabVisualDeckStorageOpen(bool value) { setValue(value, "visualDeckStorage"); @@ -155,8 +150,3 @@ void TabsSettings::setTabModerationOpen(bool value) { setValue(value, "moderation"); } - -void TabsSettings::setTabCardArtRulesOpen(bool value) -{ - setValue(value, "cardArtRules"); -} diff --git a/libcockatrice_settings/libcockatrice/settings/tabs_settings.h b/libcockatrice_settings/libcockatrice/settings/tabs_settings.h index eb78d311b..365d91af7 100644 --- a/libcockatrice_settings/libcockatrice/settings/tabs_settings.h +++ b/libcockatrice_settings/libcockatrice/settings/tabs_settings.h @@ -43,7 +43,6 @@ public: [[nodiscard]] bool getTabLogOpen() const override; [[nodiscard]] bool getTabReportOpen() const override; [[nodiscard]] bool getTabModerationOpen() const override; - [[nodiscard]] bool getTabCardArtRulesOpen() const override; void setStartupTabIndex(int value); void setStartupServerHost(const QString &host); @@ -58,7 +57,6 @@ public: void setTabLogOpen(bool value); void setTabReportOpen(bool value); void setTabModerationOpen(bool value); - void setTabCardArtRulesOpen(bool value); signals: void startupTabIndexChanged(int index); diff --git a/tests/settings/settings_defaults_test.cpp b/tests/settings/settings_defaults_test.cpp index 139656f27..6c79d5227 100644 --- a/tests/settings/settings_defaults_test.cpp +++ b/tests/settings/settings_defaults_test.cpp @@ -238,12 +238,6 @@ TEST_F(SettingsDefaultsTest, Tabs_ModerationOpen_Default) ASSERT_EQ(s.getTabModerationOpen(), false); } -TEST_F(SettingsDefaultsTest, Tabs_CardArtRulesOpen_Default) -{ - TabsSettings s(settingsPath, nullptr); - ASSERT_EQ(s.getTabCardArtRulesOpen(), false); -} - // --- ChatSettings --- TEST_F(SettingsDefaultsTest, Chat_Mention_Default)