Merge pull request #5759 from nieldm/fix-3818-allow-custom-save

Allow custom folder for SDMC and NAND Directories
master
bunnei 2021-04-23 22:35:10 +07:00 committed by GitHub
commit 78b8dfc808
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 359 additions and 3 deletions

@ -201,6 +201,10 @@ void Config::ReadValues() {
// Data Storage
Settings::values.use_virtual_sd =
sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true);
Settings::values.nand_dir = sdl2_config->GetString(
"Data Storage", "nand_directory", FileUtil::GetUserPath(FileUtil::UserPath::NANDDir));
Settings::values.sdmc_dir = sdl2_config->GetString(
"Data Storage", "sdmc_directory", FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir));
// System
Settings::values.is_new_3ds = sdl2_config->GetBoolean("System", "is_new_3ds", true);

@ -250,6 +250,14 @@ volume =
# 1 (default): Yes, 0: No
use_virtual_sd =
# The path of the virtual SD card directory.
# empty (default) will use the user_path
sdmc_directory =
# The path of NAND directory.
# empty (default) will use the user_path
nand_directory =
[System]
# The system model that Citra will try to emulate
# 0: Old 3DS, 1: New 3DS (default)

@ -66,6 +66,9 @@ add_executable(citra-qt
configuration/configure_motion_touch.cpp
configuration/configure_motion_touch.h
configuration/configure_motion_touch.ui
configuration/configure_storage.cpp
configuration/configure_storage.h
configuration/configure_storage.ui
configuration/configure_system.cpp
configuration/configure_system.h
configuration/configure_system.ui

@ -302,6 +302,16 @@ void Config::ReadDataStorageValues() {
qt_config->beginGroup(QStringLiteral("Data Storage"));
Settings::values.use_virtual_sd = ReadSetting(QStringLiteral("use_virtual_sd"), true).toBool();
std::string nand_dir = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir);
Settings::values.nand_dir =
ReadSetting(QStringLiteral("nand_directory"), QString::fromStdString(nand_dir))
.toString()
.toStdString();
std::string sdmc_dir = FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir);
Settings::values.sdmc_dir =
ReadSetting(QStringLiteral("sdmc_directory"), QString::fromStdString(sdmc_dir))
.toString()
.toStdString();
qt_config->endGroup();
}
@ -852,6 +862,12 @@ void Config::SaveDataStorageValues() {
qt_config->beginGroup(QStringLiteral("Data Storage"));
WriteSetting(QStringLiteral("use_virtual_sd"), Settings::values.use_virtual_sd, true);
WriteSetting(QStringLiteral("nand_directory"),
QString::fromStdString(Settings::values.nand_dir),
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)));
WriteSetting(QStringLiteral("sdmc_directory"),
QString::fromStdString(Settings::values.sdmc_dir),
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)));
qt_config->endGroup();
}

@ -68,6 +68,11 @@
<string>Debug</string>
</attribute>
</widget>
<widget class="ConfigureStorage" name="storageTab">
<attribute name="title">
<string>Storage</string>
</attribute>
</widget>
<widget class="ConfigureWeb" name="webTab">
<attribute name="title">
<string>Web</string>
@ -121,6 +126,12 @@
<extends>QWidget</extends>
<header>configuration/configure_debug.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ConfigureStorage</class>
<extends>QWidget</extends>
<header>configuration/configure_storage.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ConfigureInput</class>

