mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2024-12-29 11:06:07 +00:00
Multiple Install Folders (#1308)
* multiple install folders implimentation * clang format * paths setting tab * clang format
This commit is contained in:
parent
f834def7ef
commit
ede655875d
|
@ -693,6 +693,8 @@ set(QT_GUI src/qt_gui/about_dialog.cpp
|
|||
src/qt_gui/game_grid_frame.h
|
||||
src/qt_gui/game_install_dialog.cpp
|
||||
src/qt_gui/game_install_dialog.h
|
||||
src/qt_gui/install_dir_select.cpp
|
||||
src/qt_gui/install_dir_select.h
|
||||
src/qt_gui/pkg_viewer.cpp
|
||||
src/qt_gui/pkg_viewer.h
|
||||
src/qt_gui/trophy_viewer.cpp
|
||||
|
|
|
@ -62,7 +62,7 @@ static s16 cursorState = HideCursorState::Idle;
|
|||
static int cursorHideTimeout = 5; // 5 seconds (default)
|
||||
|
||||
// Gui
|
||||
std::filesystem::path settings_install_dir = {};
|
||||
std::vector<std::filesystem::path> settings_install_dirs = {};
|
||||
std::filesystem::path settings_addon_install_dir = {};
|
||||
u32 main_window_geometry_x = 400;
|
||||
u32 main_window_geometry_y = 400;
|
||||
|
@ -325,8 +325,9 @@ void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h) {
|
|||
main_window_geometry_w = w;
|
||||
main_window_geometry_h = h;
|
||||
}
|
||||
void setGameInstallDir(const std::filesystem::path& dir) {
|
||||
settings_install_dir = dir;
|
||||
void setGameInstallDirs(const std::vector<std::filesystem::path>& dir) {
|
||||
settings_install_dirs.resize(dir.size());
|
||||
settings_install_dirs = dir;
|
||||
}
|
||||
void setAddonInstallDir(const std::filesystem::path& dir) {
|
||||
settings_addon_install_dir = dir;
|
||||
|
@ -384,8 +385,8 @@ u32 getMainWindowGeometryW() {
|
|||
u32 getMainWindowGeometryH() {
|
||||
return main_window_geometry_h;
|
||||
}
|
||||
std::filesystem::path getGameInstallDir() {
|
||||
return settings_install_dir;
|
||||
std::vector<std::filesystem::path> getGameInstallDirs() {
|
||||
return settings_install_dirs;
|
||||
}
|
||||
std::filesystem::path getAddonInstallDir() {
|
||||
if (settings_addon_install_dir.empty()) {
|
||||
|
@ -523,7 +524,19 @@ void load(const std::filesystem::path& path) {
|
|||
mw_themes = toml::find_or<int>(gui, "theme", 0);
|
||||
m_window_size_W = toml::find_or<int>(gui, "mw_width", 0);
|
||||
m_window_size_H = toml::find_or<int>(gui, "mw_height", 0);
|
||||
settings_install_dir = toml::find_fs_path_or(gui, "installDir", {});
|
||||
|
||||
auto old_game_install_dir = toml::find_fs_path_or(gui, "installDir", {});
|
||||
if (!old_game_install_dir.empty()) {
|
||||
settings_install_dirs.push_back(old_game_install_dir);
|
||||
data.as_table().erase("installDir");
|
||||
}
|
||||
|
||||
const auto install_dir_array =
|
||||
toml::find_or<std::vector<std::string>>(gui, "installDirs", {});
|
||||
for (const auto& dir : install_dir_array) {
|
||||
settings_install_dirs.emplace_back(std::filesystem::path{dir});
|
||||
}
|
||||
|
||||
settings_addon_install_dir = toml::find_fs_path_or(gui, "addonInstallDir", {});
|
||||
main_window_geometry_x = toml::find_or<int>(gui, "geometry_x", 0);
|
||||
main_window_geometry_y = toml::find_or<int>(gui, "geometry_y", 0);
|
||||
|
@ -601,7 +614,13 @@ void save(const std::filesystem::path& path) {
|
|||
data["GUI"]["gameTableMode"] = m_table_mode;
|
||||
data["GUI"]["mw_width"] = m_window_size_W;
|
||||
data["GUI"]["mw_height"] = m_window_size_H;
|
||||
data["GUI"]["installDir"] = std::string{fmt::UTF(settings_install_dir.u8string()).data};
|
||||
|
||||
std::vector<std::string> install_dirs;
|
||||
for (const auto& dirString : settings_install_dirs) {
|
||||
install_dirs.emplace_back(std::string{fmt::UTF(dirString.u8string()).data});
|
||||
}
|
||||
data["GUI"]["installDirs"] = install_dirs;
|
||||
|
||||
data["GUI"]["addonInstallDir"] =
|
||||
std::string{fmt::UTF(settings_addon_install_dir.u8string()).data};
|
||||
data["GUI"]["geometry_x"] = main_window_geometry_x;
|
||||
|
|
|
@ -85,7 +85,7 @@ bool vkCrashDiagnosticEnabled();
|
|||
|
||||
// Gui
|
||||
void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h);
|
||||
void setGameInstallDir(const std::filesystem::path& dir);
|
||||
void setGameInstallDirs(const std::vector<std::filesystem::path>& dir);
|
||||
void setAddonInstallDir(const std::filesystem::path& dir);
|
||||
void setMainWindowTheme(u32 theme);
|
||||
void setIconSize(u32 size);
|
||||
|
@ -104,7 +104,7 @@ u32 getMainWindowGeometryX();
|
|||
u32 getMainWindowGeometryY();
|
||||
u32 getMainWindowGeometryW();
|
||||
u32 getMainWindowGeometryH();
|
||||
std::filesystem::path getGameInstallDir();
|
||||
std::vector<std::filesystem::path> getGameInstallDirs();
|
||||
std::filesystem::path getAddonInstallDir();
|
||||
u32 getMainWindowTheme();
|
||||
u32 getIconSize();
|
||||
|
|
|
@ -10,14 +10,16 @@ GameInfoClass::GameInfoClass() = default;
|
|||
GameInfoClass::~GameInfoClass() = default;
|
||||
|
||||
void GameInfoClass::GetGameInfo(QWidget* parent) {
|
||||
QString installDir;
|
||||
Common::FS::PathToQString(installDir, Config::getGameInstallDir());
|
||||
QStringList filePaths;
|
||||
QDir parentFolder(installDir);
|
||||
QFileInfoList fileList = parentFolder.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
for (const auto& fileInfo : fileList) {
|
||||
if (fileInfo.isDir()) {
|
||||
filePaths.append(fileInfo.absoluteFilePath());
|
||||
for (const auto& installLoc : Config::getGameInstallDirs()) {
|
||||
QString installDir;
|
||||
Common::FS::PathToQString(installDir, installLoc);
|
||||
QDir parentFolder(installDir);
|
||||
QFileInfoList fileList = parentFolder.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
for (const auto& fileInfo : fileList) {
|
||||
if (fileInfo.isDir()) {
|
||||
filePaths.append(fileInfo.absoluteFilePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
m_games = QtConcurrent::mapped(filePaths, [&](const QString& path) {
|
||||
|
|
|
@ -51,7 +51,9 @@ QWidget* GameInstallDialog::SetupGamesDirectory() {
|
|||
// Input.
|
||||
m_gamesDirectory = new QLineEdit();
|
||||
QString install_dir;
|
||||
Common::FS::PathToQString(install_dir, Config::getGameInstallDir());
|
||||
std::filesystem::path install_path =
|
||||
Config::getGameInstallDirs().empty() ? "" : Config::getGameInstallDirs().front();
|
||||
Common::FS::PathToQString(install_dir, install_path);
|
||||
m_gamesDirectory->setText(install_dir);
|
||||
m_gamesDirectory->setMinimumWidth(400);
|
||||
|
||||
|
@ -125,7 +127,9 @@ void GameInstallDialog::Save() {
|
|||
}
|
||||
}
|
||||
|
||||
Config::setGameInstallDir(Common::FS::PathFromQString(gamesDirectory));
|
||||
std::vector<std::filesystem::path> install_dirs;
|
||||
install_dirs.emplace_back(Common::FS::PathFromQString(gamesDirectory));
|
||||
Config::setGameInstallDirs(install_dirs);
|
||||
Config::setAddonInstallDir(Common::FS::PathFromQString(addonsDirectory));
|
||||
const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
|
||||
Config::save(config_dir / "config.toml");
|
||||
|
|
76
src/qt_gui/install_dir_select.cpp
Normal file
76
src/qt_gui/install_dir_select.cpp
Normal file
|
@ -0,0 +1,76 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QDir>
|
||||
#include <QFileDialog>
|
||||
#include <QGroupBox>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QListWidget>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "install_dir_select.h"
|
||||
|
||||
InstallDirSelect::InstallDirSelect() : selected_dir() {
|
||||
selected_dir = Config::getGameInstallDirs().empty() ? "" : Config::getGameInstallDirs().front();
|
||||
|
||||
if (!Config::getGameInstallDirs().empty() && Config::getGameInstallDirs().size() == 1) {
|
||||
reject();
|
||||
}
|
||||
|
||||
auto layout = new QVBoxLayout(this);
|
||||
|
||||
layout->addWidget(SetupInstallDirList());
|
||||
layout->addStretch();
|
||||
layout->addWidget(SetupDialogActions());
|
||||
|
||||
setWindowTitle(tr("shadPS4 - Choose directory"));
|
||||
setWindowIcon(QIcon(":images/shadps4.ico"));
|
||||
}
|
||||
|
||||
InstallDirSelect::~InstallDirSelect() {}
|
||||
|
||||
QWidget* InstallDirSelect::SetupInstallDirList() {
|
||||
auto group = new QGroupBox(tr("Select which directory you want to install to."));
|
||||
auto vlayout = new QVBoxLayout();
|
||||
|
||||
auto m_path_list = new QListWidget();
|
||||
QList<QString> qt_list;
|
||||
for (const auto& str : Config::getGameInstallDirs()) {
|
||||
QString installDirPath;
|
||||
Common::FS::PathToQString(installDirPath, str);
|
||||
qt_list.append(installDirPath);
|
||||
}
|
||||
m_path_list->insertItems(0, qt_list);
|
||||
m_path_list->setSpacing(1);
|
||||
|
||||
connect(m_path_list, &QListWidget::itemClicked, this, &InstallDirSelect::setSelectedDirectory);
|
||||
connect(m_path_list, &QListWidget::itemActivated, this,
|
||||
&InstallDirSelect::setSelectedDirectory);
|
||||
|
||||
vlayout->addWidget(m_path_list);
|
||||
|
||||
group->setLayout(vlayout);
|
||||
return group;
|
||||
}
|
||||
|
||||
void InstallDirSelect::setSelectedDirectory(QListWidgetItem* item) {
|
||||
if (item) {
|
||||
const auto highlighted_path = Common::FS::PathFromQString(item->text());
|
||||
if (!highlighted_path.empty()) {
|
||||
selected_dir = highlighted_path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QWidget* InstallDirSelect::SetupDialogActions() {
|
||||
auto actions = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
|
||||
connect(actions, &QDialogButtonBox::accepted, this, &InstallDirSelect::accept);
|
||||
connect(actions, &QDialogButtonBox::rejected, this, &InstallDirSelect::reject);
|
||||
|
||||
return actions;
|
||||
}
|
31
src/qt_gui/install_dir_select.h
Normal file
31
src/qt_gui/install_dir_select.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include <QListWidget>
|
||||
|
||||
#include "common/config.h"
|
||||
#include "common/path_util.h"
|
||||
|
||||
class QLineEdit;
|
||||
|
||||
class InstallDirSelect final : public QDialog {
|
||||
public:
|
||||
InstallDirSelect();
|
||||
~InstallDirSelect();
|
||||
|
||||
std::filesystem::path getSelectedDirectory() {
|
||||
return selected_dir;
|
||||
}
|
||||
|
||||
private slots:
|
||||
void BrowseGamesDirectory();
|
||||
|
||||
private:
|
||||
QWidget* SetupInstallDirList();
|
||||
QWidget* SetupDialogActions();
|
||||
void setSelectedDirectory(QListWidgetItem* item);
|
||||
std::filesystem::path selected_dir;
|
||||
};
|
|
@ -30,7 +30,7 @@ int main(int argc, char* argv[]) {
|
|||
bool has_command_line_argument = argc > 1;
|
||||
|
||||
// Check if the game install directory is set
|
||||
if (Config::getGameInstallDir().empty() && !has_command_line_argument) {
|
||||
if (Config::getGameInstallDirs().empty() && !has_command_line_argument) {
|
||||
GameInstallDialog dlg;
|
||||
dlg.exec();
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "core/file_format/pkg.h"
|
||||
#include "core/loader.h"
|
||||
#include "game_install_dialog.h"
|
||||
#include "install_dir_select.h"
|
||||
#include "main_window.h"
|
||||
#include "settings_dialog.h"
|
||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||
|
@ -672,7 +673,10 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int
|
|||
QMessageBox::critical(this, tr("PKG ERROR"), QString::fromStdString(failreason));
|
||||
return;
|
||||
}
|
||||
auto extract_path = Config::getGameInstallDir() / pkg.GetTitleID();
|
||||
InstallDirSelect ids;
|
||||
ids.exec();
|
||||
auto game_install_dir = ids.getSelectedDirectory();
|
||||
auto extract_path = game_install_dir / pkg.GetTitleID();
|
||||
QString pkgType = QString::fromStdString(pkg.GetPkgFlags());
|
||||
QString gameDirPath;
|
||||
Common::FS::PathToQString(gameDirPath, extract_path);
|
||||
|
@ -821,7 +825,7 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int
|
|||
connect(&futureWatcher, &QFutureWatcher<void>::finished, this, [=, this]() {
|
||||
if (pkgNum == nPkg) {
|
||||
QString path;
|
||||
Common::FS::PathToQString(path, Config::getGameInstallDir());
|
||||
Common::FS::PathToQString(path, game_install_dir);
|
||||
QMessageBox extractMsgBox(this);
|
||||
extractMsgBox.setWindowTitle(tr("Extraction Finished"));
|
||||
extractMsgBox.setText(
|
||||
|
|
|
@ -220,6 +220,55 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices, QWidge
|
|||
[](int val) { Config::setNullGpu(val); });
|
||||
}
|
||||
|
||||
// PATH TAB
|
||||
{
|
||||
for (const auto& dir : Config::getGameInstallDirs()) {
|
||||
QString path_string;
|
||||
Common::FS::PathToQString(path_string, dir);
|
||||
QListWidgetItem* item = new QListWidgetItem(path_string);
|
||||
ui->gameFoldersListWidget->addItem(item);
|
||||
}
|
||||
|
||||
ui->removeFolderButton->setEnabled(false);
|
||||
|
||||
connect(ui->addFolderButton, &QPushButton::clicked, this, [this]() {
|
||||
QString file_path_string =
|
||||
QFileDialog::getExistingDirectory(this, tr("Directory to install games"));
|
||||
auto file_path = Common::FS::PathFromQString(file_path_string);
|
||||
if (!file_path.empty()) {
|
||||
std::vector<std::filesystem::path> install_dirs = Config::getGameInstallDirs();
|
||||
install_dirs.push_back(file_path);
|
||||
Config::setGameInstallDirs(install_dirs);
|
||||
QListWidgetItem* item = new QListWidgetItem(file_path_string);
|
||||
ui->gameFoldersListWidget->addItem(item);
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->gameFoldersListWidget, &QListWidget::itemSelectionChanged, this, [this]() {
|
||||
ui->removeFolderButton->setEnabled(
|
||||
!ui->gameFoldersListWidget->selectedItems().isEmpty());
|
||||
});
|
||||
|
||||
connect(ui->removeFolderButton, &QPushButton::clicked, this, [this]() {
|
||||
QListWidgetItem* selected_item = ui->gameFoldersListWidget->currentItem();
|
||||
QString item_path_string = selected_item ? selected_item->text() : QString();
|
||||
if (!item_path_string.isEmpty()) {
|
||||
auto file_path = Common::FS::PathFromQString(item_path_string);
|
||||
std::vector<std::filesystem::path> install_dirs = Config::getGameInstallDirs();
|
||||
|
||||
auto iterator = std::remove_if(
|
||||
install_dirs.begin(), install_dirs.end(),
|
||||
[&file_path](const std::filesystem::path& dir) { return file_path == dir; });
|
||||
|
||||
if (iterator != install_dirs.end()) {
|
||||
install_dirs.erase(iterator, install_dirs.end());
|
||||
delete selected_item;
|
||||
}
|
||||
Config::setGameInstallDirs(install_dirs);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// DEBUG TAB
|
||||
{
|
||||
connect(ui->debugDump, &QCheckBox::stateChanged, this,
|
||||
|
|
|
@ -918,6 +918,76 @@
|
|||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="pathsTab">
|
||||
<attribute name="title">
|
||||
<string>Paths</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="inputTabVLayout" stretch="0">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gameFoldersGroupBox">
|
||||
<property name="title">
|
||||
<string>Game Folders</string>
|
||||
</property>
|
||||
<widget class="QListWidget" name="gameFoldersListWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>20</y>
|
||||
<width>401</width>
|
||||
<height>331</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="addFolderButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>100</x>
|
||||
<y>360</y>
|
||||
<width>80</width>
|
||||
<height>24</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Add...</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="removeFolderButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>210</x>
|
||||
<y>360</y>
|
||||
<width>80</width>
|
||||
<height>24</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::Preferred</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="debugTab">
|
||||
<attribute name="title">
|
||||
<string>Debug</string>
|
||||
|
|
Loading…
Reference in a new issue