From 16a68d78eb71c8b3cfa697ba9989d27f3c4ef961 Mon Sep 17 00:00:00 2001 From: DanielSvoboda Date: Mon, 24 Mar 2025 05:25:51 -0300 Subject: [PATCH] Trophy Viewer - Select Game (#2678) * Trophy Viewer - Select Game * TR - Button in Utils +icon TR - Button in Utils +icon I also made a small correction to the game folder list, where the checkboxes were being filled in incorrectly. --- REUSE.toml | 1 + src/common/config.cpp | 6 ++- src/images/trophy_icon.png | Bin 0 -> 16958 bytes src/qt_gui/gui_context_menus.h | 28 +++++++++++- src/qt_gui/main_window.cpp | 55 ++++++++++++++++++++++ src/qt_gui/main_window_ui.h | 8 ++++ src/qt_gui/translations/en_US.ts | 12 +++++ src/qt_gui/trophy_viewer.cpp | 76 +++++++++++++++++++++++++++---- src/qt_gui/trophy_viewer.h | 20 +++++++- src/shadps4.qrc | 1 + 10 files changed, 193 insertions(+), 14 deletions(-) create mode 100644 src/images/trophy_icon.png diff --git a/REUSE.toml b/REUSE.toml index d9b307d39..793990bd8 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -30,6 +30,7 @@ path = [ "src/images/dump_icon.png", "src/images/exit_icon.png", "src/images/file_icon.png", + "src/images/trophy_icon.png", "src/images/flag_china.png", "src/images/flag_eu.png", "src/images/flag_jp.png", diff --git a/src/common/config.cpp b/src/common/config.cpp index fd6538f85..e0a348fbe 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -645,7 +645,11 @@ const std::vector getGameInstallDirs() { } const std::vector getGameInstallDirsEnabled() { - return install_dirs_enabled; + std::vector enabled_dirs; + for (const auto& dir : settings_install_dirs) { + enabled_dirs.push_back(dir.enabled); + } + return enabled_dirs; } std::filesystem::path getAddonInstallDir() { diff --git a/src/images/trophy_icon.png b/src/images/trophy_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..559e7dbb2c1e2d4b5c5cb3a066a08209b7054839 GIT binary patch literal 16958 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 nEFBDj3QS8jIk allTrophyGames; + for (const auto& game : m_games) { + TrophyGameInfo gameInfo; + gameInfo.name = QString::fromStdString(game.name); + Common::FS::PathToQString(gameInfo.trophyPath, game.serial); + Common::FS::PathToQString(gameInfo.gameTrpPath, game.path); + + auto update_path = Common::FS::PathFromQString(gameInfo.gameTrpPath); + update_path += "-UPDATE"; + if (std::filesystem::exists(update_path)) { + Common::FS::PathToQString(gameInfo.gameTrpPath, update_path); + } else { + update_path = Common::FS::PathFromQString(gameInfo.gameTrpPath); + update_path += "-patch"; + if (std::filesystem::exists(update_path)) { + Common::FS::PathToQString(gameInfo.gameTrpPath, update_path); + } + } + + allTrophyGames.append(gameInfo); + } + + QString gameName = QString::fromStdString(m_games[itemID].name); + TrophyViewer* trophyViewer = + new TrophyViewer(trophyPath, gameTrpPath, gameName, allTrophyGames); trophyViewer->show(); connect(widget->parent(), &QWidget::destroyed, trophyViewer, [trophyViewer]() { trophyViewer->deleteLater(); }); diff --git a/src/qt_gui/main_window.cpp b/src/qt_gui/main_window.cpp index 68135048e..27551e997 100644 --- a/src/qt_gui/main_window.cpp +++ b/src/qt_gui/main_window.cpp @@ -593,6 +593,60 @@ void MainWindow::CreateConnects() { pkgViewer->show(); }); + // Trophy Viewer + connect(ui->trophyViewerAct, &QAction::triggered, this, [this]() { + if (m_game_info->m_games.empty()) { + QMessageBox::information( + this, tr("Trophy Viewer"), + tr("No games found. Please add your games to your library first.")); + return; + } + + const auto& firstGame = m_game_info->m_games[0]; + QString trophyPath, gameTrpPath; + Common::FS::PathToQString(trophyPath, firstGame.serial); + Common::FS::PathToQString(gameTrpPath, firstGame.path); + + auto game_update_path = Common::FS::PathFromQString(gameTrpPath); + game_update_path += "-UPDATE"; + if (std::filesystem::exists(game_update_path)) { + Common::FS::PathToQString(gameTrpPath, game_update_path); + } else { + game_update_path = Common::FS::PathFromQString(gameTrpPath); + game_update_path += "-patch"; + if (std::filesystem::exists(game_update_path)) { + Common::FS::PathToQString(gameTrpPath, game_update_path); + } + } + + QVector allTrophyGames; + for (const auto& game : m_game_info->m_games) { + TrophyGameInfo gameInfo; + gameInfo.name = QString::fromStdString(game.name); + Common::FS::PathToQString(gameInfo.trophyPath, game.serial); + Common::FS::PathToQString(gameInfo.gameTrpPath, game.path); + + auto update_path = Common::FS::PathFromQString(gameInfo.gameTrpPath); + update_path += "-UPDATE"; + if (std::filesystem::exists(update_path)) { + Common::FS::PathToQString(gameInfo.gameTrpPath, update_path); + } else { + update_path = Common::FS::PathFromQString(gameInfo.gameTrpPath); + update_path += "-patch"; + if (std::filesystem::exists(update_path)) { + Common::FS::PathToQString(gameInfo.gameTrpPath, update_path); + } + } + + allTrophyGames.append(gameInfo); + } + + QString gameName = QString::fromStdString(firstGame.name); + TrophyViewer* trophyViewer = + new TrophyViewer(trophyPath, gameTrpPath, gameName, allTrophyGames); + trophyViewer->show(); + }); + // Themes connect(ui->setThemeDark, &QAction::triggered, &m_window_themes, [this]() { m_window_themes.SetWindowTheme(Theme::Dark, ui->mw_searchbar); @@ -1169,6 +1223,7 @@ void MainWindow::SetUiIcons(bool isWhite) { ui->refreshGameListAct->setIcon(RecolorIcon(ui->refreshGameListAct->icon(), isWhite)); ui->menuGame_List_Mode->setIcon(RecolorIcon(ui->menuGame_List_Mode->icon(), isWhite)); ui->pkgViewerAct->setIcon(RecolorIcon(ui->pkgViewerAct->icon(), isWhite)); + ui->trophyViewerAct->setIcon(RecolorIcon(ui->trophyViewerAct->icon(), isWhite)); ui->configureAct->setIcon(RecolorIcon(ui->configureAct->icon(), isWhite)); ui->addElfFolderAct->setIcon(RecolorIcon(ui->addElfFolderAct->icon(), isWhite)); } diff --git a/src/qt_gui/main_window_ui.h b/src/qt_gui/main_window_ui.h index 3ebfcee9e..246c2afd6 100644 --- a/src/qt_gui/main_window_ui.h +++ b/src/qt_gui/main_window_ui.h @@ -27,6 +27,7 @@ public: QAction* downloadCheatsPatchesAct; QAction* dumpGameListAct; QAction* pkgViewerAct; + QAction* trophyViewerAct; #ifdef ENABLE_UPDATER QAction* updaterAct; #endif @@ -139,6 +140,10 @@ public: pkgViewerAct = new QAction(MainWindow); pkgViewerAct->setObjectName("pkgViewer"); pkgViewerAct->setIcon(QIcon(":images/file_icon.png")); + trophyViewerAct = new QAction(MainWindow); + trophyViewerAct->setObjectName("trophyViewer"); + trophyViewerAct->setIcon(QIcon(":images/trophy_icon.png")); + #ifdef ENABLE_UPDATER updaterAct = new QAction(MainWindow); updaterAct->setObjectName("updaterAct"); @@ -321,6 +326,7 @@ public: menuUtils->addAction(downloadCheatsPatchesAct); menuUtils->addAction(dumpGameListAct); menuUtils->addAction(pkgViewerAct); + menuUtils->addAction(trophyViewerAct); #ifdef ENABLE_UPDATER menuHelp->addAction(updaterAct); #endif @@ -379,6 +385,8 @@ public: dumpGameListAct->setText( QCoreApplication::translate("MainWindow", "Dump Game List", nullptr)); pkgViewerAct->setText(QCoreApplication::translate("MainWindow", "PKG Viewer", nullptr)); + trophyViewerAct->setText( + QCoreApplication::translate("MainWindow", "Trophy Viewer", nullptr)); mw_searchbar->setPlaceholderText( QCoreApplication::translate("MainWindow", "Search...", nullptr)); menuFile->setTitle(QCoreApplication::translate("MainWindow", "File", nullptr)); diff --git a/src/qt_gui/translations/en_US.ts b/src/qt_gui/translations/en_US.ts index 9c9d56076..20cba0378 100644 --- a/src/qt_gui/translations/en_US.ts +++ b/src/qt_gui/translations/en_US.ts @@ -1306,6 +1306,14 @@ Dump Game List Dump Game List + + Trophy Viewer + Trophy Viewer + + + No games found. Please add your games to your library first. + No games found. Please add your games to your library first. + PKG Viewer PKG Viewer @@ -2191,6 +2199,10 @@ Trophy Viewer Trophy Viewer + + Select Game: + + Progress diff --git a/src/qt_gui/trophy_viewer.cpp b/src/qt_gui/trophy_viewer.cpp index bfa47e3cc..bed487605 100644 --- a/src/qt_gui/trophy_viewer.cpp +++ b/src/qt_gui/trophy_viewer.cpp @@ -104,8 +104,10 @@ void TrophyViewer::updateTableFilters() { } } -TrophyViewer::TrophyViewer(QString trophyPath, QString gameTrpPath) : QMainWindow() { - this->setWindowTitle(tr("Trophy Viewer")); +TrophyViewer::TrophyViewer(QString trophyPath, QString gameTrpPath, QString gameName, + const QVector& allTrophyGames) + : QMainWindow(), allTrophyGames_(allTrophyGames), currentGameName_(gameName) { + this->setWindowTitle(tr("Trophy Viewer") + " - " + currentGameName_); this->setAttribute(Qt::WA_DeleteOnClose); tabWidget = new QTabWidget(this); @@ -127,11 +129,40 @@ TrophyViewer::TrophyViewer(QString trophyPath, QString gameTrpPath) : QMainWindo << "PID"; PopulateTrophyWidget(trophyPath); - QDockWidget* trophyInfoDock = new QDockWidget("", this); + trophyInfoDock = new QDockWidget("", this); QWidget* dockWidget = new QWidget(trophyInfoDock); QVBoxLayout* dockLayout = new QVBoxLayout(dockWidget); dockLayout->setAlignment(Qt::AlignTop); + // ComboBox for game selection + if (!allTrophyGames_.isEmpty()) { + QLabel* gameSelectionLabel = new QLabel(tr("Select Game:"), dockWidget); + dockLayout->addWidget(gameSelectionLabel); + + gameSelectionComboBox = new QComboBox(dockWidget); + for (const auto& game : allTrophyGames_) { + gameSelectionComboBox->addItem(game.name); + } + + // Select current game in ComboBox + if (!currentGameName_.isEmpty()) { + int index = gameSelectionComboBox->findText(currentGameName_); + if (index >= 0) { + gameSelectionComboBox->setCurrentIndex(index); + } + } + + dockLayout->addWidget(gameSelectionComboBox); + + connect(gameSelectionComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, + &TrophyViewer::onGameSelectionChanged); + + QFrame* line = new QFrame(dockWidget); + line->setFrameShape(QFrame::HLine); + line->setFrameShadow(QFrame::Sunken); + dockLayout->addWidget(line); + } + trophyInfoLabel = new QLabel(tr("Progress") + ": 0% (0/0)", dockWidget); trophyInfoLabel->setStyleSheet( "font-weight: bold; font-size: 16px; color: white; background: #333; padding: 5px;"); @@ -162,7 +193,7 @@ TrophyViewer::TrophyViewer(QString trophyPath, QString gameTrpPath) : QMainWindo expandButton->setGeometry(80, 0, 27, 27); expandButton->hide(); - connect(expandButton, &QPushButton::clicked, this, [this, trophyInfoDock] { + connect(expandButton, &QPushButton::clicked, this, [this] { trophyInfoDock->setVisible(true); expandButton->hide(); }); @@ -184,13 +215,13 @@ TrophyViewer::TrophyViewer(QString trophyPath, QString gameTrpPath) : QMainWindo updateTrophyInfo(); updateTableFilters(); - connect(trophyInfoDock, &QDockWidget::topLevelChanged, this, [this, trophyInfoDock] { + connect(trophyInfoDock, &QDockWidget::topLevelChanged, this, [this] { if (!trophyInfoDock->isVisible()) { expandButton->show(); } }); - connect(trophyInfoDock, &QDockWidget::visibilityChanged, this, [this, trophyInfoDock] { + connect(trophyInfoDock, &QDockWidget::visibilityChanged, this, [this] { if (!trophyInfoDock->isVisible()) { expandButton->show(); } else { @@ -199,6 +230,29 @@ TrophyViewer::TrophyViewer(QString trophyPath, QString gameTrpPath) : QMainWindo }); } +void TrophyViewer::onGameSelectionChanged(int index) { + if (index < 0 || index >= allTrophyGames_.size()) { + return; + } + + while (tabWidget->count() > 0) { + QWidget* widget = tabWidget->widget(0); + tabWidget->removeTab(0); + delete widget; + } + + const TrophyGameInfo& selectedGame = allTrophyGames_[index]; + currentGameName_ = selectedGame.name; + gameTrpPath_ = selectedGame.gameTrpPath; + + this->setWindowTitle(tr("Trophy Viewer") + " - " + currentGameName_); + + PopulateTrophyWidget(selectedGame.trophyPath); + + updateTrophyInfo(); + updateTableFilters(); +} + void TrophyViewer::onDockClosed() { if (!trophyInfoDock->isVisible()) { reopenButton->setVisible(true); @@ -389,13 +443,15 @@ void TrophyViewer::PopulateTrophyWidget(QString title) { tabWidget->addTab(tableWidget, tabName.insert(6, " ").replace(0, 1, tabName.at(0).toUpper())); - this->resize(width + 400, 720); - QSize mainWindowSize = QApplication::activeWindow()->size(); - this->resize(mainWindowSize.width() * 0.8, mainWindowSize.height() * 0.8); + if (!this->isMaximized()) { + this->resize(width + 400, 720); + QSize mainWindowSize = QApplication::activeWindow()->size(); + this->resize(mainWindowSize.width() * 0.8, mainWindowSize.height() * 0.8); + } this->show(); tableWidget->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed); - tableWidget->setColumnWidth(3, 650); + tableWidget->setColumnWidth(3, 500); } this->setCentralWidget(tabWidget); } diff --git a/src/qt_gui/trophy_viewer.h b/src/qt_gui/trophy_viewer.h index 75fb500e7..c63171774 100644 --- a/src/qt_gui/trophy_viewer.h +++ b/src/qt_gui/trophy_viewer.h @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -12,26 +13,38 @@ #include #include #include +#include #include #include #include #include +#include #include #include "common/types.h" #include "core/file_format/trp.h" +struct TrophyGameInfo { + QString name; + QString trophyPath; + QString gameTrpPath; +}; + class TrophyViewer : public QMainWindow { Q_OBJECT public: - explicit TrophyViewer(QString trophyPath, QString gameTrpPath); + explicit TrophyViewer( + QString trophyPath, QString gameTrpPath, QString gameName = "", + const QVector& allTrophyGames = QVector()); void updateTrophyInfo(); - void updateTableFilters(); void onDockClosed(); void reopenLeftDock(); +private slots: + void onGameSelectionChanged(int index); + private: void PopulateTrophyWidget(QString title); void SetTableItem(QTableWidget* parent, int row, int column, QString str); @@ -39,14 +52,17 @@ private: QTabWidget* tabWidget = nullptr; QStringList headers; QString gameTrpPath_; + QString currentGameName_; TRP trp; QLabel* trophyInfoLabel; QCheckBox* showEarnedCheck; QCheckBox* showNotEarnedCheck; QCheckBox* showHiddenCheck; + QComboBox* gameSelectionComboBox; QPushButton* expandButton; QDockWidget* trophyInfoDock; QPushButton* reopenButton; + QVector allTrophyGames_; std::string GetTrpType(const QChar trp_) { switch (trp_.toLatin1()) { diff --git a/src/shadps4.qrc b/src/shadps4.qrc index a1ff680ed..340756f5c 100644 --- a/src/shadps4.qrc +++ b/src/shadps4.qrc @@ -8,6 +8,7 @@ images/stop_icon.png images/utils_icon.png images/file_icon.png + images/trophy_icon.png images/folder_icon.png images/themes_icon.png images/iconsize_icon.png