shadPS4/src/qt_gui/gui_context_menus.h

536 lines
22 KiB
C
Raw Normal View History

// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
2024-08-19 04:25:15 +00:00
#include <QClipboard>
#include <QDesktopServices>
#include <QMenu>
#include <QMessageBox>
#include <QTreeWidget>
#include <QTreeWidgetItem>
Cheats/Patches (#493) * Cheats/Patches Adds the possibility of applying cheats/patches according to the specific game serial+version The logic for adding modifications has not yet been implemented! Interface based on issues/372 https://github.com/shadps4-emu/shadPS4/issues/372 [X]Front-end []Back-end Create a synchronized fork of the cheats/patches repository * Clang Format * separate files The code has been separated into separate files as suggested by georgemoralis. Added the Patch tab, which has not been implemented yet. Added the 'applyCheat' area to apply the modification, not implemented yet... And added LOG_INFO. * reuse * initial implementation of cheat functionality * Update cheats_patches.cpp sets all added buttons to the size of the largest button. and fixes some aesthetic issues. * move eboot_address to module.h fixes the non-qt builds and makes more sense to be there anyway * Patchs menu and fixes adds the possibility to download Patches, it does not modify the memory yet. and some other fixes * MemoryPatcher namespace, activate cheats on start * format * initial patch implementation * format * format again... * convertValueToHex * Fixes Choosing which cheat file to use. And some other fixes * fix bytes16, bytes32, bytes64 type patches If a patch is any of these types we convert it from little endian to big endian * format * format again :( * Implement pattern scanning for mask type patches * add check to stop patches applying to wrong game previously if you added a patch to a game, but closed the window and opened a different game it would still try to apply the patch, this is now fixed * format * Fix 'Hint' 0x400000 | and Author * Management |save checkbox | shadps4 repository MENU - Cheats/Patches Management (implementing Patches) save patches checkbox add shadps4 repository * Load saved patches, miscellaneous fixes * Fix an issue with mask patches not being saved * format + remove debug log * multiple patches | TR translation for cheats/patches * clang * ENABLE_QT_GUI * OK * move memory_patcher to qt_gui * clang * add cheats hu_HU * fix log * Remove the item from the patchesListView if no patches were added (the game has patches, but not for the current version) --------- Co-authored-by: CrazyBloo <CrazyBloo@users.noreply.github.com>
2024-08-29 04:18:50 +00:00
#include "cheats_patches.h"
#include "common/config.h"
#include "common/version.h"
#include "compatibility_info.h"
#include "game_info.h"
#include "trophy_viewer.h"
#ifdef Q_OS_WIN
#include <ShlObj.h>
#include <Windows.h>
#include <objbase.h>
#include <shlguid.h>
#include <shobjidl.h>
#include <wrl/client.h>
#endif
Cheats/Patches (#493) * Cheats/Patches Adds the possibility of applying cheats/patches according to the specific game serial+version The logic for adding modifications has not yet been implemented! Interface based on issues/372 https://github.com/shadps4-emu/shadPS4/issues/372 [X]Front-end []Back-end Create a synchronized fork of the cheats/patches repository * Clang Format * separate files The code has been separated into separate files as suggested by georgemoralis. Added the Patch tab, which has not been implemented yet. Added the 'applyCheat' area to apply the modification, not implemented yet... And added LOG_INFO. * reuse * initial implementation of cheat functionality * Update cheats_patches.cpp sets all added buttons to the size of the largest button. and fixes some aesthetic issues. * move eboot_address to module.h fixes the non-qt builds and makes more sense to be there anyway * Patchs menu and fixes adds the possibility to download Patches, it does not modify the memory yet. and some other fixes * MemoryPatcher namespace, activate cheats on start * format * initial patch implementation * format * format again... * convertValueToHex * Fixes Choosing which cheat file to use. And some other fixes * fix bytes16, bytes32, bytes64 type patches If a patch is any of these types we convert it from little endian to big endian * format * format again :( * Implement pattern scanning for mask type patches * add check to stop patches applying to wrong game previously if you added a patch to a game, but closed the window and opened a different game it would still try to apply the patch, this is now fixed * format * Fix 'Hint' 0x400000 | and Author * Management |save checkbox | shadps4 repository MENU - Cheats/Patches Management (implementing Patches) save patches checkbox add shadps4 repository * Load saved patches, miscellaneous fixes * Fix an issue with mask patches not being saved * format + remove debug log * multiple patches | TR translation for cheats/patches * clang * ENABLE_QT_GUI * OK * move memory_patcher to qt_gui * clang * add cheats hu_HU * fix log * Remove the item from the patchesListView if no patches were added (the game has patches, but not for the current version) --------- Co-authored-by: CrazyBloo <CrazyBloo@users.noreply.github.com>
2024-08-29 04:18:50 +00:00
#include "common/path_util.h"
class GuiContextMenus : public QObject {
Q_OBJECT
public:
void RequestGameMenu(const QPoint& pos, QVector<GameInfo> m_games,
std::shared_ptr<CompatibilityInfoClass> m_compat_info,
QTableWidget* widget, bool isList) {
QPoint global_pos = widget->viewport()->mapToGlobal(pos);
int itemID = 0;
if (isList) {
itemID = widget->currentRow();
} else {
itemID = widget->currentRow() * widget->columnCount() + widget->currentColumn();
}
Cheats/Patches (#493) * Cheats/Patches Adds the possibility of applying cheats/patches according to the specific game serial+version The logic for adding modifications has not yet been implemented! Interface based on issues/372 https://github.com/shadps4-emu/shadPS4/issues/372 [X]Front-end []Back-end Create a synchronized fork of the cheats/patches repository * Clang Format * separate files The code has been separated into separate files as suggested by georgemoralis. Added the Patch tab, which has not been implemented yet. Added the 'applyCheat' area to apply the modification, not implemented yet... And added LOG_INFO. * reuse * initial implementation of cheat functionality * Update cheats_patches.cpp sets all added buttons to the size of the largest button. and fixes some aesthetic issues. * move eboot_address to module.h fixes the non-qt builds and makes more sense to be there anyway * Patchs menu and fixes adds the possibility to download Patches, it does not modify the memory yet. and some other fixes * MemoryPatcher namespace, activate cheats on start * format * initial patch implementation * format * format again... * convertValueToHex * Fixes Choosing which cheat file to use. And some other fixes * fix bytes16, bytes32, bytes64 type patches If a patch is any of these types we convert it from little endian to big endian * format * format again :( * Implement pattern scanning for mask type patches * add check to stop patches applying to wrong game previously if you added a patch to a game, but closed the window and opened a different game it would still try to apply the patch, this is now fixed * format * Fix 'Hint' 0x400000 | and Author * Management |save checkbox | shadps4 repository MENU - Cheats/Patches Management (implementing Patches) save patches checkbox add shadps4 repository * Load saved patches, miscellaneous fixes * Fix an issue with mask patches not being saved * format + remove debug log * multiple patches | TR translation for cheats/patches * clang * ENABLE_QT_GUI * OK * move memory_patcher to qt_gui * clang * add cheats hu_HU * fix log * Remove the item from the patchesListView if no patches were added (the game has patches, but not for the current version) --------- Co-authored-by: CrazyBloo <CrazyBloo@users.noreply.github.com>
2024-08-29 04:18:50 +00:00
// Do not show the menu if an item is selected
if (itemID == -1) {
return;
}
// Setup menu.
QMenu menu(widget);
// "Open Folder..." submenu
QMenu* openFolderMenu = new QMenu(tr("Open Folder..."), widget);
QAction* openGameFolder = new QAction(tr("Open Game Folder"), widget);
QAction* openSaveDataFolder = new QAction(tr("Open Save Data Folder"), widget);
QAction* openLogFolder = new QAction(tr("Open Log Folder"), widget);
openFolderMenu->addAction(openGameFolder);
openFolderMenu->addAction(openSaveDataFolder);
openFolderMenu->addAction(openLogFolder);
menu.addMenu(openFolderMenu);
2024-08-25 08:45:26 +00:00
QAction createShortcut(tr("Create Shortcut"), widget);
Cheats/Patches (#493) * Cheats/Patches Adds the possibility of applying cheats/patches according to the specific game serial+version The logic for adding modifications has not yet been implemented! Interface based on issues/372 https://github.com/shadps4-emu/shadPS4/issues/372 [X]Front-end []Back-end Create a synchronized fork of the cheats/patches repository * Clang Format * separate files The code has been separated into separate files as suggested by georgemoralis. Added the Patch tab, which has not been implemented yet. Added the 'applyCheat' area to apply the modification, not implemented yet... And added LOG_INFO. * reuse * initial implementation of cheat functionality * Update cheats_patches.cpp sets all added buttons to the size of the largest button. and fixes some aesthetic issues. * move eboot_address to module.h fixes the non-qt builds and makes more sense to be there anyway * Patchs menu and fixes adds the possibility to download Patches, it does not modify the memory yet. and some other fixes * MemoryPatcher namespace, activate cheats on start * format * initial patch implementation * format * format again... * convertValueToHex * Fixes Choosing which cheat file to use. And some other fixes * fix bytes16, bytes32, bytes64 type patches If a patch is any of these types we convert it from little endian to big endian * format * format again :( * Implement pattern scanning for mask type patches * add check to stop patches applying to wrong game previously if you added a patch to a game, but closed the window and opened a different game it would still try to apply the patch, this is now fixed * format * Fix 'Hint' 0x400000 | and Author * Management |save checkbox | shadps4 repository MENU - Cheats/Patches Management (implementing Patches) save patches checkbox add shadps4 repository * Load saved patches, miscellaneous fixes * Fix an issue with mask patches not being saved * format + remove debug log * multiple patches | TR translation for cheats/patches * clang * ENABLE_QT_GUI * OK * move memory_patcher to qt_gui * clang * add cheats hu_HU * fix log * Remove the item from the patchesListView if no patches were added (the game has patches, but not for the current version) --------- Co-authored-by: CrazyBloo <CrazyBloo@users.noreply.github.com>
2024-08-29 04:18:50 +00:00
QAction openCheats(tr("Cheats / Patches"), widget);
2024-08-25 08:45:26 +00:00
QAction openSfoViewer(tr("SFO Viewer"), widget);
QAction openTrophyViewer(tr("Trophy Viewer"), widget);
menu.addAction(&createShortcut);
Cheats/Patches (#493) * Cheats/Patches Adds the possibility of applying cheats/patches according to the specific game serial+version The logic for adding modifications has not yet been implemented! Interface based on issues/372 https://github.com/shadps4-emu/shadPS4/issues/372 [X]Front-end []Back-end Create a synchronized fork of the cheats/patches repository * Clang Format * separate files The code has been separated into separate files as suggested by georgemoralis. Added the Patch tab, which has not been implemented yet. Added the 'applyCheat' area to apply the modification, not implemented yet... And added LOG_INFO. * reuse * initial implementation of cheat functionality * Update cheats_patches.cpp sets all added buttons to the size of the largest button. and fixes some aesthetic issues. * move eboot_address to module.h fixes the non-qt builds and makes more sense to be there anyway * Patchs menu and fixes adds the possibility to download Patches, it does not modify the memory yet. and some other fixes * MemoryPatcher namespace, activate cheats on start * format * initial patch implementation * format * format again... * convertValueToHex * Fixes Choosing which cheat file to use. And some other fixes * fix bytes16, bytes32, bytes64 type patches If a patch is any of these types we convert it from little endian to big endian * format * format again :( * Implement pattern scanning for mask type patches * add check to stop patches applying to wrong game previously if you added a patch to a game, but closed the window and opened a different game it would still try to apply the patch, this is now fixed * format * Fix 'Hint' 0x400000 | and Author * Management |save checkbox | shadps4 repository MENU - Cheats/Patches Management (implementing Patches) save patches checkbox add shadps4 repository * Load saved patches, miscellaneous fixes * Fix an issue with mask patches not being saved * format + remove debug log * multiple patches | TR translation for cheats/patches * clang * ENABLE_QT_GUI * OK * move memory_patcher to qt_gui * clang * add cheats hu_HU * fix log * Remove the item from the patchesListView if no patches were added (the game has patches, but not for the current version) --------- Co-authored-by: CrazyBloo <CrazyBloo@users.noreply.github.com>
2024-08-29 04:18:50 +00:00
menu.addAction(&openCheats);
menu.addAction(&openSfoViewer);
menu.addAction(&openTrophyViewer);
2024-08-19 04:25:15 +00:00
// "Copy" submenu.
QMenu* copyMenu = new QMenu(tr("Copy info..."), widget);
2024-08-25 08:45:26 +00:00
QAction* copyName = new QAction(tr("Copy Name"), widget);
QAction* copySerial = new QAction(tr("Copy Serial"), widget);
QAction* copyNameAll = new QAction(tr("Copy All"), widget);
2024-08-19 04:25:15 +00:00
copyMenu->addAction(copyName);
copyMenu->addAction(copySerial);
copyMenu->addAction(copyNameAll);
menu.addMenu(copyMenu);
// "Delete..." submenu.
QMenu* deleteMenu = new QMenu(tr("Delete..."), widget);
QAction* deleteGame = new QAction(tr("Delete Game"), widget);
QAction* deleteUpdate = new QAction(tr("Delete Update"), widget);
QAction* deleteDLC = new QAction(tr("Delete DLC"), widget);
deleteMenu->addAction(deleteGame);
deleteMenu->addAction(deleteUpdate);
deleteMenu->addAction(deleteDLC);
menu.addMenu(deleteMenu);
// Compatibility submenu.
QMenu* compatibilityMenu = new QMenu(tr("Compatibility..."), widget);
QAction* updateCompatibility = new QAction(tr("Update database"), widget);
QAction* viewCompatibilityReport = new QAction(tr("View report"), widget);
QAction* submitCompatibilityReport = new QAction(tr("Submit a report"), widget);
compatibilityMenu->addAction(updateCompatibility);
compatibilityMenu->addAction(viewCompatibilityReport);
compatibilityMenu->addAction(submitCompatibilityReport);
menu.addMenu(compatibilityMenu);
compatibilityMenu->setEnabled(Config::getCompatibilityEnabled());
viewCompatibilityReport->setEnabled(!m_games[itemID].compatibility.url.isEmpty());
// Show menu.
auto selected = menu.exec(global_pos);
if (!selected) {
return;
}
if (selected == openGameFolder) {
QString folderPath;
Common::FS::PathToQString(folderPath, m_games[itemID].path);
QDesktopServices::openUrl(QUrl::fromLocalFile(folderPath));
}
if (selected == openSaveDataFolder) {
QString userPath;
Common::FS::PathToQString(userPath,
Common::FS::GetUserPath(Common::FS::PathType::UserDir));
QString saveDataPath =
userPath + "/savedata/1/" + QString::fromStdString(m_games[itemID].serial);
QDir(saveDataPath).mkpath(saveDataPath);
QDesktopServices::openUrl(QUrl::fromLocalFile(saveDataPath));
}
if (selected == openLogFolder) {
QString userPath;
Common::FS::PathToQString(userPath,
Common::FS::GetUserPath(Common::FS::PathType::UserDir));
QDesktopServices::openUrl(QUrl::fromLocalFile(userPath + "/log"));
}
if (selected == &openSfoViewer) {
PSF psf;
std::filesystem::path game_folder_path = m_games[itemID].path;
std::filesystem::path game_update_path = game_folder_path;
game_update_path += "UPDATE";
if (std::filesystem::exists(game_update_path)) {
game_folder_path = game_update_path;
}
if (psf.Open(game_folder_path / "sce_sys" / "param.sfo")) {
int rows = psf.GetEntries().size();
QTableWidget* tableWidget = new QTableWidget(rows, 2);
tableWidget->setAttribute(Qt::WA_DeleteOnClose);
connect(widget->parent(), &QWidget::destroyed, tableWidget,
[tableWidget]() { tableWidget->deleteLater(); });
tableWidget->verticalHeader()->setVisible(false); // Hide vertical header
int row = 0;
for (const auto& entry : psf.GetEntries()) {
QTableWidgetItem* keyItem =
new QTableWidgetItem(QString::fromStdString(entry.key));
QTableWidgetItem* valueItem;
switch (entry.param_fmt) {
case PSFEntryFmt::Binary: {
const auto bin = psf.GetBinary(entry.key);
if (!bin.has_value()) {
valueItem = new QTableWidgetItem(QString("Unknown"));
} else {
std::string text;
text.reserve(bin->size() * 2);
for (const auto& c : *bin) {
static constexpr char hex[] = "0123456789ABCDEF";
text.push_back(hex[c >> 4 & 0xF]);
text.push_back(hex[c & 0xF]);
}
valueItem = new QTableWidgetItem(QString::fromStdString(text));
}
} break;
case PSFEntryFmt::Text: {
auto text = psf.GetString(entry.key);
if (!text.has_value()) {
valueItem = new QTableWidgetItem(QString("Unknown"));
} else {
valueItem =
new QTableWidgetItem(QString::fromStdString(std::string{*text}));
}
} break;
case PSFEntryFmt::Integer: {
auto integer = psf.GetInteger(entry.key);
if (!integer.has_value()) {
valueItem = new QTableWidgetItem(QString("Unknown"));
} else {
valueItem =
new QTableWidgetItem(QString("0x") + QString::number(*integer, 16));
}
} break;
}
tableWidget->setItem(row, 0, keyItem);
tableWidget->setItem(row, 1, valueItem);
keyItem->setFlags(keyItem->flags() & ~Qt::ItemIsEditable);
valueItem->setFlags(valueItem->flags() & ~Qt::ItemIsEditable);
row++;
}
tableWidget->resizeColumnsToContents();
tableWidget->resizeRowsToContents();
int width = tableWidget->horizontalHeader()->sectionSize(0) +
tableWidget->horizontalHeader()->sectionSize(1) + 2;
int height = (rows + 1) * (tableWidget->rowHeight(0));
tableWidget->setFixedSize(width, height);
tableWidget->sortItems(0, Qt::AscendingOrder);
tableWidget->horizontalHeader()->setVisible(false);
tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);
2024-08-25 08:45:26 +00:00
tableWidget->setWindowTitle(tr("SFO Viewer"));
tableWidget->show();
}
}
Cheats/Patches (#493) * Cheats/Patches Adds the possibility of applying cheats/patches according to the specific game serial+version The logic for adding modifications has not yet been implemented! Interface based on issues/372 https://github.com/shadps4-emu/shadPS4/issues/372 [X]Front-end []Back-end Create a synchronized fork of the cheats/patches repository * Clang Format * separate files The code has been separated into separate files as suggested by georgemoralis. Added the Patch tab, which has not been implemented yet. Added the 'applyCheat' area to apply the modification, not implemented yet... And added LOG_INFO. * reuse * initial implementation of cheat functionality * Update cheats_patches.cpp sets all added buttons to the size of the largest button. and fixes some aesthetic issues. * move eboot_address to module.h fixes the non-qt builds and makes more sense to be there anyway * Patchs menu and fixes adds the possibility to download Patches, it does not modify the memory yet. and some other fixes * MemoryPatcher namespace, activate cheats on start * format * initial patch implementation * format * format again... * convertValueToHex * Fixes Choosing which cheat file to use. And some other fixes * fix bytes16, bytes32, bytes64 type patches If a patch is any of these types we convert it from little endian to big endian * format * format again :( * Implement pattern scanning for mask type patches * add check to stop patches applying to wrong game previously if you added a patch to a game, but closed the window and opened a different game it would still try to apply the patch, this is now fixed * format * Fix 'Hint' 0x400000 | and Author * Management |save checkbox | shadps4 repository MENU - Cheats/Patches Management (implementing Patches) save patches checkbox add shadps4 repository * Load saved patches, miscellaneous fixes * Fix an issue with mask patches not being saved * format + remove debug log * multiple patches | TR translation for cheats/patches * clang * ENABLE_QT_GUI * OK * move memory_patcher to qt_gui * clang * add cheats hu_HU * fix log * Remove the item from the patchesListView if no patches were added (the game has patches, but not for the current version) --------- Co-authored-by: CrazyBloo <CrazyBloo@users.noreply.github.com>
2024-08-29 04:18:50 +00:00
if (selected == &openCheats) {
QString gameName = QString::fromStdString(m_games[itemID].name);
QString gameSerial = QString::fromStdString(m_games[itemID].serial);
QString gameVersion = QString::fromStdString(m_games[itemID].version);
QString gameSize = QString::fromStdString(m_games[itemID].size);
QString iconPath;
Common::FS::PathToQString(iconPath, m_games[itemID].icon_path);
QPixmap gameImage(iconPath);
Cheats/Patches (#493) * Cheats/Patches Adds the possibility of applying cheats/patches according to the specific game serial+version The logic for adding modifications has not yet been implemented! Interface based on issues/372 https://github.com/shadps4-emu/shadPS4/issues/372 [X]Front-end []Back-end Create a synchronized fork of the cheats/patches repository * Clang Format * separate files The code has been separated into separate files as suggested by georgemoralis. Added the Patch tab, which has not been implemented yet. Added the 'applyCheat' area to apply the modification, not implemented yet... And added LOG_INFO. * reuse * initial implementation of cheat functionality * Update cheats_patches.cpp sets all added buttons to the size of the largest button. and fixes some aesthetic issues. * move eboot_address to module.h fixes the non-qt builds and makes more sense to be there anyway * Patchs menu and fixes adds the possibility to download Patches, it does not modify the memory yet. and some other fixes * MemoryPatcher namespace, activate cheats on start * format * initial patch implementation * format * format again... * convertValueToHex * Fixes Choosing which cheat file to use. And some other fixes * fix bytes16, bytes32, bytes64 type patches If a patch is any of these types we convert it from little endian to big endian * format * format again :( * Implement pattern scanning for mask type patches * add check to stop patches applying to wrong game previously if you added a patch to a game, but closed the window and opened a different game it would still try to apply the patch, this is now fixed * format * Fix 'Hint' 0x400000 | and Author * Management |save checkbox | shadps4 repository MENU - Cheats/Patches Management (implementing Patches) save patches checkbox add shadps4 repository * Load saved patches, miscellaneous fixes * Fix an issue with mask patches not being saved * format + remove debug log * multiple patches | TR translation for cheats/patches * clang * ENABLE_QT_GUI * OK * move memory_patcher to qt_gui * clang * add cheats hu_HU * fix log * Remove the item from the patchesListView if no patches were added (the game has patches, but not for the current version) --------- Co-authored-by: CrazyBloo <CrazyBloo@users.noreply.github.com>
2024-08-29 04:18:50 +00:00
CheatsPatches* cheatsPatches =
new CheatsPatches(gameName, gameSerial, gameVersion, gameSize, gameImage);
cheatsPatches->show();
connect(widget->parent(), &QWidget::destroyed, cheatsPatches,
2024-08-30 13:48:21 +00:00
[cheatsPatches]() { cheatsPatches->deleteLater(); });
Cheats/Patches (#493) * Cheats/Patches Adds the possibility of applying cheats/patches according to the specific game serial+version The logic for adding modifications has not yet been implemented! Interface based on issues/372 https://github.com/shadps4-emu/shadPS4/issues/372 [X]Front-end []Back-end Create a synchronized fork of the cheats/patches repository * Clang Format * separate files The code has been separated into separate files as suggested by georgemoralis. Added the Patch tab, which has not been implemented yet. Added the 'applyCheat' area to apply the modification, not implemented yet... And added LOG_INFO. * reuse * initial implementation of cheat functionality * Update cheats_patches.cpp sets all added buttons to the size of the largest button. and fixes some aesthetic issues. * move eboot_address to module.h fixes the non-qt builds and makes more sense to be there anyway * Patchs menu and fixes adds the possibility to download Patches, it does not modify the memory yet. and some other fixes * MemoryPatcher namespace, activate cheats on start * format * initial patch implementation * format * format again... * convertValueToHex * Fixes Choosing which cheat file to use. And some other fixes * fix bytes16, bytes32, bytes64 type patches If a patch is any of these types we convert it from little endian to big endian * format * format again :( * Implement pattern scanning for mask type patches * add check to stop patches applying to wrong game previously if you added a patch to a game, but closed the window and opened a different game it would still try to apply the patch, this is now fixed * format * Fix 'Hint' 0x400000 | and Author * Management |save checkbox | shadps4 repository MENU - Cheats/Patches Management (implementing Patches) save patches checkbox add shadps4 repository * Load saved patches, miscellaneous fixes * Fix an issue with mask patches not being saved * format + remove debug log * multiple patches | TR translation for cheats/patches * clang * ENABLE_QT_GUI * OK * move memory_patcher to qt_gui * clang * add cheats hu_HU * fix log * Remove the item from the patchesListView if no patches were added (the game has patches, but not for the current version) --------- Co-authored-by: CrazyBloo <CrazyBloo@users.noreply.github.com>
2024-08-29 04:18:50 +00:00
}
if (selected == &openTrophyViewer) {
QString trophyPath, gameTrpPath;
Common::FS::PathToQString(trophyPath, m_games[itemID].serial);
Common::FS::PathToQString(gameTrpPath, m_games[itemID].path);
TrophyViewer* trophyViewer = new TrophyViewer(trophyPath, gameTrpPath);
trophyViewer->show();
connect(widget->parent(), &QWidget::destroyed, trophyViewer,
[trophyViewer]() { trophyViewer->deleteLater(); });
}
if (selected == &createShortcut) {
QString targetPath;
Common::FS::PathToQString(targetPath, m_games[itemID].path);
QString ebootPath = targetPath + "/eboot.bin";
// Get the full path to the icon
QString iconPath;
Common::FS::PathToQString(iconPath, m_games[itemID].icon_path);
QFileInfo iconFileInfo(iconPath);
QString icoPath = iconFileInfo.absolutePath() + "/" + iconFileInfo.baseName() + ".ico";
// Path to shortcut/link
QString linkPath;
// Path to the shadps4.exe executable
QString exePath;
#ifdef Q_OS_WIN
linkPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation) + "/" +
QString::fromStdString(m_games[itemID].name)
.remove(QRegularExpression("[\\\\/:*?\"<>|]")) +
".lnk";
exePath = QCoreApplication::applicationFilePath().replace("\\", "/");
#else
linkPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation) + "/" +
QString::fromStdString(m_games[itemID].name)
.remove(QRegularExpression("[\\\\/:*?\"<>|]")) +
".desktop";
#endif
// Convert the icon to .ico if necessary
if (iconFileInfo.suffix().toLower() == "png") {
// Convert icon from PNG to ICO
if (convertPngToIco(iconPath, icoPath)) {
#ifdef Q_OS_WIN
if (createShortcutWin(linkPath, ebootPath, icoPath, exePath)) {
#else
if (createShortcutLinux(linkPath, ebootPath, iconPath)) {
#endif
QMessageBox::information(
2024-08-25 08:45:26 +00:00
nullptr, tr("Shortcut creation"),
2024-12-27 11:54:31 +00:00
QString(tr("Shortcut created successfully!") + "\n%1").arg(linkPath));
} else {
QMessageBox::critical(
2024-08-25 08:45:26 +00:00
nullptr, tr("Error"),
2024-12-27 11:54:31 +00:00
QString(tr("Error creating shortcut!") + "\n%1").arg(linkPath));
}
} else {
2024-08-25 08:45:26 +00:00
QMessageBox::critical(nullptr, tr("Error"), tr("Failed to convert icon."));
}
} else {
// If the icon is already in ICO format, we just create the shortcut
#ifdef Q_OS_WIN
if (createShortcutWin(linkPath, ebootPath, iconPath, exePath)) {
#else
if (createShortcutLinux(linkPath, ebootPath, iconPath)) {
#endif
QMessageBox::information(
2024-08-25 08:45:26 +00:00
nullptr, tr("Shortcut creation"),
2024-12-27 11:54:31 +00:00
QString(tr("Shortcut created successfully!") + "\n%1").arg(linkPath));
} else {
2024-08-25 08:45:26 +00:00
QMessageBox::critical(
nullptr, tr("Error"),
2024-12-27 11:54:31 +00:00
QString(tr("Error creating shortcut!") + "\n%1").arg(linkPath));
}
}
}
2024-08-19 04:25:15 +00:00
// Handle the "Copy" actions
if (selected == copyName) {
QClipboard* clipboard = QGuiApplication::clipboard();
clipboard->setText(QString::fromStdString(m_games[itemID].name));
}
if (selected == copySerial) {
QClipboard* clipboard = QGuiApplication::clipboard();
clipboard->setText(QString::fromStdString(m_games[itemID].serial));
}
if (selected == copyNameAll) {
QClipboard* clipboard = QGuiApplication::clipboard();
QString combinedText = QString("Name:%1 | Serial:%2 | Version:%3 | Size:%4")
.arg(QString::fromStdString(m_games[itemID].name))
.arg(QString::fromStdString(m_games[itemID].serial))
.arg(QString::fromStdString(m_games[itemID].version))
.arg(QString::fromStdString(m_games[itemID].size));
clipboard->setText(combinedText);
}
if (selected == deleteGame || selected == deleteUpdate || selected == deleteDLC) {
bool error = false;
QString folder_path, game_update_path, dlc_path;
Common::FS::PathToQString(folder_path, m_games[itemID].path);
game_update_path = folder_path + "-UPDATE";
Common::FS::PathToQString(
dlc_path, Config::getAddonInstallDir() /
Common::FS::PathFromQString(folder_path).parent_path().filename());
QString message_type = tr("Game");
if (selected == deleteUpdate) {
if (!std::filesystem::exists(Common::FS::PathFromQString(game_update_path))) {
2024-12-28 10:49:44 +00:00
QMessageBox::critical(nullptr, tr("Error"),
QString(tr("This game has no update to delete!")));
error = true;
} else {
folder_path = game_update_path;
message_type = tr("Update");
}
} else if (selected == deleteDLC) {
if (!std::filesystem::exists(Common::FS::PathFromQString(dlc_path))) {
QMessageBox::critical(nullptr, tr("Error"),
QString(tr("This game has no DLC to delete!")));
error = true;
} else {
folder_path = dlc_path;
message_type = tr("DLC");
}
}
if (!error) {
QString gameName = QString::fromStdString(m_games[itemID].name);
QDir dir(folder_path);
QMessageBox::StandardButton reply = QMessageBox::question(
nullptr, QString(tr("Delete %1")).arg(message_type),
QString(tr("Are you sure you want to delete %1's %2 directory?"))
.arg(gameName, message_type),
QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) {
dir.removeRecursively();
widget->removeRow(itemID);
}
}
}
if (selected == updateCompatibility) {
m_compat_info->UpdateCompatibilityDatabase(widget, true);
}
if (selected == viewCompatibilityReport) {
if (!m_games[itemID].compatibility.url.isEmpty())
QDesktopServices::openUrl(QUrl(m_games[itemID].compatibility.url));
}
if (selected == submitCompatibilityReport) {
QUrl url = QUrl("https://github.com/shadps4-emu/shadps4-game-compatibility/issues/new");
QUrlQuery query;
query.addQueryItem("template", QString("game_compatibility.yml"));
query.addQueryItem(
"title", QString("%1 - %2").arg(QString::fromStdString(m_games[itemID].serial),
QString::fromStdString(m_games[itemID].name)));
query.addQueryItem("game-name", QString::fromStdString(m_games[itemID].name));
query.addQueryItem("game-code", QString::fromStdString(m_games[itemID].serial));
query.addQueryItem("game-version", QString::fromStdString(m_games[itemID].version));
query.addQueryItem("emulator-version", QString(Common::VERSION));
url.setQuery(query);
QDesktopServices::openUrl(url);
}
}
int GetRowIndex(QTreeWidget* treeWidget, QTreeWidgetItem* item) {
int row = 0;
for (int i = 0; i < treeWidget->topLevelItemCount(); i++) { // check top level/parent items
QTreeWidgetItem* currentItem = treeWidget->topLevelItem(i);
if (currentItem == item) {
return row;
}
row++;
if (currentItem->childCount() > 0) { // check child items
for (int j = 0; j < currentItem->childCount(); j++) {
QTreeWidgetItem* childItem = currentItem->child(j);
if (childItem == item) {
return row;
}
row++;
}
}
}
return -1;
}
void RequestGameMenuPKGViewer(
const QPoint& pos, QStringList m_pkg_app_list, QTreeWidget* treeWidget,
std::function<void(std::filesystem::path, int, int)> InstallDragDropPkg) {
QPoint global_pos = treeWidget->viewport()->mapToGlobal(pos); // context menu position
QTreeWidgetItem* currentItem = treeWidget->currentItem(); // current clicked item
int itemIndex = GetRowIndex(treeWidget, currentItem); // row
QMenu menu(treeWidget);
2024-08-25 08:45:26 +00:00
QAction installPackage(tr("Install PKG"), treeWidget);
menu.addAction(&installPackage);
auto selected = menu.exec(global_pos);
if (!selected) {
return;
}
if (selected == &installPackage) {
QStringList pkg_app_ = m_pkg_app_list[itemIndex].split(";;");
std::filesystem::path path = Common::FS::PathFromQString(pkg_app_[9]);
InstallDragDropPkg(path, 1, 1);
}
}
private:
bool convertPngToIco(const QString& pngFilePath, const QString& icoFilePath) {
// Load the PNG image
QImage image(pngFilePath);
if (image.isNull()) {
return false;
}
// Scale the image to the default icon size (256x256 pixels)
QImage scaledImage =
image.scaled(QSize(256, 256), Qt::KeepAspectRatio, Qt::SmoothTransformation);
// Convert the image to QPixmap
QPixmap pixmap = QPixmap::fromImage(scaledImage);
// Save the pixmap as an ICO file
if (pixmap.save(icoFilePath, "ICO")) {
return true;
} else {
return false;
}
}
#ifdef Q_OS_WIN
bool createShortcutWin(const QString& linkPath, const QString& targetPath,
const QString& iconPath, const QString& exePath) {
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
// Create the ShellLink object
Microsoft::WRL::ComPtr<IShellLink> pShellLink;
HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&pShellLink));
if (SUCCEEDED(hres)) {
// Defines the path to the program executable
pShellLink->SetPath((LPCWSTR)exePath.utf16());
// Sets the home directory ("Start in")
pShellLink->SetWorkingDirectory((LPCWSTR)QFileInfo(exePath).absolutePath().utf16());
// Set arguments, eboot.bin file location
2024-11-25 12:26:56 +00:00
QString arguments = QString("-g \"%1\"").arg(targetPath);
pShellLink->SetArguments((LPCWSTR)arguments.utf16());
// Set the icon for the shortcut
pShellLink->SetIconLocation((LPCWSTR)iconPath.utf16(), 0);
// Save the shortcut
Microsoft::WRL::ComPtr<IPersistFile> pPersistFile;
hres = pShellLink.As(&pPersistFile);
if (SUCCEEDED(hres)) {
hres = pPersistFile->Save((LPCWSTR)linkPath.utf16(), TRUE);
}
}
CoUninitialize();
return SUCCEEDED(hres);
}
#else
bool createShortcutLinux(const QString& linkPath, const QString& targetPath,
const QString& iconPath) {
QFile shortcutFile(linkPath);
if (!shortcutFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
QMessageBox::critical(nullptr, "Error",
QString("Error creating shortcut!\n %1").arg(linkPath));
return false;
}
QTextStream out(&shortcutFile);
out << "[Desktop Entry]\n";
out << "Version=1.0\n";
2024-07-06 18:10:28 +00:00
out << "Name=" << QFileInfo(linkPath).baseName() << "\n";
2024-07-06 16:40:26 +00:00
out << "Exec=" << QCoreApplication::applicationFilePath() << " \"" << targetPath << "\"\n";
2024-07-06 16:42:53 +00:00
out << "Icon=" << iconPath << "\n";
out << "Terminal=false\n";
out << "Type=Application\n";
shortcutFile.close();
return true;
}
#endif
};