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 <daniel.svoboda@hotmail.com>
This commit is contained in:
Dmugetsu 2025-03-02 13:36:12 -06:00 committed by GitHub
parent f4110c43a7
commit d59536a71c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 158 additions and 36 deletions

View file

@ -53,7 +53,7 @@ static bool isShaderDebug = false;
static bool isShowSplash = false; static bool isShowSplash = false;
static bool isAutoUpdate = false; static bool isAutoUpdate = false;
static bool isAlwaysShowChangelog = false; static bool isAlwaysShowChangelog = false;
static bool isLeftSideTrophy = false; static std::string isSideTrophy = "right";
static bool isNullGpu = false; static bool isNullGpu = false;
static bool shouldCopyGPUBuffers = false; static bool shouldCopyGPUBuffers = false;
static bool shouldDumpShaders = false; static bool shouldDumpShaders = false;
@ -270,8 +270,8 @@ bool alwaysShowChangelog() {
return isAlwaysShowChangelog; return isAlwaysShowChangelog;
} }
bool leftSideTrophy() { std::string sideTrophy() {
return isLeftSideTrophy; return isSideTrophy;
} }
bool nullGpu() { bool nullGpu() {
@ -381,8 +381,9 @@ void setAutoUpdate(bool enable) {
void setAlwaysShowChangelog(bool enable) { void setAlwaysShowChangelog(bool enable) {
isAlwaysShowChangelog = enable; isAlwaysShowChangelog = enable;
} }
void setLeftSideTrophy(bool enable) {
isLeftSideTrophy = enable; void setSideTrophy(std::string side) {
isSideTrophy = side;
} }
void setNullGpu(bool enable) { void setNullGpu(bool enable) {
@ -737,7 +738,7 @@ void load(const std::filesystem::path& path) {
isShowSplash = toml::find_or<bool>(general, "showSplash", true); isShowSplash = toml::find_or<bool>(general, "showSplash", true);
isAutoUpdate = toml::find_or<bool>(general, "autoUpdate", false); isAutoUpdate = toml::find_or<bool>(general, "autoUpdate", false);
isAlwaysShowChangelog = toml::find_or<bool>(general, "alwaysShowChangelog", false); isAlwaysShowChangelog = toml::find_or<bool>(general, "alwaysShowChangelog", false);
isLeftSideTrophy = toml::find_or<bool>(general, "leftSideTrophy", false); isSideTrophy = toml::find_or<std::string>(general, "sideTrophy", "right");
separateupdatefolder = toml::find_or<bool>(general, "separateUpdateEnabled", false); separateupdatefolder = toml::find_or<bool>(general, "separateUpdateEnabled", false);
compatibilityData = toml::find_or<bool>(general, "compatibilityEnabled", false); compatibilityData = toml::find_or<bool>(general, "compatibilityEnabled", false);
checkCompatibilityOnStartup = checkCompatibilityOnStartup =
@ -888,7 +889,7 @@ void save(const std::filesystem::path& path) {
data["General"]["showSplash"] = isShowSplash; data["General"]["showSplash"] = isShowSplash;
data["General"]["autoUpdate"] = isAutoUpdate; data["General"]["autoUpdate"] = isAutoUpdate;
data["General"]["alwaysShowChangelog"] = isAlwaysShowChangelog; data["General"]["alwaysShowChangelog"] = isAlwaysShowChangelog;
data["General"]["leftSideTrophy"] = isLeftSideTrophy; data["General"]["sideTrophy"] = isSideTrophy;
data["General"]["separateUpdateEnabled"] = separateupdatefolder; data["General"]["separateUpdateEnabled"] = separateupdatefolder;
data["General"]["compatibilityEnabled"] = compatibilityData; data["General"]["compatibilityEnabled"] = compatibilityData;
data["General"]["checkCompatibilityOnStartup"] = checkCompatibilityOnStartup; data["General"]["checkCompatibilityOnStartup"] = checkCompatibilityOnStartup;
@ -1018,7 +1019,7 @@ void setDefaultValues() {
isShowSplash = false; isShowSplash = false;
isAutoUpdate = false; isAutoUpdate = false;
isAlwaysShowChangelog = false; isAlwaysShowChangelog = false;
isLeftSideTrophy = false; isSideTrophy = "right";
isNullGpu = false; isNullGpu = false;
shouldDumpShaders = false; shouldDumpShaders = false;
vblankDivider = 1; vblankDivider = 1;

View file

@ -63,7 +63,7 @@ bool collectShadersForDebug();
bool showSplash(); bool showSplash();
bool autoUpdate(); bool autoUpdate();
bool alwaysShowChangelog(); bool alwaysShowChangelog();
bool leftSideTrophy(); std::string sideTrophy();
bool nullGpu(); bool nullGpu();
bool copyGPUCmdBuffers(); bool copyGPUCmdBuffers();
bool dumpShaders(); bool dumpShaders();
@ -77,7 +77,7 @@ void setCollectShaderForDebug(bool enable);
void setShowSplash(bool enable); void setShowSplash(bool enable);
void setAutoUpdate(bool enable); void setAutoUpdate(bool enable);
void setAlwaysShowChangelog(bool enable); void setAlwaysShowChangelog(bool enable);
void setLeftSideTrophy(bool enable); void setSideTrophy(std::string side);
void setNullGpu(bool enable); void setNullGpu(bool enable);
void setAllowHDR(bool enable); void setAllowHDR(bool enable);
void setCopyGPUCmdBuffers(bool enable); void setCopyGPUCmdBuffers(bool enable);

View file

@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <fstream>
#include <unordered_map> #include <unordered_map>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/path_util.h" #include "common/path_util.h"
@ -130,6 +131,21 @@ static auto UserPaths = [] {
create_path(PathType::MetaDataDir, user_dir / METADATA_DIR); create_path(PathType::MetaDataDir, user_dir / METADATA_DIR);
create_path(PathType::CustomTrophy, user_dir / CUSTOM_TROPHY); 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; return paths;
}(); }();

View file

@ -27,14 +27,17 @@ namespace Libraries::NpTrophy {
std::optional<TrophyUI> current_trophy_ui; std::optional<TrophyUI> current_trophy_ui;
std::queue<TrophyInfo> trophy_queue; std::queue<TrophyInfo> trophy_queue;
std::mutex queueMtx; std::mutex queueMtx;
bool isLeftSide;
std::string side = "right";
double trophy_timer; double trophy_timer;
TrophyUI::TrophyUI(const std::filesystem::path& trophyIconPath, const std::string& trophyName, TrophyUI::TrophyUI(const std::filesystem::path& trophyIconPath, const std::string& trophyName,
const std::string_view& rarity) const std::string_view& rarity)
: trophy_name(trophyName), trophy_type(rarity) { : trophy_name(trophyName), trophy_type(rarity) {
isLeftSide = Config::leftSideTrophy(); side = Config::sideTrophy();
trophy_timer = Config::getTrophyNotificationDuration(); trophy_timer = Config::getTrophyNotificationDuration();
if (std::filesystem::exists(trophyIconPath)) { if (std::filesystem::exists(trophyIconPath)) {
@ -115,8 +118,8 @@ float fade_out_duration = 0.5f; // Final fade duration
void TrophyUI::Draw() { void TrophyUI::Draw() {
const auto& io = GetIO(); const auto& io = GetIO();
float AdjustWidth = io.DisplaySize.x / 1280; float AdjustWidth = io.DisplaySize.x / 1920;
float AdjustHeight = io.DisplaySize.y / 720; float AdjustHeight = io.DisplaySize.y / 1080;
const ImVec2 window_size{ const ImVec2 window_size{
std::min(io.DisplaySize.x, (350 * AdjustWidth)), std::min(io.DisplaySize.x, (350 * AdjustWidth)),
std::min(io.DisplaySize.y, (70 * AdjustHeight)), std::min(io.DisplaySize.y, (70 * AdjustHeight)),
@ -125,21 +128,38 @@ void TrophyUI::Draw() {
elapsed_time += io.DeltaTime; elapsed_time += io.DeltaTime;
float progress = std::min(elapsed_time / animation_duration, 1.0f); float progress = std::min(elapsed_time / animation_duration, 1.0f);
// left or right position float final_pos_x, start_x;
float final_pos_x; float final_pos_y, start_y;
if (isLeftSide) {
start_pos.x = -window_size.x; 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; final_pos_x = 20 * AdjustWidth;
} else { final_pos_y = start_y;
start_pos.x = io.DisplaySize.x; } 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_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, ImVec2 current_pos = ImVec2(start_x + (final_pos_x - start_x) * progress,
start_pos.y + (target_pos.y - start_pos.y) * progress); start_y + (final_pos_y - start_y) * progress);
trophy_timer -= io.DeltaTime; 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 the remaining time of the trophy is less than or equal to 1 second, the fade-out begins.
if (trophy_timer <= 1.0f) { if (trophy_timer <= 1.0f) {
float fade_out_time = 1.0f - (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; const float text_height = ImGui::CalcTextSize(combinedString.c_str()).y;
SetCursorPosY((window_size.y - text_height) * 0.5); 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)); ImGui::PushTextWrapPos(window_size.x - (60 * AdjustWidth));
TextWrapped("Trophy earned!\n%s", trophy_name.c_str()); TextWrapped("Trophy earned!\n%s", trophy_name.c_str());
ImGui::SameLine(window_size.x - (60 * AdjustWidth)); ImGui::SameLine(window_size.x - (60 * AdjustWidth));

View file

@ -418,8 +418,14 @@ void SettingsDialog::LoadValuesFromConfig() {
ui->disableTrophycheckBox->setChecked( ui->disableTrophycheckBox->setChecked(
toml::find_or<bool>(data, "General", "isTrophyPopupDisabled", false)); toml::find_or<bool>(data, "General", "isTrophyPopupDisabled", false));
ui->popUpDurationSpinBox->setValue(Config::getTrophyNotificationDuration()); 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<int>(data, "General", "BGMvolume", 50)); ui->BGMVolumeSlider->setValue(toml::find_or<int>(data, "General", "BGMvolume", 50));
ui->discordRPCCheckbox->setChecked( ui->discordRPCCheckbox->setChecked(
toml::find_or<bool>(data, "General", "enableDiscordRPC", true)); toml::find_or<bool>(data, "General", "enableDiscordRPC", true));
@ -612,7 +618,7 @@ void SettingsDialog::updateNoteTextEdit(const QString& elementName) {
//User //User
if (elementName == "OpenCustomTrophyLocationButton") { 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 // Input
@ -706,7 +712,17 @@ void SettingsDialog::UpdateSettings() {
Config::setIsMotionControlsEnabled(ui->motionControlsCheckBox->isChecked()); Config::setIsMotionControlsEnabled(ui->motionControlsCheckBox->isChecked());
Config::setisTrophyPopupDisabled(ui->disableTrophycheckBox->isChecked()); Config::setisTrophyPopupDisabled(ui->disableTrophycheckBox->isChecked());
Config::setTrophyNotificationDuration(ui->popUpDurationSpinBox->value()); 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::setPlayBGM(ui->playBGMCheckBox->isChecked());
Config::setAllowHDR(ui->enableHDRCheckBox->isChecked()); Config::setAllowHDR(ui->enableHDRCheckBox->isChecked());
Config::setLogType(logTypeMap.value(ui->logTypeComboBox->currentText()).toStdString()); Config::setLogType(logTypeMap.value(ui->logTypeComboBox->currentText()).toStdString());

View file

@ -1295,17 +1295,25 @@
</item> </item>
<item> <item>
<widget class="QRadioButton" name="radioButton_Right"> <widget class="QRadioButton" name="radioButton_Right">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text"> <property name="text">
<string>Right</string> <string>Right</string>
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QRadioButton" name="radioButton_Top">
<property name="text">
<string>Top</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButton_Bottom">
<property name="text">
<string>Bottom</string>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
<item> <item>

View file

@ -1632,8 +1632,8 @@
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation> <translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
</message> </message>
<message> <message>
<source>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</source> <source>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.</source>
<translation>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</translation> <translation>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.</translation>
</message> </message>
<message> <message>
<source>Never</source> <source>Never</source>
@ -1839,6 +1839,14 @@
<source>Right</source> <source>Right</source>
<translation>Right</translation> <translation>Right</translation>
</message> </message>
<message>
<source>Top</source>
<translation>Top</translation>
</message>
<message>
<source>Bottom</source>
<translation>Bottom</translation>
</message>
<message> <message>
<source>Notification Duration</source> <source>Notification Duration</source>
<translation>Notification Duration</translation> <translation>Notification Duration</translation>

View file

@ -5,6 +5,7 @@
#include <QCheckBox> #include <QCheckBox>
#include <QDockWidget> #include <QDockWidget>
#include <QMessageBox> #include <QMessageBox>
#include <QPushButton>
#include <cmrc/cmrc.hpp> #include <cmrc/cmrc.hpp>
#include <common/config.h> #include <common/config.h>
#include "common/path_util.h" #include "common/path_util.h"
@ -157,6 +158,15 @@ TrophyViewer::TrophyViewer(QString trophyPath, QString gameTrpPath) : QMainWindo
// Adds the dock to the left area // Adds the dock to the left area
this->addDockWidget(Qt::LeftDockWidgetArea, trophyInfoDock); 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 // Connects checkbox signals to update trophy display
#if (QT_VERSION < QT_VERSION_CHECK(6, 7, 0)) #if (QT_VERSION < QT_VERSION_CHECK(6, 7, 0))
connect(showEarnedCheck, &QCheckBox::stateChanged, this, &TrophyViewer::updateTableFilters); connect(showEarnedCheck, &QCheckBox::stateChanged, this, &TrophyViewer::updateTableFilters);
@ -173,6 +183,31 @@ TrophyViewer::TrophyViewer(QString trophyPath, QString gameTrpPath) : QMainWindo
updateTrophyInfo(); updateTrophyInfo();
updateTableFilters(); 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) { void TrophyViewer::PopulateTrophyWidget(QString title) {
@ -354,7 +389,10 @@ void TrophyViewer::PopulateTrophyWidget(QString title) {
tabWidget->addTab(tableWidget, tabWidget->addTab(tableWidget,
tabName.insert(6, " ").replace(0, 1, tabName.at(0).toUpper())); 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->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed);
tableWidget->setColumnWidth(3, 650); tableWidget->setColumnWidth(3, 650);

View file

@ -4,12 +4,15 @@
#pragma once #pragma once
#include <QApplication> #include <QApplication>
#include <QCheckBox>
#include <QDir> #include <QDir>
#include <QDockWidget>
#include <QFileInfoList> #include <QFileInfoList>
#include <QGraphicsBlurEffect> #include <QGraphicsBlurEffect>
#include <QHeaderView> #include <QHeaderView>
#include <QLabel> #include <QLabel>
#include <QMainWindow> #include <QMainWindow>
#include <QPushButton>
#include <QTableWidget> #include <QTableWidget>
#include <QTableWidgetItem> #include <QTableWidgetItem>
#include <QVBoxLayout> #include <QVBoxLayout>
@ -26,6 +29,8 @@ public:
void updateTrophyInfo(); void updateTrophyInfo();
void updateTableFilters(); void updateTableFilters();
void onDockClosed();
void reopenLeftDock();
private: private:
void PopulateTrophyWidget(QString title); void PopulateTrophyWidget(QString title);
@ -39,6 +44,9 @@ private:
QCheckBox* showEarnedCheck; QCheckBox* showEarnedCheck;
QCheckBox* showNotEarnedCheck; QCheckBox* showNotEarnedCheck;
QCheckBox* showHiddenCheck; QCheckBox* showHiddenCheck;
QPushButton* expandButton;
QDockWidget* trophyInfoDock;
QPushButton* reopenButton;
std::string GetTrpType(const QChar trp_) { std::string GetTrpType(const QChar trp_) {
switch (trp_.toLatin1()) { switch (trp_.toLatin1()) {