[desktop, fs] main_window separation; fix Ryujinx save data link issues (#2929)

Some genius decided to put the entire MainWindow class into main.h and
main.cpp, which is not only horrific practice but also completely
destroys clangd beyond repair. Please, just don't do this.

(this will probably merge conflict to hell and back)

Also, fixes a bunch of issues with Ryujinx save data link:
- Paths with spaces would cause mklink to fail
- Add support for portable directories
- Symlink detection was incorrect sometimes(????)
- Some other stuff I'm forgetting

Furthermore, when selecting "From Eden" and attempting to save in Ryujinx, Ryujinx would destroy the link for... some reason? So to get around this we just copy the Eden data to Ryujinx then treat it like a "From Ryujinx" op

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2929
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
This commit is contained in:
crueter 2025-11-09 18:07:38 +01:00
parent e13c7ef3f8
commit 08f3639c80
No known key found for this signature in database
GPG key ID: 425ACD2D4830EBC6
51 changed files with 5386 additions and 5283 deletions

View file

@ -12,6 +12,8 @@ if (YUZU_USE_BUNDLED_QT AND PLATFORM_LINUX)
set(CMAKE_BUILD_RPATH "${CMAKE_BINARY_DIR}/bin/lib/")
endif()
find_package(Qt6 REQUIRED COMPONENTS Widgets)
add_executable(yuzu
Info.plist
about_dialog.cpp
@ -169,9 +171,9 @@ add_executable(yuzu
loading_screen.cpp
loading_screen.h
loading_screen.ui
main.cpp
main.h
main.ui
multiplayer/chat_room.cpp
multiplayer/chat_room.h
multiplayer/chat_room.ui
@ -235,6 +237,7 @@ add_executable(yuzu
data_dialog.h data_dialog.cpp data_dialog.ui
data_widget.ui
ryujinx_dialog.h ryujinx_dialog.cpp ryujinx_dialog.ui
main_window.h main_window.cpp
)
set_target_properties(yuzu PROPERTIES OUTPUT_NAME "eden")
@ -441,6 +444,7 @@ endif()
if (YUZU_ROOM)
target_link_libraries(yuzu PRIVATE yuzu-room)
target_link_libraries(yuzu PRIVATE Qt6::Widgets)
endif()
create_target_directory_groups(yuzu)

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -18,7 +21,7 @@
#include "web_service/web_backend.h"
#endif
#include "yuzu/applets/qt_amiibo_settings.h"
#include "yuzu/main.h"
#include "yuzu/main_window.h"
QtAmiiboSettingsDialog::QtAmiiboSettingsDialog(QWidget* parent,
Core::Frontend::CabinetParameters parameters_,
@ -244,12 +247,12 @@ void QtAmiiboSettingsDialog::SetSettingsDescription() {
}
}
QtAmiiboSettings::QtAmiiboSettings(GMainWindow& parent) {
QtAmiiboSettings::QtAmiiboSettings(MainWindow& parent) {
connect(this, &QtAmiiboSettings::MainWindowShowAmiiboSettings, &parent,
&GMainWindow::AmiiboSettingsShowDialog, Qt::QueuedConnection);
&MainWindow::AmiiboSettingsShowDialog, Qt::QueuedConnection);
connect(this, &QtAmiiboSettings::MainWindowRequestExit, &parent,
&GMainWindow::AmiiboSettingsRequestExit, Qt::QueuedConnection);
connect(&parent, &GMainWindow::AmiiboSettingsFinished, this,
&MainWindow::AmiiboSettingsRequestExit, Qt::QueuedConnection);
connect(&parent, &MainWindow::AmiiboSettingsFinished, this,
&QtAmiiboSettings::MainWindowFinished, Qt::QueuedConnection);
}

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -8,7 +11,7 @@
#include <QDialog>
#include "core/frontend/applets/cabinet.h"
class GMainWindow;
class MainWindow;
class QCheckBox;
class QComboBox;
class QDialogButtonBox;
@ -65,7 +68,7 @@ class QtAmiiboSettings final : public QObject, public Core::Frontend::CabinetApp
Q_OBJECT
public:
explicit QtAmiiboSettings(GMainWindow& parent);
explicit QtAmiiboSettings(MainWindow& parent);
~QtAmiiboSettings() override;
void Close() const override;

View file

@ -25,7 +25,7 @@
#include "yuzu/configuration/configure_motion_touch.h"
#include "yuzu/configuration/configure_vibration.h"
#include "yuzu/configuration/input_profiles.h"
#include "yuzu/main.h"
#include "yuzu/main_window.h"
#include "yuzu/util/controller_navigation.h"
namespace {
@ -753,12 +753,12 @@ void QtControllerSelectorDialog::DisableUnsupportedPlayers() {
}
}
QtControllerSelector::QtControllerSelector(GMainWindow& parent) {
QtControllerSelector::QtControllerSelector(MainWindow& parent) {
connect(this, &QtControllerSelector::MainWindowReconfigureControllers, &parent,
&GMainWindow::ControllerSelectorReconfigureControllers, Qt::QueuedConnection);
&MainWindow::ControllerSelectorReconfigureControllers, Qt::QueuedConnection);
connect(this, &QtControllerSelector::MainWindowRequestExit, &parent,
&GMainWindow::ControllerSelectorRequestExit, Qt::QueuedConnection);
connect(&parent, &GMainWindow::ControllerSelectorReconfigureFinished, this,
&MainWindow::ControllerSelectorRequestExit, Qt::QueuedConnection);
connect(&parent, &MainWindow::ControllerSelectorReconfigureFinished, this,
&QtControllerSelector::MainWindowReconfigureFinished, Qt::QueuedConnection);
}

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -8,7 +11,7 @@
#include <QDialog>
#include "core/frontend/applets/controller.h"
class GMainWindow;
class MainWindow;
class QCheckBox;
class QComboBox;
class QDialogButtonBox;
@ -163,7 +166,7 @@ class QtControllerSelector final : public QObject, public Core::Frontend::Contro
Q_OBJECT
public:
explicit QtControllerSelector(GMainWindow& parent);
explicit QtControllerSelector(MainWindow& parent);
~QtControllerSelector() override;
void Close() const override;

View file

@ -1,16 +1,19 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <QDateTime>
#include "yuzu/applets/qt_error.h"
#include "yuzu/main.h"
#include "yuzu/main_window.h"
QtErrorDisplay::QtErrorDisplay(GMainWindow& parent) {
QtErrorDisplay::QtErrorDisplay(MainWindow& parent) {
connect(this, &QtErrorDisplay::MainWindowDisplayError, &parent,
&GMainWindow::ErrorDisplayDisplayError, Qt::QueuedConnection);
&MainWindow::ErrorDisplayDisplayError, Qt::QueuedConnection);
connect(this, &QtErrorDisplay::MainWindowRequestExit, &parent,
&GMainWindow::ErrorDisplayRequestExit, Qt::QueuedConnection);
connect(&parent, &GMainWindow::ErrorDisplayFinished, this,
&MainWindow::ErrorDisplayRequestExit, Qt::QueuedConnection);
connect(&parent, &MainWindow::ErrorDisplayFinished, this,
&QtErrorDisplay::MainWindowFinishedError, Qt::DirectConnection);
}

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -7,13 +10,13 @@
#include "core/frontend/applets/error.h"
class GMainWindow;
class MainWindow;
class QtErrorDisplay final : public QObject, public Core::Frontend::ErrorApplet {
Q_OBJECT
public:
explicit QtErrorDisplay(GMainWindow& parent);
explicit QtErrorDisplay(MainWindow& parent);
~QtErrorDisplay() override;
void Close() const override;

View file

@ -20,7 +20,7 @@
#include "core/core.h"
#include "core/hle/service/acc/profile_manager.h"
#include "yuzu/applets/qt_profile_select.h"
#include "yuzu/main.h"
#include "yuzu/main_window.h"
#include "yuzu/util/controller_navigation.h"
namespace {
@ -230,12 +230,12 @@ void QtProfileSelectionDialog::SetDialogPurpose(
}
}
QtProfileSelector::QtProfileSelector(GMainWindow& parent) {
QtProfileSelector::QtProfileSelector(MainWindow& parent) {
connect(this, &QtProfileSelector::MainWindowSelectProfile, &parent,
&GMainWindow::ProfileSelectorSelectProfile, Qt::QueuedConnection);
&MainWindow::ProfileSelectorSelectProfile, Qt::QueuedConnection);
connect(this, &QtProfileSelector::MainWindowRequestExit, &parent,
&GMainWindow::ProfileSelectorRequestExit, Qt::QueuedConnection);
connect(&parent, &GMainWindow::ProfileSelectorFinishedSelection, this,
&MainWindow::ProfileSelectorRequestExit, Qt::QueuedConnection);
connect(&parent, &MainWindow::ProfileSelectorFinishedSelection, this,
&QtProfileSelector::MainWindowFinishedSelection, Qt::DirectConnection);
}

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -9,7 +12,7 @@
#include "core/frontend/applets/profile_select.h"
class ControllerNavigation;
class GMainWindow;
class MainWindow;
class QDialogButtonBox;
class QGraphicsScene;
class QLabel;
@ -69,7 +72,7 @@ class QtProfileSelector final : public QObject, public Core::Frontend::ProfileSe
Q_OBJECT
public:
explicit QtProfileSelector(GMainWindow& parent);
explicit QtProfileSelector(MainWindow& parent);
~QtProfileSelector() override;
void Close() const override;

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -15,7 +18,7 @@
#include "hid_core/hid_types.h"
#include "ui_qt_software_keyboard.h"
#include "yuzu/applets/qt_software_keyboard.h"
#include "yuzu/main.h"
#include "yuzu/main_window.h"
#include "yuzu/util/overlay_dialog.h"
namespace {
@ -1541,24 +1544,24 @@ void QtSoftwareKeyboardDialog::InputThread() {
}
}
QtSoftwareKeyboard::QtSoftwareKeyboard(GMainWindow& main_window) {
QtSoftwareKeyboard::QtSoftwareKeyboard(MainWindow& main_window) {
connect(this, &QtSoftwareKeyboard::MainWindowInitializeKeyboard, &main_window,
&GMainWindow::SoftwareKeyboardInitialize, Qt::QueuedConnection);
&MainWindow::SoftwareKeyboardInitialize, Qt::QueuedConnection);
connect(this, &QtSoftwareKeyboard::MainWindowShowNormalKeyboard, &main_window,
&GMainWindow::SoftwareKeyboardShowNormal, Qt::QueuedConnection);
&MainWindow::SoftwareKeyboardShowNormal, Qt::QueuedConnection);
connect(this, &QtSoftwareKeyboard::MainWindowShowTextCheckDialog, &main_window,
&GMainWindow::SoftwareKeyboardShowTextCheck, Qt::QueuedConnection);
&MainWindow::SoftwareKeyboardShowTextCheck, Qt::QueuedConnection);
connect(this, &QtSoftwareKeyboard::MainWindowShowInlineKeyboard, &main_window,
&GMainWindow::SoftwareKeyboardShowInline, Qt::QueuedConnection);
&MainWindow::SoftwareKeyboardShowInline, Qt::QueuedConnection);
connect(this, &QtSoftwareKeyboard::MainWindowHideInlineKeyboard, &main_window,
&GMainWindow::SoftwareKeyboardHideInline, Qt::QueuedConnection);
&MainWindow::SoftwareKeyboardHideInline, Qt::QueuedConnection);
connect(this, &QtSoftwareKeyboard::MainWindowInlineTextChanged, &main_window,
&GMainWindow::SoftwareKeyboardInlineTextChanged, Qt::QueuedConnection);
&MainWindow::SoftwareKeyboardInlineTextChanged, Qt::QueuedConnection);
connect(this, &QtSoftwareKeyboard::MainWindowExitKeyboard, &main_window,
&GMainWindow::SoftwareKeyboardExit, Qt::QueuedConnection);
connect(&main_window, &GMainWindow::SoftwareKeyboardSubmitNormalText, this,
&MainWindow::SoftwareKeyboardExit, Qt::QueuedConnection);
connect(&main_window, &MainWindow::SoftwareKeyboardSubmitNormalText, this,
&QtSoftwareKeyboard::SubmitNormalText, Qt::QueuedConnection);
connect(&main_window, &GMainWindow::SoftwareKeyboardSubmitInlineText, this,
connect(&main_window, &MainWindow::SoftwareKeyboardSubmitInlineText, this,
&QtSoftwareKeyboard::SubmitInlineText, Qt::QueuedConnection);
}

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -27,7 +30,7 @@ namespace Ui {
class QtSoftwareKeyboardDialog;
}
class GMainWindow;
class MainWindow;
class QtSoftwareKeyboardDialog final : public QDialog {
Q_OBJECT
@ -230,7 +233,7 @@ class QtSoftwareKeyboard final : public QObject, public Core::Frontend::Software
Q_OBJECT
public:
explicit QtSoftwareKeyboard(GMainWindow& parent);
explicit QtSoftwareKeyboard(MainWindow& parent);
~QtSoftwareKeyboard() override;
void Close() const override {

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -18,7 +21,7 @@
#endif
#include "yuzu/applets/qt_web_browser.h"
#include "yuzu/main.h"
#include "yuzu/main_window.h"
#ifdef YUZU_USE_QT_WEB_ENGINE
@ -391,14 +394,14 @@ void QtNXWebEngineView::FocusFirstLinkElement() {
#endif
QtWebBrowser::QtWebBrowser(GMainWindow& main_window) {
QtWebBrowser::QtWebBrowser(MainWindow& main_window) {
connect(this, &QtWebBrowser::MainWindowOpenWebPage, &main_window,
&GMainWindow::WebBrowserOpenWebPage, Qt::QueuedConnection);
&MainWindow::WebBrowserOpenWebPage, Qt::QueuedConnection);
connect(this, &QtWebBrowser::MainWindowRequestExit, &main_window,
&GMainWindow::WebBrowserRequestExit, Qt::QueuedConnection);
connect(&main_window, &GMainWindow::WebBrowserExtractOfflineRomFS, this,
&MainWindow::WebBrowserRequestExit, Qt::QueuedConnection);
connect(&main_window, &MainWindow::WebBrowserExtractOfflineRomFS, this,
&QtWebBrowser::MainWindowExtractOfflineRomFS, Qt::QueuedConnection);
connect(&main_window, &GMainWindow::WebBrowserClosed, this,
connect(&main_window, &MainWindow::WebBrowserClosed, this,
&QtWebBrowser::MainWindowWebBrowserClosed, Qt::QueuedConnection);
}

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -14,7 +17,7 @@
#include "core/frontend/applets/web_browser.h"
class GMainWindow;
class MainWindow;
class InputInterpreter;
class UrlRequestInterceptor;
@ -193,7 +196,7 @@ class QtWebBrowser final : public QObject, public Core::Frontend::WebBrowserAppl
Q_OBJECT
public:
explicit QtWebBrowser(GMainWindow& parent);
explicit QtWebBrowser(MainWindow& parent);
~QtWebBrowser() override;
void Close() const override;

View file

@ -57,7 +57,7 @@
#include "video_core/rasterizer_interface.h"
#include "video_core/renderer_base.h"
#include "yuzu/bootmanager.h"
#include "yuzu/main.h"
#include "yuzu/main_window.h"
#include "qt_common/qt_common.h"
class QObject;
@ -272,7 +272,7 @@ struct NullRenderWidget : public RenderWidget {
explicit NullRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {}
};
GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_,
GRenderWindow::GRenderWindow(MainWindow* parent, EmuThread* emu_thread_,
std::shared_ptr<InputCommon::InputSubsystem> input_subsystem_,
Core::System& system_)
: QWidget(parent),
@ -290,11 +290,11 @@ GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_,
strict_context_required = QGuiApplication::platformName() == QStringLiteral("wayland") ||
QGuiApplication::platformName() == QStringLiteral("wayland-egl");
connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete);
connect(this, &GRenderWindow::ExecuteProgramSignal, parent, &GMainWindow::OnExecuteProgram,
connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &MainWindow::OnLoadComplete);
connect(this, &GRenderWindow::ExecuteProgramSignal, parent, &MainWindow::OnExecuteProgram,
Qt::QueuedConnection);
connect(this, &GRenderWindow::ExitSignal, parent, &GMainWindow::OnExit, Qt::QueuedConnection);
connect(this, &GRenderWindow::TasPlaybackStateChanged, parent, &GMainWindow::OnTasStateChanged);
connect(this, &GRenderWindow::ExitSignal, parent, &MainWindow::OnExit, Qt::QueuedConnection);
connect(this, &GRenderWindow::TasPlaybackStateChanged, parent, &MainWindow::OnTasStateChanged);
mouse_constrain_timer.setInterval(default_mouse_constrain_timeout);
connect(&mouse_constrain_timer, &QTimer::timeout, this, &GRenderWindow::ConstrainMouse);

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -29,7 +32,7 @@
#include "common/thread.h"
#include "core/frontend/emu_window.h"
class GMainWindow;
class MainWindow;
class QCamera;
class QCameraImageCapture;
class QCloseEvent;
@ -146,7 +149,7 @@ class GRenderWindow : public QWidget, public Core::Frontend::EmuWindow {
Q_OBJECT
public:
explicit GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_,
explicit GRenderWindow(MainWindow* parent, EmuThread* emu_thread_,
std::shared_ptr<InputCommon::InputSubsystem> input_subsystem_,
Core::System& system_);
~GRenderWindow() override;

View file

@ -2,12 +2,11 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "data_dialog.h"
#include "core/hle/service/acc/profile_manager.h"
#include "frontend_common/data_manager.h"
#include "qt_common/qt_common.h"
#include "qt_common/util/content.h"
#include "qt_common/qt_string_lookup.h"
#include "ui_data_dialog.h"
#include "util/util.h"
#include <QDesktopServices>
#include <QFileDialog>
@ -26,17 +25,18 @@ DataDialog::DataDialog(QWidget *parent)
ui->setupUi(this);
// TODO: Should we make this a single widget that pulls data from a model?
#define WIDGET(name) \
#define WIDGET(label, name) \
ui->page->addWidget(new DataWidget(FrontendCommon::DataManager::DataDir::name, \
QtCommon::StringLookup::name##Tooltip, \
QStringLiteral(#name), \
this));
this)); \
ui->labels->addItem(label);
WIDGET(Shaders)
WIDGET(UserNand)
WIDGET(SysNand)
WIDGET(Mods)
WIDGET(Saves)
WIDGET(tr("Shaders"), Shaders)
WIDGET(tr("UserNAND"), UserNand)
WIDGET(tr("SysNAND"), SysNand)
WIDGET(tr("Mods"), Mods)
WIDGET(tr("Saves"), Saves)
#undef WIDGET
@ -82,7 +82,7 @@ void DataWidget::clear()
{
std::string user_id{};
if (m_dir == FrontendCommon::DataManager::DataDir::Saves) {
user_id = selectProfile();
user_id = GetProfileIDString();
}
QtCommon::Content::ClearDataDir(m_dir, user_id);
scan();
@ -92,7 +92,7 @@ void DataWidget::open()
{
std::string user_id{};
if (m_dir == FrontendCommon::DataManager::DataDir::Saves) {
user_id = selectProfile();
user_id = GetProfileIDString();
}
QDesktopServices::openUrl(QUrl::fromLocalFile(
QString::fromStdString(FrontendCommon::DataManager::GetDataDirString(m_dir, user_id))));
@ -102,7 +102,7 @@ void DataWidget::upload()
{
std::string user_id{};
if (m_dir == FrontendCommon::DataManager::DataDir::Saves) {
user_id = selectProfile();
user_id = GetProfileIDString();
}
QtCommon::Content::ExportDataDir(m_dir, user_id, m_exportName);
}
@ -111,7 +111,7 @@ void DataWidget::download()
{
std::string user_id{};
if (m_dir == FrontendCommon::DataManager::DataDir::Saves) {
user_id = selectProfile();
user_id = GetProfileIDString();
}
QtCommon::Content::ImportDataDir(m_dir, user_id, std::bind(&DataWidget::scan, this));
}
@ -131,37 +131,3 @@ void DataWidget::scan() {
watcher->setFuture(
QtConcurrent::run([this]() { return FrontendCommon::DataManager::DataDirSize(m_dir); }));
}
std::string DataWidget::selectProfile()
{
const auto select_profile = [this] {
const Core::Frontend::ProfileSelectParameters parameters{
.mode = Service::AM::Frontend::UiMode::UserSelector,
.invalid_uid_list = {},
.display_options = {},
.purpose = Service::AM::Frontend::UserSelectionPurpose::General,
};
QtProfileSelectionDialog dialog(*QtCommon::system, this, parameters);
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint
| Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
dialog.setWindowModality(Qt::WindowModal);
if (dialog.exec() == QDialog::Rejected) {
return -1;
}
return dialog.GetIndex();
};
const auto index = select_profile();
if (index == -1) {
return "";
}
const auto uuid = QtCommon::system->GetProfileManager().GetUser(static_cast<std::size_t>(index));
ASSERT(uuid);
const auto user_id = uuid->AsU128();
return fmt::format("{:016X}{:016X}", user_id[1], user_id[0]);
}

View file

@ -36,31 +36,6 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>Shaders</string>
</property>
</item>
<item>
<property name="text">
<string>UserNAND</string>
</property>
</item>
<item>
<property name="text">
<string>SysNAND</string>
</property>
</item>
<item>
<property name="text">
<string>Mods</string>
</property>
</item>
<item>
<property name="text">
<string>Saves</string>
</property>
</item>
</widget>
</item>
<item>

View file

@ -18,7 +18,7 @@ DepsDialog::DepsDialog(QWidget* parent)
{
ui->setupUi(this);
constexpr size_t rows = Common::dep_hashes.size();
constexpr int rows = (int) Common::dep_hashes.size();
ui->tableDeps->setRowCount(rows);
QStringList labels;
@ -29,7 +29,7 @@ DepsDialog::DepsDialog(QWidget* parent)
ui->tableDeps->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeMode::Fixed);
ui->tableDeps->horizontalHeader()->setMinimumSectionSize(200);
for (size_t i = 0; i < rows; ++i) {
for (int i = 0; i < rows; ++i) {
const std::string name = Common::dep_names.at(i);
const std::string sha = Common::dep_hashes.at(i);
const std::string url = Common::dep_urls.at(i);

View file

@ -23,7 +23,7 @@
#include "yuzu/compatibility_list.h"
#include "yuzu/game_list_p.h"
#include "yuzu/game_list_worker.h"
#include "yuzu/main.h"
#include "yuzu/main_window.h"
#include "yuzu/util/controller_navigation.h"
#include <fmt/ranges.h>
#include <regex>
@ -314,7 +314,7 @@ void GameList::OnFilterCloseClicked() {
GameList::GameList(FileSys::VirtualFilesystem vfs_, FileSys::ManualContentProvider* provider_,
PlayTime::PlayTimeManager& play_time_manager_, Core::System& system_,
GMainWindow* parent)
MainWindow* parent)
: QWidget{parent}, vfs{std::move(vfs_)}, provider{provider_},
play_time_manager{play_time_manager_}, system{system_} {
watcher = new QFileSystemWatcher(this);
@ -347,7 +347,7 @@ GameList::GameList(FileSys::VirtualFilesystem vfs_, FileSys::ManualContentProvid
tree_view->setColumnHidden(COLUMN_PLAY_TIME, !UISettings::values.show_play_time);
item_model->setSortRole(GameListItemPath::SortRole);
connect(main_window, &GMainWindow::UpdateThemedIcons, this, &GameList::OnUpdateThemedIcons);
connect(main_window, &MainWindow::UpdateThemedIcons, this, &GameList::OnUpdateThemedIcons);
connect(tree_view, &QTreeView::activated, this, &GameList::ValidateEntry);
connect(tree_view, &QTreeView::customContextMenuRequested, this, &GameList::PopupContextMenu);
connect(tree_view, &QTreeView::expanded, this, &GameList::OnItemExpanded);
@ -943,8 +943,8 @@ void GameList::RemoveFavorite(u64 program_id) {
}
}
GameListPlaceholder::GameListPlaceholder(GMainWindow* parent) : QWidget{parent} {
connect(parent, &GMainWindow::UpdateThemedIcons, this,
GameListPlaceholder::GameListPlaceholder(MainWindow* parent) : QWidget{parent} {
connect(parent, &MainWindow::UpdateThemedIcons, this,
&GameListPlaceholder::onUpdateThemedIcons);
layout = new QVBoxLayout;

View file

@ -33,7 +33,7 @@ class ControllerNavigation;
class GameListWorker;
class GameListSearchField;
class GameListDir;
class GMainWindow;
class MainWindow;
enum class AmLaunchType;
enum class StartGameType;
@ -69,7 +69,7 @@ public:
explicit GameList(std::shared_ptr<FileSys::VfsFilesystem> vfs_,
FileSys::ManualContentProvider* provider_,
PlayTime::PlayTimeManager& play_time_manager_, Core::System& system_,
GMainWindow* parent = nullptr);
MainWindow* parent = nullptr);
~GameList() override;
QString GetLastFilterResultItem() const;
@ -153,7 +153,7 @@ private:
std::shared_ptr<FileSys::VfsFilesystem> vfs;
FileSys::ManualContentProvider* provider;
GameListSearchField* search_field;
GMainWindow* main_window = nullptr;
MainWindow* main_window = nullptr;
QVBoxLayout* layout = nullptr;
QTreeView* tree_view = nullptr;
QStandardItemModel* item_model = nullptr;
@ -171,7 +171,7 @@ private:
class GameListPlaceholder : public QWidget {
Q_OBJECT
public:
explicit GameListPlaceholder(GMainWindow* parent = nullptr);
explicit GameListPlaceholder(MainWindow* parent = nullptr);
~GameListPlaceholder();
signals:

File diff suppressed because it is too large Load diff

4899
src/yuzu/main_window.cpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -29,7 +29,7 @@
#include <QDBusObjectPath>
#include <QVariant>
#include <QtDBus/QDBusInterface>
#include <QtDBus/QtDBus>
#include <QSocketNotifier>
#endif
#ifdef ENABLE_UPDATE_CHECKER
@ -38,7 +38,6 @@
#endif
class QtConfig;
class ClickableLabel;
class EmuThread;
class GameList;
class GImageInfo;
@ -154,7 +153,7 @@ private:
constexpr static int MaxMultiplier = 8;
};
class GMainWindow : public QMainWindow {
class MainWindow : public QMainWindow {
Q_OBJECT
/// Max number of recently loaded items to keep track of
@ -163,8 +162,8 @@ class GMainWindow : public QMainWindow {
public:
void filterBarSetChecked(bool state);
void UpdateUITheme();
explicit GMainWindow(bool has_broken_vulkan);
~GMainWindow() override;
explicit MainWindow(bool has_broken_vulkan);
~MainWindow() override;
bool DropAction(QDropEvent* event);
void AcceptDropEvent(QDropEvent* event);
@ -467,11 +466,9 @@ private:
*/
bool question(QWidget* parent, const QString& title, const QString& text,
QMessageBox::StandardButtons buttons =
QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No),
QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No),
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
std::string GetProfileID();
std::unique_ptr<Ui::MainWindow> ui;
std::unique_ptr<DiscordRPC::DiscordInterface> discord_rpc;

View file

@ -11,11 +11,11 @@
#include "common/fs/path_util.h"
MigrationWorker::MigrationWorker(const Emulator selected_legacy_emu_,
MigrationWorker::MigrationWorker(const Emulator selected_emu_,
const bool clear_shader_cache_,
const MigrationStrategy strategy_)
: QObject()
, selected_legacy_emu(selected_legacy_emu_)
, selected_emu(selected_emu_)
, clear_shader_cache(clear_shader_cache_)
, strategy(strategy_)
{}
@ -25,15 +25,20 @@ void MigrationWorker::process()
namespace fs = std::filesystem;
constexpr auto copy_options = fs::copy_options::update_existing | fs::copy_options::recursive;
const fs::path legacy_user_dir = selected_legacy_emu.get_user_dir();
const fs::path legacy_config_dir = selected_legacy_emu.get_config_dir();
const fs::path legacy_cache_dir = selected_legacy_emu.get_cache_dir();
const fs::path legacy_user_dir = selected_emu.get_user_dir();
const fs::path legacy_config_dir = selected_emu.get_config_dir();
const fs::path legacy_cache_dir = selected_emu.get_cache_dir();
// TODO(crueter): Make these constexpr since they're defaulted
const fs::path eden_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::EdenDir);
const fs::path config_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir);
const fs::path cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir);
const fs::path shader_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir);
fs::path eden_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::EdenDir);
fs::path config_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir);
fs::path cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir);
fs::path shader_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir);
eden_dir.make_preferred();
config_dir.make_preferred();
cache_dir.make_preferred();
shader_dir.make_preferred();
try {
fs::remove_all(eden_dir);
@ -55,8 +60,8 @@ void MigrationWorker::process()
std::exit(-1);
}
// Windows doesn't need any more links, because cache and config
// are already children of the root directory
// Windows doesn't need any more links, because cache and config
// are already children of the root directory
#ifndef WIN32
if (fs::is_directory(legacy_config_dir)) {
Common::FS::CreateSymlink(legacy_config_dir, config_dir);
@ -69,7 +74,7 @@ void MigrationWorker::process()
success_text.append(tr("\n\nNote that your configuration and data will be shared with %1.\n"
"If this is not desirable, delete the following files:\n%2\n%3\n%4")
.arg(selected_legacy_emu.name(),
.arg(selected_emu.name(),
QString::fromStdString(eden_dir.string()),
QString::fromStdString(config_dir.string()),
QString::fromStdString(cache_dir.string())));
@ -79,8 +84,8 @@ void MigrationWorker::process()
// Rename directories if deletion is requested (achieves the same result)
fs::rename(legacy_user_dir, eden_dir);
// Windows doesn't need any more renames, because cache and config
// are already children of the root directory
// Windows doesn't need any more renames, because cache and config
// are already children of the root directory
#ifndef WIN32
if (fs::is_directory(legacy_config_dir)) {
fs::rename(legacy_config_dir, config_dir);
@ -96,8 +101,8 @@ void MigrationWorker::process()
// Default behavior: copy
fs::copy(legacy_user_dir, eden_dir, copy_options);
// Windows doesn't need any more copies, because cache and config
// are already children of the root directory
// Windows doesn't need any more copies, because cache and config
// are already children of the root directory
#ifndef WIN32
if (fs::is_directory(legacy_config_dir)) {
fs::copy(legacy_config_dir, config_dir, copy_options);

View file

@ -7,14 +7,12 @@
#include <QObject>
#include "common/fs/path_util.h"
using namespace Common::FS;
typedef struct Emulator {
const char *m_name;
EmuPath e_user_dir;
EmuPath e_config_dir;
EmuPath e_cache_dir;
Common::FS::EmuPath e_user_dir;
Common::FS::EmuPath e_config_dir;
Common::FS::EmuPath e_cache_dir;
const std::string get_user_dir() const {
return Common::FS::GetLegacyPath(e_user_dir).string();
@ -35,11 +33,13 @@ typedef struct Emulator {
}
} Emulator;
#define STRUCT_EMU(name, enumName) Emulator{name, Common::FS::enumName##Dir, Common::FS::enumName##ConfigDir, Common::FS::enumName##CacheDir}
static constexpr std::array<Emulator, 4> legacy_emus = {
Emulator{QT_TR_NOOP("Citron"), CitronDir, CitronConfigDir, CitronCacheDir},
Emulator{QT_TR_NOOP("Sudachi"), SudachiDir, SudachiConfigDir, SudachiCacheDir},
Emulator{QT_TR_NOOP("Suyu"), SuyuDir, SuyuConfigDir, SuyuCacheDir},
Emulator{QT_TR_NOOP("Yuzu"), YuzuDir, YuzuConfigDir, YuzuCacheDir},
STRUCT_EMU(QT_TR_NOOP("Citron"), Citron),
STRUCT_EMU(QT_TR_NOOP("Sudachi"), Sudachi),
STRUCT_EMU(QT_TR_NOOP("Suyu"), Suyu),
STRUCT_EMU(QT_TR_NOOP("Yuzu"), Yuzu),
};
class MigrationWorker : public QObject
@ -52,7 +52,7 @@ public:
Link,
};
MigrationWorker(const Emulator selected_legacy_emu,
MigrationWorker(const Emulator selected_emu,
const bool clear_shader_cache,
const MigrationStrategy strategy);
@ -64,7 +64,7 @@ signals:
void error(const QString &error_message);
private:
Emulator selected_legacy_emu;
Emulator selected_emu;
bool clear_shader_cache;
MigrationStrategy strategy;
QString success_text = tr("Data was migrated successfully.");

View file

@ -15,7 +15,7 @@
#include "core/internal_network/network_interface.h"
#include "network/network.h"
#include "ui_direct_connect.h"
#include "yuzu/main.h"
#include "yuzu/main_window.h"
#include "yuzu/multiplayer/client_room.h"
#include "yuzu/multiplayer/direct_connect.h"
#include "yuzu/multiplayer/message.h"

View file

@ -20,7 +20,7 @@
#include "network/announce_multiplayer_session.h"
#include "ui_host_room.h"
#include "yuzu/game_list_p.h"
#include "yuzu/main.h"
#include "yuzu/main_window.h"
#include "yuzu/multiplayer/host_room.h"
#include "yuzu/multiplayer/message.h"
#include "yuzu/multiplayer/state.h"

View file

@ -15,7 +15,7 @@
#include "network/network.h"
#include "ui_lobby.h"
#include "yuzu/game_list_p.h"
#include "yuzu/main.h"
#include "yuzu/main_window.h"
#include "yuzu/multiplayer/client_room.h"
#include "yuzu/multiplayer/lobby.h"
#include "yuzu/multiplayer/lobby_p.h"

View file

@ -1,25 +1,25 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "qt_common/abstract/frontend.h"
#include "ryujinx_dialog.h"
#include "qt_common/util/fs.h"
#include "ui_ryujinx_dialog.h"
#include <filesystem>
namespace fs = std::filesystem;
RyujinxDialog::RyujinxDialog(std::filesystem::path eden_path,
std::filesystem::path ryu_path,
QWidget *parent)
: QDialog(parent)
, ui(new Ui::RyujinxDialog)
, m_eden(eden_path.make_preferred())
, m_ryu(ryu_path.make_preferred())
, ui(new Ui::RyujinxDialog)
, m_eden(eden_path.make_preferred())
, m_ryu(ryu_path.make_preferred())
{
ui->setupUi(this);
connect(ui->eden, &QPushButton::clicked, this, &RyujinxDialog::fromEden);
connect(ui->ryujinx, &QPushButton::clicked, this, &RyujinxDialog::fromRyujinx);
connect(ui->cancel, &QPushButton::clicked, this, &RyujinxDialog::reject);
}
RyujinxDialog::~RyujinxDialog()
@ -30,7 +30,21 @@ RyujinxDialog::~RyujinxDialog()
void RyujinxDialog::fromEden()
{
accept();
QtCommon::FS::LinkRyujinx(m_eden, m_ryu);
// Workaround: Ryujinx deletes and re-creates its directory structure???
// So we just copy Eden's data to Ryujinx and then link the other way
namespace fs = std::filesystem;
try {
fs::remove_all(m_ryu);
fs::create_directories(m_ryu);
fs::copy(m_eden, m_ryu, fs::copy_options::recursive);
} catch (std::exception &e) {
QtCommon::Frontend::Critical(tr("Failed to link save data"),
tr("OS returned error: %1").arg(QString::fromStdString(e.what())));
}
// ?ploo
QtCommon::FS::LinkRyujinx(m_ryu, m_eden);
}
void RyujinxDialog::fromRyujinx()

View file

@ -23,8 +23,6 @@
#include <QThread>
#include <filesystem>
namespace fs = std::filesystem;
UserDataMigrator::UserDataMigrator(QMainWindow *main_window)
{
// NOTE: Logging is not initialized yet, do not produce logs here.
@ -32,7 +30,7 @@ UserDataMigrator::UserDataMigrator(QMainWindow *main_window)
// Check migration if config directory does not exist
// TODO: ProfileManager messes with us a bit here, and force-creates the /nand/system/save/8000000000000010/su/avators/profiles.dat
// file. Find a way to reorder operations and have it create after this guy runs.
if (!fs::is_directory(Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir))) {
if (!std::filesystem::is_directory(Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir))) {
ShowMigrationPrompt(main_window);
}
}
@ -40,23 +38,7 @@ UserDataMigrator::UserDataMigrator(QMainWindow *main_window)
void UserDataMigrator::ShowMigrationPrompt(QMainWindow *main_window)
{
namespace fs = std::filesystem;
// define strings here for easy access
QString prompt_prefix_text = QtCommon::StringLookup::Lookup(
QtCommon::StringLookup::MigrationPromptPrefix);
QString migration_prompt_message = QtCommon::StringLookup::Lookup(
QtCommon::StringLookup::MigrationPrompt);
QString clear_shader_tooltip = QtCommon::StringLookup::Lookup(
QtCommon::StringLookup::MigrationTooltipClearShader);
QString keep_old_data_tooltip = QtCommon::StringLookup::Lookup(
QtCommon::StringLookup::MigrationTooltipKeepOld);
QString clear_old_data_tooltip = QtCommon::StringLookup::Lookup(
QtCommon::StringLookup::MigrationTooltipClearOld);
QString link_old_dir_tooltip = QtCommon::StringLookup::Lookup(
QtCommon::StringLookup::MigrationTooltipLinkOld);
// actual migration code
using namespace QtCommon::StringLookup;
MigrationDialog migration_prompt;
migration_prompt.setWindowTitle(QObject::tr("Migration"));
@ -69,11 +51,11 @@ void UserDataMigrator::ShowMigrationPrompt(QMainWindow *main_window)
#define BUTTON(clazz, name, text, tooltip, checkState) \
clazz *name = new clazz(&migration_prompt); \
name->setText(text); \
name->setToolTip(tooltip); \
name->setToolTip(Lookup(tooltip)); \
name->setChecked(checkState); \
migration_prompt.addBox(name);
BUTTON(QCheckBox, clear_shaders, QObject::tr("Clear Shader Cache"), clear_shader_tooltip, true)
BUTTON(QCheckBox, clear_shaders, QObject::tr("Clear Shader Cache"), MigrationTooltipClearShader, true)
u32 id = 0;
@ -81,9 +63,9 @@ void UserDataMigrator::ShowMigrationPrompt(QMainWindow *main_window)
BUTTON(QRadioButton, name, text, tooltip, checkState) \
group->addButton(name, ++id);
RADIO(keep_old, QObject::tr("Keep Old Data"), keep_old_data_tooltip, true)
RADIO(clear_old, QObject::tr("Clear Old Data"), clear_old_data_tooltip, false)
RADIO(link_old, QObject::tr("Link Old Directory"), link_old_dir_tooltip, false)
RADIO(keep_old, QObject::tr("Keep Old Data"), MigrationTooltipKeepOld, true)
RADIO(clear_old, QObject::tr("Clear Old Data"), MigrationTooltipClearOld, false)
RADIO(link_old, QObject::tr("Link Old Directory"), MigrationTooltipLinkOld, false)
#undef RADIO
#undef BUTTON
@ -101,7 +83,7 @@ void UserDataMigrator::ShowMigrationPrompt(QMainWindow *main_window)
// makes my life easier
qRegisterMetaType<Emulator>();
QString prompt_text = prompt_prefix_text;
QString prompt_text = Lookup(MigrationPromptPrefix);
// natural language processing is a nightmare
for (const Emulator &emu : found) {
@ -114,7 +96,7 @@ void UserDataMigrator::ShowMigrationPrompt(QMainWindow *main_window)
}
prompt_text.append(QObject::tr("\n\n"));
prompt_text = prompt_text % QStringLiteral("\n\n") % migration_prompt_message;
prompt_text = prompt_text % QStringLiteral("\n\n") % Lookup(MigrationPrompt);
migration_prompt.setText(prompt_text);
migration_prompt.addButton(QObject::tr("No"), true);
@ -127,24 +109,12 @@ void UserDataMigrator::ShowMigrationPrompt(QMainWindow *main_window)
return ShowMigrationCancelledMessage(main_window);
}
MigrationWorker::MigrationStrategy strategy;
MigrationWorker::MigrationStrategy strategy = static_cast<MigrationWorker::MigrationStrategy>(
group->checkedId());
switch (group->checkedId()) {
default:
[[fallthrough]];
case 1:
strategy = MigrationWorker::MigrationStrategy::Copy;
break;
case 2:
strategy = MigrationWorker::MigrationStrategy::Move;
break;
case 3:
strategy = MigrationWorker::MigrationStrategy::Link;
break;
}
selected_emu = button->property("emulator").value<Emulator>();
MigrateUserData(main_window,
button->property("emulator").value<Emulator>(),
clear_shaders->isChecked(),
strategy);
}
@ -161,12 +131,9 @@ void UserDataMigrator::ShowMigrationCancelledMessage(QMainWindow *main_window)
}
void UserDataMigrator::MigrateUserData(QMainWindow *main_window,
const Emulator selected_legacy_emu,
const bool clear_shader_cache,
const MigrationWorker::MigrationStrategy strategy)
{
selected_emu = selected_legacy_emu;
// Create a dialog to let the user know it's migrating
QProgressDialog *progress = new QProgressDialog(main_window);
progress->setWindowTitle(QObject::tr("Migrating"));
@ -176,7 +143,7 @@ void UserDataMigrator::MigrateUserData(QMainWindow *main_window,
progress->setWindowModality(Qt::WindowModality::ApplicationModal);
QThread *thread = new QThread(main_window);
MigrationWorker *worker = new MigrationWorker(selected_legacy_emu, clear_shader_cache, strategy);
MigrationWorker *worker = new MigrationWorker(selected_emu, clear_shader_cache, strategy);
worker->moveToThread(thread);
thread->connect(thread, &QThread::started, worker, &MigrationWorker::process);

View file

@ -22,7 +22,6 @@ private:
void ShowMigrationPrompt(QMainWindow* main_window);
void ShowMigrationCancelledMessage(QMainWindow* main_window);
void MigrateUserData(QMainWindow* main_window,
const Emulator selected_legacy_emu,
const bool clear_shader_cache,
const MigrationWorker::MigrationStrategy strategy);
};

View file

@ -8,7 +8,11 @@
#include <cmath>
#include <QPainter>
#include "applets/qt_profile_select.h"
#include "common/logging/log.h"
#include "core/frontend/applets/profile_select.h"
#include "core/hle/service/acc/profile_manager.h"
#include "qt_common/qt_common.h"
#include "yuzu/util/util.h"
#ifdef _WIN32
@ -153,3 +157,49 @@ bool SaveIconToFile(const std::filesystem::path& icon_path, const QImage& image)
return false;
#endif
}
const std::optional<Common::UUID> GetProfileID() {
// if there's only a single profile, the user probably wants to use that... right?
const auto& profiles = QtCommon::system->GetProfileManager().FindExistingProfileUUIDs();
if (profiles.size() == 1) {
return profiles[0];
}
const auto select_profile = [] {
const Core::Frontend::ProfileSelectParameters parameters{
.mode = Service::AM::Frontend::UiMode::UserSelector,
.invalid_uid_list = {},
.display_options = {},
.purpose = Service::AM::Frontend::UserSelectionPurpose::General,
};
QtProfileSelectionDialog dialog(*QtCommon::system, QtCommon::rootObject, parameters);
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
dialog.setWindowModality(Qt::WindowModal);
if (dialog.exec() == QDialog::Rejected) {
return -1;
}
return dialog.GetIndex();
};
const auto index = select_profile();
if (index == -1) {
return std::nullopt;
}
const auto uuid =
QtCommon::system->GetProfileManager().GetUser(static_cast<std::size_t>(index));
ASSERT(uuid);
return uuid;
}
std::string GetProfileIDString() {
const auto uuid = GetProfileID();
if (!uuid)
return "";
auto user_id = uuid->AsU128();
return fmt::format("{:016X}{:016X}", user_id[1], user_id[0]);
}

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2015 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -6,6 +9,7 @@
#include <filesystem>
#include <QFont>
#include <QString>
#include "common/uuid.h"
/// Returns a QFont object appropriate to use as a monospace font for debugging widgets, etc.
[[nodiscard]] QFont GetMonospaceFont();
@ -27,3 +31,15 @@
* @return bool If the operation succeeded
*/
[[nodiscard]] bool SaveIconToFile(const std::filesystem::path& icon_path, const QImage& image);
/**
* Prompt the user for a profile ID. If there is only one valid profile, returns that profile.
* @return The selected profile, or an std::nullopt if none were selected
*/
const std::optional<Common::UUID> GetProfileID();
/**
* Prompt the user for a profile ID. If there is only one valid profile, returns that profile.
* @return A string representation of the selected profile, or an empty string if none were seleeced
*/
std::string GetProfileIDString();