@ -51,6 +51,7 @@ void ConfigureDialog::SetConfiguration() {
ui->debugTab->SetConfiguration();
ui->webTab->SetConfiguration();
ui->uiTab->SetConfiguration();
ui->storageTab->SetConfiguration();
}
void ConfigureDialog::ApplyConfiguration() {
@ -66,6 +67,7 @@ void ConfigureDialog::ApplyConfiguration() {
ui->debugTab->ApplyConfiguration();
ui->webTab->ApplyConfiguration();
ui->uiTab->ApplyConfiguration();
ui->storageTab->ApplyConfiguration();
Settings::Apply();
Settings::LogSettings();
}
@ -77,7 +79,7 @@ void ConfigureDialog::PopulateSelectionList() {
const std::array<std::pair<QString, QList<QWidget*>>, 5> items{
{{tr("General"), {ui->generalTab, ui->webTab, ui->debugTab, ui->uiTab}},
{tr("System"), {ui->systemTab, ui->cameraTab}},
{tr("System"), {ui->systemTab, ui->cameraTab, ui->storageTab}},
{tr("Graphics"), {ui->enhancementsTab, ui->graphicsTab}},
{tr("Audio"), {ui->audioTab}},
{tr("Controls"), {ui->inputTab, ui->hotkeysTab}}}};
@ -118,6 +120,7 @@ void ConfigureDialog::RetranslateUI() {
ui->debugTab->RetranslateUI();
ui->webTab->RetranslateUI();
ui->uiTab->RetranslateUI();
ui->storageTab->RetranslateUI();
}
void ConfigureDialog::UpdateVisibleTabs() {
@ -134,6 +137,7 @@ void ConfigureDialog::UpdateVisibleTabs() {
{ui->audioTab, tr("Audio")},
{ui->cameraTab, tr("Camera")},
{ui->debugTab, tr("Debug")},
{ui->storageTab, tr("Storage")},
{ui->webTab, tr("Web")},
{ui->uiTab, tr("UI")}};

@ -0,0 +1,78 @@
// Copyright 2021 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <QDesktopServices>
#include <QFileDialog>
#include <QUrl>
#include "citra_qt/configuration/configure_storage.h"
#include "core/core.h"
#include "core/settings.h"
#include "ui_configure_storage.h"
ConfigureStorage::ConfigureStorage(QWidget* parent)
: QWidget(parent), ui(std::make_unique<Ui::ConfigureStorage>()) {
ui->setupUi(this);
SetConfiguration();
connect(ui->open_nand_dir, &QPushButton::clicked, []() {
QString path = QString::fromStdString(Settings::values.nand_dir);
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
});
connect(ui->change_nand_dir, &QPushButton::clicked, this, [this]() {
const QString dir_path = QFileDialog::getExistingDirectory(
this, tr("Select NAND Directory"), QString::fromStdString(Settings::values.nand_dir),
QFileDialog::ShowDirsOnly);
if (!dir_path.isEmpty()) {
Settings::values.nand_dir = dir_path.toStdString();
SetConfiguration();
}
});
connect(ui->open_sdmc_dir, &QPushButton::clicked, []() {
QString path = QString::fromStdString(Settings::values.sdmc_dir);
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
});
connect(ui->change_sdmc_dir, &QPushButton::clicked, this, [this]() {
const QString dir_path = QFileDialog::getExistingDirectory(
this, tr("Select SDMC Directory"), QString::fromStdString(Settings::values.sdmc_dir),
QFileDialog::ShowDirsOnly);
if (!dir_path.isEmpty()) {
Settings::values.sdmc_dir = dir_path.toStdString();
SetConfiguration();
}
});
connect(ui->toggle_virtual_sd, &QCheckBox::clicked, this, [this]() {
ApplyConfiguration();
SetConfiguration();
});
}
ConfigureStorage::~ConfigureStorage() = default;
void ConfigureStorage::SetConfiguration() {
ui->nand_group->setVisible(Settings::values.use_virtual_sd);
QString nand_path = QString::fromStdString(Settings::values.nand_dir);
ui->nand_dir_path->setText(nand_path);
ui->open_nand_dir->setEnabled(!Settings::values.nand_dir.empty());
ui->sdmc_group->setVisible(Settings::values.use_virtual_sd);
QString sdmc_path = QString::fromStdString(Settings::values.sdmc_dir);
ui->sdmc_dir_path->setText(sdmc_path);
ui->open_sdmc_dir->setEnabled(!Settings::values.sdmc_dir.empty());
ui->toggle_virtual_sd->setChecked(Settings::values.use_virtual_sd);
ui->storage_group->setEnabled(!Core::System::GetInstance().IsPoweredOn());
}
void ConfigureStorage::ApplyConfiguration() {
Settings::values.use_virtual_sd = ui->toggle_virtual_sd->isChecked();
}
void ConfigureStorage::RetranslateUI() {
ui->retranslateUi(this);
}

@ -0,0 +1,26 @@
// Copyright 2021 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include <QWidget>
namespace Ui {
class ConfigureStorage;
}
class ConfigureStorage : public QWidget {
Q_OBJECT
public:
explicit ConfigureStorage(QWidget* parent = nullptr);
~ConfigureStorage() override;
void ApplyConfiguration();
void RetranslateUI();
void SetConfiguration();
std::unique_ptr<Ui::ConfigureStorage> ui;
};

@ -0,0 +1,188 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ConfigureStorage</class>
<widget class="QWidget" name="ConfigureStorage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>681</width>
<height>375</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_1">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="storage_group">
<property name="title">
<string>Storage</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_1">
<item>
<widget class="QCheckBox" name="toggle_virtual_sd">
<property name="text">
<string>Use Virtual SD</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="nand_group">
<property name="title">
<string/>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>NAND Directory</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="nand_dir_path">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="open_nand_dir">
<property name="text">
<string>Open</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>NOTE: this does not move the contents of the previous directory to the new one</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="change_nand_dir">
<property name="text">
<string>Change</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="sdmc_group">
<property name="title">
<string/>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>SDMC Directory</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="sdmc_dir_path">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="open_sdmc_dir">
<property name="text">
<string>Open</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>NOTE: this does not move the contents of the previous directory to the new one</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="change_sdmc_dir">
<property name="text">
<string>Change</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

@ -12,6 +12,7 @@
#include "common/common_paths.h"
#include "common/file_util.h"
#include "common/logging/log.h"
#include "core/settings.h"
#ifdef _WIN32
#include <windows.h>
@ -716,8 +717,13 @@ void SetUserPath(const std::string& path) {
}
#endif
}
g_paths.emplace(UserPath::SDMCDir, user_path + SDMC_DIR DIR_SEP);
g_paths.emplace(UserPath::NANDDir, user_path + NAND_DIR DIR_SEP);
g_paths.emplace(UserPath::SDMCDir, !Settings::values.sdmc_dir.empty()
? Settings::values.sdmc_dir
: user_path + SDMC_DIR DIR_SEP);
g_paths.emplace(UserPath::NANDDir, !Settings::values.nand_dir.empty()
? Settings::values.nand_dir
: user_path + NAND_DIR DIR_SEP);
g_paths.emplace(UserPath::SysDataDir, user_path + SYSDATA_DIR DIR_SEP);
// TODO: Put the logs in a better location for each OS
g_paths.emplace(UserPath::LogDir, user_path + LOG_DIR DIR_SEP);
@ -762,6 +768,11 @@ const std::string& GetUserPath(UserPath path) {
SetUserPath();
return g_paths[path];
}
const void UpdateUserPath(UserPath path, const std::string& filename) {
g_paths[path] = filename + DIR_SEP;
}
std::size_t WriteStringToFile(bool text_file, const std::string& filename, std::string_view str) {
return IOFile(filename, text_file ? "w" : "wb").WriteString(str);
}

@ -186,6 +186,9 @@ void SetCurrentRomPath(const std::string& path);
// directory. To be used in "multi-user" mode (that is, installed).
[[nodiscard]] const std::string& GetUserPath(UserPath path);
// Update the Global Path with the new value
const void UpdateUserPath(UserPath path, const std::string& filename);
// Returns the path to where the sys file are
[[nodiscard]] std::string GetSysDirectory();

@ -118,6 +118,8 @@ void LogSettings() {
log_setting("Camera_OuterLeftConfig", values.camera_config[OuterLeftCamera]);
log_setting("Camera_OuterLeftFlip", values.camera_flip[OuterLeftCamera]);
log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd);
log_setting("DataStorage_SdmcDir", values.sdmc_dir);
log_setting("DataStorage_NandDir", values.nand_dir);
log_setting("System_IsNew3ds", values.is_new_3ds);
log_setting("System_RegionValue", values.region_value);
log_setting("Debugging_UseGdbstub", values.use_gdbstub);

@ -140,6 +140,8 @@ struct Values {
// Data Storage
bool use_virtual_sd;
std::string nand_dir;
std::string sdmc_dir;
// System
int region_value;