From d59536a71c923508e8f2d730110f55fa43161696 Mon Sep 17 00:00:00 2001 From: Dmugetsu <168934208+diegolix29@users.noreply.github.com> Date: Sun, 2 Mar 2025 13:36:12 -0600 Subject: [PATCH] Adding Top and Bottom trophy option for pop window + Trophy improvements (#2566) * Adding top button option for trophy pop up * Ui fix * Clang format * improvements to trophy pr * improvements * Note: The sound will only work in QT versions * -. * Update path_util.cpp * Update path_util.cpp * centered text when using top and bottom option * Clang * trophy viewer now opens in window not fullscreen --------- Co-authored-by: DanielSvoboda --- src/common/config.cpp | 17 ++++---- src/common/config.h | 4 +- src/common/path_util.cpp | 18 +++++++- src/core/libraries/np_trophy/trophy_ui.cpp | 51 +++++++++++++++++----- src/qt_gui/settings_dialog.cpp | 24 ++++++++-- src/qt_gui/settings_dialog.ui | 20 ++++++--- src/qt_gui/translations/en_US.ts | 12 ++++- src/qt_gui/trophy_viewer.cpp | 40 ++++++++++++++++- src/qt_gui/trophy_viewer.h | 8 ++++ 9 files changed, 158 insertions(+), 36 deletions(-) diff --git a/src/common/config.cpp b/src/common/config.cpp index 36566a14c..514024c30 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -53,7 +53,7 @@ static bool isShaderDebug = false; static bool isShowSplash = false; static bool isAutoUpdate = false; static bool isAlwaysShowChangelog = false; -static bool isLeftSideTrophy = false; +static std::string isSideTrophy = "right"; static bool isNullGpu = false; static bool shouldCopyGPUBuffers = false; static bool shouldDumpShaders = false; @@ -270,8 +270,8 @@ bool alwaysShowChangelog() { return isAlwaysShowChangelog; } -bool leftSideTrophy() { - return isLeftSideTrophy; +std::string sideTrophy() { + return isSideTrophy; } bool nullGpu() { @@ -381,8 +381,9 @@ void setAutoUpdate(bool enable) { void setAlwaysShowChangelog(bool enable) { isAlwaysShowChangelog = enable; } -void setLeftSideTrophy(bool enable) { - isLeftSideTrophy = enable; + +void setSideTrophy(std::string side) { + isSideTrophy = side; } void setNullGpu(bool enable) { @@ -737,7 +738,7 @@ void load(const std::filesystem::path& path) { isShowSplash = toml::find_or(general, "showSplash", true); isAutoUpdate = toml::find_or(general, "autoUpdate", false); isAlwaysShowChangelog = toml::find_or(general, "alwaysShowChangelog", false); - isLeftSideTrophy = toml::find_or(general, "leftSideTrophy", false); + isSideTrophy = toml::find_or(general, "sideTrophy", "right"); separateupdatefolder = toml::find_or(general, "separateUpdateEnabled", false); compatibilityData = toml::find_or(general, "compatibilityEnabled", false); checkCompatibilityOnStartup = @@ -888,7 +889,7 @@ void save(const std::filesystem::path& path) { data["General"]["showSplash"] = isShowSplash; data["General"]["autoUpdate"] = isAutoUpdate; data["General"]["alwaysShowChangelog"] = isAlwaysShowChangelog; - data["General"]["leftSideTrophy"] = isLeftSideTrophy; + data["General"]["sideTrophy"] = isSideTrophy; data["General"]["separateUpdateEnabled"] = separateupdatefolder; data["General"]["compatibilityEnabled"] = compatibilityData; data["General"]["checkCompatibilityOnStartup"] = checkCompatibilityOnStartup; @@ -1018,7 +1019,7 @@ void setDefaultValues() { isShowSplash = false; isAutoUpdate = false; isAlwaysShowChangelog = false; - isLeftSideTrophy = false; + isSideTrophy = "right"; isNullGpu = false; shouldDumpShaders = false; vblankDivider = 1; diff --git a/src/common/config.h b/src/common/config.h index 988734b93..82d65d30e 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -63,7 +63,7 @@ bool collectShadersForDebug(); bool showSplash(); bool autoUpdate(); bool alwaysShowChangelog(); -bool leftSideTrophy(); +std::string sideTrophy(); bool nullGpu(); bool copyGPUCmdBuffers(); bool dumpShaders(); @@ -77,7 +77,7 @@ void setCollectShaderForDebug(bool enable); void setShowSplash(bool enable); void setAutoUpdate(bool enable); void setAlwaysShowChangelog(bool enable); -void setLeftSideTrophy(bool enable); +void setSideTrophy(std::string side); void setNullGpu(bool enable); void setAllowHDR(bool enable); void setCopyGPUCmdBuffers(bool enable); diff --git a/src/common/path_util.cpp b/src/common/path_util.cpp index d48e8c3fe..6bc73ee43 100644 --- a/src/common/path_util.cpp +++ b/src/common/path_util.cpp @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include #include #include "common/logging/log.h" #include "common/path_util.h" @@ -130,6 +131,21 @@ static auto UserPaths = [] { create_path(PathType::MetaDataDir, user_dir / METADATA_DIR); create_path(PathType::CustomTrophy, user_dir / CUSTOM_TROPHY); + std::ofstream notice_file(user_dir / CUSTOM_TROPHY / "Notice.txt"); + if (notice_file.is_open()) { + notice_file + << "++++++++++++++++++++++++++++++++\n+ Custom Trophy Images / Sound " + "+\n++++++++++++++++++++++++++++++++\n\nYou can add custom images to the " + "trophies.\n*We recommend a square resolution image, for example 200x200, 500x500, " + "the same size as the height and width.\nIn this folder ('user\\custom_trophy'), " + "add the files with the following " + "names:\n\nbronze.png\nsilver.png\ngold.png\nplatinum.png\n\nYou can add a custom " + "sound for trophy notifications.\n*By default, no audio is played unless it is in " + "this folder and you are using the QT version.\nIn this folder " + "('user\\custom_trophy'), add the files with the following names:\n\ntrophy.mp3"; + notice_file.close(); + } + return paths; }(); @@ -223,4 +239,4 @@ std::filesystem::path PathFromQString(const QString& path) { } #endif -} // namespace Common::FS \ No newline at end of file +} // namespace Common::FS diff --git a/src/core/libraries/np_trophy/trophy_ui.cpp b/src/core/libraries/np_trophy/trophy_ui.cpp index 2564cbf5d..aba56f341 100644 --- a/src/core/libraries/np_trophy/trophy_ui.cpp +++ b/src/core/libraries/np_trophy/trophy_ui.cpp @@ -27,14 +27,17 @@ namespace Libraries::NpTrophy { std::optional current_trophy_ui; std::queue trophy_queue; std::mutex queueMtx; -bool isLeftSide; + +std::string side = "right"; + double trophy_timer; TrophyUI::TrophyUI(const std::filesystem::path& trophyIconPath, const std::string& trophyName, const std::string_view& rarity) : trophy_name(trophyName), trophy_type(rarity) { - isLeftSide = Config::leftSideTrophy(); + side = Config::sideTrophy(); + trophy_timer = Config::getTrophyNotificationDuration(); if (std::filesystem::exists(trophyIconPath)) { @@ -115,8 +118,8 @@ float fade_out_duration = 0.5f; // Final fade duration void TrophyUI::Draw() { const auto& io = GetIO(); - float AdjustWidth = io.DisplaySize.x / 1280; - float AdjustHeight = io.DisplaySize.y / 720; + float AdjustWidth = io.DisplaySize.x / 1920; + float AdjustHeight = io.DisplaySize.y / 1080; const ImVec2 window_size{ std::min(io.DisplaySize.x, (350 * AdjustWidth)), std::min(io.DisplaySize.y, (70 * AdjustHeight)), @@ -125,21 +128,38 @@ void TrophyUI::Draw() { elapsed_time += io.DeltaTime; float progress = std::min(elapsed_time / animation_duration, 1.0f); - // left or right position - float final_pos_x; - if (isLeftSide) { - start_pos.x = -window_size.x; + float final_pos_x, start_x; + float final_pos_y, start_y; + + if (side == "top") { + start_x = (io.DisplaySize.x - window_size.x) * 0.5f; + start_y = -window_size.y; + final_pos_x = start_x; + final_pos_y = 20 * AdjustHeight; + } else if (side == "left") { + start_x = -window_size.x; + start_y = 50 * AdjustHeight; final_pos_x = 20 * AdjustWidth; - } else { - start_pos.x = io.DisplaySize.x; + final_pos_y = start_y; + } else if (side == "right") { + start_x = io.DisplaySize.x; + start_y = 50 * AdjustHeight; final_pos_x = io.DisplaySize.x - window_size.x - 20 * AdjustWidth; + final_pos_y = start_y; + } else if (side == "bottom") { + start_x = (io.DisplaySize.x - window_size.x) * 0.5f; + start_y = io.DisplaySize.y; + final_pos_x = start_x; + final_pos_y = io.DisplaySize.y - window_size.y - 20 * AdjustHeight; } - ImVec2 current_pos = ImVec2(start_pos.x + (final_pos_x - start_pos.x) * progress, - start_pos.y + (target_pos.y - start_pos.y) * progress); + ImVec2 current_pos = ImVec2(start_x + (final_pos_x - start_x) * progress, + start_y + (final_pos_y - start_y) * progress); trophy_timer -= io.DeltaTime; + ImGui::SetNextWindowPos(current_pos); + // If the remaining time of the trophy is less than or equal to 1 second, the fade-out begins. if (trophy_timer <= 1.0f) { float fade_out_time = 1.0f - (trophy_timer / 1.0f); @@ -192,6 +212,13 @@ void TrophyUI::Draw() { const float text_height = ImGui::CalcTextSize(combinedString.c_str()).y; SetCursorPosY((window_size.y - text_height) * 0.5); } + + if (side == "top" || side == "bottom") { + float text_width = ImGui::CalcTextSize(trophy_name.c_str()).x; + float centered_x = (window_size.x - text_width) * 0.5f; + ImGui::SetCursorPosX(std::max(centered_x, 10.0f * AdjustWidth)); + } + ImGui::PushTextWrapPos(window_size.x - (60 * AdjustWidth)); TextWrapped("Trophy earned!\n%s", trophy_name.c_str()); ImGui::SameLine(window_size.x - (60 * AdjustWidth)); diff --git a/src/qt_gui/settings_dialog.cpp b/src/qt_gui/settings_dialog.cpp index bde104828..a3890b548 100644 --- a/src/qt_gui/settings_dialog.cpp +++ b/src/qt_gui/settings_dialog.cpp @@ -418,8 +418,14 @@ void SettingsDialog::LoadValuesFromConfig() { ui->disableTrophycheckBox->setChecked( toml::find_or(data, "General", "isTrophyPopupDisabled", false)); ui->popUpDurationSpinBox->setValue(Config::getTrophyNotificationDuration()); - ui->radioButton_Left->setChecked(Config::leftSideTrophy()); - ui->radioButton_Right->setChecked(!ui->radioButton_Left->isChecked()); + + QString side = QString::fromStdString(Config::sideTrophy()); + + ui->radioButton_Left->setChecked(side == "left"); + ui->radioButton_Right->setChecked(side == "right"); + ui->radioButton_Top->setChecked(side == "top"); + ui->radioButton_Bottom->setChecked(side == "bottom"); + ui->BGMVolumeSlider->setValue(toml::find_or(data, "General", "BGMvolume", 50)); ui->discordRPCCheckbox->setChecked( toml::find_or(data, "General", "enableDiscordRPC", true)); @@ -612,7 +618,7 @@ void SettingsDialog::updateNoteTextEdit(const QString& elementName) { //User if (elementName == "OpenCustomTrophyLocationButton") { - text = tr("Open the custom trophy images/sounds folder:\\nYou can add custom images to the trophies and an audio.\\nAdd the files to custom_trophy with the following names:\\nthophy.mp3, bronze.png, gold.png, platinum.png, silver.png"); + text = tr("Open the custom trophy images/sounds folder:\\nYou can add custom images to the trophies and an audio.\\nAdd the files to custom_trophy with the following names:\\nthophy.mp3, bronze.png, gold.png, platinum.png, silver.png\\nNote: The sound will only work in QT versions."); } // Input @@ -706,7 +712,17 @@ void SettingsDialog::UpdateSettings() { Config::setIsMotionControlsEnabled(ui->motionControlsCheckBox->isChecked()); Config::setisTrophyPopupDisabled(ui->disableTrophycheckBox->isChecked()); Config::setTrophyNotificationDuration(ui->popUpDurationSpinBox->value()); - Config::setLeftSideTrophy(ui->radioButton_Left->isChecked()); + + if (ui->radioButton_Top->isChecked()) { + Config::setSideTrophy("top"); + } else if (ui->radioButton_Left->isChecked()) { + Config::setSideTrophy("left"); + } else if (ui->radioButton_Right->isChecked()) { + Config::setSideTrophy("right"); + } else if (ui->radioButton_Bottom->isChecked()) { + Config::setSideTrophy("bottom"); + } + Config::setPlayBGM(ui->playBGMCheckBox->isChecked()); Config::setAllowHDR(ui->enableHDRCheckBox->isChecked()); Config::setLogType(logTypeMap.value(ui->logTypeComboBox->currentText()).toStdString()); diff --git a/src/qt_gui/settings_dialog.ui b/src/qt_gui/settings_dialog.ui index c793aced5..7db0afa59 100644 --- a/src/qt_gui/settings_dialog.ui +++ b/src/qt_gui/settings_dialog.ui @@ -1295,17 +1295,25 @@ - - - 0 - 0 - - Right + + + + Top + + + + + + + Bottom + + + diff --git a/src/qt_gui/translations/en_US.ts b/src/qt_gui/translations/en_US.ts index 92fb59a02..29ce27f07 100644 --- a/src/qt_gui/translations/en_US.ts +++ b/src/qt_gui/translations/en_US.ts @@ -1632,8 +1632,8 @@ Update Compatibility Database:\nImmediately update the compatibility database. - Open the custom trophy images/sounds folder:\nYou can add custom images to the trophies and an audio.\nAdd the files to custom_trophy with the following names:\nthophy.mp3, bronze.png, gold.png, platinum.png, silver.png - Open the custom trophy images/sounds folder:\nYou can add custom images to the trophies and an audio.\nAdd the files to custom_trophy with the following names:\nthophy.mp3, bronze.png, gold.png, platinum.png, silver.png + Open the custom trophy images/sounds folder:\nYou can add custom images to the trophies and an audio.\nAdd the files to custom_trophy with the following names:\nthophy.mp3, bronze.png, gold.png, platinum.png, silver.png\nNote: The sound will only work in QT versions. + Open the custom trophy images/sounds folder:\nYou can add custom images to the trophies and an audio.\nAdd the files to custom_trophy with the following names:\nthophy.mp3, bronze.png, gold.png, platinum.png, silver.png\nNote: The sound will only work in QT versions. Never @@ -1839,6 +1839,14 @@ Right Right + + Top + Top + + + Bottom + Bottom + Notification Duration Notification Duration diff --git a/src/qt_gui/trophy_viewer.cpp b/src/qt_gui/trophy_viewer.cpp index 148cbee06..bfa47e3cc 100644 --- a/src/qt_gui/trophy_viewer.cpp +++ b/src/qt_gui/trophy_viewer.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include "common/path_util.h" @@ -157,6 +158,15 @@ TrophyViewer::TrophyViewer(QString trophyPath, QString gameTrpPath) : QMainWindo // Adds the dock to the left area this->addDockWidget(Qt::LeftDockWidgetArea, trophyInfoDock); + expandButton = new QPushButton(">>", this); + expandButton->setGeometry(80, 0, 27, 27); + expandButton->hide(); + + connect(expandButton, &QPushButton::clicked, this, [this, trophyInfoDock] { + trophyInfoDock->setVisible(true); + expandButton->hide(); + }); + // Connects checkbox signals to update trophy display #if (QT_VERSION < QT_VERSION_CHECK(6, 7, 0)) connect(showEarnedCheck, &QCheckBox::stateChanged, this, &TrophyViewer::updateTableFilters); @@ -173,6 +183,31 @@ TrophyViewer::TrophyViewer(QString trophyPath, QString gameTrpPath) : QMainWindo updateTrophyInfo(); updateTableFilters(); + + connect(trophyInfoDock, &QDockWidget::topLevelChanged, this, [this, trophyInfoDock] { + if (!trophyInfoDock->isVisible()) { + expandButton->show(); + } + }); + + connect(trophyInfoDock, &QDockWidget::visibilityChanged, this, [this, trophyInfoDock] { + if (!trophyInfoDock->isVisible()) { + expandButton->show(); + } else { + expandButton->hide(); + } + }); +} + +void TrophyViewer::onDockClosed() { + if (!trophyInfoDock->isVisible()) { + reopenButton->setVisible(true); + } +} + +void TrophyViewer::reopenLeftDock() { + trophyInfoDock->show(); + reopenButton->setVisible(false); } void TrophyViewer::PopulateTrophyWidget(QString title) { @@ -354,7 +389,10 @@ void TrophyViewer::PopulateTrophyWidget(QString title) { tabWidget->addTab(tableWidget, tabName.insert(6, " ").replace(0, 1, tabName.at(0).toUpper())); - this->showMaximized(); + 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); diff --git a/src/qt_gui/trophy_viewer.h b/src/qt_gui/trophy_viewer.h index bd99e1a8c..75fb500e7 100644 --- a/src/qt_gui/trophy_viewer.h +++ b/src/qt_gui/trophy_viewer.h @@ -4,12 +4,15 @@ #pragma once #include +#include #include +#include #include #include #include #include #include +#include #include #include #include @@ -26,6 +29,8 @@ public: void updateTrophyInfo(); void updateTableFilters(); + void onDockClosed(); + void reopenLeftDock(); private: void PopulateTrophyWidget(QString title); @@ -39,6 +44,9 @@ private: QCheckBox* showEarnedCheck; QCheckBox* showNotEarnedCheck; QCheckBox* showHiddenCheck; + QPushButton* expandButton; + QDockWidget* trophyInfoDock; + QPushButton* reopenButton; std::string GetTrpType(const QChar trp_) { switch (trp_.toLatin1()) {