From 11db0f0dbf73ab933d43352183430f64c4d1d70e Mon Sep 17 00:00:00 2001 From: crueter Date: Tue, 22 Jul 2025 16:31:36 -0400 Subject: [PATCH 01/34] qt_common init Signed-off-by: crueter --- ffmpeg.patch | 40 ++++++++++++++++ src/CMakeLists.txt | 1 + src/qt_common/CMakeLists.txt | 23 +++++++++ src/{yuzu => qt_common}/qt_common.cpp | 25 ++++++++-- src/qt_common/qt_common.h | 47 +++++++++++++++++++ .../configuration => qt_common}/qt_config.cpp | 0 .../configuration => qt_common}/qt_config.h | 0 .../shared_translation.cpp | 10 ++-- .../shared_translation.h | 9 ++-- src/{yuzu => qt_common}/uisettings.cpp | 2 +- src/{yuzu => qt_common}/uisettings.h | 2 +- src/yuzu/CMakeLists.txt | 13 ++--- src/yuzu/bootmanager.cpp | 9 ++-- src/yuzu/configuration/configure_audio.cpp | 4 +- src/yuzu/configuration/configure_cpu.h | 2 +- src/yuzu/configuration/configure_debug.cpp | 2 +- src/yuzu/configuration/configure_dialog.cpp | 2 +- src/yuzu/configuration/configure_dialog.h | 2 +- .../configuration/configure_filesystem.cpp | 28 +++++------ src/yuzu/configuration/configure_general.cpp | 2 +- src/yuzu/configuration/configure_graphics.cpp | 4 +- src/yuzu/configuration/configure_graphics.h | 2 +- .../configure_graphics_advanced.cpp | 2 +- .../configure_graphics_extensions.cpp | 2 +- src/yuzu/configuration/configure_hotkeys.cpp | 2 +- .../configuration/configure_input_per_game.h | 2 +- .../configuration/configure_input_player.cpp | 2 +- src/yuzu/configuration/configure_per_game.cpp | 2 +- src/yuzu/configuration/configure_per_game.h | 4 +- .../configure_per_game_addons.cpp | 2 +- src/yuzu/configuration/configure_ringcon.cpp | 2 +- src/yuzu/configuration/configure_tas.cpp | 2 +- src/yuzu/configuration/configure_ui.cpp | 2 +- src/yuzu/configuration/configure_web.cpp | 2 +- src/yuzu/configuration/input_profiles.h | 2 +- src/yuzu/configuration/shared_widget.cpp | 2 +- src/yuzu/configuration/shared_widget.h | 2 +- src/yuzu/debugger/console.cpp | 2 +- src/yuzu/debugger/wait_tree.cpp | 2 +- src/yuzu/game_list.cpp | 15 ++---- src/yuzu/game_list.h | 5 +- src/yuzu/game_list_p.h | 2 +- src/yuzu/game_list_worker.cpp | 30 ++++-------- src/yuzu/game_list_worker.h | 7 +-- src/yuzu/hotkeys.cpp | 2 +- src/yuzu/install_dialog.cpp | 2 +- src/yuzu/main.cpp | 27 ++++++----- src/yuzu/main.h | 2 +- src/yuzu/multiplayer/direct_connect.cpp | 2 +- src/yuzu/multiplayer/host_room.cpp | 2 +- src/yuzu/multiplayer/lobby.cpp | 2 +- src/yuzu/multiplayer/state.cpp | 2 +- src/yuzu/play_time_manager.cpp | 1 - src/yuzu/play_time_manager.h | 3 +- src/yuzu/qt_common.h | 15 ------ src/yuzu/vk_device_info.cpp | 2 +- 56 files changed, 233 insertions(+), 153 deletions(-) create mode 100644 ffmpeg.patch create mode 100644 src/qt_common/CMakeLists.txt rename src/{yuzu => qt_common}/qt_common.cpp (80%) create mode 100644 src/qt_common/qt_common.h rename src/{yuzu/configuration => qt_common}/qt_config.cpp (100%) rename src/{yuzu/configuration => qt_common}/qt_config.h (100%) rename src/{yuzu/configuration => qt_common}/shared_translation.cpp (99%) rename src/{yuzu/configuration => qt_common}/shared_translation.h (94%) rename src/{yuzu => qt_common}/uisettings.cpp (99%) rename src/{yuzu => qt_common}/uisettings.h (99%) delete mode 100644 src/yuzu/qt_common.h diff --git a/ffmpeg.patch b/ffmpeg.patch new file mode 100644 index 0000000000..58fa9dff61 --- /dev/null +++ b/ffmpeg.patch @@ -0,0 +1,40 @@ +diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt +index 54c852f831..ff35c8dc2c 100644 +--- a/externals/ffmpeg/CMakeLists.txt ++++ b/externals/ffmpeg/CMakeLists.txt +@@ -63,20 +63,22 @@ if (NOT WIN32 AND NOT ANDROID) + set(FFmpeg_HWACCEL_INCLUDE_DIRS) + set(FFmpeg_HWACCEL_LDFLAGS) + +- # In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so +- if(PLATFORM_SUN) +- list(APPEND FFmpeg_HWACCEL_LIBRARIES +- X11 +- "/usr/lib/xorg/amd64/libdrm.so") +- else() +- pkg_check_modules(LIBDRM libdrm REQUIRED) +- list(APPEND FFmpeg_HWACCEL_LIBRARIES +- ${LIBDRM_LIBRARIES}) +- list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS +- ${LIBDRM_INCLUDE_DIRS}) ++ if (NOT APPLE) ++ # In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so ++ if(PLATFORM_SUN) ++ list(APPEND FFmpeg_HWACCEL_LIBRARIES ++ X11 ++ "/usr/lib/xorg/amd64/libdrm.so") ++ else() ++ pkg_check_modules(LIBDRM libdrm REQUIRED) ++ list(APPEND FFmpeg_HWACCEL_LIBRARIES ++ ${LIBDRM_LIBRARIES}) ++ list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ++ ${LIBDRM_INCLUDE_DIRS}) ++ endif() ++ list(APPEND FFmpeg_HWACCEL_FLAGS ++ --enable-libdrm) + endif() +- list(APPEND FFmpeg_HWACCEL_FLAGS +- --enable-libdrm) + + if(LIBVA_FOUND) + find_package(X11 REQUIRED) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eb66e55964..0032b20029 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -234,6 +234,7 @@ if (YUZU_ROOM_STANDALONE) endif() if (ENABLE_QT) + add_subdirectory(qt_common) add_subdirectory(yuzu) endif() diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt new file mode 100644 index 0000000000..be1a8ebbd0 --- /dev/null +++ b/src/qt_common/CMakeLists.txt @@ -0,0 +1,23 @@ +# SPDX-FileCopyrightText: 2023 yuzu Emulator Project +# SPDX-License-Identifier: GPL-2.0-or-later + +add_library(qt_common STATIC + qt_common.h + qt_common.cpp + + uisettings.cpp + uisettings.h + + qt_config.cpp + qt_config.h + + shared_translation.cpp + shared_translation.h +) + +create_target_directory_groups(qt_common) +target_link_libraries(qt_common PUBLIC core Qt6::Core Qt6::Gui SimpleIni::SimpleIni) + +if (NOT WIN32) + target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) +endif() diff --git a/src/yuzu/qt_common.cpp b/src/qt_common/qt_common.cpp similarity index 80% rename from src/yuzu/qt_common.cpp rename to src/qt_common/qt_common.cpp index 413402165c..29379c1d54 100644 --- a/src/yuzu/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -1,12 +1,13 @@ -// SPDX-FileCopyrightText: 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later +#include "qt_common.h" +#include "common/fs/fs.h" +#include "common/fs/path_util.h" +#include "uisettings.h" #include #include #include #include "common/logging/log.h" #include "core/frontend/emu_window.h" -#include "yuzu/qt_common.h" #if !defined(WIN32) && !defined(__APPLE__) #include @@ -15,6 +16,21 @@ #endif namespace QtCommon { + +MetadataResult ResetMetadata() +{ + if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) + / "game_list/")) { + return Empty; + } else if (Common::FS::RemoveDirRecursively( + Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) { + return Success; + UISettings::values.is_game_list_reload_pending.exchange(true); + } else { + return Failure; + } +} + Core::Frontend::WindowSystemType GetWindowSystemType() { // Determine WSI type based on Qt platform. QString platform_name = QGuiApplication::platformName(); @@ -57,4 +73,5 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) return wsi; } -} // namespace QtCommon + +} diff --git a/src/qt_common/qt_common.h b/src/qt_common/qt_common.h new file mode 100644 index 0000000000..3c7dddfc1f --- /dev/null +++ b/src/qt_common/qt_common.h @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef QT_COMMON_H +#define QT_COMMON_H + +#include + +#include +#include + +namespace QtCommon { + +static constexpr std::array METADATA_RESULTS = { + "The operation completed successfully.", + "The metadata cache couldn't be deleted. It might be in use or non-existent.", + "The metadata cache is already empty.", +}; + +enum MetadataResult { + Success, + Failure, + Empty, +}; +/** + * @brief ResetMetadata Reset game list metadata. + * @return A result code. + */ +MetadataResult ResetMetadata(); + +/** + * \brief Get a string representation of a result from ResetMetadata. + * \param result The result code. + * \return A string representation of the passed result code. + */ +inline constexpr const char *GetResetMetadataResultString(MetadataResult result) +{ + return METADATA_RESULTS.at(static_cast(result)); +} + +Core::Frontend::WindowSystemType GetWindowSystemType(); + +Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window); + + +} // namespace QtCommon +#endif diff --git a/src/yuzu/configuration/qt_config.cpp b/src/qt_common/qt_config.cpp similarity index 100% rename from src/yuzu/configuration/qt_config.cpp rename to src/qt_common/qt_config.cpp diff --git a/src/yuzu/configuration/qt_config.h b/src/qt_common/qt_config.h similarity index 100% rename from src/yuzu/configuration/qt_config.h rename to src/qt_common/qt_config.h diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/qt_common/shared_translation.cpp similarity index 99% rename from src/yuzu/configuration/shared_translation.cpp rename to src/qt_common/shared_translation.cpp index 1137145659..018af56c67 100644 --- a/src/yuzu/configuration/shared_translation.cpp +++ b/src/qt_common/shared_translation.cpp @@ -7,23 +7,21 @@ // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "yuzu/configuration/shared_translation.h" +#include "shared_translation.h" #include -#include #include "common/settings.h" #include "common/settings_enums.h" #include "common/settings_setting.h" #include "common/time_zone.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #include #include -#include #include namespace ConfigurationShared { -std::unique_ptr InitializeTranslations(QWidget* parent) +std::unique_ptr InitializeTranslations(QObject* parent) { std::unique_ptr translations = std::make_unique(); const auto& tr = [parent](const char* text) -> QString { return parent->tr(text); }; @@ -473,7 +471,7 @@ std::unique_ptr InitializeTranslations(QWidget* parent) return translations; } -std::unique_ptr ComboboxEnumeration(QWidget* parent) +std::unique_ptr ComboboxEnumeration(QObject* parent) { std::unique_ptr translations = std::make_unique(); const auto& tr = [&](const char* text, const char* context = "") { diff --git a/src/yuzu/configuration/shared_translation.h b/src/qt_common/shared_translation.h similarity index 94% rename from src/yuzu/configuration/shared_translation.h rename to src/qt_common/shared_translation.h index 574b1e2c78..48a2cb5205 100644 --- a/src/yuzu/configuration/shared_translation.h +++ b/src/qt_common/shared_translation.h @@ -11,23 +11,20 @@ #include #include -#include #include #include #include #include "common/common_types.h" -#include "common/settings.h" - -class QWidget; +#include "common/settings_enums.h" namespace ConfigurationShared { using TranslationMap = std::map>; using ComboboxTranslations = std::vector>; using ComboboxTranslationMap = std::map; -std::unique_ptr InitializeTranslations(QWidget* parent); +std::unique_ptr InitializeTranslations(QObject *parent); -std::unique_ptr ComboboxEnumeration(QWidget* parent); +std::unique_ptr ComboboxEnumeration(QObject* parent); static const std::map anti_aliasing_texts_map = { {Settings::AntiAliasing::None, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "None"))}, diff --git a/src/yuzu/uisettings.cpp b/src/qt_common/uisettings.cpp similarity index 99% rename from src/yuzu/uisettings.cpp rename to src/qt_common/uisettings.cpp index 6da5424775..a17f3c0a4a 100644 --- a/src/yuzu/uisettings.cpp +++ b/src/qt_common/uisettings.cpp @@ -7,7 +7,7 @@ #include #include "common/fs/fs.h" #include "common/fs/path_util.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #ifndef CANNOT_EXPLICITLY_INSTANTIATE namespace Settings { diff --git a/src/yuzu/uisettings.h b/src/qt_common/uisettings.h similarity index 99% rename from src/yuzu/uisettings.h rename to src/qt_common/uisettings.h index 3322b31ca3..4981d98dbf 100644 --- a/src/yuzu/uisettings.h +++ b/src/qt_common/uisettings.h @@ -17,7 +17,7 @@ #include "common/common_types.h" #include "common/settings.h" #include "common/settings_enums.h" -#include "configuration/qt_config.h" +#include "qt_common/qt_config.h" using Settings::Category; using Settings::ConfirmStop; diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index d663f6c282..9e052b385d 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -150,12 +150,8 @@ add_executable(yuzu configuration/configure_web.ui configuration/input_profiles.cpp configuration/input_profiles.h - configuration/shared_translation.cpp - configuration/shared_translation.h configuration/shared_widget.cpp configuration/shared_widget.h - configuration/qt_config.cpp - configuration/qt_config.h debugger/console.cpp debugger/console.h debugger/controller.cpp @@ -205,12 +201,8 @@ add_executable(yuzu play_time_manager.cpp play_time_manager.h precompiled_headers.h - qt_common.cpp - qt_common.h startup_checks.cpp startup_checks.h - uisettings.cpp - uisettings.h util/clickable_label.cpp util/clickable_label.h util/controller_navigation.cpp @@ -396,14 +388,17 @@ elseif(WIN32) endif() endif() -target_link_libraries(yuzu PRIVATE common core input_common frontend_common network video_core) target_link_libraries(yuzu PRIVATE nlohmann_json::nlohmann_json) +target_link_libraries(yuzu PRIVATE common core input_common frontend_common network video_core qt_common) target_link_libraries(yuzu PRIVATE Boost::headers glad Qt6::Widgets) target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) if (NOT WIN32) target_include_directories(yuzu PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) endif() + +target_link_libraries(yuzu PRIVATE Vulkan::Headers) + if (UNIX AND NOT APPLE) target_link_libraries(yuzu PRIVATE Qt6::DBus) diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 63e7a74003..7b5f2a314f 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -12,7 +12,7 @@ #include #include "common/settings_enums.h" -#include "uisettings.h" +#include "qt_common/uisettings.h" #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA #include #include @@ -58,7 +58,7 @@ #include "video_core/renderer_base.h" #include "yuzu/bootmanager.h" #include "yuzu/main.h" -#include "yuzu/qt_common.h" +#include "qt_common/qt_common.h" class QObject; class QPaintEngine; @@ -234,7 +234,7 @@ class DummyContext : public Core::Frontend::GraphicsContext {}; class RenderWidget : public QWidget { public: - explicit RenderWidget(GRenderWindow* parent) : QWidget(parent), render_window(parent) { + explicit RenderWidget(GRenderWindow* parent) : QWidget(parent) { setAttribute(Qt::WA_NativeWindow); setAttribute(Qt::WA_PaintOnScreen); if (QtCommon::GetWindowSystemType() == Core::Frontend::WindowSystemType::Wayland) { @@ -247,9 +247,6 @@ public: QPaintEngine* paintEngine() const override { return nullptr; } - -private: - GRenderWindow* render_window; }; struct OpenGLRenderWidget : public RenderWidget { diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp index c235b0fca4..8d11920d31 100644 --- a/src/yuzu/configuration/configure_audio.cpp +++ b/src/yuzu/configuration/configure_audio.cpp @@ -16,9 +16,9 @@ #include "ui_configure_audio.h" #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_audio.h" -#include "yuzu/configuration/shared_translation.h" +#include "qt_common/shared_translation.h" #include "yuzu/configuration/shared_widget.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" ConfigureAudio::ConfigureAudio(const Core::System& system_, std::shared_ptr> group_, diff --git a/src/yuzu/configuration/configure_cpu.h b/src/yuzu/configuration/configure_cpu.h index 098e0e397b..16cf74af33 100644 --- a/src/yuzu/configuration/configure_cpu.h +++ b/src/yuzu/configuration/configure_cpu.h @@ -7,7 +7,7 @@ #include #include #include "yuzu/configuration/configuration_shared.h" -#include "yuzu/configuration/shared_translation.h" +#include "qt_common/shared_translation.h" class QComboBox; diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index 733c419c4b..18f629f639 100644 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp @@ -15,7 +15,7 @@ #include "ui_configure_debug.h" #include "yuzu/configuration/configure_debug.h" #include "yuzu/debugger/console.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" ConfigureDebug::ConfigureDebug(const Core::System& system_, QWidget* parent) : QScrollArea(parent), ui{std::make_unique()}, system{system_} { diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 987b1462db..4e128106e7 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -27,7 +27,7 @@ #include "yuzu/configuration/configure_ui.h" #include "yuzu/configuration/configure_web.h" #include "yuzu/hotkeys.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_, InputCommon::InputSubsystem* input_subsystem, diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h index 0b6b285678..bf96035752 100644 --- a/src/yuzu/configuration/configure_dialog.h +++ b/src/yuzu/configuration/configure_dialog.h @@ -8,7 +8,7 @@ #include #include "configuration/shared_widget.h" #include "yuzu/configuration/configuration_shared.h" -#include "yuzu/configuration/shared_translation.h" +#include "qt_common/shared_translation.h" #include "yuzu/vk_device_info.h" namespace Core { diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp index f25f14708b..392155d2a3 100644 --- a/src/yuzu/configuration/configure_filesystem.cpp +++ b/src/yuzu/configuration/configure_filesystem.cpp @@ -1,14 +1,15 @@ // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "yuzu/configuration/configure_filesystem.h" #include #include #include "common/fs/fs.h" #include "common/fs/path_util.h" #include "common/settings.h" +#include "qt_common/qt_common.h" +#include "qt_common/uisettings.h" #include "ui_configure_filesystem.h" -#include "yuzu/configuration/configure_filesystem.h" -#include "yuzu/uisettings.h" ConfigureFilesystem::ConfigureFilesystem(QWidget* parent) : QWidget(parent), ui(std::make_unique()) { @@ -126,19 +127,16 @@ void ConfigureFilesystem::SetDirectory(DirectoryTarget target, QLineEdit* edit) } void ConfigureFilesystem::ResetMetadata() { - if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / - "game_list/")) { - QMessageBox::information(this, tr("Reset Metadata Cache"), - tr("The metadata cache is already empty.")); - } else if (Common::FS::RemoveDirRecursively( - Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) { - QMessageBox::information(this, tr("Reset Metadata Cache"), - tr("The operation completed successfully.")); - UISettings::values.is_game_list_reload_pending.exchange(true); - } else { - QMessageBox::warning( - this, tr("Reset Metadata Cache"), - tr("The metadata cache couldn't be deleted. It might be in use or non-existent.")); + auto result = QtCommon::ResetMetadata(); + const QString resultMessage = tr(QtCommon::GetResetMetadataResultString(result)); + const QString title = tr("Reset Metadata Cache"); + + switch (result) { + case QtCommon::Failure: + QMessageBox::warning(this, title, resultMessage); + break; + default: + QMessageBox::information(this, title, resultMessage); } } diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 918fa15d4d..352ae8ab85 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -11,7 +11,7 @@ #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_general.h" #include "yuzu/configuration/shared_widget.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" ConfigureGeneral::ConfigureGeneral(const Core::System& system_, std::shared_ptr> group_, diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index 16846878f9..e1e68b917a 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -40,8 +40,8 @@ #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_graphics.h" #include "yuzu/configuration/shared_widget.h" -#include "yuzu/qt_common.h" -#include "yuzu/uisettings.h" +#include "qt_common/qt_common.h" +#include "qt_common/uisettings.h" #include "yuzu/vk_device_info.h" static const std::vector default_present_modes{VK_PRESENT_MODE_IMMEDIATE_KHR, diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h index b92b4496ba..9f7ece5714 100644 --- a/src/yuzu/configuration/configure_graphics.h +++ b/src/yuzu/configuration/configure_graphics.h @@ -15,7 +15,7 @@ #include #include "common/common_types.h" #include "common/settings_enums.h" -#include "configuration/shared_translation.h" +#include "qt_common/shared_translation.h" #include "vk_device_info.h" #include "yuzu/configuration/configuration_shared.h" diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp index 4db18673d4..921cb83b08 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.cpp +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp @@ -9,7 +9,7 @@ #include "ui_configure_graphics_advanced.h" #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_graphics_advanced.h" -#include "yuzu/configuration/shared_translation.h" +#include "qt_common/shared_translation.h" #include "yuzu/configuration/shared_widget.h" ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced( diff --git a/src/yuzu/configuration/configure_graphics_extensions.cpp b/src/yuzu/configuration/configure_graphics_extensions.cpp index 322fa9ea08..c4c7fbb31f 100644 --- a/src/yuzu/configuration/configure_graphics_extensions.cpp +++ b/src/yuzu/configuration/configure_graphics_extensions.cpp @@ -11,7 +11,7 @@ #include "ui_configure_graphics_extensions.h" #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_graphics_extensions.h" -#include "yuzu/configuration/shared_translation.h" +#include "qt_common/shared_translation.h" #include "yuzu/configuration/shared_widget.h" ConfigureGraphicsExtensions::ConfigureGraphicsExtensions( diff --git a/src/yuzu/configuration/configure_hotkeys.cpp b/src/yuzu/configuration/configure_hotkeys.cpp index 3f68de12d8..53f7401ef4 100644 --- a/src/yuzu/configuration/configure_hotkeys.cpp +++ b/src/yuzu/configuration/configure_hotkeys.cpp @@ -13,7 +13,7 @@ #include "ui_configure_hotkeys.h" #include "yuzu/configuration/configure_hotkeys.h" #include "yuzu/hotkeys.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #include "yuzu/util/sequence_dialog/sequence_dialog.h" constexpr int name_column = 0; diff --git a/src/yuzu/configuration/configure_input_per_game.h b/src/yuzu/configuration/configure_input_per_game.h index 4420e856cb..1323d101d3 100644 --- a/src/yuzu/configuration/configure_input_per_game.h +++ b/src/yuzu/configuration/configure_input_per_game.h @@ -9,7 +9,7 @@ #include "ui_configure_input_per_game.h" #include "yuzu/configuration/input_profiles.h" -#include "yuzu/configuration/qt_config.h" +#include "qt_common/qt_config.h" class QComboBox; diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index d0dc0ff44c..6afa8320a2 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -14,7 +14,7 @@ #include #include "common/assert.h" #include "common/param_package.h" -#include "configuration/qt_config.h" +#include "qt_common/qt_config.h" #include "hid_core/frontend/emulated_controller.h" #include "hid_core/hid_core.h" #include "hid_core/hid_types.h" diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp index 031a8d4c2d..545c37a2c9 100644 --- a/src/yuzu/configuration/configure_per_game.cpp +++ b/src/yuzu/configuration/configure_per_game.cpp @@ -38,7 +38,7 @@ #include "yuzu/configuration/configure_per_game.h" #include "yuzu/configuration/configure_per_game_addons.h" #include "yuzu/configuration/configure_system.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #include "yuzu/util/util.h" #include "yuzu/vk_device_info.h" diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h index e0f4e5cd67..a756b561a8 100644 --- a/src/yuzu/configuration/configure_per_game.h +++ b/src/yuzu/configuration/configure_per_game.h @@ -15,8 +15,8 @@ #include "frontend_common/config.h" #include "vk_device_info.h" #include "yuzu/configuration/configuration_shared.h" -#include "yuzu/configuration/qt_config.h" -#include "yuzu/configuration/shared_translation.h" +#include "qt_common/qt_config.h" +#include "qt_common/shared_translation.h" namespace Core { class System; diff --git a/src/yuzu/configuration/configure_per_game_addons.cpp b/src/yuzu/configuration/configure_per_game_addons.cpp index 078f2e8288..90c94cb923 100644 --- a/src/yuzu/configuration/configure_per_game_addons.cpp +++ b/src/yuzu/configuration/configure_per_game_addons.cpp @@ -21,7 +21,7 @@ #include "ui_configure_per_game_addons.h" #include "yuzu/configuration/configure_input.h" #include "yuzu/configuration/configure_per_game_addons.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" ConfigurePerGameAddons::ConfigurePerGameAddons(Core::System& system_, QWidget* parent) : QWidget(parent), ui{std::make_unique()}, system{system_} { diff --git a/src/yuzu/configuration/configure_ringcon.cpp b/src/yuzu/configuration/configure_ringcon.cpp index f7249be97e..7e7877aaf6 100644 --- a/src/yuzu/configuration/configure_ringcon.cpp +++ b/src/yuzu/configuration/configure_ringcon.cpp @@ -8,7 +8,7 @@ #include #include -#include "configuration/qt_config.h" +#include "qt_common/qt_config.h" #include "hid_core/frontend/emulated_controller.h" #include "hid_core/hid_core.h" #include "input_common/drivers/keyboard.h" diff --git a/src/yuzu/configuration/configure_tas.cpp b/src/yuzu/configuration/configure_tas.cpp index 773658bf22..290e825fe6 100644 --- a/src/yuzu/configuration/configure_tas.cpp +++ b/src/yuzu/configuration/configure_tas.cpp @@ -8,7 +8,7 @@ #include "common/settings.h" #include "ui_configure_tas.h" #include "yuzu/configuration/configure_tas.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" ConfigureTasDialog::ConfigureTasDialog(QWidget* parent) : QDialog(parent), ui(std::make_unique()) { diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp index 8dafee628b..ac6d6e34aa 100644 --- a/src/yuzu/configuration/configure_ui.cpp +++ b/src/yuzu/configuration/configure_ui.cpp @@ -27,7 +27,7 @@ #include "core/core.h" #include "core/frontend/framebuffer_layout.h" #include "ui_configure_ui.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" namespace { constexpr std::array default_game_icon_sizes{ diff --git a/src/yuzu/configuration/configure_web.cpp b/src/yuzu/configuration/configure_web.cpp index d62b5b0853..15a0029901 100644 --- a/src/yuzu/configuration/configure_web.cpp +++ b/src/yuzu/configuration/configure_web.cpp @@ -17,7 +17,7 @@ #include #include "common/settings.h" #include "ui_configure_web.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" ConfigureWeb::ConfigureWeb(QWidget* parent) : QWidget(parent) diff --git a/src/yuzu/configuration/input_profiles.h b/src/yuzu/configuration/input_profiles.h index 023ec74a63..64dcf0e603 100644 --- a/src/yuzu/configuration/input_profiles.h +++ b/src/yuzu/configuration/input_profiles.h @@ -6,7 +6,7 @@ #include #include -#include "configuration/qt_config.h" +#include "qt_common/qt_config.h" namespace Core { class System; diff --git a/src/yuzu/configuration/shared_widget.cpp b/src/yuzu/configuration/shared_widget.cpp index e23d86dc69..02b354b0a5 100644 --- a/src/yuzu/configuration/shared_widget.cpp +++ b/src/yuzu/configuration/shared_widget.cpp @@ -42,7 +42,7 @@ #include "common/logging/log.h" #include "common/settings.h" #include "common/settings_common.h" -#include "yuzu/configuration/shared_translation.h" +#include "qt_common/shared_translation.h" namespace ConfigurationShared { diff --git a/src/yuzu/configuration/shared_widget.h b/src/yuzu/configuration/shared_widget.h index 5c67d83542..a793347ce5 100644 --- a/src/yuzu/configuration/shared_widget.h +++ b/src/yuzu/configuration/shared_widget.h @@ -11,7 +11,7 @@ #include #include #include -#include "yuzu/configuration/shared_translation.h" +#include "qt_common/shared_translation.h" class QCheckBox; class QComboBox; diff --git a/src/yuzu/debugger/console.cpp b/src/yuzu/debugger/console.cpp index 1c1342ff18..40b2fddbc9 100644 --- a/src/yuzu/debugger/console.cpp +++ b/src/yuzu/debugger/console.cpp @@ -9,7 +9,7 @@ #include "common/logging/backend.h" #include "yuzu/debugger/console.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" namespace Debugger { void ToggleConsole() { diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 9f9e21bc28..f32f6348a5 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -5,7 +5,7 @@ #include #include "yuzu/debugger/wait_tree.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #include "core/arm/debug.h" #include "core/core.h" diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 1ecef4af92..0d89dc892e 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -24,7 +24,7 @@ #include "yuzu/game_list_p.h" #include "yuzu/game_list_worker.h" #include "yuzu/main.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #include "yuzu/util/controller_navigation.h" GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist_, QObject* parent) @@ -820,7 +820,7 @@ QStandardItemModel* GameList::GetModel() const { return item_model; } -void GameList::PopulateAsync(QVector& game_dirs, const bool cached) +void GameList::PopulateAsync(QVector& game_dirs) { tree_view->setEnabled(false); @@ -843,8 +843,7 @@ void GameList::PopulateAsync(QVector& game_dirs, const bool game_dirs, compatibility_list, play_time_manager, - system, - cached); + system); // Get events from the worker as data becomes available connect(current_worker.get(), &GameListWorker::DataAvailable, this, &GameList::WorkerEvent, @@ -873,14 +872,6 @@ const QStringList GameList::supported_file_extensions = { QStringLiteral("nso"), QStringLiteral("nro"), QStringLiteral("nca"), QStringLiteral("xci"), QStringLiteral("nsp"), QStringLiteral("kip")}; -void GameList::ForceRefreshGameDirectory() -{ - if (!UISettings::values.game_dirs.empty() && current_worker != nullptr) { - LOG_INFO(Frontend, "Force-reloading game list per user request."); - PopulateAsync(UISettings::values.game_dirs, false); - } -} - void GameList::RefreshGameDirectory() { if (!UISettings::values.game_dirs.empty() && current_worker != nullptr) { diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 7c492bc19f..328432138c 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h @@ -20,7 +20,7 @@ #include "common/common_types.h" #include "core/core.h" -#include "uisettings.h" +#include "qt_common/uisettings.h" #include "yuzu/compatibility_list.h" #include "yuzu/play_time_manager.h" @@ -97,7 +97,7 @@ public: bool IsEmpty() const; void LoadCompatibilityList(); - void PopulateAsync(QVector& game_dirs, const bool cached = true); + void PopulateAsync(QVector& game_dirs); void SaveInterfaceLayout(); void LoadInterfaceLayout(); @@ -110,7 +110,6 @@ public: static const QStringList supported_file_extensions; public slots: - void ForceRefreshGameDirectory(); void RefreshGameDirectory(); signals: diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index c330b574f9..b3e05b8b34 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h @@ -19,7 +19,7 @@ #include "common/logging/log.h" #include "common/string_util.h" #include "yuzu/play_time_manager.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #include "yuzu/util/util.h" enum class GameListItemType { diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp index 60109769bf..267faa7182 100644 --- a/src/yuzu/game_list_worker.cpp +++ b/src/yuzu/game_list_worker.cpp @@ -27,7 +27,7 @@ #include "yuzu/game_list.h" #include "yuzu/game_list_p.h" #include "yuzu/game_list_worker.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" namespace { @@ -199,8 +199,7 @@ QList MakeGameListEntry(const std::string& path, u64 program_id, const CompatibilityList& compatibility_list, const PlayTime::PlayTimeManager& play_time_manager, - const FileSys::PatchManager& patch, - const bool cached) + const FileSys::PatchManager& patch) { const auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); @@ -224,14 +223,10 @@ QList MakeGameListEntry(const std::string& path, QString patch_versions; - if (cached) { - patch_versions = GetGameListCachedObject( - fmt::format("{:016X}", patch.GetTitleID()), "pv.txt", [&patch, &loader] { - return FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable()); - }); - } else { - patch_versions = FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable()); - } + patch_versions = GetGameListCachedObject( + fmt::format("{:016X}", patch.GetTitleID()), "pv.txt", [&patch, &loader] { + return FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable()); + }); list.insert(2, new GameListItem(patch_versions)); @@ -244,15 +239,13 @@ GameListWorker::GameListWorker(FileSys::VirtualFilesystem vfs_, QVector& game_dirs_, const CompatibilityList& compatibility_list_, const PlayTime::PlayTimeManager& play_time_manager_, - Core::System& system_, - const bool cached_) + Core::System& system_) : vfs{std::move(vfs_)} , provider{provider_} , game_dirs{game_dirs_} , compatibility_list{compatibility_list_} , play_time_manager{play_time_manager_} , system{system_} - , cached{cached_} { // We want the game list to manage our lifetime. setAutoDelete(false); @@ -355,8 +348,7 @@ void GameListWorker::AddTitlesToGameList(GameListDir* parent_dir) { program_id, compatibility_list, play_time_manager, - patch, - cached); + patch); RecordEvent([=](GameList* game_list) { game_list->AddEntry(entry, parent_dir); }); } } @@ -439,8 +431,7 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa id, compatibility_list, play_time_manager, - patch, - cached); + patch); RecordEvent( [=](GameList* game_list) { game_list->AddEntry(entry, parent_dir); }); @@ -463,8 +454,7 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa program_id, compatibility_list, play_time_manager, - patch, - cached); + patch); RecordEvent( [=](GameList* game_list) { game_list->AddEntry(entry, parent_dir); }); diff --git a/src/yuzu/game_list_worker.h b/src/yuzu/game_list_worker.h index 0afd7c7849..5c5fbb251f 100644 --- a/src/yuzu/game_list_worker.h +++ b/src/yuzu/game_list_worker.h @@ -15,7 +15,7 @@ #include "common/thread.h" #include "core/file_sys/registered_cache.h" -#include "uisettings.h" +#include "qt_common/uisettings.h" #include "yuzu/compatibility_list.h" #include "yuzu/play_time_manager.h" @@ -45,8 +45,7 @@ public: QVector& game_dirs_, const CompatibilityList& compatibility_list_, const PlayTime::PlayTimeManager& play_time_manager_, - Core::System& system_, - const bool cached = true); + Core::System& system_); ~GameListWorker() override; /// Starts the processing of directory tree information. @@ -95,6 +94,4 @@ private: Common::Event processing_completed; Core::System& system; - - const bool cached; }; diff --git a/src/yuzu/hotkeys.cpp b/src/yuzu/hotkeys.cpp index 1931dcd1f6..e9d0b4e23f 100644 --- a/src/yuzu/hotkeys.cpp +++ b/src/yuzu/hotkeys.cpp @@ -8,7 +8,7 @@ #include "hid_core/frontend/emulated_controller.h" #include "yuzu/hotkeys.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" HotkeyRegistry::HotkeyRegistry() = default; HotkeyRegistry::~HotkeyRegistry() = default; diff --git a/src/yuzu/install_dialog.cpp b/src/yuzu/install_dialog.cpp index 673bbaa836..0e8e785ae9 100644 --- a/src/yuzu/install_dialog.cpp +++ b/src/yuzu/install_dialog.cpp @@ -8,7 +8,7 @@ #include #include #include "yuzu/install_dialog.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" InstallDialog::InstallDialog(QWidget* parent, const QStringList& files) : QDialog(parent) { file_list = new QListWidget(this); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index e23e9a6a48..34423589cc 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -11,6 +11,7 @@ #include "core/loader/nca.h" #include "core/tools/renderdoc.h" #include "frontend_common/firmware_manager.h" +#include "qt_common/qt_common.h" #include @@ -156,7 +157,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "yuzu/compatibility_list.h" #include "yuzu/configuration/configure_dialog.h" #include "yuzu/configuration/configure_input_per_game.h" -#include "yuzu/configuration/qt_config.h" +#include "qt_common/qt_config.h" #include "yuzu/debugger/console.h" #include "yuzu/debugger/controller.h" #include "yuzu/debugger/wait_tree.h" @@ -170,7 +171,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "yuzu/main.h" #include "yuzu/play_time_manager.h" #include "yuzu/startup_checks.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #include "yuzu/util/clickable_label.h" #include "yuzu/vk_device_info.h" @@ -559,7 +560,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) game_list->LoadCompatibilityList(); // force reload on first load to ensure add-ons get updated - game_list->PopulateAsync(UISettings::values.game_dirs, false); + game_list->PopulateAsync(UISettings::values.game_dirs); // make sure menubar has the arrow cursor instead of inheriting from this ui->menubar->setCursor(QCursor()); @@ -4609,9 +4610,11 @@ void GMainWindow::OnToggleStatusBar() { statusBar()->setVisible(ui->action_Show_Status_Bar->isChecked()); } -void GMainWindow::OnGameListRefresh() { - // force reload add-ons etc - game_list->ForceRefreshGameDirectory(); +void GMainWindow::OnGameListRefresh() +{ + // Resets metadata cache and reloads + QtCommon::ResetMetadata(); + game_list->RefreshGameDirectory(); SetFirmwareVersion(); } @@ -4620,7 +4623,7 @@ void GMainWindow::OnAlbum() { auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), - tr("Please install the firmware to use the Album applet.")); + tr("Please install firmware to use the Album applet.")); return; } @@ -4643,7 +4646,7 @@ void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), - tr("Please install the firmware to use the Cabinet applet.")); + tr("Please install firmware to use the Cabinet applet.")); return; } @@ -4667,7 +4670,7 @@ void GMainWindow::OnMiiEdit() { auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), - tr("Please install the firmware to use the Mii editor.")); + tr("Please install firmware to use the Mii editor.")); return; } @@ -4690,7 +4693,7 @@ void GMainWindow::OnOpenControllerMenu() { auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), - tr("Please install the firmware to use the Controller Menu.")); + tr("Please install firmware to use the Controller Menu.")); return; } @@ -4745,6 +4748,8 @@ void GMainWindow::OnHomeMenu() { break; } + // TODO(crueter): So much of this crap is common to qt that I should just move it all tbh + constexpr u64 QLaunchId = static_cast(Service::AM::AppletProgramId::QLaunch); auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); @@ -4767,7 +4772,7 @@ void GMainWindow::OnInitialSetup() { auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), - tr("Please install the firmware to use Starter.")); + tr("Please install firmware to use Starter.")); return; } diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 7857788fcf..b20f601381 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -17,7 +17,7 @@ #include #include "common/common_types.h" -#include "configuration/qt_config.h" +#include "qt_common/qt_config.h" #include "frontend_common/content_manager.h" #include "input_common/drivers/tas_input.h" #include "user_data_migration.h" diff --git a/src/yuzu/multiplayer/direct_connect.cpp b/src/yuzu/multiplayer/direct_connect.cpp index 30f37c2b4a..deac3b9e59 100644 --- a/src/yuzu/multiplayer/direct_connect.cpp +++ b/src/yuzu/multiplayer/direct_connect.cpp @@ -21,7 +21,7 @@ #include "yuzu/multiplayer/message.h" #include "yuzu/multiplayer/state.h" #include "yuzu/multiplayer/validation.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" enum class ConnectionType : u8 { TraversalServer, IP }; diff --git a/src/yuzu/multiplayer/host_room.cpp b/src/yuzu/multiplayer/host_room.cpp index d8e63da600..4dd3958550 100644 --- a/src/yuzu/multiplayer/host_room.cpp +++ b/src/yuzu/multiplayer/host_room.cpp @@ -25,7 +25,7 @@ #include "yuzu/multiplayer/message.h" #include "yuzu/multiplayer/state.h" #include "yuzu/multiplayer/validation.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #ifdef ENABLE_WEB_SERVICE #include "web_service/verify_user_jwt.h" #endif diff --git a/src/yuzu/multiplayer/lobby.cpp b/src/yuzu/multiplayer/lobby.cpp index ed6ba6a15c..84723041df 100644 --- a/src/yuzu/multiplayer/lobby.cpp +++ b/src/yuzu/multiplayer/lobby.cpp @@ -22,7 +22,7 @@ #include "yuzu/multiplayer/message.h" #include "yuzu/multiplayer/state.h" #include "yuzu/multiplayer/validation.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #ifdef ENABLE_WEB_SERVICE #include "web_service/web_backend.h" #endif diff --git a/src/yuzu/multiplayer/state.cpp b/src/yuzu/multiplayer/state.cpp index d5529712b0..2eed3cba63 100644 --- a/src/yuzu/multiplayer/state.cpp +++ b/src/yuzu/multiplayer/state.cpp @@ -19,7 +19,7 @@ #include "yuzu/multiplayer/lobby.h" #include "yuzu/multiplayer/message.h" #include "yuzu/multiplayer/state.h" -#include "yuzu/uisettings.h" +#include "qt_common/uisettings.h" #include "yuzu/util/clickable_label.h" MultiplayerState::MultiplayerState(QWidget* parent, QStandardItemModel* game_list_model_, diff --git a/src/yuzu/play_time_manager.cpp b/src/yuzu/play_time_manager.cpp index 8317386816..d9579706ca 100644 --- a/src/yuzu/play_time_manager.cpp +++ b/src/yuzu/play_time_manager.cpp @@ -1,7 +1,6 @@ // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "common/alignment.h" #include "common/fs/file.h" #include "common/fs/fs.h" #include "common/fs/path_util.h" diff --git a/src/yuzu/play_time_manager.h b/src/yuzu/play_time_manager.h index 1714b91313..ea7d9debc3 100644 --- a/src/yuzu/play_time_manager.h +++ b/src/yuzu/play_time_manager.h @@ -9,8 +9,9 @@ #include "common/common_funcs.h" #include "common/common_types.h" -#include "common/polyfill_thread.h" +#include +// TODO(crueter): Extract this into frontend_common namespace Service::Account { class ProfileManager; } diff --git a/src/yuzu/qt_common.h b/src/yuzu/qt_common.h deleted file mode 100644 index 9c63f08f34..0000000000 --- a/src/yuzu/qt_common.h +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-FileCopyrightText: 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include "core/frontend/emu_window.h" - -namespace QtCommon { - -Core::Frontend::WindowSystemType GetWindowSystemType(); - -Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window); - -} // namespace QtCommon diff --git a/src/yuzu/vk_device_info.cpp b/src/yuzu/vk_device_info.cpp index ab0d39c256..65838f7d42 100644 --- a/src/yuzu/vk_device_info.cpp +++ b/src/yuzu/vk_device_info.cpp @@ -4,7 +4,7 @@ #include #include -#include "yuzu/qt_common.h" +#include "qt_common/qt_common.h" #include "common/dynamic_library.h" #include "common/logging/log.h" From 7a0712af1f537e7f508cb2e065b950c3a931faba Mon Sep 17 00:00:00 2001 From: crueter Date: Tue, 22 Jul 2025 17:05:57 -0400 Subject: [PATCH 02/34] move fw install Signed-off-by: crueter --- src/qt_common/qt_common.cpp | 105 +++++++++++++++-- src/qt_common/qt_common.h | 35 +++++- .../configuration/configure_filesystem.cpp | 2 +- src/yuzu/main.cpp | 110 ++++-------------- 4 files changed, 155 insertions(+), 97 deletions(-) diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index 29379c1d54..260255c62e 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -1,6 +1,7 @@ #include "qt_common.h" #include "common/fs/fs.h" #include "common/fs/path_util.h" +#include "core/hle/service/filesystem/filesystem.h" #include "uisettings.h" #include @@ -21,17 +22,18 @@ MetadataResult ResetMetadata() { if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list/")) { - return Empty; + return MetadataResult::Empty; } else if (Common::FS::RemoveDirRecursively( Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) { - return Success; + return MetadataResult::Success; UISettings::values.is_game_list_reload_pending.exchange(true); } else { - return Failure; + return MetadataResult::Failure; } } -Core::Frontend::WindowSystemType GetWindowSystemType() { +Core::Frontend::WindowSystemType GetWindowSystemType() +{ // Determine WSI type based on Qt platform. QString platform_name = QGuiApplication::platformName(); if (platform_name == QStringLiteral("windows")) @@ -51,7 +53,8 @@ Core::Frontend::WindowSystemType GetWindowSystemType() { return Core::Frontend::WindowSystemType::Windows; } // namespace Core::Frontend::WindowSystemType -Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) { +Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) +{ Core::Frontend::EmuWindow::WindowSystemInfo wsi; wsi.type = GetWindowSystemType(); @@ -59,8 +62,8 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) // Our Win32 Qt external doesn't have the private API. wsi.render_surface = reinterpret_cast(window->winId()); #elif defined(__APPLE__) - wsi.render_surface = reinterpret_cast(objc_msgSend)( - reinterpret_cast(window->winId()), sel_registerName("layer")); + wsi.render_surface = reinterpret_cast( + objc_msgSend)(reinterpret_cast(window->winId()), sel_registerName("layer")); #else QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface(); wsi.display_connection = pni->nativeResourceForWindow("display", window); @@ -74,4 +77,92 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) return wsi; } +FirmwareInstallResult InstallFirmware(const QString& location, + bool recursive, + std::function QtProgressCallback, + Core::System* system, + FileSys::VfsFilesystem* vfs) +{ + LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); + + // Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in + // there.) + std::filesystem::path firmware_source_path = location.toStdString(); + if (!Common::FS::IsDir(firmware_source_path)) { + return FirmwareInstallResult::NoOp; + } + + std::vector out; + const Common::FS::DirEntryCallable callback = + [&out](const std::filesystem::directory_entry& entry) { + if (entry.path().has_extension() && entry.path().extension() == ".nca") { + out.emplace_back(entry.path()); + } + + return true; + }; + + QtProgressCallback(100, 10); + + if (recursive) { + Common::FS::IterateDirEntriesRecursively(firmware_source_path, + callback, + Common::FS::DirEntryFilter::File); + } else { + Common::FS::IterateDirEntries(firmware_source_path, + callback, + Common::FS::DirEntryFilter::File); + } + + if (out.size() <= 0) { + return FirmwareInstallResult::NoNCAs; + } + + // Locate and erase the content of nand/system/Content/registered/*.nca, if any. + auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); + if (!sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { + return FirmwareInstallResult::FailedDelete; + } + + LOG_INFO(Frontend, + "Cleaned nand/system/Content/registered folder in preparation for new firmware."); + + QtProgressCallback(100, 20); + + auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered"); + + bool success = true; + int i = 0; + for (const auto& firmware_src_path : out) { + i++; + auto firmware_src_vfile = vfs->OpenFile(firmware_src_path.generic_string(), + FileSys::OpenMode::Read); + auto firmware_dst_vfile = firmware_vdir + ->CreateFileRelative(firmware_src_path.filename().string()); + + if (!VfsRawCopy(firmware_src_vfile, firmware_dst_vfile)) { + LOG_ERROR(Frontend, + "Failed to copy firmware file {} to {} in registered folder!", + firmware_src_path.generic_string(), + firmware_src_path.filename().string()); + success = false; + } + + if (QtProgressCallback(100, + 20 + + static_cast(((i) / static_cast(out.size())) + * 70.0))) { + return FirmwareInstallResult::FailedCorrupted; + } + } + + if (!success) { + return FirmwareInstallResult::FailedCopy; + } + + // Re-scan VFS for the newly placed firmware files. + system->GetFileSystemController().CreateFactories(*vfs); + return FirmwareInstallResult::Success; +} + } diff --git a/src/qt_common/qt_common.h b/src/qt_common/qt_common.h index 3c7dddfc1f..31adcf05c7 100644 --- a/src/qt_common/qt_common.h +++ b/src/qt_common/qt_common.h @@ -7,8 +7,11 @@ #include #include +#include "core/core.h" #include +#include + namespace QtCommon { static constexpr std::array METADATA_RESULTS = { @@ -17,7 +20,7 @@ static constexpr std::array METADATA_RESULTS = { "The metadata cache is already empty.", }; -enum MetadataResult { +enum class MetadataResult { Success, Failure, Empty, @@ -38,6 +41,36 @@ inline constexpr const char *GetResetMetadataResultString(MetadataResult result) return METADATA_RESULTS.at(static_cast(result)); } +static constexpr std::array FIRMWARE_RESULTS = { + "", + "", + "Unable to locate potential firmware NCA files", + "Failed to delete one or more firmware files.", + "One or more firmware files failed to copy into NAND.", + "Firmware installation cancelled, firmware may be in a bad state or corrupted." + "Restart Eden or re-install firmware." +}; + +enum class FirmwareInstallResult { + Success, + NoOp, + NoNCAs, + FailedDelete, + FailedCopy, + FailedCorrupted, +}; + +FirmwareInstallResult InstallFirmware(const QString &location, + bool recursive, + std::function QtProgressCallback, + Core::System *system, + FileSys::VfsFilesystem *vfs); + +inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResult result) +{ + return FIRMWARE_RESULTS.at(static_cast(result)); +} + Core::Frontend::WindowSystemType GetWindowSystemType(); Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window); diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp index 392155d2a3..5459dc0377 100644 --- a/src/yuzu/configuration/configure_filesystem.cpp +++ b/src/yuzu/configuration/configure_filesystem.cpp @@ -132,7 +132,7 @@ void ConfigureFilesystem::ResetMetadata() { const QString title = tr("Reset Metadata Cache"); switch (result) { - case QtCommon::Failure: + case QtCommon::MetadataResult::Failure: QMessageBox::warning(this, title, resultMessage); break; default: diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 34423589cc..b0aaa953a9 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -4356,106 +4356,40 @@ void GMainWindow::InstallFirmware(const QString& location, bool recursive) { return progress.wasCanceled(); }; - LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); + auto result = QtCommon::InstallFirmware(location, recursive, QtProgressCallback, system.get(), vfs.get()); + const char* resultMessage = QtCommon::GetFirmwareInstallResultString(result); - // Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in - // there.) - std::filesystem::path firmware_source_path = location.toStdString(); - if (!Common::FS::IsDir(firmware_source_path)) { - progress.close(); + progress.close(); + + QMessageBox *box = new QMessageBox(QMessageBox::Icon::NoIcon, tr("Firmware Install Failed"), tr(resultMessage), QMessageBox::Ok, this); + + switch (result) { + case QtCommon::FirmwareInstallResult::NoNCAs: + case QtCommon::FirmwareInstallResult::FailedCorrupted: + box->setIcon(QMessageBox::Icon::Warning); + box->exec(); return; - } - - std::vector out; - const Common::FS::DirEntryCallable callback = - [&out](const std::filesystem::directory_entry& entry) { - if (entry.path().has_extension() && entry.path().extension() == ".nca") { - out.emplace_back(entry.path()); - } - - return true; - }; - - QtProgressCallback(100, 10); - - if (recursive) { - Common::FS::IterateDirEntriesRecursively(firmware_source_path, callback, - Common::FS::DirEntryFilter::File); - } else { - Common::FS::IterateDirEntries(firmware_source_path, callback, - Common::FS::DirEntryFilter::File); - } - - if (out.size() <= 0) { - progress.close(); - QMessageBox::warning(this, tr("Firmware install failed"), - tr("Unable to locate potential firmware NCA files")); + case QtCommon::FirmwareInstallResult::FailedCopy: + case QtCommon::FirmwareInstallResult::FailedDelete: + box->setIcon(QMessageBox::Icon::Critical); + box->exec(); return; + default: + box->deleteLater(); + break; } - // Locate and erase the content of nand/system/Content/registered/*.nca, if any. - auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); - if (!sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { - progress.close(); - QMessageBox::critical(this, tr("Firmware install failed"), - tr("Failed to delete one or more firmware file.")); - return; - } - - LOG_INFO(Frontend, - "Cleaned nand/system/Content/registered folder in preparation for new firmware."); - - QtProgressCallback(100, 20); - - auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered"); - - bool success = true; - int i = 0; - for (const auto& firmware_src_path : out) { - i++; - auto firmware_src_vfile = - vfs->OpenFile(firmware_src_path.generic_string(), FileSys::OpenMode::Read); - auto firmware_dst_vfile = - firmware_vdir->CreateFileRelative(firmware_src_path.filename().string()); - - if (!VfsRawCopy(firmware_src_vfile, firmware_dst_vfile)) { - LOG_ERROR(Frontend, "Failed to copy firmware file {} to {} in registered folder!", - firmware_src_path.generic_string(), firmware_src_path.filename().string()); - success = false; - } - - if (QtProgressCallback( - 100, 20 + static_cast(((i) / static_cast(out.size())) * 70.0))) { - progress.close(); - QMessageBox::warning( - this, tr("Firmware install failed"), - tr("Firmware installation cancelled, firmware may be in a bad state or corrupted. " - "Restart Eden or re-install firmware.")); - return; - } - } - - if (!success) { - progress.close(); - QMessageBox::critical(this, tr("Firmware install failed"), - tr("One or more firmware files failed to copy into NAND.")); - return; - } - - // Re-scan VFS for the newly placed firmware files. - system->GetFileSystemController().CreateFactories(*vfs); - auto VerifyFirmwareCallback = [&](size_t total_size, size_t processed_size) { progress.setValue(90 + static_cast((processed_size * 10) / total_size)); return progress.wasCanceled(); }; - auto result = - ContentManager::VerifyInstalledContents(*system, *provider, VerifyFirmwareCallback, true); + auto results = + ContentManager::VerifyInstalledContents(*system, *provider, VerifyFirmwareCallback, true); - if (result.size() > 0) { + if (results.size() > 0) { const auto failed_names = - QString::fromStdString(fmt::format("{}", fmt::join(result, "\n"))); + QString::fromStdString(fmt::format("{}", fmt::join(results, "\n"))); progress.close(); QMessageBox::critical( this, tr("Firmware integrity verification failed!"), From 35082084731f802326100129e810954131001428 Mon Sep 17 00:00:00 2001 From: crueter Date: Tue, 22 Jul 2025 17:12:24 -0400 Subject: [PATCH 03/34] Fix license headers Signed-off-by: crueter --- .ci/license-header.sh | 12 +++++++++--- src/qt_common/qt_common.cpp | 3 +++ src/qt_common/qt_config.cpp | 3 +++ src/qt_common/qt_config.h | 3 +++ src/yuzu/configuration/configure_audio.cpp | 3 +++ src/yuzu/configuration/configure_cpu.h | 3 +++ src/yuzu/configuration/configure_dialog.cpp | 3 +++ src/yuzu/configuration/configure_dialog.h | 3 +++ src/yuzu/configuration/configure_filesystem.cpp | 3 +++ src/yuzu/configuration/configure_general.cpp | 3 +++ src/yuzu/configuration/configure_graphics.cpp | 3 +++ src/yuzu/configuration/configure_graphics.h | 3 +++ .../configuration/configure_graphics_advanced.cpp | 3 +++ .../configuration/configure_graphics_extensions.cpp | 3 +++ src/yuzu/configuration/configure_hotkeys.cpp | 3 +++ src/yuzu/configuration/configure_input_per_game.h | 3 +++ src/yuzu/configuration/configure_per_game.cpp | 3 +++ src/yuzu/configuration/configure_per_game.h | 3 +++ src/yuzu/configuration/configure_per_game_addons.cpp | 3 +++ src/yuzu/configuration/configure_ringcon.cpp | 3 +++ src/yuzu/configuration/configure_tas.cpp | 3 +++ src/yuzu/configuration/input_profiles.h | 3 +++ src/yuzu/configuration/shared_widget.cpp | 3 +++ src/yuzu/configuration/shared_widget.h | 3 +++ src/yuzu/debugger/console.cpp | 3 +++ src/yuzu/debugger/wait_tree.cpp | 3 +++ src/yuzu/game_list_p.h | 3 +++ src/yuzu/game_list_worker.cpp | 3 +++ src/yuzu/game_list_worker.h | 3 +++ src/yuzu/hotkeys.cpp | 3 +++ src/yuzu/install_dialog.cpp | 3 +++ src/yuzu/multiplayer/state.cpp | 3 +++ src/yuzu/play_time_manager.cpp | 3 +++ src/yuzu/play_time_manager.h | 3 +++ src/yuzu/vk_device_info.cpp | 3 +++ 35 files changed, 111 insertions(+), 3 deletions(-) diff --git a/.ci/license-header.sh b/.ci/license-header.sh index fecffaa7d3..f1e16abbe6 100755 --- a/.ci/license-header.sh +++ b/.ci/license-header.sh @@ -5,13 +5,19 @@ HEADER_HASH="$(cat "$PWD/.ci/license/header-hash.txt")" echo "Getting branch changes" -BRANCH=`git rev-parse --abbrev-ref HEAD` -COMMITS=`git log ${BRANCH} --not master --pretty=format:"%h"` -RANGE="${COMMITS[${#COMMITS[@]}-1]}^..${COMMITS[0]}" +# BRANCH=`git rev-parse --abbrev-ref HEAD` +# COMMITS=`git log ${BRANCH} --not master --pretty=format:"%h"` +# RANGE="${COMMITS[${#COMMITS[@]}-1]}^..${COMMITS[0]}" +# FILES=`git diff-tree --no-commit-id --name-only ${RANGE} -r` + +CURRENT=`git rev-parse --short=10 HEAD` +BASE=`git merge-base master $CURRENT` +RANGE="$CURRENT^..$BASE" FILES=`git diff-tree --no-commit-id --name-only ${RANGE} -r` #FILES=$(git diff --name-only master) +echo $FILES echo "Done" check_header() { diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index 260255c62e..4a27566107 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #include "qt_common.h" #include "common/fs/fs.h" #include "common/fs/path_util.h" diff --git a/src/qt_common/qt_config.cpp b/src/qt_common/qt_config.cpp index ae5b330e23..f787873cf6 100644 --- a/src/qt_common/qt_config.cpp +++ b/src/qt_common/qt_config.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/qt_common/qt_config.h b/src/qt_common/qt_config.h index dc2dceb4d7..a8c80dd273 100644 --- a/src/qt_common/qt_config.h +++ b/src/qt_common/qt_config.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp index 8d11920d31..a7ebae91f8 100644 --- a/src/yuzu/configuration/configure_audio.cpp +++ b/src/yuzu/configuration/configure_audio.cpp @@ -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 diff --git a/src/yuzu/configuration/configure_cpu.h b/src/yuzu/configuration/configure_cpu.h index 16cf74af33..bbc6096f9b 100644 --- a/src/yuzu/configuration/configure_cpu.h +++ b/src/yuzu/configuration/configure_cpu.h @@ -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 diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 4e128106e7..0816782282 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2016 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h index bf96035752..c1e148fc8e 100644 --- a/src/yuzu/configuration/configure_dialog.h +++ b/src/yuzu/configuration/configure_dialog.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2016 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp index 5459dc0377..d02e6dec2b 100644 --- a/src/yuzu/configuration/configure_filesystem.cpp +++ b/src/yuzu/configuration/configure_filesystem.cpp @@ -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 diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 352ae8ab85..18c2c9cb77 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2016 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index e1e68b917a..cd806e5ef8 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2016 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h index 9f7ece5714..38d97aae80 100644 --- a/src/yuzu/configuration/configure_graphics.h +++ b/src/yuzu/configuration/configure_graphics.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2016 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp index 921cb83b08..e07ad8c466 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.cpp +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp @@ -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 diff --git a/src/yuzu/configuration/configure_graphics_extensions.cpp b/src/yuzu/configuration/configure_graphics_extensions.cpp index c4c7fbb31f..f165e703d9 100644 --- a/src/yuzu/configuration/configure_graphics_extensions.cpp +++ b/src/yuzu/configuration/configure_graphics_extensions.cpp @@ -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 diff --git a/src/yuzu/configuration/configure_hotkeys.cpp b/src/yuzu/configuration/configure_hotkeys.cpp index 53f7401ef4..a5c1ee009a 100644 --- a/src/yuzu/configuration/configure_hotkeys.cpp +++ b/src/yuzu/configuration/configure_hotkeys.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2017 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/configuration/configure_input_per_game.h b/src/yuzu/configuration/configure_input_per_game.h index 1323d101d3..dcd6dd841b 100644 --- a/src/yuzu/configuration/configure_input_per_game.h +++ b/src/yuzu/configuration/configure_input_per_game.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp index 545c37a2c9..b51ede0de8 100644 --- a/src/yuzu/configuration/configure_per_game.cpp +++ b/src/yuzu/configuration/configure_per_game.cpp @@ -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 diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h index a756b561a8..83afc27f3d 100644 --- a/src/yuzu/configuration/configure_per_game.h +++ b/src/yuzu/configuration/configure_per_game.h @@ -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 diff --git a/src/yuzu/configuration/configure_per_game_addons.cpp b/src/yuzu/configuration/configure_per_game_addons.cpp index 90c94cb923..ed4cbc1147 100644 --- a/src/yuzu/configuration/configure_per_game_addons.cpp +++ b/src/yuzu/configuration/configure_per_game_addons.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2016 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/configuration/configure_ringcon.cpp b/src/yuzu/configuration/configure_ringcon.cpp index 7e7877aaf6..795ad1a85e 100644 --- a/src/yuzu/configuration/configure_ringcon.cpp +++ b/src/yuzu/configuration/configure_ringcon.cpp @@ -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 diff --git a/src/yuzu/configuration/configure_tas.cpp b/src/yuzu/configuration/configure_tas.cpp index 290e825fe6..898a1a3e59 100644 --- a/src/yuzu/configuration/configure_tas.cpp +++ b/src/yuzu/configuration/configure_tas.cpp @@ -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 diff --git a/src/yuzu/configuration/input_profiles.h b/src/yuzu/configuration/input_profiles.h index 64dcf0e603..dba5ce1318 100644 --- a/src/yuzu/configuration/input_profiles.h +++ b/src/yuzu/configuration/input_profiles.h @@ -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 diff --git a/src/yuzu/configuration/shared_widget.cpp b/src/yuzu/configuration/shared_widget.cpp index 02b354b0a5..e30ecc4848 100644 --- a/src/yuzu/configuration/shared_widget.cpp +++ b/src/yuzu/configuration/shared_widget.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/configuration/shared_widget.h b/src/yuzu/configuration/shared_widget.h index a793347ce5..9e718098a3 100644 --- a/src/yuzu/configuration/shared_widget.h +++ b/src/yuzu/configuration/shared_widget.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/debugger/console.cpp b/src/yuzu/debugger/console.cpp index 40b2fddbc9..8fb22db192 100644 --- a/src/yuzu/debugger/console.cpp +++ b/src/yuzu/debugger/console.cpp @@ -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 diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index f32f6348a5..feb814b25e 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2016 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index b3e05b8b34..5a3b5829f5 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h @@ -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 diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp index 267faa7182..538c7ab822 100644 --- a/src/yuzu/game_list_worker.cpp +++ b/src/yuzu/game_list_worker.cpp @@ -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 diff --git a/src/yuzu/game_list_worker.h b/src/yuzu/game_list_worker.h index 5c5fbb251f..f5d5f6341b 100644 --- a/src/yuzu/game_list_worker.h +++ b/src/yuzu/game_list_worker.h @@ -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 diff --git a/src/yuzu/hotkeys.cpp b/src/yuzu/hotkeys.cpp index e9d0b4e23f..31932e6f43 100644 --- a/src/yuzu/hotkeys.cpp +++ b/src/yuzu/hotkeys.cpp @@ -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 diff --git a/src/yuzu/install_dialog.cpp b/src/yuzu/install_dialog.cpp index 0e8e785ae9..e6f1392ce0 100644 --- a/src/yuzu/install_dialog.cpp +++ b/src/yuzu/install_dialog.cpp @@ -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 diff --git a/src/yuzu/multiplayer/state.cpp b/src/yuzu/multiplayer/state.cpp index 2eed3cba63..8ff1d991ec 100644 --- a/src/yuzu/multiplayer/state.cpp +++ b/src/yuzu/multiplayer/state.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2018 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/play_time_manager.cpp b/src/yuzu/play_time_manager.cpp index d9579706ca..6d06bc7614 100644 --- a/src/yuzu/play_time_manager.cpp +++ b/src/yuzu/play_time_manager.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/play_time_manager.h b/src/yuzu/play_time_manager.h index ea7d9debc3..cd81bdb061 100644 --- a/src/yuzu/play_time_manager.h +++ b/src/yuzu/play_time_manager.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/vk_device_info.cpp b/src/yuzu/vk_device_info.cpp index 65838f7d42..d961d550a1 100644 --- a/src/yuzu/vk_device_info.cpp +++ b/src/yuzu/vk_device_info.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later From cb5719ec0e0f3f348428de35c408b75d6afb3ae0 Mon Sep 17 00:00:00 2001 From: crueter Date: Tue, 22 Jul 2025 17:56:58 -0400 Subject: [PATCH 04/34] debug: log user/save id Signed-off-by: crueter --- src/core/file_sys/savedata_factory.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index 106922e04f..0591517727 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp @@ -126,6 +126,10 @@ std::string SaveDataFactory::GetFullPath(ProgramId program_id, VirtualDir dir, std::string out = GetSaveDataSpaceIdPath(space); + LOG_INFO(Common_Filesystem, "Save ID: {:016X}", save_id); + LOG_INFO(Common_Filesystem, "User ID[1]: {:016X}", user_id[1]); + LOG_INFO(Common_Filesystem, "User ID[0]: {:016X}", user_id[0]); + switch (type) { case SaveDataType::System: return fmt::format("{}save/{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]); From ae62ee3d27e39dd7a28cecfb8578c291fa7cf6b7 Mon Sep 17 00:00:00 2001 From: crueter Date: Tue, 22 Jul 2025 18:17:20 -0400 Subject: [PATCH 05/34] explicitly check write status for dir Signed-off-by: crueter --- src/qt_common/qt_common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index 4a27566107..abeae4c3a1 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -123,7 +123,7 @@ FirmwareInstallResult InstallFirmware(const QString& location, // Locate and erase the content of nand/system/Content/registered/*.nca, if any. auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); - if (!sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { + if (sysnand_content_vdir->IsWritable() && !sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { return FirmwareInstallResult::FailedDelete; } From 195bd7005e3afe85199619b6a5fa59cc709b5355 Mon Sep 17 00:00:00 2001 From: crueter Date: Tue, 22 Jul 2025 23:23:14 -0400 Subject: [PATCH 06/34] more common funcs Signed-off-by: crueter --- .ci/license-header.sh | 6 +- src/core/file_sys/savedata_factory.cpp | 3 + src/qt_common/CMakeLists.txt | 4 +- src/qt_common/qt_common.cpp | 43 ++++- src/qt_common/qt_common.h | 4 +- src/qt_common/qt_game_util.cpp | 171 +++++++++++++++++ src/qt_common/qt_game_util.h | 41 +++++ src/qt_common/qt_path_util.cpp | 20 ++ src/qt_common/qt_path_util.h | 7 + src/yuzu/main.cpp | 243 +++++-------------------- src/yuzu/main.h | 9 - 11 files changed, 331 insertions(+), 220 deletions(-) create mode 100644 src/qt_common/qt_game_util.cpp create mode 100644 src/qt_common/qt_game_util.h create mode 100644 src/qt_common/qt_path_util.cpp create mode 100644 src/qt_common/qt_path_util.h diff --git a/.ci/license-header.sh b/.ci/license-header.sh index f1e16abbe6..d98f42fc97 100755 --- a/.ci/license-header.sh +++ b/.ci/license-header.sh @@ -10,10 +10,8 @@ echo "Getting branch changes" # RANGE="${COMMITS[${#COMMITS[@]}-1]}^..${COMMITS[0]}" # FILES=`git diff-tree --no-commit-id --name-only ${RANGE} -r` -CURRENT=`git rev-parse --short=10 HEAD` -BASE=`git merge-base master $CURRENT` -RANGE="$CURRENT^..$BASE" -FILES=`git diff-tree --no-commit-id --name-only ${RANGE} -r` +BASE=`git merge-base master HEAD` +FILES=`git diff --name-only $BASE` #FILES=$(git diff --name-only master) diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index 0591517727..edf51e74de 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp @@ -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 diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index be1a8ebbd0..d6ef427ba6 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -13,10 +13,12 @@ add_library(qt_common STATIC shared_translation.cpp shared_translation.h + qt_path_util.h qt_path_util.cpp + qt_game_util.h qt_game_util.cpp ) create_target_directory_groups(qt_common) -target_link_libraries(qt_common PUBLIC core Qt6::Core Qt6::Gui SimpleIni::SimpleIni) +target_link_libraries(qt_common PUBLIC core Qt6::Core Qt6::Gui SimpleIni::SimpleIni QuaZip::QuaZip) if (NOT WIN32) target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index abeae4c3a1..0cd4c86b4a 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -15,6 +15,11 @@ #if !defined(WIN32) && !defined(__APPLE__) #include + +#include + +#include + #elif defined(__APPLE__) #include #endif @@ -80,11 +85,12 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) return wsi; } -FirmwareInstallResult InstallFirmware(const QString& location, - bool recursive, - std::function QtProgressCallback, - Core::System* system, - FileSys::VfsFilesystem* vfs) +FirmwareInstallResult InstallFirmware( + const QString& location, + bool recursive, + std::function QtProgressCallback, + Core::System* system, + FileSys::VfsFilesystem* vfs) { LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); @@ -123,7 +129,8 @@ FirmwareInstallResult InstallFirmware(const QString& location, // Locate and erase the content of nand/system/Content/registered/*.nca, if any. auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); - if (sysnand_content_vdir->IsWritable() && !sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { + if (sysnand_content_vdir->IsWritable() + && !sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { return FirmwareInstallResult::FailedDelete; } @@ -168,4 +175,28 @@ FirmwareInstallResult InstallFirmware(const QString& location, return FirmwareInstallResult::Success; } +QString UnzipFirmwareToTmp(const QString& location) +{ + namespace fs = std::filesystem; + fs::path tmp{fs::temp_directory_path()}; + + if (!fs::create_directories(tmp / "eden" / "firmware")) { + return ""; + } + + tmp /= "eden"; + tmp /= "firmware"; + + QString qCacheDir = QString::fromStdString(tmp.string()); + + QFile zip(location); + + QStringList result = JlCompress::extractDir(&zip, qCacheDir); + if (result.isEmpty()) { + return ""; + } + + return qCacheDir; } + +} // namespace QtCommon diff --git a/src/qt_common/qt_common.h b/src/qt_common/qt_common.h index 31adcf05c7..b3ca99e65a 100644 --- a/src/qt_common/qt_common.h +++ b/src/qt_common/qt_common.h @@ -62,10 +62,12 @@ enum class FirmwareInstallResult { FirmwareInstallResult InstallFirmware(const QString &location, bool recursive, - std::function QtProgressCallback, + std::function QtProgressCallback, Core::System *system, FileSys::VfsFilesystem *vfs); +QString UnzipFirmwareToTmp(const QString &location); + inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResult result) { return FIRMWARE_RESULTS.at(static_cast(result)); diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp new file mode 100644 index 0000000000..9aba4e393c --- /dev/null +++ b/src/qt_common/qt_game_util.cpp @@ -0,0 +1,171 @@ +#include "qt_game_util.h" +#include "common/fs/fs.h" +#include "common/fs/path_util.h" + +#include +#include +#include "fmt/ostream.h" +#include + +#ifdef _WIN32 +#include +#endif + +namespace QtCommon { + +bool CreateShortcutLink(const std::filesystem::path& shortcut_path, + const std::string& comment, + const std::filesystem::path& icon_path, + const std::filesystem::path& command, + const std::string& arguments, const std::string& categories, + const std::string& keywords, const std::string& name) try { +#ifdef _WIN32 // Windows + HRESULT hr = CoInitialize(nullptr); + if (FAILED(hr)) { + LOG_ERROR(Frontend, "CoInitialize failed"); + return false; + } + SCOPE_EXIT { + CoUninitialize(); + }; + IShellLinkW* ps1 = nullptr; + IPersistFile* persist_file = nullptr; + SCOPE_EXIT { + if (persist_file != nullptr) { + persist_file->Release(); + } + if (ps1 != nullptr) { + ps1->Release(); + } + }; + HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW, + reinterpret_cast(&ps1)); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to create IShellLinkW instance"); + return false; + } + hres = ps1->SetPath(command.c_str()); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to set path"); + return false; + } + if (!arguments.empty()) { + hres = ps1->SetArguments(Common::UTF8ToUTF16W(arguments).data()); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to set arguments"); + return false; + } + } + if (!comment.empty()) { + hres = ps1->SetDescription(Common::UTF8ToUTF16W(comment).data()); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to set description"); + return false; + } + } + if (std::filesystem::is_regular_file(icon_path)) { + hres = ps1->SetIconLocation(icon_path.c_str(), 0); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to set icon location"); + return false; + } + } + hres = ps1->QueryInterface(IID_IPersistFile, reinterpret_cast(&persist_file)); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to get IPersistFile interface"); + return false; + } + hres = persist_file->Save(std::filesystem::path{shortcut_path / (name + ".lnk")}.c_str(), TRUE); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to save shortcut"); + return false; + } + return true; +#elif defined(__unix__) && !defined(__APPLE__) && !defined(__ANDROID__) // Any desktop NIX + std::filesystem::path shortcut_path_full = shortcut_path / (name + ".desktop"); + std::ofstream shortcut_stream(shortcut_path_full, std::ios::binary | std::ios::trunc); + if (!shortcut_stream.is_open()) { + LOG_ERROR(Frontend, "Failed to create shortcut"); + return false; + } + // TODO: Migrate fmt::print to std::print in futures STD C++ 23. + fmt::print(shortcut_stream, "[Desktop Entry]\n"); + fmt::print(shortcut_stream, "Type=Application\n"); + fmt::print(shortcut_stream, "Version=1.0\n"); + fmt::print(shortcut_stream, "Name={}\n", name); + if (!comment.empty()) { + fmt::print(shortcut_stream, "Comment={}\n", comment); + } + if (std::filesystem::is_regular_file(icon_path)) { + fmt::print(shortcut_stream, "Icon={}\n", icon_path.string()); + } + fmt::print(shortcut_stream, "TryExec={}\n", command.string()); + fmt::print(shortcut_stream, "Exec={} {}\n", command.string(), arguments); + if (!categories.empty()) { + fmt::print(shortcut_stream, "Categories={}\n", categories); + } + if (!keywords.empty()) { + fmt::print(shortcut_stream, "Keywords={}\n", keywords); + } + return true; +#else // Unsupported platform + return false; +#endif +} + catch (const std::exception& e) { + LOG_ERROR(Frontend, "Failed to create shortcut: {}", e.what()); + return false; +} + +bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, + std::filesystem::path& out_icon_path) { + // Get path to Yuzu icons directory & icon extension + std::string ico_extension = "png"; +#if defined(_WIN32) + out_icon_path = Common::FS::GetEdenPath(Common::FS::EdenPath::IconsDir); + ico_extension = "ico"; +#elif defined(__linux__) || defined(__FreeBSD__) + out_icon_path = Common::FS::GetDataDirectory("XDG_DATA_HOME") / "icons/hicolor/256x256"; +#endif + // Create icons directory if it doesn't exist + if (!Common::FS::CreateDirs(out_icon_path)) { + out_icon_path.clear(); + return false; + } + + // Create icon file path + out_icon_path /= (program_id == 0 ? fmt::format("eden-{}.{}", game_file_name, ico_extension) + : fmt::format("eden-{:016X}.{}", program_id, ico_extension)); + return true; +} + +void OpenRootDataFolder() { + QDesktopServices::openUrl(QUrl( + QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::EdenDir)))); +} + +void OpenNANDFolder() +{ + QDesktopServices::openUrl(QUrl::fromLocalFile( + QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::NANDDir)))); +} + +void OpenSDMCFolder() +{ + QDesktopServices::openUrl(QUrl::fromLocalFile( + QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir)))); +} + +void OpenModFolder() +{ + QDesktopServices::openUrl(QUrl::fromLocalFile( + QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::LoadDir)))); +} + +void OpenLogFolder() +{ + QDesktopServices::openUrl(QUrl::fromLocalFile( + QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::LogDir)))); +} + +} diff --git a/src/qt_common/qt_game_util.h b/src/qt_common/qt_game_util.h new file mode 100644 index 0000000000..98d17027c4 --- /dev/null +++ b/src/qt_common/qt_game_util.h @@ -0,0 +1,41 @@ +#ifndef QT_GAME_UTIL_H +#define QT_GAME_UTIL_H + +#include "frontend_common/content_manager.h" +#include + +namespace QtCommon { + +static constexpr std::array GAME_VERIFICATION_RESULTS = { + "The operation completed successfully.", + "File contents may be corrupt or missing..", + "Firmware installation cancelled, firmware may be in a bad state or corrupted." + "File contents could not be checked for validity." +}; + +inline constexpr const char *GetGameVerificationResultString(ContentManager::GameVerificationResult result) +{ + return GAME_VERIFICATION_RESULTS.at(static_cast(result)); +} + +bool CreateShortcutLink(const std::filesystem::path& shortcut_path, + const std::string& comment, + const std::filesystem::path& icon_path, + const std::filesystem::path& command, + const std::string& arguments, + const std::string& categories, + const std::string& keywords, + const std::string& name); + +bool MakeShortcutIcoPath(const u64 program_id, + const std::string_view game_file_name, + std::filesystem::path& out_icon_path); + +void OpenRootDataFolder(); +void OpenNANDFolder(); +void OpenSDMCFolder(); +void OpenModFolder(); +void OpenLogFolder(); +} + +#endif // QT_GAME_UTIL_H diff --git a/src/qt_common/qt_path_util.cpp b/src/qt_common/qt_path_util.cpp new file mode 100644 index 0000000000..2ca2f6bf72 --- /dev/null +++ b/src/qt_common/qt_path_util.cpp @@ -0,0 +1,20 @@ +#include "qt_path_util.h" +#include +#include +#include +#include "common/fs/fs.h" +#include "common/fs/path_util.h" +#include + +bool QtCommon::PathUtil::OpenShaderCache(u64 program_id) +{ + const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); + const auto shader_cache_folder_path{shader_cache_dir / fmt::format("{:016x}", program_id)}; + if (!Common::FS::CreateDirs(shader_cache_folder_path)) { + return false; + } + + const auto shader_path_string{Common::FS::PathToUTF8String(shader_cache_folder_path)}; + const auto qt_shader_cache_path = QString::fromStdString(shader_path_string); + return QDesktopServices::openUrl(QUrl::fromLocalFile(qt_shader_cache_path)); +} diff --git a/src/qt_common/qt_path_util.h b/src/qt_common/qt_path_util.h new file mode 100644 index 0000000000..6fafad7ed9 --- /dev/null +++ b/src/qt_common/qt_path_util.h @@ -0,0 +1,7 @@ +#ifndef QT_PATH_UTIL_H +#define QT_PATH_UTIL_H + +#include "common/common_types.h" +namespace QtCommon::PathUtil { bool OpenShaderCache(u64 program_id); } + +#endif // QT_PATH_UTIL_H diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index b0aaa953a9..88f3a3d743 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -12,6 +12,8 @@ #include "core/tools/renderdoc.h" #include "frontend_common/firmware_manager.h" #include "qt_common/qt_common.h" +#include "qt_common/qt_game_util.h" +#include "qt_common/qt_path_util.h" #include @@ -1166,7 +1168,7 @@ void GMainWindow::InitializeWidgets() { loading_screen = new LoadingScreen(this); loading_screen->hide(); ui->horizontalLayout->addWidget(loading_screen); - connect(loading_screen, &LoadingScreen::Hidden, [&] { + connect(loading_screen, &LoadingScreen::Hidden, this, [&] { loading_screen->Clear(); if (emulation_running) { render_window->show(); @@ -2613,16 +2615,9 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target } void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) { - const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); - const auto shader_cache_folder_path{shader_cache_dir / fmt::format("{:016x}", program_id)}; - if (!Common::FS::CreateDirs(shader_cache_folder_path)) { - QMessageBox::warning(this, tr("Error Opening Transferable Shader Cache"), - tr("Failed to create the shader cache directory for this title.")); - return; + if (!QtCommon::PathUtil::OpenShaderCache(program_id)) { + QMessageBox::warning(this, tr("Error Opening Shader Cache"), tr("Failed to create or open shader cache for this title, ensure your app data directory has write permissions.")); } - const auto shader_path_string{Common::FS::PathToUTF8String(shader_cache_folder_path)}; - const auto qt_shader_cache_path = QString::fromStdString(shader_path_string); - QDesktopServices::openUrl(QUrl::fromLocalFile(qt_shader_cache_path)); } static bool RomFSRawCopy(size_t total_size, size_t& read_size, QProgressDialog& dialog, @@ -2687,6 +2682,7 @@ static bool RomFSRawCopy(size_t total_size, size_t& read_size, QProgressDialog& return true; } +// TODO(crueter): All this can be transfered to qt_common QString GMainWindow::GetGameListErrorRemoving(InstalledEntryType type) const { switch (type) { case InstalledEntryType::Game: @@ -3043,12 +3039,8 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa } } +// END void GMainWindow::OnGameListVerifyIntegrity(const std::string& game_path) { - const auto NotImplemented = [this] { - QMessageBox::warning(this, tr("Integrity verification couldn't be performed!"), - tr("File contents were not checked for validity.")); - }; - QProgressDialog progress(tr("Verifying integrity..."), tr("Cancel"), 0, 100, this); progress.setWindowModality(Qt::WindowModal); progress.setMinimumDuration(100); @@ -3061,18 +3053,20 @@ void GMainWindow::OnGameListVerifyIntegrity(const std::string& game_path) { }; const auto result = ContentManager::VerifyGameContents(*system, game_path, QtProgressCallback); + const QString resultString = tr(QtCommon::GetGameVerificationResultString(result)); progress.close(); switch (result) { case ContentManager::GameVerificationResult::Success: QMessageBox::information(this, tr("Integrity verification succeeded!"), - tr("The operation completed successfully.")); + resultString); break; case ContentManager::GameVerificationResult::Failed: QMessageBox::critical(this, tr("Integrity verification failed!"), - tr("File contents may be corrupt.")); + resultString); break; case ContentManager::GameVerificationResult::NotImplemented: - NotImplemented(); + QMessageBox::warning(this, tr("Integrity verification couldn't be performed"), + resultString); } } @@ -3094,109 +3088,8 @@ void GMainWindow::OnGameListNavigateToGamedbEntry(u64 program_id, QUrl(QStringLiteral("https://eden-emulator.github.io/game/") + directory)); } -bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path, - const std::string& comment, - const std::filesystem::path& icon_path, - const std::filesystem::path& command, - const std::string& arguments, const std::string& categories, - const std::string& keywords, const std::string& name) try { -#ifdef _WIN32 // Windows - HRESULT hr = CoInitialize(nullptr); - if (FAILED(hr)) { - LOG_ERROR(Frontend, "CoInitialize failed"); - return false; - } - SCOPE_EXIT { - CoUninitialize(); - }; - IShellLinkW* ps1 = nullptr; - IPersistFile* persist_file = nullptr; - SCOPE_EXIT { - if (persist_file != nullptr) { - persist_file->Release(); - } - if (ps1 != nullptr) { - ps1->Release(); - } - }; - HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW, - reinterpret_cast(&ps1)); - if (FAILED(hres)) { - LOG_ERROR(Frontend, "Failed to create IShellLinkW instance"); - return false; - } - hres = ps1->SetPath(command.c_str()); - if (FAILED(hres)) { - LOG_ERROR(Frontend, "Failed to set path"); - return false; - } - if (!arguments.empty()) { - hres = ps1->SetArguments(Common::UTF8ToUTF16W(arguments).data()); - if (FAILED(hres)) { - LOG_ERROR(Frontend, "Failed to set arguments"); - return false; - } - } - if (!comment.empty()) { - hres = ps1->SetDescription(Common::UTF8ToUTF16W(comment).data()); - if (FAILED(hres)) { - LOG_ERROR(Frontend, "Failed to set description"); - return false; - } - } - if (std::filesystem::is_regular_file(icon_path)) { - hres = ps1->SetIconLocation(icon_path.c_str(), 0); - if (FAILED(hres)) { - LOG_ERROR(Frontend, "Failed to set icon location"); - return false; - } - } - hres = ps1->QueryInterface(IID_IPersistFile, reinterpret_cast(&persist_file)); - if (FAILED(hres)) { - LOG_ERROR(Frontend, "Failed to get IPersistFile interface"); - return false; - } - hres = persist_file->Save(std::filesystem::path{shortcut_path / (name + ".lnk")}.c_str(), TRUE); - if (FAILED(hres)) { - LOG_ERROR(Frontend, "Failed to save shortcut"); - return false; - } - return true; -#elif defined(__unix__) && !defined(__APPLE__) && !defined(__ANDROID__) // Any desktop NIX - std::filesystem::path shortcut_path_full = shortcut_path / (name + ".desktop"); - std::ofstream shortcut_stream(shortcut_path_full, std::ios::binary | std::ios::trunc); - if (!shortcut_stream.is_open()) { - LOG_ERROR(Frontend, "Failed to create shortcut"); - return false; - } - // TODO: Migrate fmt::print to std::print in futures STD C++ 23. - fmt::print(shortcut_stream, "[Desktop Entry]\n"); - fmt::print(shortcut_stream, "Type=Application\n"); - fmt::print(shortcut_stream, "Version=1.0\n"); - fmt::print(shortcut_stream, "Name={}\n", name); - if (!comment.empty()) { - fmt::print(shortcut_stream, "Comment={}\n", comment); - } - if (std::filesystem::is_regular_file(icon_path)) { - fmt::print(shortcut_stream, "Icon={}\n", icon_path.string()); - } - fmt::print(shortcut_stream, "TryExec={}\n", command.string()); - fmt::print(shortcut_stream, "Exec={} {}\n", command.string(), arguments); - if (!categories.empty()) { - fmt::print(shortcut_stream, "Categories={}\n", categories); - } - if (!keywords.empty()) { - fmt::print(shortcut_stream, "Keywords={}\n", keywords); - } - return true; -#else // Unsupported platform - return false; -#endif -} catch (const std::exception& e) { - LOG_ERROR(Frontend, "Failed to create shortcut: {}", e.what()); - return false; -} // Messages in pre-defined message boxes for less code spaghetti +// TODO(crueter): Still need to decide what to do re: message boxes w/ qml bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QString& game_title) { int result = 0; QMessageBox::StandardButtons buttons; @@ -3227,33 +3120,6 @@ bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QSt } } -bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, - std::filesystem::path& out_icon_path) { - // Get path to Yuzu icons directory & icon extension - std::string ico_extension = "png"; -#if defined(_WIN32) - out_icon_path = Common::FS::GetEdenPath(Common::FS::EdenPath::IconsDir); - ico_extension = "ico"; -#elif defined(__unix__) && !defined(__APPLE__) && !defined(__ANDROID__) - out_icon_path = Common::FS::GetDataDirectory("XDG_DATA_HOME") / "icons/hicolor/256x256"; -#endif - // Create icons directory if it doesn't exist - if (!Common::FS::CreateDirs(out_icon_path)) { - QMessageBox::critical( - this, tr("Create Icon"), - tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.") - .arg(QString::fromStdString(out_icon_path.string())), - QMessageBox::StandardButton::Ok); - out_icon_path.clear(); - return false; - } - - // Create icon file path - out_icon_path /= (program_id == 0 ? fmt::format("eden-{}.{}", game_file_name, ico_extension) - : fmt::format("eden-{:016X}.{}", program_id, ico_extension)); - return true; -} - void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path, GameListShortcutTarget target) { // Create shortcut @@ -4288,28 +4154,27 @@ void GMainWindow::LoadAmiibo(const QString& filename) { } void GMainWindow::OnOpenRootDataFolder() { - QDesktopServices::openUrl( - QUrl(QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::EdenDir)))); + QtCommon::OpenRootDataFolder(); } -void GMainWindow::OnOpenNANDFolder() { - QDesktopServices::openUrl(QUrl::fromLocalFile( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::NANDDir)))); +void GMainWindow::OnOpenNANDFolder() +{ + QtCommon::OpenNANDFolder(); } -void GMainWindow::OnOpenSDMCFolder() { - QDesktopServices::openUrl(QUrl::fromLocalFile( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir)))); +void GMainWindow::OnOpenSDMCFolder() +{ + QtCommon::OpenSDMCFolder(); } -void GMainWindow::OnOpenModFolder() { - QDesktopServices::openUrl(QUrl::fromLocalFile( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::LoadDir)))); +void GMainWindow::OnOpenModFolder() +{ + QtCommon::OpenModFolder(); } -void GMainWindow::OnOpenLogFolder() { - QDesktopServices::openUrl(QUrl::fromLocalFile( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::LogDir)))); +void GMainWindow::OnOpenLogFolder() +{ + QtCommon::OpenLogFolder(); } void GMainWindow::OnVerifyInstalledContents() { @@ -4444,32 +4309,14 @@ void GMainWindow::OnInstallFirmwareFromZIP() { return; } - namespace fs = std::filesystem; - fs::path tmp{std::filesystem::temp_directory_path()}; + const QString qCacheDir = QtCommon::UnzipFirmwareToTmp(firmware_zip_location); - if (!std::filesystem::create_directories(tmp / "eden" / "firmware")) { - goto unzipFailed; - } - - { - tmp /= "eden"; - tmp /= "firmware"; - - QString qCacheDir = QString::fromStdString(tmp.string()); - - QFile zip(firmware_zip_location); - - QStringList result = JlCompress::extractDir(&zip, qCacheDir); - if (result.isEmpty()) { - goto unzipFailed; - } - - // In this case, it has to be done recursively, since sometimes people - // will pack it into a subdirectory after dumping + // In this case, it has to be done recursively, since sometimes people + // will pack it into a subdirectory after dumping + if (!qCacheDir.isEmpty()) { InstallFirmware(qCacheDir, true); - std::error_code ec; - std::filesystem::remove_all(tmp, ec); + std::filesystem::remove_all(std::filesystem::temp_directory_path() / "eden" / "firmware", ec); if (ec) { QMessageBox::warning(this, tr("Firmware cleanup failed"), @@ -4478,14 +4325,7 @@ void GMainWindow::OnInstallFirmwareFromZIP() { "again.\nOS reported error: %1") .arg(QString::fromStdString(ec.message()))); } - - return; } -unzipFailed: - QMessageBox::critical( - this, tr("Firmware unzip failed"), - tr("Check write permissions in the system temp directory and try again.")); - return; } void GMainWindow::OnInstallDecryptionKeys() { @@ -4764,10 +4604,8 @@ std::filesystem::path GMainWindow::GetShortcutPath(GameListShortcutTarget target return shortcut_path; } -void GMainWindow::CreateShortcut(const std::string& game_path, const u64 program_id, - const std::string& game_title_, GameListShortcutTarget target, - std::string arguments_, const bool needs_title) { - // Get path to yuzu executable +void GMainWindow::CreateShortcut(const std::string &game_path, const u64 program_id, const std::string& game_title_, GameListShortcutTarget target, std::string arguments_, const bool needs_title) { + // Get path to Eden executable std::filesystem::path command = GetEdenCommand(); // Shortcut path @@ -4819,10 +4657,16 @@ void GMainWindow::CreateShortcut(const std::string& game_path, const u64 program QImage icon_data = QImage::fromData(icon_image_file.data(), static_cast(icon_image_file.size())); std::filesystem::path out_icon_path; - if (GMainWindow::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) { + if (QtCommon::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) { if (!SaveIconToFile(out_icon_path, icon_data)) { LOG_ERROR(Frontend, "Could not write icon to file"); } + } else { + QMessageBox::critical( + this, tr("Create Icon"), + tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.") + .arg(QString::fromStdString(out_icon_path.string())), + QMessageBox::StandardButton::Ok); } #if defined(__unix__) && !defined(__APPLE__) && !defined(__ANDROID__) @@ -4843,12 +4687,12 @@ void GMainWindow::CreateShortcut(const std::string& game_path, const u64 program this, GMainWindow::CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, qgame_title)) { arguments = "-f " + arguments; } - const std::string comment = fmt::format("Start {:s} with the eden Emulator", game_title); + const std::string comment = fmt::format("Start {:s} with the Eden Emulator", game_title); const std::string categories = "Game;Emulator;Qt;"; const std::string keywords = "Switch;Nintendo;"; - if (GMainWindow::CreateShortcutLink(shortcut_path, comment, out_icon_path, command, arguments, - categories, keywords, game_title)) { + if (QtCommon::CreateShortcutLink(shortcut_path, comment, out_icon_path, command, + arguments, categories, keywords, game_title)) { GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS, qgame_title); return; @@ -4876,6 +4720,7 @@ void GMainWindow::OnCreateHomeMenuShortcut(GameListShortcutTarget target) { auto qlaunch_applet_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program); const auto game_path = qlaunch_applet_nca->GetFullPath(); + // TODO(crueter): Make this use the Eden icon CreateShortcut(game_path, QLaunchId, "Switch Home Menu", target, "-qlaunch", false); } diff --git a/src/yuzu/main.h b/src/yuzu/main.h index b20f601381..8d00fef4f8 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -478,15 +478,6 @@ private: QString GetTasStateDescription() const; bool CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QString& game_title); - bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, - std::filesystem::path& out_icon_path); - bool CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::string& comment, - const std::filesystem::path& icon_path, - const std::filesystem::path& command, const std::string& arguments, - const std::string& categories, const std::string& keywords, - const std::string& name); - - bool OnCheckNcaVerification(); /** * Mimic the behavior of QMessageBox::question but link controller navigation to the dialog From 886b649a0db5439fa25c3d3c5f3f5bfe952038c4 Mon Sep 17 00:00:00 2001 From: crueter Date: Tue, 22 Jul 2025 23:28:13 -0400 Subject: [PATCH 07/34] Fix license headers --- src/qt_common/qt_game_util.cpp | 3 +++ src/qt_common/qt_game_util.h | 3 +++ src/qt_common/qt_path_util.cpp | 3 +++ src/qt_common/qt_path_util.h | 3 +++ 4 files changed, 12 insertions(+) diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp index 9aba4e393c..9264c782d1 100644 --- a/src/qt_common/qt_game_util.cpp +++ b/src/qt_common/qt_game_util.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #include "qt_game_util.h" #include "common/fs/fs.h" #include "common/fs/path_util.h" diff --git a/src/qt_common/qt_game_util.h b/src/qt_common/qt_game_util.h index 98d17027c4..3d27839672 100644 --- a/src/qt_common/qt_game_util.h +++ b/src/qt_common/qt_game_util.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #ifndef QT_GAME_UTIL_H #define QT_GAME_UTIL_H diff --git a/src/qt_common/qt_path_util.cpp b/src/qt_common/qt_path_util.cpp index 2ca2f6bf72..6875d01dea 100644 --- a/src/qt_common/qt_path_util.cpp +++ b/src/qt_common/qt_path_util.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #include "qt_path_util.h" #include #include diff --git a/src/qt_common/qt_path_util.h b/src/qt_common/qt_path_util.h index 6fafad7ed9..7f399c4bb4 100644 --- a/src/qt_common/qt_path_util.h +++ b/src/qt_common/qt_path_util.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #ifndef QT_PATH_UTIL_H #define QT_PATH_UTIL_H From 115d0484a65dfed9663dc601d80078edc5576fe2 Mon Sep 17 00:00:00 2001 From: crueter Date: Wed, 23 Jul 2025 01:21:18 -0400 Subject: [PATCH 08/34] thank you Qt Creator, very cool Signed-off-by: crueter --- src/qt_common/qt_common.cpp | 7 ++----- src/qt_common/qt_game_util.cpp | 10 +++++++--- src/yuzu/main.cpp | 3 --- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index 0cd4c86b4a..54c79c93e1 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -9,17 +9,14 @@ #include #include -#include #include "common/logging/log.h" #include "core/frontend/emu_window.h" -#if !defined(WIN32) && !defined(__APPLE__) -#include - #include - #include +#if !defined(WIN32) && !defined(__APPLE__) +#include #elif defined(__APPLE__) #include #endif diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp index 9264c782d1..add9d46a39 100644 --- a/src/qt_common/qt_game_util.cpp +++ b/src/qt_common/qt_game_util.cpp @@ -7,11 +7,15 @@ #include #include -#include "fmt/ostream.h" -#include #ifdef _WIN32 -#include + #include + #include + #include "common/scope_exit.h" + #include "common/string_util.h" +#else + #include "fmt/ostream.h" + #include #endif namespace QtCommon { diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 88f3a3d743..86e0755ce8 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -15,8 +15,6 @@ #include "qt_common/qt_game_util.h" #include "qt_common/qt_path_util.h" -#include - #ifdef __APPLE__ #include // for chdir #endif @@ -121,7 +119,6 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "common/scm_rev.h" #include "common/scope_exit.h" #ifdef _WIN32 -#include #include "common/windows/timer_resolution.h" #endif #ifdef ARCHITECTURE_x86_64 From 49670ebb0ff8187323a04350494998bc273b2e04 Mon Sep 17 00:00:00 2001 From: crueter Date: Wed, 23 Jul 2025 21:10:17 -0400 Subject: [PATCH 09/34] [qt] frontend abstraction and message box early handling Signed-off-by: crueter --- src/CMakeLists.txt | 1 + src/frontend_common/firmware_manager.h | 5 ++- src/qt_common/CMakeLists.txt | 6 ++- src/qt_common/qt_common.cpp | 59 ++++++++++++++++++++++---- src/qt_common/qt_common.h | 34 +++++++-------- src/qt_common/qt_frontend_util.cpp | 25 +++++++++++ src/qt_common/qt_frontend_util.h | 29 +++++++++++++ src/yuzu/main.cpp | 24 +++-------- 8 files changed, 136 insertions(+), 47 deletions(-) create mode 100644 src/qt_common/qt_frontend_util.cpp create mode 100644 src/qt_common/qt_frontend_util.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0032b20029..184b049d06 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -234,6 +234,7 @@ if (YUZU_ROOM_STANDALONE) endif() if (ENABLE_QT) + add_definitions(-DYUZU_QT_WIDGETS) add_subdirectory(qt_common) add_subdirectory(yuzu) endif() diff --git a/src/frontend_common/firmware_manager.h b/src/frontend_common/firmware_manager.h index 20f3b41478..23fce59eb3 100644 --- a/src/frontend_common/firmware_manager.h +++ b/src/frontend_common/firmware_manager.h @@ -7,6 +7,7 @@ #include "common/common_types.h" #include "core/core.h" #include "core/file_sys/nca_metadata.h" +#include "core/file_sys/content_archive.h" #include "core/file_sys/registered_cache.h" #include "core/hle/service/filesystem/filesystem.h" #include @@ -143,6 +144,8 @@ inline std::pair GetFirmwareVersion return {firmware_data, result}; } + +// TODO(crueter): GET AS STRING } -#endif // FIRMWARE_MANAGER_H +#endif diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index d6ef427ba6..0c9bb54b11 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -1,6 +1,8 @@ # SPDX-FileCopyrightText: 2023 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later +find_package(Qt6 REQUIRED COMPONENTS Core) + add_library(qt_common STATIC qt_common.h qt_common.cpp @@ -15,10 +17,12 @@ add_library(qt_common STATIC shared_translation.h qt_path_util.h qt_path_util.cpp qt_game_util.h qt_game_util.cpp + qt_frontend_util.h qt_frontend_util.cpp ) create_target_directory_groups(qt_common) -target_link_libraries(qt_common PUBLIC core Qt6::Core Qt6::Gui SimpleIni::SimpleIni QuaZip::QuaZip) +target_link_libraries(qt_common PUBLIC core Qt6::Widgets SimpleIni::SimpleIni QuaZip::QuaZip) +target_link_libraries(qt_common PRIVATE Qt6::Core) if (NOT WIN32) target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index 54c79c93e1..c7b75a196d 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -5,6 +5,7 @@ #include "common/fs/fs.h" #include "common/fs/path_util.h" #include "core/hle/service/filesystem/filesystem.h" +#include "frontend_common/firmware_manager.h" #include "uisettings.h" #include @@ -13,6 +14,10 @@ #include "core/frontend/emu_window.h" #include + +#include +#include "qt_frontend_util.h" + #include #if !defined(WIN32) && !defined(__APPLE__) @@ -22,7 +27,6 @@ #endif namespace QtCommon { - MetadataResult ResetMetadata() { if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) @@ -87,8 +91,24 @@ FirmwareInstallResult InstallFirmware( bool recursive, std::function QtProgressCallback, Core::System* system, - FileSys::VfsFilesystem* vfs) + FileSys::VfsFilesystem* vfs, + QWidget* parent) { + static constexpr const char* failedTitle = "Firmware Install Failed"; + static constexpr const char* successTitle = "Firmware Install Failed"; + static constexpr QMessageBox::StandardButtons buttons = QMessageBox::Ok; + + QMessageBox::Icon icon; + FirmwareInstallResult result; + + const auto ShowMessage = [&]() { + QtCommon::Frontend::ShowMessage(icon, + failedTitle, + GetFirmwareInstallResultString(result), + buttons, + parent); + }; + LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); // Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in @@ -121,14 +141,20 @@ FirmwareInstallResult InstallFirmware( } if (out.size() <= 0) { - return FirmwareInstallResult::NoNCAs; + result = FirmwareInstallResult::NoNCAs; + icon = QMessageBox::Warning; + ShowMessage(); + return result; } // Locate and erase the content of nand/system/Content/registered/*.nca, if any. auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); if (sysnand_content_vdir->IsWritable() && !sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { - return FirmwareInstallResult::FailedDelete; + result = FirmwareInstallResult::FailedDelete; + icon = QMessageBox::Critical; + ShowMessage(); + return result; } LOG_INFO(Frontend, @@ -159,17 +185,35 @@ FirmwareInstallResult InstallFirmware( 20 + static_cast(((i) / static_cast(out.size())) * 70.0))) { - return FirmwareInstallResult::FailedCorrupted; + result = FirmwareInstallResult::FailedCorrupted; + icon = QMessageBox::Warning; + ShowMessage(); + return result; } } if (!success) { - return FirmwareInstallResult::FailedCopy; + result = FirmwareInstallResult::FailedCopy; + icon = QMessageBox::Critical; + ShowMessage(); + return result; } // Re-scan VFS for the newly placed firmware files. system->GetFileSystemController().CreateFactories(*vfs); - return FirmwareInstallResult::Success; + + const auto pair = FirmwareManager::GetFirmwareVersion(*system); + const auto firmware_data = pair.first; + const std::string display_version(firmware_data.display_version.data()); + + result = FirmwareInstallResult::Success; + QtCommon::Frontend::ShowMessage(QMessageBox::Information, + qApp->tr(successTitle), + qApp->tr(GetFirmwareInstallResultString(result)) + .arg(QString::fromStdString(display_version)), + buttons, + parent); + return result; } QString UnzipFirmwareToTmp(const QString& location) @@ -195,5 +239,4 @@ QString UnzipFirmwareToTmp(const QString& location) return qCacheDir; } - } // namespace QtCommon diff --git a/src/qt_common/qt_common.h b/src/qt_common/qt_common.h index b3ca99e65a..ef9b5577f1 100644 --- a/src/qt_common/qt_common.h +++ b/src/qt_common/qt_common.h @@ -13,7 +13,6 @@ #include namespace QtCommon { - static constexpr std::array METADATA_RESULTS = { "The operation completed successfully.", "The metadata cache couldn't be deleted. It might be in use or non-existent.", @@ -41,15 +40,14 @@ inline constexpr const char *GetResetMetadataResultString(MetadataResult result) return METADATA_RESULTS.at(static_cast(result)); } -static constexpr std::array FIRMWARE_RESULTS = { - "", - "", - "Unable to locate potential firmware NCA files", - "Failed to delete one or more firmware files.", - "One or more firmware files failed to copy into NAND.", - "Firmware installation cancelled, firmware may be in a bad state or corrupted." - "Restart Eden or re-install firmware." -}; +static constexpr std::array FIRMWARE_RESULTS + = {"Successfully installed firmware version %1", + "", + "Unable to locate potential firmware NCA files", + "Failed to delete one or more firmware files.", + "One or more firmware files failed to copy into NAND.", + "Firmware installation cancelled, firmware may be in a bad state or corrupted." + "Restart Eden or re-install firmware."}; enum class FirmwareInstallResult { Success, @@ -60,11 +58,13 @@ enum class FirmwareInstallResult { FailedCorrupted, }; -FirmwareInstallResult InstallFirmware(const QString &location, - bool recursive, - std::function QtProgressCallback, - Core::System *system, - FileSys::VfsFilesystem *vfs); +FirmwareInstallResult InstallFirmware( + const QString &location, + bool recursive, + std::function QtProgressCallback, + Core::System *system, + FileSys::VfsFilesystem *vfs, + QWidget *parent = nullptr); QString UnzipFirmwareToTmp(const QString &location); @@ -75,8 +75,6 @@ inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResul Core::Frontend::WindowSystemType GetWindowSystemType(); -Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window); - - +Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow *window); } // namespace QtCommon #endif diff --git a/src/qt_common/qt_frontend_util.cpp b/src/qt_common/qt_frontend_util.cpp new file mode 100644 index 0000000000..6cbe82e000 --- /dev/null +++ b/src/qt_common/qt_frontend_util.cpp @@ -0,0 +1,25 @@ +#include "qt_frontend_util.h" + +namespace QtCommon::Frontend { +QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons, + QWidget *parent) +{ +#ifdef YUZU_QT_WIDGETS + QMessageBox *box = new QMessageBox(icon, title, text, buttons, parent); + return static_cast(box->exec()); +#endif +} + +QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons, + QWidget *parent) +{ + return ShowMessage(icon, qApp->tr(title), qApp->tr(text), buttons, parent); +} + +} // namespace QtCommon::Frontend diff --git a/src/qt_common/qt_frontend_util.h b/src/qt_common/qt_frontend_util.h new file mode 100644 index 0000000000..8508e29f18 --- /dev/null +++ b/src/qt_common/qt_frontend_util.h @@ -0,0 +1,29 @@ +#ifndef QT_FRONTEND_UTIL_H +#define QT_FRONTEND_UTIL_H + +#include +#include + +#ifdef YUZU_QT_WIDGETS +#include +#endif + +/** + * manages common functionality e.g. message boxes and such for Qt/QML + */ +namespace QtCommon::Frontend { +Q_NAMESPACE + +QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::NoButton, + QWidget *parent = nullptr); + +QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons = QMessageBox::NoButton, + QWidget *parent = nullptr); +} // namespace QtCommon::Frontend +#endif // QT_FRONTEND_UTIL_H diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 86e0755ce8..19110781bf 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2611,6 +2611,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target QDesktopServices::openUrl(QUrl::fromLocalFile(qpath)); } +// TODO(crueter): Transfer ts to showmessage void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) { if (!QtCommon::PathUtil::OpenShaderCache(program_id)) { QMessageBox::warning(this, tr("Error Opening Shader Cache"), tr("Failed to create or open shader cache for this title, ensure your app data directory has write permissions.")); @@ -2680,6 +2681,8 @@ static bool RomFSRawCopy(size_t total_size, size_t& read_size, QProgressDialog& } // TODO(crueter): All this can be transfered to qt_common +// Aldoe I need to decide re: message boxes for QML +// translations_common? strings_common? qt_strings? who knows QString GMainWindow::GetGameListErrorRemoving(InstalledEntryType type) const { switch (type) { case InstalledEntryType::Game: @@ -4218,28 +4221,11 @@ void GMainWindow::InstallFirmware(const QString& location, bool recursive) { return progress.wasCanceled(); }; - auto result = QtCommon::InstallFirmware(location, recursive, QtProgressCallback, system.get(), vfs.get()); - const char* resultMessage = QtCommon::GetFirmwareInstallResultString(result); + auto result = QtCommon::InstallFirmware(location, recursive, QtProgressCallback, system.get(), vfs.get(), this); progress.close(); - QMessageBox *box = new QMessageBox(QMessageBox::Icon::NoIcon, tr("Firmware Install Failed"), tr(resultMessage), QMessageBox::Ok, this); - - switch (result) { - case QtCommon::FirmwareInstallResult::NoNCAs: - case QtCommon::FirmwareInstallResult::FailedCorrupted: - box->setIcon(QMessageBox::Icon::Warning); - box->exec(); - return; - case QtCommon::FirmwareInstallResult::FailedCopy: - case QtCommon::FirmwareInstallResult::FailedDelete: - box->setIcon(QMessageBox::Icon::Critical); - box->exec(); - return; - default: - box->deleteLater(); - break; - } + if (result != QtCommon::FirmwareInstallResult::Success) return; auto VerifyFirmwareCallback = [&](size_t total_size, size_t processed_size) { progress.setValue(90 + static_cast((processed_size * 10) / total_size)); From 092e645296a7f79b5428347124e41dbe61231ece Mon Sep 17 00:00:00 2001 From: crueter Date: Wed, 23 Jul 2025 21:12:22 -0400 Subject: [PATCH 10/34] Fix license headers --- src/qt_common/qt_frontend_util.cpp | 3 +++ src/qt_common/qt_frontend_util.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/qt_common/qt_frontend_util.cpp b/src/qt_common/qt_frontend_util.cpp index 6cbe82e000..9a05c89928 100644 --- a/src/qt_common/qt_frontend_util.cpp +++ b/src/qt_common/qt_frontend_util.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #include "qt_frontend_util.h" namespace QtCommon::Frontend { diff --git a/src/qt_common/qt_frontend_util.h b/src/qt_common/qt_frontend_util.h index 8508e29f18..8a38c033bf 100644 --- a/src/qt_common/qt_frontend_util.h +++ b/src/qt_common/qt_frontend_util.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #ifndef QT_FRONTEND_UTIL_H #define QT_FRONTEND_UTIL_H From 75f18095e0616b805daea98d932f74c415644e2c Mon Sep 17 00:00:00 2001 From: crueter Date: Thu, 7 Aug 2025 20:45:16 -0400 Subject: [PATCH 11/34] [qt_common] update translations Signed-off-by: crueter --- src/qt_common/qt_frontend_util.cpp | 2 + src/qt_common/qt_game_util.cpp | 20 ++--- src/qt_common/qt_game_util.h | 4 +- src/qt_common/shared_translation.cpp | 110 +++++++++++++-------------- 4 files changed, 70 insertions(+), 66 deletions(-) diff --git a/src/qt_common/qt_frontend_util.cpp b/src/qt_common/qt_frontend_util.cpp index 9a05c89928..bcb662239b 100644 --- a/src/qt_common/qt_frontend_util.cpp +++ b/src/qt_common/qt_frontend_util.cpp @@ -14,6 +14,8 @@ QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, QMessageBox *box = new QMessageBox(icon, title, text, buttons, parent); return static_cast(box->exec()); #endif + // TODO(crueter): If Qt Widgets is disabled... + // need a way to reference icon/buttons too } QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp index add9d46a39..a870c2ab27 100644 --- a/src/qt_common/qt_game_util.cpp +++ b/src/qt_common/qt_game_util.cpp @@ -146,33 +146,33 @@ bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_ return true; } -void OpenRootDataFolder() { +void OpenEdenFolder(const Common::FS::EdenPath& path) { QDesktopServices::openUrl(QUrl( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::EdenDir)))); + QString::fromStdString(Common::FS::GetEdenPathString(path)))); +} + +void OpenRootDataFolder() { + OpenEdenFolder(Common::FS::EdenPath::EdenDir); } void OpenNANDFolder() { - QDesktopServices::openUrl(QUrl::fromLocalFile( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::NANDDir)))); + OpenEdenFolder(Common::FS::EdenPath::NANDDir); } void OpenSDMCFolder() { - QDesktopServices::openUrl(QUrl::fromLocalFile( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir)))); + OpenEdenFolder(Common::FS::EdenPath::SDMCDir); } void OpenModFolder() { - QDesktopServices::openUrl(QUrl::fromLocalFile( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::LoadDir)))); + OpenEdenFolder(Common::FS::EdenPath::LoadDir); } void OpenLogFolder() { - QDesktopServices::openUrl(QUrl::fromLocalFile( - QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::LogDir)))); + OpenEdenFolder(Common::FS::EdenPath::LogDir); } } diff --git a/src/qt_common/qt_game_util.h b/src/qt_common/qt_game_util.h index 3d27839672..12916d8a98 100644 --- a/src/qt_common/qt_game_util.h +++ b/src/qt_common/qt_game_util.h @@ -4,6 +4,7 @@ #ifndef QT_GAME_UTIL_H #define QT_GAME_UTIL_H +#include "common/fs/path_util.h" #include "frontend_common/content_manager.h" #include @@ -12,7 +13,7 @@ namespace QtCommon { static constexpr std::array GAME_VERIFICATION_RESULTS = { "The operation completed successfully.", "File contents may be corrupt or missing..", - "Firmware installation cancelled, firmware may be in a bad state or corrupted." + "Firmware installation cancelled, firmware may be in a bad state or corrupted. " "File contents could not be checked for validity." }; @@ -34,6 +35,7 @@ bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, std::filesystem::path& out_icon_path); +void OpenEdenFolder(const Common::FS::EdenPath &path); void OpenRootDataFolder(); void OpenNANDFolder(); void OpenSDMCFolder(); diff --git a/src/qt_common/shared_translation.cpp b/src/qt_common/shared_translation.cpp index 018af56c67..81ec35b6d8 100644 --- a/src/qt_common/shared_translation.cpp +++ b/src/qt_common/shared_translation.cpp @@ -29,10 +29,10 @@ std::unique_ptr InitializeTranslations(QObject* parent) #define INSERT(SETTINGS, ID, NAME, TOOLTIP) \ translations->insert(std::pair{SETTINGS::values.ID.Id(), std::pair{(NAME), (TOOLTIP)}}) - // A setting can be ignored by giving it a blank name + // A setting can be ignored by giving it a blank name - // Applets - INSERT(Settings, cabinet_applet_mode, tr("Amiibo editor"), QString()); + // Applets + INSERT(Settings, cabinet_applet_mode, tr("Amiibo editor"), QString()); INSERT(Settings, controller_applet_mode, tr("Controller configuration"), QString()); INSERT(Settings, data_erase_applet_mode, tr("Data erase"), QString()); INSERT(Settings, error_applet_mode, tr("Error"), QString()); @@ -648,58 +648,58 @@ std::unique_ptr ComboboxEnumeration(QObject* parent) translations->insert( {Settings::EnumMetadata::Index(), { - {static_cast(Settings::TimeZone::Auto), - tr("Auto (%1)", "Auto select time zone") - .arg(QString::fromStdString( - Settings::GetTimeZoneString(Settings::TimeZone::Auto)))}, - {static_cast(Settings::TimeZone::Default), - tr("Default (%1)", "Default time zone") - .arg(QString::fromStdString(Common::TimeZone::GetDefaultTimeZone()))}, - PAIR(TimeZone, Cet, tr("CET")), - PAIR(TimeZone, Cst6Cdt, tr("CST6CDT")), - PAIR(TimeZone, Cuba, tr("Cuba")), - PAIR(TimeZone, Eet, tr("EET")), - PAIR(TimeZone, Egypt, tr("Egypt")), - PAIR(TimeZone, Eire, tr("Eire")), - PAIR(TimeZone, Est, tr("EST")), - PAIR(TimeZone, Est5Edt, tr("EST5EDT")), - PAIR(TimeZone, Gb, tr("GB")), - PAIR(TimeZone, GbEire, tr("GB-Eire")), - PAIR(TimeZone, Gmt, tr("GMT")), - PAIR(TimeZone, GmtPlusZero, tr("GMT+0")), - PAIR(TimeZone, GmtMinusZero, tr("GMT-0")), - PAIR(TimeZone, GmtZero, tr("GMT0")), - PAIR(TimeZone, Greenwich, tr("Greenwich")), - PAIR(TimeZone, Hongkong, tr("Hongkong")), - PAIR(TimeZone, Hst, tr("HST")), - PAIR(TimeZone, Iceland, tr("Iceland")), - PAIR(TimeZone, Iran, tr("Iran")), - PAIR(TimeZone, Israel, tr("Israel")), - PAIR(TimeZone, Jamaica, tr("Jamaica")), - PAIR(TimeZone, Japan, tr("Japan")), - PAIR(TimeZone, Kwajalein, tr("Kwajalein")), - PAIR(TimeZone, Libya, tr("Libya")), - PAIR(TimeZone, Met, tr("MET")), - PAIR(TimeZone, Mst, tr("MST")), - PAIR(TimeZone, Mst7Mdt, tr("MST7MDT")), - PAIR(TimeZone, Navajo, tr("Navajo")), - PAIR(TimeZone, Nz, tr("NZ")), - PAIR(TimeZone, NzChat, tr("NZ-CHAT")), - PAIR(TimeZone, Poland, tr("Poland")), - PAIR(TimeZone, Portugal, tr("Portugal")), - PAIR(TimeZone, Prc, tr("PRC")), - PAIR(TimeZone, Pst8Pdt, tr("PST8PDT")), - PAIR(TimeZone, Roc, tr("ROC")), - PAIR(TimeZone, Rok, tr("ROK")), - PAIR(TimeZone, Singapore, tr("Singapore")), - PAIR(TimeZone, Turkey, tr("Turkey")), - PAIR(TimeZone, Uct, tr("UCT")), - PAIR(TimeZone, Universal, tr("Universal")), - PAIR(TimeZone, Utc, tr("UTC")), - PAIR(TimeZone, WSu, tr("W-SU")), - PAIR(TimeZone, Wet, tr("WET")), - PAIR(TimeZone, Zulu, tr("Zulu")), - }}); + {static_cast(Settings::TimeZone::Auto), + tr("Auto (%1)", "Auto select time zone") + .arg(QString::fromStdString( + Settings::GetTimeZoneString(Settings::TimeZone::Auto)))}, + {static_cast(Settings::TimeZone::Default), + tr("Default (%1)", "Default time zone") + .arg(QString::fromStdString(Common::TimeZone::GetDefaultTimeZone()))}, + PAIR(TimeZone, Cet, tr("CET")), + PAIR(TimeZone, Cst6Cdt, tr("CST6CDT")), + PAIR(TimeZone, Cuba, tr("Cuba")), + PAIR(TimeZone, Eet, tr("EET")), + PAIR(TimeZone, Egypt, tr("Egypt")), + PAIR(TimeZone, Eire, tr("Eire")), + PAIR(TimeZone, Est, tr("EST")), + PAIR(TimeZone, Est5Edt, tr("EST5EDT")), + PAIR(TimeZone, Gb, tr("GB")), + PAIR(TimeZone, GbEire, tr("GB-Eire")), + PAIR(TimeZone, Gmt, tr("GMT")), + PAIR(TimeZone, GmtPlusZero, tr("GMT+0")), + PAIR(TimeZone, GmtMinusZero, tr("GMT-0")), + PAIR(TimeZone, GmtZero, tr("GMT0")), + PAIR(TimeZone, Greenwich, tr("Greenwich")), + PAIR(TimeZone, Hongkong, tr("Hongkong")), + PAIR(TimeZone, Hst, tr("HST")), + PAIR(TimeZone, Iceland, tr("Iceland")), + PAIR(TimeZone, Iran, tr("Iran")), + PAIR(TimeZone, Israel, tr("Israel")), + PAIR(TimeZone, Jamaica, tr("Jamaica")), + PAIR(TimeZone, Japan, tr("Japan")), + PAIR(TimeZone, Kwajalein, tr("Kwajalein")), + PAIR(TimeZone, Libya, tr("Libya")), + PAIR(TimeZone, Met, tr("MET")), + PAIR(TimeZone, Mst, tr("MST")), + PAIR(TimeZone, Mst7Mdt, tr("MST7MDT")), + PAIR(TimeZone, Navajo, tr("Navajo")), + PAIR(TimeZone, Nz, tr("NZ")), + PAIR(TimeZone, NzChat, tr("NZ-CHAT")), + PAIR(TimeZone, Poland, tr("Poland")), + PAIR(TimeZone, Portugal, tr("Portugal")), + PAIR(TimeZone, Prc, tr("PRC")), + PAIR(TimeZone, Pst8Pdt, tr("PST8PDT")), + PAIR(TimeZone, Roc, tr("ROC")), + PAIR(TimeZone, Rok, tr("ROK")), + PAIR(TimeZone, Singapore, tr("Singapore")), + PAIR(TimeZone, Turkey, tr("Turkey")), + PAIR(TimeZone, Uct, tr("UCT")), + PAIR(TimeZone, Universal, tr("Universal")), + PAIR(TimeZone, Utc, tr("UTC")), + PAIR(TimeZone, WSu, tr("W-SU")), + PAIR(TimeZone, Wet, tr("WET")), + PAIR(TimeZone, Zulu, tr("Zulu")), + }}); translations->insert({Settings::EnumMetadata::Index(), { PAIR(AudioMode, Mono, tr("Mono")), From ca349ad7b0cc50c87548b5c41e1e108568183ad5 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 30 Aug 2025 19:48:13 -0400 Subject: [PATCH 12/34] [qt_common] reorg, move more stuff out of main Signed-off-by: crueter --- src/qt_common/CMakeLists.txt | 5 + src/qt_common/qt_common.cpp | 175 +------- src/qt_common/qt_common.h | 76 +--- src/qt_common/qt_content_util.cpp | 202 +++++++++ src/qt_common/qt_content_util.h | 48 +++ src/qt_common/qt_frontend_util.cpp | 73 +++- src/qt_common/qt_frontend_util.h | 44 +- src/qt_common/qt_game_util.cpp | 270 ++++++++++-- src/qt_common/qt_game_util.h | 40 +- src/qt_common/qt_meta.cpp | 72 ++++ src/qt_common/qt_meta.h | 12 + src/qt_common/qt_path_util.cpp | 9 +- src/qt_common/qt_path_util.h | 4 +- src/qt_common/qt_rom_util.cpp | 75 ++++ src/qt_common/qt_rom_util.h | 17 + .../configuration/configure_filesystem.cpp | 13 +- src/yuzu/game_list.cpp | 25 +- src/yuzu/game_list.h | 19 +- src/yuzu/main.cpp | 403 +++--------------- src/yuzu/main.h | 21 +- 20 files changed, 923 insertions(+), 680 deletions(-) create mode 100644 src/qt_common/qt_content_util.cpp create mode 100644 src/qt_common/qt_content_util.h create mode 100644 src/qt_common/qt_meta.cpp create mode 100644 src/qt_common/qt_meta.h create mode 100644 src/qt_common/qt_rom_util.cpp create mode 100644 src/qt_common/qt_rom_util.h diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index 0c9bb54b11..da6c9b0481 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2023 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later +find_package(Qt6 REQUIRED COMPONENTS Core) find_package(Qt6 REQUIRED COMPONENTS Core) add_library(qt_common STATIC @@ -18,11 +19,15 @@ add_library(qt_common STATIC qt_path_util.h qt_path_util.cpp qt_game_util.h qt_game_util.cpp qt_frontend_util.h qt_frontend_util.cpp + qt_meta.h qt_meta.cpp + qt_content_util.h qt_content_util.cpp + qt_rom_util.h qt_rom_util.cpp ) create_target_directory_groups(qt_common) target_link_libraries(qt_common PUBLIC core Qt6::Widgets SimpleIni::SimpleIni QuaZip::QuaZip) target_link_libraries(qt_common PRIVATE Qt6::Core) +target_link_libraries(qt_common PRIVATE Qt6::Core) if (NOT WIN32) target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index c7b75a196d..6f8808ca32 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -2,11 +2,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "qt_common.h" -#include "common/fs/fs.h" -#include "common/fs/path_util.h" -#include "core/hle/service/filesystem/filesystem.h" -#include "frontend_common/firmware_manager.h" -#include "uisettings.h" #include #include @@ -16,7 +11,6 @@ #include #include -#include "qt_frontend_util.h" #include @@ -27,19 +21,9 @@ #endif namespace QtCommon { -MetadataResult ResetMetadata() -{ - if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) - / "game_list/")) { - return MetadataResult::Empty; - } else if (Common::FS::RemoveDirRecursively( - Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) { - return MetadataResult::Success; - UISettings::values.is_game_list_reload_pending.exchange(true); - } else { - return MetadataResult::Failure; - } -} + +QObject *rootObject = nullptr; +Core::System *system = nullptr; Core::Frontend::WindowSystemType GetWindowSystemType() { @@ -86,157 +70,14 @@ Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) return wsi; } -FirmwareInstallResult InstallFirmware( - const QString& location, - bool recursive, - std::function QtProgressCallback, - Core::System* system, - FileSys::VfsFilesystem* vfs, - QWidget* parent) +const QString tr(const char* str) { - static constexpr const char* failedTitle = "Firmware Install Failed"; - static constexpr const char* successTitle = "Firmware Install Failed"; - static constexpr QMessageBox::StandardButtons buttons = QMessageBox::Ok; - - QMessageBox::Icon icon; - FirmwareInstallResult result; - - const auto ShowMessage = [&]() { - QtCommon::Frontend::ShowMessage(icon, - failedTitle, - GetFirmwareInstallResultString(result), - buttons, - parent); - }; - - LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); - - // Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in - // there.) - std::filesystem::path firmware_source_path = location.toStdString(); - if (!Common::FS::IsDir(firmware_source_path)) { - return FirmwareInstallResult::NoOp; - } - - std::vector out; - const Common::FS::DirEntryCallable callback = - [&out](const std::filesystem::directory_entry& entry) { - if (entry.path().has_extension() && entry.path().extension() == ".nca") { - out.emplace_back(entry.path()); - } - - return true; - }; - - QtProgressCallback(100, 10); - - if (recursive) { - Common::FS::IterateDirEntriesRecursively(firmware_source_path, - callback, - Common::FS::DirEntryFilter::File); - } else { - Common::FS::IterateDirEntries(firmware_source_path, - callback, - Common::FS::DirEntryFilter::File); - } - - if (out.size() <= 0) { - result = FirmwareInstallResult::NoNCAs; - icon = QMessageBox::Warning; - ShowMessage(); - return result; - } - - // Locate and erase the content of nand/system/Content/registered/*.nca, if any. - auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); - if (sysnand_content_vdir->IsWritable() - && !sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { - result = FirmwareInstallResult::FailedDelete; - icon = QMessageBox::Critical; - ShowMessage(); - return result; - } - - LOG_INFO(Frontend, - "Cleaned nand/system/Content/registered folder in preparation for new firmware."); - - QtProgressCallback(100, 20); - - auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered"); - - bool success = true; - int i = 0; - for (const auto& firmware_src_path : out) { - i++; - auto firmware_src_vfile = vfs->OpenFile(firmware_src_path.generic_string(), - FileSys::OpenMode::Read); - auto firmware_dst_vfile = firmware_vdir - ->CreateFileRelative(firmware_src_path.filename().string()); - - if (!VfsRawCopy(firmware_src_vfile, firmware_dst_vfile)) { - LOG_ERROR(Frontend, - "Failed to copy firmware file {} to {} in registered folder!", - firmware_src_path.generic_string(), - firmware_src_path.filename().string()); - success = false; - } - - if (QtProgressCallback(100, - 20 - + static_cast(((i) / static_cast(out.size())) - * 70.0))) { - result = FirmwareInstallResult::FailedCorrupted; - icon = QMessageBox::Warning; - ShowMessage(); - return result; - } - } - - if (!success) { - result = FirmwareInstallResult::FailedCopy; - icon = QMessageBox::Critical; - ShowMessage(); - return result; - } - - // Re-scan VFS for the newly placed firmware files. - system->GetFileSystemController().CreateFactories(*vfs); - - const auto pair = FirmwareManager::GetFirmwareVersion(*system); - const auto firmware_data = pair.first; - const std::string display_version(firmware_data.display_version.data()); - - result = FirmwareInstallResult::Success; - QtCommon::Frontend::ShowMessage(QMessageBox::Information, - qApp->tr(successTitle), - qApp->tr(GetFirmwareInstallResultString(result)) - .arg(QString::fromStdString(display_version)), - buttons, - parent); - return result; + return QGuiApplication::tr(str); } -QString UnzipFirmwareToTmp(const QString& location) +const QString tr(const std::string& str) { - namespace fs = std::filesystem; - fs::path tmp{fs::temp_directory_path()}; - - if (!fs::create_directories(tmp / "eden" / "firmware")) { - return ""; - } - - tmp /= "eden"; - tmp /= "firmware"; - - QString qCacheDir = QString::fromStdString(tmp.string()); - - QFile zip(location); - - QStringList result = JlCompress::extractDir(&zip, qCacheDir); - if (result.isEmpty()) { - return ""; - } - - return qCacheDir; + return QGuiApplication::tr(str.c_str()); } + } // namespace QtCommon diff --git a/src/qt_common/qt_common.h b/src/qt_common/qt_common.h index ef9b5577f1..cf52cedc32 100644 --- a/src/qt_common/qt_common.h +++ b/src/qt_common/qt_common.h @@ -4,8 +4,6 @@ #ifndef QT_COMMON_H #define QT_COMMON_H -#include - #include #include "core/core.h" #include @@ -13,68 +11,28 @@ #include namespace QtCommon { -static constexpr std::array METADATA_RESULTS = { - "The operation completed successfully.", - "The metadata cache couldn't be deleted. It might be in use or non-existent.", - "The metadata cache is already empty.", -}; -enum class MetadataResult { - Success, - Failure, - Empty, -}; -/** - * @brief ResetMetadata Reset game list metadata. - * @return A result code. - */ -MetadataResult ResetMetadata(); +extern QObject *rootObject; +extern Core::System *system; -/** - * \brief Get a string representation of a result from ResetMetadata. - * \param result The result code. - * \return A string representation of the passed result code. - */ -inline constexpr const char *GetResetMetadataResultString(MetadataResult result) -{ - return METADATA_RESULTS.at(static_cast(result)); -} - -static constexpr std::array FIRMWARE_RESULTS - = {"Successfully installed firmware version %1", - "", - "Unable to locate potential firmware NCA files", - "Failed to delete one or more firmware files.", - "One or more firmware files failed to copy into NAND.", - "Firmware installation cancelled, firmware may be in a bad state or corrupted." - "Restart Eden or re-install firmware."}; - -enum class FirmwareInstallResult { - Success, - NoOp, - NoNCAs, - FailedDelete, - FailedCopy, - FailedCorrupted, -}; - -FirmwareInstallResult InstallFirmware( - const QString &location, - bool recursive, - std::function QtProgressCallback, - Core::System *system, - FileSys::VfsFilesystem *vfs, - QWidget *parent = nullptr); - -QString UnzipFirmwareToTmp(const QString &location); - -inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResult result) -{ - return FIRMWARE_RESULTS.at(static_cast(result)); -} +typedef std::function QtProgressCallback; Core::Frontend::WindowSystemType GetWindowSystemType(); Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow *window); + +static inline void SetRootObject(QObject *parent) +{ + rootObject = parent; +} + +static inline void SetSystem(Core::System *newSystem) +{ + system = newSystem; +} + +const QString tr(const char *str); +const QString tr(const std::string &str); + } // namespace QtCommon #endif diff --git a/src/qt_common/qt_content_util.cpp b/src/qt_common/qt_content_util.cpp new file mode 100644 index 0000000000..81ec7c9cea --- /dev/null +++ b/src/qt_common/qt_content_util.cpp @@ -0,0 +1,202 @@ +#include "qt_content_util.h" +#include "common/fs/fs.h" +#include "frontend_common/content_manager.h" +#include "frontend_common/firmware_manager.h" +#include "qt_common/qt_game_util.h" +#include "qt_frontend_util.h" + +#include + +namespace QtCommon::Content { + +bool CheckGameFirmware(u64 program_id, Core::System &system, QObject *parent) +{ + if (FirmwareManager::GameRequiresFirmware(program_id) + && !FirmwareManager::CheckFirmwarePresence(system)) { + auto result = QtCommon::Frontend::ShowMessage( + QMessageBox::Warning, + "Game Requires Firmware", + "The game you are trying to launch requires firmware to boot or to get past the " + "opening menu. Please " + "dump and install firmware, or press \"OK\" to launch anyways.", + QMessageBox::Ok | QMessageBox::Cancel, + parent); + + return result == QMessageBox::Ok; + } + + return true; +} + +FirmwareInstallResult InstallFirmware( + const QString& location, + bool recursive, + QtProgressCallback callback, + FileSys::VfsFilesystem* vfs) +{ + static constexpr const char* failedTitle = "Firmware Install Failed"; + static constexpr const char* successTitle = "Firmware Install Failed"; + static constexpr QMessageBox::StandardButtons buttons = QMessageBox::Ok; + + QMessageBox::Icon icon; + FirmwareInstallResult result; + + const auto ShowMessage = [&]() { + QtCommon::Frontend::ShowMessage(icon, + failedTitle, + GetFirmwareInstallResultString(result), + buttons, + rootObject); + }; + + LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); + + // Check for a reasonable number of .nca files (don't hardcode them, just see if there's some in + // there.) + std::filesystem::path firmware_source_path = location.toStdString(); + if (!Common::FS::IsDir(firmware_source_path)) { + return FirmwareInstallResult::NoOp; + } + + std::vector out; + const Common::FS::DirEntryCallable dir_callback = + [&out](const std::filesystem::directory_entry& entry) { + if (entry.path().has_extension() && entry.path().extension() == ".nca") { + out.emplace_back(entry.path()); + } + + return true; + }; + + callback(100, 10); + + if (recursive) { + Common::FS::IterateDirEntriesRecursively(firmware_source_path, + dir_callback, + Common::FS::DirEntryFilter::File); + } else { + Common::FS::IterateDirEntries(firmware_source_path, + dir_callback, + Common::FS::DirEntryFilter::File); + } + + if (out.size() <= 0) { + result = FirmwareInstallResult::NoNCAs; + icon = QMessageBox::Warning; + ShowMessage(); + return result; + } + + // Locate and erase the content of nand/system/Content/registered/*.nca, if any. + auto sysnand_content_vdir = system->GetFileSystemController().GetSystemNANDContentDirectory(); + if (sysnand_content_vdir->IsWritable() + && !sysnand_content_vdir->CleanSubdirectoryRecursive("registered")) { + result = FirmwareInstallResult::FailedDelete; + icon = QMessageBox::Critical; + ShowMessage(); + return result; + } + + LOG_INFO(Frontend, + "Cleaned nand/system/Content/registered folder in preparation for new firmware."); + + callback(100, 20); + + auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered"); + + bool success = true; + int i = 0; + for (const auto& firmware_src_path : out) { + i++; + auto firmware_src_vfile = vfs->OpenFile(firmware_src_path.generic_string(), + FileSys::OpenMode::Read); + auto firmware_dst_vfile = firmware_vdir + ->CreateFileRelative(firmware_src_path.filename().string()); + + if (!VfsRawCopy(firmware_src_vfile, firmware_dst_vfile)) { + LOG_ERROR(Frontend, + "Failed to copy firmware file {} to {} in registered folder!", + firmware_src_path.generic_string(), + firmware_src_path.filename().string()); + success = false; + } + + if (callback(100, 20 + static_cast(((i) / static_cast(out.size())) * 70.0))) { + result = FirmwareInstallResult::FailedCorrupted; + icon = QMessageBox::Warning; + ShowMessage(); + return result; + } + } + + if (!success) { + result = FirmwareInstallResult::FailedCopy; + icon = QMessageBox::Critical; + ShowMessage(); + return result; + } + + // Re-scan VFS for the newly placed firmware files. + system->GetFileSystemController().CreateFactories(*vfs); + + const auto pair = FirmwareManager::GetFirmwareVersion(*system); + const auto firmware_data = pair.first; + const std::string display_version(firmware_data.display_version.data()); + + result = FirmwareInstallResult::Success; + QtCommon::Frontend::Information(rootObject, + tr(successTitle), + tr(GetFirmwareInstallResultString(result)) + .arg(QString::fromStdString(display_version)), + buttons); + return result; +} + +QString UnzipFirmwareToTmp(const QString& location) +{ + namespace fs = std::filesystem; + fs::path tmp{fs::temp_directory_path()}; + + if (!fs::create_directories(tmp / "eden" / "firmware")) { + return ""; + } + + tmp /= "eden"; + tmp /= "firmware"; + + QString qCacheDir = QString::fromStdString(tmp.string()); + + QFile zip(location); + + QStringList result = JlCompress::extractDir(&zip, qCacheDir); + if (result.isEmpty()) { + return ""; + } + + return qCacheDir; +} + +// Content // +void VerifyGameContents(const std::string& game_path, QtProgressCallback callback) { + const auto result = ContentManager::VerifyGameContents(*system, game_path, callback); + + switch (result) { + case ContentManager::GameVerificationResult::Success: + QtCommon::Frontend::Information(rootObject, tr("Integrity verification succeeded!"), + tr("The operation completed successfully.")); + break; + case ContentManager::GameVerificationResult::Failed: + QtCommon::Frontend::Critical(rootObject, tr("Integrity verification failed!"), + tr("File contents may be corrupt or missing.")); + break; + case ContentManager::GameVerificationResult::NotImplemented: + QtCommon::Frontend::Warning( + rootObject, + tr("Integrity verification couldn't be performed"), + tr("Firmware installation cancelled, firmware may be in a bad state or corrupted. " + "File contents could not be checked for validity.")); + } +} + + +} diff --git a/src/qt_common/qt_content_util.h b/src/qt_common/qt_content_util.h new file mode 100644 index 0000000000..9a1a4e5bc2 --- /dev/null +++ b/src/qt_common/qt_content_util.h @@ -0,0 +1,48 @@ +#ifndef QT_CONTENT_UTIL_H +#define QT_CONTENT_UTIL_H + +#include +#include "common/common_types.h" +#include "core/core.h" +#include "qt_common/qt_common.h" + +namespace QtCommon::Content { + +// +bool CheckGameFirmware(u64 program_id, Core::System &system, QObject *parent); + +static constexpr std::array FIRMWARE_RESULTS + = {"Successfully installed firmware version %1", + "", + "Unable to locate potential firmware NCA files", + "Failed to delete one or more firmware files.", + "One or more firmware files failed to copy into NAND.", + "Firmware installation cancelled, firmware may be in a bad state or corrupted." + "Restart Eden or re-install firmware."}; + +enum class FirmwareInstallResult { + Success, + NoOp, + NoNCAs, + FailedDelete, + FailedCopy, + FailedCorrupted, +}; + +FirmwareInstallResult InstallFirmware( + const QString &location, + bool recursive, + QtProgressCallback callback, + FileSys::VfsFilesystem *vfs); + +QString UnzipFirmwareToTmp(const QString &location); + +inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResult result) +{ + return FIRMWARE_RESULTS.at(static_cast(result)); +} + +// Content // +void VerifyGameContents(const std::string &game_path, QtProgressCallback callback); +} +#endif // QT_CONTENT_UTIL_H diff --git a/src/qt_common/qt_frontend_util.cpp b/src/qt_common/qt_frontend_util.cpp index bcb662239b..6b96a26a21 100644 --- a/src/qt_common/qt_frontend_util.cpp +++ b/src/qt_common/qt_frontend_util.cpp @@ -4,27 +4,84 @@ #include "qt_frontend_util.h" namespace QtCommon::Frontend { + QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, - QWidget *parent) + QObject *parent) { #ifdef YUZU_QT_WIDGETS - QMessageBox *box = new QMessageBox(icon, title, text, buttons, parent); + QMessageBox *box = new QMessageBox(icon, title, text, buttons, (QWidget *) parent); return static_cast(box->exec()); #endif // TODO(crueter): If Qt Widgets is disabled... // need a way to reference icon/buttons too } -QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons, - QWidget *parent) +QMessageBox::StandardButton Information(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons) { - return ShowMessage(icon, qApp->tr(title), qApp->tr(text), buttons, parent); + return ShowMessage(QMessageBox::Information, title, text, buttons, parent); } +QMessageBox::StandardButton Warning(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Warning, title, text, buttons, parent); +} + +QMessageBox::StandardButton Critical(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Critical, title, text, buttons, parent); +} + +QMessageBox::StandardButton Question(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Question, title, text, buttons, parent); +} + +QMessageBox::StandardButton Information(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Information, parent->tr(title), parent->tr(text), buttons, parent); +} + +QMessageBox::StandardButton Warning(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Warning, parent->tr(title), parent->tr(text), buttons, parent); +} + +QMessageBox::StandardButton Critical(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Critical, parent->tr(title), parent->tr(text), buttons, parent); +} + +QMessageBox::StandardButton Question(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons) +{ + return ShowMessage(QMessageBox::Question, parent->tr(title), parent->tr(text), buttons, parent); +} + + } // namespace QtCommon::Frontend diff --git a/src/qt_common/qt_frontend_util.h b/src/qt_common/qt_frontend_util.h index 8a38c033bf..a91a0db07b 100644 --- a/src/qt_common/qt_frontend_util.h +++ b/src/qt_common/qt_frontend_util.h @@ -17,16 +17,52 @@ namespace QtCommon::Frontend { Q_NAMESPACE +// TODO(crueter) widgets-less impl, choices et al. QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, const QString &title, const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::NoButton, - QWidget *parent = nullptr); + QObject *parent = nullptr); -QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, +QMessageBox::StandardButton Information(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Warning(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Critical(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Question(QObject *parent, + const QString &title, + const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Information(QObject *parent, const char *title, const char *text, - QMessageBox::StandardButtons buttons = QMessageBox::NoButton, - QWidget *parent = nullptr); + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Warning(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Critical(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + +QMessageBox::StandardButton Question(QObject *parent, + const char *title, + const char *text, + QMessageBox::StandardButtons buttons = QMessageBox::Ok); + } // namespace QtCommon::Frontend #endif // QT_FRONTEND_UTIL_H diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp index a870c2ab27..488eb8c971 100644 --- a/src/qt_common/qt_game_util.cpp +++ b/src/qt_common/qt_game_util.cpp @@ -4,40 +4,50 @@ #include "qt_game_util.h" #include "common/fs/fs.h" #include "common/fs/path_util.h" +#include "core/file_sys/savedata_factory.h" +#include "frontend_common/content_manager.h" +#include "qt_common.h" +#include "qt_common/uisettings.h" +#include "qt_frontend_util.h" #include #include #ifdef _WIN32 - #include - #include - #include "common/scope_exit.h" - #include "common/string_util.h" +#include "common/scope_exit.h" +#include "common/string_util.h" +#include +#include #else - #include "fmt/ostream.h" - #include +#include "fmt/ostream.h" +#include #endif -namespace QtCommon { +namespace QtCommon::Game { bool CreateShortcutLink(const std::filesystem::path& shortcut_path, - const std::string& comment, - const std::filesystem::path& icon_path, - const std::filesystem::path& command, - const std::string& arguments, const std::string& categories, - const std::string& keywords, const std::string& name) try { + const std::string& comment, + const std::filesystem::path& icon_path, + const std::filesystem::path& command, + const std::string& arguments, + const std::string& categories, + const std::string& keywords, + const std::string& name) +try { #ifdef _WIN32 // Windows HRESULT hr = CoInitialize(nullptr); if (FAILED(hr)) { LOG_ERROR(Frontend, "CoInitialize failed"); return false; } - SCOPE_EXIT { + SCOPE_EXIT + { CoUninitialize(); }; IShellLinkW* ps1 = nullptr; IPersistFile* persist_file = nullptr; - SCOPE_EXIT { + SCOPE_EXIT + { if (persist_file != nullptr) { persist_file->Release(); } @@ -45,7 +55,10 @@ bool CreateShortcutLink(const std::filesystem::path& shortcut_path, ps1->Release(); } }; - HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW, + HRESULT hres = CoCreateInstance(CLSID_ShellLink, + nullptr, + CLSCTX_INPROC_SERVER, + IID_IShellLinkW, reinterpret_cast(&ps1)); if (FAILED(hres)) { LOG_ERROR(Frontend, "Failed to create IShellLinkW instance"); @@ -115,17 +128,18 @@ bool CreateShortcutLink(const std::filesystem::path& shortcut_path, fmt::print(shortcut_stream, "Keywords={}\n", keywords); } return true; -#else // Unsupported platform +#else // Unsupported platform return false; #endif -} - catch (const std::exception& e) { +} catch (const std::exception& e) { LOG_ERROR(Frontend, "Failed to create shortcut: {}", e.what()); return false; } -bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, - std::filesystem::path& out_icon_path) { +bool MakeShortcutIcoPath(const u64 program_id, + const std::string_view game_file_name, + std::filesystem::path& out_icon_path) +{ // Get path to Yuzu icons directory & icon extension std::string ico_extension = "png"; #if defined(_WIN32) @@ -146,12 +160,13 @@ bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_ return true; } -void OpenEdenFolder(const Common::FS::EdenPath& path) { - QDesktopServices::openUrl(QUrl( - QString::fromStdString(Common::FS::GetEdenPathString(path)))); +void OpenEdenFolder(const Common::FS::EdenPath& path) +{ + QDesktopServices::openUrl(QUrl(QString::fromStdString(Common::FS::GetEdenPathString(path)))); } -void OpenRootDataFolder() { +void OpenRootDataFolder() +{ OpenEdenFolder(Common::FS::EdenPath::EdenDir); } @@ -175,4 +190,211 @@ void OpenLogFolder() OpenEdenFolder(Common::FS::EdenPath::LogDir); } +static QString GetGameListErrorRemoving(QtCommon::Game::InstalledEntryType type) +{ + switch (type) { + case QtCommon::Game::InstalledEntryType::Game: + return tr("Error Removing Contents"); + case QtCommon::Game::InstalledEntryType::Update: + return tr("Error Removing Update"); + case QtCommon::Game::InstalledEntryType::AddOnContent: + return tr("Error Removing DLC"); + default: + return QStringLiteral("Error Removing "); + } } + +// Game Content // +void RemoveBaseContent(u64 program_id, InstalledEntryType type) +{ + const auto res = ContentManager::RemoveBaseContent(system->GetFileSystemController(), + program_id); + if (res) { + QtCommon::Frontend::Information(rootObject, + "Successfully Removed", + "Successfully removed the installed base game."); + } else { + QtCommon::Frontend::Warning( + rootObject, + GetGameListErrorRemoving(type), + tr("The base game is not installed in the NAND and cannot be removed.")); + } +} + +void RemoveUpdateContent(u64 program_id, InstalledEntryType type) +{ + const auto res = ContentManager::RemoveUpdate(system->GetFileSystemController(), program_id); + if (res) { + QtCommon::Frontend::Information(rootObject, + "Successfully Removed", + "Successfully removed the installed update."); + } else { + QtCommon::Frontend::Warning(rootObject, + GetGameListErrorRemoving(type), + tr("There is no update installed for this title.")); + } +} + +void RemoveAddOnContent(u64 program_id, InstalledEntryType type) +{ + const size_t count = ContentManager::RemoveAllDLC(*system, program_id); + if (count == 0) { + QtCommon::Frontend::Warning(rootObject, + GetGameListErrorRemoving(type), + tr("There are no DLCs installed for this title.")); + return; + } + + QtCommon::Frontend::Information(rootObject, + tr("Successfully Removed"), + tr("Successfully removed %1 installed DLC.").arg(count)); +} + +// Global Content // + +void RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target) +{ + const auto target_file_name = [target] { + switch (target) { + case GameListRemoveTarget::GlShaderCache: + return "opengl.bin"; + case GameListRemoveTarget::VkShaderCache: + return "vulkan.bin"; + default: + return ""; + } + }(); + const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); + const auto shader_cache_folder_path = shader_cache_dir / fmt::format("{:016x}", program_id); + const auto target_file = shader_cache_folder_path / target_file_name; + + if (!Common::FS::Exists(target_file)) { + QtCommon::Frontend::Warning(rootObject, + tr("Error Removing Transferable Shader Cache"), + tr("A shader cache for this title does not exist.")); + return; + } + if (Common::FS::RemoveFile(target_file)) { + QtCommon::Frontend::Information(rootObject, + tr("Successfully Removed"), + tr("Successfully removed the transferable shader cache.")); + } else { + QtCommon::Frontend::Warning(rootObject, + tr("Error Removing Transferable Shader Cache"), + tr("Failed to remove the transferable shader cache.")); + } +} + +void RemoveVulkanDriverPipelineCache(u64 program_id) +{ + static constexpr std::string_view target_file_name = "vulkan_pipelines.bin"; + + const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); + const auto shader_cache_folder_path = shader_cache_dir / fmt::format("{:016x}", program_id); + const auto target_file = shader_cache_folder_path / target_file_name; + + if (!Common::FS::Exists(target_file)) { + return; + } + if (!Common::FS::RemoveFile(target_file)) { + QtCommon::Frontend::Warning(rootObject, + tr("Error Removing Vulkan Driver Pipeline Cache"), + tr("Failed to remove the driver pipeline cache.")); + } +} + +void RemoveAllTransferableShaderCaches(u64 program_id) +{ + const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); + const auto program_shader_cache_dir = shader_cache_dir / fmt::format("{:016x}", program_id); + + if (!Common::FS::Exists(program_shader_cache_dir)) { + QtCommon::Frontend::Warning(rootObject, + tr("Error Removing Transferable Shader Caches"), + tr("A shader cache for this title does not exist.")); + return; + } + if (Common::FS::RemoveDirRecursively(program_shader_cache_dir)) { + QtCommon::Frontend::Information(rootObject, + tr("Successfully Removed"), + tr("Successfully removed the transferable shader caches.")); + } else { + QtCommon::Frontend::Warning( + rootObject, + tr("Error Removing Transferable Shader Caches"), + tr("Failed to remove the transferable shader cache directory.")); + } +} + +void RemoveCustomConfiguration(u64 program_id, const std::string& game_path) +{ + const auto file_path = std::filesystem::path(Common::FS::ToU8String(game_path)); + const auto config_file_name = program_id == 0 + ? Common::FS::PathToUTF8String(file_path.filename()) + .append(".ini") + : fmt::format("{:016X}.ini", program_id); + const auto custom_config_file_path = Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir) + / "custom" / config_file_name; + + if (!Common::FS::Exists(custom_config_file_path)) { + QtCommon::Frontend::Warning(rootObject, + tr("Error Removing Custom Configuration"), + tr("A custom configuration for this title does not exist.")); + return; + } + + if (Common::FS::RemoveFile(custom_config_file_path)) { + QtCommon::Frontend::Information(rootObject, + tr("Successfully Removed"), + tr("Successfully removed the custom game configuration.")); + } else { + QtCommon::Frontend::Warning(rootObject, + tr("Error Removing Custom Configuration"), + tr("Failed to remove the custom game configuration.")); + } +} + +void RemoveCacheStorage(u64 program_id, FileSys::VfsFilesystem* vfs) +{ + const auto nand_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir); + auto vfs_nand_dir = vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), + FileSys::OpenMode::Read); + + const auto cache_storage_path + = FileSys::SaveDataFactory::GetFullPath({}, + vfs_nand_dir, + FileSys::SaveDataSpaceId::User, + FileSys::SaveDataType::Cache, + 0 /* program_id */, + {}, + 0); + + const auto path = Common::FS::ConcatPathSafe(nand_dir, cache_storage_path); + + // Not an error if it wasn't cleared. + Common::FS::RemoveDirRecursively(path); +} + +// Metadata // +void ResetMetadata() +{ + const QString title = tr("Reset Metadata Cache"); + + if (!Common::FS::Exists(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) + / "game_list/")) { + QtCommon::Frontend::Warning(rootObject, title, tr("The metadata cache is already empty.")); + } else if (Common::FS::RemoveDirRecursively( + Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "game_list")) { + QtCommon::Frontend::Information(rootObject, + title, + tr("The operation completed successfully.")); + UISettings::values.is_game_list_reload_pending.exchange(true); + } else { + QtCommon::Frontend::Warning( + rootObject, + title, + tr("The metadata cache couldn't be deleted. It might be in use or non-existent.")); + } +} + +} // namespace QtCommon::Game diff --git a/src/qt_common/qt_game_util.h b/src/qt_common/qt_game_util.h index 12916d8a98..9861910833 100644 --- a/src/qt_common/qt_game_util.h +++ b/src/qt_common/qt_game_util.h @@ -4,23 +4,25 @@ #ifndef QT_GAME_UTIL_H #define QT_GAME_UTIL_H +#include #include "common/fs/path_util.h" -#include "frontend_common/content_manager.h" -#include +#include -namespace QtCommon { +namespace QtCommon::Game { -static constexpr std::array GAME_VERIFICATION_RESULTS = { - "The operation completed successfully.", - "File contents may be corrupt or missing..", - "Firmware installation cancelled, firmware may be in a bad state or corrupted. " - "File contents could not be checked for validity." +enum class InstalledEntryType { + Game, + Update, + AddOnContent, }; -inline constexpr const char *GetGameVerificationResultString(ContentManager::GameVerificationResult result) -{ - return GAME_VERIFICATION_RESULTS.at(static_cast(result)); -} +enum class GameListRemoveTarget { + GlShaderCache, + VkShaderCache, + AllShaderCache, + CustomConfiguration, + CacheStorage, +}; bool CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::string& comment, @@ -41,6 +43,20 @@ void OpenNANDFolder(); void OpenSDMCFolder(); void OpenModFolder(); void OpenLogFolder(); + +void RemoveBaseContent(u64 program_id, InstalledEntryType type); +void RemoveUpdateContent(u64 program_id, InstalledEntryType type); +void RemoveAddOnContent(u64 program_id, InstalledEntryType type); + +void RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target); +void RemoveVulkanDriverPipelineCache(u64 program_id); +void RemoveAllTransferableShaderCaches(u64 program_id); +void RemoveCustomConfiguration(u64 program_id, const std::string& game_path); +void RemoveCacheStorage(u64 program_id, FileSys::VfsFilesystem* vfs); + +// Metadata // +void ResetMetadata(); + } #endif // QT_GAME_UTIL_H diff --git a/src/qt_common/qt_meta.cpp b/src/qt_common/qt_meta.cpp new file mode 100644 index 0000000000..c972c0fe45 --- /dev/null +++ b/src/qt_common/qt_meta.cpp @@ -0,0 +1,72 @@ +#include "qt_meta.h" +#include "common/common_types.h" +#include "core/core.h" +#include "core/frontend/applets/cabinet.h" +#include "core/frontend/applets/controller.h" +#include "core/frontend/applets/profile_select.h" +#include "core/frontend/applets/software_keyboard.h" +#include "core/hle/service/am/frontend/applet_web_browser_types.h" + +namespace QtCommon::Meta { + +void RegisterMetaTypes() +{ + // Register integral and floating point types + qRegisterMetaType("u8"); + qRegisterMetaType("u16"); + qRegisterMetaType("u32"); + qRegisterMetaType("u64"); + qRegisterMetaType("u128"); + qRegisterMetaType("s8"); + qRegisterMetaType("s16"); + qRegisterMetaType("s32"); + qRegisterMetaType("s64"); + qRegisterMetaType("f32"); + qRegisterMetaType("f64"); + + // Register string types + qRegisterMetaType("std::string"); + qRegisterMetaType("std::wstring"); + qRegisterMetaType("std::u8string"); + qRegisterMetaType("std::u16string"); + qRegisterMetaType("std::u32string"); + qRegisterMetaType("std::string_view"); + qRegisterMetaType("std::wstring_view"); + qRegisterMetaType("std::u8string_view"); + qRegisterMetaType("std::u16string_view"); + qRegisterMetaType("std::u32string_view"); + + // Register applet types + + // Cabinet Applet + qRegisterMetaType("Core::Frontend::CabinetParameters"); + qRegisterMetaType>( + "std::shared_ptr"); + + // Controller Applet + qRegisterMetaType("Core::Frontend::ControllerParameters"); + + // Profile Select Applet + qRegisterMetaType( + "Core::Frontend::ProfileSelectParameters"); + + // Software Keyboard Applet + qRegisterMetaType( + "Core::Frontend::KeyboardInitializeParameters"); + qRegisterMetaType( + "Core::Frontend::InlineAppearParameters"); + qRegisterMetaType("Core::Frontend::InlineTextParameters"); + qRegisterMetaType("Service::AM::Frontend::SwkbdResult"); + qRegisterMetaType( + "Service::AM::Frontend::SwkbdTextCheckResult"); + qRegisterMetaType( + "Service::AM::Frontend::SwkbdReplyType"); + + // Web Browser Applet + qRegisterMetaType("Service::AM::Frontend::WebExitReason"); + + // Register loader types + qRegisterMetaType("Core::SystemResultStatus"); +} + +} diff --git a/src/qt_common/qt_meta.h b/src/qt_common/qt_meta.h new file mode 100644 index 0000000000..36cafba2bf --- /dev/null +++ b/src/qt_common/qt_meta.h @@ -0,0 +1,12 @@ +#ifndef QT_META_H +#define QT_META_H + +#include + +namespace QtCommon::Meta { + +// +void RegisterMetaTypes(); + +} +#endif // QT_META_H diff --git a/src/qt_common/qt_path_util.cpp b/src/qt_common/qt_path_util.cpp index 6875d01dea..761e6e8405 100644 --- a/src/qt_common/qt_path_util.cpp +++ b/src/qt_common/qt_path_util.cpp @@ -7,17 +7,22 @@ #include #include "common/fs/fs.h" #include "common/fs/path_util.h" +#include "qt_common/qt_frontend_util.h" #include -bool QtCommon::PathUtil::OpenShaderCache(u64 program_id) +namespace QtCommon::Path { + +bool OpenShaderCache(u64 program_id, QObject *parent) { const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); const auto shader_cache_folder_path{shader_cache_dir / fmt::format("{:016x}", program_id)}; if (!Common::FS::CreateDirs(shader_cache_folder_path)) { - return false; + QtCommon::Frontend::ShowMessage(QMessageBox::Warning, "Error Opening Shader Cache", "Failed to create or open shader cache for this title, ensure your app data directory has write permissions.", QMessageBox::Ok, parent); } const auto shader_path_string{Common::FS::PathToUTF8String(shader_cache_folder_path)}; const auto qt_shader_cache_path = QString::fromStdString(shader_path_string); return QDesktopServices::openUrl(QUrl::fromLocalFile(qt_shader_cache_path)); } + +} diff --git a/src/qt_common/qt_path_util.h b/src/qt_common/qt_path_util.h index 7f399c4bb4..855b06caa9 100644 --- a/src/qt_common/qt_path_util.h +++ b/src/qt_common/qt_path_util.h @@ -5,6 +5,8 @@ #define QT_PATH_UTIL_H #include "common/common_types.h" -namespace QtCommon::PathUtil { bool OpenShaderCache(u64 program_id); } +#include + +namespace QtCommon::Path { bool OpenShaderCache(u64 program_id, QObject *parent); } #endif // QT_PATH_UTIL_H diff --git a/src/qt_common/qt_rom_util.cpp b/src/qt_common/qt_rom_util.cpp new file mode 100644 index 0000000000..e707d1e471 --- /dev/null +++ b/src/qt_common/qt_rom_util.cpp @@ -0,0 +1,75 @@ +#include "qt_rom_util.h" + +#include + +namespace QtCommon::ROM { + +bool RomFSRawCopy(size_t total_size, + size_t& read_size, + QtProgressCallback callback, + const FileSys::VirtualDir& src, + const FileSys::VirtualDir& dest, + bool full) +{ + // TODO(crueter) + // if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) + // return false; + // if (dialog.wasCanceled()) + // return false; + + // std::vector buffer(CopyBufferSize); + // auto last_timestamp = std::chrono::steady_clock::now(); + + // const auto QtRawCopy = [&](const FileSys::VirtualFile& src_file, + // const FileSys::VirtualFile& dest_file) { + // if (src_file == nullptr || dest_file == nullptr) { + // return false; + // } + // if (!dest_file->Resize(src_file->GetSize())) { + // return false; + // } + + // for (std::size_t i = 0; i < src_file->GetSize(); i += buffer.size()) { + // if (dialog.wasCanceled()) { + // dest_file->Resize(0); + // return false; + // } + + // using namespace std::literals::chrono_literals; + // const auto new_timestamp = std::chrono::steady_clock::now(); + + // if ((new_timestamp - last_timestamp) > 33ms) { + // last_timestamp = new_timestamp; + // dialog.setValue( + // static_cast(std::min(read_size, total_size) * 100 / total_size)); + // QCoreApplication::processEvents(); + // } + + // const auto read = src_file->Read(buffer.data(), buffer.size(), i); + // dest_file->Write(buffer.data(), read, i); + + // read_size += read; + // } + + // return true; + // }; + + // if (full) { + // for (const auto& file : src->GetFiles()) { + // const auto out = VfsDirectoryCreateFileWrapper(dest, file->GetName()); + // if (!QtRawCopy(file, out)) + // return false; + // } + // } + + // for (const auto& dir : src->GetSubdirectories()) { + // const auto out = dest->CreateSubdirectory(dir->GetName()); + // if (!RomFSRawCopy(total_size, read_size, dialog, dir, out, full)) + // return false; + // } + + // return true; + return true; +} + +} diff --git a/src/qt_common/qt_rom_util.h b/src/qt_common/qt_rom_util.h new file mode 100644 index 0000000000..52ebb1e8d0 --- /dev/null +++ b/src/qt_common/qt_rom_util.h @@ -0,0 +1,17 @@ +#ifndef QT_ROM_UTIL_H +#define QT_ROM_UTIL_H + +#include "qt_common/qt_common.h" +#include + +namespace QtCommon::ROM { + +bool RomFSRawCopy(size_t total_size, + size_t& read_size, + QtProgressCallback callback, + const FileSys::VirtualDir& src, + const FileSys::VirtualDir& dest, + bool full); + +} +#endif // QT_ROM_UTIL_H diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp index d02e6dec2b..d461bd2cc9 100644 --- a/src/yuzu/configuration/configure_filesystem.cpp +++ b/src/yuzu/configuration/configure_filesystem.cpp @@ -11,6 +11,7 @@ #include "common/fs/path_util.h" #include "common/settings.h" #include "qt_common/qt_common.h" +#include "qt_common/qt_game_util.h" #include "qt_common/uisettings.h" #include "ui_configure_filesystem.h" @@ -130,17 +131,7 @@ void ConfigureFilesystem::SetDirectory(DirectoryTarget target, QLineEdit* edit) } void ConfigureFilesystem::ResetMetadata() { - auto result = QtCommon::ResetMetadata(); - const QString resultMessage = tr(QtCommon::GetResetMetadataResultString(result)); - const QString title = tr("Reset Metadata Cache"); - - switch (result) { - case QtCommon::MetadataResult::Failure: - QMessageBox::warning(this, title, resultMessage); - break; - default: - QMessageBox::information(this, title, resultMessage); - } + QtCommon::Game::ResetMetadata(); } void ConfigureFilesystem::UpdateEnabledControls() { diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 0d89dc892e..7c89730651 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later -#include +#include "yuzu/game_list.h" #include #include #include @@ -13,19 +13,20 @@ #include #include #include -#include #include "common/common_types.h" #include "common/logging/log.h" #include "core/core.h" #include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" +#include "qt_common/qt_game_util.h" +#include "qt_common/uisettings.h" #include "yuzu/compatibility_list.h" -#include "yuzu/game_list.h" #include "yuzu/game_list_p.h" #include "yuzu/game_list_worker.h" #include "yuzu/main.h" -#include "qt_common/uisettings.h" #include "yuzu/util/controller_navigation.h" +#include +#include GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist_, QObject* parent) : QObject(parent), gamelist{gamelist_} {} @@ -608,30 +609,30 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri connect(open_transferable_shader_cache, &QAction::triggered, [this, program_id]() { emit OpenTransferableShaderCacheRequested(program_id); }); connect(remove_all_content, &QAction::triggered, [this, program_id]() { - emit RemoveInstalledEntryRequested(program_id, InstalledEntryType::Game); + emit RemoveInstalledEntryRequested(program_id, QtCommon::Game::InstalledEntryType::Game); }); connect(remove_update, &QAction::triggered, [this, program_id]() { - emit RemoveInstalledEntryRequested(program_id, InstalledEntryType::Update); + emit RemoveInstalledEntryRequested(program_id, QtCommon::Game::InstalledEntryType::Update); }); connect(remove_dlc, &QAction::triggered, [this, program_id]() { - emit RemoveInstalledEntryRequested(program_id, InstalledEntryType::AddOnContent); + emit RemoveInstalledEntryRequested(program_id, QtCommon::Game::InstalledEntryType::AddOnContent); }); connect(remove_gl_shader_cache, &QAction::triggered, [this, program_id, path]() { - emit RemoveFileRequested(program_id, GameListRemoveTarget::GlShaderCache, path); + emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::GlShaderCache, path); }); connect(remove_vk_shader_cache, &QAction::triggered, [this, program_id, path]() { - emit RemoveFileRequested(program_id, GameListRemoveTarget::VkShaderCache, path); + emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::VkShaderCache, path); }); connect(remove_shader_cache, &QAction::triggered, [this, program_id, path]() { - emit RemoveFileRequested(program_id, GameListRemoveTarget::AllShaderCache, path); + emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::AllShaderCache, path); }); connect(remove_custom_config, &QAction::triggered, [this, program_id, path]() { - emit RemoveFileRequested(program_id, GameListRemoveTarget::CustomConfiguration, path); + emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::CustomConfiguration, path); }); connect(remove_play_time_data, &QAction::triggered, [this, program_id]() { emit RemovePlayTimeRequested(program_id); }); connect(remove_cache_storage, &QAction::triggered, [this, program_id, path] { - emit RemoveFileRequested(program_id, GameListRemoveTarget::CacheStorage, path); + emit RemoveFileRequested(program_id, QtCommon::Game::GameListRemoveTarget::CacheStorage, path); }); connect(dump_romfs, &QAction::triggered, [this, program_id, path]() { emit DumpRomFSRequested(program_id, path, DumpRomFSTarget::Normal); diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 328432138c..367d047c40 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h @@ -21,6 +21,7 @@ #include "common/common_types.h" #include "core/core.h" #include "qt_common/uisettings.h" +#include "qt_common/qt_game_util.h" #include "yuzu/compatibility_list.h" #include "yuzu/play_time_manager.h" @@ -46,14 +47,6 @@ enum class GameListOpenTarget { ModData, }; -enum class GameListRemoveTarget { - GlShaderCache, - VkShaderCache, - AllShaderCache, - CustomConfiguration, - CacheStorage, -}; - enum class DumpRomFSTarget { Normal, SDMC, @@ -64,12 +57,6 @@ enum class GameListShortcutTarget { Applications, }; -enum class InstalledEntryType { - Game, - Update, - AddOnContent, -}; - class GameList : public QWidget { Q_OBJECT @@ -118,8 +105,8 @@ signals: void OpenFolderRequested(u64 program_id, GameListOpenTarget target, const std::string& game_path); void OpenTransferableShaderCacheRequested(u64 program_id); - void RemoveInstalledEntryRequested(u64 program_id, InstalledEntryType type); - void RemoveFileRequested(u64 program_id, GameListRemoveTarget target, + void RemoveInstalledEntryRequested(u64 program_id, QtCommon::Game::InstalledEntryType type); + void RemoveFileRequested(u64 program_id, QtCommon::Game::GameListRemoveTarget target, const std::string& game_path); void RemovePlayTimeRequested(u64 program_id); void DumpRomFSRequested(u64 program_id, const std::string& game_path, DumpRomFSTarget target); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 19110781bf..7db448af01 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -14,6 +14,8 @@ #include "qt_common/qt_common.h" #include "qt_common/qt_game_util.h" #include "qt_common/qt_path_util.h" +#include "qt_common/qt_meta.h" +#include "qt_common/qt_content_util.h" #ifdef __APPLE__ #include // for chdir @@ -299,14 +301,6 @@ enum class CalloutFlag : uint32_t { DRDDeprecation = 0x2, }; -/** - * Some games perform worse or straight-up don't work with updates, - * so this tracks which games are bad in this regard. - */ -constexpr std::array bad_update_games{ - 0x0100F2C0115B6000 // Tears of the Kingdom -}; - const int GMainWindow::max_recent_files_item; static void RemoveCachedContents() { @@ -389,6 +383,7 @@ static void OverrideWindowsFont() { #endif #ifndef _WIN32 +// TODO(crueter): carboxyl does this, is it needed in qml? inline static bool isDarkMode() { #if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) const auto scheme = QGuiApplication::styleHints()->colorScheme(); @@ -407,6 +402,9 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) input_subsystem{std::make_shared()}, user_data_migrator{this}, vfs{std::make_shared()}, provider{std::make_unique()} { + QtCommon::SetSystem(system.get()); + QtCommon::SetRootObject(this); + Common::FS::CreateEdenPaths(); this->config = std::make_unique(); @@ -463,7 +461,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) Network::Init(); - RegisterMetaTypes(); + QtCommon::Meta::RegisterMetaTypes(); InitializeWidgets(); InitializeDebugWidgets(); @@ -734,65 +732,6 @@ GMainWindow::~GMainWindow() { #endif } -void GMainWindow::RegisterMetaTypes() { - // Register integral and floating point types - qRegisterMetaType("u8"); - qRegisterMetaType("u16"); - qRegisterMetaType("u32"); - qRegisterMetaType("u64"); - qRegisterMetaType("u128"); - qRegisterMetaType("s8"); - qRegisterMetaType("s16"); - qRegisterMetaType("s32"); - qRegisterMetaType("s64"); - qRegisterMetaType("f32"); - qRegisterMetaType("f64"); - - // Register string types - qRegisterMetaType("std::string"); - qRegisterMetaType("std::wstring"); - qRegisterMetaType("std::u8string"); - qRegisterMetaType("std::u16string"); - qRegisterMetaType("std::u32string"); - qRegisterMetaType("std::string_view"); - qRegisterMetaType("std::wstring_view"); - qRegisterMetaType("std::u8string_view"); - qRegisterMetaType("std::u16string_view"); - qRegisterMetaType("std::u32string_view"); - - // Register applet types - - // Cabinet Applet - qRegisterMetaType("Core::Frontend::CabinetParameters"); - qRegisterMetaType>( - "std::shared_ptr"); - - // Controller Applet - qRegisterMetaType("Core::Frontend::ControllerParameters"); - - // Profile Select Applet - qRegisterMetaType( - "Core::Frontend::ProfileSelectParameters"); - - // Software Keyboard Applet - qRegisterMetaType( - "Core::Frontend::KeyboardInitializeParameters"); - qRegisterMetaType( - "Core::Frontend::InlineAppearParameters"); - qRegisterMetaType("Core::Frontend::InlineTextParameters"); - qRegisterMetaType("Service::AM::Frontend::SwkbdResult"); - qRegisterMetaType( - "Service::AM::Frontend::SwkbdTextCheckResult"); - qRegisterMetaType( - "Service::AM::Frontend::SwkbdReplyType"); - - // Web Browser Applet - qRegisterMetaType("Service::AM::Frontend::WebExitReason"); - - // Register loader types - qRegisterMetaType("Core::SystemResultStatus"); -} - void GMainWindow::AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters, std::shared_ptr nfp_device) { cabinet_applet = @@ -1634,8 +1573,9 @@ void GMainWindow::ConnectWidgetEvents() { connect(game_list, &GameList::GameChosen, this, &GMainWindow::OnGameListLoadFile); connect(game_list, &GameList::OpenDirectory, this, &GMainWindow::OnGameListOpenDirectory); connect(game_list, &GameList::OpenFolderRequested, this, &GMainWindow::OnGameListOpenFolder); - connect(game_list, &GameList::OpenTransferableShaderCacheRequested, this, - &GMainWindow::OnTransferableShaderCacheOpenFile); + connect(game_list, &GameList::OpenTransferableShaderCacheRequested, this, [this](u64 program_id) { + QtCommon::Path::OpenShaderCache(program_id, this); + }); connect(game_list, &GameList::RemoveInstalledEntryRequested, this, &GMainWindow::OnGameListRemoveInstalledEntry); connect(game_list, &GameList::RemoveFileRequested, this, &GMainWindow::OnGameListRemoveFile); @@ -1970,74 +1910,10 @@ bool GMainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPa nullptr, // Net Connect }); - /** Game Updates check */ + /** firmware check */ - // yuzu's configuration doesn't actually support lists so this is a bit hacky - QSettings settings; - QStringList currentIgnored = settings.value("ignoredBadUpdates", {}).toStringList(); - - if (std::find(bad_update_games.begin(), bad_update_games.end(), params.program_id) != - bad_update_games.end() && - !currentIgnored.contains(QString::number(params.program_id))) { - QMessageBox* msg = new QMessageBox(this); - msg->setWindowTitle(tr("Game Updates Warning")); - msg->setIcon(QMessageBox::Warning); - msg->setText( - tr("The game you are trying to launch is known to have performance or booting " - "issues when updates are applied. Please try increasing the memory layout to " - "6GB or 8GB if any issues occur.

Press \"OK\" to continue launching, or " - "\"Cancel\" to cancel the launch.")); - - msg->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); - - QCheckBox* dontShowAgain = new QCheckBox(msg); - dontShowAgain->setText(tr("Don't show again for this game")); - msg->setCheckBox(dontShowAgain); - - int result = msg->exec(); - - // wtf - QMessageBox::ButtonRole role = - msg->buttonRole(msg->button((QMessageBox::StandardButton)result)); - - switch (role) { - case QMessageBox::RejectRole: - return false; - case QMessageBox::AcceptRole: - default: - if (dontShowAgain->isChecked()) { - currentIgnored << QString::number(params.program_id); - settings.setValue("ignoredBadUpdates", currentIgnored); - settings.sync(); - } - break; - } - } - - if (FirmwareManager::GameRequiresFirmware(params.program_id) && - !FirmwareManager::CheckFirmwarePresence(*system)) { - QMessageBox* msg = new QMessageBox(this); - msg->setWindowTitle(tr("Game Requires Firmware")); - msg->setIcon(QMessageBox::Warning); - msg->setText( - tr("The game you are trying to launch requires firmware to boot or to get past the " - "opening menu. Please " - "dump and install firmware, or press \"OK\" to launch anyways.")); - - msg->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); - - int exec_result = msg->exec(); - - QMessageBox::ButtonRole role = - msg->buttonRole(msg->button((QMessageBox::StandardButton)exec_result)); - - switch (role) { - case QMessageBox::RejectRole: - return false; - case QMessageBox::AcceptRole: - default: - break; - } + if (!QtCommon::Content::CheckGameFirmware(params.program_id, *system, this)) { + return false; } if (!OnCheckNcaVerification()) { @@ -2459,6 +2335,7 @@ void GMainWindow::ShutdownGame() { return; } + // TODO(crueter): make this common as well (frontend_common?) play_time_manager->Stop(); OnShutdownBegin(); OnEmulationStopTimeExpired(); @@ -2503,6 +2380,7 @@ void GMainWindow::OnGameListLoadFile(QString game_path, u64 program_id) { BootGame(game_path, params); } +// TODO(crueter): Common profile selector void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target, const std::string& game_path) { std::filesystem::path path; @@ -2611,13 +2489,6 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target QDesktopServices::openUrl(QUrl::fromLocalFile(qpath)); } -// TODO(crueter): Transfer ts to showmessage -void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) { - if (!QtCommon::PathUtil::OpenShaderCache(program_id)) { - QMessageBox::warning(this, tr("Error Opening Shader Cache"), tr("Failed to create or open shader cache for this title, ensure your app data directory has write permissions.")); - } -} - static bool RomFSRawCopy(size_t total_size, size_t& read_size, QProgressDialog& dialog, const FileSys::VirtualDir& src, const FileSys::VirtualDir& dest, bool full) { @@ -2683,26 +2554,14 @@ static bool RomFSRawCopy(size_t total_size, size_t& read_size, QProgressDialog& // TODO(crueter): All this can be transfered to qt_common // Aldoe I need to decide re: message boxes for QML // translations_common? strings_common? qt_strings? who knows -QString GMainWindow::GetGameListErrorRemoving(InstalledEntryType type) const { - switch (type) { - case InstalledEntryType::Game: - return tr("Error Removing Contents"); - case InstalledEntryType::Update: - return tr("Error Removing Update"); - case InstalledEntryType::AddOnContent: - return tr("Error Removing DLC"); - default: - return QStringLiteral("Error Removing "); - } -} -void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryType type) { +void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, QtCommon::Game::InstalledEntryType type) { const QString entry_question = [type] { switch (type) { - case InstalledEntryType::Game: + case QtCommon::Game::InstalledEntryType::Game: return tr("Remove Installed Game Contents?"); - case InstalledEntryType::Update: + case QtCommon::Game::InstalledEntryType::Update: return tr("Remove Installed Game Update?"); - case InstalledEntryType::AddOnContent: + case QtCommon::Game::InstalledEntryType::AddOnContent: return tr("Remove Installed Game DLC?"); default: return QStringLiteral("Remove Installed Game ?"); @@ -2714,18 +2573,19 @@ void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryT return; } + // TODO(crueter): move this to QtCommon (populate async?) switch (type) { - case InstalledEntryType::Game: - RemoveBaseContent(program_id, type); + case QtCommon::Game::InstalledEntryType::Game: + QtCommon::Game::RemoveBaseContent(program_id, type); [[fallthrough]]; - case InstalledEntryType::Update: - RemoveUpdateContent(program_id, type); - if (type != InstalledEntryType::Game) { + case QtCommon::Game::InstalledEntryType::Update: + QtCommon::Game::RemoveUpdateContent(program_id, type); + if (type != QtCommon::Game::InstalledEntryType::Game) { break; } [[fallthrough]]; - case InstalledEntryType::AddOnContent: - RemoveAddOnContent(program_id, type); + case QtCommon::Game::InstalledEntryType::AddOnContent: + QtCommon::Game::RemoveAddOnContent(program_id, type); break; } Common::FS::RemoveDirRecursively(Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / @@ -2733,55 +2593,19 @@ void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryT game_list->PopulateAsync(UISettings::values.game_dirs); } -void GMainWindow::RemoveBaseContent(u64 program_id, InstalledEntryType type) { - const auto res = - ContentManager::RemoveBaseContent(system->GetFileSystemController(), program_id); - if (res) { - QMessageBox::information(this, tr("Successfully Removed"), - tr("Successfully removed the installed base game.")); - } else { - QMessageBox::warning( - this, GetGameListErrorRemoving(type), - tr("The base game is not installed in the NAND and cannot be removed.")); - } -} - -void GMainWindow::RemoveUpdateContent(u64 program_id, InstalledEntryType type) { - const auto res = ContentManager::RemoveUpdate(system->GetFileSystemController(), program_id); - if (res) { - QMessageBox::information(this, tr("Successfully Removed"), - tr("Successfully removed the installed update.")); - } else { - QMessageBox::warning(this, GetGameListErrorRemoving(type), - tr("There is no update installed for this title.")); - } -} - -void GMainWindow::RemoveAddOnContent(u64 program_id, InstalledEntryType type) { - const size_t count = ContentManager::RemoveAllDLC(*system, program_id); - if (count == 0) { - QMessageBox::warning(this, GetGameListErrorRemoving(type), - tr("There are no DLC installed for this title.")); - return; - } - - QMessageBox::information(this, tr("Successfully Removed"), - tr("Successfully removed %1 installed DLC.").arg(count)); -} - -void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target, +void GMainWindow::OnGameListRemoveFile(u64 program_id, QtCommon::Game::GameListRemoveTarget target, const std::string& game_path) { const QString question = [target] { switch (target) { - case GameListRemoveTarget::GlShaderCache: + case QtCommon::Game::GameListRemoveTarget::GlShaderCache: return tr("Delete OpenGL Transferable Shader Cache?"); - case GameListRemoveTarget::VkShaderCache: + case QtCommon::Game::GameListRemoveTarget::VkShaderCache: return tr("Delete Vulkan Transferable Shader Cache?"); - case GameListRemoveTarget::AllShaderCache: + case QtCommon::Game::GameListRemoveTarget::AllShaderCache: return tr("Delete All Transferable Shader Caches?"); - case GameListRemoveTarget::CustomConfiguration: + case QtCommon::Game::GameListRemoveTarget::CustomConfiguration: return tr("Remove Custom Game Configuration?"); - case GameListRemoveTarget::CacheStorage: + case QtCommon::Game::GameListRemoveTarget::CacheStorage: return tr("Remove Cache Storage?"); default: return QString{}; @@ -2794,20 +2618,20 @@ void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget targ } switch (target) { - case GameListRemoveTarget::VkShaderCache: - RemoveVulkanDriverPipelineCache(program_id); + case QtCommon::Game::GameListRemoveTarget::VkShaderCache: + QtCommon::Game::RemoveVulkanDriverPipelineCache(program_id); [[fallthrough]]; - case GameListRemoveTarget::GlShaderCache: - RemoveTransferableShaderCache(program_id, target); + case QtCommon::Game::GameListRemoveTarget::GlShaderCache: + QtCommon::Game::RemoveTransferableShaderCache(program_id, target); break; - case GameListRemoveTarget::AllShaderCache: - RemoveAllTransferableShaderCaches(program_id); + case QtCommon::Game::GameListRemoveTarget::AllShaderCache: + QtCommon::Game::RemoveAllTransferableShaderCaches(program_id); break; - case GameListRemoveTarget::CustomConfiguration: - RemoveCustomConfiguration(program_id, game_path); + case QtCommon::Game::GameListRemoveTarget::CustomConfiguration: + QtCommon::Game::RemoveCustomConfiguration(program_id, game_path); break; - case GameListRemoveTarget::CacheStorage: - RemoveCacheStorage(program_id); + case QtCommon::Game::GameListRemoveTarget::CacheStorage: + QtCommon::Game::RemoveCacheStorage(program_id, vfs.get()); break; } } @@ -2823,107 +2647,6 @@ void GMainWindow::OnGameListRemovePlayTimeData(u64 program_id) { game_list->PopulateAsync(UISettings::values.game_dirs); } -void GMainWindow::RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target) { - const auto target_file_name = [target] { - switch (target) { - case GameListRemoveTarget::GlShaderCache: - return "opengl.bin"; - case GameListRemoveTarget::VkShaderCache: - return "vulkan.bin"; - default: - return ""; - } - }(); - const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); - const auto shader_cache_folder_path = shader_cache_dir / fmt::format("{:016x}", program_id); - const auto target_file = shader_cache_folder_path / target_file_name; - - if (!Common::FS::Exists(target_file)) { - QMessageBox::warning(this, tr("Error Removing Transferable Shader Cache"), - tr("A shader cache for this title does not exist.")); - return; - } - if (Common::FS::RemoveFile(target_file)) { - QMessageBox::information(this, tr("Successfully Removed"), - tr("Successfully removed the transferable shader cache.")); - } else { - QMessageBox::warning(this, tr("Error Removing Transferable Shader Cache"), - tr("Failed to remove the transferable shader cache.")); - } -} - -void GMainWindow::RemoveVulkanDriverPipelineCache(u64 program_id) { - static constexpr std::string_view target_file_name = "vulkan_pipelines.bin"; - - const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); - const auto shader_cache_folder_path = shader_cache_dir / fmt::format("{:016x}", program_id); - const auto target_file = shader_cache_folder_path / target_file_name; - - if (!Common::FS::Exists(target_file)) { - return; - } - if (!Common::FS::RemoveFile(target_file)) { - QMessageBox::warning(this, tr("Error Removing Vulkan Driver Pipeline Cache"), - tr("Failed to remove the driver pipeline cache.")); - } -} - -void GMainWindow::RemoveAllTransferableShaderCaches(u64 program_id) { - const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); - const auto program_shader_cache_dir = shader_cache_dir / fmt::format("{:016x}", program_id); - - if (!Common::FS::Exists(program_shader_cache_dir)) { - QMessageBox::warning(this, tr("Error Removing Transferable Shader Caches"), - tr("A shader cache for this title does not exist.")); - return; - } - if (Common::FS::RemoveDirRecursively(program_shader_cache_dir)) { - QMessageBox::information(this, tr("Successfully Removed"), - tr("Successfully removed the transferable shader caches.")); - } else { - QMessageBox::warning(this, tr("Error Removing Transferable Shader Caches"), - tr("Failed to remove the transferable shader cache directory.")); - } -} - -void GMainWindow::RemoveCustomConfiguration(u64 program_id, const std::string& game_path) { - const auto file_path = std::filesystem::path(Common::FS::ToU8String(game_path)); - const auto config_file_name = - program_id == 0 ? Common::FS::PathToUTF8String(file_path.filename()).append(".ini") - : fmt::format("{:016X}.ini", program_id); - const auto custom_config_file_path = - Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir) / "custom" / config_file_name; - - if (!Common::FS::Exists(custom_config_file_path)) { - QMessageBox::warning(this, tr("Error Removing Custom Configuration"), - tr("A custom configuration for this title does not exist.")); - return; - } - - if (Common::FS::RemoveFile(custom_config_file_path)) { - QMessageBox::information(this, tr("Successfully Removed"), - tr("Successfully removed the custom game configuration.")); - } else { - QMessageBox::warning(this, tr("Error Removing Custom Configuration"), - tr("Failed to remove the custom game configuration.")); - } -} - -void GMainWindow::RemoveCacheStorage(u64 program_id) { - const auto nand_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir); - auto vfs_nand_dir = - vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read); - - const auto cache_storage_path = FileSys::SaveDataFactory::GetFullPath( - {}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Cache, - 0 /* program_id */, {}, 0); - - const auto path = Common::FS::ConcatPathSafe(nand_dir, cache_storage_path); - - // Not an error if it wasn't cleared. - Common::FS::RemoveDirRecursively(path); -} - void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path, DumpRomFSTarget target) { const auto failed = [this] { @@ -3052,22 +2775,7 @@ void GMainWindow::OnGameListVerifyIntegrity(const std::string& game_path) { return progress.wasCanceled(); }; - const auto result = ContentManager::VerifyGameContents(*system, game_path, QtProgressCallback); - const QString resultString = tr(QtCommon::GetGameVerificationResultString(result)); - progress.close(); - switch (result) { - case ContentManager::GameVerificationResult::Success: - QMessageBox::information(this, tr("Integrity verification succeeded!"), - resultString); - break; - case ContentManager::GameVerificationResult::Failed: - QMessageBox::critical(this, tr("Integrity verification failed!"), - resultString); - break; - case ContentManager::GameVerificationResult::NotImplemented: - QMessageBox::warning(this, tr("Integrity verification couldn't be performed"), - resultString); - } + QtCommon::Content::VerifyGameContents(game_path, QtProgressCallback); } void GMainWindow::OnGameListCopyTID(u64 program_id) { @@ -4103,6 +3811,7 @@ void GMainWindow::OnLoadAmiibo() { LoadAmiibo(filename); } +// TODO(crueter): does this need to be ported to QML? bool GMainWindow::question(QWidget* parent, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { @@ -4154,27 +3863,27 @@ void GMainWindow::LoadAmiibo(const QString& filename) { } void GMainWindow::OnOpenRootDataFolder() { - QtCommon::OpenRootDataFolder(); + QtCommon::Game::OpenRootDataFolder(); } void GMainWindow::OnOpenNANDFolder() { - QtCommon::OpenNANDFolder(); + QtCommon::Game::OpenNANDFolder(); } void GMainWindow::OnOpenSDMCFolder() { - QtCommon::OpenSDMCFolder(); + QtCommon::Game::OpenSDMCFolder(); } void GMainWindow::OnOpenModFolder() { - QtCommon::OpenModFolder(); + QtCommon::Game::OpenModFolder(); } void GMainWindow::OnOpenLogFolder() { - QtCommon::OpenLogFolder(); + QtCommon::Game::OpenLogFolder(); } void GMainWindow::OnVerifyInstalledContents() { @@ -4221,11 +3930,11 @@ void GMainWindow::InstallFirmware(const QString& location, bool recursive) { return progress.wasCanceled(); }; - auto result = QtCommon::InstallFirmware(location, recursive, QtProgressCallback, system.get(), vfs.get(), this); + auto result = QtCommon::Content::InstallFirmware(location, recursive, QtProgressCallback, vfs.get()); progress.close(); - if (result != QtCommon::FirmwareInstallResult::Success) return; + if (result != QtCommon::Content::FirmwareInstallResult::Success) return; auto VerifyFirmwareCallback = [&](size_t total_size, size_t processed_size) { progress.setValue(90 + static_cast((processed_size * 10) / total_size)); @@ -4292,7 +4001,7 @@ void GMainWindow::OnInstallFirmwareFromZIP() { return; } - const QString qCacheDir = QtCommon::UnzipFirmwareToTmp(firmware_zip_location); + const QString qCacheDir = QtCommon::Content::UnzipFirmwareToTmp(firmware_zip_location); // In this case, it has to be done recursively, since sometimes people // will pack it into a subdirectory after dumping @@ -4370,7 +4079,7 @@ void GMainWindow::OnToggleStatusBar() { void GMainWindow::OnGameListRefresh() { // Resets metadata cache and reloads - QtCommon::ResetMetadata(); + QtCommon::Game::ResetMetadata(); game_list->RefreshGameDirectory(); SetFirmwareVersion(); } @@ -4640,7 +4349,7 @@ void GMainWindow::CreateShortcut(const std::string &game_path, const u64 program QImage icon_data = QImage::fromData(icon_image_file.data(), static_cast(icon_image_file.size())); std::filesystem::path out_icon_path; - if (QtCommon::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) { + if (QtCommon::Game::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) { if (!SaveIconToFile(out_icon_path, icon_data)) { LOG_ERROR(Frontend, "Could not write icon to file"); } @@ -4674,7 +4383,7 @@ void GMainWindow::CreateShortcut(const std::string &game_path, const u64 program const std::string categories = "Game;Emulator;Qt;"; const std::string keywords = "Switch;Nintendo;"; - if (QtCommon::CreateShortcutLink(shortcut_path, comment, out_icon_path, command, + if (QtCommon::Game::CreateShortcutLink(shortcut_path, comment, out_icon_path, command, arguments, categories, keywords, game_title)) { GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS, qgame_title); diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 8d00fef4f8..f523561628 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -17,9 +17,10 @@ #include #include "common/common_types.h" -#include "qt_common/qt_config.h" #include "frontend_common/content_manager.h" #include "input_common/drivers/tas_input.h" +#include "qt_common/qt_config.h" +#include "qt_common/qt_game_util.h" #include "user_data_migration.h" #include "yuzu/compatibility_list.h" #include "yuzu/hotkeys.h" @@ -53,10 +54,8 @@ class QSlider; class QHBoxLayout; class WaitTreeWidget; enum class GameListOpenTarget; -enum class GameListRemoveTarget; enum class GameListShortcutTarget; enum class DumpRomFSTarget; -enum class InstalledEntryType; class GameListPlaceholder; class QtAmiiboSettingsDialog; @@ -258,8 +257,6 @@ private: void LinkActionShortcut(QAction* action, const QString& action_name, const bool tas_allowed = false); - void RegisterMetaTypes(); - void InitializeWidgets(); void InitializeDebugWidgets(); void InitializeRecentFileMenuActions(); @@ -353,9 +350,8 @@ private slots: void OnGameListLoadFile(QString game_path, u64 program_id); void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target, const std::string& game_path); - void OnTransferableShaderCacheOpenFile(u64 program_id); - void OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryType type); - void OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target, + void OnGameListRemoveInstalledEntry(u64 program_id, QtCommon::Game::InstalledEntryType type); + void OnGameListRemoveFile(u64 program_id, QtCommon::Game::GameListRemoveTarget target, const std::string& game_path); void OnGameListRemovePlayTimeData(u64 program_id); void OnGameListDumpRomFS(u64 program_id, const std::string& game_path, DumpRomFSTarget target); @@ -436,16 +432,7 @@ private slots: #endif private: - QString GetGameListErrorRemoving(InstalledEntryType type) const; - void RemoveBaseContent(u64 program_id, InstalledEntryType type); - void RemoveUpdateContent(u64 program_id, InstalledEntryType type); - void RemoveAddOnContent(u64 program_id, InstalledEntryType type); - void RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target); - void RemoveVulkanDriverPipelineCache(u64 program_id); - void RemoveAllTransferableShaderCaches(u64 program_id); - void RemoveCustomConfiguration(u64 program_id, const std::string& game_path); void RemovePlayTimeData(u64 program_id); - void RemoveCacheStorage(u64 program_id); bool SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id, u64* selected_title_id, u8* selected_content_record_type); ContentManager::InstallResult InstallNCA(const QString& filename); From c6a2d2acad2f781747fbd2e3d57dd53504917ad5 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 30 Aug 2025 19:50:05 -0400 Subject: [PATCH 13/34] Fix license headers Signed-off-by: crueter --- ffmpeg.patch | 40 ------------------------------- src/qt_common/qt_content_util.cpp | 3 +++ src/qt_common/qt_content_util.h | 3 +++ src/qt_common/qt_meta.cpp | 3 +++ src/qt_common/qt_meta.h | 3 +++ src/qt_common/qt_rom_util.cpp | 3 +++ src/qt_common/qt_rom_util.h | 3 +++ 7 files changed, 18 insertions(+), 40 deletions(-) delete mode 100644 ffmpeg.patch diff --git a/ffmpeg.patch b/ffmpeg.patch deleted file mode 100644 index 58fa9dff61..0000000000 --- a/ffmpeg.patch +++ /dev/null @@ -1,40 +0,0 @@ -diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt -index 54c852f831..ff35c8dc2c 100644 ---- a/externals/ffmpeg/CMakeLists.txt -+++ b/externals/ffmpeg/CMakeLists.txt -@@ -63,20 +63,22 @@ if (NOT WIN32 AND NOT ANDROID) - set(FFmpeg_HWACCEL_INCLUDE_DIRS) - set(FFmpeg_HWACCEL_LDFLAGS) - -- # In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so -- if(PLATFORM_SUN) -- list(APPEND FFmpeg_HWACCEL_LIBRARIES -- X11 -- "/usr/lib/xorg/amd64/libdrm.so") -- else() -- pkg_check_modules(LIBDRM libdrm REQUIRED) -- list(APPEND FFmpeg_HWACCEL_LIBRARIES -- ${LIBDRM_LIBRARIES}) -- list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS -- ${LIBDRM_INCLUDE_DIRS}) -+ if (NOT APPLE) -+ # In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so -+ if(PLATFORM_SUN) -+ list(APPEND FFmpeg_HWACCEL_LIBRARIES -+ X11 -+ "/usr/lib/xorg/amd64/libdrm.so") -+ else() -+ pkg_check_modules(LIBDRM libdrm REQUIRED) -+ list(APPEND FFmpeg_HWACCEL_LIBRARIES -+ ${LIBDRM_LIBRARIES}) -+ list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS -+ ${LIBDRM_INCLUDE_DIRS}) -+ endif() -+ list(APPEND FFmpeg_HWACCEL_FLAGS -+ --enable-libdrm) - endif() -- list(APPEND FFmpeg_HWACCEL_FLAGS -- --enable-libdrm) - - if(LIBVA_FOUND) - find_package(X11 REQUIRED) diff --git a/src/qt_common/qt_content_util.cpp b/src/qt_common/qt_content_util.cpp index 81ec7c9cea..9c3ae6e115 100644 --- a/src/qt_common/qt_content_util.cpp +++ b/src/qt_common/qt_content_util.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #include "qt_content_util.h" #include "common/fs/fs.h" #include "frontend_common/content_manager.h" diff --git a/src/qt_common/qt_content_util.h b/src/qt_common/qt_content_util.h index 9a1a4e5bc2..b7073d2d35 100644 --- a/src/qt_common/qt_content_util.h +++ b/src/qt_common/qt_content_util.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #ifndef QT_CONTENT_UTIL_H #define QT_CONTENT_UTIL_H diff --git a/src/qt_common/qt_meta.cpp b/src/qt_common/qt_meta.cpp index c972c0fe45..67ae659771 100644 --- a/src/qt_common/qt_meta.cpp +++ b/src/qt_common/qt_meta.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #include "qt_meta.h" #include "common/common_types.h" #include "core/core.h" diff --git a/src/qt_common/qt_meta.h b/src/qt_common/qt_meta.h index 36cafba2bf..c0a37db983 100644 --- a/src/qt_common/qt_meta.h +++ b/src/qt_common/qt_meta.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #ifndef QT_META_H #define QT_META_H diff --git a/src/qt_common/qt_rom_util.cpp b/src/qt_common/qt_rom_util.cpp index e707d1e471..08ccb05a97 100644 --- a/src/qt_common/qt_rom_util.cpp +++ b/src/qt_common/qt_rom_util.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #include "qt_rom_util.h" #include diff --git a/src/qt_common/qt_rom_util.h b/src/qt_common/qt_rom_util.h index 52ebb1e8d0..f76b09753d 100644 --- a/src/qt_common/qt_rom_util.h +++ b/src/qt_common/qt_rom_util.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #ifndef QT_ROM_UTIL_H #define QT_ROM_UTIL_H From fd7711aa5d28e64cf27713b335506febacf6a8d9 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 30 Aug 2025 19:54:46 -0400 Subject: [PATCH 14/34] cleanup Signed-off-by: crueter --- src/qt_common/CMakeLists.txt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index da6c9b0481..add8e59311 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -1,7 +1,6 @@ # SPDX-FileCopyrightText: 2023 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later -find_package(Qt6 REQUIRED COMPONENTS Core) find_package(Qt6 REQUIRED COMPONENTS Core) add_library(qt_common STATIC @@ -25,9 +24,13 @@ add_library(qt_common STATIC ) create_target_directory_groups(qt_common) -target_link_libraries(qt_common PUBLIC core Qt6::Widgets SimpleIni::SimpleIni QuaZip::QuaZip) -target_link_libraries(qt_common PRIVATE Qt6::Core) -target_link_libraries(qt_common PRIVATE Qt6::Core) + +# TODO(crueter) +if (ENABLE_QT) + target_link_libraries(qt_common PRIVATE Qt6::Widgets) +endif() + +target_link_libraries(qt_common PUBLIC core Qt6::Core SimpleIni::SimpleIni QuaZip::QuaZip) if (NOT WIN32) target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) From c45d9a71e80af4a13ad5f1105df7eaa6c649f4f7 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 30 Aug 2025 20:08:30 -0400 Subject: [PATCH 15/34] fix win Signed-off-by: crueter --- src/qt_common/qt_content_util.cpp | 5 ++--- src/qt_common/qt_content_util.h | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/qt_common/qt_content_util.cpp b/src/qt_common/qt_content_util.cpp index 9c3ae6e115..5ad361a527 100644 --- a/src/qt_common/qt_content_util.cpp +++ b/src/qt_common/qt_content_util.cpp @@ -5,17 +5,16 @@ #include "common/fs/fs.h" #include "frontend_common/content_manager.h" #include "frontend_common/firmware_manager.h" -#include "qt_common/qt_game_util.h" #include "qt_frontend_util.h" #include namespace QtCommon::Content { -bool CheckGameFirmware(u64 program_id, Core::System &system, QObject *parent) +bool CheckGameFirmware(u64 program_id, QObject *parent) { if (FirmwareManager::GameRequiresFirmware(program_id) - && !FirmwareManager::CheckFirmwarePresence(system)) { + && !FirmwareManager::CheckFirmwarePresence(*system)) { auto result = QtCommon::Frontend::ShowMessage( QMessageBox::Warning, "Game Requires Firmware", diff --git a/src/qt_common/qt_content_util.h b/src/qt_common/qt_content_util.h index b7073d2d35..529b887146 100644 --- a/src/qt_common/qt_content_util.h +++ b/src/qt_common/qt_content_util.h @@ -12,7 +12,7 @@ namespace QtCommon::Content { // -bool CheckGameFirmware(u64 program_id, Core::System &system, QObject *parent); +bool CheckGameFirmware(u64 program_id, QObject *parent); static constexpr std::array FIRMWARE_RESULTS = {"Successfully installed firmware version %1", From 4356e80e50ed3bf2b8ba77de8d2d72ffad457a5f Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 30 Aug 2025 20:30:19 -0400 Subject: [PATCH 16/34] fix Signed-off-by: crueter --- src/yuzu/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 7db448af01..30ea8702be 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1912,7 +1912,7 @@ bool GMainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPa /** firmware check */ - if (!QtCommon::Content::CheckGameFirmware(params.program_id, *system, this)) { + if (!QtCommon::Content::CheckGameFirmware(params.program_id, this)) { return false; } From c65f07563815bfafad6f053d91c3c54ce75f64ac Mon Sep 17 00:00:00 2001 From: crueter Date: Sun, 31 Aug 2025 14:56:25 -0400 Subject: [PATCH 17/34] better handling for sys/vfs/rootobject Signed-off-by: crueter --- src/qt_common/CMakeLists.txt | 5 +- .../externals/CMakeLists.txt | 0 .../externals/cpmfile.json | 0 src/qt_common/qt_applet_util.cpp | 1 + src/qt_common/qt_applet_util.h | 8 + src/qt_common/qt_common.cpp | 10 +- src/qt_common/qt_common.h | 14 +- src/qt_common/qt_content_util.cpp | 51 ++- src/qt_common/qt_content_util.h | 11 +- src/qt_common/qt_frontend_util.cpp | 75 +---- src/qt_common/qt_frontend_util.h | 97 +++--- src/yuzu/CMakeLists.txt | 4 - src/yuzu/main.cpp | 297 ++++++++---------- src/yuzu/main.h | 3 - src/yuzu/user_data_migration.h | 1 + 15 files changed, 286 insertions(+), 291 deletions(-) rename src/{yuzu => qt_common}/externals/CMakeLists.txt (100%) rename src/{yuzu => qt_common}/externals/cpmfile.json (100%) create mode 100644 src/qt_common/qt_applet_util.cpp create mode 100644 src/qt_common/qt_applet_util.h diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index add8e59311..1acf8344a1 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -21,6 +21,7 @@ add_library(qt_common STATIC qt_meta.h qt_meta.cpp qt_content_util.h qt_content_util.cpp qt_rom_util.h qt_rom_util.cpp + qt_applet_util.h qt_applet_util.cpp ) create_target_directory_groups(qt_common) @@ -30,7 +31,9 @@ if (ENABLE_QT) target_link_libraries(qt_common PRIVATE Qt6::Widgets) endif() -target_link_libraries(qt_common PUBLIC core Qt6::Core SimpleIni::SimpleIni QuaZip::QuaZip) +add_subdirectory(externals) + +target_link_libraries(qt_common PRIVATE core Qt6::Core SimpleIni::SimpleIni QuaZip::QuaZip) if (NOT WIN32) target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) diff --git a/src/yuzu/externals/CMakeLists.txt b/src/qt_common/externals/CMakeLists.txt similarity index 100% rename from src/yuzu/externals/CMakeLists.txt rename to src/qt_common/externals/CMakeLists.txt diff --git a/src/yuzu/externals/cpmfile.json b/src/qt_common/externals/cpmfile.json similarity index 100% rename from src/yuzu/externals/cpmfile.json rename to src/qt_common/externals/cpmfile.json diff --git a/src/qt_common/qt_applet_util.cpp b/src/qt_common/qt_applet_util.cpp new file mode 100644 index 0000000000..332f4796e8 --- /dev/null +++ b/src/qt_common/qt_applet_util.cpp @@ -0,0 +1 @@ +#include "qt_applet_util.h" diff --git a/src/qt_common/qt_applet_util.h b/src/qt_common/qt_applet_util.h new file mode 100644 index 0000000000..9ceb4a2522 --- /dev/null +++ b/src/qt_common/qt_applet_util.h @@ -0,0 +1,8 @@ +#ifndef QT_APPLET_UTIL_H +#define QT_APPLET_UTIL_H + +// TODO +namespace QtCommon::Applets { + +} +#endif // QT_APPLET_UTIL_H diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index 6f8808ca32..9c20f1e6d9 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -23,7 +23,8 @@ namespace QtCommon { QObject *rootObject = nullptr; -Core::System *system = nullptr; +std::unique_ptr system = nullptr; +std::shared_ptr vfs = nullptr; Core::Frontend::WindowSystemType GetWindowSystemType() { @@ -80,4 +81,11 @@ const QString tr(const std::string& str) return QGuiApplication::tr(str.c_str()); } +void Init(QObject* root) +{ + system = std::make_unique(); + rootObject = root; + vfs = std::make_unique(); +} + } // namespace QtCommon diff --git a/src/qt_common/qt_common.h b/src/qt_common/qt_common.h index cf52cedc32..5f9b5d7de9 100644 --- a/src/qt_common/qt_common.h +++ b/src/qt_common/qt_common.h @@ -4,6 +4,7 @@ #ifndef QT_COMMON_H #define QT_COMMON_H +#include #include #include "core/core.h" #include @@ -13,7 +14,8 @@ namespace QtCommon { extern QObject *rootObject; -extern Core::System *system; +extern std::unique_ptr system; +extern std::shared_ptr vfs; typedef std::function QtProgressCallback; @@ -21,15 +23,7 @@ Core::Frontend::WindowSystemType GetWindowSystemType(); Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow *window); -static inline void SetRootObject(QObject *parent) -{ - rootObject = parent; -} - -static inline void SetSystem(Core::System *newSystem) -{ - system = newSystem; -} +void Init(QObject *root); const QString tr(const char *str); const QString tr(const std::string &str); diff --git a/src/qt_common/qt_content_util.cpp b/src/qt_common/qt_content_util.cpp index 5ad361a527..5f8ca14504 100644 --- a/src/qt_common/qt_content_util.cpp +++ b/src/qt_common/qt_content_util.cpp @@ -5,13 +5,14 @@ #include "common/fs/fs.h" #include "frontend_common/content_manager.h" #include "frontend_common/firmware_manager.h" +#include "qt_common/qt_common.h" #include "qt_frontend_util.h" #include namespace QtCommon::Content { -bool CheckGameFirmware(u64 program_id, QObject *parent) +bool CheckGameFirmware(u64 program_id, QObject* parent) { if (FirmwareManager::GameRequiresFirmware(program_id) && !FirmwareManager::CheckFirmwarePresence(*system)) { @@ -30,11 +31,10 @@ bool CheckGameFirmware(u64 program_id, QObject *parent) return true; } -FirmwareInstallResult InstallFirmware( - const QString& location, - bool recursive, - QtProgressCallback callback, - FileSys::VfsFilesystem* vfs) +FirmwareInstallResult InstallFirmware(const QString& location, + bool recursive, + QtProgressCallback callback, + FileSys::VfsFilesystem* vfs) { static constexpr const char* failedTitle = "Firmware Install Failed"; static constexpr const char* successTitle = "Firmware Install Failed"; @@ -179,16 +179,19 @@ QString UnzipFirmwareToTmp(const QString& location) } // Content // -void VerifyGameContents(const std::string& game_path, QtProgressCallback callback) { +void VerifyGameContents(const std::string& game_path, QtProgressCallback callback) +{ const auto result = ContentManager::VerifyGameContents(*system, game_path, callback); switch (result) { case ContentManager::GameVerificationResult::Success: - QtCommon::Frontend::Information(rootObject, tr("Integrity verification succeeded!"), + QtCommon::Frontend::Information(rootObject, + tr("Integrity verification succeeded!"), tr("The operation completed successfully.")); break; case ContentManager::GameVerificationResult::Failed: - QtCommon::Frontend::Critical(rootObject, tr("Integrity verification failed!"), + QtCommon::Frontend::Critical(rootObject, + tr("Integrity verification failed!"), tr("File contents may be corrupt or missing.")); break; case ContentManager::GameVerificationResult::NotImplemented: @@ -200,5 +203,35 @@ void VerifyGameContents(const std::string& game_path, QtProgressCallback callbac } } +void InstallKeys() +{ + const QString key_source_location + = QtCommon::Frontend::GetOpenFileName(tr("Select Dumped Keys Location"), + {}, + QStringLiteral("Decryption Keys (*.keys)"), + {}, + QtCommon::Frontend::Option::ReadOnly); + if (key_source_location.isEmpty()) { + return; + } + + FirmwareManager::KeyInstallResult result = FirmwareManager::InstallKeys(key_source_location + .toStdString(), + "keys"); + + system->GetFileSystemController().CreateFactories(*QtCommon::vfs); + + switch (result) { + case FirmwareManager::KeyInstallResult::Success: + QtCommon::Frontend::Information(tr("Decryption Keys install succeeded"), + tr("Decryption Keys were successfully installed")); + break; + default: + QtCommon::Frontend::Critical(tr("Decryption Keys install failed"), + tr(FirmwareManager::GetKeyInstallResultString(result))); + break; + } } + +} // namespace QtCommon::Content diff --git a/src/qt_common/qt_content_util.h b/src/qt_common/qt_content_util.h index 529b887146..b401bdf1e3 100644 --- a/src/qt_common/qt_content_util.h +++ b/src/qt_common/qt_content_util.h @@ -32,6 +32,11 @@ enum class FirmwareInstallResult { FailedCorrupted, }; +inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResult result) +{ + return FIRMWARE_RESULTS.at(static_cast(result)); +} + FirmwareInstallResult InstallFirmware( const QString &location, bool recursive, @@ -40,10 +45,8 @@ FirmwareInstallResult InstallFirmware( QString UnzipFirmwareToTmp(const QString &location); -inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResult result) -{ - return FIRMWARE_RESULTS.at(static_cast(result)); -} +// Keys // +void InstallKeys(); // Content // void VerifyGameContents(const std::string &game_path, QtProgressCallback callback); diff --git a/src/qt_common/qt_frontend_util.cpp b/src/qt_common/qt_frontend_util.cpp index 6b96a26a21..d357c11338 100644 --- a/src/qt_common/qt_frontend_util.cpp +++ b/src/qt_common/qt_frontend_util.cpp @@ -2,6 +2,11 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "qt_frontend_util.h" +#include "qt_common/qt_common.h" + +#ifdef YUZU_QT_WIDGETS +#include +#endif namespace QtCommon::Frontend { @@ -19,69 +24,15 @@ QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, // need a way to reference icon/buttons too } -QMessageBox::StandardButton Information(QObject *parent, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons) +const QString GetOpenFileName(const QString &title, + const QString &dir, + const QString &filter, + QString *selectedFilter, + Options options) { - return ShowMessage(QMessageBox::Information, title, text, buttons, parent); +#ifdef YUZU_QT_WIDGETS + return QFileDialog::getOpenFileName((QWidget *) rootObject, title, dir, filter, selectedFilter, options); +#endif } -QMessageBox::StandardButton Warning(QObject *parent, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons) -{ - return ShowMessage(QMessageBox::Warning, title, text, buttons, parent); -} - -QMessageBox::StandardButton Critical(QObject *parent, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons) -{ - return ShowMessage(QMessageBox::Critical, title, text, buttons, parent); -} - -QMessageBox::StandardButton Question(QObject *parent, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons) -{ - return ShowMessage(QMessageBox::Question, title, text, buttons, parent); -} - -QMessageBox::StandardButton Information(QObject *parent, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons) -{ - return ShowMessage(QMessageBox::Information, parent->tr(title), parent->tr(text), buttons, parent); -} - -QMessageBox::StandardButton Warning(QObject *parent, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons) -{ - return ShowMessage(QMessageBox::Warning, parent->tr(title), parent->tr(text), buttons, parent); -} - -QMessageBox::StandardButton Critical(QObject *parent, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons) -{ - return ShowMessage(QMessageBox::Critical, parent->tr(title), parent->tr(text), buttons, parent); -} - -QMessageBox::StandardButton Question(QObject *parent, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons) -{ - return ShowMessage(QMessageBox::Question, parent->tr(title), parent->tr(text), buttons, parent); -} - - } // namespace QtCommon::Frontend diff --git a/src/qt_common/qt_frontend_util.h b/src/qt_common/qt_frontend_util.h index a91a0db07b..7f43286430 100644 --- a/src/qt_common/qt_frontend_util.h +++ b/src/qt_common/qt_frontend_util.h @@ -6,8 +6,10 @@ #include #include +#include "qt_common/qt_common.h" #ifdef YUZU_QT_WIDGETS +#include #include #endif @@ -15,8 +17,27 @@ * manages common functionality e.g. message boxes and such for Qt/QML */ namespace QtCommon::Frontend { + Q_NAMESPACE +#ifdef YUZU_QT_WIDGETS +using Options = QFileDialog::Options; +using Option = QFileDialog::Option; +#else +enum Option { + ShowDirsOnly = 0x00000001, + DontResolveSymlinks = 0x00000002, + DontConfirmOverwrite = 0x00000004, + DontUseNativeDialog = 0x00000008, + ReadOnly = 0x00000010, + HideNameFilterDetails = 0x00000020, + DontUseCustomDirectoryIcons = 0x00000040 +}; +Q_ENUM_NS(Option) +Q_DECLARE_FLAGS(Options, Option) +Q_FLAG_NS(Options) +#endif + // TODO(crueter) widgets-less impl, choices et al. QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, const QString &title, @@ -24,45 +45,47 @@ QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, QMessageBox::StandardButtons buttons = QMessageBox::NoButton, QObject *parent = nullptr); -QMessageBox::StandardButton Information(QObject *parent, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); +#define UTIL_OVERRIDES(level) \ + inline QMessageBox::StandardButton level(QObject *parent, \ + const QString &title, \ + const QString &text, \ + QMessageBox::StandardButtons buttons = QMessageBox::Ok) \ + { \ + return ShowMessage(QMessageBox::level, title, text, buttons, parent); \ + } \ + inline QMessageBox::StandardButton level(QObject *parent, \ + const char *title, \ + const char *text, \ + QMessageBox::StandardButtons buttons \ + = QMessageBox::Ok) \ + { \ + return ShowMessage(QMessageBox::level, tr(title), tr(text), buttons, parent); \ + } \ + inline QMessageBox::StandardButton level(const char *title, \ + const char *text, \ + QMessageBox::StandardButtons buttons \ + = QMessageBox::Ok) \ + { \ + return ShowMessage(QMessageBox::level, tr(title), tr(text), buttons, rootObject); \ + } \ + inline QMessageBox::StandardButton level(const QString title, \ + const QString &text, \ + QMessageBox::StandardButtons buttons \ + = QMessageBox::Ok) \ + { \ + return ShowMessage(QMessageBox::level, title, text, buttons, rootObject); \ + } -QMessageBox::StandardButton Warning(QObject *parent, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); +UTIL_OVERRIDES(Information) +UTIL_OVERRIDES(Warning) +UTIL_OVERRIDES(Critical) +UTIL_OVERRIDES(Question) -QMessageBox::StandardButton Critical(QObject *parent, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); - -QMessageBox::StandardButton Question(QObject *parent, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); - -QMessageBox::StandardButton Information(QObject *parent, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); - -QMessageBox::StandardButton Warning(QObject *parent, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); - -QMessageBox::StandardButton Critical(QObject *parent, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); - -QMessageBox::StandardButton Question(QObject *parent, - const char *title, - const char *text, - QMessageBox::StandardButtons buttons = QMessageBox::Ok); +const QString GetOpenFileName(const QString &title, + const QString &dir, + const QString &filter, + QString *selectedFilter = nullptr, + Options options = Options()); } // namespace QtCommon::Frontend #endif // QT_FRONTEND_UTIL_H diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 9e052b385d..8a1d760c50 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -496,8 +496,4 @@ if (YUZU_ROOM) target_link_libraries(yuzu PRIVATE yuzu-room) endif() -# Extra deps -add_subdirectory(externals) -target_link_libraries(yuzu PRIVATE QuaZip::QuaZip) - create_target_directory_groups(yuzu) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 30ea8702be..728ed2068c 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -70,9 +70,8 @@ // These are wrappers to avoid the calls to CreateDirectory and CreateFile because of the Windows // defines. -static FileSys::VirtualDir VfsFilesystemCreateDirectoryWrapper( - const FileSys::VirtualFilesystem& vfs, const std::string& path, FileSys::OpenMode mode) { - return vfs->CreateDirectory(path, mode); +static FileSys::VirtualDir VfsFilesystemCreateDirectoryWrapper(const std::string& path, FileSys::OpenMode mode) { + return QtCommon::vfs->CreateDirectory(path, mode); } static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::VirtualDir& dir, @@ -398,12 +397,10 @@ inline static bool isDarkMode() { #endif // _WIN32 GMainWindow::GMainWindow(bool has_broken_vulkan) - : ui{std::make_unique()}, system{std::make_unique()}, + : ui{std::make_unique()}, input_subsystem{std::make_shared()}, user_data_migrator{this}, - vfs{std::make_shared()}, provider{std::make_unique()} { - QtCommon::SetSystem(system.get()); - QtCommon::SetRootObject(this); + QtCommon::Init(this); Common::FS::CreateEdenPaths(); this->config = std::make_unique(); @@ -435,7 +432,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) UISettings::RestoreWindowState(config); - system->Initialize(); + QtCommon::system->Initialize(); Common::Log::Initialize(); Common::Log::Start(); @@ -457,7 +454,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) SetDiscordEnabled(UISettings::values.enable_discord_presence.GetValue()); discord_rpc->Update(); - play_time_manager = std::make_unique(system->GetProfileManager()); + play_time_manager = std::make_unique(QtCommon::system->GetProfileManager()); Network::Init(); @@ -474,7 +471,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) ConnectMenuEvents(); ConnectWidgetEvents(); - system->HIDCore().ReloadInputDevices(); + QtCommon::system->HIDCore().ReloadInputDevices(); controller_dialog->refreshConfiguration(); const auto branch_name = std::string(Common::g_scm_branch); @@ -518,7 +515,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) std::chrono::duration_cast>( Common::Windows::SetCurrentTimerResolutionToMaximum()) .count()); - system->CoreTiming().SetTimerResolutionNs(Common::Windows::GetCurrentTimerResolution()); + QtCommon::system->CoreTiming().SetTimerResolutionNs(Common::Windows::GetCurrentTimerResolution()); #endif UpdateWindowTitle(); @@ -544,10 +541,10 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) } #endif - system->SetContentProvider(std::make_unique()); - system->RegisterContentProvider(FileSys::ContentProviderUnionSlot::FrontendManual, + QtCommon::system->SetContentProvider(std::make_unique()); + QtCommon::system->RegisterContentProvider(FileSys::ContentProviderUnionSlot::FrontendManual, provider.get()); - system->GetFileSystemController().CreateFactories(*vfs); + QtCommon::system->GetFileSystemController().CreateFactories(*QtCommon::vfs); // Remove cached contents generated during the previous session RemoveCachedContents(); @@ -661,7 +658,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) if (!argument_ok) { // try to look it up by username, only finds the first username that matches. const std::string user_arg_str = args[user_arg_idx].toStdString(); - const auto user_idx = system->GetProfileManager().GetUserIndex(user_arg_str); + const auto user_idx = QtCommon::system->GetProfileManager().GetUserIndex(user_arg_str); if (user_idx == std::nullopt) { LOG_ERROR(Frontend, "Invalid user argument"); @@ -671,7 +668,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) selected_user = user_idx.value(); } - if (!system->GetProfileManager().UserExistsIndex(selected_user)) { + if (!QtCommon::system->GetProfileManager().UserExistsIndex(selected_user)) { LOG_ERROR(Frontend, "Selected user doesn't exist"); continue; } @@ -762,7 +759,7 @@ void GMainWindow::AmiiboSettingsRequestExit() { void GMainWindow::ControllerSelectorReconfigureControllers( const Core::Frontend::ControllerParameters& parameters) { controller_applet = - new QtControllerSelectorDialog(this, parameters, input_subsystem.get(), *system); + new QtControllerSelectorDialog(this, parameters, input_subsystem.get(), *QtCommon::system); SCOPE_EXIT { controller_applet->deleteLater(); controller_applet = nullptr; @@ -775,8 +772,8 @@ void GMainWindow::ControllerSelectorReconfigureControllers( bool is_success = controller_applet->exec() != QDialog::Rejected; // Don't forget to apply settings. - system->HIDCore().DisableAllControllerConfiguration(); - system->ApplySettings(); + QtCommon::system->HIDCore().DisableAllControllerConfiguration(); + QtCommon::system->ApplySettings(); config->SaveAllValues(); UpdateStatusButtons(); @@ -792,7 +789,7 @@ void GMainWindow::ControllerSelectorRequestExit() { void GMainWindow::ProfileSelectorSelectProfile( const Core::Frontend::ProfileSelectParameters& parameters) { - profile_select_applet = new QtProfileSelectionDialog(*system, this, parameters); + profile_select_applet = new QtProfileSelectionDialog(*QtCommon::system, this, parameters); SCOPE_EXIT { profile_select_applet->deleteLater(); profile_select_applet = nullptr; @@ -807,7 +804,7 @@ void GMainWindow::ProfileSelectorSelectProfile( return; } - const auto uuid = system->GetProfileManager().GetUser( + const auto uuid = QtCommon::system->GetProfileManager().GetUser( static_cast(profile_select_applet->GetIndex())); if (!uuid.has_value()) { emit ProfileSelectorFinishedSelection(std::nullopt); @@ -830,7 +827,7 @@ void GMainWindow::SoftwareKeyboardInitialize( return; } - software_keyboard = new QtSoftwareKeyboardDialog(render_window, *system, is_inline, + software_keyboard = new QtSoftwareKeyboardDialog(render_window, *QtCommon::system, is_inline, std::move(initialize_parameters)); if (is_inline) { @@ -947,7 +944,7 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url, return; } - web_applet = new QtNXWebEngineView(this, *system, input_subsystem.get()); + web_applet = new QtNXWebEngineView(this, *QtCommon::system, input_subsystem.get()); ui->action_Pause->setEnabled(false); ui->action_Restart->setEnabled(false); @@ -1091,10 +1088,10 @@ void GMainWindow::InitializeWidgets() { #ifdef YUZU_ENABLE_COMPATIBILITY_REPORTING ui->action_Report_Compatibility->setVisible(true); #endif - render_window = new GRenderWindow(this, emu_thread.get(), input_subsystem, *system); + render_window = new GRenderWindow(this, emu_thread.get(), input_subsystem, *QtCommon::system); render_window->hide(); - game_list = new GameList(vfs, provider.get(), *play_time_manager, *system, this); + game_list = new GameList(QtCommon::vfs, provider.get(), *play_time_manager, *QtCommon::system, this); ui->horizontalLayout->addWidget(game_list); game_list_placeholder = new GameListPlaceholder(this); @@ -1113,7 +1110,7 @@ void GMainWindow::InitializeWidgets() { }); multiplayer_state = new MultiplayerState(this, game_list->GetModel(), ui->action_Leave_Room, - ui->action_Show_Room, *system); + ui->action_Show_Room, *QtCommon::system); multiplayer_state->setVisible(false); // Create status bar @@ -1367,12 +1364,12 @@ void GMainWindow::InitializeWidgets() { void GMainWindow::InitializeDebugWidgets() { QMenu* debug_menu = ui->menu_View_Debugging; - waitTreeWidget = new WaitTreeWidget(*system, this); + waitTreeWidget = new WaitTreeWidget(*QtCommon::system, this); addDockWidget(Qt::LeftDockWidgetArea, waitTreeWidget); waitTreeWidget->hide(); debug_menu->addAction(waitTreeWidget->toggleViewAction()); - controller_dialog = new ControllerDialog(system->HIDCore(), input_subsystem, this); + controller_dialog = new ControllerDialog(QtCommon::system->HIDCore(), input_subsystem, this); controller_dialog->hide(); debug_menu->addAction(controller_dialog->toggleViewAction()); @@ -1412,7 +1409,7 @@ void GMainWindow::LinkActionShortcut(QAction* action, const QString& action_name this->addAction(action); - auto* controller = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + auto* controller = QtCommon::system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); const auto* controller_hotkey = hotkey_registry.GetControllerHotkey(main_window, action_name.toStdString(), controller); connect( @@ -1457,7 +1454,7 @@ void GMainWindow::InitializeHotkeys() { const auto connect_shortcut = [&](const QString& action_name, const Fn& function) { const auto* hotkey = hotkey_registry.GetHotkey(main_window.toStdString(), action_name.toStdString(), this); - auto* controller = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + auto* controller = QtCommon::system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); const auto* controller_hotkey = hotkey_registry.GetControllerHotkey( main_window.toStdString(), action_name.toStdString(), controller); connect(hotkey, &QShortcut::activated, this, function); @@ -1483,7 +1480,7 @@ void GMainWindow::InitializeHotkeys() { }); connect_shortcut(QStringLiteral("Toggle Renderdoc Capture"), [this] { if (Settings::values.enable_renderdoc_hotkey) { - system->GetRenderdocAPI().ToggleCapture(); + QtCommon::system->GetRenderdocAPI().ToggleCapture(); } }); connect_shortcut(QStringLiteral("Toggle Mouse Panning"), [&] { @@ -1889,13 +1886,13 @@ bool GMainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPa return false; } - system->SetFilesystem(vfs); + QtCommon::system->SetFilesystem(QtCommon::vfs); if (params.launch_type == Service::AM::LaunchType::FrontendInitiated) { - system->GetUserChannel().clear(); + QtCommon::system->GetUserChannel().clear(); } - system->SetFrontendAppletSet({ + QtCommon::system->SetFrontendAppletSet({ std::make_unique(*this), // Amiibo Settings (UISettings::values.controller_applet_disabled.GetValue() == true) ? nullptr @@ -1922,13 +1919,13 @@ bool GMainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPa /** Exec */ const Core::SystemResultStatus result{ - system->Load(*render_window, filename.toStdString(), params)}; + QtCommon::system->Load(*render_window, filename.toStdString(), params)}; const auto drd_callout = (UISettings::values.callout_flags.GetValue() & static_cast(CalloutFlag::DRDDeprecation)) == 0; if (result == Core::SystemResultStatus::Success && - system->GetAppLoader().GetFileType() == Loader::FileType::DeconstructedRomDirectory && + QtCommon::system->GetAppLoader().GetFileType() == Loader::FileType::DeconstructedRomDirectory && drd_callout) { UISettings::values.callout_flags = UISettings::values.callout_flags.GetValue() | static_cast(CalloutFlag::DRDDeprecation); @@ -1993,7 +1990,7 @@ bool GMainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPa bool GMainWindow::SelectAndSetCurrentUser( const Core::Frontend::ProfileSelectParameters& parameters) { - QtProfileSelectionDialog dialog(*system, this, parameters); + QtProfileSelectionDialog dialog(*QtCommon::system, this, parameters); dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); dialog.setWindowModality(Qt::WindowModal); @@ -2008,12 +2005,12 @@ bool GMainWindow::SelectAndSetCurrentUser( void GMainWindow::ConfigureFilesystemProvider(const std::string& filepath) { // Ensure all NCAs are registered before launching the game - const auto file = vfs->OpenFile(filepath, FileSys::OpenMode::Read); + const auto file = QtCommon::vfs->OpenFile(filepath, FileSys::OpenMode::Read); if (!file) { return; } - auto loader = Loader::GetLoader(*system, file); + auto loader = Loader::GetLoader(*QtCommon::system, file); if (!loader) { return; } @@ -2062,8 +2059,8 @@ void GMainWindow::BootGame(const QString& filename, Service::AM::FrontendAppletP last_filename_booted = filename; ConfigureFilesystemProvider(filename.toStdString()); - const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData()); - const auto loader = Loader::GetLoader(*system, v_file, params.program_id, params.program_index); + const auto v_file = Core::GetGameFileFromPath(QtCommon::vfs, filename.toUtf8().constData()); + const auto loader = Loader::GetLoader(*QtCommon::system, v_file, params.program_id, params.program_index); if (loader != nullptr && loader->ReadProgramId(title_id) == Loader::ResultStatus::Success && type == StartGameType::Normal) { @@ -2074,8 +2071,8 @@ void GMainWindow::BootGame(const QString& filename, Service::AM::FrontendAppletP ? Common::FS::PathToUTF8String(file_path.filename()) : fmt::format("{:016X}", title_id); QtConfig per_game_config(config_file_name, Config::ConfigType::PerGameConfig); - system->HIDCore().ReloadInputDevices(); - system->ApplySettings(); + QtCommon::system->HIDCore().ReloadInputDevices(); + QtCommon::system->ApplySettings(); } Settings::LogSettings(); @@ -2101,19 +2098,19 @@ void GMainWindow::BootGame(const QString& filename, Service::AM::FrontendAppletP return; } - system->SetShuttingDown(false); + QtCommon::system->SetShuttingDown(false); game_list->setDisabled(true); // Create and start the emulation thread - emu_thread = std::make_unique(*system); + emu_thread = std::make_unique(*QtCommon::system); emit EmulationStarting(emu_thread.get()); emu_thread->start(); // Register an ExecuteProgram callback such that Core can execute a sub-program - system->RegisterExecuteProgramCallback( + QtCommon::system->RegisterExecuteProgramCallback( [this](std::size_t program_index_) { render_window->ExecuteProgram(program_index_); }); - system->RegisterExitCallback([this] { + QtCommon::system->RegisterExitCallback([this] { emu_thread->ForceStop(); render_window->Exit(); }); @@ -2153,11 +2150,11 @@ void GMainWindow::BootGame(const QString& filename, Service::AM::FrontendAppletP std::string title_name; std::string title_version; - const auto res = system->GetGameName(title_name); + const auto res = QtCommon::system->GetGameName(title_name); const auto metadata = [this, title_id] { - const FileSys::PatchManager pm(title_id, system->GetFileSystemController(), - system->GetContentProvider()); + const FileSys::PatchManager pm(title_id, QtCommon::system->GetFileSystemController(), + QtCommon::system->GetContentProvider()); return pm.GetControlMetadata(); }(); if (metadata.first != nullptr) { @@ -2169,16 +2166,16 @@ void GMainWindow::BootGame(const QString& filename, Service::AM::FrontendAppletP std::filesystem::path{Common::U16StringFromBuffer(filename.utf16(), filename.size())} .filename()); } - const bool is_64bit = system->Kernel().ApplicationProcess()->Is64Bit(); + const bool is_64bit = QtCommon::system->Kernel().ApplicationProcess()->Is64Bit(); const auto instruction_set_suffix = is_64bit ? tr("(64-bit)") : tr("(32-bit)"); title_name = tr("%1 %2", "%1 is the title name. %2 indicates if the title is 64-bit or 32-bit") .arg(QString::fromStdString(title_name), instruction_set_suffix) .toStdString(); LOG_INFO(Frontend, "Booting game: {:016X} | {} | {}", title_id, title_name, title_version); - const auto gpu_vendor = system->GPU().Renderer().GetDeviceVendor(); + const auto gpu_vendor = QtCommon::system->GPU().Renderer().GetDeviceVendor(); UpdateWindowTitle(title_name, title_version, gpu_vendor); - loading_screen->Prepare(system->GetAppLoader()); + loading_screen->Prepare(QtCommon::system->GetAppLoader()); loading_screen->show(); emulation_running = true; @@ -2206,11 +2203,11 @@ bool GMainWindow::OnShutdownBegin() { // Disable unlimited frame rate Settings::values.use_speed_limit.SetValue(true); - if (system->IsShuttingDown()) { + if (QtCommon::system->IsShuttingDown()) { return false; } - system->SetShuttingDown(true); + QtCommon::system->SetShuttingDown(true); discord_rpc->Pause(); RequestGameExit(); @@ -2221,9 +2218,9 @@ bool GMainWindow::OnShutdownBegin() { int shutdown_time = 1000; - if (system->DebuggerEnabled()) { + if (QtCommon::system->DebuggerEnabled()) { shutdown_time = 0; - } else if (system->GetExitLocked()) { + } else if (QtCommon::system->GetExitLocked()) { shutdown_time = 5000; } @@ -2241,7 +2238,7 @@ bool GMainWindow::OnShutdownBegin() { } void GMainWindow::OnShutdownBeginDialog() { - shutdown_dialog = new OverlayDialog(this, *system, QString{}, tr("Closing software..."), + shutdown_dialog = new OverlayDialog(this, *QtCommon::system, QString{}, tr("Closing software..."), QString{}, QString{}, Qt::AlignHCenter | Qt::AlignVCenter); shutdown_dialog->open(); } @@ -2293,10 +2290,10 @@ void GMainWindow::OnEmulationStopped() { OnTasStateChanged(); render_window->FinalizeCamera(); - system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::None); + QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::None); // Enable all controllers - system->HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All}); + QtCommon::system->HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All}); render_window->removeEventFilter(render_window); render_window->setAttribute(Qt::WA_Hover, false); @@ -2325,8 +2322,8 @@ void GMainWindow::OnEmulationStopped() { // Enable game list game_list->setEnabled(true); - Settings::RestoreGlobalState(system->IsPoweredOn()); - system->HIDCore().ReloadInputDevices(); + Settings::RestoreGlobalState(QtCommon::system->IsPoweredOn()); + QtCommon::system->HIDCore().ReloadInputDevices(); UpdateStatusButtons(); } @@ -2387,15 +2384,15 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target QString open_target; const auto [user_save_size, device_save_size] = [this, &game_path, &program_id] { - const FileSys::PatchManager pm{program_id, system->GetFileSystemController(), - system->GetContentProvider()}; + const FileSys::PatchManager pm{program_id, QtCommon::system->GetFileSystemController(), + QtCommon::system->GetContentProvider()}; const auto control = pm.GetControlMetadata().first; if (control != nullptr) { return std::make_pair(control->GetDefaultNormalSaveSize(), control->GetDeviceSaveDataSize()); } else { - const auto file = Core::GetGameFileFromPath(vfs, game_path); - const auto loader = Loader::GetLoader(*system, file); + const auto file = Core::GetGameFileFromPath(QtCommon::vfs, game_path); + const auto loader = Loader::GetLoader(*QtCommon::system, file); FileSys::NACP nacp{}; loader->ReadControlData(nacp); @@ -2414,7 +2411,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target open_target = tr("Save Data"); const auto nand_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir); auto vfs_nand_dir = - vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read); + QtCommon::vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read); if (has_user_save) { // User save data @@ -2425,7 +2422,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target .display_options = {}, .purpose = Service::AM::Frontend::UserSelectionPurpose::General, }; - QtProfileSelectionDialog dialog(*system, this, parameters); + QtProfileSelectionDialog dialog(*QtCommon::system, this, parameters); dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); dialog.setWindowModality(Qt::WindowModal); @@ -2443,7 +2440,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target } const auto user_id = - system->GetProfileManager().GetUser(static_cast(index)); + QtCommon::system->GetProfileManager().GetUser(static_cast(index)); ASSERT(user_id); const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( @@ -2631,7 +2628,7 @@ void GMainWindow::OnGameListRemoveFile(u64 program_id, QtCommon::Game::GameListR QtCommon::Game::RemoveCustomConfiguration(program_id, game_path); break; case QtCommon::Game::GameListRemoveTarget::CacheStorage: - QtCommon::Game::RemoveCacheStorage(program_id, vfs.get()); + QtCommon::Game::RemoveCacheStorage(program_id, QtCommon::vfs.get()); break; } } @@ -2656,7 +2653,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa }; const auto loader = - Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::OpenMode::Read)); + Loader::GetLoader(*QtCommon::system, QtCommon::vfs->OpenFile(game_path, FileSys::OpenMode::Read)); if (loader == nullptr) { failed(); return; @@ -2665,7 +2662,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa FileSys::VirtualFile packed_update_raw{}; loader->ReadUpdateRaw(packed_update_raw); - const auto& installed = system->GetContentProvider(); + const auto& installed = QtCommon::system->GetContentProvider(); u64 title_id{}; u8 raw_type{}; @@ -2697,14 +2694,14 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa const auto path = Common::FS::PathToUTF8String(dump_dir / romfs_dir); - const FileSys::PatchManager pm{title_id, system->GetFileSystemController(), installed}; + const FileSys::PatchManager pm{title_id, QtCommon::system->GetFileSystemController(), installed}; auto romfs = pm.PatchRomFS(base_nca.get(), base_romfs, type, packed_update_raw, false); - const auto out = VfsFilesystemCreateDirectoryWrapper(vfs, path, FileSys::OpenMode::ReadWrite); + const auto out = VfsFilesystemCreateDirectoryWrapper(path, FileSys::OpenMode::ReadWrite); if (out == nullptr) { failed(); - vfs->DeleteDirectory(path); + QtCommon::vfs->DeleteDirectory(path); return; } @@ -2718,7 +2715,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa selections, 0, false, &ok); if (!ok) { failed(); - vfs->DeleteDirectory(path); + QtCommon::vfs->DeleteDirectory(path); return; } @@ -2758,7 +2755,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa } else { progress.close(); failed(); - vfs->DeleteDirectory(path); + QtCommon::vfs->DeleteDirectory(path); } } @@ -2888,8 +2885,8 @@ void GMainWindow::OnGameListShowList(bool show) { void GMainWindow::OnGameListOpenPerGameProperties(const std::string& file) { u64 title_id{}; - const auto v_file = Core::GetGameFileFromPath(vfs, file); - const auto loader = Loader::GetLoader(*system, v_file); + const auto v_file = Core::GetGameFileFromPath(QtCommon::vfs, file); + const auto loader = Loader::GetLoader(*QtCommon::system, v_file); if (loader == nullptr || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) { QMessageBox::information(this, tr("Properties"), @@ -3017,7 +3014,7 @@ void GMainWindow::OnMenuInstallToNAND() { return false; }; future = QtConcurrent::run([this, &file, progress_callback] { - return ContentManager::InstallNSP(*system, *vfs, file.toStdString(), + return ContentManager::InstallNSP(*QtCommon::system, *QtCommon::vfs, file.toStdString(), progress_callback); }); @@ -3109,7 +3106,7 @@ ContentManager::InstallResult GMainWindow::InstallNCA(const QString& filename) { } const bool is_application = index >= static_cast(FileSys::TitleType::Application); - const auto& fs_controller = system->GetFileSystemController(); + const auto& fs_controller = QtCommon::system->GetFileSystemController(); auto* registered_cache = is_application ? fs_controller.GetUserNANDContents() : fs_controller.GetSystemNANDContents(); @@ -3120,7 +3117,7 @@ ContentManager::InstallResult GMainWindow::InstallNCA(const QString& filename) { } return false; }; - return ContentManager::InstallNCA(*vfs, filename.toStdString(), *registered_cache, + return ContentManager::InstallNCA(*QtCommon::vfs, filename.toStdString(), *registered_cache, static_cast(index), progress_callback); } @@ -3149,7 +3146,7 @@ void GMainWindow::OnStartGame() { UpdateMenuState(); OnTasStateChanged(); - play_time_manager->SetProgramId(system->GetApplicationProcessProgramID()); + play_time_manager->SetProgramId(QtCommon::system->GetApplicationProcessProgramID()); play_time_manager->Start(); discord_rpc->Update(); @@ -3160,7 +3157,7 @@ void GMainWindow::OnStartGame() { } void GMainWindow::OnRestartGame() { - if (!system->IsPoweredOn()) { + if (!QtCommon::system->IsPoweredOn()) { return; } @@ -3208,7 +3205,7 @@ void GMainWindow::OnStopGame() { bool GMainWindow::ConfirmShutdownGame() { if (UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Always) { - if (system->GetExitLocked()) { + if (QtCommon::system->GetExitLocked()) { if (!ConfirmForceLockedExit()) { return false; } @@ -3220,7 +3217,7 @@ bool GMainWindow::ConfirmShutdownGame() { } else { if (UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Based_On_Game && - system->GetExitLocked()) { + QtCommon::system->GetExitLocked()) { if (!ConfirmForceLockedExit()) { return false; } @@ -3247,12 +3244,12 @@ void GMainWindow::OnExit() { } void GMainWindow::OnSaveConfig() { - system->ApplySettings(); + QtCommon::system->ApplySettings(); config->SaveAllValues(); } void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) { - error_applet = new OverlayDialog(render_window, *system, error_code, error_text, QString{}, + error_applet = new OverlayDialog(render_window, *QtCommon::system, error_code, error_text, QString{}, tr("OK"), Qt::AlignLeft | Qt::AlignVCenter); SCOPE_EXIT { error_applet->deleteLater(); @@ -3481,7 +3478,7 @@ void GMainWindow::OnConfigure() { Settings::SetConfiguringGlobal(true); ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get(), - vk_device_records, *system, + vk_device_records, *QtCommon::system, !multiplayer_state->IsHostingPublicRoom()); connect(&configure_dialog, &ConfigureDialog::LanguageChanged, this, &GMainWindow::OnLanguageChanged); @@ -3582,7 +3579,7 @@ void GMainWindow::OnConfigure() { UpdateStatusButtons(); controller_dialog->refreshConfiguration(); - system->ApplySettings(); + QtCommon::system->ApplySettings(); } void GMainWindow::OnConfigureTas() { @@ -3590,7 +3587,7 @@ void GMainWindow::OnConfigureTas() { const auto result = dialog.exec(); if (result != QDialog::Accepted && !UISettings::values.configuration_applied) { - Settings::RestoreGlobalState(system->IsPoweredOn()); + Settings::RestoreGlobalState(QtCommon::system->IsPoweredOn()); return; } else if (result == QDialog::Accepted) { dialog.ApplyConfiguration(); @@ -3604,7 +3601,7 @@ void GMainWindow::OnTasStartStop() { } // Disable system buttons to prevent TAS from executing a hotkey - auto* controller = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + auto* controller = QtCommon::system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); controller->ResetSystemButtons(); input_subsystem->GetTas()->StartStop(); @@ -3620,7 +3617,7 @@ void GMainWindow::OnTasRecord() { } // Disable system buttons to prevent TAS from recording a hotkey - auto* controller = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + auto* controller = QtCommon::system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); controller->ResetSystemButtons(); const bool is_recording = input_subsystem->GetTas()->Record(); @@ -3642,8 +3639,8 @@ void GMainWindow::OnTasReset() { void GMainWindow::OnToggleDockedMode() { const bool is_docked = Settings::IsDockedMode(); - auto* player_1 = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); - auto* handheld = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); + auto* player_1 = QtCommon::system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + auto* handheld = QtCommon::system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); if (!is_docked && handheld->IsConnected()) { QMessageBox::warning(this, tr("Invalid config detected"), @@ -3658,7 +3655,7 @@ void GMainWindow::OnToggleDockedMode() { Settings::values.use_docked_mode.SetValue(is_docked ? Settings::ConsoleMode::Handheld : Settings::ConsoleMode::Docked); UpdateDockedButton(); - OnDockedModeChanged(is_docked, !is_docked, *system); + OnDockedModeChanged(is_docked, !is_docked, *QtCommon::system); } void GMainWindow::OnToggleGpuAccuracy() { @@ -3675,7 +3672,7 @@ void GMainWindow::OnToggleGpuAccuracy() { } } - system->ApplySettings(); + QtCommon::system->ApplySettings(); UpdateGPUAccuracyButton(); } @@ -3740,20 +3737,20 @@ void GMainWindow::OnToggleGraphicsAPI() { } void GMainWindow::OnConfigurePerGame() { - const u64 title_id = system->GetApplicationProcessProgramID(); + const u64 title_id = QtCommon::system->GetApplicationProcessProgramID(); OpenPerGameConfiguration(title_id, current_game_path.toStdString()); } void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file_name) { - const auto v_file = Core::GetGameFileFromPath(vfs, file_name); + const auto v_file = Core::GetGameFileFromPath(QtCommon::vfs, file_name); Settings::SetConfiguringGlobal(false); - ConfigurePerGame dialog(this, title_id, file_name, vk_device_records, *system); + ConfigurePerGame dialog(this, title_id, file_name, vk_device_records, *QtCommon::system); dialog.LoadFromFile(v_file); const auto result = dialog.exec(); if (result != QDialog::Accepted && !UISettings::values.configuration_applied) { - Settings::RestoreGlobalState(system->IsPoweredOn()); + Settings::RestoreGlobalState(QtCommon::system->IsPoweredOn()); return; } else if (result == QDialog::Accepted) { dialog.ApplyConfiguration(); @@ -3765,9 +3762,9 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file } // Do not cause the global config to write local settings into the config file - const bool is_powered_on = system->IsPoweredOn(); + const bool is_powered_on = QtCommon::system->IsPoweredOn(); Settings::RestoreGlobalState(is_powered_on); - system->HIDCore().ReloadInputDevices(); + QtCommon::system->HIDCore().ReloadInputDevices(); UISettings::values.configuration_applied = false; @@ -3822,7 +3819,7 @@ bool GMainWindow::question(QWidget* parent, const QString& title, const QString& box_dialog->setDefaultButton(defaultButton); ControllerNavigation* controller_navigation = - new ControllerNavigation(system->HIDCore(), box_dialog); + new ControllerNavigation(QtCommon::system->HIDCore(), box_dialog); connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent, [box_dialog](Qt::Key key) { QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier); @@ -3901,7 +3898,7 @@ void GMainWindow::OnVerifyInstalledContents() { }; const std::vector result = - ContentManager::VerifyInstalledContents(*system, *provider, QtProgressCallback); + ContentManager::VerifyInstalledContents(*QtCommon::system, *provider, QtProgressCallback); progress.close(); if (result.empty()) { @@ -3930,7 +3927,7 @@ void GMainWindow::InstallFirmware(const QString& location, bool recursive) { return progress.wasCanceled(); }; - auto result = QtCommon::Content::InstallFirmware(location, recursive, QtProgressCallback, vfs.get()); + auto result = QtCommon::Content::InstallFirmware(location, recursive, QtProgressCallback, QtCommon::vfs.get()); progress.close(); @@ -3942,7 +3939,7 @@ void GMainWindow::InstallFirmware(const QString& location, bool recursive) { }; auto results = - ContentManager::VerifyInstalledContents(*system, *provider, VerifyFirmwareCallback, true); + ContentManager::VerifyInstalledContents(*QtCommon::system, *provider, VerifyFirmwareCallback, true); if (results.size() > 0) { const auto failed_names = @@ -4026,30 +4023,9 @@ void GMainWindow::OnInstallDecryptionKeys() { return; } - const QString key_source_location = QFileDialog::getOpenFileName( - this, tr("Select Dumped Keys Location"), {}, QStringLiteral("Decryption Keys (*.keys)"), {}, - QFileDialog::ReadOnly); - if (key_source_location.isEmpty()) { - return; - } + QtCommon::Content::InstallKeys(); - FirmwareManager::KeyInstallResult result = - FirmwareManager::InstallKeys(key_source_location.toStdString(), "keys"); - - system->GetFileSystemController().CreateFactories(*vfs); game_list->PopulateAsync(UISettings::values.game_dirs); - - switch (result) { - case FirmwareManager::KeyInstallResult::Success: - QMessageBox::information(this, tr("Decryption Keys install succeeded"), - tr("Decryption Keys were successfully installed")); - break; - default: - QMessageBox::critical(this, tr("Decryption Keys install failed"), - tr(FirmwareManager::GetKeyInstallResultString(result))); - break; - } - OnCheckFirmwareDecryption(); } @@ -4086,7 +4062,7 @@ void GMainWindow::OnGameListRefresh() void GMainWindow::OnAlbum() { constexpr u64 AlbumId = static_cast(Service::AM::AppletProgramId::PhotoViewer); - auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); + auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), tr("Please install firmware to use the Album applet.")); @@ -4100,7 +4076,7 @@ void GMainWindow::OnAlbum() { return; } - system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::PhotoViewer); + QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::PhotoViewer); const auto filename = QString::fromStdString(album_nca->GetFullPath()); UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); @@ -4109,7 +4085,7 @@ void GMainWindow::OnAlbum() { void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { constexpr u64 CabinetId = static_cast(Service::AM::AppletProgramId::Cabinet); - auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); + auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), tr("Please install firmware to use the Cabinet applet.")); @@ -4123,8 +4099,8 @@ void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { return; } - system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Cabinet); - system->GetFrontendAppletHolder().SetCabinetMode(mode); + QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Cabinet); + QtCommon::system->GetFrontendAppletHolder().SetCabinetMode(mode); const auto filename = QString::fromStdString(cabinet_nca->GetFullPath()); UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); @@ -4133,7 +4109,7 @@ void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { void GMainWindow::OnMiiEdit() { constexpr u64 MiiEditId = static_cast(Service::AM::AppletProgramId::MiiEdit); - auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); + auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), tr("Please install firmware to use the Mii editor.")); @@ -4147,7 +4123,7 @@ void GMainWindow::OnMiiEdit() { return; } - system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::MiiEdit); + QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::MiiEdit); const auto filename = QString::fromStdString((mii_applet_nca->GetFullPath())); UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); @@ -4156,7 +4132,7 @@ void GMainWindow::OnMiiEdit() { void GMainWindow::OnOpenControllerMenu() { constexpr u64 ControllerAppletId = static_cast(Service::AM::AppletProgramId::Controller); - auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); + auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), tr("Please install firmware to use the Controller Menu.")); @@ -4171,7 +4147,7 @@ void GMainWindow::OnOpenControllerMenu() { return; } - system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Controller); + QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Controller); const auto filename = QString::fromStdString((controller_applet_nca->GetFullPath())); UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); @@ -4180,7 +4156,7 @@ void GMainWindow::OnOpenControllerMenu() { } void GMainWindow::OnHomeMenu() { - auto result = FirmwareManager::VerifyFirmware(*system.get()); + auto result = FirmwareManager::VerifyFirmware(*QtCommon::system.get()); switch (result) { case FirmwareManager::ErrorFirmwareMissing: @@ -4217,7 +4193,7 @@ void GMainWindow::OnHomeMenu() { // TODO(crueter): So much of this crap is common to qt that I should just move it all tbh constexpr u64 QLaunchId = static_cast(Service::AM::AppletProgramId::QLaunch); - auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); + auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); auto qlaunch_applet_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program); if (!qlaunch_applet_nca) { @@ -4226,7 +4202,7 @@ void GMainWindow::OnHomeMenu() { return; } - system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::QLaunch); + QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::QLaunch); const auto filename = QString::fromStdString((qlaunch_applet_nca->GetFullPath())); UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); @@ -4235,7 +4211,7 @@ void GMainWindow::OnHomeMenu() { void GMainWindow::OnInitialSetup() { constexpr u64 Starter = static_cast(Service::AM::AppletProgramId::Starter); - auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); + auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), tr("Please install firmware to use Starter.")); @@ -4249,7 +4225,7 @@ void GMainWindow::OnInitialSetup() { return; } - system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Starter); + QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Starter); const auto filename = QString::fromStdString((qlaunch_nca->GetFullPath())); UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); @@ -4296,6 +4272,7 @@ std::filesystem::path GMainWindow::GetShortcutPath(GameListShortcutTarget target return shortcut_path; } +// TODO(crueter): Migrate void GMainWindow::CreateShortcut(const std::string &game_path, const u64 program_id, const std::string& game_title_, GameListShortcutTarget target, std::string arguments_, const bool needs_title) { // Get path to Eden executable std::filesystem::path command = GetEdenCommand(); @@ -4311,11 +4288,11 @@ void GMainWindow::CreateShortcut(const std::string &game_path, const u64 program return; } - const FileSys::PatchManager pm{program_id, system->GetFileSystemController(), - system->GetContentProvider()}; + const FileSys::PatchManager pm{program_id, QtCommon::system->GetFileSystemController(), + QtCommon::system->GetContentProvider()}; const auto control = pm.GetControlMetadata(); const auto loader = - Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::OpenMode::Read)); + Loader::GetLoader(*QtCommon::system, QtCommon::vfs->OpenFile(game_path, FileSys::OpenMode::Read)); std::string game_title{game_title_}; @@ -4395,7 +4372,7 @@ void GMainWindow::CreateShortcut(const std::string &game_path, const u64 program void GMainWindow::OnCreateHomeMenuShortcut(GameListShortcutTarget target) { constexpr u64 QLaunchId = static_cast(Service::AM::AppletProgramId::QLaunch); - auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); + auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), tr("Please install firmware to use the home menu.")); @@ -4421,7 +4398,7 @@ void GMainWindow::OnCaptureScreenshot() { return; } - const u64 title_id = system->GetApplicationProcessProgramID(); + const u64 title_id = QtCommon::system->GetApplicationProcessProgramID(); const auto screenshot_path = QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::ScreenshotsDir)); const auto date = @@ -4583,7 +4560,7 @@ void GMainWindow::OnTasStateChanged() { } void GMainWindow::UpdateStatusBar() { - if (emu_thread == nullptr || !system->IsPoweredOn()) { + if (emu_thread == nullptr || !QtCommon::system->IsPoweredOn()) { status_bar_update_timer.stop(); return; } @@ -4594,8 +4571,8 @@ void GMainWindow::UpdateStatusBar() { tas_label->clear(); } - auto results = system->GetAndResetPerfStats(); - auto& shader_notify = system->GPU().ShaderNotify(); + auto results = QtCommon::system->GetAndResetPerfStats(); + auto& shader_notify = QtCommon::system->GPU().ShaderNotify(); const int shaders_building = shader_notify.ShadersBuilding(); if (shaders_building > 0) { @@ -4741,7 +4718,7 @@ void GMainWindow::OnMouseActivity() { } void GMainWindow::OnCheckFirmwareDecryption() { - system->GetFileSystemController().CreateFactories(*vfs); + QtCommon::system->GetFileSystemController().CreateFactories(*QtCommon::vfs); if (!ContentManager::AreKeysPresent()) { QMessageBox::warning(this, tr("Derivation Components Missing"), tr("Encryption keys are missing.")); @@ -4786,11 +4763,11 @@ bool GMainWindow::OnCheckNcaVerification() { } bool GMainWindow::CheckFirmwarePresence() { - return FirmwareManager::CheckFirmwarePresence(*system.get()); + return FirmwareManager::CheckFirmwarePresence(*QtCommon::system.get()); } void GMainWindow::SetFirmwareVersion() { - const auto pair = FirmwareManager::GetFirmwareVersion(*system.get()); + const auto pair = FirmwareManager::GetFirmwareVersion(*QtCommon::system.get()); const auto firmware_data = pair.first; const auto result = pair.second; @@ -4876,7 +4853,7 @@ bool GMainWindow::ConfirmClose() { UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Never) { return true; } - if (!system->GetExitLocked() && + if (!QtCommon::system->GetExitLocked() && UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Based_On_Game) { return true; } @@ -4906,7 +4883,7 @@ void GMainWindow::closeEvent(QCloseEvent* event) { render_window->close(); multiplayer_state->Close(); - system->HIDCore().UnloadInputDevices(); + QtCommon::system->HIDCore().UnloadInputDevices(); Network::Shutdown(); QWidget::closeEvent(event); @@ -4977,12 +4954,12 @@ bool GMainWindow::ConfirmForceLockedExit() { } void GMainWindow::RequestGameExit() { - if (!system->IsPoweredOn()) { + if (!QtCommon::system->IsPoweredOn()) { return; } - system->SetExitRequested(true); - system->GetAppletManager().RequestExit(); + QtCommon::system->SetExitRequested(true); + QtCommon::system->GetAppletManager().RequestExit(); } void GMainWindow::filterBarSetChecked(bool state) { @@ -5092,7 +5069,7 @@ void GMainWindow::OnLanguageChanged(const QString& locale) { void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) { #ifdef USE_DISCORD_PRESENCE if (state) { - discord_rpc = std::make_unique(*system); + discord_rpc = std::make_unique(*QtCommon::system); } else { discord_rpc = std::make_unique(); } diff --git a/src/yuzu/main.h b/src/yuzu/main.h index f523561628..0bc5913acc 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -71,7 +71,6 @@ enum class StartGameType { namespace Core { enum class SystemResultStatus : u32; -class System; } // namespace Core namespace Core::Frontend { @@ -479,7 +478,6 @@ private: std::unique_ptr ui; - std::unique_ptr system; std::unique_ptr discord_rpc; std::unique_ptr play_time_manager; std::shared_ptr input_subsystem; @@ -540,7 +538,6 @@ private: QString startup_icon_theme; // FS - std::shared_ptr vfs; std::unique_ptr provider; // Debugger panes diff --git a/src/yuzu/user_data_migration.h b/src/yuzu/user_data_migration.h index 3684d14916..a3ac2c15d3 100644 --- a/src/yuzu/user_data_migration.h +++ b/src/yuzu/user_data_migration.h @@ -10,6 +10,7 @@ #include #include "migration_worker.h" +// TODO(crueter): Quick implementation class UserDataMigrator { public: UserDataMigrator(QMainWindow* main_window); From 2d94767f9625630095a663200e6a13bfab1e9160 Mon Sep 17 00:00:00 2001 From: crueter Date: Sun, 31 Aug 2025 14:57:21 -0400 Subject: [PATCH 18/34] Fix license headers --- src/qt_common/qt_applet_util.cpp | 3 +++ src/qt_common/qt_applet_util.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/qt_common/qt_applet_util.cpp b/src/qt_common/qt_applet_util.cpp index 332f4796e8..1b0189392e 100644 --- a/src/qt_common/qt_applet_util.cpp +++ b/src/qt_common/qt_applet_util.cpp @@ -1 +1,4 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #include "qt_applet_util.h" diff --git a/src/qt_common/qt_applet_util.h b/src/qt_common/qt_applet_util.h index 9ceb4a2522..2b48d16698 100644 --- a/src/qt_common/qt_applet_util.h +++ b/src/qt_common/qt_applet_util.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #ifndef QT_APPLET_UTIL_H #define QT_APPLET_UTIL_H From 8974aed013dae12150da80b163616495a1afc9dc Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 13 Sep 2025 11:39:10 -0400 Subject: [PATCH 19/34] QProgressDialog abstractor, more moving Signed-off-by: crueter --- .ci/license-header.sh | 1 - .../org/yuzu/yuzu_emu/adapters/GameAdapter.kt | 19 - .../features/settings/model/BooleanSetting.kt | 1 - .../settings/model/view/SettingsItem.kt | 7 - .../settings/ui/SettingsFragmentPresenter.kt | 1 - .../app/src/main/res/values/strings.xml | 3 - src/common/settings.h | 4 - .../fssystem/fssystem_bucket_tree.cpp | 4 +- .../fssystem_nca_file_system_driver.cpp | 133 +++---- src/qt_common/CMakeLists.txt | 9 +- src/qt_common/externals/CMakeLists.txt | 4 + src/qt_common/externals/cpmfile.json | 7 + src/qt_common/qt_common.cpp | 33 +- src/qt_common/qt_common.h | 14 +- src/qt_common/qt_content_util.cpp | 114 +++++- src/qt_common/qt_content_util.h | 11 +- src/qt_common/qt_frontend_util.cpp | 7 +- src/qt_common/qt_frontend_util.h | 93 ++++- src/qt_common/qt_game_util.cpp | 177 +++++++++ src/qt_common/qt_game_util.h | 24 ++ src/qt_common/qt_progress_dialog.cpp | 4 + src/qt_common/qt_progress_dialog.h | 47 +++ src/qt_common/shared_translation.cpp | 12 +- src/yuzu/game_list.cpp | 4 +- src/yuzu/game_list.h | 7 +- src/yuzu/main.cpp | 345 ++---------------- src/yuzu/main.h | 21 +- 27 files changed, 580 insertions(+), 526 deletions(-) create mode 100644 src/qt_common/qt_progress_dialog.cpp create mode 100644 src/qt_common/qt_progress_dialog.h diff --git a/.ci/license-header.sh b/.ci/license-header.sh index d98f42fc97..3d4929d1c1 100755 --- a/.ci/license-header.sh +++ b/.ci/license-header.sh @@ -15,7 +15,6 @@ FILES=`git diff --name-only $BASE` #FILES=$(git diff --name-only master) -echo $FILES echo "Done" check_header() { diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt index 98f342c274..b383cc147f 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt @@ -232,8 +232,6 @@ class GameAdapter(private val activity: AppCompatActivity) : binding.root.findNavController().navigate(action) } - val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) - if (NativeLibrary.gameRequiresFirmware(game.programId) && !NativeLibrary.isFirmwareAvailable()) { MaterialAlertDialogBuilder(activity) .setTitle(R.string.loader_requires_firmware) @@ -248,23 +246,6 @@ class GameAdapter(private val activity: AppCompatActivity) : } .setNegativeButton(android.R.string.cancel) { _, _ -> } .show() - } else if (BooleanSetting.DISABLE_NCA_VERIFICATION.getBoolean(false) && !preferences.getBoolean( - Settings.PREF_HIDE_NCA_POPUP, false)) { - MaterialAlertDialogBuilder(activity) - .setTitle(R.string.nca_verification_disabled) - .setMessage(activity.getString(R.string.nca_verification_disabled_description)) - .setPositiveButton(android.R.string.ok) { _, _ -> - launch() - } - .setNeutralButton(R.string.dont_show_again) { _, _ -> - preferences.edit { - putBoolean(Settings.PREF_HIDE_NCA_POPUP, true) - } - - launch() - } - .setNegativeButton(android.R.string.cancel) { _, _ -> } - .show() } else { launch() } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt index 6d4bfd97ac..3c5b9003de 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt @@ -35,7 +35,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting { RENDERER_SAMPLE_SHADING("sample_shading"), PICTURE_IN_PICTURE("picture_in_picture"), USE_CUSTOM_RTC("custom_rtc_enabled"), - DISABLE_NCA_VERIFICATION("disable_nca_verification"), BLACK_BACKGROUNDS("black_backgrounds"), JOYSTICK_REL_CENTER("joystick_rel_center"), DPAD_SLIDE("dpad_slide"), diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index 883d8efaef..1f2ba81a73 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt @@ -297,13 +297,6 @@ abstract class SettingsItem( descriptionId = R.string.use_custom_rtc_description ) ) - put( - SwitchSetting( - BooleanSetting.DISABLE_NCA_VERIFICATION, - titleId = R.string.disable_nca_verification, - descriptionId = R.string.disable_nca_verification_description - ) - ) put( StringInputSetting( StringSetting.WEB_TOKEN, diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index 630bcb0d74..14d62ceec3 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -210,7 +210,6 @@ class SettingsFragmentPresenter( add(IntSetting.LANGUAGE_INDEX.key) add(BooleanSetting.USE_CUSTOM_RTC.key) add(LongSetting.CUSTOM_RTC.key) - add(BooleanSetting.DISABLE_NCA_VERIFICATION.key) add(HeaderSetting(R.string.network)) add(StringSetting.WEB_TOKEN.key) diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 2c7923d5a3..6e428a1f7f 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -784,9 +784,6 @@ Game Requires Firmware dump and install firmware, or press "OK" to launch anyways.]]> - NCA Verification Disabled - This is required to run new games and updates, but may cause instability or crashes if NCA files are corrupt, modified, or tampered with. If unsure, re-enable verification in Advanced Settings -> System, and use firmware versions of 19.0.1 or below. - Searching for game... Game not found for Title ID: %1$s diff --git a/src/common/settings.h b/src/common/settings.h index 9d448a2b38..fafd765804 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -626,10 +626,6 @@ struct Values { true, true, &rng_seed_enabled}; Setting device_name{ linkage, "Eden", "device_name", Category::System, Specialization::Default, true, true}; - SwitchableSetting disable_nca_verification{linkage, true, "disable_nca_verification", - Category::System, Specialization::Default}; - Setting hide_nca_verification_popup{ - linkage, false, "hide_nca_verification_popup", Category::System, Specialization::Default}; Setting current_user{linkage, 0, "current_user", Category::System}; diff --git a/src/core/file_sys/fssystem/fssystem_bucket_tree.cpp b/src/core/file_sys/fssystem/fssystem_bucket_tree.cpp index 615a624f4f..71ba458cef 100644 --- a/src/core/file_sys/fssystem/fssystem_bucket_tree.cpp +++ b/src/core/file_sys/fssystem/fssystem_bucket_tree.cpp @@ -238,9 +238,7 @@ void BucketTree::Initialize(size_t node_size, s64 end_offset) { ASSERT(NodeSizeMin <= node_size && node_size <= NodeSizeMax); ASSERT(Common::IsPowerOfTwo(node_size)); - if (!Settings::values.disable_nca_verification.GetValue()) { - ASSERT(end_offset > 0); - } + ASSERT(end_offset > 0); ASSERT(!this->IsInitialized()); m_node_size = node_size; diff --git a/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp b/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp index 4cfa5c58f8..4e624ad3f4 100644 --- a/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp +++ b/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later @@ -1296,91 +1299,65 @@ Result NcaFileSystemDriver::CreateIntegrityVerificationStorageImpl( ASSERT(base_storage != nullptr); ASSERT(layer_info_offset >= 0); - if (!Settings::values.disable_nca_verification.GetValue()) { - // Define storage types. - using VerificationStorage = HierarchicalIntegrityVerificationStorage; - using StorageInfo = VerificationStorage::HierarchicalStorageInformation; + // Define storage types. + using VerificationStorage = HierarchicalIntegrityVerificationStorage; + using StorageInfo = VerificationStorage::HierarchicalStorageInformation; - // Validate the meta info. - HierarchicalIntegrityVerificationInformation level_hash_info; - std::memcpy(std::addressof(level_hash_info), std::addressof(meta_info.level_hash_info), - sizeof(level_hash_info)); + // Validate the meta info. + HierarchicalIntegrityVerificationInformation level_hash_info; + std::memcpy(std::addressof(level_hash_info), + std::addressof(meta_info.level_hash_info), + sizeof(level_hash_info)); - R_UNLESS(IntegrityMinLayerCount <= level_hash_info.max_layers, - ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount); - R_UNLESS(level_hash_info.max_layers <= IntegrityMaxLayerCount, - ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount); + R_UNLESS(IntegrityMinLayerCount <= level_hash_info.max_layers, + ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount); + R_UNLESS(level_hash_info.max_layers <= IntegrityMaxLayerCount, + ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount); - // Get the base storage size. - s64 base_storage_size = base_storage->GetSize(); + // Get the base storage size. + s64 base_storage_size = base_storage->GetSize(); - // Create storage info. - StorageInfo storage_info; - for (s32 i = 0; i < static_cast(level_hash_info.max_layers - 2); ++i) { - const auto& layer_info = level_hash_info.info[i]; - R_UNLESS(layer_info_offset + layer_info.offset + layer_info.size <= base_storage_size, - ResultNcaBaseStorageOutOfRangeD); - - storage_info[i + 1] = std::make_shared( - base_storage, layer_info.size, layer_info_offset + layer_info.offset); - } - - // Set the last layer info. - const auto& layer_info = level_hash_info.info[level_hash_info.max_layers - 2]; - const s64 last_layer_info_offset = layer_info_offset > 0 ? 0LL : layer_info.offset.Get(); - R_UNLESS(last_layer_info_offset + layer_info.size <= base_storage_size, + // Create storage info. + StorageInfo storage_info; + for (s32 i = 0; i < static_cast(level_hash_info.max_layers - 2); ++i) { + const auto& layer_info = level_hash_info.info[i]; + R_UNLESS(layer_info_offset + layer_info.offset + layer_info.size <= base_storage_size, ResultNcaBaseStorageOutOfRangeD); - if (layer_info_offset > 0) { - R_UNLESS(last_layer_info_offset + layer_info.size <= layer_info_offset, - ResultRomNcaInvalidIntegrityLayerInfoOffset); - } - storage_info[level_hash_info.max_layers - 1] = std::make_shared( - std::move(base_storage), layer_info.size, last_layer_info_offset); - // Make the integrity romfs storage. - auto integrity_storage = std::make_shared(); - R_UNLESS(integrity_storage != nullptr, ResultAllocationMemoryFailedAllocateShared); - - // Initialize the integrity storage. - R_TRY(integrity_storage->Initialize(level_hash_info, meta_info.master_hash, storage_info, - max_data_cache_entries, max_hash_cache_entries, - buffer_level)); - - // Set the output. - *out = std::move(integrity_storage); - R_SUCCEED(); - } else { - // Read IVFC layout - HierarchicalIntegrityVerificationInformation lhi{}; - std::memcpy(std::addressof(lhi), std::addressof(meta_info.level_hash_info), sizeof(lhi)); - - R_UNLESS(IntegrityMinLayerCount <= lhi.max_layers, - ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount); - R_UNLESS(lhi.max_layers <= IntegrityMaxLayerCount, - ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount); - - const auto& data_li = lhi.info[lhi.max_layers - 2]; - - const s64 base_size = base_storage->GetSize(); - - // Compute the data layer window - const s64 data_off = (layer_info_offset > 0) ? 0LL : data_li.offset.Get(); - R_UNLESS(data_off + data_li.size <= base_size, ResultNcaBaseStorageOutOfRangeD); - if (layer_info_offset > 0) { - R_UNLESS(data_off + data_li.size <= layer_info_offset, - ResultRomNcaInvalidIntegrityLayerInfoOffset); - } - - // TODO: Passthrough (temporary compatibility: integrity disabled) - auto data_view = std::make_shared(base_storage, data_li.size, data_off); - R_UNLESS(data_view != nullptr, ResultAllocationMemoryFailedAllocateShared); - - auto passthrough = std::make_shared(std::move(data_view)); - R_UNLESS(passthrough != nullptr, ResultAllocationMemoryFailedAllocateShared); - - *out = std::move(passthrough); - R_SUCCEED(); + storage_info[i + 1] = std::make_shared(base_storage, + layer_info.size, + layer_info_offset + layer_info.offset); } + + // Set the last layer info. + const auto& layer_info = level_hash_info.info[level_hash_info.max_layers - 2]; + const s64 last_layer_info_offset = layer_info_offset > 0 ? 0LL : layer_info.offset.Get(); + R_UNLESS(last_layer_info_offset + layer_info.size <= base_storage_size, + ResultNcaBaseStorageOutOfRangeD); + if (layer_info_offset > 0) { + R_UNLESS(last_layer_info_offset + layer_info.size <= layer_info_offset, + ResultRomNcaInvalidIntegrityLayerInfoOffset); + } + storage_info[level_hash_info.max_layers - 1] + = std::make_shared(std::move(base_storage), + layer_info.size, + last_layer_info_offset); + + // Make the integrity romfs storage. + auto integrity_storage = std::make_shared(); + R_UNLESS(integrity_storage != nullptr, ResultAllocationMemoryFailedAllocateShared); + + // Initialize the integrity storage. + R_TRY(integrity_storage->Initialize(level_hash_info, + meta_info.master_hash, + storage_info, + max_data_cache_entries, + max_hash_cache_entries, + buffer_level)); + + // Set the output. + *out = std::move(integrity_storage); + R_SUCCEED(); } Result NcaFileSystemDriver::CreateRegionSwitchStorage(VirtualFile* out, diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index 1acf8344a1..9d292da401 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -1,6 +1,10 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + # SPDX-FileCopyrightText: 2023 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later +find_package(Qt6 REQUIRED COMPONENTS Core) find_package(Qt6 REQUIRED COMPONENTS Core) add_library(qt_common STATIC @@ -22,6 +26,8 @@ add_library(qt_common STATIC qt_content_util.h qt_content_util.cpp qt_rom_util.h qt_rom_util.cpp qt_applet_util.h qt_applet_util.cpp + qt_progress_dialog.h qt_progress_dialog.cpp + ) create_target_directory_groups(qt_common) @@ -33,7 +39,8 @@ endif() add_subdirectory(externals) -target_link_libraries(qt_common PRIVATE core Qt6::Core SimpleIni::SimpleIni QuaZip::QuaZip) +target_link_libraries(qt_common PRIVATE core Qt6::Core SimpleIni::SimpleIni QuaZip::QuaZip frozen::frozen) +target_link_libraries(qt_common PRIVATE Qt6::Core) if (NOT WIN32) target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) diff --git a/src/qt_common/externals/CMakeLists.txt b/src/qt_common/externals/CMakeLists.txt index 50594a741f..189a52c0a6 100644 --- a/src/qt_common/externals/CMakeLists.txt +++ b/src/qt_common/externals/CMakeLists.txt @@ -14,3 +14,7 @@ set_directory_properties(PROPERTIES EXCLUDE_FROM_ALL ON) # QuaZip AddJsonPackage(quazip) + +# frozen +# TODO(crueter): Qt String Lookup +AddJsonPackage(frozen) diff --git a/src/qt_common/externals/cpmfile.json b/src/qt_common/externals/cpmfile.json index e3590d0f7f..0b464b95b2 100644 --- a/src/qt_common/externals/cpmfile.json +++ b/src/qt_common/externals/cpmfile.json @@ -8,5 +8,12 @@ "options": [ "QUAZIP_INSTALL OFF" ] + }, + "frozen": { + "package": "frozen", + "repo": "serge-sans-paille/frozen", + "sha": "61dce5ae18", + "hash": "1ae3d073e659c1f24b2cdd76379c90d6af9e06bc707d285a4fafce05f7a4c9e592ff208c94a9ae0f0d07620b3c6cec191f126b03d70ad4dfa496a86ed5658a6d", + "bundled": true } } diff --git a/src/qt_common/qt_common.cpp b/src/qt_common/qt_common.cpp index 9c20f1e6d9..6be241c740 100644 --- a/src/qt_common/qt_common.cpp +++ b/src/qt_common/qt_common.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "qt_common.h" +#include "common/fs/fs.h" #include #include @@ -22,9 +23,15 @@ namespace QtCommon { -QObject *rootObject = nullptr; +#ifdef YUZU_QT_WIDGETS +QWidget* rootObject = nullptr; +#else +QObject* rootObject = nullptr; +#endif + std::unique_ptr system = nullptr; std::shared_ptr vfs = nullptr; +std::unique_ptr provider = nullptr; Core::Frontend::WindowSystemType GetWindowSystemType() { @@ -81,11 +88,35 @@ const QString tr(const std::string& str) return QGuiApplication::tr(str.c_str()); } +#ifdef YUZU_QT_WIDGETS +void Init(QWidget* root) +#else void Init(QObject* root) +#endif { system = std::make_unique(); rootObject = root; vfs = std::make_unique(); + provider = std::make_unique(); +} + +std::filesystem::path GetEdenCommand() { + std::filesystem::path command; + + QString appimage = QString::fromLocal8Bit(getenv("APPIMAGE")); + if (!appimage.isEmpty()) { + command = std::filesystem::path{appimage.toStdString()}; + } else { + const QStringList args = QGuiApplication::arguments(); + command = args[0].toStdString(); + } + + // If relative path, make it an absolute path + if (command.c_str()[0] == '.') { + command = Common::FS::GetCurrentDir() / command; + } + + return command; } } // namespace QtCommon diff --git a/src/qt_common/qt_common.h b/src/qt_common/qt_common.h index 5f9b5d7de9..a2700427ab 100644 --- a/src/qt_common/qt_common.h +++ b/src/qt_common/qt_common.h @@ -4,18 +4,25 @@ #ifndef QT_COMMON_H #define QT_COMMON_H -#include #include #include "core/core.h" +#include "core/file_sys/registered_cache.h" #include +#include #include namespace QtCommon { +#ifdef YUZU_QT_WIDGETS +extern QWidget *rootObject; +#else extern QObject *rootObject; +#endif + extern std::unique_ptr system; extern std::shared_ptr vfs; +extern std::unique_ptr provider; typedef std::function QtProgressCallback; @@ -23,10 +30,15 @@ Core::Frontend::WindowSystemType GetWindowSystemType(); Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow *window); +#ifdef YUZU_QT_WIDGETS +void Init(QWidget *root); +#else void Init(QObject *root); +#endif const QString tr(const char *str); const QString tr(const std::string &str); +std::filesystem::path GetEdenCommand(); } // namespace QtCommon #endif diff --git a/src/qt_common/qt_content_util.cpp b/src/qt_common/qt_content_util.cpp index 5f8ca14504..e4625aa423 100644 --- a/src/qt_common/qt_content_util.cpp +++ b/src/qt_common/qt_content_util.cpp @@ -6,6 +6,7 @@ #include "frontend_common/content_manager.h" #include "frontend_common/firmware_manager.h" #include "qt_common/qt_common.h" +#include "qt_common/qt_progress_dialog.h" #include "qt_frontend_util.h" #include @@ -31,24 +32,34 @@ bool CheckGameFirmware(u64 program_id, QObject* parent) return true; } -FirmwareInstallResult InstallFirmware(const QString& location, - bool recursive, - QtProgressCallback callback, - FileSys::VfsFilesystem* vfs) +void InstallFirmware(const QString& location, bool recursive) { - static constexpr const char* failedTitle = "Firmware Install Failed"; - static constexpr const char* successTitle = "Firmware Install Failed"; - static constexpr QMessageBox::StandardButtons buttons = QMessageBox::Ok; + QtCommon::Frontend::QtProgressDialog progress(tr("Installing Firmware..."), + tr("Cancel"), + 0, + 100, + rootObject); + progress.setWindowModality(Qt::WindowModal); + progress.setMinimumDuration(100); + progress.setAutoClose(false); + progress.setAutoReset(false); + progress.show(); + // Declare progress callback. + auto callback = [&](size_t total_size, size_t processed_size) { + progress.setValue(static_cast((processed_size * 100) / total_size)); + return progress.wasCanceled(); + }; + + static constexpr const char* failedTitle = "Firmware Install Failed"; + static constexpr const char* successTitle = "Firmware Install Succeeded"; QMessageBox::Icon icon; FirmwareInstallResult result; const auto ShowMessage = [&]() { QtCommon::Frontend::ShowMessage(icon, failedTitle, - GetFirmwareInstallResultString(result), - buttons, - rootObject); + GetFirmwareInstallResultString(result)); }; LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString()); @@ -57,7 +68,7 @@ FirmwareInstallResult InstallFirmware(const QString& location, // there.) std::filesystem::path firmware_source_path = location.toStdString(); if (!Common::FS::IsDir(firmware_source_path)) { - return FirmwareInstallResult::NoOp; + return; } std::vector out; @@ -86,7 +97,7 @@ FirmwareInstallResult InstallFirmware(const QString& location, result = FirmwareInstallResult::NoNCAs; icon = QMessageBox::Warning; ShowMessage(); - return result; + return; } // Locate and erase the content of nand/system/Content/registered/*.nca, if any. @@ -96,7 +107,7 @@ FirmwareInstallResult InstallFirmware(const QString& location, result = FirmwareInstallResult::FailedDelete; icon = QMessageBox::Critical; ShowMessage(); - return result; + return; } LOG_INFO(Frontend, @@ -127,7 +138,7 @@ FirmwareInstallResult InstallFirmware(const QString& location, result = FirmwareInstallResult::FailedCorrupted; icon = QMessageBox::Warning; ShowMessage(); - return result; + return; } } @@ -135,12 +146,34 @@ FirmwareInstallResult InstallFirmware(const QString& location, result = FirmwareInstallResult::FailedCopy; icon = QMessageBox::Critical; ShowMessage(); - return result; + return; } // Re-scan VFS for the newly placed firmware files. system->GetFileSystemController().CreateFactories(*vfs); + auto VerifyFirmwareCallback = [&](size_t total_size, size_t processed_size) { + progress.setValue(90 + static_cast((processed_size * 10) / total_size)); + return progress.wasCanceled(); + }; + + auto results = ContentManager::VerifyInstalledContents(*QtCommon::system, + *QtCommon::provider, + VerifyFirmwareCallback, + true); + + if (results.size() > 0) { + const auto failed_names = QString::fromStdString( + fmt::format("{}", fmt::join(results, "\n"))); + progress.close(); + QtCommon::Frontend::Critical(tr("Firmware integrity verification failed!"), + tr("Verification failed for the following files:\n\n%1") + .arg(failed_names)); + return; + } + + progress.close(); + const auto pair = FirmwareManager::GetFirmwareVersion(*system); const auto firmware_data = pair.first; const std::string display_version(firmware_data.display_version.data()); @@ -149,9 +182,7 @@ FirmwareInstallResult InstallFirmware(const QString& location, QtCommon::Frontend::Information(rootObject, tr(successTitle), tr(GetFirmwareInstallResultString(result)) - .arg(QString::fromStdString(display_version)), - buttons); - return result; + .arg(QString::fromStdString(display_version))); } QString UnzipFirmwareToTmp(const QString& location) @@ -179,8 +210,23 @@ QString UnzipFirmwareToTmp(const QString& location) } // Content // -void VerifyGameContents(const std::string& game_path, QtProgressCallback callback) +void VerifyGameContents(const std::string& game_path) { + QtCommon::Frontend::QtProgressDialog progress(tr("Verifying integrity..."), + tr("Cancel"), + 0, + 100, + rootObject); + progress.setWindowModality(Qt::WindowModal); + progress.setMinimumDuration(100); + progress.setAutoClose(false); + progress.setAutoReset(false); + + const auto callback = [&](size_t total_size, size_t processed_size) { + progress.setValue(static_cast((processed_size * 100) / total_size)); + return progress.wasCanceled(); + }; + const auto result = ContentManager::VerifyGameContents(*system, game_path, callback); switch (result) { @@ -234,4 +280,34 @@ void InstallKeys() } } +void VerifyInstalledContents() { + // Initialize a progress dialog. + QtCommon::Frontend::QtProgressDialog progress(tr("Verifying integrity..."), tr("Cancel"), 0, 100, QtCommon::rootObject); + progress.setWindowModality(Qt::WindowModal); + progress.setMinimumDuration(100); + progress.setAutoClose(false); + progress.setAutoReset(false); + + // Declare progress callback. + auto QtProgressCallback = [&](size_t total_size, size_t processed_size) { + progress.setValue(static_cast((processed_size * 100) / total_size)); + return progress.wasCanceled(); + }; + + const std::vector result = + ContentManager::VerifyInstalledContents(*QtCommon::system, *QtCommon::provider, QtProgressCallback); + progress.close(); + + if (result.empty()) { + QtCommon::Frontend::Information(tr("Integrity verification succeeded!"), + tr("The operation completed successfully.")); + } else { + const auto failed_names = + QString::fromStdString(fmt::format("{}", fmt::join(result, "\n"))); + QtCommon::Frontend::Critical( + tr("Integrity verification failed!"), + tr("Verification failed for the following files:\n\n%1").arg(failed_names)); + } +} + } // namespace QtCommon::Content diff --git a/src/qt_common/qt_content_util.h b/src/qt_common/qt_content_util.h index b401bdf1e3..b572c1c4a3 100644 --- a/src/qt_common/qt_content_util.h +++ b/src/qt_common/qt_content_util.h @@ -6,8 +6,6 @@ #include #include "common/common_types.h" -#include "core/core.h" -#include "qt_common/qt_common.h" namespace QtCommon::Content { @@ -37,11 +35,7 @@ inline constexpr const char *GetFirmwareInstallResultString(FirmwareInstallResul return FIRMWARE_RESULTS.at(static_cast(result)); } -FirmwareInstallResult InstallFirmware( - const QString &location, - bool recursive, - QtProgressCallback callback, - FileSys::VfsFilesystem *vfs); +void InstallFirmware(const QString &location, bool recursive); QString UnzipFirmwareToTmp(const QString &location); @@ -49,6 +43,7 @@ QString UnzipFirmwareToTmp(const QString &location); void InstallKeys(); // Content // -void VerifyGameContents(const std::string &game_path, QtProgressCallback callback); +void VerifyGameContents(const std::string &game_path); +void VerifyInstalledContents(); } #endif // QT_CONTENT_UTIL_H diff --git a/src/qt_common/qt_frontend_util.cpp b/src/qt_common/qt_frontend_util.cpp index d357c11338..d519669ad5 100644 --- a/src/qt_common/qt_frontend_util.cpp +++ b/src/qt_common/qt_frontend_util.cpp @@ -10,11 +10,8 @@ namespace QtCommon::Frontend { -QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, - const QString &title, - const QString &text, - QMessageBox::StandardButtons buttons, - QObject *parent) +StandardButton ShowMessage( + Icon icon, const QString &title, const QString &text, StandardButtons buttons, QObject *parent) { #ifdef YUZU_QT_WIDGETS QMessageBox *box = new QMessageBox(icon, title, text, buttons, (QWidget *) parent); diff --git a/src/qt_common/qt_frontend_util.h b/src/qt_common/qt_frontend_util.h index 7f43286430..f86b9e1357 100644 --- a/src/qt_common/qt_frontend_util.h +++ b/src/qt_common/qt_frontend_util.h @@ -5,12 +5,12 @@ #define QT_FRONTEND_UTIL_H #include -#include #include "qt_common/qt_common.h" #ifdef YUZU_QT_WIDGETS #include #include +#include #endif /** @@ -23,6 +23,11 @@ Q_NAMESPACE #ifdef YUZU_QT_WIDGETS using Options = QFileDialog::Options; using Option = QFileDialog::Option; + +using StandardButton = QMessageBox::StandardButton; +using StandardButtons = QMessageBox::StandardButtons; + +using Icon = QMessageBox::Icon; #else enum Option { ShowDirsOnly = 0x00000001, @@ -36,44 +41,96 @@ enum Option { Q_ENUM_NS(Option) Q_DECLARE_FLAGS(Options, Option) Q_FLAG_NS(Options) + +enum StandardButton { + // keep this in sync with QDialogButtonBox::StandardButton and QPlatformDialogHelper::StandardButton + NoButton = 0x00000000, + Ok = 0x00000400, + Save = 0x00000800, + SaveAll = 0x00001000, + Open = 0x00002000, + Yes = 0x00004000, + YesToAll = 0x00008000, + No = 0x00010000, + NoToAll = 0x00020000, + Abort = 0x00040000, + Retry = 0x00080000, + Ignore = 0x00100000, + Close = 0x00200000, + Cancel = 0x00400000, + Discard = 0x00800000, + Help = 0x01000000, + Apply = 0x02000000, + Reset = 0x04000000, + RestoreDefaults = 0x08000000, + + FirstButton = Ok, // internal + LastButton = RestoreDefaults, // internal + + YesAll = YesToAll, // obsolete + NoAll = NoToAll, // obsolete + + Default = 0x00000100, // obsolete + Escape = 0x00000200, // obsolete + FlagMask = 0x00000300, // obsolete + ButtonMask = ~FlagMask // obsolete +}; +Q_ENUM_NS(StandardButton) + +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) +typedef StandardButton Button; +#endif +Q_DECLARE_FLAGS(StandardButtons, StandardButton) +Q_FLAG_NS(StandardButtons) + +enum Icon { + // keep this in sync with QMessageDialogOptions::StandardIcon + NoIcon = 0, + Information = 1, + Warning = 2, + Critical = 3, + Question = 4 +}; +Q_ENUM_NS(Icon) + #endif // TODO(crueter) widgets-less impl, choices et al. -QMessageBox::StandardButton ShowMessage(QMessageBox::Icon icon, +StandardButton ShowMessage(Icon icon, const QString &title, const QString &text, - QMessageBox::StandardButtons buttons = QMessageBox::NoButton, + StandardButtons buttons = StandardButton::NoButton, QObject *parent = nullptr); #define UTIL_OVERRIDES(level) \ - inline QMessageBox::StandardButton level(QObject *parent, \ + inline StandardButton level(QObject *parent, \ const QString &title, \ const QString &text, \ - QMessageBox::StandardButtons buttons = QMessageBox::Ok) \ + StandardButtons buttons = StandardButton::Ok) \ { \ - return ShowMessage(QMessageBox::level, title, text, buttons, parent); \ + return ShowMessage(Icon::level, title, text, buttons, parent); \ } \ - inline QMessageBox::StandardButton level(QObject *parent, \ + inline StandardButton level(QObject *parent, \ const char *title, \ const char *text, \ - QMessageBox::StandardButtons buttons \ - = QMessageBox::Ok) \ + StandardButtons buttons \ + = StandardButton::Ok) \ { \ - return ShowMessage(QMessageBox::level, tr(title), tr(text), buttons, parent); \ + return ShowMessage(Icon::level, tr(title), tr(text), buttons, parent); \ } \ - inline QMessageBox::StandardButton level(const char *title, \ + inline StandardButton level(const char *title, \ const char *text, \ - QMessageBox::StandardButtons buttons \ - = QMessageBox::Ok) \ + StandardButtons buttons \ + = StandardButton::Ok) \ { \ - return ShowMessage(QMessageBox::level, tr(title), tr(text), buttons, rootObject); \ + return ShowMessage(Icon::level, tr(title), tr(text), buttons, rootObject); \ } \ - inline QMessageBox::StandardButton level(const QString title, \ + inline StandardButton level(const QString title, \ const QString &text, \ - QMessageBox::StandardButtons buttons \ - = QMessageBox::Ok) \ + StandardButtons buttons \ + = StandardButton::Ok) \ { \ - return ShowMessage(QMessageBox::level, title, text, buttons, rootObject); \ + return ShowMessage(Icon::level, title, text, buttons, rootObject); \ } UTIL_OVERRIDES(Information) diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp index 488eb8c971..292eefa224 100644 --- a/src/qt_common/qt_game_util.cpp +++ b/src/qt_common/qt_game_util.cpp @@ -5,12 +5,15 @@ #include "common/fs/fs.h" #include "common/fs/path_util.h" #include "core/file_sys/savedata_factory.h" +#include "core/hle/service/am/am_types.h" #include "frontend_common/content_manager.h" #include "qt_common.h" #include "qt_common/uisettings.h" #include "qt_frontend_util.h" +#include "yuzu/util/util.h" #include +#include #include #ifdef _WIN32 @@ -397,4 +400,178 @@ void ResetMetadata() } } +// Uhhh // + +// Messages in pre-defined message boxes for less code spaghetti +inline constexpr bool CreateShortcutMessagesGUI(ShortcutMessages imsg, const QString& game_title) +{ + int result = 0; + QMessageBox::StandardButtons buttons; + switch (imsg) { + case ShortcutMessages::Fullscreen: + buttons = QMessageBox::Yes | QMessageBox::No; + result + = QtCommon::Frontend::Information(tr("Create Shortcut"), + tr("Do you want to launch the game in fullscreen?"), + buttons); + return result == QMessageBox::Yes; + case ShortcutMessages::Success: + QtCommon::Frontend::Information(tr("Shortcut Created"), + tr("Successfully created a shortcut to %1").arg(game_title)); + return false; + case ShortcutMessages::Volatile: + buttons = QMessageBox::StandardButton::Ok | QMessageBox::StandardButton::Cancel; + result = QtCommon::Frontend::Warning( + tr("Shortcut may be Volatile!"), + tr("This will create a shortcut to the current AppImage. This may " + "not work well if you update. Continue?"), + buttons); + return result == QMessageBox::Ok; + default: + buttons = QMessageBox::Ok; + QtCommon::Frontend::Critical(tr("Failed to Create Shortcut"), + tr("Failed to create a shortcut to %1").arg(game_title), + buttons); + return false; + } +} + +void CreateShortcut(const std::string& game_path, + const u64 program_id, + const std::string& game_title_, + const ShortcutTarget &target, + std::string arguments_, + const bool needs_title) +{ + // Get path to Eden executable + std::filesystem::path command = GetEdenCommand(); + + // Shortcut path + std::filesystem::path shortcut_path = GetShortcutPath(target); + + if (!std::filesystem::exists(shortcut_path)) { + CreateShortcutMessagesGUI(ShortcutMessages::Failed, + QString::fromStdString(shortcut_path.generic_string())); + LOG_ERROR(Frontend, "Invalid shortcut target {}", shortcut_path.generic_string()); + return; + } + + const FileSys::PatchManager pm{program_id, QtCommon::system->GetFileSystemController(), + QtCommon::system->GetContentProvider()}; + const auto control = pm.GetControlMetadata(); + const auto loader = + Loader::GetLoader(*QtCommon::system, QtCommon::vfs->OpenFile(game_path, FileSys::OpenMode::Read)); + + std::string game_title{game_title_}; + + // Delete illegal characters from title + if (needs_title) { + game_title = fmt::format("{:016X}", program_id); + if (control.first != nullptr) { + game_title = control.first->GetApplicationName(); + } else { + loader->ReadTitle(game_title); + } + } + + const std::string illegal_chars = "<>:\"/\\|?*."; + for (auto it = game_title.rbegin(); it != game_title.rend(); ++it) { + if (illegal_chars.find(*it) != std::string::npos) { + game_title.erase(it.base() - 1); + } + } + + const QString qgame_title = QString::fromStdString(game_title); + + // Get icon from game file + std::vector icon_image_file{}; + if (control.second != nullptr) { + icon_image_file = control.second->ReadAllBytes(); + } else if (loader->ReadIcon(icon_image_file) != Loader::ResultStatus::Success) { + LOG_WARNING(Frontend, "Could not read icon from {:s}", game_path); + } + + QImage icon_data = + QImage::fromData(icon_image_file.data(), static_cast(icon_image_file.size())); + std::filesystem::path out_icon_path; + if (QtCommon::Game::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) { + if (!SaveIconToFile(out_icon_path, icon_data)) { + LOG_ERROR(Frontend, "Could not write icon to file"); + } + } else { + QtCommon::Frontend::Critical( + tr("Create Icon"), + tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.") + .arg(QString::fromStdString(out_icon_path.string()))); + } + +#if defined(__unix__) && !defined(__APPLE__) && !defined(__ANDROID__) + // Special case for AppImages + // Warn once if we are making a shortcut to a volatile AppImage + if (command.string().ends_with(".AppImage") && !UISettings::values.shortcut_already_warned) { + if (!CreateShortcutMessagesGUI(ShortcutMessages::Volatile, qgame_title)) { + return; + } + UISettings::values.shortcut_already_warned = true; + } +#endif + + // Create shortcut + std::string arguments{arguments_}; + if (CreateShortcutMessagesGUI(ShortcutMessages::Fullscreen, qgame_title)) { + arguments = "-f " + arguments; + } + const std::string comment = fmt::format("Start {:s} with the Eden Emulator", game_title); + const std::string categories = "Game;Emulator;Qt;"; + const std::string keywords = "Switch;Nintendo;"; + + if (QtCommon::Game::CreateShortcutLink(shortcut_path, comment, out_icon_path, command, + arguments, categories, keywords, game_title)) { + CreateShortcutMessagesGUI(ShortcutMessages::Success, + qgame_title); + return; + } + CreateShortcutMessagesGUI(ShortcutMessages::Failed, + qgame_title); +} + +constexpr std::string GetShortcutPath(ShortcutTarget target) { + { + std::string shortcut_path{}; + if (target == ShortcutTarget::Desktop) { + shortcut_path = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation) + .toStdString(); + } else if (target == ShortcutTarget::Applications) { + shortcut_path = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + .toStdString(); + } + + return shortcut_path; + } +} + +void CreateHomeMenuShortcut(ShortcutTarget target) { + constexpr u64 QLaunchId = static_cast(Service::AM::AppletProgramId::QLaunch); + auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); + if (!bis_system) { + QtCommon::Frontend::Warning(tr("No firmware available"), + tr("Please install firmware to use the home menu.")); + return; + } + + auto qlaunch_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program); + if (!qlaunch_nca) { + QtCommon::Frontend::Warning(tr("Home Menu Applet"), + tr("Home Menu is not available. Please reinstall firmware.")); + return; + } + + auto qlaunch_applet_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program); + const auto game_path = qlaunch_applet_nca->GetFullPath(); + + // TODO(crueter): Make this use the Eden icon + CreateShortcut(game_path, QLaunchId, "Switch Home Menu", target, "-qlaunch", false); +} + + } // namespace QtCommon::Game diff --git a/src/qt_common/qt_game_util.h b/src/qt_common/qt_game_util.h index 9861910833..2872734390 100644 --- a/src/qt_common/qt_game_util.h +++ b/src/qt_common/qt_game_util.h @@ -5,6 +5,7 @@ #define QT_GAME_UTIL_H #include +#include #include "common/fs/path_util.h" #include @@ -24,6 +25,18 @@ enum class GameListRemoveTarget { CacheStorage, }; +enum class ShortcutTarget { + Desktop, + Applications, +}; + +enum class ShortcutMessages{ + Fullscreen = 0, + Success = 1, + Volatile = 2, + Failed = 3 +}; + bool CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::string& comment, const std::filesystem::path& icon_path, @@ -57,6 +70,17 @@ void RemoveCacheStorage(u64 program_id, FileSys::VfsFilesystem* vfs); // Metadata // void ResetMetadata(); +// Shortcuts // +void CreateShortcut(const std::string& game_path, + const u64 program_id, + const std::string& game_title_, + const ShortcutTarget& target, + std::string arguments_, + const bool needs_title); + +constexpr std::string GetShortcutPath(ShortcutTarget target); +void CreateHomeMenuShortcut(ShortcutTarget target); + } #endif // QT_GAME_UTIL_H diff --git a/src/qt_common/qt_progress_dialog.cpp b/src/qt_common/qt_progress_dialog.cpp new file mode 100644 index 0000000000..b4bf74c8bd --- /dev/null +++ b/src/qt_common/qt_progress_dialog.cpp @@ -0,0 +1,4 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "qt_progress_dialog.h" diff --git a/src/qt_common/qt_progress_dialog.h b/src/qt_common/qt_progress_dialog.h new file mode 100644 index 0000000000..17f6817ffa --- /dev/null +++ b/src/qt_common/qt_progress_dialog.h @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef QT_PROGRESS_DIALOG_H +#define QT_PROGRESS_DIALOG_H + +#include + +#ifdef YUZU_QT_WIDGETS +#include +#endif + +namespace QtCommon::Frontend { +#ifdef YUZU_QT_WIDGETS + +using QtProgressDialog = QProgressDialog; + +// TODO(crueter): QML impl +#else +class QtProgressDialog +{ +public: + QtProgressDialog(const QString &labelText, + const QString &cancelButtonText, + int minimum, + int maximum, + QObject *parent = nullptr, + Qt::WindowFlags f = Qt::WindowFlags()); + + bool wasCanceled() const; + void setWindowModality(Qt::WindowModality modality); + void setMinimumDuration(int durationMs); + void setAutoClose(bool autoClose); + void setAutoReset(bool autoReset); + +public slots: + void setLabelText(QString &text); + void setRange(int min, int max); + void setValue(int progress); + bool close(); + + void show(); +}; +#endif // YUZU_QT_WIDGETS + +} +#endif // QT_PROGRESS_DIALOG_H diff --git a/src/qt_common/shared_translation.cpp b/src/qt_common/shared_translation.cpp index 81ec35b6d8..8f31e07154 100644 --- a/src/qt_common/shared_translation.cpp +++ b/src/qt_common/shared_translation.cpp @@ -29,10 +29,10 @@ std::unique_ptr InitializeTranslations(QObject* parent) #define INSERT(SETTINGS, ID, NAME, TOOLTIP) \ translations->insert(std::pair{SETTINGS::values.ID.Id(), std::pair{(NAME), (TOOLTIP)}}) - // A setting can be ignored by giving it a blank name + // A setting can be ignored by giving it a blank name - // Applets - INSERT(Settings, cabinet_applet_mode, tr("Amiibo editor"), QString()); + // Applets + INSERT(Settings, cabinet_applet_mode, tr("Amiibo editor"), QString()); INSERT(Settings, controller_applet_mode, tr("Controller configuration"), QString()); INSERT(Settings, data_erase_applet_mode, tr("Data erase"), QString()); INSERT(Settings, error_applet_mode, tr("Error"), QString()); @@ -407,12 +407,6 @@ std::unique_ptr InitializeTranslations(QObject* parent) "their resolution, details and supported controllers and depending on this setting.\n" "Setting to Handheld can help improve performance for low end systems.")); INSERT(Settings, current_user, QString(), QString()); - INSERT(Settings, disable_nca_verification, tr("Disable NCA Verification"), - tr("Disables integrity verification of NCA content archives." - "\nThis may improve loading speed but risks data corruption or invalid files going " - "undetected.\n" - "Is necessary to make games and updates work that needs firmware 20+.")); - INSERT(Settings, hide_nca_verification_popup, QString(), QString()); // Controls diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 7c89730651..fa61cdfb1f 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -650,10 +650,10 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri // TODO: Implement shortcut creation for macOS #if !defined(__APPLE__) connect(create_desktop_shortcut, &QAction::triggered, [this, program_id, path]() { - emit CreateShortcut(program_id, path, GameListShortcutTarget::Desktop); + emit CreateShortcut(program_id, path, QtCommon::Game::ShortcutTarget::Desktop); }); connect(create_applications_menu_shortcut, &QAction::triggered, [this, program_id, path]() { - emit CreateShortcut(program_id, path, GameListShortcutTarget::Applications); + emit CreateShortcut(program_id, path, QtCommon::Game::ShortcutTarget::Applications); }); #endif connect(properties, &QAction::triggered, diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 367d047c40..94e7b2dc42 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h @@ -52,11 +52,6 @@ enum class DumpRomFSTarget { SDMC, }; -enum class GameListShortcutTarget { - Desktop, - Applications, -}; - class GameList : public QWidget { Q_OBJECT @@ -113,7 +108,7 @@ signals: void VerifyIntegrityRequested(const std::string& game_path); void CopyTIDRequested(u64 program_id); void CreateShortcut(u64 program_id, const std::string& game_path, - GameListShortcutTarget target); + const QtCommon::Game::ShortcutTarget target); void NavigateToGamedbEntryRequested(u64 program_id, const CompatibilityList& compatibility_list); void OpenPerGameGeneralRequested(const std::string& file); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 728ed2068c..0d7a08d63d 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1,21 +1,22 @@ // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later +#include "core/hle/service/am/applet_manager.h" +#include "core/loader/nca.h" +#include "core/tools/renderdoc.h" +#include "frontend_common/firmware_manager.h" +#include "qt_common/qt_common.h" +#include "qt_common/qt_content_util.h" +#include "qt_common/qt_game_util.h" +#include "qt_common/qt_meta.h" +#include "qt_common/qt_path_util.h" +#include "qt_common/qt_progress_dialog.h" #include #include #include #include #include #include -#include "core/hle/service/am/applet_manager.h" -#include "core/loader/nca.h" -#include "core/tools/renderdoc.h" -#include "frontend_common/firmware_manager.h" -#include "qt_common/qt_common.h" -#include "qt_common/qt_game_util.h" -#include "qt_common/qt_path_util.h" -#include "qt_common/qt_meta.h" -#include "qt_common/qt_content_util.h" #ifdef __APPLE__ #include // for chdir @@ -398,8 +399,7 @@ inline static bool isDarkMode() { GMainWindow::GMainWindow(bool has_broken_vulkan) : ui{std::make_unique()}, - input_subsystem{std::make_shared()}, user_data_migrator{this}, - provider{std::make_unique()} { + input_subsystem{std::make_shared()}, user_data_migrator{this} { QtCommon::Init(this); Common::FS::CreateEdenPaths(); @@ -543,7 +543,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) QtCommon::system->SetContentProvider(std::make_unique()); QtCommon::system->RegisterContentProvider(FileSys::ContentProviderUnionSlot::FrontendManual, - provider.get()); + QtCommon::provider.get()); QtCommon::system->GetFileSystemController().CreateFactories(*QtCommon::vfs); // Remove cached contents generated during the previous session @@ -1091,7 +1091,7 @@ void GMainWindow::InitializeWidgets() { render_window = new GRenderWindow(this, emu_thread.get(), input_subsystem, *QtCommon::system); render_window->hide(); - game_list = new GameList(QtCommon::vfs, provider.get(), *play_time_manager, *QtCommon::system, this); + game_list = new GameList(QtCommon::vfs, QtCommon::provider.get(), *play_time_manager, *QtCommon::system, this); ui->horizontalLayout->addWidget(game_list); game_list_placeholder = new GameListPlaceholder(this); @@ -1913,10 +1913,6 @@ bool GMainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletPa return false; } - if (!OnCheckNcaVerification()) { - return false; - } - /** Exec */ const Core::SystemResultStatus result{ QtCommon::system->Load(*render_window, filename.toStdString(), params)}; @@ -2023,7 +2019,7 @@ void GMainWindow::ConfigureFilesystemProvider(const std::string& filepath) { u64 program_id = 0; const auto res2 = loader->ReadProgramId(program_id); if (res2 == Loader::ResultStatus::Success && file_type == Loader::FileType::NCA) { - provider->AddEntry(FileSys::TitleType::Application, + QtCommon::provider->AddEntry(FileSys::TitleType::Application, FileSys::GetCRTypeFromNCAType(FileSys::NCA{file}.GetType()), program_id, file); } else if (res2 == Loader::ResultStatus::Success && @@ -2033,7 +2029,7 @@ void GMainWindow::ConfigureFilesystemProvider(const std::string& filepath) { : FileSys::XCI{file}.GetSecurePartitionNSP(); for (const auto& title : nsp->GetNCAs()) { for (const auto& entry : title.second) { - provider->AddEntry(entry.first.first, entry.first.second, title.first, + QtCommon::provider->AddEntry(entry.first.first, entry.first.second, title.first, entry.second->GetBaseFile()); } } @@ -2761,18 +2757,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa // END void GMainWindow::OnGameListVerifyIntegrity(const std::string& game_path) { - QProgressDialog progress(tr("Verifying integrity..."), tr("Cancel"), 0, 100, this); - progress.setWindowModality(Qt::WindowModal); - progress.setMinimumDuration(100); - progress.setAutoClose(false); - progress.setAutoReset(false); - - const auto QtProgressCallback = [&](size_t total_size, size_t processed_size) { - progress.setValue(static_cast((processed_size * 100) / total_size)); - return progress.wasCanceled(); - }; - - QtCommon::Content::VerifyGameContents(game_path, QtProgressCallback); + QtCommon::Content::VerifyGameContents(game_path); } void GMainWindow::OnGameListCopyTID(u64 program_id) { @@ -2793,44 +2778,12 @@ void GMainWindow::OnGameListNavigateToGamedbEntry(u64 program_id, QUrl(QStringLiteral("https://eden-emulator.github.io/game/") + directory)); } -// Messages in pre-defined message boxes for less code spaghetti -// TODO(crueter): Still need to decide what to do re: message boxes w/ qml -bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QString& game_title) { - int result = 0; - QMessageBox::StandardButtons buttons; - switch (imsg) { - case GMainWindow::CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES: - buttons = QMessageBox::Yes | QMessageBox::No; - result = - QMessageBox::information(parent, tr("Create Shortcut"), - tr("Do you want to launch the game in fullscreen?"), buttons); - return result == QMessageBox::Yes; - case GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS: - QMessageBox::information(parent, tr("Create Shortcut"), - tr("Successfully created a shortcut to %1").arg(game_title)); - return false; - case GMainWindow::CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING: - buttons = QMessageBox::StandardButton::Ok | QMessageBox::StandardButton::Cancel; - result = - QMessageBox::warning(this, tr("Create Shortcut"), - tr("This will create a shortcut to the current AppImage. This may " - "not work well if you update. Continue?"), - buttons); - return result == QMessageBox::Ok; - default: - buttons = QMessageBox::Ok; - QMessageBox::critical(parent, tr("Create Shortcut"), - tr("Failed to create a shortcut to %1").arg(game_title), buttons); - return false; - } -} - void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path, - GameListShortcutTarget target) { + const QtCommon::Game::ShortcutTarget target) { // Create shortcut std::string arguments = fmt::format("-g \"{:s}\"", game_path); - CreateShortcut(game_path, program_id, "", target, arguments, true); + QtCommon::Game::CreateShortcut(game_path, program_id, "", target, arguments, true); } void GMainWindow::OnGameListOpenDirectory(const QString& directory) { @@ -3884,74 +3837,11 @@ void GMainWindow::OnOpenLogFolder() } void GMainWindow::OnVerifyInstalledContents() { - // Initialize a progress dialog. - QProgressDialog progress(tr("Verifying integrity..."), tr("Cancel"), 0, 100, this); - progress.setWindowModality(Qt::WindowModal); - progress.setMinimumDuration(100); - progress.setAutoClose(false); - progress.setAutoReset(false); - - // Declare progress callback. - auto QtProgressCallback = [&](size_t total_size, size_t processed_size) { - progress.setValue(static_cast((processed_size * 100) / total_size)); - return progress.wasCanceled(); - }; - - const std::vector result = - ContentManager::VerifyInstalledContents(*QtCommon::system, *provider, QtProgressCallback); - progress.close(); - - if (result.empty()) { - QMessageBox::information(this, tr("Integrity verification succeeded!"), - tr("The operation completed successfully.")); - } else { - const auto failed_names = - QString::fromStdString(fmt::format("{}", fmt::join(result, "\n"))); - QMessageBox::critical( - this, tr("Integrity verification failed!"), - tr("Verification failed for the following files:\n\n%1").arg(failed_names)); - } + QtCommon::Content::VerifyInstalledContents(); } void GMainWindow::InstallFirmware(const QString& location, bool recursive) { - QProgressDialog progress(tr("Installing Firmware..."), tr("Cancel"), 0, 100, this); - progress.setWindowModality(Qt::WindowModal); - progress.setMinimumDuration(100); - progress.setAutoClose(false); - progress.setAutoReset(false); - progress.show(); - - // Declare progress callback. - auto QtProgressCallback = [&](size_t total_size, size_t processed_size) { - progress.setValue(static_cast((processed_size * 100) / total_size)); - return progress.wasCanceled(); - }; - - auto result = QtCommon::Content::InstallFirmware(location, recursive, QtProgressCallback, QtCommon::vfs.get()); - - progress.close(); - - if (result != QtCommon::Content::FirmwareInstallResult::Success) return; - - auto VerifyFirmwareCallback = [&](size_t total_size, size_t processed_size) { - progress.setValue(90 + static_cast((processed_size * 10) / total_size)); - return progress.wasCanceled(); - }; - - auto results = - ContentManager::VerifyInstalledContents(*QtCommon::system, *provider, VerifyFirmwareCallback, true); - - if (results.size() > 0) { - const auto failed_names = - QString::fromStdString(fmt::format("{}", fmt::join(results, "\n"))); - progress.close(); - QMessageBox::critical( - this, tr("Firmware integrity verification failed!"), - tr("Verification failed for the following files:\n\n%1").arg(failed_names)); - return; - } - - progress.close(); + QtCommon::Content::InstallFirmware(location, recursive); OnCheckFirmwareDecryption(); } @@ -4190,8 +4080,6 @@ void GMainWindow::OnHomeMenu() { break; } - // TODO(crueter): So much of this crap is common to qt that I should just move it all tbh - constexpr u64 QLaunchId = static_cast(Service::AM::AppletProgramId::QLaunch); auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); @@ -4233,164 +4121,11 @@ void GMainWindow::OnInitialSetup() { } void GMainWindow::OnCreateHomeMenuDesktopShortcut() { - OnCreateHomeMenuShortcut(GameListShortcutTarget::Desktop); + QtCommon::Game::CreateHomeMenuShortcut(QtCommon::Game::ShortcutTarget::Desktop); } void GMainWindow::OnCreateHomeMenuApplicationMenuShortcut() { - OnCreateHomeMenuShortcut(GameListShortcutTarget::Applications); -} - -std::filesystem::path GMainWindow::GetEdenCommand() { - std::filesystem::path command; - - QString appimage = QString::fromLocal8Bit(getenv("APPIMAGE")); - if (!appimage.isEmpty()) { - command = std::filesystem::path{appimage.toStdString()}; - } else { - const QStringList args = QApplication::arguments(); - command = args[0].toStdString(); - } - - // If relative path, make it an absolute path - if (command.c_str()[0] == '.') { - command = Common::FS::GetCurrentDir() / command; - } - - return command; -} - -std::filesystem::path GMainWindow::GetShortcutPath(GameListShortcutTarget target) { - std::filesystem::path shortcut_path{}; - if (target == GameListShortcutTarget::Desktop) { - shortcut_path = - QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).toStdString(); - } else if (target == GameListShortcutTarget::Applications) { - shortcut_path = - QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).toStdString(); - } - - return shortcut_path; -} - -// TODO(crueter): Migrate -void GMainWindow::CreateShortcut(const std::string &game_path, const u64 program_id, const std::string& game_title_, GameListShortcutTarget target, std::string arguments_, const bool needs_title) { - // Get path to Eden executable - std::filesystem::path command = GetEdenCommand(); - - // Shortcut path - std::filesystem::path shortcut_path = GetShortcutPath(target); - - if (!std::filesystem::exists(shortcut_path)) { - GMainWindow::CreateShortcutMessagesGUI( - this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR, - QString::fromStdString(shortcut_path.generic_string())); - LOG_ERROR(Frontend, "Invalid shortcut target {}", shortcut_path.generic_string()); - return; - } - - const FileSys::PatchManager pm{program_id, QtCommon::system->GetFileSystemController(), - QtCommon::system->GetContentProvider()}; - const auto control = pm.GetControlMetadata(); - const auto loader = - Loader::GetLoader(*QtCommon::system, QtCommon::vfs->OpenFile(game_path, FileSys::OpenMode::Read)); - - std::string game_title{game_title_}; - - // Delete illegal characters from title - if (needs_title) { - game_title = fmt::format("{:016X}", program_id); - if (control.first != nullptr) { - game_title = control.first->GetApplicationName(); - } else { - loader->ReadTitle(game_title); - } - } - - const std::string illegal_chars = "<>:\"/\\|?*."; - for (auto it = game_title.rbegin(); it != game_title.rend(); ++it) { - if (illegal_chars.find(*it) != std::string::npos) { - game_title.erase(it.base() - 1); - } - } - - const QString qgame_title = QString::fromStdString(game_title); - - // Get icon from game file - std::vector icon_image_file{}; - if (control.second != nullptr) { - icon_image_file = control.second->ReadAllBytes(); - } else if (loader->ReadIcon(icon_image_file) != Loader::ResultStatus::Success) { - LOG_WARNING(Frontend, "Could not read icon from {:s}", game_path); - } - - QImage icon_data = - QImage::fromData(icon_image_file.data(), static_cast(icon_image_file.size())); - std::filesystem::path out_icon_path; - if (QtCommon::Game::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) { - if (!SaveIconToFile(out_icon_path, icon_data)) { - LOG_ERROR(Frontend, "Could not write icon to file"); - } - } else { - QMessageBox::critical( - this, tr("Create Icon"), - tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.") - .arg(QString::fromStdString(out_icon_path.string())), - QMessageBox::StandardButton::Ok); - } - -#if defined(__unix__) && !defined(__APPLE__) && !defined(__ANDROID__) - // Special case for AppImages - // Warn once if we are making a shortcut to a volatile AppImage - if (command.string().ends_with(".AppImage") && !UISettings::values.shortcut_already_warned) { - if (!GMainWindow::CreateShortcutMessagesGUI( - this, GMainWindow::CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING, qgame_title)) { - return; - } - UISettings::values.shortcut_already_warned = true; - } -#endif - - // Create shortcut - std::string arguments{arguments_}; - if (GMainWindow::CreateShortcutMessagesGUI( - this, GMainWindow::CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, qgame_title)) { - arguments = "-f " + arguments; - } - const std::string comment = fmt::format("Start {:s} with the Eden Emulator", game_title); - const std::string categories = "Game;Emulator;Qt;"; - const std::string keywords = "Switch;Nintendo;"; - - if (QtCommon::Game::CreateShortcutLink(shortcut_path, comment, out_icon_path, command, - arguments, categories, keywords, game_title)) { - GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS, - qgame_title); - return; - } - GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR, - qgame_title); -} - -void GMainWindow::OnCreateHomeMenuShortcut(GameListShortcutTarget target) { - constexpr u64 QLaunchId = static_cast(Service::AM::AppletProgramId::QLaunch); - auto bis_system = QtCommon::system->GetFileSystemController().GetSystemNANDContents(); - if (!bis_system) { - QMessageBox::warning(this, tr("No firmware available"), - tr("Please install firmware to use the home menu.")); - return; - } - - auto qlaunch_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program); - if (!qlaunch_nca) { - QMessageBox::warning(this, tr("Home Menu Applet"), - tr("Home Menu is not available. Please reinstall firmware.")); - return; - } - - auto qlaunch_applet_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program); - const auto game_path = qlaunch_applet_nca->GetFullPath(); - - // TODO(crueter): Make this use the Eden icon - CreateShortcut(game_path, QLaunchId, "Switch Home Menu", target, "-qlaunch", false); + QtCommon::Game::CreateHomeMenuShortcut(QtCommon::Game::ShortcutTarget::Applications); } void GMainWindow::OnCaptureScreenshot() { @@ -4718,7 +4453,6 @@ void GMainWindow::OnMouseActivity() { } void GMainWindow::OnCheckFirmwareDecryption() { - QtCommon::system->GetFileSystemController().CreateFactories(*QtCommon::vfs); if (!ContentManager::AreKeysPresent()) { QMessageBox::warning(this, tr("Derivation Components Missing"), tr("Encryption keys are missing.")); @@ -4727,41 +4461,6 @@ void GMainWindow::OnCheckFirmwareDecryption() { UpdateMenuState(); } -bool GMainWindow::OnCheckNcaVerification() { - if (!Settings::values.disable_nca_verification.GetValue()) - return true; - - const bool currently_hidden = Settings::values.hide_nca_verification_popup.GetValue(); - LOG_INFO(Frontend, "NCA Verification is disabled. Popup State={}", currently_hidden); - if (currently_hidden) - return true; - - QMessageBox msgbox(this); - msgbox.setWindowTitle(tr("NCA Verification Disabled")); - msgbox.setText(tr("NCA Verification is disabled.\n" - "This is required to run new games and updates.\n" - "Running without verification can cause instability or crashes if NCA files " - "are corrupt, modified, or tampered.\n" - "If unsure, re-enable verification in Eden's Settings and use firmware " - "version 19.0.1 or below.")); - msgbox.setIcon(QMessageBox::Warning); - msgbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); - msgbox.setDefaultButton(QMessageBox::Ok); - - QCheckBox* cb = new QCheckBox(tr("Don't show again"), &msgbox); - cb->setChecked(currently_hidden); - msgbox.setCheckBox(cb); - - int result = msgbox.exec(); - - const bool hide = cb->isChecked(); - if (hide != currently_hidden) { - Settings::values.hide_nca_verification_popup.SetValue(hide); - } - - return result == static_cast(QMessageBox::Ok); -} - bool GMainWindow::CheckFirmwarePresence() { return FirmwareManager::CheckFirmwarePresence(*QtCommon::system.get()); } diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 0bc5913acc..e3922759b0 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -54,7 +54,6 @@ class QSlider; class QHBoxLayout; class WaitTreeWidget; enum class GameListOpenTarget; -enum class GameListShortcutTarget; enum class DumpRomFSTarget; class GameListPlaceholder; @@ -161,13 +160,6 @@ class GMainWindow : public QMainWindow { /// Max number of recently loaded items to keep track of static const int max_recent_files_item = 10; - enum { - CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, - CREATE_SHORTCUT_MSGBOX_SUCCESS, - CREATE_SHORTCUT_MSGBOX_ERROR, - CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING, - }; - public: void filterBarSetChecked(bool state); void UpdateUITheme(); @@ -177,7 +169,7 @@ public: bool DropAction(QDropEvent* event); void AcceptDropEvent(QDropEvent* event); - std::filesystem::path GetShortcutPath(GameListShortcutTarget target); + std::filesystem::path GetShortcutPath(QtCommon::Game::ShortcutTarget target); signals: @@ -358,8 +350,9 @@ private slots: void OnGameListCopyTID(u64 program_id); void OnGameListNavigateToGamedbEntry(u64 program_id, const CompatibilityList& compatibility_list); - void OnGameListCreateShortcut(u64 program_id, const std::string& game_path, - GameListShortcutTarget target); + void OnGameListCreateShortcut(u64 program_id, + const std::string& game_path, + const QtCommon::Game::ShortcutTarget target); void OnGameListOpenDirectory(const QString& directory); void OnGameListAddDirectory(); void OnGameListShowList(bool show); @@ -416,7 +409,6 @@ private slots: void OnInitialSetup(); void OnCreateHomeMenuDesktopShortcut(); void OnCreateHomeMenuApplicationMenuShortcut(); - void OnCreateHomeMenuShortcut(GameListShortcutTarget target); void OnCaptureScreenshot(); void OnCheckFirmwareDecryption(); void OnLanguageChanged(const QString& locale); @@ -537,9 +529,6 @@ private: QString startup_icon_theme; - // FS - std::unique_ptr provider; - // Debugger panes WaitTreeWidget* waitTreeWidget; ControllerDialog* controller_dialog; @@ -586,7 +575,7 @@ private: void CreateShortcut(const std::string& game_path, const u64 program_id, const std::string& game_title, - GameListShortcutTarget target, + QtCommon::Game::ShortcutTarget target, std::string arguments, const bool needs_title); From b326f2e3e0440208d99e2851522beb339a3b2044 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 13 Sep 2025 11:47:34 -0400 Subject: [PATCH 20/34] fix headers Signed-off-by: crueter --- .../fssystem/fssystem_nca_file_system_driver.cpp | 3 --- src/yuzu/main.cpp | 12 ++---------- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp b/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp index 4e624ad3f4..37fb71e9e3 100644 --- a/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp +++ b/src/core/file_sys/fssystem/fssystem_nca_file_system_driver.cpp @@ -1,9 +1,6 @@ // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 0d7a08d63d..9480fed5b3 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -10,11 +10,8 @@ #include "qt_common/qt_game_util.h" #include "qt_common/qt_meta.h" #include "qt_common/qt_path_util.h" -#include "qt_common/qt_progress_dialog.h" #include #include -#include -#include #include #include @@ -43,21 +40,16 @@ #include "configuration/configure_input.h" #include "configuration/configure_per_game.h" #include "configuration/configure_tas.h" -#include "core/core_timing.h" #include "core/file_sys/romfs_factory.h" -#include "core/file_sys/vfs/vfs.h" -#include "core/file_sys/vfs/vfs_real.h" #include "core/frontend/applets/cabinet.h" #include "core/frontend/applets/controller.h" #include "core/frontend/applets/general.h" #include "core/frontend/applets/mii_edit.h" #include "core/frontend/applets/software_keyboard.h" -#include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/frontend/applets.h" -#include "core/hle/service/set/system_settings_server.h" #include "frontend_common/content_manager.h" -#include "hid_core/frontend/emulated_controller.h" #include "hid_core/hid_core.h" +#include "hid_core/frontend/emulated_controller.h" #include "yuzu/multiplayer/state.h" #include "yuzu/util/controller_navigation.h" @@ -139,6 +131,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "core/file_sys/savedata_factory.h" #include "core/file_sys/submission_package.h" #include "core/hle/kernel/k_process.h" +#include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/am.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/sm/sm.h" @@ -166,7 +159,6 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "yuzu/discord.h" #include "yuzu/game_list.h" #include "yuzu/game_list_p.h" -#include "yuzu/hotkeys.h" #include "yuzu/install_dialog.h" #include "yuzu/loading_screen.h" #include "yuzu/main.h" From c70d9140a48e121326f278f8e6da550242a62432 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 13 Sep 2025 11:49:10 -0400 Subject: [PATCH 21/34] Fix cpm-fetch Signed-off-by: crueter --- docs/CPM.md | 2 +- tools/cpm-fetch-all.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CPM.md b/docs/CPM.md index 2afcdaf164..bce224da40 100644 --- a/docs/CPM.md +++ b/docs/CPM.md @@ -245,6 +245,6 @@ include(CPMUtil) Currently, `cpm-fetch.sh` defines the following directories for cpmfiles (max depth of 2, so subdirs are caught as well): -`externals src/yuzu src/dynarmic .` +`externals src/qt_common src/dynarmic .` Whenever you add a new cpmfile, update the script accordingly \ No newline at end of file diff --git a/tools/cpm-fetch-all.sh b/tools/cpm-fetch-all.sh index eac0f861a4..66f55df94d 100755 --- a/tools/cpm-fetch-all.sh +++ b/tools/cpm-fetch-all.sh @@ -6,6 +6,6 @@ # SPDX-FileCopyrightText: 2025 crueter # SPDX-License-Identifier: GPL-3.0-or-later -LIBS=$(find . externals src/yuzu/externals src/dynarmic -maxdepth 2 -name cpmfile.json -exec jq -j 'keys_unsorted | join(" ")' {} \; -printf " ") +LIBS=$(find . externals src/qt_common src/dynarmic -maxdepth 2 -name cpmfile.json -exec jq -j 'keys_unsorted | join(" ")' {} \; -printf " ") tools/cpm-fetch.sh $LIBS \ No newline at end of file From 63961f3741b49ff7dd4133cc9ec8a57fdbca6cea Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 13 Sep 2025 11:51:44 -0400 Subject: [PATCH 22/34] fix cpm-fetch (again) Signed-off-by: crueter --- tools/cpm-fetch.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/cpm-fetch.sh b/tools/cpm-fetch.sh index 5620996433..996cf76a97 100755 --- a/tools/cpm-fetch.sh +++ b/tools/cpm-fetch.sh @@ -105,7 +105,8 @@ ci_package() { for package in $@ do # prepare for cancer - JSON=$(find . externals src/yuzu/externals externals/ffmpeg src/dynarmic/externals externals/nx_tzdb -maxdepth 1 -name cpmfile.json -exec jq -r ".\"$package\" | select( . != null )" {} \;) + # TODO(crueter): Fetch json once? + JSON=$(find . externals src/qt_common src/dynarmic -maxdepth 1 -name cpmfile.json -exec jq -r ".\"$package\" | select( . != null )" {} \;) [ -z "$JSON" ] && echo "No cpmfile definition for $package" && continue From ae31504772b8d1b10b294eb9f8ebde90abc0dc57 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 13 Sep 2025 12:09:12 -0400 Subject: [PATCH 23/34] fix msvc Signed-off-by: crueter --- src/qt_common/qt_game_util.cpp | 2 +- src/qt_common/qt_game_util.h | 3 +-- src/yuzu/main.cpp | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp index 292eefa224..3b667b7700 100644 --- a/src/qt_common/qt_game_util.cpp +++ b/src/qt_common/qt_game_util.cpp @@ -357,7 +357,7 @@ void RemoveCustomConfiguration(u64 program_id, const std::string& game_path) } } -void RemoveCacheStorage(u64 program_id, FileSys::VfsFilesystem* vfs) +void RemoveCacheStorage(u64 program_id) { const auto nand_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir); auto vfs_nand_dir = vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), diff --git a/src/qt_common/qt_game_util.h b/src/qt_common/qt_game_util.h index 2872734390..0a21208659 100644 --- a/src/qt_common/qt_game_util.h +++ b/src/qt_common/qt_game_util.h @@ -7,7 +7,6 @@ #include #include #include "common/fs/path_util.h" -#include namespace QtCommon::Game { @@ -65,7 +64,7 @@ void RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target); void RemoveVulkanDriverPipelineCache(u64 program_id); void RemoveAllTransferableShaderCaches(u64 program_id); void RemoveCustomConfiguration(u64 program_id, const std::string& game_path); -void RemoveCacheStorage(u64 program_id, FileSys::VfsFilesystem* vfs); +void RemoveCacheStorage(u64 program_id); // Metadata // void ResetMetadata(); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 9480fed5b3..a411270ca8 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2616,7 +2616,7 @@ void GMainWindow::OnGameListRemoveFile(u64 program_id, QtCommon::Game::GameListR QtCommon::Game::RemoveCustomConfiguration(program_id, game_path); break; case QtCommon::Game::GameListRemoveTarget::CacheStorage: - QtCommon::Game::RemoveCacheStorage(program_id, QtCommon::vfs.get()); + QtCommon::Game::RemoveCacheStorage(program_id); break; } } From a572ee58d3c77df201c9af2eeeeab9395f56b47b Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 13 Sep 2025 12:28:59 -0400 Subject: [PATCH 24/34] fix windows Signed-off-by: crueter --- src/yuzu/main.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index a411270ca8..d7d4e94ab7 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -113,6 +113,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "common/scm_rev.h" #include "common/scope_exit.h" #ifdef _WIN32 +#include "core/core_timing.h" #include "common/windows/timer_resolution.h" #endif #ifdef ARCHITECTURE_x86_64 @@ -1470,7 +1471,7 @@ void GMainWindow::InitializeHotkeys() { connect_shortcut(QStringLiteral("Toggle Framerate Limit"), [] { Settings::values.use_speed_limit.SetValue(!Settings::values.use_speed_limit.GetValue()); }); - connect_shortcut(QStringLiteral("Toggle Renderdoc Capture"), [this] { + connect_shortcut(QStringLiteral("Toggle Renderdoc Capture"), [] { if (Settings::values.enable_renderdoc_hotkey) { QtCommon::system->GetRenderdocAPI().ToggleCapture(); } @@ -2140,7 +2141,7 @@ void GMainWindow::BootGame(const QString& filename, Service::AM::FrontendAppletP std::string title_version; const auto res = QtCommon::system->GetGameName(title_name); - const auto metadata = [this, title_id] { + const auto metadata = [title_id] { const FileSys::PatchManager pm(title_id, QtCommon::system->GetFileSystemController(), QtCommon::system->GetContentProvider()); return pm.GetControlMetadata(); @@ -2371,7 +2372,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target std::filesystem::path path; QString open_target; - const auto [user_save_size, device_save_size] = [this, &game_path, &program_id] { + const auto [user_save_size, device_save_size] = [&game_path, &program_id] { const FileSys::PatchManager pm{program_id, QtCommon::system->GetFileSystemController(), QtCommon::system->GetContentProvider()}; const auto control = pm.GetControlMetadata().first; @@ -2958,7 +2959,7 @@ void GMainWindow::OnMenuInstallToNAND() { } return false; }; - future = QtConcurrent::run([this, &file, progress_callback] { + future = QtConcurrent::run([&file, progress_callback] { return ContentManager::InstallNSP(*QtCommon::system, *QtCommon::vfs, file.toStdString(), progress_callback); }); From 6d7820cf01664586e8c560899671f0fadd6e2bfe Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 13 Sep 2025 13:31:32 -0400 Subject: [PATCH 25/34] fix windows dir opening Signed-off-by: crueter --- src/qt_common/qt_game_util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt_common/qt_game_util.cpp b/src/qt_common/qt_game_util.cpp index 3b667b7700..5d0b4d8ae7 100644 --- a/src/qt_common/qt_game_util.cpp +++ b/src/qt_common/qt_game_util.cpp @@ -165,7 +165,7 @@ bool MakeShortcutIcoPath(const u64 program_id, void OpenEdenFolder(const Common::FS::EdenPath& path) { - QDesktopServices::openUrl(QUrl(QString::fromStdString(Common::FS::GetEdenPathString(path)))); + QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(Common::FS::GetEdenPathString(path)))); } void OpenRootDataFolder() From 2f6b68685924cef1b4300656b6f682e00f7b6796 Mon Sep 17 00:00:00 2001 From: crueter Date: Mon, 16 Jun 2025 19:05:20 -0400 Subject: [PATCH 26/34] merge Signed-off-by: crueter --- src/CMakeLists.txt | 2 +- src/eden/.gitignore | 82 +++ src/eden/CMakeLists.txt | 82 +++ src/eden/gamepad/CMakeLists.txt | 9 + src/eden/gamepad/gamepad.cpp | 78 +++ src/eden/gamepad/gamepad.h | 31 + src/eden/icons.qrc | 14 + src/eden/icons/audio.svg | 1 + src/eden/icons/back.svg | 39 ++ src/eden/icons/controls.svg | 1 + src/eden/icons/cpu.svg | 1 + src/eden/icons/debug.svg | 1 + src/eden/icons/forward.svg | 39 ++ src/eden/icons/general.svg | 1 + src/eden/icons/graphics.svg | 60 ++ src/eden/icons/help.svg | 1 + src/eden/icons/system.svg | 1 + src/eden/interface/CMakeLists.txt | 13 + src/eden/interface/MetaObjectHelper.h | 22 + src/eden/interface/QMLSetting.cpp | 261 ++++++++ src/eden/interface/QMLSetting.h | 105 ++++ src/eden/interface/SettingsInterface.cpp | 124 ++++ src/eden/interface/SettingsInterface.h | 84 +++ src/eden/interface/qt_config.cpp | 562 +++++++++++++++++ src/eden/interface/qt_config.h | 55 ++ src/eden/interface/shared_translation.cpp | 569 ++++++++++++++++++ src/eden/interface/shared_translation.h | 65 ++ src/eden/interface/uisettings.cpp | 112 ++++ src/eden/interface/uisettings.h | 282 +++++++++ src/eden/main.cpp | 56 ++ src/eden/models/CMakeLists.txt | 16 + src/eden/models/GameListModel.cpp | 70 +++ src/eden/models/GameListModel.h | 39 ++ src/eden/models/SettingsModel.cpp | 90 +++ src/eden/models/SettingsModel.h | 42 ++ src/eden/qml/CMakeLists.txt | 5 + src/eden/qml/config/CMakeLists.txt | 57 ++ src/eden/qml/config/GlobalConfigureDialog.qml | 73 +++ src/eden/qml/config/SectionHeader.qml | 8 + src/eden/qml/config/Setting.qml | 92 +++ src/eden/qml/config/TestSetting.qml | 39 ++ src/eden/qml/config/fields/BaseField.qml | 160 +++++ src/eden/qml/config/fields/ConfigCheckbox.qml | 27 + src/eden/qml/config/fields/ConfigComboBox.qml | 33 + src/eden/qml/config/fields/ConfigHexEdit.qml | 26 + src/eden/qml/config/fields/ConfigIntLine.qml | 28 + .../qml/config/fields/ConfigIntSlider.qml | 39 ++ src/eden/qml/config/fields/ConfigIntSpin.qml | 25 + .../qml/config/fields/ConfigStringEdit.qml | 22 + src/eden/qml/config/fields/ConfigTimeEdit.qml | 27 + src/eden/qml/config/fields/FieldCheckbox.qml | 17 + src/eden/qml/config/fields/FieldLabel.qml | 18 + src/eden/qml/config/icons.qrc | 1 + src/eden/qml/config/pages/SettingsList.qml | 47 ++ .../config/pages/audio/AudioGeneralPage.qml | 17 + .../qml/config/pages/cpu/CpuGeneralPage.qml | 17 + .../config/pages/debug/DebugAdvancedPage.qml | 19 + .../qml/config/pages/debug/DebugCpuPage.qml | 18 + .../config/pages/debug/DebugGeneralPage.qml | 28 + .../config/pages/debug/DebugGraphicsPage.qml | 20 + .../config/pages/general/UiGameListPage.qml | 18 + .../config/pages/general/UiGeneralPage.qml | 23 + .../config/pages/global/GlobalAudioPage.qml | 14 + .../qml/config/pages/global/GlobalCpuPage.qml | 14 + .../config/pages/global/GlobalDebugPage.qml | 17 + .../config/pages/global/GlobalGeneralPage.qml | 17 + .../pages/global/GlobalGraphicsPage.qml | 16 + .../config/pages/global/GlobalSystemPage.qml | 18 + .../qml/config/pages/global/GlobalTab.qml | 34 ++ .../pages/global/GlobalTabSwipeView.qml | 16 + .../pages/graphics/RendererAdvancedPage.qml | 17 + .../pages/graphics/RendererExtensionsPage.qml | 17 + .../config/pages/graphics/RendererPage.qml | 17 + .../qml/config/pages/system/AppletsPage.qml | 17 + .../config/pages/system/FileSystemPage.qml | 17 + .../config/pages/system/SystemCorePage.qml | 17 + .../config/pages/system/SystemGeneralPage.qml | 22 + src/eden/qml/constants/CMakeLists.txt | 23 + src/eden/qml/constants/Constants.qml | 24 + src/eden/qml/items/AnimatedDialog.qml | 79 +++ src/eden/qml/items/BetterMenu.qml | 59 ++ src/eden/qml/items/BetterMenuBar.qml | 33 + src/eden/qml/items/CMakeLists.txt | 22 + src/eden/qml/items/IconButton.qml | 23 + src/eden/qml/items/SettingsTabButton.qml | 40 ++ src/eden/qml/items/StatusBarButton.qml | 36 ++ src/eden/qml/items/VerticalTabBar.qml | 46 ++ src/eden/qml/items/fields/BetterSpinBox.qml | 68 +++ src/eden/qml/items/fields/BetterTextField.qml | 38 ++ src/eden/qml/items/fields/FieldFooter.qml | 20 + src/eden/qml/main/CMakeLists.txt | 13 + src/eden/qml/main/GameList.qml | 141 +++++ src/eden/qml/main/GamePreview.qml | 77 +++ src/eden/qml/main/Main.qml | 207 +++++++ src/eden/qml/main/StatusBar.qml | 160 +++++ 95 files changed, 5292 insertions(+), 1 deletion(-) create mode 100644 src/eden/.gitignore create mode 100644 src/eden/CMakeLists.txt create mode 100644 src/eden/gamepad/CMakeLists.txt create mode 100644 src/eden/gamepad/gamepad.cpp create mode 100644 src/eden/gamepad/gamepad.h create mode 100644 src/eden/icons.qrc create mode 100644 src/eden/icons/audio.svg create mode 100644 src/eden/icons/back.svg create mode 100644 src/eden/icons/controls.svg create mode 100644 src/eden/icons/cpu.svg create mode 100644 src/eden/icons/debug.svg create mode 100644 src/eden/icons/forward.svg create mode 100644 src/eden/icons/general.svg create mode 100644 src/eden/icons/graphics.svg create mode 100644 src/eden/icons/help.svg create mode 100644 src/eden/icons/system.svg create mode 100644 src/eden/interface/CMakeLists.txt create mode 100644 src/eden/interface/MetaObjectHelper.h create mode 100644 src/eden/interface/QMLSetting.cpp create mode 100644 src/eden/interface/QMLSetting.h create mode 100644 src/eden/interface/SettingsInterface.cpp create mode 100644 src/eden/interface/SettingsInterface.h create mode 100644 src/eden/interface/qt_config.cpp create mode 100644 src/eden/interface/qt_config.h create mode 100644 src/eden/interface/shared_translation.cpp create mode 100644 src/eden/interface/shared_translation.h create mode 100644 src/eden/interface/uisettings.cpp create mode 100644 src/eden/interface/uisettings.h create mode 100644 src/eden/main.cpp create mode 100644 src/eden/models/CMakeLists.txt create mode 100644 src/eden/models/GameListModel.cpp create mode 100644 src/eden/models/GameListModel.h create mode 100644 src/eden/models/SettingsModel.cpp create mode 100644 src/eden/models/SettingsModel.h create mode 100644 src/eden/qml/CMakeLists.txt create mode 100644 src/eden/qml/config/CMakeLists.txt create mode 100644 src/eden/qml/config/GlobalConfigureDialog.qml create mode 100644 src/eden/qml/config/SectionHeader.qml create mode 100644 src/eden/qml/config/Setting.qml create mode 100644 src/eden/qml/config/TestSetting.qml create mode 100644 src/eden/qml/config/fields/BaseField.qml create mode 100644 src/eden/qml/config/fields/ConfigCheckbox.qml create mode 100644 src/eden/qml/config/fields/ConfigComboBox.qml create mode 100644 src/eden/qml/config/fields/ConfigHexEdit.qml create mode 100644 src/eden/qml/config/fields/ConfigIntLine.qml create mode 100644 src/eden/qml/config/fields/ConfigIntSlider.qml create mode 100644 src/eden/qml/config/fields/ConfigIntSpin.qml create mode 100644 src/eden/qml/config/fields/ConfigStringEdit.qml create mode 100644 src/eden/qml/config/fields/ConfigTimeEdit.qml create mode 100644 src/eden/qml/config/fields/FieldCheckbox.qml create mode 100644 src/eden/qml/config/fields/FieldLabel.qml create mode 100644 src/eden/qml/config/icons.qrc create mode 100644 src/eden/qml/config/pages/SettingsList.qml create mode 100644 src/eden/qml/config/pages/audio/AudioGeneralPage.qml create mode 100644 src/eden/qml/config/pages/cpu/CpuGeneralPage.qml create mode 100644 src/eden/qml/config/pages/debug/DebugAdvancedPage.qml create mode 100644 src/eden/qml/config/pages/debug/DebugCpuPage.qml create mode 100644 src/eden/qml/config/pages/debug/DebugGeneralPage.qml create mode 100644 src/eden/qml/config/pages/debug/DebugGraphicsPage.qml create mode 100644 src/eden/qml/config/pages/general/UiGameListPage.qml create mode 100644 src/eden/qml/config/pages/general/UiGeneralPage.qml create mode 100644 src/eden/qml/config/pages/global/GlobalAudioPage.qml create mode 100644 src/eden/qml/config/pages/global/GlobalCpuPage.qml create mode 100644 src/eden/qml/config/pages/global/GlobalDebugPage.qml create mode 100644 src/eden/qml/config/pages/global/GlobalGeneralPage.qml create mode 100644 src/eden/qml/config/pages/global/GlobalGraphicsPage.qml create mode 100644 src/eden/qml/config/pages/global/GlobalSystemPage.qml create mode 100644 src/eden/qml/config/pages/global/GlobalTab.qml create mode 100644 src/eden/qml/config/pages/global/GlobalTabSwipeView.qml create mode 100644 src/eden/qml/config/pages/graphics/RendererAdvancedPage.qml create mode 100644 src/eden/qml/config/pages/graphics/RendererExtensionsPage.qml create mode 100644 src/eden/qml/config/pages/graphics/RendererPage.qml create mode 100644 src/eden/qml/config/pages/system/AppletsPage.qml create mode 100644 src/eden/qml/config/pages/system/FileSystemPage.qml create mode 100644 src/eden/qml/config/pages/system/SystemCorePage.qml create mode 100644 src/eden/qml/config/pages/system/SystemGeneralPage.qml create mode 100644 src/eden/qml/constants/CMakeLists.txt create mode 100644 src/eden/qml/constants/Constants.qml create mode 100644 src/eden/qml/items/AnimatedDialog.qml create mode 100644 src/eden/qml/items/BetterMenu.qml create mode 100644 src/eden/qml/items/BetterMenuBar.qml create mode 100644 src/eden/qml/items/CMakeLists.txt create mode 100644 src/eden/qml/items/IconButton.qml create mode 100644 src/eden/qml/items/SettingsTabButton.qml create mode 100644 src/eden/qml/items/StatusBarButton.qml create mode 100644 src/eden/qml/items/VerticalTabBar.qml create mode 100644 src/eden/qml/items/fields/BetterSpinBox.qml create mode 100644 src/eden/qml/items/fields/BetterTextField.qml create mode 100644 src/eden/qml/items/fields/FieldFooter.qml create mode 100644 src/eden/qml/main/CMakeLists.txt create mode 100644 src/eden/qml/main/GameList.qml create mode 100644 src/eden/qml/main/GamePreview.qml create mode 100644 src/eden/qml/main/Main.qml create mode 100644 src/eden/qml/main/StatusBar.qml diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 184b049d06..5f12646c71 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -236,7 +236,7 @@ endif() if (ENABLE_QT) add_definitions(-DYUZU_QT_WIDGETS) add_subdirectory(qt_common) - add_subdirectory(yuzu) + add_subdirectory(eden) endif() if (ENABLE_WEB_SERVICE) diff --git a/src/eden/.gitignore b/src/eden/.gitignore new file mode 100644 index 0000000000..aa3808c5a9 --- /dev/null +++ b/src/eden/.gitignore @@ -0,0 +1,82 @@ +# This file is used to ignore files which are generated +# ---------------------------------------------------------------------------- + +*~ +*.autosave +*.a +*.core +*.moc +*.o +*.obj +*.orig +*.rej +*.so +*.so.* +*_pch.h.cpp +*_resource.rc +*.qm +.#* +*.*# +core +!core/ +tags +.DS_Store +.directory +*.debug +Makefile* +*.prl +*.app +moc_*.cpp +ui_*.h +qrc_*.cpp +Thumbs.db +*.res +*.rc +/.qmake.cache +/.qmake.stash + +# qtcreator generated files +*.pro.user* +*.qbs.user* +CMakeLists.txt.user* + +# xemacs temporary files +*.flc + +# Vim temporary files +.*.swp + +# Visual Studio generated files +*.ib_pdb_index +*.idb +*.ilk +*.pdb +*.sln +*.suo +*.vcproj +*vcproj.*.*.user +*.ncb +*.sdf +*.opensdf +*.vcxproj +*vcxproj.* + +# MinGW generated files +*.Debug +*.Release + +# Python byte code +*.pyc + +# Binaries +# -------- +*.dll +*.exe + +# Directories with generated files +.moc/ +.obj/ +.pch/ +.rcc/ +.uic/ +/build*/ diff --git a/src/eden/CMakeLists.txt b/src/eden/CMakeLists.txt new file mode 100644 index 0000000000..702ccd3adf --- /dev/null +++ b/src/eden/CMakeLists.txt @@ -0,0 +1,82 @@ +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +find_package(Qt6 REQUIRED COMPONENTS Widgets Core Gui Quick QuickControls2) + +qt_standard_project_setup(REQUIRES 6.7) + +qt_add_executable(yuzu + main.cpp + icons.qrc +) + +add_subdirectory(qml) +add_subdirectory(interface) +add_subdirectory(models) + +set(PLUGINS + edenMainplugin + edenItemsplugin + edenConfigplugin + edenInterfaceplugin + edenConstantsplugin +) + +if (ENABLE_SDL2) + add_subdirectory(gamepad) + set(PLUGINS ${PLUGINS} edenGamepadplugin) +endif() + +target_link_libraries(yuzu + PRIVATE + Qt6::Core + Qt6::Widgets + Qt6::Gui + Qt6::Quick + Qt6::QuickControls2 + edenModels + + # Explicitly link to static plugins + ${PLUGINS} +) + +set(NATIVE_MODULES yuzu edenInterface) + +foreach(MODULE ${NATIVE_MODULES}) + target_link_libraries(${MODULE} PRIVATE common core input_common frontend_common network video_core) + target_link_libraries(${MODULE} PRIVATE Boost::headers glad fmt) + target_link_libraries(${MODULE} PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) + + target_link_libraries(${MODULE} PRIVATE Vulkan::Headers) + + if (NOT WIN32) + target_include_directories(${MODULE} PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) + endif() + if (UNIX AND NOT APPLE) + target_link_libraries(${MODULE} PRIVATE Qt6::DBus) + endif() + + target_compile_definitions(${MODULE} PRIVATE + # Use QStringBuilder for string concatenation to reduce + # the overall number of temporary strings created. + -DQT_USE_QSTRINGBUILDER + + # Disable implicit type narrowing in signal/slot connect() calls. + -DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT + + # Disable unsafe overloads of QProcess' start() function. + -DQT_NO_PROCESS_COMBINED_ARGUMENT_START + + # Disable implicit QString->QUrl conversions to enforce use of proper resolving functions. + -DQT_NO_URL_CAST_FROM_STRING + ) +endforeach() + +set_target_properties(yuzu PROPERTIES OUTPUT_NAME "eden") +include(GNUInstallDirs) +install(TARGETS yuzu + BUNDLE DESTINATION . + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) diff --git a/src/eden/gamepad/CMakeLists.txt b/src/eden/gamepad/CMakeLists.txt new file mode 100644 index 0000000000..f4bbb7cf54 --- /dev/null +++ b/src/eden/gamepad/CMakeLists.txt @@ -0,0 +1,9 @@ +set(CMAKE_AUTOMOC ON) + +qt_add_library(edenGamepad STATIC) + +qt_add_qml_module(edenGamepad + URI org.eden_emu.gamepad + VERSION 1.0 + SOURCES gamepad.h gamepad.cpp +) diff --git a/src/eden/gamepad/gamepad.cpp b/src/eden/gamepad/gamepad.cpp new file mode 100644 index 0000000000..daba8e35e8 --- /dev/null +++ b/src/eden/gamepad/gamepad.cpp @@ -0,0 +1,78 @@ +#include "gamepad.h" + +Gamepad::Gamepad(QObject *parent) + : QObject(parent) +{ + SDL_Init(SDL_INIT_GAMECONTROLLER); +} + +Gamepad::~Gamepad() +{ + if (controller) + SDL_GameControllerClose(controller); + SDL_Quit(); +} + +void Gamepad::openController(int deviceIndex) +{ + if (controller) { + closeController(); + } + + controller = SDL_GameControllerOpen(deviceIndex); +} + +void Gamepad::closeController() +{ + if (controller) { + SDL_GameControllerClose(controller); + controller = nullptr; + } +} +void Gamepad::pollEvents() +{ + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_CONTROLLERDEVICEADDED: + openController(event.cdevice.which); + break; + case SDL_CONTROLLERDEVICEREMOVED: + if (controller + && event.cdevice.which + == SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(controller))) { + closeController(); + } + break; + + case SDL_CONTROLLERBUTTONDOWN: + switch (event.cbutton.button) { + case SDL_CONTROLLER_BUTTON_DPAD_UP: + emit upPressed(); + break; + case SDL_CONTROLLER_BUTTON_DPAD_DOWN: + emit downPressed(); + break; + case SDL_CONTROLLER_BUTTON_DPAD_LEFT: + emit leftPressed(); + break; + case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: + emit rightPressed(); + break; + case SDL_CONTROLLER_BUTTON_A: + emit aPressed(); + break; + } + break; + + case SDL_CONTROLLERAXISMOTION: + if (event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTX + || event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTY) { + int x = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX); + int y = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY); + emit leftStickMoved(x, y); + } + break; + } + } +} diff --git a/src/eden/gamepad/gamepad.h b/src/eden/gamepad/gamepad.h new file mode 100644 index 0000000000..42c2b3faed --- /dev/null +++ b/src/eden/gamepad/gamepad.h @@ -0,0 +1,31 @@ +#pragma once +#include +#include +#include + +#include + +class Gamepad : public QObject { + Q_OBJECT + QML_ELEMENT +public: + explicit Gamepad(QObject *parent = nullptr); + ~Gamepad(); + + Q_INVOKABLE void pollEvents(); + +signals: + void upPressed(); + void downPressed(); + void leftPressed(); + void rightPressed(); + void aPressed(); + + void leftStickMoved(int x, int y); + +private: + SDL_GameController *controller = nullptr; + + void closeController(); + void openController(int deviceIndex); +}; diff --git a/src/eden/icons.qrc b/src/eden/icons.qrc new file mode 100644 index 0000000000..9844c5ff9e --- /dev/null +++ b/src/eden/icons.qrc @@ -0,0 +1,14 @@ + + + icons/audio.svg + icons/controls.svg + icons/cpu.svg + icons/general.svg + icons/graphics.svg + icons/system.svg + icons/debug.svg + icons/forward.svg + icons/back.svg + icons/help.svg + + diff --git a/src/eden/icons/audio.svg b/src/eden/icons/audio.svg new file mode 100644 index 0000000000..7244ec4388 --- /dev/null +++ b/src/eden/icons/audio.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/eden/icons/back.svg b/src/eden/icons/back.svg new file mode 100644 index 0000000000..b14bde76b7 --- /dev/null +++ b/src/eden/icons/back.svg @@ -0,0 +1,39 @@ + + + + + + diff --git a/src/eden/icons/controls.svg b/src/eden/icons/controls.svg new file mode 100644 index 0000000000..f115376c87 --- /dev/null +++ b/src/eden/icons/controls.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/eden/icons/cpu.svg b/src/eden/icons/cpu.svg new file mode 100644 index 0000000000..683e20bf7c --- /dev/null +++ b/src/eden/icons/cpu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/eden/icons/debug.svg b/src/eden/icons/debug.svg new file mode 100644 index 0000000000..d279fc6d23 --- /dev/null +++ b/src/eden/icons/debug.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/eden/icons/forward.svg b/src/eden/icons/forward.svg new file mode 100644 index 0000000000..dab7cca73c --- /dev/null +++ b/src/eden/icons/forward.svg @@ -0,0 +1,39 @@ + + + + + + diff --git a/src/eden/icons/general.svg b/src/eden/icons/general.svg new file mode 100644 index 0000000000..63cebb1c3a --- /dev/null +++ b/src/eden/icons/general.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/eden/icons/graphics.svg b/src/eden/icons/graphics.svg new file mode 100644 index 0000000000..47b5bc7ca8 --- /dev/null +++ b/src/eden/icons/graphics.svg @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + diff --git a/src/eden/icons/help.svg b/src/eden/icons/help.svg new file mode 100644 index 0000000000..fef5d20286 --- /dev/null +++ b/src/eden/icons/help.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/eden/icons/system.svg b/src/eden/icons/system.svg new file mode 100644 index 0000000000..df53b9b617 --- /dev/null +++ b/src/eden/icons/system.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/eden/interface/CMakeLists.txt b/src/eden/interface/CMakeLists.txt new file mode 100644 index 0000000000..374b4ec70d --- /dev/null +++ b/src/eden/interface/CMakeLists.txt @@ -0,0 +1,13 @@ +qt_add_library(edenInterface STATIC) +qt_add_qml_module(edenInterface + URI org.eden_emu.interface + VERSION 1.0 + SOURCES + SettingsInterface.h SettingsInterface.cpp + uisettings.h uisettings.cpp + qt_config.h qt_config.cpp + shared_translation.h shared_translation.cpp + QMLSetting.h QMLSetting.cpp + MetaObjectHelper.h + +) diff --git a/src/eden/interface/MetaObjectHelper.h b/src/eden/interface/MetaObjectHelper.h new file mode 100644 index 0000000000..922e1cbb47 --- /dev/null +++ b/src/eden/interface/MetaObjectHelper.h @@ -0,0 +1,22 @@ +#ifndef METAOBJECTHELPER_H +#define METAOBJECTHELPER_H + +#include +#include +#include + +class MetaObjectHelper : public QObject { + Q_OBJECT + QML_ELEMENT + QML_SINGLETON +public: + using QObject::QObject; + Q_INVOKABLE QString typeName(QObject* object, const QString& property) const + { + QQmlProperty qmlProperty(object, property); + QMetaProperty metaProperty = qmlProperty.property(); + return metaProperty.typeName(); + } +}; + +#endif // METAOBJECTHELPER_H diff --git a/src/eden/interface/QMLSetting.cpp b/src/eden/interface/QMLSetting.cpp new file mode 100644 index 0000000000..4e559df26b --- /dev/null +++ b/src/eden/interface/QMLSetting.cpp @@ -0,0 +1,261 @@ +#include "QMLSetting.h" +#include "common/settings.h" + +QMLSetting::QMLSetting(Settings::BasicSetting *setting, QObject *parent, RequestType request) + : QObject(parent) + , m_setting(setting) +{ + + // TODO: restore/touch + /* + if (!Settings::IsConfiguringGlobal() && managed) { + restore_button = CreateRestoreGlobalButton(setting.UsingGlobal(), this); + + touch = [this]() { + LOG_DEBUG(Frontend, "Enabling custom setting for \"{}\"", setting.GetLabel()); + restore_button->setEnabled(true); + restore_button->setVisible(true); + }; + } + */ + + const auto type = setting->TypeId(); + + request = [&]() { + if (request != RequestType::Default) { + return request; + } + switch (setting->Specialization() & Settings::SpecializationTypeMask) { + case Settings::Specialization::Default: + return RequestType::Default; + case Settings::Specialization::Time: + return RequestType::DateTimeEdit; + case Settings::Specialization::Hex: + return RequestType::HexEdit; + case Settings::Specialization::RuntimeList: + // managed = false; + [[fallthrough]]; + case Settings::Specialization::List: + return RequestType::ComboBox; + case Settings::Specialization::Scalar: + return RequestType::Slider; + case Settings::Specialization::Countable: + return RequestType::SpinBox; + case Settings::Specialization::Radio: + return RequestType::RadioGroup; + default: + break; + } + return request; + }(); + + if (type == typeid(bool)) { + m_type = "bool"; + m_metaType = QMetaType::Bool; + } else if (setting->IsEnum()) { + m_metaType = QMetaType::UInt; + + if (request == RequestType::RadioGroup) { + m_type = "radio"; + // TODO: Add the options and whatnot + // see CreateRadioGroup + } else { + m_type = "enumCombo"; + } + } else if (setting->IsIntegral()) { + m_metaType = QMetaType::UInt; + + switch (request) { + case RequestType::Slider: + case RequestType::ReverseSlider: + // TODO: Reversal and multiplier + m_type = "intSlider"; + break; + case RequestType::Default: + case RequestType::LineEdit: + m_type = "intSpin"; + break; + case RequestType::DateTimeEdit: + // TODO: disabled/restrict + m_type = "time"; + break; + case RequestType::SpinBox: + // TODO: suffix + m_type = "intSpin"; + break; + case RequestType::HexEdit: + m_type = "hex"; + break; + case RequestType::ComboBox: + // TODO: Add the options and whatnot + // see CreateComboBox + m_type = "intCombo"; + break; + default: + // UNIMPLEMENTED(); + break; + } + } else if (setting->IsFloatingPoint()) { + m_metaType = QMetaType::Double; + + switch (request) { + case RequestType::Default: + case RequestType::SpinBox: + // TODO: suffix + m_type = "doubleSpin"; + break; + case RequestType::Slider: + case RequestType::ReverseSlider: + // TODO: multiplier, suffix, reversal + m_type = "doubleSlider"; + break; + default: + // UNIMPLEMENTED assert + // UNIMPLEMENTED(); + break; + } + } else if (type == typeid(std::string)) { + m_metaType = QMetaType::QString; + + switch (request) { + case RequestType::Default: + case RequestType::LineEdit: + m_type = "stringLine"; + break; + case RequestType::ComboBox: + m_type = "stringCombo"; + break; + default: + // UNIMPLEMENTED(); + break; + } + } +} + +QVariant QMLSetting::value() const +{ + QVariant var = QVariant::fromValue(QString::fromStdString(m_setting->ToString())); + var.convert(QMetaType(m_metaType)); + return var; +} + +void QMLSetting::setValue(const QVariant &newValue) +{ + QVariant var = newValue; + var.convert(QMetaType(m_metaType)); + + m_setting->LoadString(var.toString().toStdString()); + emit valueChanged(); +} + +bool QMLSetting::global() const +{ + return m_setting->UsingGlobal(); +} + +void QMLSetting::setGlobal(bool newGlobal) +{ + m_setting->SetGlobal(newGlobal); + emit globalChanged(); + emit valueChanged(); +} + +void QMLSetting::restore() +{ + std::string toSet = Settings::IsConfiguringGlobal() ? m_setting->DefaultToString() : m_setting->ToStringGlobal(); + setValue(QString::fromStdString(toSet)); + setGlobal(false); +} + +QMLSetting *QMLSetting::other() const +{ + return m_other; +} + +void QMLSetting::setOther(QMLSetting *newOther) +{ + if (m_other == newOther) + return; + m_other = newOther; + emit otherChanged(); +} + +u32 QMLSetting::max() const +{ + return std::strtol(m_setting->MaxVal().c_str(), nullptr, 0); +} + +u32 QMLSetting::min() const +{ + return std::strtol(m_setting->MinVal().c_str(), nullptr, 0); +} + +QString QMLSetting::suffix() const +{ + return m_suffix; +} + +void QMLSetting::setSuffix(const QString &newSuffix) +{ + if (m_suffix == newSuffix) + return; + m_suffix = newSuffix; + emit suffixChanged(); +} + +QStringList QMLSetting::combo() const +{ + return m_combo; +} + +void QMLSetting::setCombo(const QStringList &newCombo) +{ + if (m_combo == newCombo) + return; + m_combo = newCombo; + emit comboChanged(); +} + +QString QMLSetting::type() const +{ + return m_type; +} + +void QMLSetting::setType(const QString &newType) +{ + if (m_type == newType) + return; + m_type = newType; + emit typeChanged(); +} + +u32 QMLSetting::id() const +{ + return m_setting->Id(); +} + +QString QMLSetting::tooltip() const +{ + return m_tooltip; +} + +void QMLSetting::setTooltip(const QString &newTooltip) +{ + if (m_tooltip == newTooltip) + return; + m_tooltip = newTooltip; + emit tooltipChanged(); +} + +QString QMLSetting::label() const +{ + return m_label.isEmpty() ? QString::fromStdString(m_setting->GetLabel()) : m_label; +} + +void QMLSetting::setLabel(const QString &newLabel) +{ + if (m_label == newLabel) + return; + m_label = newLabel; + emit labelChanged(); +} diff --git a/src/eden/interface/QMLSetting.h b/src/eden/interface/QMLSetting.h new file mode 100644 index 0000000000..78349ae4f4 --- /dev/null +++ b/src/eden/interface/QMLSetting.h @@ -0,0 +1,105 @@ +#ifndef QMLSETTING_H +#define QMLSETTING_H + +#include +#include +#include "common/settings_common.h" + +enum class RequestType { + Default, + ComboBox, + SpinBox, + Slider, + ReverseSlider, + LineEdit, + HexEdit, + DateTimeEdit, + RadioGroup, + MaxEnum, +}; + +class QMLSetting : public QObject { + Q_OBJECT + +public: + explicit QMLSetting(Settings::BasicSetting *setting, QObject *parent = nullptr, RequestType request = RequestType::Default); + + QVariant value() const; + void setValue(const QVariant &newValue); + + bool global() const; + void setGlobal(bool newGlobal); + + QString label() const; + void setLabel(const QString &newLabel); + + QString tooltip() const; + void setTooltip(const QString &newTooltip); + + u32 id() const; + + QString type() const; + void setType(const QString &newType); + + QStringList combo() const; + void setCombo(const QStringList &newCombo); + + QString suffix() const; + void setSuffix(const QString &newSuffix); + + // TODO: float versions + u32 min() const; + u32 max() const; + + QMLSetting *other() const; + void setOther(QMLSetting *newOther); + +public slots: + void restore(); + +signals: + void valueChanged(); + void globalChanged(); + + void labelChanged(); + + void tooltipChanged(); + + void typeChanged(); + + void comboChanged(); + + void suffixChanged(); + + void otherChanged(); + +private: + Settings::BasicSetting *m_setting; + + QMLSetting *m_other; + + QString m_label; + QString m_tooltip; + QString m_type; + QStringList m_combo; + QString m_suffix; + + QMetaType::Type m_metaType; + + Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged FINAL) + Q_PROPERTY(bool global READ global WRITE setGlobal NOTIFY globalChanged FINAL) + Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY labelChanged FINAL) + Q_PROPERTY(QString tooltip READ tooltip WRITE setTooltip NOTIFY tooltipChanged FINAL) + Q_PROPERTY(u32 id READ id FINAL CONSTANT) + Q_PROPERTY(QString type READ type WRITE setType NOTIFY typeChanged FINAL) + Q_PROPERTY(QStringList combo READ combo WRITE setCombo NOTIFY comboChanged FINAL) + Q_PROPERTY(QString suffix READ suffix WRITE setSuffix NOTIFY suffixChanged FINAL) + + Q_PROPERTY(u32 min READ min FINAL CONSTANT) + Q_PROPERTY(u32 max READ max FINAL CONSTANT) + Q_PROPERTY(QMLSetting *other READ other WRITE setOther NOTIFY otherChanged FINAL) +}; + +Q_DECLARE_METATYPE(QMLSetting *) + +#endif // QMLSETTING_H diff --git a/src/eden/interface/SettingsInterface.cpp b/src/eden/interface/SettingsInterface.cpp new file mode 100644 index 0000000000..0265440628 --- /dev/null +++ b/src/eden/interface/SettingsInterface.cpp @@ -0,0 +1,124 @@ +#include "SettingsInterface.h" +#include "common/settings.h" +#include "common/logging/log.h" +#include "uisettings.h" + +SettingsInterface::SettingsInterface(QObject* parent) + : QObject{parent} + , translations{ConfigurationShared::InitializeTranslations(parent)} + , combobox_translations{ConfigurationShared::ComboboxEnumeration(parent)} +{} + +// TODO: idExclude +SettingsModel *SettingsInterface::category(SettingsCategories::Category category, + QList idInclude, + QList idExclude) +{ + std::vector settings = Settings::values.linkage.by_category[static_cast(category)]; + std::vector uisettings = UISettings::values.linkage.by_category[static_cast(category)]; + + settings.insert(settings.end(), uisettings.begin(), uisettings.end()); + + QList settingsList; + for (Settings::BasicSetting *setting : settings) { + // paired settings get ignored + if (setting->Specialization() == Settings::Specialization::Paired) { + LOG_DEBUG(Frontend, "\"{}\" has specialization Paired: ignoring", setting->GetLabel()); + continue; + } + + if ((idInclude.empty() || idInclude.contains(setting->GetLabel())) + && (idExclude.empty() || !idExclude.contains(setting->GetLabel()))) { + settingsList.append(this->getSetting(setting)); + } + } + + SettingsModel *model = new SettingsModel(this); + model->append(settingsList); + + return model; +} + +int SettingsInterface::id(const QString &key) +{ + return setting(key)->id(); +} + +bool SettingsInterface::global() const +{ + return Settings::IsConfiguringGlobal(); +} + +void SettingsInterface::setGlobal(bool newGlobal) +{ + Settings::SetConfiguringGlobal(newGlobal); +} + +QMLSetting *SettingsInterface::getSetting(Settings::BasicSetting *setting) +{ + if (setting == nullptr) { + return nullptr; + } + + if (m_settings.contains(setting->GetLabel())) { + return m_settings.value(setting->GetLabel()); + } + + const int id = setting->Id(); + + const auto [label, tooltip] = [&]() { + const auto& setting_label = setting->GetLabel(); + if (translations->contains(id)) { + return std::pair{translations->at(id).first, translations->at(id).second}; + } + + LOG_WARNING(Frontend, "Translation table lacks entry for \"{}\"", setting_label); + return std::pair{QString::fromStdString(setting_label), QString()}; + }(); + + const auto type = setting->EnumIndex(); + QStringList items; + + const ConfigurationShared::ComboboxTranslations* enumeration{nullptr}; + if (combobox_translations->contains(type)) { + enumeration = &combobox_translations->at(type); + for (const auto& [_, name] : *enumeration) { + items << name; + } + } + + // TODO: Suffix (fr) + QString suffix = ""; + + if ((setting->Specialization() & Settings::SpecializationAttributeMask) == + Settings::Specialization::Percentage) { + suffix = "%"; + } + + // paired setting (I/A) + QMLSetting *other = this->getSetting(setting->PairedSetting()); + + QMLSetting *qsetting = new QMLSetting(setting, this); + qsetting->setLabel(label); + qsetting->setTooltip(tooltip); + qsetting->setCombo(items); + qsetting->setSuffix(suffix); + qsetting->setOther(other); + + m_settings.insert(setting->GetLabel(), qsetting); + + return qsetting; +} + +QMLSetting *SettingsInterface::setting(const QString &key) +{ + std::string skey = key.toStdString(); + if (!m_settings.contains(skey)) { + Settings::BasicSetting *basicSetting = Settings::values.linkage.by_key.contains(skey) ? + Settings::values.linkage.by_key[skey] : + UISettings::values.linkage.by_key[skey]; + return getSetting(basicSetting); + } else { + return m_settings.value(skey); + } +} diff --git a/src/eden/interface/SettingsInterface.h b/src/eden/interface/SettingsInterface.h new file mode 100644 index 0000000000..4c132c3ce6 --- /dev/null +++ b/src/eden/interface/SettingsInterface.h @@ -0,0 +1,84 @@ +#ifndef SETTINGSINTERFACE_H +#define SETTINGSINTERFACE_H + +#include +#include + +#include "QMLSetting.h" +#include "shared_translation.h" +#include "yuzu/models/SettingsModel.h" + +namespace SettingsCategories { +Q_NAMESPACE + +enum class Category { + Android = static_cast(Settings::Category::Android), + Audio = static_cast(Settings::Category::Audio), + Core = static_cast(Settings::Category::Core), + Cpu = static_cast(Settings::Category::Cpu), + CpuDebug = static_cast(Settings::Category::CpuDebug), + CpuUnsafe = static_cast(Settings::Category::CpuUnsafe), + Overlay = static_cast(Settings::Category::Overlay), + Renderer = static_cast(Settings::Category::Renderer), + RendererAdvanced = static_cast(Settings::Category::RendererAdvanced), + RendererExtensions = static_cast(Settings::Category::RendererExtensions), + RendererDebug = static_cast(Settings::Category::RendererDebug), + System = static_cast(Settings::Category::System), + SystemAudio = static_cast(Settings::Category::SystemAudio), + DataStorage = static_cast(Settings::Category::DataStorage), + Debugging = static_cast(Settings::Category::Debugging), + DebuggingGraphics = static_cast(Settings::Category::DebuggingGraphics), + GpuDriver = static_cast(Settings::Category::GpuDriver), + Miscellaneous = static_cast(Settings::Category::Miscellaneous), + Network = static_cast(Settings::Category::Network), + WebService = static_cast(Settings::Category::WebService), + AddOns = static_cast(Settings::Category::AddOns), + Controls = static_cast(Settings::Category::Controls), + Ui = static_cast(Settings::Category::Ui), + UiAudio = static_cast(Settings::Category::UiAudio), + UiGeneral = static_cast(Settings::Category::UiGeneral), + UiLayout = static_cast(Settings::Category::UiLayout), + UiGameList = static_cast(Settings::Category::UiGameList), + Screenshots = static_cast(Settings::Category::Screenshots), + Shortcuts = static_cast(Settings::Category::Shortcuts), + Multiplayer = static_cast(Settings::Category::Multiplayer), + Services = static_cast(Settings::Category::Services), + Paths = static_cast(Settings::Category::Paths), + Linux = static_cast(Settings::Category::Linux), + LibraryApplet = static_cast(Settings::Category::LibraryApplet), + MaxEnum = static_cast(Settings::Category::MaxEnum), +}; +Q_ENUM_NS(Category) +} + +class SettingsInterface : public QObject { + Q_OBJECT + QML_SINGLETON + QML_ELEMENT +public: + explicit SettingsInterface(QObject* parent = nullptr); + + QMLSetting *getSetting(Settings::BasicSetting *setting); + Q_INVOKABLE QMLSetting *setting(const QString &key); + Q_INVOKABLE SettingsModel *category(SettingsCategories::Category category, + QList idInclude = {}, + QList idExclude = {}); + + Q_INVOKABLE int id(const QString &key); + + bool global() const; + void setGlobal(bool newGlobal); + +signals: + void globalChanged(); + +private: + QMap m_settings; + + std::unique_ptr translations; + std::unique_ptr combobox_translations; + + Q_PROPERTY(bool global READ global WRITE setGlobal NOTIFY globalChanged FINAL) +}; + +#endif // SETTINGSINTERFACE_H diff --git a/src/eden/interface/qt_config.cpp b/src/eden/interface/qt_config.cpp new file mode 100644 index 0000000000..f4390065c4 --- /dev/null +++ b/src/eden/interface/qt_config.cpp @@ -0,0 +1,562 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "qt_config.h" +#include "common/logging/log.h" +#include "input_common/main.h" +#include "uisettings.h" + +const std::array QtConfig::default_buttons = { + Qt::Key_C, Qt::Key_X, Qt::Key_V, Qt::Key_Z, Qt::Key_F, + Qt::Key_G, Qt::Key_Q, Qt::Key_E, Qt::Key_R, Qt::Key_T, + Qt::Key_M, Qt::Key_N, Qt::Key_Left, Qt::Key_Up, Qt::Key_Right, + Qt::Key_Down, Qt::Key_Q, Qt::Key_E, 0, 0, + Qt::Key_Q, Qt::Key_E, +}; + +const std::array QtConfig::default_motions = { + Qt::Key_7, + Qt::Key_8, +}; + +const std::array, Settings::NativeAnalog::NumAnalogs> QtConfig::default_analogs{{ + { + Qt::Key_W, + Qt::Key_S, + Qt::Key_A, + Qt::Key_D, + }, + { + Qt::Key_I, + Qt::Key_K, + Qt::Key_J, + Qt::Key_L, + }, +}}; + +const std::array QtConfig::default_stick_mod = { + Qt::Key_Shift, + 0, +}; + +const std::array QtConfig::default_ringcon_analogs{{ + Qt::Key_A, + Qt::Key_D, +}}; + +QtConfig::QtConfig(const std::string& config_name, const ConfigType config_type) + : Config(config_type) { + Initialize(config_name); + if (config_type != ConfigType::InputProfile) { + ReadQtValues(); + SaveQtValues(); + } +} + +QtConfig::~QtConfig() { + if (global) { + QtConfig::SaveAllValues(); + } +} + +void QtConfig::ReloadAllValues() { + Reload(); + ReadQtValues(); + SaveQtValues(); +} + +void QtConfig::SaveAllValues() { + SaveValues(); + SaveQtValues(); +} + +void QtConfig::ReadQtValues() { + if (global) { + ReadUIValues(); + } + ReadQtControlValues(); +} + +void QtConfig::ReadQtPlayerValues(const std::size_t player_index) { + std::string player_prefix; + if (type != ConfigType::InputProfile) { + player_prefix.append("player_").append(ToString(player_index)).append("_"); + } + + auto& player = Settings::values.players.GetValue()[player_index]; + if (IsCustomConfig()) { + const auto profile_name = + ReadStringSetting(std::string(player_prefix).append("profile_name")); + if (profile_name.empty()) { + // Use the global input config + player = Settings::values.players.GetValue(true)[player_index]; + player.profile_name = ""; + return; + } + } + + for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { + const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); + auto& player_buttons = player.buttons[i]; + + player_buttons = ReadStringSetting( + std::string(player_prefix).append(Settings::NativeButton::mapping[i]), default_param); + if (player_buttons.empty()) { + player_buttons = default_param; + } + } + + for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], + default_analogs[i][3], default_stick_mod[i], 0.5f); + auto& player_analogs = player.analogs[i]; + + player_analogs = ReadStringSetting( + std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), default_param); + if (player_analogs.empty()) { + player_analogs = default_param; + } + } + + for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { + const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); + auto& player_motions = player.motions[i]; + + player_motions = ReadStringSetting( + std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), default_param); + if (player_motions.empty()) { + player_motions = default_param; + } + } +} + +void QtConfig::ReadHidbusValues() { + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); + auto& ringcon_analogs = Settings::values.ringcon_analogs; + + ringcon_analogs = ReadStringSetting(std::string("ring_controller"), default_param); + if (ringcon_analogs.empty()) { + ringcon_analogs = default_param; + } +} + +void QtConfig::ReadDebugControlValues() { + for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { + const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); + auto& debug_pad_buttons = Settings::values.debug_pad_buttons[i]; + + debug_pad_buttons = ReadStringSetting( + std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), default_param); + if (debug_pad_buttons.empty()) { + debug_pad_buttons = default_param; + } + } + + for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], + default_analogs[i][3], default_stick_mod[i], 0.5f); + auto& debug_pad_analogs = Settings::values.debug_pad_analogs[i]; + + debug_pad_analogs = ReadStringSetting( + std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), default_param); + if (debug_pad_analogs.empty()) { + debug_pad_analogs = default_param; + } + } +} + +void QtConfig::ReadQtControlValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); + + Settings::values.players.SetGlobal(!IsCustomConfig()); + for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { + ReadQtPlayerValues(p); + } + if (IsCustomConfig()) { + EndGroup(); + return; + } + ReadDebugControlValues(); + ReadHidbusValues(); + + EndGroup(); +} + +void QtConfig::ReadPathValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Paths)); + + UISettings::values.roms_path = ReadStringSetting(std::string("romsPath")); + UISettings::values.game_dir_deprecated = + ReadStringSetting(std::string("gameListRootDir"), std::string(".")); + UISettings::values.game_dir_deprecated_deepscan = + ReadBooleanSetting(std::string("gameListDeepScan"), std::make_optional(false)); + + const int gamedirs_size = BeginArray(std::string("gamedirs")); + for (int i = 0; i < gamedirs_size; ++i) { + SetArrayIndex(i); + UISettings::GameDir game_dir; + game_dir.path = ReadStringSetting(std::string("path")); + game_dir.deep_scan = + ReadBooleanSetting(std::string("deep_scan"), std::make_optional(false)); + game_dir.expanded = ReadBooleanSetting(std::string("expanded"), std::make_optional(true)); + UISettings::values.game_dirs.append(game_dir); + } + EndArray(); + + // Create NAND and SD card directories if empty, these are not removable through the UI, + // also carries over old game list settings if present + if (UISettings::values.game_dirs.empty()) { + UISettings::GameDir game_dir; + game_dir.path = std::string("SDMC"); + game_dir.expanded = true; + UISettings::values.game_dirs.append(game_dir); + game_dir.path = std::string("UserNAND"); + UISettings::values.game_dirs.append(game_dir); + game_dir.path = std::string("SysNAND"); + UISettings::values.game_dirs.append(game_dir); + if (UISettings::values.game_dir_deprecated != std::string(".")) { + game_dir.path = UISettings::values.game_dir_deprecated; + game_dir.deep_scan = UISettings::values.game_dir_deprecated_deepscan; + UISettings::values.game_dirs.append(game_dir); + } + } + UISettings::values.recent_files = + QString::fromStdString(ReadStringSetting(std::string("recentFiles"))) + .split(QStringLiteral(", "), Qt::SkipEmptyParts, Qt::CaseSensitive); + + ReadCategory(Settings::Category::Paths); + + EndGroup(); +} + +void QtConfig::ReadShortcutValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Shortcuts)); + + for (const auto& [name, group, shortcut] : UISettings::default_hotkeys) { + BeginGroup(group); + BeginGroup(name); + + // No longer using ReadSetting for shortcut.second as it inaccurately returns a value of 1 + // for WidgetWithChildrenShortcut which is a value of 3. Needed to fix shortcuts the open + // a file dialog in windowed mode + UISettings::values.shortcuts.push_back( + {name, + group, + {ReadStringSetting(std::string("KeySeq"), shortcut.keyseq), + ReadStringSetting(std::string("Controller_KeySeq"), shortcut.controller_keyseq), + shortcut.context, + ReadBooleanSetting(std::string("Repeat"), std::optional(shortcut.repeat))}}); + + EndGroup(); // name + EndGroup(); // group + } + + EndGroup(); +} + +void QtConfig::ReadUIValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Ui)); + + UISettings::values.theme = ReadStringSetting( + std::string("theme"), + std::string(UISettings::themes[static_cast(UISettings::default_theme)].second)); + + ReadUIGamelistValues(); + ReadUILayoutValues(); + ReadPathValues(); + ReadScreenshotValues(); + ReadShortcutValues(); + ReadMultiplayerValues(); + + ReadCategory(Settings::Category::Ui); + ReadCategory(Settings::Category::UiGeneral); + + EndGroup(); +} + +void QtConfig::ReadUIGamelistValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::UiGameList)); + + ReadCategory(Settings::Category::UiGameList); + + const int favorites_size = BeginArray("favorites"); + for (int i = 0; i < favorites_size; i++) { + SetArrayIndex(i); + UISettings::values.favorited_ids.append( + ReadUnsignedIntegerSetting(std::string("program_id"))); + } + EndArray(); + + EndGroup(); +} + +void QtConfig::ReadUILayoutValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::UiGameList)); + + ReadCategory(Settings::Category::UiLayout); + + EndGroup(); +} + +void QtConfig::ReadMultiplayerValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Multiplayer)); + + ReadCategory(Settings::Category::Multiplayer); + + // Read ban list back + int size = BeginArray(std::string("username_ban_list")); + UISettings::values.multiplayer_ban_list.first.resize(size); + for (int i = 0; i < size; ++i) { + SetArrayIndex(i); + UISettings::values.multiplayer_ban_list.first[i] = + ReadStringSetting(std::string("username"), std::string("")); + } + EndArray(); + + size = BeginArray(std::string("ip_ban_list")); + UISettings::values.multiplayer_ban_list.second.resize(size); + for (int i = 0; i < size; ++i) { + UISettings::values.multiplayer_ban_list.second[i] = + ReadStringSetting("username", std::string("")); + } + EndArray(); + + EndGroup(); +} + +void QtConfig::SaveQtValues() +{ + if (global) { + LOG_DEBUG(Config, "Saving global Qt configuration values"); + SaveUIValues(); + } else { + LOG_DEBUG(Config, "Saving Qt configuration values"); + } + SaveQtControlValues(); + + WriteToIni(); +} + +void QtConfig::SaveQtPlayerValues(const std::size_t player_index) { + std::string player_prefix; + if (type != ConfigType::InputProfile) { + player_prefix = std::string("player_").append(ToString(player_index)).append("_"); + } + + const auto& player = Settings::values.players.GetValue()[player_index]; + if (IsCustomConfig() && player.profile_name.empty()) { + // No custom profile selected + return; + } + + for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { + const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); + WriteStringSetting(std::string(player_prefix).append(Settings::NativeButton::mapping[i]), + player.buttons[i], std::make_optional(default_param)); + } + for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], + default_analogs[i][3], default_stick_mod[i], 0.5f); + WriteStringSetting(std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), + player.analogs[i], std::make_optional(default_param)); + } + for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { + const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); + WriteStringSetting(std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), + player.motions[i], std::make_optional(default_param)); + } +} + +void QtConfig::SaveDebugControlValues() { + for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { + const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); + WriteStringSetting(std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), + Settings::values.debug_pad_buttons[i], + std::make_optional(default_param)); + } + for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], + default_analogs[i][3], default_stick_mod[i], 0.5f); + WriteStringSetting(std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), + Settings::values.debug_pad_analogs[i], + std::make_optional(default_param)); + } +} + +void QtConfig::SaveHidbusValues() { + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); + WriteStringSetting(std::string("ring_controller"), Settings::values.ringcon_analogs, + std::make_optional(default_param)); +} + +void QtConfig::SaveQtControlValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); + + Settings::values.players.SetGlobal(!IsCustomConfig()); + for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { + SaveQtPlayerValues(p); + } + if (IsCustomConfig()) { + EndGroup(); + return; + } + SaveDebugControlValues(); + SaveHidbusValues(); + + EndGroup(); +} + +void QtConfig::SavePathValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Paths)); + + WriteCategory(Settings::Category::Paths); + + WriteStringSetting(std::string("romsPath"), UISettings::values.roms_path); + BeginArray(std::string("gamedirs")); + for (int i = 0; i < UISettings::values.game_dirs.size(); ++i) { + SetArrayIndex(i); + const auto& game_dir = UISettings::values.game_dirs[i]; + WriteStringSetting(std::string("path"), game_dir.path); + WriteBooleanSetting(std::string("deep_scan"), game_dir.deep_scan, + std::make_optional(false)); + WriteBooleanSetting(std::string("expanded"), game_dir.expanded, std::make_optional(true)); + } + EndArray(); + + WriteStringSetting(std::string("recentFiles"), + UISettings::values.recent_files.join(QStringLiteral(", ")).toStdString()); + + EndGroup(); +} + +void QtConfig::SaveShortcutValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Shortcuts)); + + // Lengths of UISettings::values.shortcuts & default_hotkeys are same. + // However, their ordering must also be the same. + for (std::size_t i = 0; i < UISettings::default_hotkeys.size(); i++) { + const auto& [name, group, shortcut] = UISettings::values.shortcuts[i]; + const auto& default_hotkey = UISettings::default_hotkeys[i].shortcut; + + BeginGroup(group); + BeginGroup(name); + + WriteStringSetting(std::string("KeySeq"), shortcut.keyseq, + std::make_optional(default_hotkey.keyseq)); + WriteStringSetting(std::string("Controller_KeySeq"), shortcut.controller_keyseq, + std::make_optional(default_hotkey.controller_keyseq)); + WriteIntegerSetting(std::string("Context"), shortcut.context, + std::make_optional(default_hotkey.context)); + WriteBooleanSetting(std::string("Repeat"), shortcut.repeat, + std::make_optional(default_hotkey.repeat)); + + EndGroup(); // name + EndGroup(); // group + } + + EndGroup(); +} + +void QtConfig::SaveUIValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Ui)); + + WriteCategory(Settings::Category::Ui); + WriteCategory(Settings::Category::UiGeneral); + + WriteStringSetting( + std::string("theme"), UISettings::values.theme, + std::make_optional(std::string( + UISettings::themes[static_cast(UISettings::default_theme)].second))); + + SaveUIGamelistValues(); + SaveUILayoutValues(); + SavePathValues(); + SaveScreenshotValues(); + SaveShortcutValues(); + SaveMultiplayerValues(); + + EndGroup(); +} + +void QtConfig::SaveUIGamelistValues() +{ + BeginGroup(Settings::TranslateCategory(Settings::Category::UiGameList)); + + WriteCategory(Settings::Category::UiGameList); + + BeginArray(std::string("favorites")); + for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) { + SetArrayIndex(i); + WriteIntegerSetting(std::string("program_id"), UISettings::values.favorited_ids[i]); + } + EndArray(); // favorites + + EndGroup(); +} + +void QtConfig::SaveUILayoutValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::UiLayout)); + + WriteCategory(Settings::Category::UiLayout); + + EndGroup(); +} + +void QtConfig::SaveMultiplayerValues() { + BeginGroup(std::string("Multiplayer")); + + WriteCategory(Settings::Category::Multiplayer); + + // Write ban list + BeginArray(std::string("username_ban_list")); + for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.first.size(); ++i) { + SetArrayIndex(static_cast(i)); + WriteStringSetting(std::string("username"), + UISettings::values.multiplayer_ban_list.first[i]); + } + EndArray(); // username_ban_list + + BeginArray(std::string("ip_ban_list")); + for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.second.size(); ++i) { + SetArrayIndex(static_cast(i)); + WriteStringSetting(std::string("ip"), UISettings::values.multiplayer_ban_list.second[i]); + } + EndArray(); // ip_ban_list + + EndGroup(); +} + +std::vector& QtConfig::FindRelevantList(Settings::Category category) { + auto& map = Settings::values.linkage.by_category; + if (map.contains(category)) { + return Settings::values.linkage.by_category[category]; + } + return UISettings::values.linkage.by_category[category]; +} + +void QtConfig::ReadQtControlPlayerValues(std::size_t player_index) { + BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); + + ReadPlayerValues(player_index); + ReadQtPlayerValues(player_index); + + EndGroup(); +} + +void QtConfig::SaveQtControlPlayerValues(std::size_t player_index) { + BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); + + LOG_DEBUG(Config, "Saving players control configuration values"); + SavePlayerValues(player_index); + SaveQtPlayerValues(player_index); + + EndGroup(); + + WriteToIni(); +} diff --git a/src/eden/interface/qt_config.h b/src/eden/interface/qt_config.h new file mode 100644 index 0000000000..dc2dceb4d7 --- /dev/null +++ b/src/eden/interface/qt_config.h @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include "frontend_common/config.h" + +class QtConfig final : public Config { +public: + explicit QtConfig(const std::string& config_name = "qt-config", + ConfigType config_type = ConfigType::GlobalConfig); + ~QtConfig() override; + + void ReloadAllValues() override; + void SaveAllValues() override; + + void ReadQtControlPlayerValues(std::size_t player_index); + void SaveQtControlPlayerValues(std::size_t player_index); + +protected: + void ReadQtValues(); + void ReadQtPlayerValues(std::size_t player_index); + void ReadQtControlValues(); + void ReadHidbusValues() override; + void ReadDebugControlValues() override; + void ReadPathValues() override; + void ReadShortcutValues() override; + void ReadUIValues() override; + void ReadUIGamelistValues() override; + void ReadUILayoutValues() override; + void ReadMultiplayerValues() override; + + void SaveQtValues(); + void SaveQtPlayerValues(std::size_t player_index); + void SaveQtControlValues(); + void SaveHidbusValues() override; + void SaveDebugControlValues() override; + void SavePathValues() override; + void SaveShortcutValues() override; + void SaveUIValues() override; + void SaveUIGamelistValues() override; + void SaveUILayoutValues() override; + void SaveMultiplayerValues() override; + + std::vector& FindRelevantList(Settings::Category category) override; + +public: + static const std::array default_buttons; + static const std::array default_motions; + static const std::array, Settings::NativeAnalog::NumAnalogs> default_analogs; + static const std::array default_stick_mod; + static const std::array default_ringcon_analogs; +}; diff --git a/src/eden/interface/shared_translation.cpp b/src/eden/interface/shared_translation.cpp new file mode 100644 index 0000000000..c0eea3d440 --- /dev/null +++ b/src/eden/interface/shared_translation.cpp @@ -0,0 +1,569 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "shared_translation.h" + +#include +#include "common/settings.h" +#include "common/settings_enums.h" +#include "common/settings_setting.h" +#include "common/time_zone.h" +#include "uisettings.h" +#include +#include +#include +#include + +namespace ConfigurationShared { + +std::unique_ptr InitializeTranslations(QObject* parent) +{ + std::unique_ptr translations = std::make_unique(); + const auto& tr = [parent](const char* text) -> QString { return parent->tr(text); }; + +#define INSERT(SETTINGS, ID, NAME, TOOLTIP) \ + translations->insert(std::pair{SETTINGS::values.ID.Id(), std::pair{(NAME), (TOOLTIP)}}) + + // A setting can be ignored by giving it a blank name + + // Applets + INSERT(Settings, cabinet_applet_mode, tr("Amiibo editor"), QString()); + INSERT(Settings, controller_applet_mode, tr("Controller configuration"), QString()); + INSERT(Settings, data_erase_applet_mode, tr("Data erase"), QString()); + INSERT(Settings, error_applet_mode, tr("Error"), QString()); + INSERT(Settings, net_connect_applet_mode, tr("Net connect"), QString()); + INSERT(Settings, player_select_applet_mode, tr("Player select"), QString()); + INSERT(Settings, swkbd_applet_mode, tr("Software keyboard"), QString()); + INSERT(Settings, mii_edit_applet_mode, tr("Mii Edit"), QString()); + INSERT(Settings, web_applet_mode, tr("Online web"), QString()); + INSERT(Settings, shop_applet_mode, tr("Shop"), QString()); + INSERT(Settings, photo_viewer_applet_mode, tr("Photo viewer"), QString()); + INSERT(Settings, offline_web_applet_mode, tr("Offline web"), QString()); + INSERT(Settings, login_share_applet_mode, tr("Login share"), QString()); + INSERT(Settings, wifi_web_auth_applet_mode, tr("Wifi web auth"), QString()); + INSERT(Settings, my_page_applet_mode, tr("My page"), QString()); + + // Audio + INSERT(Settings, sink_id, tr("Output Engine:"), QString()); + INSERT(Settings, audio_output_device_id, tr("Output Device:"), QString()); + INSERT(Settings, audio_input_device_id, tr("Input Device:"), QString()); + INSERT(Settings, audio_muted, tr("Mute audio"), QString()); + INSERT(Settings, volume, tr("Volume:"), QString()); + INSERT(Settings, dump_audio_commands, QString(), QString()); + INSERT(UISettings, mute_when_in_background, tr("Mute audio when in background"), QString()); + + // Core + INSERT( + Settings, use_multi_core, tr("Multicore CPU Emulation"), + tr("This option increases CPU emulation thread use from 1 to the Switch’s maximum of 4.\n" + "This is mainly a debug option and shouldn’t be disabled.")); + INSERT( + Settings, memory_layout_mode, tr("Memory Layout"), + tr("Increases the amount of emulated RAM from the stock 4GB of the retail Switch to the " + "developer kit's 8/6GB.\nIt’s doesn’t improve stability or performance and is intended " + "to let big texture mods fit in emulated RAM.\nEnabling it will increase memory " + "use. It is not recommended to enable unless a specific game with a texture mod needs " + "it.")); + INSERT(Settings, use_speed_limit, QString(), QString()); + INSERT(Settings, speed_limit, tr("Limit Speed Percent"), + tr("Controls the game's maximum rendering speed, but it’s up to each game if it runs " + "faster or not.\n200% for a 30 FPS game is 60 FPS, and for a " + "60 FPS game it will be 120 FPS.\nDisabling it means unlocking the framerate to the " + "maximum your PC can reach.")); + INSERT(Settings, sync_core_speed, tr("Synchronize Core Speed"), + tr("Synchronizes CPU core speed with the game's maximum rendering speed to boost FPS without affecting game speed (animations, physics, etc.).\n" + "Compatibility varies by game; many (especially older ones) may not respond well.\n" + "Can help reduce stuttering at lower framerates.")); + + // Cpu + INSERT(Settings, cpu_accuracy, tr("Accuracy:"), + tr("This setting controls the accuracy of the emulated CPU.\nDon't change this unless " + "you know what you are doing.")); + INSERT(Settings, cpu_backend, tr("Backend:"), QString()); + + // Cpu Debug + + // Cpu Unsafe + INSERT( + Settings, cpuopt_unsafe_unfuse_fma, + tr("Unfuse FMA (improve performance on CPUs without FMA)"), + tr("This option improves speed by reducing accuracy of fused-multiply-add instructions on " + "CPUs without native FMA support.")); + INSERT( + Settings, cpuopt_unsafe_reduce_fp_error, tr("Faster FRSQRTE and FRECPE"), + tr("This option improves the speed of some approximate floating-point functions by using " + "less accurate native approximations.")); + INSERT(Settings, cpuopt_unsafe_ignore_standard_fpcr, + tr("Faster ASIMD instructions (32 bits only)"), + tr("This option improves the speed of 32 bits ASIMD floating-point functions by running " + "with incorrect rounding modes.")); + INSERT(Settings, cpuopt_unsafe_inaccurate_nan, tr("Inaccurate NaN handling"), + tr("This option improves speed by removing NaN checking.\nPlease note this also reduces " + "accuracy of certain floating-point instructions.")); + INSERT(Settings, cpuopt_unsafe_fastmem_check, tr("Disable address space checks"), + tr("This option improves speed by eliminating a safety check before every memory " + "read/write in guest.\nDisabling it may allow a game to read/write the emulator's " + "memory.")); + INSERT( + Settings, cpuopt_unsafe_ignore_global_monitor, tr("Ignore global monitor"), + tr("This option improves speed by relying only on the semantics of cmpxchg to ensure " + "safety of exclusive access instructions.\nPlease note this may result in deadlocks and " + "other race conditions.")); + + // Renderer + INSERT( + Settings, renderer_backend, tr("API:"), + tr("Switches between the available graphics APIs.\nVulkan is recommended in most cases.")); + INSERT(Settings, vulkan_device, tr("Device:"), + tr("This setting selects the GPU to use with the Vulkan backend.")); + INSERT(Settings, shader_backend, tr("Shader Backend:"), + tr("The shader backend to use for the OpenGL renderer.\nGLSL is the fastest in " + "performance and the best in rendering accuracy.\n" + "GLASM is a deprecated NVIDIA-only backend that offers much better shader building " + "performance at the cost of FPS and rendering accuracy.\n" + "SPIR-V compiles the fastest, but yields poor results on most GPU drivers.")); + INSERT(Settings, resolution_setup, tr("Resolution:"), + tr("Forces the game to render at a different resolution.\nHigher resolutions require " + "much more VRAM and bandwidth.\n" + "Options lower than 1X can cause rendering issues.")); + INSERT(Settings, scaling_filter, tr("Window Adapting Filter:"), QString()); + INSERT(Settings, fsr_sharpening_slider, tr("FSR Sharpness:"), + tr("Determines how sharpened the image will look while using FSR’s dynamic contrast.")); + INSERT(Settings, anti_aliasing, tr("Anti-Aliasing Method:"), + tr("The anti-aliasing method to use.\nSMAA offers the best quality.\nFXAA has a " + "lower performance impact and can produce a better and more stable picture under " + "very low resolutions.")); + INSERT(Settings, fullscreen_mode, tr("Fullscreen Mode:"), + tr("The method used to render the window in fullscreen.\nBorderless offers the best " + "compatibility with the on-screen keyboard that some games request for " + "input.\nExclusive " + "fullscreen may offer better performance and better Freesync/Gsync support.")); + INSERT(Settings, aspect_ratio, tr("Aspect Ratio:"), + tr("Stretches the game to fit the specified aspect ratio.\nSwitch games only support " + "16:9, so custom game mods are required to get other ratios.\nAlso controls the " + "aspect ratio of captured screenshots.")); + INSERT(Settings, use_disk_shader_cache, tr("Use disk pipeline cache"), + tr("Allows saving shaders to storage for faster loading on following game " + "boots.\nDisabling " + "it is only intended for debugging.")); + INSERT(Settings, optimize_spirv_output, tr("Optimize SPIRV output shader"), + tr("Runs an additional optimization pass over generated SPIRV shaders.\n" + "Will increase time required for shader compilation.\nMay slightly improve " + "performance.\nThis feature is experimental.")); + INSERT( + Settings, use_asynchronous_gpu_emulation, tr("Use asynchronous GPU emulation"), + tr("Uses an extra CPU thread for rendering.\nThis option should always remain enabled.")); + INSERT(Settings, nvdec_emulation, tr("NVDEC emulation:"), + tr("Specifies how videos should be decoded.\nIt can either use the CPU or the GPU for " + "decoding, or perform no decoding at all (black screen on videos).\n" + "In most cases, GPU decoding provides the best performance.")); + INSERT(Settings, accelerate_astc, tr("ASTC Decoding Method:"), + tr("This option controls how ASTC textures should be decoded.\n" + "CPU: Use the CPU for decoding, slowest but safest method.\n" + "GPU: Use the GPU's compute shaders to decode ASTC textures, recommended for most " + "games and users.\n" + "CPU Asynchronously: Use the CPU to decode ASTC textures as they arrive. Completely " + "eliminates ASTC decoding\nstuttering at the cost of rendering issues while the " + "texture is being decoded.")); + INSERT( + Settings, astc_recompression, tr("ASTC Recompression Method:"), + tr("Almost all desktop and laptop dedicated GPUs lack support for ASTC textures, forcing " + "the emulator to decompress to an intermediate format any card supports, RGBA8.\n" + "This option recompresses RGBA8 to either the BC1 or BC3 format, saving VRAM but " + "negatively affecting image quality.")); + INSERT(Settings, vram_usage_mode, tr("VRAM Usage Mode:"), + tr("Selects whether the emulator should prefer to conserve memory or make maximum usage " + "of available video memory for performance. Has no effect on integrated graphics. " + "Aggressive mode may severely impact the performance of other applications such as " + "recording software.")); + INSERT( + Settings, vsync_mode, tr("VSync Mode:"), + tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen " + "refresh rate.\nFIFO Relaxed is similar to FIFO but allows tearing as it recovers from " + "a slow down.\nMailbox can have lower latency than FIFO and does not tear but may drop " + "frames.\nImmediate (no synchronization) just presents whatever is available and can " + "exhibit tearing.")); + INSERT(Settings, bg_red, QString(), QString()); + INSERT(Settings, bg_green, QString(), QString()); + INSERT(Settings, bg_blue, QString(), QString()); + + // Renderer (Advanced Graphics) + INSERT(Settings, async_presentation, tr("Enable asynchronous presentation (Vulkan only)"), + tr("Slightly improves performance by moving presentation to a separate CPU thread.")); + INSERT( + Settings, renderer_force_max_clock, tr("Force maximum clocks (Vulkan only)"), + tr("Runs work in the background while waiting for graphics commands to keep the GPU from " + "lowering its clock speed.")); + INSERT(Settings, max_anisotropy, tr("Anisotropic Filtering:"), + tr("Controls the quality of texture rendering at oblique angles.\nIt’s a light setting " + "and safe to set at 16x on most GPUs.")); + INSERT(Settings, gpu_accuracy, tr("Accuracy Level:"), + tr("GPU emulation accuracy.\nMost games render fine with Normal, but High is still " + "required for some.\nParticles tend to only render correctly with High " + "accuracy.\nExtreme should only be used for debugging.\nThis option can " + "be changed while playing.\nSome games may require booting on high to render " + "properly.")); + INSERT(Settings, use_asynchronous_shaders, tr("Use asynchronous shader building (Hack)"), + tr("Enables asynchronous shader compilation, which may reduce shader stutter.\nThis " + "feature " + "is experimental.")); + INSERT(Settings, use_fast_gpu_time, tr("Use Fast GPU Time (Hack)"), + tr("Enables Fast GPU Time. This option will force most games to run at their highest " + "native resolution.")); + INSERT(Settings, use_vulkan_driver_pipeline_cache, tr("Use Vulkan pipeline cache"), + tr("Enables GPU vendor-specific pipeline cache.\nThis option can improve shader loading " + "time significantly in cases where the Vulkan driver does not store pipeline cache " + "files internally.")); + INSERT( + Settings, enable_compute_pipelines, tr("Enable Compute Pipelines (Intel Vulkan Only)"), + tr("Enable compute pipelines, required by some games.\nThis setting only exists for Intel " + "proprietary drivers, and may crash if enabled.\nCompute pipelines are always enabled " + "on all other drivers.")); + INSERT( + Settings, use_reactive_flushing, tr("Enable Reactive Flushing"), + tr("Uses reactive flushing instead of predictive flushing, allowing more accurate memory " + "syncing.")); + INSERT(Settings, use_video_framerate, tr("Sync to framerate of video playback"), + tr("Run the game at normal speed during video playback, even when the framerate is " + "unlocked.")); + INSERT(Settings, barrier_feedback_loops, tr("Barrier feedback loops"), + tr("Improves rendering of transparency effects in specific games.")); + + // Renderer (Extensions) + INSERT(Settings, dyna_state, tr("Extended Dynamic State"), + tr("Enables the VkExtendedDynamicState* extensions.\nHigher dynamic states will generally improve " + "performance, but may cause issues on certain games or devices.")); + + INSERT(Settings, provoking_vertex, tr("Provoking Vertex"), + tr("Improves lighting and vertex handling in certain games.\n" + "Only Vulkan 1.0+ devices support this extension.")); + + INSERT(Settings, descriptor_indexing, tr("Descriptor Indexing"), + tr("Improves texture & buffer handling and the Maxwell translation layer.\n" + "Some Vulkan 1.1+ and all 1.2+ devices support this extension.")); + + // Renderer (Debug) + + // System + INSERT(Settings, rng_seed, tr("RNG Seed"), + tr("Controls the seed of the random number generator.\nMainly used for speedrunning " + "purposes.")); + INSERT(Settings, rng_seed_enabled, QString(), QString()); + INSERT(Settings, device_name, tr("Device Name"), tr("The name of the emulated Switch.")); + INSERT(Settings, custom_rtc, tr("Custom RTC Date:"), + tr("This option allows to change the emulated clock of the Switch.\n" + "Can be used to manipulate time in games.")); + INSERT(Settings, custom_rtc_enabled, QString(), QString()); + INSERT(Settings, custom_rtc_offset, QStringLiteral(" "), + QStringLiteral("The number of seconds from the current unix time")); + INSERT(Settings, language_index, tr("Language:"), + tr("Note: this can be overridden when region setting is auto-select")); + INSERT(Settings, region_index, tr("Region:"), tr("The region of the emulated Switch.")); + INSERT(Settings, time_zone_index, tr("Time Zone:"), + tr("The time zone of the emulated Switch.")); + INSERT(Settings, sound_index, tr("Sound Output Mode:"), QString()); + INSERT(Settings, use_docked_mode, tr("Console Mode:"), + tr("Selects if the console is emulated in Docked or Handheld mode.\nGames will change " + "their resolution, details and supported controllers and depending on this setting.\n" + "Setting to Handheld can help improve performance for low end systems.")); + INSERT(Settings, current_user, QString(), QString()); + + // Controls + + // Data Storage + + // Debugging + + // Debugging Graphics + + // Network + + // Web Service + + // Ui + + // Ui General + INSERT(UISettings, select_user_on_boot, tr("Prompt for user on game boot"), + tr("Ask to select a user profile on each boot, useful if multiple people use eden on " + "the same PC.")); + INSERT(UISettings, pause_when_in_background, tr("Pause emulation when in background"), + tr("This setting pauses eden when focusing other windows.")); + INSERT(UISettings, confirm_before_stopping, tr("Confirm before stopping emulation"), + tr("This setting overrides game prompts asking to confirm stopping the game.\nEnabling " + "it bypasses such prompts and directly exits the emulation.")); + INSERT(UISettings, hide_mouse, tr("Hide mouse on inactivity"), + tr("This setting hides the mouse after 2.5s of inactivity.")); + INSERT(UISettings, controller_applet_disabled, tr("Disable controller applet"), + tr("Forcibly disables the use of the controller applet by guests.\nWhen a guest " + "attempts to open the controller applet, it is immediately closed.")); + + // Linux + INSERT(Settings, enable_gamemode, tr("Enable Gamemode"), QString()); + + // Ui Debugging + + // Ui Multiplayer + + // Ui Games list + INSERT(UISettings, + grid_columns, + tr("Grid View Columns"), + tr("Number of games to show per row in the grid view.")); + +#undef INSERT + + return translations; +} + +std::unique_ptr ComboboxEnumeration(QObject* parent) +{ + std::unique_ptr translations = + std::make_unique(); + const auto& tr = [&](const char* text, const char* context = "") { + return parent->tr(text, context); + }; + +#define PAIR(ENUM, VALUE, TRANSLATION) {static_cast(Settings::ENUM::VALUE), (TRANSLATION)} + + // Intentionally skipping VSyncMode to let the UI fill that one out + translations->insert({Settings::EnumMetadata::Index(), + { + PAIR(AppletMode, HLE, tr("Custom frontend")), + PAIR(AppletMode, LLE, tr("Real applet")), + }}); + translations->insert({Settings::EnumMetadata::Index(), + { + PAIR(SpirvOptimizeMode, Never, tr("Never")), + PAIR(SpirvOptimizeMode, OnLoad, tr("On Load")), + PAIR(SpirvOptimizeMode, Always, tr("Always")), + }}); + translations->insert({Settings::EnumMetadata::Index(), + { + PAIR(AstcDecodeMode, Cpu, tr("CPU")), + PAIR(AstcDecodeMode, Gpu, tr("GPU")), + PAIR(AstcDecodeMode, CpuAsynchronous, tr("CPU Asynchronous")), + }}); + translations->insert( + {Settings::EnumMetadata::Index(), + { + PAIR(AstcRecompression, Uncompressed, tr("Uncompressed (Best quality)")), + PAIR(AstcRecompression, Bc1, tr("BC1 (Low quality)")), + PAIR(AstcRecompression, Bc3, tr("BC3 (Medium quality)")), + }}); + translations->insert({Settings::EnumMetadata::Index(), + { + PAIR(VramUsageMode, Conservative, tr("Conservative")), + PAIR(VramUsageMode, Aggressive, tr("Aggressive")), + }}); + translations->insert({Settings::EnumMetadata::Index(), + { +#ifdef HAS_OPENGL + PAIR(RendererBackend, OpenGL, tr("OpenGL")), +#endif + PAIR(RendererBackend, Vulkan, tr("Vulkan")), + PAIR(RendererBackend, Null, tr("Null")), + }}); + translations->insert( + {Settings::EnumMetadata::Index(), + { + PAIR(ShaderBackend, Glsl, tr("GLSL")), + PAIR(ShaderBackend, Glasm, tr("GLASM (Assembly Shaders, NVIDIA Only)")), + PAIR(ShaderBackend, SpirV, tr("SPIR-V (Experimental, AMD/Mesa Only)")), + }}); + translations->insert({Settings::EnumMetadata::Index(), + { + PAIR(GpuAccuracy, Normal, tr("Normal")), + PAIR(GpuAccuracy, High, tr("High")), + PAIR(GpuAccuracy, Extreme, tr("Extreme")), + }}); + translations->insert( + {Settings::EnumMetadata::Index(), + { + PAIR(CpuAccuracy, Auto, tr("Auto")), + PAIR(CpuAccuracy, Accurate, tr("Accurate")), + PAIR(CpuAccuracy, Unsafe, tr("Unsafe")), + PAIR(CpuAccuracy, Paranoid, tr("Paranoid (disables most optimizations)")), + }}); + translations->insert({Settings::EnumMetadata::Index(), + { + PAIR(CpuBackend, Dynarmic, tr("Dynarmic")), + PAIR(CpuBackend, Nce, tr("NCE")), + }}); + translations->insert({Settings::EnumMetadata::Index(), + { + PAIR(FullscreenMode, Borderless, tr("Borderless Windowed")), + PAIR(FullscreenMode, Exclusive, tr("Exclusive Fullscreen")), + }}); + translations->insert({Settings::EnumMetadata::Index(), + { + PAIR(NvdecEmulation, Off, tr("No Video Output")), + PAIR(NvdecEmulation, Cpu, tr("CPU Video Decoding")), + PAIR(NvdecEmulation, Gpu, tr("GPU Video Decoding (Default)")), + }}); + translations->insert( + {Settings::EnumMetadata::Index(), + { + PAIR(ResolutionSetup, Res1_2X, tr("0.5X (360p/540p) [EXPERIMENTAL]")), + PAIR(ResolutionSetup, Res3_4X, tr("0.75X (540p/810p) [EXPERIMENTAL]")), + PAIR(ResolutionSetup, Res1X, tr("1X (720p/1080p)")), + PAIR(ResolutionSetup, Res3_2X, tr("1.5X (1080p/1620p) [EXPERIMENTAL]")), + PAIR(ResolutionSetup, Res2X, tr("2X (1440p/2160p)")), + PAIR(ResolutionSetup, Res3X, tr("3X (2160p/3240p)")), + PAIR(ResolutionSetup, Res4X, tr("4X (2880p/4320p)")), + PAIR(ResolutionSetup, Res5X, tr("5X (3600p/5400p)")), + PAIR(ResolutionSetup, Res6X, tr("6X (4320p/6480p)")), + PAIR(ResolutionSetup, Res7X, tr("7X (5040p/7560p)")), + PAIR(ResolutionSetup, Res8X, tr("8X (5760p/8640p)")), + }}); + translations->insert({Settings::EnumMetadata::Index(), + { + PAIR(ScalingFilter, NearestNeighbor, tr("Nearest Neighbor")), + PAIR(ScalingFilter, Bilinear, tr("Bilinear")), + PAIR(ScalingFilter, Bicubic, tr("Bicubic")), + PAIR(ScalingFilter, Gaussian, tr("Gaussian")), + PAIR(ScalingFilter, ScaleForce, tr("ScaleForce")), + PAIR(ScalingFilter, Fsr, tr("AMD FidelityFX™️ Super Resolution")), + }}); + translations->insert({Settings::EnumMetadata::Index(), + { + PAIR(AntiAliasing, None, tr("None")), + PAIR(AntiAliasing, Fxaa, tr("FXAA")), + PAIR(AntiAliasing, Smaa, tr("SMAA")), + }}); + translations->insert({Settings::EnumMetadata::Index(), + { + PAIR(AspectRatio, R16_9, tr("Default (16:9)")), + PAIR(AspectRatio, R4_3, tr("Force 4:3")), + PAIR(AspectRatio, R21_9, tr("Force 21:9")), + PAIR(AspectRatio, R16_10, tr("Force 16:10")), + PAIR(AspectRatio, Stretch, tr("Stretch to Window")), + }}); + translations->insert({Settings::EnumMetadata::Index(), + { + PAIR(AnisotropyMode, Automatic, tr("Automatic")), + PAIR(AnisotropyMode, Default, tr("Default")), + PAIR(AnisotropyMode, X2, tr("2x")), + PAIR(AnisotropyMode, X4, tr("4x")), + PAIR(AnisotropyMode, X8, tr("8x")), + PAIR(AnisotropyMode, X16, tr("16x")), + }}); + translations->insert( + {Settings::EnumMetadata::Index(), + { + PAIR(Language, Japanese, tr("Japanese (日本語)")), + PAIR(Language, EnglishAmerican, tr("American English")), + PAIR(Language, French, tr("French (français)")), + PAIR(Language, German, tr("German (Deutsch)")), + PAIR(Language, Italian, tr("Italian (italiano)")), + PAIR(Language, Spanish, tr("Spanish (español)")), + PAIR(Language, Chinese, tr("Chinese")), + PAIR(Language, Korean, tr("Korean (한국어)")), + PAIR(Language, Dutch, tr("Dutch (Nederlands)")), + PAIR(Language, Portuguese, tr("Portuguese (português)")), + PAIR(Language, Russian, tr("Russian (Русский)")), + PAIR(Language, Taiwanese, tr("Taiwanese")), + PAIR(Language, EnglishBritish, tr("British English")), + PAIR(Language, FrenchCanadian, tr("Canadian French")), + PAIR(Language, SpanishLatin, tr("Latin American Spanish")), + PAIR(Language, ChineseSimplified, tr("Simplified Chinese")), + PAIR(Language, ChineseTraditional, tr("Traditional Chinese (正體中文)")), + PAIR(Language, PortugueseBrazilian, tr("Brazilian Portuguese (português do Brasil)")), + }}); + translations->insert({Settings::EnumMetadata::Index(), + { + PAIR(Region, Japan, tr("Japan")), + PAIR(Region, Usa, tr("USA")), + PAIR(Region, Europe, tr("Europe")), + PAIR(Region, Australia, tr("Australia")), + PAIR(Region, China, tr("China")), + PAIR(Region, Korea, tr("Korea")), + PAIR(Region, Taiwan, tr("Taiwan")), + }}); + translations->insert( + {Settings::EnumMetadata::Index(), + { + {static_cast(Settings::TimeZone::Auto), + tr("Auto (%1)", "Auto select time zone") + .arg(QString::fromStdString( + Settings::GetTimeZoneString(Settings::TimeZone::Auto)))}, + {static_cast(Settings::TimeZone::Default), + tr("Default (%1)", "Default time zone") + .arg(QString::fromStdString(Common::TimeZone::GetDefaultTimeZone()))}, + PAIR(TimeZone, Cet, tr("CET")), + PAIR(TimeZone, Cst6Cdt, tr("CST6CDT")), + PAIR(TimeZone, Cuba, tr("Cuba")), + PAIR(TimeZone, Eet, tr("EET")), + PAIR(TimeZone, Egypt, tr("Egypt")), + PAIR(TimeZone, Eire, tr("Eire")), + PAIR(TimeZone, Est, tr("EST")), + PAIR(TimeZone, Est5Edt, tr("EST5EDT")), + PAIR(TimeZone, Gb, tr("GB")), + PAIR(TimeZone, GbEire, tr("GB-Eire")), + PAIR(TimeZone, Gmt, tr("GMT")), + PAIR(TimeZone, GmtPlusZero, tr("GMT+0")), + PAIR(TimeZone, GmtMinusZero, tr("GMT-0")), + PAIR(TimeZone, GmtZero, tr("GMT0")), + PAIR(TimeZone, Greenwich, tr("Greenwich")), + PAIR(TimeZone, Hongkong, tr("Hongkong")), + PAIR(TimeZone, Hst, tr("HST")), + PAIR(TimeZone, Iceland, tr("Iceland")), + PAIR(TimeZone, Iran, tr("Iran")), + PAIR(TimeZone, Israel, tr("Israel")), + PAIR(TimeZone, Jamaica, tr("Jamaica")), + PAIR(TimeZone, Japan, tr("Japan")), + PAIR(TimeZone, Kwajalein, tr("Kwajalein")), + PAIR(TimeZone, Libya, tr("Libya")), + PAIR(TimeZone, Met, tr("MET")), + PAIR(TimeZone, Mst, tr("MST")), + PAIR(TimeZone, Mst7Mdt, tr("MST7MDT")), + PAIR(TimeZone, Navajo, tr("Navajo")), + PAIR(TimeZone, Nz, tr("NZ")), + PAIR(TimeZone, NzChat, tr("NZ-CHAT")), + PAIR(TimeZone, Poland, tr("Poland")), + PAIR(TimeZone, Portugal, tr("Portugal")), + PAIR(TimeZone, Prc, tr("PRC")), + PAIR(TimeZone, Pst8Pdt, tr("PST8PDT")), + PAIR(TimeZone, Roc, tr("ROC")), + PAIR(TimeZone, Rok, tr("ROK")), + PAIR(TimeZone, Singapore, tr("Singapore")), + PAIR(TimeZone, Turkey, tr("Turkey")), + PAIR(TimeZone, Uct, tr("UCT")), + PAIR(TimeZone, Universal, tr("Universal")), + PAIR(TimeZone, Utc, tr("UTC")), + PAIR(TimeZone, WSu, tr("W-SU")), + PAIR(TimeZone, Wet, tr("WET")), + PAIR(TimeZone, Zulu, tr("Zulu")), + }}); + translations->insert({Settings::EnumMetadata::Index(), + { + PAIR(AudioMode, Mono, tr("Mono")), + PAIR(AudioMode, Stereo, tr("Stereo")), + PAIR(AudioMode, Surround, tr("Surround")), + }}); + translations->insert({Settings::EnumMetadata::Index(), + { + PAIR(MemoryLayout, Memory_4Gb, tr("4GB DRAM (Default)")), + PAIR(MemoryLayout, Memory_6Gb, tr("6GB DRAM (Unsafe)")), + PAIR(MemoryLayout, Memory_8Gb, tr("8GB DRAM")), + PAIR(MemoryLayout, Memory_10Gb, tr("10GB DRAM (Unsafe)")), + PAIR(MemoryLayout, Memory_12Gb, tr("12GB DRAM (Unsafe)")), + }}); + translations->insert({Settings::EnumMetadata::Index(), + { + PAIR(ConsoleMode, Docked, tr("Docked")), + PAIR(ConsoleMode, Handheld, tr("Handheld")), + }}); + translations->insert( + {Settings::EnumMetadata::Index(), + { + PAIR(ConfirmStop, Ask_Always, tr("Always ask (Default)")), + PAIR(ConfirmStop, Ask_Based_On_Game, tr("Only if game specifies not to stop")), + PAIR(ConfirmStop, Ask_Never, tr("Never ask")), + }}); + +#undef PAIR +#undef CTX_PAIR + + return translations; +} +} // namespace ConfigurationShared diff --git a/src/eden/interface/shared_translation.h b/src/eden/interface/shared_translation.h new file mode 100644 index 0000000000..bfd508372b --- /dev/null +++ b/src/eden/interface/shared_translation.h @@ -0,0 +1,65 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include +#include +#include +#include "common/common_types.h" +#include "common/settings.h" + +namespace ConfigurationShared { +using TranslationMap = std::map>; +using ComboboxTranslations = std::vector>; +using ComboboxTranslationMap = std::map; + +std::unique_ptr InitializeTranslations(QObject *parent); + +std::unique_ptr ComboboxEnumeration(QObject *parent); + +static const std::map anti_aliasing_texts_map = { + {Settings::AntiAliasing::None, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "None"))}, + {Settings::AntiAliasing::Fxaa, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FXAA"))}, + {Settings::AntiAliasing::Smaa, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SMAA"))}, +}; + +static const std::map scaling_filter_texts_map = { + {Settings::ScalingFilter::NearestNeighbor, + QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Nearest"))}, + {Settings::ScalingFilter::Bilinear, + QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Bilinear"))}, + {Settings::ScalingFilter::Bicubic, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Bicubic"))}, + {Settings::ScalingFilter::Gaussian, + QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Gaussian"))}, + {Settings::ScalingFilter::ScaleForce, + QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "ScaleForce"))}, + {Settings::ScalingFilter::Fsr, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FSR"))}, +}; + +static const std::map use_docked_mode_texts_map = { + {Settings::ConsoleMode::Docked, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Docked"))}, + {Settings::ConsoleMode::Handheld, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Handheld"))}, +}; + +static const std::map gpu_accuracy_texts_map = { + {Settings::GpuAccuracy::Normal, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Normal"))}, + {Settings::GpuAccuracy::High, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "High"))}, + {Settings::GpuAccuracy::Extreme, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Extreme"))}, +}; + +static const std::map renderer_backend_texts_map = { + {Settings::RendererBackend::Vulkan, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Vulkan"))}, + {Settings::RendererBackend::OpenGL, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "OpenGL"))}, + {Settings::RendererBackend::Null, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Null"))}, +}; + +static const std::map shader_backend_texts_map = { + {Settings::ShaderBackend::Glsl, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLSL"))}, + {Settings::ShaderBackend::Glasm, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLASM"))}, + {Settings::ShaderBackend::SpirV, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SPIRV"))}, +}; + +} // namespace ConfigurationShared diff --git a/src/eden/interface/uisettings.cpp b/src/eden/interface/uisettings.cpp new file mode 100644 index 0000000000..f5203de421 --- /dev/null +++ b/src/eden/interface/uisettings.cpp @@ -0,0 +1,112 @@ +// SPDX-FileCopyrightText: 2016 Citra Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "uisettings.h" +#include +#include "common/fs/fs.h" +#include "common/fs/path_util.h" + +#ifndef CANNOT_EXPLICITLY_INSTANTIATE +namespace Settings { +template class Setting; +template class Setting; +template class Setting; +template class Setting; +template class Setting; +template class Setting; +template class Setting; +} // namespace Settings +#endif + +namespace FS = Common::FS; + +namespace UISettings { + +const Themes themes{{ + {"Default", "default"}, + {"Default Colorful", "colorful"}, + {"Dark", "qdarkstyle"}, + {"Dark Colorful", "colorful_dark"}, + {"Midnight Blue", "qdarkstyle_midnight_blue"}, + {"Midnight Blue Colorful", "colorful_midnight_blue"}, +}}; + +bool IsDarkTheme() { + const auto& theme = UISettings::values.theme; + return theme == std::string("qdarkstyle") || theme == std::string("qdarkstyle_midnight_blue") || + theme == std::string("colorful_dark") || theme == std::string("colorful_midnight_blue"); +} + +Values values = {}; + +u32 CalculateWidth(u32 height, Settings::AspectRatio ratio) { + switch (ratio) { + case Settings::AspectRatio::R4_3: + return height * 4 / 3; + case Settings::AspectRatio::R21_9: + return height * 21 / 9; + case Settings::AspectRatio::R16_10: + return height * 16 / 10; + case Settings::AspectRatio::R16_9: + case Settings::AspectRatio::Stretch: + // TODO: Move this function wherever appropriate to implement Stretched aspect + break; + } + return height * 16 / 9; +} + +void SaveWindowState() { + const auto window_state_config_loc = + FS::PathToUTF8String(FS::GetEdenPath(FS::EdenPath::ConfigDir) / "window_state.ini"); + + void(FS::CreateParentDir(window_state_config_loc)); + QSettings config(QString::fromStdString(window_state_config_loc), QSettings::IniFormat); + + config.setValue(QStringLiteral("geometry"), values.geometry); + config.setValue(QStringLiteral("state"), values.state); + config.setValue(QStringLiteral("geometryRenderWindow"), values.renderwindow_geometry); + config.setValue(QStringLiteral("gameListHeaderState"), values.gamelist_header_state); + config.setValue(QStringLiteral("microProfileDialogGeometry"), values.microprofile_geometry); + + config.sync(); +} + +void RestoreWindowState(std::unique_ptr& qtConfig) { + const auto window_state_config_loc = + FS::PathToUTF8String(FS::GetEdenPath(FS::EdenPath::ConfigDir) / "window_state.ini"); + + // Migrate window state from old location + if (!FS::Exists(window_state_config_loc) && qtConfig->Exists("UI", "UILayout\\geometry")) { + const auto config_loc = + FS::PathToUTF8String(FS::GetEdenPath(FS::EdenPath::ConfigDir) / "qt-config.ini"); + QSettings config(QString::fromStdString(config_loc), QSettings::IniFormat); + + config.beginGroup(QStringLiteral("UI")); + config.beginGroup(QStringLiteral("UILayout")); + values.geometry = config.value(QStringLiteral("geometry")).toByteArray(); + values.state = config.value(QStringLiteral("state")).toByteArray(); + values.renderwindow_geometry = + config.value(QStringLiteral("geometryRenderWindow")).toByteArray(); + values.gamelist_header_state = + config.value(QStringLiteral("gameListHeaderState")).toByteArray(); + values.microprofile_geometry = + config.value(QStringLiteral("microProfileDialogGeometry")).toByteArray(); + config.endGroup(); + config.endGroup(); + return; + } + + void(FS::CreateParentDir(window_state_config_loc)); + const QSettings config(QString::fromStdString(window_state_config_loc), QSettings::IniFormat); + + values.geometry = config.value(QStringLiteral("geometry")).toByteArray(); + values.state = config.value(QStringLiteral("state")).toByteArray(); + values.renderwindow_geometry = + config.value(QStringLiteral("geometryRenderWindow")).toByteArray(); + values.gamelist_header_state = + config.value(QStringLiteral("gameListHeaderState")).toByteArray(); + values.microprofile_geometry = + config.value(QStringLiteral("microProfileDialogGeometry")).toByteArray(); +} + +} // namespace UISettings diff --git a/src/eden/interface/uisettings.h b/src/eden/interface/uisettings.h new file mode 100644 index 0000000000..b8ac6a1e11 --- /dev/null +++ b/src/eden/interface/uisettings.h @@ -0,0 +1,282 @@ +// SPDX-FileCopyrightText: 2016 Citra Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include +#include +#include +#include "common/common_types.h" +#include "common/settings.h" +#include "common/settings_enums.h" +#include "qt_config.h" +#include +#include +#include + +using Settings::Category; +using Settings::ConfirmStop; +using Settings::Setting; +using Settings::SwitchableSetting; + +#ifndef CANNOT_EXPLICITLY_INSTANTIATE +namespace Settings { +extern template class Setting; +extern template class Setting; +extern template class Setting; +extern template class Setting; +extern template class Setting; +extern template class Setting; +extern template class Setting; +} // namespace Settings +#endif + +namespace UISettings { + +bool IsDarkTheme(); + +struct ContextualShortcut { + std::string keyseq; + std::string controller_keyseq; + int context; + bool repeat; +}; + +struct Shortcut { + std::string name; + std::string group; + ContextualShortcut shortcut; +}; + +enum class Theme { + Default, + DefaultColorful, + Dark, + DarkColorful, + MidnightBlue, + MidnightBlueColorful, +}; + +static constexpr Theme default_theme{ +#ifdef _WIN32 + Theme::DarkColorful +#else + Theme::DefaultColorful +#endif +}; + +using Themes = std::array, 6>; +extern const Themes themes; + +struct GameDir { + std::string path; + bool deep_scan = false; + bool expanded = false; + bool operator==(const GameDir& rhs) const { + return path == rhs.path; + } + bool operator!=(const GameDir& rhs) const { + return !operator==(rhs); + } +}; + +struct Values { + Settings::Linkage linkage{1000}; + + QByteArray geometry; + QByteArray state; + + QByteArray renderwindow_geometry; + + QByteArray gamelist_header_state; + + QByteArray microprofile_geometry; + Setting microprofile_visible{linkage, false, "microProfileDialogVisible", + Category::UiLayout}; + + Setting single_window_mode{linkage, true, "singleWindowMode", Category::Ui}; + Setting fullscreen{linkage, false, "fullscreen", Category::Ui}; + Setting display_titlebar{linkage, true, "displayTitleBars", Category::Ui}; + Setting show_filter_bar{linkage, true, "showFilterBar", Category::Ui}; + Setting show_status_bar{linkage, true, "showStatusBar", Category::Ui}; + + SwitchableSetting confirm_before_stopping{linkage, + ConfirmStop::Ask_Always, + "confirmStop", + Category::UiGeneral, + Settings::Specialization::Default, + true, + true}; + + Setting first_start{linkage, true, "firstStart", Category::Ui}; + Setting pause_when_in_background{linkage, + false, + "pauseWhenInBackground", + Category::UiGeneral, + Settings::Specialization::Default, + true, + true}; + Setting mute_when_in_background{linkage, + false, + "muteWhenInBackground", + Category::UiAudio, + Settings::Specialization::Default, + true, + true}; + Setting hide_mouse{ + linkage, true, "hideInactiveMouse", Category::UiGeneral, Settings::Specialization::Default, + true, true}; + Setting controller_applet_disabled{linkage, false, "disableControllerApplet", + Category::UiGeneral}; + // Set when Vulkan is known to crash the application + bool has_broken_vulkan = false; + + Setting select_user_on_boot{linkage, + false, + "select_user_on_boot", + Category::UiGeneral, + Settings::Specialization::Default, + true, + true}; + Setting disable_web_applet{linkage, true, "disable_web_applet", Category::Ui}; + + // Discord RPC + Setting enable_discord_presence{linkage, false, "enable_discord_presence", Category::Ui}; + + // logging + Setting show_console{linkage, false, "showConsole", Category::Ui}; + + // Screenshots + Setting enable_screenshot_save_as{linkage, true, "enable_screenshot_save_as", + Category::Screenshots}; + Setting screenshot_height{linkage, 0, "screenshot_height", Category::Screenshots}; + + std::string roms_path; + std::string game_dir_deprecated; + bool game_dir_deprecated_deepscan; + QVector game_dirs; + QStringList recent_files; + Setting language{linkage, {}, "language", Category::Paths}; + + std::string theme; + + // Shortcut name + std::vector shortcuts; + + Setting callout_flags{linkage, 0, "calloutFlags", Category::Ui}; + + // multiplayer settings + Setting multiplayer_nickname{linkage, {}, "nickname", Category::Multiplayer}; + Setting multiplayer_filter_text{linkage, {}, "filter_text", Category::Multiplayer}; + Setting multiplayer_filter_games_owned{linkage, false, "filter_games_owned", + Category::Multiplayer}; + Setting multiplayer_filter_hide_empty{linkage, false, "filter_games_hide_empty", + Category::Multiplayer}; + Setting multiplayer_filter_hide_full{linkage, false, "filter_games_hide_full", + Category::Multiplayer}; + Setting multiplayer_ip{linkage, {}, "ip", Category::Multiplayer}; + Setting multiplayer_port{linkage, 24872, 0, + UINT16_MAX, "port", Category::Multiplayer}; + Setting multiplayer_room_nickname{ + linkage, {}, "room_nickname", Category::Multiplayer}; + Setting multiplayer_room_name{linkage, {}, "room_name", Category::Multiplayer}; + Setting multiplayer_max_player{linkage, 8, 0, 8, "max_player", Category::Multiplayer}; + Setting multiplayer_room_port{linkage, 24872, 0, + UINT16_MAX, "room_port", Category::Multiplayer}; + Setting multiplayer_host_type{linkage, 0, 0, 1, "host_type", Category::Multiplayer}; + Setting multiplayer_game_id{linkage, {}, "game_id", Category::Multiplayer}; + Setting multiplayer_room_description{ + linkage, {}, "room_description", Category::Multiplayer}; + std::pair, std::vector> multiplayer_ban_list; + + // Game List + Setting show_add_ons{linkage, true, "show_add_ons", Category::UiGameList}; + Setting game_icon_size{linkage, 64, "game_icon_size", Category::UiGameList}; + Setting folder_icon_size{linkage, 48, "folder_icon_size", Category::UiGameList}; + Setting row_1_text_id{linkage, 3, "row_1_text_id", Category::UiGameList}; + Setting row_2_text_id{linkage, 2, "row_2_text_id", Category::UiGameList}; + std::atomic_bool is_game_list_reload_pending{false}; + Setting cache_game_list{linkage, true, "cache_game_list", Category::UiGameList}; + Setting favorites_expanded{linkage, true, "favorites_expanded", Category::UiGameList}; + QVector favorited_ids; + + Setting grid_columns{linkage, 4, 1, 8, "grid_columns", Category::UiGameList}; + + // Compatibility List + Setting show_compat{linkage, false, "show_compat", Category::UiGameList}; + + // Size & File Types Column + Setting show_size{linkage, true, "show_size", Category::UiGameList}; + Setting show_types{linkage, true, "show_types", Category::UiGameList}; + + // Play time + Setting show_play_time{linkage, true, "show_play_time", Category::UiGameList}; + + bool configuration_applied; + bool reset_to_defaults; + bool shortcut_already_warned{false}; +}; + +extern Values values; + +u32 CalculateWidth(u32 height, Settings::AspectRatio ratio); + +void SaveWindowState(); +void RestoreWindowState(std::unique_ptr& qtConfig); + +// This shouldn't have anything except static initializers (no functions). So +// QKeySequence(...).toString() is NOT ALLOWED HERE. +// This must be in alphabetical order according to action name as it must have the same order as +// UISetting::values.shortcuts, which is alphabetically ordered. +// clang-format off +const std::array default_hotkeys{{ + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+M"), std::string("Home+Dpad_Right"), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("-"), std::string("Home+Dpad_Down"), Qt::ApplicationShortcut, true}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("="), std::string("Home+Dpad_Up"), Qt::ApplicationShortcut, true}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Capture Screenshot")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+P"), std::string("Screenshot"), Qt::WidgetWithChildrenShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Adapting Filter")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F8"), std::string("Home+L"), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Docked Mode")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F10"), std::string("Home+X"), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change GPU Accuracy")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F9"), std::string("Home+R"), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Continue/Pause Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F4"), std::string("Home+Plus"), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Esc"), std::string(""), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit eden")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+Q"), std::string("Home+Minus"), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F11"), std::string("Home+B"), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+O"), std::string(""), Qt::WidgetWithChildrenShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F2"), std::string("Home+A"), Qt::WidgetWithChildrenShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Browse Public Game Lobby")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+B"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Create Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+N"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Direct Connect to Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+C"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Leave Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+L"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Show Current Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+R"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F6"), std::string("R+Plus+Minus"), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F5"), std::string("L+Plus+Minus"), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F7"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Reset")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F6"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Start/Stop")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F5"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Filter Bar")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F"), std::string(""), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Framerate Limit")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+U"), std::string("Home+Y"), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Mouse Panning")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F9"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Renderdoc Capture")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string(""), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+S"), std::string(""), Qt::WindowShortcut, false}}, +}}; +// clang-format on + +} // namespace UISettings + +Q_DECLARE_METATYPE(UISettings::GameDir*); + +// These metatype declarations cannot be in common/settings.h because core is devoid of QT +Q_DECLARE_METATYPE(Settings::CpuAccuracy); +Q_DECLARE_METATYPE(Settings::GpuAccuracy); +Q_DECLARE_METATYPE(Settings::FullscreenMode); +Q_DECLARE_METATYPE(Settings::NvdecEmulation); +Q_DECLARE_METATYPE(Settings::ResolutionSetup); +Q_DECLARE_METATYPE(Settings::ScalingFilter); +Q_DECLARE_METATYPE(Settings::AntiAliasing); +Q_DECLARE_METATYPE(Settings::RendererBackend); +Q_DECLARE_METATYPE(Settings::ShaderBackend); +Q_DECLARE_METATYPE(Settings::AstcRecompression); +Q_DECLARE_METATYPE(Settings::AstcDecodeMode); +Q_DECLARE_METATYPE(Settings::SpirvOptimizeMode); diff --git a/src/eden/main.cpp b/src/eden/main.cpp new file mode 100644 index 0000000000..6e4126d466 --- /dev/null +++ b/src/eden/main.cpp @@ -0,0 +1,56 @@ +#include "core/core.h" +#include "interface/SettingsInterface.h" +#include "interface/qt_config.h" +#include "models/GameListModel.h" +#include +#include +#include + +#include + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + QQuickStyle::setStyle(QObject::tr("Material")); + + QCoreApplication::setOrganizationName(QStringLiteral("yuzu")); + QCoreApplication::setApplicationName(QStringLiteral("eden")); + + /// Settings, etc + Settings::SetConfiguringGlobal(true); + QtConfig *config = new QtConfig; + config->SaveAllValues(); + + // TODO: Save all values on launch and per game etc + app.connect(&app, &QCoreApplication::aboutToQuit, &app, [config]() { + config->SaveAllValues(); + }); + + /// Expose Enums + + // Core + std::unique_ptr system = std::make_unique(); + + /// CONTEXT + QQmlApplicationEngine engine; + + // Enums + qmlRegisterUncreatableMetaObject(SettingsCategories::staticMetaObject, "org.eden_emu.interface", 1, 0, "SettingsCategories", QString()); + + // Directory List + GameListModel *gameListModel = new GameListModel(&app); + engine.rootContext()->setContextProperty(QStringLiteral("EdenGameList"), gameListModel); + + /// LOAD + QObject::connect( + &engine, + &QQmlApplicationEngine::objectCreationFailed, + &app, + []() { QCoreApplication::exit(-1); }, + Qt::QueuedConnection); + + engine.loadFromModule("org.eden_emu.main", "Main"); + + return app.exec(); +} diff --git a/src/eden/models/CMakeLists.txt b/src/eden/models/CMakeLists.txt new file mode 100644 index 0000000000..f4e1f1f92f --- /dev/null +++ b/src/eden/models/CMakeLists.txt @@ -0,0 +1,16 @@ +set(CMAKE_AUTOMOC ON) + +# TODO: This might not need to be exposed to QML? +qt_add_library(edenModels STATIC) +qt_add_qml_module(edenModels + URI org.eden_emu.models + VERSION 1.0 + SOURCES + GameListModel.h GameListModel.cpp + SettingsModel.h SettingsModel.cpp +) + +target_link_libraries(edenModels + PRIVATE + Qt6::Gui +) diff --git a/src/eden/models/GameListModel.cpp b/src/eden/models/GameListModel.cpp new file mode 100644 index 0000000000..e20717970b --- /dev/null +++ b/src/eden/models/GameListModel.cpp @@ -0,0 +1,70 @@ +#include "GameListModel.h" + +#include + +const QStringList GameListModel::ValidSuffixes{"jpg", "png", "webp", "jpeg"}; + +GameListModel::GameListModel(QObject *parent) { + QHash rez = QStandardItemModel::roleNames(); + rez.insert(GLMRoleTypes::NAME, "name"); + rez.insert(GLMRoleTypes::PATH, "path"); + rez.insert(GLMRoleTypes::FILESIZE, "size"); + + QStandardItemModel::setItemRoleNames(rez); +} + +QVariant GameListModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (role == GLMRoleTypes::NAME) { + return itemFromIndex(index)->text(); + } + + return QStandardItemModel::data(index, role); +} + +void GameListModel::addDir(const QString &toAdd) +{ + QString name = toAdd; +#ifdef Q_OS_WINDOWS + name.replace("file:///", ""); +#else + name.replace("file://", ""); +#endif + + m_dirs << name; + reload(); +} + +void GameListModel::removeDir(const QString &toRemove) +{ + m_dirs.removeAll(toRemove); + reload(); +} + +void GameListModel::reload() +{ + clear(); + for (const QString &dir : std::as_const(m_dirs)) { + qDebug() << dir; + for (const auto &entry : QDirListing(dir, QDirListing::IteratorFlag::FilesOnly)) { + if (ValidSuffixes.contains(entry.completeSuffix().toLower())) { + QString path = entry.absoluteFilePath(); + QString name = entry.baseName(); + qreal size = entry.size(); + QString sizeString = QLocale::system().formattedDataSize(size); + + qDebug() << path << name << size; + // m_data << Game{path, name, size}; + + QStandardItem *game = new QStandardItem(name); + game->setData(path, GLMRoleTypes::PATH); + game->setData(sizeString, GLMRoleTypes::FILESIZE); + + invisibleRootItem()->appendRow(game); + } + } + } +} diff --git a/src/eden/models/GameListModel.h b/src/eden/models/GameListModel.h new file mode 100644 index 0000000000..fb6ce62955 --- /dev/null +++ b/src/eden/models/GameListModel.h @@ -0,0 +1,39 @@ +#ifndef GAMELISTMODEL_H +#define GAMELISTMODEL_H + +#include +#include + +typedef struct Game { + QString absPath; + QString name; + QString fileSize; +} Game; + +class GameListModel : public QStandardItemModel +{ + Q_OBJECT +public: + enum GLMRoleTypes { + NAME = Qt::UserRole + 1, + PATH, + FILESIZE + }; + + GameListModel(QObject *parent = nullptr); + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + Q_INVOKABLE void addDir(const QString &toAdd); + Q_INVOKABLE void removeDir(const QString &toRemove); + + static const QStringList ValidSuffixes; + +private: + QStringList m_dirs; + QList m_data; + + void reload(); +}; + +#endif // GAMELISTMODEL_H diff --git a/src/eden/models/SettingsModel.cpp b/src/eden/models/SettingsModel.cpp new file mode 100644 index 0000000000..a6a9d1bb62 --- /dev/null +++ b/src/eden/models/SettingsModel.cpp @@ -0,0 +1,90 @@ +#include "SettingsModel.h" + +SettingsModel::SettingsModel(QObject* parent) : QAbstractListModel(parent) {} + +int SettingsModel::rowCount(const QModelIndex& parent) const { + return m_data.count(); +} + +QVariant SettingsModel::data(const QModelIndex& index, int role) const { + if (!index.isValid()) + return QVariant(); + + QMLSetting *s = m_data[index.row()]; + + switch (role) { + case LABEL: + return s->label(); + case TOOLTIP: + return s->tooltip(); + case VALUE: + return s->value(); + case ID: + return s->id(); + case TYPE: + return s->type(); + case COMBO: + return s->combo(); + case SUFFIX: + return s->suffix(); + case MIN: + return s->min(); + case MAX: + return s->max(); + case OTHER: + return QVariant::fromValue(s->other()); + default: + break; + } + + return QVariant(); +} + +bool SettingsModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (data(index, role) != value) { + QMLSetting *s = m_data[index.row()]; + + switch (role) { + case VALUE: + s->setValue(value); + + break; + } + emit dataChanged(index, index, {role}); + return true; + } + return false; + +} + +void SettingsModel::append(QMLSetting *setting) +{ + beginInsertRows(QModelIndex(), rowCount(), rowCount()); + m_data << setting; + endInsertRows(); +} + +void SettingsModel::append(QList settings) +{ + for (QMLSetting *setting : settings) { + append(setting); + } +} + +QHash SettingsModel::roleNames() const +{ + QHash rez; + rez[LABEL] = "label"; + rez[TOOLTIP] = "tooltip"; + rez[VALUE] = "value"; + rez[ID] = "id"; + rez[TYPE] = "type"; + rez[COMBO] = "combo"; + rez[SUFFIX] = "suffix"; + rez[MIN] = "min"; + rez[MAX] = "max"; + rez[OTHER] = "other"; + + return rez; +} diff --git a/src/eden/models/SettingsModel.h b/src/eden/models/SettingsModel.h new file mode 100644 index 0000000000..0edaab7982 --- /dev/null +++ b/src/eden/models/SettingsModel.h @@ -0,0 +1,42 @@ +#ifndef SETTINGSMODEL_H +#define SETTINGSMODEL_H + +#include +#include "yuzu/interface/QMLSetting.h" + +class SettingsModel : public QAbstractListModel { + Q_OBJECT + +public: + enum SMTypes { + LABEL = Qt::UserRole + 1, + TOOLTIP, + ID, + VALUE, + TYPE, + COMBO, // combobox translations + SUFFIX, + MIN, + MAX, + OTHER + }; + + explicit SettingsModel(QObject* parent = nullptr); + + // Basic functionality: + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; + + void append(QMLSetting *setting); + void append(QList settings); + +protected: + QHash roleNames() const override; + +private: + QList m_data; +}; + +#endif // SETTINGSMODEL_H diff --git a/src/eden/qml/CMakeLists.txt b/src/eden/qml/CMakeLists.txt new file mode 100644 index 0000000000..958f84c3dd --- /dev/null +++ b/src/eden/qml/CMakeLists.txt @@ -0,0 +1,5 @@ +add_subdirectory(config) +add_subdirectory(constants) +add_subdirectory(items) + +add_subdirectory(main) diff --git a/src/eden/qml/config/CMakeLists.txt b/src/eden/qml/config/CMakeLists.txt new file mode 100644 index 0000000000..94b0bf7a0e --- /dev/null +++ b/src/eden/qml/config/CMakeLists.txt @@ -0,0 +1,57 @@ +set(CMAKE_AUTOMOC ON) + +qt_add_library(edenConfig STATIC) +qt_add_qml_module(edenConfig + URI org.eden_emu.config + VERSION 1.0 + + QML_FILES GlobalConfigureDialog.qml + QML_FILES Setting.qml + QML_FILES SectionHeader.qml + + QML_FILES pages/SettingsList.qml + + QML_FILES pages/global/GlobalTab.qml + QML_FILES pages/global/GlobalTabSwipeView.qml + QML_FILES pages/global/GlobalGeneralPage.qml + + QML_FILES pages/global/GlobalSystemPage.qml + QML_FILES pages/global/GlobalCpuPage.qml + QML_FILES pages/global/GlobalGraphicsPage.qml + QML_FILES pages/global/GlobalAudioPage.qml + + QML_FILES pages/general/UiGeneralPage.qml + QML_FILES pages/general/UiGameListPage.qml + QML_FILES + + QML_FILES pages/graphics/RendererPage.qml + QML_FILES pages/graphics/RendererAdvancedPage.qml + QML_FILES pages/graphics/RendererExtensionsPage.qml + + QML_FILES pages/system/SystemGeneralPage.qml + QML_FILES + QML_FILES pages/system/FileSystemPage.qml + QML_FILES pages/system/AppletsPage.qml + + QML_FILES pages/cpu/CpuGeneralPage.qml + + QML_FILES pages/audio/AudioGeneralPage.qml + QML_FILES pages/global/GlobalDebugPage.qml + QML_FILES pages/debug/DebugGeneralPage.qml + QML_FILES pages/debug/DebugGraphicsPage.qml + QML_FILES pages/debug/DebugAdvancedPage.qml + QML_FILES pages/debug/DebugCpuPage.qml + QML_FILES fields/ConfigCheckbox.qml + QML_FILES fields/FieldLabel.qml + QML_FILES fields/ConfigComboBox.qml + QML_FILES TestSetting.qml + QML_FILES fields/ConfigIntLine.qml + QML_FILES fields/ConfigTimeEdit.qml + QML_FILES fields/ConfigIntSpin.qml + QML_FILES fields/ConfigHexEdit.qml + QML_FILES fields/ConfigStringEdit.qml + QML_FILES fields/FieldCheckbox.qml + QML_FILES fields/ConfigIntSlider.qml + QML_FILES pages/system/SystemCorePage.qml + QML_FILES fields/BaseField.qml +) diff --git a/src/eden/qml/config/GlobalConfigureDialog.qml b/src/eden/qml/config/GlobalConfigureDialog.qml new file mode 100644 index 0000000000..869a682858 --- /dev/null +++ b/src/eden/qml/config/GlobalConfigureDialog.qml @@ -0,0 +1,73 @@ +import QtQuick +import QtQuick.Controls.Material +import QtQuick.Layouts + +import org.eden_emu.constants +import org.eden_emu.items +import org.eden_emu.interface + +Dialog { + preferredWidth: 1280 + + title: "Configuration" + standardButtons: Dialog.Ok | Dialog.Cancel + + onOpened: { + for (var tab in tabBar.children) { + console.log(tab) + } + } + + onAccepted: { + + } + + VerticalTabBar { + id: tabBar + + anchors { + top: parent.top + topMargin: 55 * Constants.scalar + + left: parent.left + bottom: parent.bottom + } + contentWidth: 100 + + currentIndex: swipe.currentIndex + + Repeater { + model: ["General", "System", "CPU", "Graphics", "Audio", "Debug", "Controls"] + + SettingsTabButton { + required property string modelData + label: modelData + onClicked: tabBar.currentIndex = TabBar.index + } + } + } + + SwipeView { + id: swipe + currentIndex: tabBar.currentIndex + + orientation: Qt.Vertical + anchors { + left: tabBar.right + right: parent.right + top: parent.top + bottom: parent.bottom + + leftMargin: 5 * Constants.scalar + } + + clip: true + + GlobalGeneralPage {} + GlobalSystemPage {} + GlobalCpuPage {} + GlobalGraphicsPage {} + GlobalAudioPage {} + GlobalDebugPage {} + } +} diff --git a/src/eden/qml/config/SectionHeader.qml b/src/eden/qml/config/SectionHeader.qml new file mode 100644 index 0000000000..2a69504bd2 --- /dev/null +++ b/src/eden/qml/config/SectionHeader.qml @@ -0,0 +1,8 @@ +import QtQuick + +import org.eden_emu.constants + +Text { + color: Constants.text + font.pixelSize: 16 +} diff --git a/src/eden/qml/config/Setting.qml b/src/eden/qml/config/Setting.qml new file mode 100644 index 0000000000..5da913689c --- /dev/null +++ b/src/eden/qml/config/Setting.qml @@ -0,0 +1,92 @@ +import QtQuick + +import Qt.labs.qmlmodels + +import org.eden_emu.config + +// TODO: make settings independently available (model vs setting? +DelegateChooser { + id: chooser + role: "type" + + DelegateChoice { + roleValue: "bool" + + ConfigCheckbox { + setting: model + width: ListView.view.width + } + } + + DelegateChoice { + roleValue: "enumCombo" + + ConfigComboBox { + setting: model + width: ListView.view.width + } + } + + DelegateChoice { + roleValue: "intCombo" + + ConfigComboBox { + setting: model + width: ListView.view.width + } + } + + DelegateChoice { + roleValue: "intLine" + + ConfigIntLine { + setting: model + width: ListView.view.width + } + } + + DelegateChoice { + roleValue: "intSlider" + + ConfigIntSlider { + setting: model + width: ListView.view.width + } + } + + DelegateChoice { + roleValue: "time" + + ConfigTimeEdit { + setting: model + width: ListView.view.width + } + } + + DelegateChoice { + roleValue: "intSpin" + + ConfigIntSpin { + setting: model + width: ListView.view.width + } + } + + DelegateChoice { + roleValue: "stringLine" + + ConfigStringEdit { + setting: model + width: ListView.view.width + } + } + + DelegateChoice { + roleValue: "hex" + + ConfigHexEdit { + setting: model + width: ListView.view.width + } + } +} diff --git a/src/eden/qml/config/TestSetting.qml b/src/eden/qml/config/TestSetting.qml new file mode 100644 index 0000000000..e8d6e36d50 --- /dev/null +++ b/src/eden/qml/config/TestSetting.qml @@ -0,0 +1,39 @@ +import QtQuick +import QtQuick.Layouts + +import org.eden_emu.constants + +Column { + topPadding: 5 * Constants.scalar + leftPadding: 10 * Constants.scalar + + RowLayout { + uniformCellSizes: true + Text { + Layout.fillWidth: true + text: model.label + color: Constants.text + font.pixelSize: 16 + + height: 40 + } + + Text { + Layout.fillWidth: true + text: model.value + color: "lightblue" + font.pixelSize: 14 + + height: 40 + horizontalAlignment: Text.AlignRight + } + } + + Text { + text: model.type + " " + typeof model.value + " " + model.other + color: "lightgray" + font.pixelSize: 12 + + height: 25 + } +} diff --git a/src/eden/qml/config/fields/BaseField.qml b/src/eden/qml/config/fields/BaseField.qml new file mode 100644 index 0000000000..092f69f3eb --- /dev/null +++ b/src/eden/qml/config/fields/BaseField.qml @@ -0,0 +1,160 @@ +import QtQuick +import QtQuick.Layouts + +import org.eden_emu.items +import org.eden_emu.config +import org.eden_emu.constants + +Item { + id: field + property var setting + property var value + property bool showLabel: true + + property alias enable: enable.checked + property Item contentItem + + clip: true + height: content.height + (helpText.height + helpText.anchors.topMargin) + + function apply() { + setting.value = value + } + + function sync() { + value = setting.value + } + + RowLayout { + id: content + height: 45 * Constants.scalar + + spacing: 0 + + anchors { + left: parent.left + right: parent.right + } + + z: 2 + + IconButton { + label: "help" + icon.width: 20 + icon.height: 20 + + onClicked: helpText.toggle() + visible: setting.tooltip !== "" + z: 2 + } + + FieldCheckbox { + id: enable + setting: field.setting + z: 2 + } + + RowLayout { + Layout.fillWidth: true + uniformCellSizes: true + spacing: 0 + z: 2 + + FieldLabel { + z: 2 + id: label + setting: field.setting + } + + children: showLabel ? [label, contentItem] : [contentItem] + } + } + + Rectangle { + color: Constants.dialog + anchors.fill: content + z: 0 + } + + Text { + id: helpText + + anchors { + left: parent.left + leftMargin: 20 * Constants.scalar + right: parent.right + rightMargin: 20 * Constants.scalar + + top: content.bottom + topMargin: -height + } + + z: -1 + + text: setting.tooltip + color: Constants.subText + font.pixelSize: 12 * Constants.scalar + wrapMode: Text.WordWrap + + visible: false + opacity: 0 + + function toggle() { + if (visible) { + hideAnim.start() + } else { + showAnim.start() + } + } + + ParallelAnimation { + id: showAnim + + SmoothedAnimation { + target: helpText + property: "opacity" + from: 0 + to: 1 + + velocity: 3 + } + + SmoothedAnimation { + target: helpText + property: "anchors.topMargin" + from: -helpText.height + to: 0 + + duration: 300 + velocity: -1 + } + + onStarted: helpText.visible = true + } + + ParallelAnimation { + id: hideAnim + + SmoothedAnimation { + target: helpText + property: "opacity" + from: 1 + to: 0 + + velocity: 3 + } + + SmoothedAnimation { + target: helpText + property: "anchors.topMargin" + from: 0 + to: -helpText.height + + duration: 300 + velocity: -1 + } + + onFinished: helpText.visible = false + } + } +} diff --git a/src/eden/qml/config/fields/ConfigCheckbox.qml b/src/eden/qml/config/fields/ConfigCheckbox.qml new file mode 100644 index 0000000000..43c84e2248 --- /dev/null +++ b/src/eden/qml/config/fields/ConfigCheckbox.qml @@ -0,0 +1,27 @@ +import QtQuick +import QtQuick.Controls.Material +import QtQuick.Layouts + +import org.eden_emu.constants + +BaseField { + showLabel: false + // TODO: global/custom + contentItem: CheckBox { + id: control + + Layout.rightMargin: 10 * Constants.scalar + Layout.fillWidth: true + + font.pixelSize: 15 * Constants.scalar + indicator.implicitHeight: 25 * Constants.scalar + indicator.implicitWidth: 25 * Constants.scalar + + text: setting.label + checked: setting.value + + onClicked: setting.value = checked + + checkable: true + } +} diff --git a/src/eden/qml/config/fields/ConfigComboBox.qml b/src/eden/qml/config/fields/ConfigComboBox.qml new file mode 100644 index 0000000000..c4762813b7 --- /dev/null +++ b/src/eden/qml/config/fields/ConfigComboBox.qml @@ -0,0 +1,33 @@ +import QtQuick +import QtQuick.Controls.Material +import QtQuick.Layouts +import QtQuick.Controls.Material.impl + +import org.eden_emu.constants +import org.eden_emu.config + +BaseField { + contentItem: ComboBox { + id: control + enabled: enable + + Layout.fillWidth: true + Layout.rightMargin: 10 * Constants.scalar + + font.pixelSize: 14 * Constants.scalar + model: setting.combo + currentIndex: value + + background: MaterialTextContainer { + implicitWidth: 120 + implicitHeight: 40 * Constants.scalar + + outlineColor: (enabled + && control.hovered) ? control.Material.primaryTextColor : control.Material.hintTextColor + focusedOutlineColor: control.Material.accentColor + controlHasActiveFocus: control.activeFocus + controlHasText: true + horizontalPadding: control.Material.textFieldHorizontalPadding + } + } +} diff --git a/src/eden/qml/config/fields/ConfigHexEdit.qml b/src/eden/qml/config/fields/ConfigHexEdit.qml new file mode 100644 index 0000000000..983b0e94c7 --- /dev/null +++ b/src/eden/qml/config/fields/ConfigHexEdit.qml @@ -0,0 +1,26 @@ +import QtQuick +import QtQuick.Layouts + +import org.eden_emu.items +import org.eden_emu.config +import org.eden_emu.constants + +BaseField { + contentItem: BetterTextField { + enabled: enable + + Layout.fillWidth: true + Layout.rightMargin: 10 * Constants.scalar + + validator: RegularExpressionValidator { + regularExpression: /[0-9a-fA-F]{0,8}/ + } + + font.pixelSize: 15 * Constants.scalar + + text: Number(setting.value).toString(16) + suffix: setting.suffix + + onTextEdited: setting.value = Number("0x" + text) + } +} diff --git a/src/eden/qml/config/fields/ConfigIntLine.qml b/src/eden/qml/config/fields/ConfigIntLine.qml new file mode 100644 index 0000000000..7f1653207c --- /dev/null +++ b/src/eden/qml/config/fields/ConfigIntLine.qml @@ -0,0 +1,28 @@ +import QtQuick +import QtQuick.Layouts + +import org.eden_emu.items +import org.eden_emu.config +import org.eden_emu.constants + +BaseField { + contentItem: BetterTextField { + enabled: enable + + Layout.fillWidth: true + Layout.rightMargin: 10 * Constants.scalar + + inputMethodHints: Qt.ImhDigitsOnly + validator: IntValidator { + bottom: setting.min + top: setting.max + } + + font.pixelSize: 15 * Constants.scalar + + text: setting.value + suffix: setting.suffix + + onTextEdited: setting.value = parseInt(text) + } +} diff --git a/src/eden/qml/config/fields/ConfigIntSlider.qml b/src/eden/qml/config/fields/ConfigIntSlider.qml new file mode 100644 index 0000000000..eac6f66993 --- /dev/null +++ b/src/eden/qml/config/fields/ConfigIntSlider.qml @@ -0,0 +1,39 @@ +import QtQuick +import QtQuick.Controls.Material +import QtQuick.Layouts + +import org.eden_emu.items +import org.eden_emu.config +import org.eden_emu.constants + +// Lots of cancer but idrc +BaseField { + contentItem: RowLayout { + Layout.fillWidth: true + + Slider { + Layout.fillWidth: true + + from: setting.min + to: setting.max + stepSize: 1 + + value: setting.value + + onMoved: setting.value = value + + Layout.rightMargin: 10 * Constants.scalar + + snapMode: Slider.SnapAlways + } + + Text { + font.pixelSize: 14 * Constants.scalar + color: Constants.text + + text: setting.value + setting.suffix + + Layout.rightMargin: 10 * Constants.scalar + } + } +} diff --git a/src/eden/qml/config/fields/ConfigIntSpin.qml b/src/eden/qml/config/fields/ConfigIntSpin.qml new file mode 100644 index 0000000000..7d65e90663 --- /dev/null +++ b/src/eden/qml/config/fields/ConfigIntSpin.qml @@ -0,0 +1,25 @@ +import QtQuick +import QtQuick.Layouts + +import org.eden_emu.items +import org.eden_emu.config +import org.eden_emu.constants + +BaseField { + contentItem: BetterSpinBox { + enabled: enable + + Layout.fillWidth: true + Layout.rightMargin: 10 * Constants.scalar + + from: setting.min + to: setting.max + + font.pixelSize: 15 * Constants.scalar + + value: setting.value + label: setting.suffix + + onValueModified: setting.value = value + } +} diff --git a/src/eden/qml/config/fields/ConfigStringEdit.qml b/src/eden/qml/config/fields/ConfigStringEdit.qml new file mode 100644 index 0000000000..32873c96b2 --- /dev/null +++ b/src/eden/qml/config/fields/ConfigStringEdit.qml @@ -0,0 +1,22 @@ +import QtQuick +import QtQuick.Layouts + +import org.eden_emu.items +import org.eden_emu.config +import org.eden_emu.constants + +BaseField { + contentItem: BetterTextField { + enabled: enable + + Layout.fillWidth: true + Layout.rightMargin: 10 * Constants.scalar + + font.pixelSize: 15 * Constants.scalar + + text: setting.value + suffix: setting.suffix + + onTextEdited: setting.value = text + } +} diff --git a/src/eden/qml/config/fields/ConfigTimeEdit.qml b/src/eden/qml/config/fields/ConfigTimeEdit.qml new file mode 100644 index 0000000000..e070102ca3 --- /dev/null +++ b/src/eden/qml/config/fields/ConfigTimeEdit.qml @@ -0,0 +1,27 @@ +import QtQuick +import QtQuick.Layouts + +import org.eden_emu.items +import org.eden_emu.config +import org.eden_emu.constants + +BaseField { + // TODO: real impl + contentItem: BetterTextField { + enabled: enable + + Layout.fillWidth: true + Layout.rightMargin: 10 * Constants.scalar + + inputMethodHints: Qt.ImhDigitsOnly + validator: IntValidator { + bottom: setting.min + top: setting.max + } + + font.pixelSize: 15 * Constants.scalar + + text: setting.value + suffix: setting.suffix + } +} diff --git a/src/eden/qml/config/fields/FieldCheckbox.qml b/src/eden/qml/config/fields/FieldCheckbox.qml new file mode 100644 index 0000000000..f1bc4039e6 --- /dev/null +++ b/src/eden/qml/config/fields/FieldCheckbox.qml @@ -0,0 +1,17 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import org.eden_emu.constants + +CheckBox { + property var setting + + indicator.implicitHeight: 25 * Constants.scalar + indicator.implicitWidth: 25 * Constants.scalar + + checked: setting.other !== null ? setting.other.value : true + onClicked: setting.other.value = checked + + visible: setting.other !== null +} diff --git a/src/eden/qml/config/fields/FieldLabel.qml b/src/eden/qml/config/fields/FieldLabel.qml new file mode 100644 index 0000000000..71ef3ad228 --- /dev/null +++ b/src/eden/qml/config/fields/FieldLabel.qml @@ -0,0 +1,18 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import org.eden_emu.constants + +Text { + property var setting + + text: setting.label + color: Constants.text + font.pixelSize: 14 * Constants.scalar + + height: 50 * Constants.scalar + ToolTip.text: setting.tooltip + + Layout.fillWidth: true +} diff --git a/src/eden/qml/config/icons.qrc b/src/eden/qml/config/icons.qrc new file mode 100644 index 0000000000..7646d2b36c --- /dev/null +++ b/src/eden/qml/config/icons.qrc @@ -0,0 +1 @@ + diff --git a/src/eden/qml/config/pages/SettingsList.qml b/src/eden/qml/config/pages/SettingsList.qml new file mode 100644 index 0000000000..13a1b4fdbf --- /dev/null +++ b/src/eden/qml/config/pages/SettingsList.qml @@ -0,0 +1,47 @@ +import QtQuick +import QtQuick.Layouts + +import org.eden_emu.config +import org.eden_emu.constants +import org.eden_emu.interface + +ColumnLayout { + required property int category + + property bool inset: false + property string header: "" + property list idInclude: [] + property list idExclude: [] + + SectionHeader { + text: header + visible: header != "" + } + + ListView { + clip: true + boundsBehavior: Flickable.StopAtBounds + + interactive: false + + implicitHeight: contentHeight + delegate: Setting {} + + Layout.fillHeight: true + Layout.fillWidth: true + Layout.leftMargin: 5 * Constants.scalar + spacing: 8 * Constants.scalar + + model: SettingsInterface.category(category, idInclude, idExclude) + + Rectangle { + anchors.fill: parent + color: "transparent" + + border { + color: inset ? Constants.text : "transparent" + width: 1 + } + } + } +} diff --git a/src/eden/qml/config/pages/audio/AudioGeneralPage.qml b/src/eden/qml/config/pages/audio/AudioGeneralPage.qml new file mode 100644 index 0000000000..83217cb420 --- /dev/null +++ b/src/eden/qml/config/pages/audio/AudioGeneralPage.qml @@ -0,0 +1,17 @@ +import QtQuick +import QtQuick.Controls.Material +import QtQuick.Layouts + +import org.eden_emu.interface +import org.eden_emu.config + +ScrollView { + id: scroll + ColumnLayout { + width: scroll.width - scroll.effectiveScrollBarWidth + + SettingsList { + category: SettingsCategories.Audio + } + } +} diff --git a/src/eden/qml/config/pages/cpu/CpuGeneralPage.qml b/src/eden/qml/config/pages/cpu/CpuGeneralPage.qml new file mode 100644 index 0000000000..49e52a87f9 --- /dev/null +++ b/src/eden/qml/config/pages/cpu/CpuGeneralPage.qml @@ -0,0 +1,17 @@ +import QtQuick +import QtQuick.Controls.Material +import QtQuick.Layouts + +import org.eden_emu.interface +import org.eden_emu.config + +ScrollView { + id: scroll + ColumnLayout { + width: scroll.width - scroll.effectiveScrollBarWidth + + SettingsList { + category: SettingsCategories.Cpu + } + } +} diff --git a/src/eden/qml/config/pages/debug/DebugAdvancedPage.qml b/src/eden/qml/config/pages/debug/DebugAdvancedPage.qml new file mode 100644 index 0000000000..c5ee3b73b3 --- /dev/null +++ b/src/eden/qml/config/pages/debug/DebugAdvancedPage.qml @@ -0,0 +1,19 @@ +import QtQuick +import QtQuick.Controls.Material +import QtQuick.Layouts + +import org.eden_emu.interface +import org.eden_emu.config + +ScrollView { + id: scroll + + ColumnLayout { + width: scroll.width - scroll.effectiveScrollBarWidth + + // TODO: filter + SettingsList { + category: SettingsCategories.Debugging + } + } +} diff --git a/src/eden/qml/config/pages/debug/DebugCpuPage.qml b/src/eden/qml/config/pages/debug/DebugCpuPage.qml new file mode 100644 index 0000000000..67c9f612d1 --- /dev/null +++ b/src/eden/qml/config/pages/debug/DebugCpuPage.qml @@ -0,0 +1,18 @@ +import QtQuick +import QtQuick.Controls.Material +import QtQuick.Layouts + +import org.eden_emu.interface +import org.eden_emu.config + +ScrollView { + id: scroll + + ColumnLayout { + width: scroll.width - scroll.effectiveScrollBarWidth + + SettingsList { + category: SettingsCategories.CpuDebug + } + } +} diff --git a/src/eden/qml/config/pages/debug/DebugGeneralPage.qml b/src/eden/qml/config/pages/debug/DebugGeneralPage.qml new file mode 100644 index 0000000000..7fa39e315e --- /dev/null +++ b/src/eden/qml/config/pages/debug/DebugGeneralPage.qml @@ -0,0 +1,28 @@ +import QtQuick +import QtQuick.Controls.Material +import QtQuick.Layouts + +import org.eden_emu.interface +import org.eden_emu.config + +ScrollView { + id: scroll + + ColumnLayout { + width: scroll.width - scroll.effectiveScrollBarWidth + + RowLayout { + Layout.fillWidth: true + + // TODO: split + SettingsList { + category: SettingsCategories.Debugging + } + + // TODO: wrong category? + SettingsList { + category: SettingsCategories.Miscellaneous + } + } + } +} diff --git a/src/eden/qml/config/pages/debug/DebugGraphicsPage.qml b/src/eden/qml/config/pages/debug/DebugGraphicsPage.qml new file mode 100644 index 0000000000..8f34c525ee --- /dev/null +++ b/src/eden/qml/config/pages/debug/DebugGraphicsPage.qml @@ -0,0 +1,20 @@ +import QtQuick +import QtQuick.Controls.Material +import QtQuick.Layouts + +import org.eden_emu.interface +import org.eden_emu.config + +ScrollView { + id: scroll + + ColumnLayout { + width: scroll.width - scroll.effectiveScrollBarWidth + + SettingsList { + Layout.fillWidth: true + + category: SettingsCategories.DebuggingGraphics + } + } +} diff --git a/src/eden/qml/config/pages/general/UiGameListPage.qml b/src/eden/qml/config/pages/general/UiGameListPage.qml new file mode 100644 index 0000000000..7ec92a11ba --- /dev/null +++ b/src/eden/qml/config/pages/general/UiGameListPage.qml @@ -0,0 +1,18 @@ +import QtQuick +import QtQuick.Controls.Material +import QtQuick.Layouts + +import org.eden_emu.interface +import org.eden_emu.config + +ScrollView { + id: scroll + // TODO: language, theme + ColumnLayout { + width: scroll.width - scroll.effectiveScrollBarWidth + + SettingsList { + category: SettingsCategories.UiGameList + } + } +} diff --git a/src/eden/qml/config/pages/general/UiGeneralPage.qml b/src/eden/qml/config/pages/general/UiGeneralPage.qml new file mode 100644 index 0000000000..06ad55d49c --- /dev/null +++ b/src/eden/qml/config/pages/general/UiGeneralPage.qml @@ -0,0 +1,23 @@ +import QtQuick +import QtQuick.Controls.Material +import QtQuick.Layouts + +import org.eden_emu.interface +import org.eden_emu.config + +ScrollView { + id: scroll + ColumnLayout { + width: scroll.width - scroll.effectiveScrollBarWidth + + SettingsList { + category: SettingsCategories.UiGeneral + // onContentHeightChanged: console.log(height, parent.height) + } + + SettingsList { + category: SettingsCategories.Linux + visible: Qt.platform.os === "linux" + } + } +} diff --git a/src/eden/qml/config/pages/global/GlobalAudioPage.qml b/src/eden/qml/config/pages/global/GlobalAudioPage.qml new file mode 100644 index 0000000000..ddfdef51f8 --- /dev/null +++ b/src/eden/qml/config/pages/global/GlobalAudioPage.qml @@ -0,0 +1,14 @@ +import QtQuick + +import org.eden_emu.config + +GlobalTab { + tabs: ["Audio"] + + GlobalTabSwipeView { + id: swipe + currentIndex: tabBar.currentIndex + + AudioGeneralPage {} + } +} diff --git a/src/eden/qml/config/pages/global/GlobalCpuPage.qml b/src/eden/qml/config/pages/global/GlobalCpuPage.qml new file mode 100644 index 0000000000..bcca4f17ae --- /dev/null +++ b/src/eden/qml/config/pages/global/GlobalCpuPage.qml @@ -0,0 +1,14 @@ +import QtQuick + +import org.eden_emu.config + +GlobalTab { + tabs: ["CPU"] + + GlobalTabSwipeView { + id: swipe + currentIndex: tabBar.currentIndex + + CpuGeneralPage {} + } +} diff --git a/src/eden/qml/config/pages/global/GlobalDebugPage.qml b/src/eden/qml/config/pages/global/GlobalDebugPage.qml new file mode 100644 index 0000000000..85df6bd1e4 --- /dev/null +++ b/src/eden/qml/config/pages/global/GlobalDebugPage.qml @@ -0,0 +1,17 @@ +import QtQuick + +import org.eden_emu.config + +GlobalTab { + tabs: ["General", "Graphics", "Advanced", "CPU"] + + GlobalTabSwipeView { + id: swipe + currentIndex: tabBar.currentIndex + + DebugGeneralPage {} + DebugGraphicsPage {} + DebugAdvancedPage {} + DebugCpuPage {} + } +} diff --git a/src/eden/qml/config/pages/global/GlobalGeneralPage.qml b/src/eden/qml/config/pages/global/GlobalGeneralPage.qml new file mode 100644 index 0000000000..30a782d5a8 --- /dev/null +++ b/src/eden/qml/config/pages/global/GlobalGeneralPage.qml @@ -0,0 +1,17 @@ +import QtQuick + +import org.eden_emu.config + +GlobalTab { + tabs: ["General", "Hotkeys", "Game List"] + + GlobalTabSwipeView { + id: swipe + currentIndex: tabBar.currentIndex + + // TODO: platform-specific stuff + UiGeneralPage {} + Item {} + UiGameListPage {} + } +} diff --git a/src/eden/qml/config/pages/global/GlobalGraphicsPage.qml b/src/eden/qml/config/pages/global/GlobalGraphicsPage.qml new file mode 100644 index 0000000000..af42494591 --- /dev/null +++ b/src/eden/qml/config/pages/global/GlobalGraphicsPage.qml @@ -0,0 +1,16 @@ +import QtQuick + +import org.eden_emu.config + +GlobalTab { + tabs: ["Graphics", "Advanced", "Extensions"] + + GlobalTabSwipeView { + id: swipe + currentIndex: tabBar.currentIndex + + RendererPage {} + RendererAdvancedPage {} + RendererExtensionsPage {} + } +} diff --git a/src/eden/qml/config/pages/global/GlobalSystemPage.qml b/src/eden/qml/config/pages/global/GlobalSystemPage.qml new file mode 100644 index 0000000000..20f0780c97 --- /dev/null +++ b/src/eden/qml/config/pages/global/GlobalSystemPage.qml @@ -0,0 +1,18 @@ +import QtQuick + +import org.eden_emu.config + +GlobalTab { + tabs: ["System", "Core", "Profiles", "Filesystem", "Applets"] + + GlobalTabSwipeView { + id: swipe + currentIndex: tabBar.currentIndex + + SystemGeneralPage {} + SystemCorePage {} + Item {} + FileSystemPage {} + AppletsPage {} + } +} diff --git a/src/eden/qml/config/pages/global/GlobalTab.qml b/src/eden/qml/config/pages/global/GlobalTab.qml new file mode 100644 index 0000000000..68a262aedc --- /dev/null +++ b/src/eden/qml/config/pages/global/GlobalTab.qml @@ -0,0 +1,34 @@ +import QtQuick 2.15 +import QtQuick.Controls.Material + +import org.eden_emu.constants + +Item { + required property list tabs + property alias tabBar: tabBar + + TabBar { + id: tabBar + currentIndex: swipe.currentIndex + + anchors { + top: parent.top + left: parent.left + right: parent.right + } + + Repeater { + model: tabs + + TabButton { + font.pixelSize: 16 * Constants.scalar + text: modelData + } + } + + background: Rectangle { + color: tabBar.Material.backgroundColor + radius: 8 * Constants.scalar + } + } +} diff --git a/src/eden/qml/config/pages/global/GlobalTabSwipeView.qml b/src/eden/qml/config/pages/global/GlobalTabSwipeView.qml new file mode 100644 index 0000000000..b5f746d02e --- /dev/null +++ b/src/eden/qml/config/pages/global/GlobalTabSwipeView.qml @@ -0,0 +1,16 @@ +import QtQuick 2.15 +import QtQuick.Controls.Material + +import org.eden_emu.constants + +SwipeView { + anchors { + top: tabBar.bottom + left: parent.left + right: parent.right + bottom: parent.bottom + + leftMargin: 20 * Constants.scalar + topMargin: 10 * Constants.scalar + } +} diff --git a/src/eden/qml/config/pages/graphics/RendererAdvancedPage.qml b/src/eden/qml/config/pages/graphics/RendererAdvancedPage.qml new file mode 100644 index 0000000000..d9699a5120 --- /dev/null +++ b/src/eden/qml/config/pages/graphics/RendererAdvancedPage.qml @@ -0,0 +1,17 @@ +import QtQuick +import QtQuick.Controls.Material +import QtQuick.Layouts + +import org.eden_emu.interface +import org.eden_emu.config + +ScrollView { + id: scroll + ColumnLayout { + width: scroll.width - scroll.effectiveScrollBarWidth + + SettingsList { + category: SettingsCategories.RendererAdvanced + } + } +} diff --git a/src/eden/qml/config/pages/graphics/RendererExtensionsPage.qml b/src/eden/qml/config/pages/graphics/RendererExtensionsPage.qml new file mode 100644 index 0000000000..ce6f5536d7 --- /dev/null +++ b/src/eden/qml/config/pages/graphics/RendererExtensionsPage.qml @@ -0,0 +1,17 @@ +import QtQuick +import QtQuick.Controls.Material +import QtQuick.Layouts + +import org.eden_emu.interface +import org.eden_emu.config + +ScrollView { + id: scroll + ColumnLayout { + width: scroll.width - scroll.effectiveScrollBarWidth + + SettingsList { + category: SettingsCategories.RendererExtensions + } + } +} diff --git a/src/eden/qml/config/pages/graphics/RendererPage.qml b/src/eden/qml/config/pages/graphics/RendererPage.qml new file mode 100644 index 0000000000..99b95a2699 --- /dev/null +++ b/src/eden/qml/config/pages/graphics/RendererPage.qml @@ -0,0 +1,17 @@ +import QtQuick +import QtQuick.Controls.Material +import QtQuick.Layouts + +import org.eden_emu.interface +import org.eden_emu.config + +ScrollView { + id: scroll + ColumnLayout { + width: scroll.width - scroll.effectiveScrollBarWidth + + SettingsList { + category: SettingsCategories.Renderer + } + } +} diff --git a/src/eden/qml/config/pages/system/AppletsPage.qml b/src/eden/qml/config/pages/system/AppletsPage.qml new file mode 100644 index 0000000000..4759fe1546 --- /dev/null +++ b/src/eden/qml/config/pages/system/AppletsPage.qml @@ -0,0 +1,17 @@ +import QtQuick +import QtQuick.Controls.Material +import QtQuick.Layouts + +import org.eden_emu.interface +import org.eden_emu.config + +ScrollView { + id: scroll + ColumnLayout { + width: scroll.width - scroll.effectiveScrollBarWidth + + SettingsList { + category: SettingsCategories.LibraryApplet + } + } +} diff --git a/src/eden/qml/config/pages/system/FileSystemPage.qml b/src/eden/qml/config/pages/system/FileSystemPage.qml new file mode 100644 index 0000000000..ad0b230e5b --- /dev/null +++ b/src/eden/qml/config/pages/system/FileSystemPage.qml @@ -0,0 +1,17 @@ +import QtQuick +import QtQuick.Controls.Material +import QtQuick.Layouts + +import org.eden_emu.interface +import org.eden_emu.config + +ScrollView { + id: scroll + ColumnLayout { + width: scroll.width - scroll.effectiveScrollBarWidth + + SettingsList { + category: SettingsCategories.DataStorage + } + } +} diff --git a/src/eden/qml/config/pages/system/SystemCorePage.qml b/src/eden/qml/config/pages/system/SystemCorePage.qml new file mode 100644 index 0000000000..913e9a456f --- /dev/null +++ b/src/eden/qml/config/pages/system/SystemCorePage.qml @@ -0,0 +1,17 @@ +import QtQuick +import QtQuick.Controls.Material +import QtQuick.Layouts + +import org.eden_emu.interface +import org.eden_emu.config + +ScrollView { + id: scroll + ColumnLayout { + width: scroll.width - scroll.effectiveScrollBarWidth + + SettingsList { + category: SettingsCategories.Core + } + } +} diff --git a/src/eden/qml/config/pages/system/SystemGeneralPage.qml b/src/eden/qml/config/pages/system/SystemGeneralPage.qml new file mode 100644 index 0000000000..dab840e5ad --- /dev/null +++ b/src/eden/qml/config/pages/system/SystemGeneralPage.qml @@ -0,0 +1,22 @@ +import QtQuick +import QtQuick.Controls.Material +import QtQuick.Layouts + +import org.eden_emu.interface +import org.eden_emu.config + +ScrollView { + id: scroll + ColumnLayout { + width: scroll.width - scroll.effectiveScrollBarWidth + + SettingsList { + category: SettingsCategories.Network + } + + SettingsList { + category: SettingsCategories.System + idExclude: ["custom_rtc", "custom_rtc_offset", "current_user"] + } + } +} diff --git a/src/eden/qml/constants/CMakeLists.txt b/src/eden/qml/constants/CMakeLists.txt new file mode 100644 index 0000000000..27e8a6a6c1 --- /dev/null +++ b/src/eden/qml/constants/CMakeLists.txt @@ -0,0 +1,23 @@ +set(CMAKE_AUTOMOC ON) + +find_package(Qt6 REQUIRED COMPONENTS Quick) + +set_source_files_properties(Constants.qml + PROPERTIES + QT_QML_SINGLETON_TYPE true +) + +qt_add_library(edenConstants STATIC) +qt_add_qml_module(edenConstants + URI org.eden_emu.constants + OUTPUT_DIRECTORY EdenConstants + VERSION 1.0 + QML_FILES + + Constants.qml +) + +target_link_libraries(edenConstants + PRIVATE + Qt6::Quick +) diff --git a/src/eden/qml/constants/Constants.qml b/src/eden/qml/constants/Constants.qml new file mode 100644 index 0000000000..6ca069e3b8 --- /dev/null +++ b/src/eden/qml/constants/Constants.qml @@ -0,0 +1,24 @@ +pragma Singleton + +import QtQuick + +QtObject { + readonly property int width: 1200 + readonly property int height: 1000 + + property color accent: "#FF4444" + property color accentPressed: "#ff5252" + + readonly property color bg: "#111111" + readonly property color dialog: "#222222" + readonly property color dialogButton: "#000000" + readonly property color sub: "#181818" + + readonly property color button: "#1E1E1E" + readonly property color buttonHighlighted: "#4A4A4A" + + readonly property color text: "#EEEEEE" + readonly property color subText: "#AAAAAA" + + property real scalar: 1.0 +} diff --git a/src/eden/qml/items/AnimatedDialog.qml b/src/eden/qml/items/AnimatedDialog.qml new file mode 100644 index 0000000000..98fc2e8d9e --- /dev/null +++ b/src/eden/qml/items/AnimatedDialog.qml @@ -0,0 +1,79 @@ +import QtQuick +import QtQuick.Controls.Material + +import org.eden_emu.constants + +Dialog { + id: dia + + property int preferredWidth: Overlay.overlay.width / 2 + property int preferredHeight: Overlay.overlay.height / 1.25 + + width: Math.min(preferredWidth, Overlay.overlay.width) + height: Math.min(preferredHeight, Overlay.overlay.height) + + property int radius: 12 + property bool colorful: false + + anchors.centerIn: Overlay.overlay + + enter: Transition { + NumberAnimation { + property: "opacity" + duration: 200 + + from: 0.0 + to: 1.0 + } + } + + exit: Transition { + NumberAnimation { + property: "opacity" + duration: 200 + + from: 1.0 + to: 0.0 + } + } + + header: Rectangle { + topLeftRadius: dia.radius + topRightRadius: dia.radius + + color: colorful ? Qt.alpha(Constants.accent, 0.5) : Constants.dialog + + height: 50 + + Text { + anchors.fill: parent + font.pixelSize: Math.round(25) + + text: title + color: Constants.text + + font.bold: true + + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + } + } + + background: Rectangle { + radius: dia.radius + + color: Constants.dialog + } + + footer: DialogButtonBox { + id: control + + background: Item {} + + delegate: Button { + id: btn + } + } + Overlay.modal: Item {} + Overlay.modeless: Item {} +} diff --git a/src/eden/qml/items/BetterMenu.qml b/src/eden/qml/items/BetterMenu.qml new file mode 100644 index 0000000000..51a38451e5 --- /dev/null +++ b/src/eden/qml/items/BetterMenu.qml @@ -0,0 +1,59 @@ +import QtQuick +import QtQuick.Controls + +import org.eden_emu.constants + +Menu { + background: Rectangle { + implicitWidth: 200 + implicitHeight: 40 + color: Constants.button + + radius: 10 + } + + function fixAmpersands(originalText) { + var regex = /&(\w)/g + return originalText.replace(regex, "$1") + } + + delegate: MenuItem { + id: control + + font.pixelSize: 14 + + background: Rectangle { + color: control.down || control.hovered + || control.highlighted ? Constants.buttonHighlighted : Constants.button + } + + contentItem: Item { + Text { + anchors { + left: parent.left + leftMargin: 5 + (control.checkable ? control.indicator.width : 0) + verticalCenter: parent.verticalCenter + } + + text: fixAmpersands(control.text) + color: Constants.text + font: control.font + } + + Text { + anchors { + right: parent.right + rightMargin: 5 + verticalCenter: parent.verticalCenter + } + + Component.onCompleted: if (control.action != null + && typeof control.action.shortcut !== 'undefined') + text = control.action.shortcut + + color: Constants.text + font: control.font + } + } + } +} diff --git a/src/eden/qml/items/BetterMenuBar.qml b/src/eden/qml/items/BetterMenuBar.qml new file mode 100644 index 0000000000..8b5fd10d9a --- /dev/null +++ b/src/eden/qml/items/BetterMenuBar.qml @@ -0,0 +1,33 @@ +import QtQuick +import QtQuick.Controls + +import org.eden_emu.constants + +MenuBar { + background: Rectangle { + implicitHeight: 30 + color: Constants.button + } + + function fixAmpersands(originalText) { + var regex = /&(\w)/g + return originalText.replace(regex, "$1") + } + + delegate: MenuBarItem { + id: control + + font.pixelSize: 16 + + background: Rectangle { + color: control.down || control.hovered + || control.highlighted ? Constants.buttonHighlighted : Constants.button + } + + contentItem: Text { + text: fixAmpersands(control.text) + color: Constants.text + font: control.font + } + } +} diff --git a/src/eden/qml/items/CMakeLists.txt b/src/eden/qml/items/CMakeLists.txt new file mode 100644 index 0000000000..57ff683ec2 --- /dev/null +++ b/src/eden/qml/items/CMakeLists.txt @@ -0,0 +1,22 @@ +set(CMAKE_AUTOMOC ON) + +qt_add_library(edenItems STATIC) + +qt_add_qml_module(edenItems + URI org.eden_emu.items + VERSION 1.0 + QML_FILES + + StatusBarButton.qml + BetterMenu.qml + AnimatedDialog.qml + BetterMenuBar.qml + + SettingsTabButton.qml + IconButton.qml + QML_FILES VerticalTabBar.qml + QML_FILES + QML_FILES fields/BetterSpinBox.qml + QML_FILES fields/BetterTextField.qml + QML_FILES fields/FieldFooter.qml +) diff --git a/src/eden/qml/items/IconButton.qml b/src/eden/qml/items/IconButton.qml new file mode 100644 index 0000000000..14f28b3fff --- /dev/null +++ b/src/eden/qml/items/IconButton.qml @@ -0,0 +1,23 @@ +import QtQuick +import QtQuick.Controls.Material + +import org.eden_emu.constants + +Button { + required property string label + + bottomInset: 0 + topInset: 0 + leftPadding: 5 * Constants.scalar + rightPadding: 5 * Constants.scalar + + width: icon.width + height: icon.height + + icon.source: "qrc:/icons/" + label.toLowerCase() + ".svg" + icon.width: 45 + icon.height: 45 + icon.color: Constants.text + + background: Item {} +} diff --git a/src/eden/qml/items/SettingsTabButton.qml b/src/eden/qml/items/SettingsTabButton.qml new file mode 100644 index 0000000000..bdc0190aaa --- /dev/null +++ b/src/eden/qml/items/SettingsTabButton.qml @@ -0,0 +1,40 @@ +import QtQuick +import QtQuick.Controls.Material +import QtQuick.Layouts + +import org.eden_emu.constants + +TabButton { + required property string label + + id: button + + implicitHeight: 100 * Constants.scalar + width: 95 * Constants.scalar + + contentItem: ColumnLayout { + IconButton { + label: button.label + + Layout.maximumHeight: 60 * Constants.scalar + Layout.maximumWidth: 65 * Constants.scalar + + Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter + + onClicked: button.clicked() + } + + Text { + font.pixelSize: 16 * Constants.scalar + text: label + + Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter + + color: Constants.text + } + } + + // background: Rectangle { + // color: button.Material.backgroundColor + // } +} diff --git a/src/eden/qml/items/StatusBarButton.qml b/src/eden/qml/items/StatusBarButton.qml new file mode 100644 index 0000000000..211795e337 --- /dev/null +++ b/src/eden/qml/items/StatusBarButton.qml @@ -0,0 +1,36 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import org.eden_emu.constants + +MouseArea { + id: button + + required property string text + property color textColor: Constants.text + + implicitHeight: 20 + implicitWidth: txt.width + + hoverEnabled: true + onHoveredChanged: rect.color = containsMouse ? Constants.buttonHighlighted : "transparent" + + Rectangle { + id: rect + + anchors.fill: parent + color: "transparent" + + Text { + id: txt + + font.pixelSize: 12 * Constants.scalar + leftPadding: 4 + rightPadding: 4 + + color: button.textColor + text: button.text + } + } +} diff --git a/src/eden/qml/items/VerticalTabBar.qml b/src/eden/qml/items/VerticalTabBar.qml new file mode 100644 index 0000000000..2c4fe85886 --- /dev/null +++ b/src/eden/qml/items/VerticalTabBar.qml @@ -0,0 +1,46 @@ +import QtQuick +import QtQuick.Controls.Material + +import org.eden_emu.constants + +TabBar { + clip: true + id: control + + contentItem: ListView { + model: control.contentModel + currentIndex: control.currentIndex + + spacing: control.spacing + orientation: ListView.Vertical + boundsBehavior: Flickable.StopAtBounds + flickableDirection: Flickable.AutoFlickIfNeeded + snapMode: ListView.SnapToItem + + highlightMoveDuration: 300 + highlightRangeMode: ListView.ApplyRange + preferredHighlightBegin: 40 + preferredHighlightEnd: height - 40 + + highlight: Item { + z: 2 + Rectangle { + radius: 5 * Constants.scalar + anchors { + right: parent.right + verticalCenter: parent.verticalCenter + } + + height: parent.height / 2 + width: 5 * Constants.scalar + + color: Constants.accent + } + } + } + + background: Rectangle { + color: control.Material.backgroundColor + radius: 8 * Constants.scalar + } +} diff --git a/src/eden/qml/items/fields/BetterSpinBox.qml b/src/eden/qml/items/fields/BetterSpinBox.qml new file mode 100644 index 0000000000..709b7b75e0 --- /dev/null +++ b/src/eden/qml/items/fields/BetterSpinBox.qml @@ -0,0 +1,68 @@ +import QtQuick +import QtQuick.Controls.Material +import QtQuick.Controls.impl + +import org.eden_emu.constants + +SpinBox { + id: control + property string label: "" + + from: -0x7FFFFFFF + to: 0x7FFFFFFF + + contentItem: BetterTextField { + text: parent.textFromValue(parent.value, parent.locale) + + placeholderText: parent.label + + width: parent.width + + font: parent.font + + horizontalAlignment: Qt.AlignHCenter + verticalAlignment: Qt.AlignVCenter + + inputMethodHints: Qt.ImhFormattedNumbersOnly + + onEditingFinished: { + control.value = parseFloat(text.replace(/,/g, "")) + valueModified() + } + } + + up.indicator: IconLabel { + icon { + source: "qrc:/icons/forward.svg" + } + + x: control.mirrored ? 0 : control.width - width + + implicitWidth: 40 * Constants.scalar + implicitHeight: 40 * Constants.scalar + + height: parent.height + width: height / 2 + } + + down.indicator: IconLabel { + icon { + source: "qrc:/icons/back.svg" + } + + x: control.mirrored ? control.width - width : 0 + + implicitWidth: 40 * Constants.scalar + implicitHeight: 40 * Constants.scalar + + height: parent.height + width: height / 2 + } + background: Item {} + + FieldFooter { + anchors { + bottom: contentItem.bottom + } + } +} diff --git a/src/eden/qml/items/fields/BetterTextField.qml b/src/eden/qml/items/fields/BetterTextField.qml new file mode 100644 index 0000000000..5d32b4022e --- /dev/null +++ b/src/eden/qml/items/fields/BetterTextField.qml @@ -0,0 +1,38 @@ +import QtQuick +import QtQuick.Controls.Material + +import org.eden_emu.constants +import org.eden_emu.items + +TextField { + property string suffix: "" + + placeholderTextColor: enabled && activeFocus ? Constants.accent : Qt.darker( + Constants.text, 1.3) + + color: enabled ? Constants.text : Qt.darker(Constants.text, 1.5) + + background: Rectangle { + color: "transparent" + } + + FieldFooter {} + + horizontalAlignment: "AlignHCenter" + + Text { + id: txt + text: suffix + + font.pixelSize: 14 * Constants.scalar + + anchors { + verticalCenter: parent.verticalCenter + right: parent.right + + rightMargin: 5 * Constants.scalar + } + + color: "gray" + } +} diff --git a/src/eden/qml/items/fields/FieldFooter.qml b/src/eden/qml/items/fields/FieldFooter.qml new file mode 100644 index 0000000000..897785a21b --- /dev/null +++ b/src/eden/qml/items/fields/FieldFooter.qml @@ -0,0 +1,20 @@ +import QtQuick +import QtQuick.Controls.Material +import org.eden_emu.constants + +Rectangle { + height: 2 * Constants.scalar + color: enabled ? Constants.text : Qt.darker(Constants.text, 1.5) + width: parent.width + + anchors { + bottom: parent.bottom + left: parent.left + } + + Behavior on color { + ColorAnimation { + duration: 250 + } + } +} diff --git a/src/eden/qml/main/CMakeLists.txt b/src/eden/qml/main/CMakeLists.txt new file mode 100644 index 0000000000..c2a9e6eed8 --- /dev/null +++ b/src/eden/qml/main/CMakeLists.txt @@ -0,0 +1,13 @@ +set(CMAKE_AUTOMOC ON) + +qt_add_library(edenMain STATIC) +qt_add_qml_module(edenMain + URI org.eden_emu.main + VERSION 1.0 + QML_FILES + + Main.qml + StatusBar.qml + GameList.qml + GamePreview.qml +) diff --git a/src/eden/qml/main/GameList.qml b/src/eden/qml/main/GameList.qml new file mode 100644 index 0000000000..1540452774 --- /dev/null +++ b/src/eden/qml/main/GameList.qml @@ -0,0 +1,141 @@ +import QtQuick +import QtQuick.Controls +import Qt.labs.platform +import QtCore + +import org.eden_emu.constants +import org.eden_emu.interface +import org.eden_emu.gamepad + +Rectangle { + id: root + + property var setting: SettingsInterface.setting("grid_columns") + + property int gx: 0 + property int gy: 0 + + readonly property int deadzone: 8000 + readonly property int repeatTimeMs: 125 + + color: Constants.bg + + // TODO: make this optional. + // Probably just make a Gamepad frontend/backend split with a null backend + Gamepad { + id: gamepad + + onUpPressed: grid.moveCurrentIndexUp() + onDownPressed: grid.moveCurrentIndexDown() + onLeftPressed: grid.moveCurrentIndexLeft() + onRightPressed: grid.moveCurrentIndexRight() + onAPressed: console.log("A pressed") + onLeftStickMoved: (x, y) => { + gx = x + gy = y + } + } + + Timer { + interval: repeatTimeMs + running: true + repeat: true + onTriggered: { + if (gx > deadzone) { + gamepad.rightPressed() + } else if (gx < -deadzone) { + gamepad.leftPressed() + } + + if (gy > deadzone) { + gamepad.downPressed() + } else if (gy < -deadzone) { + gamepad.upPressed() + } + } + } + + Timer { + interval: 16 + running: true + repeat: true + onTriggered: gamepad.pollEvents() + } + + FolderDialog { + id: openDir + folder: StandardPaths.writableLocation(StandardPaths.HomeLocation) + onAccepted: { + button.visible = false + grid.anchors.bottom = root.bottom + EdenGameList.addDir(folder) + } + } + + GridView { + id: grid + + property int cellSize: Math.floor(width / setting.value) + + highlightFollowsCurrentItem: true + clip: true + + cellWidth: cellSize + cellHeight: cellSize + 60 * Constants.scalar + + anchors { + top: parent.top + left: parent.left + right: parent.right + + bottom: button.top + + margins: 8 + } + + model: EdenGameList + + delegate: GamePreview { + id: game + + width: grid.cellSize - 20 * Constants.scalar + height: grid.cellHeight - 20 * Constants.scalar + } + + highlight: Rectangle { + color: "transparent" + z: 5 + + radius: 16 * Constants.scalar + border { + color: Constants.text + width: 3 + } + } + + focus: true + focusPolicy: "StrongFocus" + } + + Button { + id: button + font.pixelSize: 25 + + anchors { + left: parent.left + right: parent.right + + bottom: parent.bottom + + margins: 8 + } + + text: "Add Directory" + onClicked: openDir.open() + + background: Rectangle { + color: button.pressed ? Constants.accentPressed : Constants.accent + radius: 5 + } + } +} diff --git a/src/eden/qml/main/GamePreview.qml b/src/eden/qml/main/GamePreview.qml new file mode 100644 index 0000000000..c1af89bce7 --- /dev/null +++ b/src/eden/qml/main/GamePreview.qml @@ -0,0 +1,77 @@ +import QtQuick +import QtQuick.Controls +import Qt.labs.platform +import QtCore + +import org.eden_emu.constants + +Rectangle { + id: wrapper + + color: Constants.dialog + radius: 16 * Constants.scalar + + Image { + id: image + + fillMode: Image.PreserveAspectFit + source: "file://" + model.path + + clip: true + + anchors { + top: parent.top + left: parent.left + right: parent.right + + margins: 4 * Constants.scalar + } + + height: parent.height - 40 * Constants.scalar + + MouseArea { + id: mouseArea + hoverEnabled: true + + z: 3 + + x: (parent.width - parent.paintedWidth) / 2 + y: (parent.height - parent.paintedHeight) / 2 + + width: parent.paintedWidth + height: parent.paintedHeight + + onContainsMouseChanged: { + if (containsMouse) { + wrapper.GridView.view.currentIndex = index + wrapper.GridView.view.focus = true + } + } + } + } + + Text { + id: nameText + + anchors { + bottom: parent.bottom + bottomMargin: 5 * Constants.scalar + + left: parent.left + right: parent.right + } + + style: Text.Outline + styleColor: Constants.bg + + text: model.name.replace(/-/g, " ") + wrapMode: Text.WordWrap + horizontalAlignment: Qt.AlignHCenter + + font { + pixelSize: 15 * Constants.scalar + } + + color: "white" + } +} diff --git a/src/eden/qml/main/Main.qml b/src/eden/qml/main/Main.qml new file mode 100644 index 0000000000..071b052525 --- /dev/null +++ b/src/eden/qml/main/Main.qml @@ -0,0 +1,207 @@ +import QtQuick +import QtQuick.Controls.Material + +import org.eden_emu.config +import org.eden_emu.items +import org.eden_emu.constants + +ApplicationWindow { + width: Constants.width + height: Constants.height + visible: true + title: qsTr("eden") + + Material.theme: Material.Dark + Material.accent: Material.Red + + Material.roundedScale: Material.NotRounded + + GameList { + anchors { + top: parent.top + left: parent.left + right: parent.right + bottom: status.top + } + } + + /** Dialogs */ + GlobalConfigureDialog { + id: globalConfig + } + + menuBar: BetterMenuBar { + BetterMenu { + title: qsTr("&File") + contentWidth: 225 + + Action { + text: qsTr("&Install files to NAND...") + } + MenuSeparator {} + + Action { + text: qsTr("L&oad File...") + shortcut: "Ctrl+O" + } + + Action { + text: qsTr("Load &Folder...") + } + + MenuSeparator {} + + BetterMenu { + title: "&Recent Files" + } + + MenuSeparator {} + + Action { + text: qsTr("Load/Remove &Amiibo...") + shortcut: "F2" + } + + MenuSeparator {} + + Action { + text: qsTr("Open &eden Directory") + } + + MenuSeparator {} + + Action { + text: qsTr("E&xit") + shortcut: "Ctrl+Q" + } + } + BetterMenu { + title: qsTr("&Emulation") + contentWidth: 240 + + Action { + text: qsTr("&Pause") + shortcut: "F4" + } + + Action { + text: qsTr("&Stop") + shortcut: "F5" + } + + Action { + text: qsTr("&Restart") + shortcut: "F6" + } + + MenuSeparator {} + + Action { + text: qsTr("Con&figure...") + shortcut: "Ctrl+," + onTriggered: globalConfig.open() + } + + Action { + text: qsTr("Configure &Current Game...") + shortcut: "Ctrl+." + } + } + + BetterMenu { + title: qsTr("&View") + contentWidth: 260 + + Action { + text: qsTr("F&ullscreen") + shortcut: "F11" + checkable: true + } + + Action { + text: qsTr("Single &Window Mode") + checkable: true + } + + Action { + text: qsTr("Display D&ock Widget Headers") + checkable: true + } + + Action { + text: qsTr("Show &Filter Bar") + shortcut: "Ctrl+F" + checkable: true + } + + Action { + text: qsTr("Show &Status Bar") + shortcut: "Ctrl+S" + checkable: true + } + + MenuSeparator {} + } + + BetterMenu { + title: qsTr("&Tools") + contentWidth: 225 + + Action { + text: qsTr("Install &Decryption Keys") + } + + Action { + text: qsTr("Install &Firmware") + } + + Action { + text: qsTr("&Verify Installed Contents") + } + + MenuSeparator {} + + BetterMenu { + title: qsTr("&Amiibo") + } + + Action { + text: qsTr("Open A&lbum") + } + + Action { + text: qsTr("Open &Mii Editor") + } + + Action { + text: qsTr("Open Co&ntroller Menu") + } + + Action { + text: qsTr("Open &Home Menu") + } + + MenuSeparator {} + + Action { + text: qsTr("&Capture Screenshot") + shortcut: "Ctrl+P" + } + + BetterMenu { + title: "&TAS" + } + } + } + + StatusBar { + id: status + + height: 30 + anchors { + left: parent.left + right: parent.right + bottom: parent.bottom + } + } +} diff --git a/src/eden/qml/main/StatusBar.qml b/src/eden/qml/main/StatusBar.qml new file mode 100644 index 0000000000..39aeaed393 --- /dev/null +++ b/src/eden/qml/main/StatusBar.qml @@ -0,0 +1,160 @@ +import QtQuick +import QtQuick.Controls.Material +import QtQuick.Layouts + +import org.eden_emu.constants +import org.eden_emu.items + +ToolBar { + id: toolbar + + property string graphicsBackend: "vulkan" + property string gpuAccuracy: "high" + property string consoleMode: "docked" + property int adapting: 5 + property int antialiasing: 0 + property int volume: 100 + + property string firmwareVersion: "16.0.3" + + implicitHeight: 30 + + background: Rectangle { + color: Constants.bg + } + + // TODO: reduce duplicate code + RowLayout { + id: row + + anchors { + left: parent.left + top: parent.top + bottom: parent.bottom + + leftMargin: 10 + } + + StatusBarButton { + property alias value: toolbar.graphicsBackend + + text: value.toUpperCase() + + textColor: value === "vulkan" ? "orange" : "lightblue" + + onClicked: { + if (value === "vulkan") { + value = "opengl" + } else { + value = "vulkan" + } + } + } + + StatusBarButton { + property alias value: toolbar.gpuAccuracy + + text: value.toUpperCase() + + textColor: value === "high" ? "orange" : "lightgreen" + + onClicked: { + if (value === "high") { + value = "normal" + } else { + value = "high" + } + } + } + + StatusBarButton { + property alias value: toolbar.consoleMode + + text: value.toUpperCase() + + textColor: Constants.text + + onClicked: { + if (value === "docked") { + value = "handheld" + } else { + value = "docked" + } + } + } + + StatusBarButton { + property list choices: ["nearest", "bilinear", "bicubic", "gaussian", "scaleforce", "fsr"] + + property alias index: toolbar.adapting + property string value: choices[index] + + text: value.toUpperCase() + + onClicked: { + let newIndex = index + 1 + if (newIndex >= choices.length) { + newIndex = 0 + } + + index = newIndex + } + } + + StatusBarButton { + property list choices: ["no aa", "fxaa", "msaa"] + + property alias index: toolbar.antialiasing + property string value: choices[index] + + text: value.toUpperCase() + + onClicked: { + let newIndex = index + 1 + if (newIndex >= choices.length) { + newIndex = 0 + } + + index = newIndex + } + } + + StatusBarButton { + id: volumeButton + + property alias value: toolbar.volume + + text: "VOLUME: " + value + "%" + + onClicked: { + volumeSlider.open() + } + + onWheel: wheel => { + value += wheel.angleDelta.y / 120 + } + } + } + + Popup { + id: volumeSlider + + width: 200 + height: 50 + + x: volumeButton.x + y: volumeButton.y - height + + focus: true + + Slider { + value: volumeButton.value + onMoved: volumeButton.value = value + + from: 0 + to: 200 + + anchors.fill: parent + } + } +} From a1db66cf7ae546797de3b588e51ff179559532d9 Mon Sep 17 00:00:00 2001 From: crueter Date: Mon, 16 Jun 2025 20:46:40 -0400 Subject: [PATCH 27/34] tmp Signed-off-by: crueter --- .gitignore | 2 ++ src/CMakeLists.txt | 1 - src/eden/CMakeLists.txt | 1 + src/eden/interface/CMakeLists.txt | 1 + src/eden/interface/QMLConfig.h | 26 +++++++++++++++ src/eden/interface/SettingsInterface.h | 2 +- src/eden/interface/qt_config.cpp | 3 ++ src/eden/main.cpp | 27 +++++++++------- src/eden/models/SettingsModel.cpp | 2 ++ src/eden/models/SettingsModel.h | 2 +- src/eden/qml/CMakeLists.txt | 1 + src/eden/qml/config/GlobalConfigureDialog.qml | 21 ++++++++---- src/eden/qml/config/fields/BaseField.qml | 10 +++++- src/eden/qml/config/fields/ConfigCheckbox.qml | 2 +- src/eden/qml/config/fields/ConfigHexEdit.qml | 4 +-- src/eden/qml/config/fields/ConfigIntLine.qml | 4 +-- .../qml/config/fields/ConfigIntSlider.qml | 7 ++-- src/eden/qml/config/fields/ConfigIntSpin.qml | 5 +-- .../qml/config/fields/ConfigStringEdit.qml | 4 +-- src/eden/qml/config/fields/ConfigTimeEdit.qml | 2 +- .../config/pages/global/GlobalAudioPage.qml | 2 ++ .../qml/config/pages/global/GlobalCpuPage.qml | 1 + .../config/pages/global/GlobalDebugPage.qml | 1 + .../config/pages/global/GlobalGeneralPage.qml | 1 + .../pages/global/GlobalGraphicsPage.qml | 1 + .../config/pages/global/GlobalSystemPage.qml | 1 + src/eden/qml/util/CMakeLists.txt | 23 +++++++++++++ src/eden/qml/util/Util.qml | 32 +++++++++++++++++++ 28 files changed, 153 insertions(+), 36 deletions(-) create mode 100644 src/eden/interface/QMLConfig.h create mode 100644 src/eden/qml/util/CMakeLists.txt create mode 100644 src/eden/qml/util/Util.qml diff --git a/.gitignore b/.gitignore index 2b342e5145..b263cb6a42 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,5 @@ eden-windows-msvc artifacts *.AppImage* /install* +/*.patch +/.cache diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5f12646c71..f3d45bbfe2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -131,7 +131,6 @@ else() add_compile_options( -Werror=all -Werror=extra - -Werror=missing-declarations -Werror=shadow -Werror=unused diff --git a/src/eden/CMakeLists.txt b/src/eden/CMakeLists.txt index 702ccd3adf..50d9b30db7 100644 --- a/src/eden/CMakeLists.txt +++ b/src/eden/CMakeLists.txt @@ -21,6 +21,7 @@ set(PLUGINS edenConfigplugin edenInterfaceplugin edenConstantsplugin + edenUtilplugin ) if (ENABLE_SDL2) diff --git a/src/eden/interface/CMakeLists.txt b/src/eden/interface/CMakeLists.txt index 374b4ec70d..290dec22b9 100644 --- a/src/eden/interface/CMakeLists.txt +++ b/src/eden/interface/CMakeLists.txt @@ -9,5 +9,6 @@ qt_add_qml_module(edenInterface shared_translation.h shared_translation.cpp QMLSetting.h QMLSetting.cpp MetaObjectHelper.h + SOURCES QMLConfig.h ) diff --git a/src/eden/interface/QMLConfig.h b/src/eden/interface/QMLConfig.h new file mode 100644 index 0000000000..83b7f174cb --- /dev/null +++ b/src/eden/interface/QMLConfig.h @@ -0,0 +1,26 @@ +#ifndef QMLCONFIG_H +#define QMLCONFIG_H + +#include "eden/interface/qt_config.h" + +#include + +class QMLConfig : public QObject { + Q_OBJECT + + QtConfig *m_config; + +public: + QMLConfig() + : m_config{new QtConfig} + {} + + Q_INVOKABLE inline void reload() { + m_config->ReloadAllValues(); + } + Q_INVOKABLE inline void save() { + m_config->SaveAllValues(); + } +}; + +#endif // QMLCONFIG_H diff --git a/src/eden/interface/SettingsInterface.h b/src/eden/interface/SettingsInterface.h index 4c132c3ce6..c5a0617f26 100644 --- a/src/eden/interface/SettingsInterface.h +++ b/src/eden/interface/SettingsInterface.h @@ -6,7 +6,7 @@ #include "QMLSetting.h" #include "shared_translation.h" -#include "yuzu/models/SettingsModel.h" +#include "eden/models/SettingsModel.h" namespace SettingsCategories { Q_NAMESPACE diff --git a/src/eden/interface/qt_config.cpp b/src/eden/interface/qt_config.cpp index f4390065c4..9cd8f58c3d 100644 --- a/src/eden/interface/qt_config.cpp +++ b/src/eden/interface/qt_config.cpp @@ -534,6 +534,9 @@ void QtConfig::SaveMultiplayerValues() { std::vector& QtConfig::FindRelevantList(Settings::Category category) { auto& map = Settings::values.linkage.by_category; + // if (!map[category].empty()) { + // return map[category]; + // } if (map.contains(category)) { return Settings::values.linkage.by_category[category]; } diff --git a/src/eden/main.cpp b/src/eden/main.cpp index 6e4126d466..810d293c36 100644 --- a/src/eden/main.cpp +++ b/src/eden/main.cpp @@ -1,10 +1,10 @@ -#include "core/core.h" -#include "interface/SettingsInterface.h" -#include "interface/qt_config.h" -#include "models/GameListModel.h" #include #include #include +#include "core/core.h" +#include "interface/QMLConfig.h" +#include "models/GameListModel.h" +#include "interface/SettingsInterface.h" #include @@ -14,18 +14,18 @@ int main(int argc, char *argv[]) QQuickStyle::setStyle(QObject::tr("Material")); - QCoreApplication::setOrganizationName(QStringLiteral("yuzu")); + QCoreApplication::setOrganizationName(QStringLiteral("eden-emu")); QCoreApplication::setApplicationName(QStringLiteral("eden")); + QApplication::setDesktopFileName(QStringLiteral("org.eden-emu.eden")); /// Settings, etc Settings::SetConfiguringGlobal(true); - QtConfig *config = new QtConfig; - config->SaveAllValues(); + QMLConfig *config = new QMLConfig; - // TODO: Save all values on launch and per game etc - app.connect(&app, &QCoreApplication::aboutToQuit, &app, [config]() { - config->SaveAllValues(); - }); + // // TODO: Save all values on launch and per game etc + // app.connect(&app, &QCoreApplication::aboutToQuit, &app, [config]() { + // config->save(); + // }); /// Expose Enums @@ -34,13 +34,16 @@ int main(int argc, char *argv[]) /// CONTEXT QQmlApplicationEngine engine; + auto ctx = engine.rootContext(); + + ctx->setContextProperty(QStringLiteral("QtConfig"), QVariant::fromValue(config)); // Enums qmlRegisterUncreatableMetaObject(SettingsCategories::staticMetaObject, "org.eden_emu.interface", 1, 0, "SettingsCategories", QString()); // Directory List GameListModel *gameListModel = new GameListModel(&app); - engine.rootContext()->setContextProperty(QStringLiteral("EdenGameList"), gameListModel); + ctx->setContextProperty(QStringLiteral("EdenGameList"), gameListModel); /// LOAD QObject::connect( diff --git a/src/eden/models/SettingsModel.cpp b/src/eden/models/SettingsModel.cpp index a6a9d1bb62..6627ef2c72 100644 --- a/src/eden/models/SettingsModel.cpp +++ b/src/eden/models/SettingsModel.cpp @@ -47,7 +47,9 @@ bool SettingsModel::setData(const QModelIndex &index, const QVariant &value, int switch (role) { case VALUE: + qDebug() << "Before" << s->value(); s->setValue(value); + qDebug() << "After" << s->value(); break; } diff --git a/src/eden/models/SettingsModel.h b/src/eden/models/SettingsModel.h index 0edaab7982..4f7ff9860e 100644 --- a/src/eden/models/SettingsModel.h +++ b/src/eden/models/SettingsModel.h @@ -2,7 +2,7 @@ #define SETTINGSMODEL_H #include -#include "yuzu/interface/QMLSetting.h" +#include "eden/interface/QMLSetting.h" class SettingsModel : public QAbstractListModel { Q_OBJECT diff --git a/src/eden/qml/CMakeLists.txt b/src/eden/qml/CMakeLists.txt index 958f84c3dd..293061b88f 100644 --- a/src/eden/qml/CMakeLists.txt +++ b/src/eden/qml/CMakeLists.txt @@ -1,5 +1,6 @@ add_subdirectory(config) add_subdirectory(constants) add_subdirectory(items) +add_subdirectory(util) add_subdirectory(main) diff --git a/src/eden/qml/config/GlobalConfigureDialog.qml b/src/eden/qml/config/GlobalConfigureDialog.qml index 869a682858..50d81a5469 100644 --- a/src/eden/qml/config/GlobalConfigureDialog.qml +++ b/src/eden/qml/config/GlobalConfigureDialog.qml @@ -5,21 +5,28 @@ import QtQuick.Layouts import org.eden_emu.constants import org.eden_emu.items import org.eden_emu.interface +import org.eden_emu.util + +AnimatedDialog { + property list configs -Dialog { preferredWidth: 1280 title: "Configuration" standardButtons: Dialog.Ok | Dialog.Cancel - onOpened: { - for (var tab in tabBar.children) { - console.log(tab) - } - } + Component.onCompleted: configs = Util.searchItem(swipe, "BaseField") onAccepted: { - + configs.forEach(config => { + config.apply() + // console.log(config.setting.label) + }) + QtConfig.save() + } + onRejected: { + configs.forEach(config => config.sync()) + QtConfig.reload() } VerticalTabBar { diff --git a/src/eden/qml/config/fields/BaseField.qml b/src/eden/qml/config/fields/BaseField.qml index 092f69f3eb..3d045a3b7b 100644 --- a/src/eden/qml/config/fields/BaseField.qml +++ b/src/eden/qml/config/fields/BaseField.qml @@ -14,11 +14,19 @@ Item { property alias enable: enable.checked property Item contentItem + readonly property string typeName: "BaseField" + clip: true height: content.height + (helpText.height + helpText.anchors.topMargin) + Component.onCompleted: sync() + function apply() { - setting.value = value + if (setting.value !== value) { + console.log(setting.label, "previous value:", setting.value, + "new value:", value) + setting.value = value + } } function sync() { diff --git a/src/eden/qml/config/fields/ConfigCheckbox.qml b/src/eden/qml/config/fields/ConfigCheckbox.qml index 43c84e2248..846be6147d 100644 --- a/src/eden/qml/config/fields/ConfigCheckbox.qml +++ b/src/eden/qml/config/fields/ConfigCheckbox.qml @@ -20,7 +20,7 @@ BaseField { text: setting.label checked: setting.value - onClicked: setting.value = checked + onClicked: value = checked checkable: true } diff --git a/src/eden/qml/config/fields/ConfigHexEdit.qml b/src/eden/qml/config/fields/ConfigHexEdit.qml index 983b0e94c7..0e4a3c1974 100644 --- a/src/eden/qml/config/fields/ConfigHexEdit.qml +++ b/src/eden/qml/config/fields/ConfigHexEdit.qml @@ -18,9 +18,9 @@ BaseField { font.pixelSize: 15 * Constants.scalar - text: Number(setting.value).toString(16) + text: Number(value).toString(16) suffix: setting.suffix - onTextEdited: setting.value = Number("0x" + text) + onTextEdited: value = Number("0x" + text) } } diff --git a/src/eden/qml/config/fields/ConfigIntLine.qml b/src/eden/qml/config/fields/ConfigIntLine.qml index 7f1653207c..6f48b72492 100644 --- a/src/eden/qml/config/fields/ConfigIntLine.qml +++ b/src/eden/qml/config/fields/ConfigIntLine.qml @@ -20,9 +20,9 @@ BaseField { font.pixelSize: 15 * Constants.scalar - text: setting.value + text: value suffix: setting.suffix - onTextEdited: setting.value = parseInt(text) + onTextEdited: value = parseInt(text) } } diff --git a/src/eden/qml/config/fields/ConfigIntSlider.qml b/src/eden/qml/config/fields/ConfigIntSlider.qml index eac6f66993..9428a0c791 100644 --- a/src/eden/qml/config/fields/ConfigIntSlider.qml +++ b/src/eden/qml/config/fields/ConfigIntSlider.qml @@ -8,6 +8,7 @@ import org.eden_emu.constants // Lots of cancer but idrc BaseField { + id: field contentItem: RowLayout { Layout.fillWidth: true @@ -18,9 +19,9 @@ BaseField { to: setting.max stepSize: 1 - value: setting.value + value: field.value - onMoved: setting.value = value + onMoved: field.value = value Layout.rightMargin: 10 * Constants.scalar @@ -31,7 +32,7 @@ BaseField { font.pixelSize: 14 * Constants.scalar color: Constants.text - text: setting.value + setting.suffix + text: field.value + setting.suffix Layout.rightMargin: 10 * Constants.scalar } diff --git a/src/eden/qml/config/fields/ConfigIntSpin.qml b/src/eden/qml/config/fields/ConfigIntSpin.qml index 7d65e90663..3fe0a82183 100644 --- a/src/eden/qml/config/fields/ConfigIntSpin.qml +++ b/src/eden/qml/config/fields/ConfigIntSpin.qml @@ -6,6 +6,7 @@ import org.eden_emu.config import org.eden_emu.constants BaseField { + id: field contentItem: BetterSpinBox { enabled: enable @@ -17,9 +18,9 @@ BaseField { font.pixelSize: 15 * Constants.scalar - value: setting.value + value: field.value label: setting.suffix - onValueModified: setting.value = value + onValueModified: field.value = value } } diff --git a/src/eden/qml/config/fields/ConfigStringEdit.qml b/src/eden/qml/config/fields/ConfigStringEdit.qml index 32873c96b2..11c58ac7a3 100644 --- a/src/eden/qml/config/fields/ConfigStringEdit.qml +++ b/src/eden/qml/config/fields/ConfigStringEdit.qml @@ -14,9 +14,9 @@ BaseField { font.pixelSize: 15 * Constants.scalar - text: setting.value + text: value suffix: setting.suffix - onTextEdited: setting.value = text + onTextEdited: value = text } } diff --git a/src/eden/qml/config/fields/ConfigTimeEdit.qml b/src/eden/qml/config/fields/ConfigTimeEdit.qml index e070102ca3..66c731c7ed 100644 --- a/src/eden/qml/config/fields/ConfigTimeEdit.qml +++ b/src/eden/qml/config/fields/ConfigTimeEdit.qml @@ -21,7 +21,7 @@ BaseField { font.pixelSize: 15 * Constants.scalar - text: setting.value + text: value suffix: setting.suffix } } diff --git a/src/eden/qml/config/pages/global/GlobalAudioPage.qml b/src/eden/qml/config/pages/global/GlobalAudioPage.qml index ddfdef51f8..73ed7f20fe 100644 --- a/src/eden/qml/config/pages/global/GlobalAudioPage.qml +++ b/src/eden/qml/config/pages/global/GlobalAudioPage.qml @@ -3,6 +3,8 @@ import QtQuick import org.eden_emu.config GlobalTab { + property alias swipe: swipe + tabs: ["Audio"] GlobalTabSwipeView { diff --git a/src/eden/qml/config/pages/global/GlobalCpuPage.qml b/src/eden/qml/config/pages/global/GlobalCpuPage.qml index bcca4f17ae..457565ede7 100644 --- a/src/eden/qml/config/pages/global/GlobalCpuPage.qml +++ b/src/eden/qml/config/pages/global/GlobalCpuPage.qml @@ -3,6 +3,7 @@ import QtQuick import org.eden_emu.config GlobalTab { + property alias swipe: swipe tabs: ["CPU"] GlobalTabSwipeView { diff --git a/src/eden/qml/config/pages/global/GlobalDebugPage.qml b/src/eden/qml/config/pages/global/GlobalDebugPage.qml index 85df6bd1e4..bbbbfbf29f 100644 --- a/src/eden/qml/config/pages/global/GlobalDebugPage.qml +++ b/src/eden/qml/config/pages/global/GlobalDebugPage.qml @@ -3,6 +3,7 @@ import QtQuick import org.eden_emu.config GlobalTab { + property alias swipe: swipe tabs: ["General", "Graphics", "Advanced", "CPU"] GlobalTabSwipeView { diff --git a/src/eden/qml/config/pages/global/GlobalGeneralPage.qml b/src/eden/qml/config/pages/global/GlobalGeneralPage.qml index 30a782d5a8..feae9cd482 100644 --- a/src/eden/qml/config/pages/global/GlobalGeneralPage.qml +++ b/src/eden/qml/config/pages/global/GlobalGeneralPage.qml @@ -3,6 +3,7 @@ import QtQuick import org.eden_emu.config GlobalTab { + property alias swipe: swipe tabs: ["General", "Hotkeys", "Game List"] GlobalTabSwipeView { diff --git a/src/eden/qml/config/pages/global/GlobalGraphicsPage.qml b/src/eden/qml/config/pages/global/GlobalGraphicsPage.qml index af42494591..67380be9e4 100644 --- a/src/eden/qml/config/pages/global/GlobalGraphicsPage.qml +++ b/src/eden/qml/config/pages/global/GlobalGraphicsPage.qml @@ -3,6 +3,7 @@ import QtQuick import org.eden_emu.config GlobalTab { + property alias swipe: swipe tabs: ["Graphics", "Advanced", "Extensions"] GlobalTabSwipeView { diff --git a/src/eden/qml/config/pages/global/GlobalSystemPage.qml b/src/eden/qml/config/pages/global/GlobalSystemPage.qml index 20f0780c97..1fa34e0d26 100644 --- a/src/eden/qml/config/pages/global/GlobalSystemPage.qml +++ b/src/eden/qml/config/pages/global/GlobalSystemPage.qml @@ -3,6 +3,7 @@ import QtQuick import org.eden_emu.config GlobalTab { + property alias swipe: swipe tabs: ["System", "Core", "Profiles", "Filesystem", "Applets"] GlobalTabSwipeView { diff --git a/src/eden/qml/util/CMakeLists.txt b/src/eden/qml/util/CMakeLists.txt new file mode 100644 index 0000000000..a2243aa611 --- /dev/null +++ b/src/eden/qml/util/CMakeLists.txt @@ -0,0 +1,23 @@ +set(CMAKE_AUTOMOC ON) + +find_package(Qt6 REQUIRED COMPONENTS Quick) + +set_source_files_properties(Util.qml + PROPERTIES + QT_QML_SINGLETON_TYPE true +) + +qt_add_library(edenUtil STATIC) +qt_add_qml_module(edenUtil + URI org.eden_emu.util + OUTPUT_DIRECTORY EdenUtil + VERSION 1.0 + QML_FILES + + Util.qml +) + +target_link_libraries(edenUtil + PRIVATE + Qt6::Quick +) diff --git a/src/eden/qml/util/Util.qml b/src/eden/qml/util/Util.qml new file mode 100644 index 0000000000..03d2a09beb --- /dev/null +++ b/src/eden/qml/util/Util.qml @@ -0,0 +1,32 @@ +pragma Singleton + +import QtQuick + +QtObject { + /** + * Recursively search an Item for children matching the specified type. + * @return A list of found items. + */ + function searchItem(parent, typeName) { + let results = [] + + // Search contentChildren too for views/layouts/etc + let children = parent.children + if (parent.contentChildren) { + children = parent.contentChildren + } + + for (var i = 0; i < children.length; ++i) { + let child = children[i] + + if (child.typeName === typeName) { + results.push(child) + } + + let childResults = searchItem(child, typeName) + results = results.concat(childResults) + } + + return results + } +} From 0e13a362f1cc10131245189845d78009fcc3982a Mon Sep 17 00:00:00 2001 From: crueter Date: Mon, 16 Jun 2025 21:53:19 -0400 Subject: [PATCH 28/34] Working configuration Signed-off-by: crueter --- src/eden/interface/qt_config.cpp | 7 +- src/eden/interface/shared_translation.cpp | 275 +++++++++++++----- src/eden/models/SettingsModel.cpp | 2 - src/eden/qml/config/fields/BaseField.qml | 12 +- src/eden/qml/config/fields/ConfigCheckbox.qml | 28 +- src/eden/qml/config/fields/FieldCheckbox.qml | 9 +- 6 files changed, 228 insertions(+), 105 deletions(-) diff --git a/src/eden/interface/qt_config.cpp b/src/eden/interface/qt_config.cpp index 9cd8f58c3d..5dcad01eb1 100644 --- a/src/eden/interface/qt_config.cpp +++ b/src/eden/interface/qt_config.cpp @@ -534,11 +534,8 @@ void QtConfig::SaveMultiplayerValues() { std::vector& QtConfig::FindRelevantList(Settings::Category category) { auto& map = Settings::values.linkage.by_category; - // if (!map[category].empty()) { - // return map[category]; - // } - if (map.contains(category)) { - return Settings::values.linkage.by_category[category]; + if (!map[category].empty()) { + return map[category]; } return UISettings::values.linkage.by_category[category]; } diff --git a/src/eden/interface/shared_translation.cpp b/src/eden/interface/shared_translation.cpp index c0eea3d440..59c1011465 100644 --- a/src/eden/interface/shared_translation.cpp +++ b/src/eden/interface/shared_translation.cpp @@ -1,14 +1,14 @@ // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "shared_translation.h" +#include "eden/interface/shared_translation.h" #include #include "common/settings.h" #include "common/settings_enums.h" #include "common/settings_setting.h" #include "common/time_zone.h" -#include "uisettings.h" +#include "yuzu/uisettings.h" #include #include #include @@ -21,7 +21,7 @@ std::unique_ptr InitializeTranslations(QObject* parent) std::unique_ptr translations = std::make_unique(); const auto& tr = [parent](const char* text) -> QString { return parent->tr(text); }; -#define INSERT(SETTINGS, ID, NAME, TOOLTIP) \ +#define INSERT(SETTINGS, ID, NAME, TOOLTIP) \ translations->insert(std::pair{SETTINGS::values.ID.Id(), std::pair{(NAME), (TOOLTIP)}}) // A setting can be ignored by giving it a blank name @@ -54,110 +54,166 @@ std::unique_ptr InitializeTranslations(QObject* parent) // Core INSERT( - Settings, use_multi_core, tr("Multicore CPU Emulation"), + Settings, + use_multi_core, + tr("Multicore CPU Emulation"), tr("This option increases CPU emulation thread use from 1 to the Switch’s maximum of 4.\n" "This is mainly a debug option and shouldn’t be disabled.")); INSERT( - Settings, memory_layout_mode, tr("Memory Layout"), + Settings, + memory_layout_mode, + tr("Memory Layout"), tr("Increases the amount of emulated RAM from the stock 4GB of the retail Switch to the " "developer kit's 8/6GB.\nIt’s doesn’t improve stability or performance and is intended " "to let big texture mods fit in emulated RAM.\nEnabling it will increase memory " "use. It is not recommended to enable unless a specific game with a texture mod needs " "it.")); INSERT(Settings, use_speed_limit, QString(), QString()); - INSERT(Settings, speed_limit, tr("Limit Speed Percent"), + INSERT(Settings, + speed_limit, + tr("Limit Speed Percent"), tr("Controls the game's maximum rendering speed, but it’s up to each game if it runs " "faster or not.\n200% for a 30 FPS game is 60 FPS, and for a " "60 FPS game it will be 120 FPS.\nDisabling it means unlocking the framerate to the " "maximum your PC can reach.")); - INSERT(Settings, sync_core_speed, tr("Synchronize Core Speed"), - tr("Synchronizes CPU core speed with the game's maximum rendering speed to boost FPS without affecting game speed (animations, physics, etc.).\n" - "Compatibility varies by game; many (especially older ones) may not respond well.\n" - "Can help reduce stuttering at lower framerates.")); + INSERT(Settings, + sync_core_speed, + tr("Synchronize Core Speed"), + tr("Synchronizes CPU core speed with the game's maximum rendering speed to boost FPS " + "without affecting game speed (animations, physics, etc.).\n" + "Compatibility varies by game; many (especially older ones) may not respond well.\n" + "Can help reduce stuttering at lower framerates.")); // Cpu - INSERT(Settings, cpu_accuracy, tr("Accuracy:"), + INSERT(Settings, + cpu_accuracy, + tr("Accuracy:"), tr("This setting controls the accuracy of the emulated CPU.\nDon't change this unless " "you know what you are doing.")); INSERT(Settings, cpu_backend, tr("Backend:"), QString()); + INSERT(Settings, use_fast_cpu_time, QString(), QString()); + INSERT(Settings, + fast_cpu_time, + tr("Fast CPU Time"), + tr("Overclocks the emulated CPU to remove some FPS limiters. Weaker CPUs may see reduced performance, " + "and certain games may behave improperly.\nUse Boost (1700MHz) to run at the Switch's highest native " + "clock, or Fast (2000MHz) to run at 2x clock.")); + INSERT(Settings, cpu_backend, tr("Backend:"), QString()); + // Cpu Debug // Cpu Unsafe INSERT( - Settings, cpuopt_unsafe_unfuse_fma, + Settings, + cpuopt_unsafe_unfuse_fma, tr("Unfuse FMA (improve performance on CPUs without FMA)"), tr("This option improves speed by reducing accuracy of fused-multiply-add instructions on " "CPUs without native FMA support.")); INSERT( - Settings, cpuopt_unsafe_reduce_fp_error, tr("Faster FRSQRTE and FRECPE"), + Settings, + cpuopt_unsafe_reduce_fp_error, + tr("Faster FRSQRTE and FRECPE"), tr("This option improves the speed of some approximate floating-point functions by using " "less accurate native approximations.")); - INSERT(Settings, cpuopt_unsafe_ignore_standard_fpcr, + INSERT(Settings, + cpuopt_unsafe_ignore_standard_fpcr, tr("Faster ASIMD instructions (32 bits only)"), tr("This option improves the speed of 32 bits ASIMD floating-point functions by running " "with incorrect rounding modes.")); - INSERT(Settings, cpuopt_unsafe_inaccurate_nan, tr("Inaccurate NaN handling"), + INSERT(Settings, + cpuopt_unsafe_inaccurate_nan, + tr("Inaccurate NaN handling"), tr("This option improves speed by removing NaN checking.\nPlease note this also reduces " "accuracy of certain floating-point instructions.")); - INSERT(Settings, cpuopt_unsafe_fastmem_check, tr("Disable address space checks"), + INSERT(Settings, + cpuopt_unsafe_fastmem_check, + tr("Disable address space checks"), tr("This option improves speed by eliminating a safety check before every memory " "read/write in guest.\nDisabling it may allow a game to read/write the emulator's " "memory.")); INSERT( - Settings, cpuopt_unsafe_ignore_global_monitor, tr("Ignore global monitor"), + Settings, + cpuopt_unsafe_ignore_global_monitor, + tr("Ignore global monitor"), tr("This option improves speed by relying only on the semantics of cmpxchg to ensure " "safety of exclusive access instructions.\nPlease note this may result in deadlocks and " "other race conditions.")); // Renderer INSERT( - Settings, renderer_backend, tr("API:"), + Settings, + renderer_backend, + tr("API:"), tr("Switches between the available graphics APIs.\nVulkan is recommended in most cases.")); - INSERT(Settings, vulkan_device, tr("Device:"), + INSERT(Settings, + vulkan_device, + tr("Device:"), tr("This setting selects the GPU to use with the Vulkan backend.")); - INSERT(Settings, shader_backend, tr("Shader Backend:"), + INSERT(Settings, + shader_backend, + tr("Shader Backend:"), tr("The shader backend to use for the OpenGL renderer.\nGLSL is the fastest in " "performance and the best in rendering accuracy.\n" "GLASM is a deprecated NVIDIA-only backend that offers much better shader building " "performance at the cost of FPS and rendering accuracy.\n" "SPIR-V compiles the fastest, but yields poor results on most GPU drivers.")); - INSERT(Settings, resolution_setup, tr("Resolution:"), + INSERT(Settings, + resolution_setup, + tr("Resolution:"), tr("Forces the game to render at a different resolution.\nHigher resolutions require " "much more VRAM and bandwidth.\n" "Options lower than 1X can cause rendering issues.")); INSERT(Settings, scaling_filter, tr("Window Adapting Filter:"), QString()); - INSERT(Settings, fsr_sharpening_slider, tr("FSR Sharpness:"), + INSERT(Settings, + fsr_sharpening_slider, + tr("FSR Sharpness:"), tr("Determines how sharpened the image will look while using FSR’s dynamic contrast.")); - INSERT(Settings, anti_aliasing, tr("Anti-Aliasing Method:"), + INSERT(Settings, + anti_aliasing, + tr("Anti-Aliasing Method:"), tr("The anti-aliasing method to use.\nSMAA offers the best quality.\nFXAA has a " "lower performance impact and can produce a better and more stable picture under " "very low resolutions.")); - INSERT(Settings, fullscreen_mode, tr("Fullscreen Mode:"), + INSERT(Settings, + fullscreen_mode, + tr("Fullscreen Mode:"), tr("The method used to render the window in fullscreen.\nBorderless offers the best " "compatibility with the on-screen keyboard that some games request for " "input.\nExclusive " "fullscreen may offer better performance and better Freesync/Gsync support.")); - INSERT(Settings, aspect_ratio, tr("Aspect Ratio:"), + INSERT(Settings, + aspect_ratio, + tr("Aspect Ratio:"), tr("Stretches the game to fit the specified aspect ratio.\nSwitch games only support " "16:9, so custom game mods are required to get other ratios.\nAlso controls the " "aspect ratio of captured screenshots.")); - INSERT(Settings, use_disk_shader_cache, tr("Use disk pipeline cache"), + INSERT(Settings, + use_disk_shader_cache, + tr("Use disk pipeline cache"), tr("Allows saving shaders to storage for faster loading on following game " "boots.\nDisabling " "it is only intended for debugging.")); - INSERT(Settings, optimize_spirv_output, tr("Optimize SPIRV output shader"), - tr("Runs an additional optimization pass over generated SPIRV shaders.\n" - "Will increase time required for shader compilation.\nMay slightly improve " - "performance.\nThis feature is experimental.")); + INSERT(Settings, + optimize_spirv_output, + tr("Optimize SPIRV output shader"), + tr("Runs an additional optimization pass over generated SPIRV shaders.\n" + "Will increase time required for shader compilation.\nMay slightly improve " + "performance.\nThis feature is experimental.")); INSERT( - Settings, use_asynchronous_gpu_emulation, tr("Use asynchronous GPU emulation"), + Settings, + use_asynchronous_gpu_emulation, + tr("Use asynchronous GPU emulation"), tr("Uses an extra CPU thread for rendering.\nThis option should always remain enabled.")); - INSERT(Settings, nvdec_emulation, tr("NVDEC emulation:"), + INSERT(Settings, + nvdec_emulation, + tr("NVDEC emulation:"), tr("Specifies how videos should be decoded.\nIt can either use the CPU or the GPU for " "decoding, or perform no decoding at all (black screen on videos).\n" "In most cases, GPU decoding provides the best performance.")); - INSERT(Settings, accelerate_astc, tr("ASTC Decoding Method:"), + INSERT(Settings, + accelerate_astc, + tr("ASTC Decoding Method:"), tr("This option controls how ASTC textures should be decoded.\n" "CPU: Use the CPU for decoding, slowest but safest method.\n" "GPU: Use the GPU's compute shaders to decode ASTC textures, recommended for most " @@ -166,18 +222,24 @@ std::unique_ptr InitializeTranslations(QObject* parent) "eliminates ASTC decoding\nstuttering at the cost of rendering issues while the " "texture is being decoded.")); INSERT( - Settings, astc_recompression, tr("ASTC Recompression Method:"), + Settings, + astc_recompression, + tr("ASTC Recompression Method:"), tr("Almost all desktop and laptop dedicated GPUs lack support for ASTC textures, forcing " "the emulator to decompress to an intermediate format any card supports, RGBA8.\n" "This option recompresses RGBA8 to either the BC1 or BC3 format, saving VRAM but " "negatively affecting image quality.")); - INSERT(Settings, vram_usage_mode, tr("VRAM Usage Mode:"), + INSERT(Settings, + vram_usage_mode, + tr("VRAM Usage Mode:"), tr("Selects whether the emulator should prefer to conserve memory or make maximum usage " "of available video memory for performance. Has no effect on integrated graphics. " "Aggressive mode may severely impact the performance of other applications such as " "recording software.")); INSERT( - Settings, vsync_mode, tr("VSync Mode:"), + Settings, + vsync_mode, + tr("VSync Mode:"), tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen " "refresh rate.\nFIFO Relaxed is similar to FIFO but allows tearing as it recovers from " "a slow down.\nMailbox can have lower latency than FIFO and does not tear but may drop " @@ -188,81 +250,121 @@ std::unique_ptr InitializeTranslations(QObject* parent) INSERT(Settings, bg_blue, QString(), QString()); // Renderer (Advanced Graphics) - INSERT(Settings, async_presentation, tr("Enable asynchronous presentation (Vulkan only)"), + INSERT(Settings, + async_presentation, + tr("Enable asynchronous presentation (Vulkan only)"), tr("Slightly improves performance by moving presentation to a separate CPU thread.")); INSERT( - Settings, renderer_force_max_clock, tr("Force maximum clocks (Vulkan only)"), + Settings, + renderer_force_max_clock, + tr("Force maximum clocks (Vulkan only)"), tr("Runs work in the background while waiting for graphics commands to keep the GPU from " "lowering its clock speed.")); - INSERT(Settings, max_anisotropy, tr("Anisotropic Filtering:"), + INSERT(Settings, + max_anisotropy, + tr("Anisotropic Filtering:"), tr("Controls the quality of texture rendering at oblique angles.\nIt’s a light setting " "and safe to set at 16x on most GPUs.")); - INSERT(Settings, gpu_accuracy, tr("Accuracy Level:"), + INSERT(Settings, + gpu_accuracy, + tr("Accuracy Level:"), tr("GPU emulation accuracy.\nMost games render fine with Normal, but High is still " "required for some.\nParticles tend to only render correctly with High " "accuracy.\nExtreme should only be used for debugging.\nThis option can " "be changed while playing.\nSome games may require booting on high to render " "properly.")); - INSERT(Settings, use_asynchronous_shaders, tr("Use asynchronous shader building (Hack)"), + INSERT(Settings, + use_asynchronous_shaders, + tr("Use asynchronous shader building (Hack)"), tr("Enables asynchronous shader compilation, which may reduce shader stutter.\nThis " "feature " "is experimental.")); - INSERT(Settings, use_fast_gpu_time, tr("Use Fast GPU Time (Hack)"), - tr("Enables Fast GPU Time. This option will force most games to run at their highest " - "native resolution.")); - INSERT(Settings, use_vulkan_driver_pipeline_cache, tr("Use Vulkan pipeline cache"), + INSERT(Settings, use_fast_gpu_time, QString(), QString()); + INSERT(Settings, + fast_gpu_time, + tr("Fast GPU Time (Hack)"), + tr("Overclocks the emulated GPU to increase dynamic resolution and render " + "distance.\nUse 128 for maximal performance and 512 for maximal graphics fidelity.")); + + INSERT(Settings, + use_vulkan_driver_pipeline_cache, + tr("Use Vulkan pipeline cache"), tr("Enables GPU vendor-specific pipeline cache.\nThis option can improve shader loading " "time significantly in cases where the Vulkan driver does not store pipeline cache " "files internally.")); INSERT( - Settings, enable_compute_pipelines, tr("Enable Compute Pipelines (Intel Vulkan Only)"), + Settings, + enable_compute_pipelines, + tr("Enable Compute Pipelines (Intel Vulkan Only)"), tr("Enable compute pipelines, required by some games.\nThis setting only exists for Intel " "proprietary drivers, and may crash if enabled.\nCompute pipelines are always enabled " "on all other drivers.")); INSERT( - Settings, use_reactive_flushing, tr("Enable Reactive Flushing"), + Settings, + use_reactive_flushing, + tr("Enable Reactive Flushing"), tr("Uses reactive flushing instead of predictive flushing, allowing more accurate memory " "syncing.")); - INSERT(Settings, use_video_framerate, tr("Sync to framerate of video playback"), + INSERT(Settings, + use_video_framerate, + tr("Sync to framerate of video playback"), tr("Run the game at normal speed during video playback, even when the framerate is " "unlocked.")); - INSERT(Settings, barrier_feedback_loops, tr("Barrier feedback loops"), + INSERT(Settings, + barrier_feedback_loops, + tr("Barrier feedback loops"), tr("Improves rendering of transparency effects in specific games.")); // Renderer (Extensions) - INSERT(Settings, dyna_state, tr("Extended Dynamic State"), - tr("Enables the VkExtendedDynamicState* extensions.\nHigher dynamic states will generally improve " + INSERT(Settings, + dyna_state, + tr("Extended Dynamic State"), + tr("Enables the VkExtendedDynamicState* extensions.\nHigher dynamic states will " + "generally improve " "performance, but may cause issues on certain games or devices.")); - INSERT(Settings, provoking_vertex, tr("Provoking Vertex"), + INSERT(Settings, + provoking_vertex, + tr("Provoking Vertex"), tr("Improves lighting and vertex handling in certain games.\n" "Only Vulkan 1.0+ devices support this extension.")); - INSERT(Settings, descriptor_indexing, tr("Descriptor Indexing"), + INSERT(Settings, + descriptor_indexing, + tr("Descriptor Indexing"), tr("Improves texture & buffer handling and the Maxwell translation layer.\n" "Some Vulkan 1.1+ and all 1.2+ devices support this extension.")); // Renderer (Debug) // System - INSERT(Settings, rng_seed, tr("RNG Seed"), + INSERT(Settings, + rng_seed, + tr("RNG Seed"), tr("Controls the seed of the random number generator.\nMainly used for speedrunning " "purposes.")); INSERT(Settings, rng_seed_enabled, QString(), QString()); INSERT(Settings, device_name, tr("Device Name"), tr("The name of the emulated Switch.")); - INSERT(Settings, custom_rtc, tr("Custom RTC Date:"), + INSERT(Settings, + custom_rtc, + tr("Custom RTC Date:"), tr("This option allows to change the emulated clock of the Switch.\n" "Can be used to manipulate time in games.")); INSERT(Settings, custom_rtc_enabled, QString(), QString()); - INSERT(Settings, custom_rtc_offset, QStringLiteral(" "), + INSERT(Settings, + custom_rtc_offset, + QStringLiteral(" "), QStringLiteral("The number of seconds from the current unix time")); - INSERT(Settings, language_index, tr("Language:"), + INSERT(Settings, + language_index, + tr("Language:"), tr("Note: this can be overridden when region setting is auto-select")); INSERT(Settings, region_index, tr("Region:"), tr("The region of the emulated Switch.")); - INSERT(Settings, time_zone_index, tr("Time Zone:"), - tr("The time zone of the emulated Switch.")); + INSERT(Settings, time_zone_index, tr("Time Zone:"), tr("The time zone of the emulated Switch.")); INSERT(Settings, sound_index, tr("Sound Output Mode:"), QString()); - INSERT(Settings, use_docked_mode, tr("Console Mode:"), + INSERT(Settings, + use_docked_mode, + tr("Console Mode:"), tr("Selects if the console is emulated in Docked or Handheld mode.\nGames will change " "their resolution, details and supported controllers and depending on this setting.\n" "Setting to Handheld can help improve performance for low end systems.")); @@ -283,19 +385,33 @@ std::unique_ptr InitializeTranslations(QObject* parent) // Ui // Ui General - INSERT(UISettings, select_user_on_boot, tr("Prompt for user on game boot"), + INSERT(UISettings, + select_user_on_boot, + tr("Prompt for user on game boot"), tr("Ask to select a user profile on each boot, useful if multiple people use eden on " "the same PC.")); - INSERT(UISettings, pause_when_in_background, tr("Pause emulation when in background"), + INSERT(UISettings, + pause_when_in_background, + tr("Pause emulation when in background"), tr("This setting pauses eden when focusing other windows.")); - INSERT(UISettings, confirm_before_stopping, tr("Confirm before stopping emulation"), + INSERT(UISettings, + confirm_before_stopping, + tr("Confirm before stopping emulation"), tr("This setting overrides game prompts asking to confirm stopping the game.\nEnabling " "it bypasses such prompts and directly exits the emulation.")); - INSERT(UISettings, hide_mouse, tr("Hide mouse on inactivity"), + INSERT(UISettings, + hide_mouse, + tr("Hide mouse on inactivity"), tr("This setting hides the mouse after 2.5s of inactivity.")); - INSERT(UISettings, controller_applet_disabled, tr("Disable controller applet"), + INSERT(UISettings, + controller_applet_disabled, + tr("Disable controller applet"), tr("Forcibly disables the use of the controller applet by guests.\nWhen a guest " "attempts to open the controller applet, it is immediately closed.")); + INSERT(UISettings, + check_for_updates, + tr("Check for updates"), + tr("Whether or not to check for updates upon startup.")); // Linux INSERT(Settings, enable_gamemode, tr("Enable Gamemode"), QString()); @@ -305,10 +421,6 @@ std::unique_ptr InitializeTranslations(QObject* parent) // Ui Multiplayer // Ui Games list - INSERT(UISettings, - grid_columns, - tr("Grid View Columns"), - tr("Number of games to show per row in the grid view.")); #undef INSERT @@ -317,8 +429,7 @@ std::unique_ptr InitializeTranslations(QObject* parent) std::unique_ptr ComboboxEnumeration(QObject* parent) { - std::unique_ptr translations = - std::make_unique(); + std::unique_ptr translations = std::make_unique(); const auto& tr = [&](const char* text, const char* context = "") { return parent->tr(text, context); }; @@ -332,11 +443,11 @@ std::unique_ptr ComboboxEnumeration(QObject* parent) PAIR(AppletMode, LLE, tr("Real applet")), }}); translations->insert({Settings::EnumMetadata::Index(), - { - PAIR(SpirvOptimizeMode, Never, tr("Never")), - PAIR(SpirvOptimizeMode, OnLoad, tr("On Load")), - PAIR(SpirvOptimizeMode, Always, tr("Always")), - }}); + { + PAIR(SpirvOptimizeMode, Never, tr("Never")), + PAIR(SpirvOptimizeMode, OnLoad, tr("On Load")), + PAIR(SpirvOptimizeMode, Always, tr("Always")), + }}); translations->insert({Settings::EnumMetadata::Index(), { PAIR(AstcDecodeMode, Cpu, tr("CPU")), @@ -403,6 +514,7 @@ std::unique_ptr ComboboxEnumeration(QObject* parent) translations->insert( {Settings::EnumMetadata::Index(), { + PAIR(ResolutionSetup, Res1_4X, tr("0.25X (180p/270p) [EXPERIMENTAL]")), PAIR(ResolutionSetup, Res1_2X, tr("0.5X (360p/540p) [EXPERIMENTAL]")), PAIR(ResolutionSetup, Res3_4X, tr("0.75X (540p/810p) [EXPERIMENTAL]")), PAIR(ResolutionSetup, Res1X, tr("1X (720p/1080p)")), @@ -553,6 +665,11 @@ std::unique_ptr ComboboxEnumeration(QObject* parent) PAIR(ConsoleMode, Docked, tr("Docked")), PAIR(ConsoleMode, Handheld, tr("Handheld")), }}); + translations->insert({Settings::EnumMetadata::Index(), + { + PAIR(CpuClock, Boost, tr("Boost (1700MHz)")), + PAIR(CpuClock, Fast, tr("Fast (2000MHz)")), + }}); translations->insert( {Settings::EnumMetadata::Index(), { @@ -560,6 +677,12 @@ std::unique_ptr ComboboxEnumeration(QObject* parent) PAIR(ConfirmStop, Ask_Based_On_Game, tr("Only if game specifies not to stop")), PAIR(ConfirmStop, Ask_Never, tr("Never ask")), }}); + translations->insert({Settings::EnumMetadata::Index(), + { + PAIR(GpuOverclock, Low, tr("Low (128)")), + PAIR(GpuOverclock, Medium, tr("Medium (256)")), + PAIR(GpuOverclock, High, tr("High (512)")), + }}); #undef PAIR #undef CTX_PAIR diff --git a/src/eden/models/SettingsModel.cpp b/src/eden/models/SettingsModel.cpp index 6627ef2c72..a6a9d1bb62 100644 --- a/src/eden/models/SettingsModel.cpp +++ b/src/eden/models/SettingsModel.cpp @@ -47,9 +47,7 @@ bool SettingsModel::setData(const QModelIndex &index, const QVariant &value, int switch (role) { case VALUE: - qDebug() << "Before" << s->value(); s->setValue(value); - qDebug() << "After" << s->value(); break; } diff --git a/src/eden/qml/config/fields/BaseField.qml b/src/eden/qml/config/fields/BaseField.qml index 3d045a3b7b..dc9f22d92b 100644 --- a/src/eden/qml/config/fields/BaseField.qml +++ b/src/eden/qml/config/fields/BaseField.qml @@ -10,6 +10,7 @@ Item { property var setting property var value property bool showLabel: true + property bool forceCheckbox: false property alias enable: enable.checked property Item contentItem @@ -23,19 +24,19 @@ Item { function apply() { if (setting.value !== value) { - console.log(setting.label, "previous value:", setting.value, - "new value:", value) setting.value = value } } function sync() { - value = setting.value + if (value !== setting.value) { + value = setting.value + } } RowLayout { id: content - height: 45 * Constants.scalar + height: 50 * Constants.scalar spacing: 0 @@ -52,7 +53,7 @@ Item { icon.height: 20 onClicked: helpText.toggle() - visible: setting.tooltip !== "" + icon.color: setting.tooltip !== "" ? Constants.text : Constants.dialog z: 2 } @@ -60,6 +61,7 @@ Item { id: enable setting: field.setting z: 2 + force: field.forceCheckbox } RowLayout { diff --git a/src/eden/qml/config/fields/ConfigCheckbox.qml b/src/eden/qml/config/fields/ConfigCheckbox.qml index 846be6147d..e40d28833b 100644 --- a/src/eden/qml/config/fields/ConfigCheckbox.qml +++ b/src/eden/qml/config/fields/ConfigCheckbox.qml @@ -5,23 +5,23 @@ import QtQuick.Layouts import org.eden_emu.constants BaseField { - showLabel: false - // TODO: global/custom - contentItem: CheckBox { - id: control + forceCheckbox: true + // // TODO: global/custom + // contentItem: CheckBox { + // id: control - Layout.rightMargin: 10 * Constants.scalar - Layout.fillWidth: true + // Layout.rightMargin: 10 * Constants.scalar + // Layout.fillWidth: true - font.pixelSize: 15 * Constants.scalar - indicator.implicitHeight: 25 * Constants.scalar - indicator.implicitWidth: 25 * Constants.scalar + // font.pixelSize: 15 * Constants.scalar + // indicator.implicitHeight: 25 * Constants.scalar + // indicator.implicitWidth: 25 * Constants.scalar - text: setting.label - checked: setting.value + // text: setting.label + // checked: setting.value - onClicked: value = checked + // onClicked: value = checked - checkable: true - } + // checkable: true + // } } diff --git a/src/eden/qml/config/fields/FieldCheckbox.qml b/src/eden/qml/config/fields/FieldCheckbox.qml index f1bc4039e6..0e4e00d6a8 100644 --- a/src/eden/qml/config/fields/FieldCheckbox.qml +++ b/src/eden/qml/config/fields/FieldCheckbox.qml @@ -5,13 +5,16 @@ import QtQuick.Layouts import org.eden_emu.constants CheckBox { + property bool force: false property var setting + property var other: setting.other === null ? setting : setting.other indicator.implicitHeight: 25 * Constants.scalar indicator.implicitWidth: 25 * Constants.scalar - checked: setting.other !== null ? setting.other.value : true - onClicked: setting.other.value = checked + checked: visible ? other.value : true + onClicked: if (visible) + other.value = checked - visible: setting.other !== null + visible: setting.other !== null || force } From 97d648cac679546ee17c6c7ba48182d491d82f1a Mon Sep 17 00:00:00 2001 From: crueter Date: Tue, 17 Jun 2025 00:29:05 -0400 Subject: [PATCH 29/34] carousel/list view Signed-off-by: crueter --- src/eden/interface/qt_config.cpp | 26 ++--- src/eden/interface/uisettings.h | 24 +++-- src/eden/models/GameListModel.cpp | 3 - src/eden/qml/main/CMakeLists.txt | 7 +- src/eden/qml/main/GameCarousel.qml | 94 +++++++++++++++++++ src/eden/qml/main/GameGrid.qml | 44 +++++++++ .../{GamePreview.qml => GameGridCard.qml} | 0 src/eden/qml/main/GameList.qml | 68 ++++++-------- src/eden/qml/main/MarqueeText.qml | 43 +++++++++ 9 files changed, 244 insertions(+), 65 deletions(-) create mode 100644 src/eden/qml/main/GameCarousel.qml create mode 100644 src/eden/qml/main/GameGrid.qml rename src/eden/qml/main/{GamePreview.qml => GameGridCard.qml} (100%) create mode 100644 src/eden/qml/main/MarqueeText.qml diff --git a/src/eden/interface/qt_config.cpp b/src/eden/interface/qt_config.cpp index 5dcad01eb1..463bbc72a8 100644 --- a/src/eden/interface/qt_config.cpp +++ b/src/eden/interface/qt_config.cpp @@ -282,13 +282,13 @@ void QtConfig::ReadUIGamelistValues() { ReadCategory(Settings::Category::UiGameList); - const int favorites_size = BeginArray("favorites"); - for (int i = 0; i < favorites_size; i++) { - SetArrayIndex(i); - UISettings::values.favorited_ids.append( - ReadUnsignedIntegerSetting(std::string("program_id"))); - } - EndArray(); + // const int favorites_size = BeginArray("favorites"); + // for (int i = 0; i < favorites_size; i++) { + // SetArrayIndex(i); + // UISettings::values.favorited_ids.append( + // ReadUnsignedIntegerSetting(std::string("program_id"))); + // } + // EndArray(); EndGroup(); } @@ -490,12 +490,12 @@ void QtConfig::SaveUIGamelistValues() WriteCategory(Settings::Category::UiGameList); - BeginArray(std::string("favorites")); - for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) { - SetArrayIndex(i); - WriteIntegerSetting(std::string("program_id"), UISettings::values.favorited_ids[i]); - } - EndArray(); // favorites + // BeginArray(std::string("favorites")); + // for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) { + // SetArrayIndex(i); + // WriteIntegerSetting(std::string("program_id"), UISettings::values.favorited_ids[i]); + // } + // EndArray(); // favorites EndGroup(); } diff --git a/src/eden/interface/uisettings.h b/src/eden/interface/uisettings.h index b8ac6a1e11..aaedb99e8b 100644 --- a/src/eden/interface/uisettings.h +++ b/src/eden/interface/uisettings.h @@ -59,6 +59,12 @@ enum class Theme { MidnightBlueColorful, }; +enum class GameView { + Grid, + List, + Carousel, +}; + static constexpr Theme default_theme{ #ifdef _WIN32 Theme::DarkColorful @@ -192,15 +198,15 @@ struct Values { std::pair, std::vector> multiplayer_ban_list; // Game List - Setting show_add_ons{linkage, true, "show_add_ons", Category::UiGameList}; - Setting game_icon_size{linkage, 64, "game_icon_size", Category::UiGameList}; - Setting folder_icon_size{linkage, 48, "folder_icon_size", Category::UiGameList}; - Setting row_1_text_id{linkage, 3, "row_1_text_id", Category::UiGameList}; - Setting row_2_text_id{linkage, 2, "row_2_text_id", Category::UiGameList}; - std::atomic_bool is_game_list_reload_pending{false}; - Setting cache_game_list{linkage, true, "cache_game_list", Category::UiGameList}; - Setting favorites_expanded{linkage, true, "favorites_expanded", Category::UiGameList}; - QVector favorited_ids; + // Setting show_add_ons{linkage, true, "show_add_ons", Category::UiGameList}; + // Setting game_icon_size{linkage, 64, "game_icon_size", Category::UiGameList}; + // Setting folder_icon_size{linkage, 48, "folder_icon_size", Category::UiGameList}; + // Setting row_1_text_id{linkage, 3, "row_1_text_id", Category::UiGameList}; + // Setting row_2_text_id{linkage, 2, "row_2_text_id", Category::UiGameList}; + // std::atomic_bool is_game_list_reload_pending{false}; + // Setting cache_game_list{linkage, true, "cache_game_list", Category::UiGameList}; + // Setting favorites_expanded{linkage, true, "favorites_expanded", Category::UiGameList}; + // QVector favorited_ids; Setting grid_columns{linkage, 4, 1, 8, "grid_columns", Category::UiGameList}; diff --git a/src/eden/models/GameListModel.cpp b/src/eden/models/GameListModel.cpp index e20717970b..61c51ac08f 100644 --- a/src/eden/models/GameListModel.cpp +++ b/src/eden/models/GameListModel.cpp @@ -56,9 +56,6 @@ void GameListModel::reload() qreal size = entry.size(); QString sizeString = QLocale::system().formattedDataSize(size); - qDebug() << path << name << size; - // m_data << Game{path, name, size}; - QStandardItem *game = new QStandardItem(name); game->setData(path, GLMRoleTypes::PATH); game->setData(sizeString, GLMRoleTypes::FILESIZE); diff --git a/src/eden/qml/main/CMakeLists.txt b/src/eden/qml/main/CMakeLists.txt index c2a9e6eed8..c0441d539d 100644 --- a/src/eden/qml/main/CMakeLists.txt +++ b/src/eden/qml/main/CMakeLists.txt @@ -9,5 +9,10 @@ qt_add_qml_module(edenMain Main.qml StatusBar.qml GameList.qml - GamePreview.qml + GameGridCard.qml + MarqueeText.qml + GameGrid.qml + + GameCarouselCard.qml + GameCarousel.qml ) diff --git a/src/eden/qml/main/GameCarousel.qml b/src/eden/qml/main/GameCarousel.qml new file mode 100644 index 0000000000..7989d46d71 --- /dev/null +++ b/src/eden/qml/main/GameCarousel.qml @@ -0,0 +1,94 @@ +import QtQuick +import QtQuick.Controls +import Qt.labs.platform +import QtCore + +import org.eden_emu.constants +import org.eden_emu.interface + +ListView { + id: carousel + + focus: true + focusPolicy: Qt.StrongFocus + + model: EdenGameList + orientation: ListView.Horizontal + clip: false + flickDeceleration: 1000 + snapMode: ListView.SnapToItem + + onHeightChanged: console.log(width, height) + + spacing: 20 + + Keys.enabled: true + Keys.onRightPressed: incrementCurrentIndex() + Keys.onLeftPressed: decrementCurrentIndex() + + onCurrentIndexChanged: scrollToCenter() + + highlight: Rectangle { + id: hg + clip: false + z: 3 + + color: "transparent" + border { + color: "deepskyblue" + width: 4 * Constants.scalar + } + + radius: 8 * Constants.scalar + + // TODO: marquee + Text { + function toTitleCase(str) { + return str.replace(/\w\S*/g, text => text.charAt(0).toUpperCase( + ) + text.substring(1).toLowerCase()) + } + + property var item: carousel.currentItem + + text: toTitleCase(item.title) + font.pixelSize: 22 * Constants.scalar + color: "lightblue" + + anchors { + bottom: hg.top + + bottomMargin: 10 * Constants.scalar + left: hg.left + right: hg.right + } + + horizontalAlignment: Text.AlignHCenter + elide: Text.ElideRight + } + } + + highlightFollowsCurrentItem: true + highlightMoveDuration: 300 + highlightMoveVelocity: -1 + + delegate: GameCarouselCard { + id: game + width: 300 + height: 300 + } + + function scrollToCenter() { + let targetX = currentIndex * 320 - (width - 320) / 2 + let min = 0 + let max = contentWidth + + contentX = Math.max(min, Math.min(max, targetX)) + } + + Behavior on contentX { + NumberAnimation { + duration: 300 + easing.type: Easing.OutQuad + } + } +} diff --git a/src/eden/qml/main/GameGrid.qml b/src/eden/qml/main/GameGrid.qml new file mode 100644 index 0000000000..8094ae4cdd --- /dev/null +++ b/src/eden/qml/main/GameGrid.qml @@ -0,0 +1,44 @@ +import QtQuick +import QtQuick.Controls +import Qt.labs.platform +import QtCore + +import org.eden_emu.constants +import org.eden_emu.interface +import org.eden_emu.gamepad + +GridView { + property var setting + id: grid + + property int cellSize: Math.floor(width / setting.value) + + highlightFollowsCurrentItem: true + clip: true + + cellWidth: cellSize + cellHeight: cellSize + 60 * Constants.scalar + + model: EdenGameList + + delegate: GameGridCard { + id: game + + width: grid.cellSize - 20 * Constants.scalar + height: grid.cellHeight - 20 * Constants.scalar + } + + highlight: Rectangle { + color: "transparent" + z: 5 + + radius: 16 * Constants.scalar + border { + color: Constants.text + width: 3 + } + } + + focus: true + focusPolicy: "StrongFocus" +} diff --git a/src/eden/qml/main/GamePreview.qml b/src/eden/qml/main/GameGridCard.qml similarity index 100% rename from src/eden/qml/main/GamePreview.qml rename to src/eden/qml/main/GameGridCard.qml diff --git a/src/eden/qml/main/GameList.qml b/src/eden/qml/main/GameList.qml index 1540452774..81937d1f87 100644 --- a/src/eden/qml/main/GameList.qml +++ b/src/eden/qml/main/GameList.qml @@ -20,15 +20,16 @@ Rectangle { color: Constants.bg - // TODO: make this optional. - // Probably just make a Gamepad frontend/backend split with a null backend + // TODO: use the original yuzu backend for dis Gamepad { id: gamepad - onUpPressed: grid.moveCurrentIndexUp() - onDownPressed: grid.moveCurrentIndexDown() - onLeftPressed: grid.moveCurrentIndexLeft() - onRightPressed: grid.moveCurrentIndexRight() + // onUpPressed: grid.moveCurrentIndexUp() + // onDownPressed: grid.moveCurrentIndexDown() + // onLeftPressed: grid.moveCurrentIndexLeft() + // onRightPressed: grid.moveCurrentIndexRight() + onLeftPressed: carousel.decrementCurrentIndex() + onRightPressed: carousel.incrementCurrentIndex() onAPressed: console.log("A pressed") onLeftStickMoved: (x, y) => { gx = x @@ -54,67 +55,56 @@ Rectangle { } } } - Timer { interval: 16 running: true repeat: true onTriggered: gamepad.pollEvents() } - FolderDialog { id: openDir folder: StandardPaths.writableLocation(StandardPaths.HomeLocation) onAccepted: { button.visible = false - grid.anchors.bottom = root.bottom + view.anchors.bottom = root.bottom EdenGameList.addDir(folder) } } - GridView { - id: grid + // GameGrid { + // setting: parent.setting - property int cellSize: Math.floor(width / setting.value) + // id: grid - highlightFollowsCurrentItem: true - clip: true - - cellWidth: cellSize - cellHeight: cellSize + 60 * Constants.scalar + // anchors.bottom: button.top + // anchors.left: parent.left + // anchors.margins: 8 + // anchors.right: parent.right + // anchors.top: parent.top + // } + Item { + id: view anchors { - top: parent.top + bottom: button.top left: parent.left right: parent.right - - bottom: button.top - - margins: 8 + top: parent.top + margins: 8 * Constants.scalar } - model: EdenGameList + GameCarousel { + id: carousel - delegate: GamePreview { - id: game + height: 300 - width: grid.cellSize - 20 * Constants.scalar - height: grid.cellHeight - 20 * Constants.scalar - } + anchors { + right: view.right + left: view.left - highlight: Rectangle { - color: "transparent" - z: 5 - - radius: 16 * Constants.scalar - border { - color: Constants.text - width: 3 + verticalCenter: view.verticalCenter } } - - focus: true - focusPolicy: "StrongFocus" } Button { diff --git a/src/eden/qml/main/MarqueeText.qml b/src/eden/qml/main/MarqueeText.qml new file mode 100644 index 0000000000..7a70c53141 --- /dev/null +++ b/src/eden/qml/main/MarqueeText.qml @@ -0,0 +1,43 @@ +import QtQuick + +Item { + required property string text + + property int spacing: 30 + property int startDelay: 2000 + property int speed: 40 + + property alias font: t1.font + property alias color: t1.color + + id: root + + width: t1.width + spacing + height: t1.height + clip: true + + Text { + id: t1 + + SequentialAnimation on x { + loops: Animation.Infinite + running: true + + PauseAnimation { + duration: root.startDelay + } + + NumberAnimation { + from: root.width + to: -t1.width + duration: (root.width + t1.width) * 1000 / root.speed + easing.type: Easing.Linear + } + } + + Text { + x: root.width + text: t1.text + } + } +} From 783afb54e7176445de9323f5e0dfa84ea8c309ff Mon Sep 17 00:00:00 2001 From: crueter Date: Mon, 21 Jul 2025 18:43:44 -0400 Subject: [PATCH 30/34] Oops Signed-off-by: crueter --- src/eden/qml/main/GameCarouselCard.qml | 39 ++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/eden/qml/main/GameCarouselCard.qml diff --git a/src/eden/qml/main/GameCarouselCard.qml b/src/eden/qml/main/GameCarouselCard.qml new file mode 100644 index 0000000000..7e7514f7ec --- /dev/null +++ b/src/eden/qml/main/GameCarouselCard.qml @@ -0,0 +1,39 @@ +import QtQuick +import QtQuick.Controls +import Qt.labs.platform +import QtCore + +import org.eden_emu.constants + +Item { + property string title: model.name.replace(/-/g, " ") + + id: wrapper + + width: 300 + height: 300 + + Rectangle { + anchors.fill: parent + color: "transparent" + border { + width: 4 * Constants.scalar + color: PathView.isCurrentItem ? "deepskyblue" : "transparent" + } + + Image { + id: image + + fillMode: Image.PreserveAspectFit + source: "file://" + model.path + + clip: true + + anchors { + fill: parent + + margins: 10 * Constants.scalar + } + } + } +} From 06fe470e5cee762bdebe1345926d8781f75efb21 Mon Sep 17 00:00:00 2001 From: crueter Date: Thu, 7 Aug 2025 20:50:09 -0400 Subject: [PATCH 31/34] fix Signed-off-by: crueter --- src/qt_common/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index 9d292da401..615ec77d84 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -30,6 +30,10 @@ add_library(qt_common STATIC ) +# Extra deps +add_subdirectory(externals) +target_link_libraries(qt_common PUBLIC QuaZip::QuaZip) + create_target_directory_groups(qt_common) # TODO(crueter) From 0793e85b47db9edf83f05a57376ad8048e19e9a1 Mon Sep 17 00:00:00 2001 From: crueter Date: Thu, 7 Aug 2025 21:47:08 -0400 Subject: [PATCH 32/34] proper cmake uris, fix game carousel Signed-off-by: crueter --- src/eden/CMakeLists.txt | 76 +- src/eden/Eden/CMakeLists.txt | 9 + .../config => Eden/Config}/CMakeLists.txt | 6 +- .../Config}/GlobalConfigureDialog.qml | 8 +- .../config => Eden/Config}/SectionHeader.qml | 2 +- .../{qml/config => Eden/Config}/Setting.qml | 2 +- .../config => Eden/Config}/TestSetting.qml | 2 +- .../Config}/fields/BaseField.qml | 6 +- .../Config}/fields/ConfigCheckbox.qml | 2 +- .../Config}/fields/ConfigComboBox.qml | 4 +- .../Config}/fields/ConfigHexEdit.qml | 6 +- .../Config}/fields/ConfigIntLine.qml | 6 +- .../Config}/fields/ConfigIntSlider.qml | 6 +- .../Config}/fields/ConfigIntSpin.qml | 6 +- .../Config}/fields/ConfigStringEdit.qml | 6 +- .../Config}/fields/ConfigTimeEdit.qml | 6 +- .../Config}/fields/FieldCheckbox.qml | 2 +- .../Config}/fields/FieldLabel.qml | 2 +- .../{qml/config => Eden/Config}/icons.qrc | 0 .../Config}/pages/SettingsList.qml | 6 +- .../Config}/pages/audio/AudioGeneralPage.qml | 4 +- .../Config}/pages/cpu/CpuGeneralPage.qml | 4 +- .../Config}/pages/debug/DebugAdvancedPage.qml | 4 +- .../Config}/pages/debug/DebugCpuPage.qml | 4 +- .../Config}/pages/debug/DebugGeneralPage.qml | 4 +- .../Config}/pages/debug/DebugGraphicsPage.qml | 4 +- .../Config}/pages/general/UiGameListPage.qml | 4 +- .../Config}/pages/general/UiGeneralPage.qml | 4 +- .../Config}/pages/global/GlobalAudioPage.qml | 2 +- .../Config}/pages/global/GlobalCpuPage.qml | 2 +- .../Config}/pages/global/GlobalDebugPage.qml | 2 +- .../pages/global/GlobalGeneralPage.qml | 2 +- .../pages/global/GlobalGraphicsPage.qml | 2 +- .../Config}/pages/global/GlobalSystemPage.qml | 2 +- .../Config}/pages/global/GlobalTab.qml | 2 +- .../pages/global/GlobalTabSwipeView.qml | 2 +- .../pages/graphics/RendererAdvancedPage.qml | 4 +- .../pages/graphics/RendererExtensionsPage.qml | 4 +- .../Config}/pages/graphics/RendererPage.qml | 4 +- .../Config}/pages/system/AppletsPage.qml | 4 +- .../Config}/pages/system/FileSystemPage.qml | 4 +- .../Config}/pages/system/SystemCorePage.qml | 4 +- .../pages/system/SystemGeneralPage.qml | 4 +- .../Constants}/CMakeLists.txt | 8 +- .../Constants}/Constants.qml | 0 .../items => Eden/Items}/AnimatedDialog.qml | 2 +- .../{qml/items => Eden/Items}/BetterMenu.qml | 2 +- .../items => Eden/Items}/BetterMenuBar.qml | 2 +- .../{qml/items => Eden/Items}/CMakeLists.txt | 6 +- .../{qml/items => Eden/Items}/IconButton.qml | 2 +- .../Items}/SettingsTabButton.qml | 2 +- .../items => Eden/Items}/StatusBarButton.qml | 2 +- .../items => Eden/Items}/VerticalTabBar.qml | 2 +- .../Items}/fields/BetterSpinBox.qml | 2 +- .../Items}/fields/BetterTextField.qml | 4 +- .../Items}/fields/FieldFooter.qml | 2 +- .../{qml/main => Eden/Main}/CMakeLists.txt | 6 +- .../{qml/main => Eden/Main}/GameCarousel.qml | 60 +- .../main => Eden/Main}/GameCarouselCard.qml | 2 +- src/eden/{qml/main => Eden/Main}/GameGrid.qml | 6 +- .../{qml/main => Eden/Main}/GameGridCard.qml | 2 +- src/eden/{qml/main => Eden/Main}/GameList.qml | 28 +- src/eden/{qml/main => Eden/Main}/Main.qml | 6 +- .../{qml/main => Eden/Main}/MarqueeText.qml | 0 .../{qml/main => Eden/Main}/StatusBar.qml | 4 +- src/eden/Eden/Native/CMakeLists.txt | 71 ++ .../Native/Gamepad}/CMakeLists.txt | 2 +- .../Native/Gamepad}/gamepad.cpp | 1 + .../Native/Gamepad}/gamepad.h | 0 src/eden/Eden/Native/Interface/CMakeLists.txt | 11 + .../Native/Interface}/MetaObjectHelper.h | 0 .../Native/Interface}/QMLConfig.h | 2 +- .../Native/Interface}/QMLSetting.cpp | 0 .../Native/Interface}/QMLSetting.h | 0 .../Native/Interface}/SettingsInterface.cpp | 2 +- .../Native/Interface}/SettingsInterface.h | 6 +- .../Native/Models}/CMakeLists.txt | 8 +- .../Native/Models}/GameListModel.cpp | 0 .../Native/Models}/GameListModel.h | 0 .../Native/Models}/SettingsModel.cpp | 0 .../Native/Models}/SettingsModel.h | 2 +- src/eden/{ => Eden/Native}/icons.qrc | 0 src/eden/{ => Eden/Native}/icons/audio.svg | 0 src/eden/{ => Eden/Native}/icons/back.svg | 0 src/eden/{ => Eden/Native}/icons/controls.svg | 0 src/eden/{ => Eden/Native}/icons/cpu.svg | 0 src/eden/{ => Eden/Native}/icons/debug.svg | 0 src/eden/{ => Eden/Native}/icons/forward.svg | 0 src/eden/{ => Eden/Native}/icons/general.svg | 0 src/eden/{ => Eden/Native}/icons/graphics.svg | 0 src/eden/{ => Eden/Native}/icons/help.svg | 0 src/eden/{ => Eden/Native}/icons/system.svg | 0 src/eden/{ => Eden/Native}/main.cpp | 10 +- .../{qml/util => Eden/Util}/CMakeLists.txt | 8 +- src/eden/{qml/util => Eden/Util}/Util.qml | 0 src/eden/interface/CMakeLists.txt | 14 - src/eden/interface/qt_config.cpp | 562 -------------- src/eden/interface/qt_config.h | 55 -- src/eden/interface/shared_translation.cpp | 692 ------------------ src/eden/interface/shared_translation.h | 65 -- src/eden/interface/uisettings.cpp | 112 --- src/eden/interface/uisettings.h | 288 -------- src/eden/qml/CMakeLists.txt | 6 - src/qt_common/CMakeLists.txt | 1 - src/qt_common/uisettings.h | 2 + 105 files changed, 266 insertions(+), 2043 deletions(-) create mode 100644 src/eden/Eden/CMakeLists.txt rename src/eden/{qml/config => Eden/Config}/CMakeLists.txt (95%) rename src/eden/{qml/config => Eden/Config}/GlobalConfigureDialog.qml (93%) rename src/eden/{qml/config => Eden/Config}/SectionHeader.qml (71%) rename src/eden/{qml/config => Eden/Config}/Setting.qml (98%) rename src/eden/{qml/config => Eden/Config}/TestSetting.qml (96%) rename src/eden/{qml/config => Eden/Config}/fields/BaseField.qml (97%) rename src/eden/{qml/config => Eden/Config}/fields/ConfigCheckbox.qml (95%) rename src/eden/{qml/config => Eden/Config}/fields/ConfigComboBox.qml (94%) rename src/eden/{qml/config => Eden/Config}/fields/ConfigHexEdit.qml (85%) rename src/eden/{qml/config => Eden/Config}/fields/ConfigIntLine.qml (85%) rename src/eden/{qml/config => Eden/Config}/fields/ConfigIntSlider.qml (89%) rename src/eden/{qml/config => Eden/Config}/fields/ConfigIntSpin.qml (83%) rename src/eden/{qml/config => Eden/Config}/fields/ConfigStringEdit.qml (80%) rename src/eden/{qml/config => Eden/Config}/fields/ConfigTimeEdit.qml (85%) rename src/eden/{qml/config => Eden/Config}/fields/FieldCheckbox.qml (93%) rename src/eden/{qml/config => Eden/Config}/fields/FieldLabel.qml (90%) rename src/eden/{qml/config => Eden/Config}/icons.qrc (100%) rename src/eden/{qml/config => Eden/Config}/pages/SettingsList.qml (91%) rename src/eden/{qml/config => Eden/Config}/pages/audio/AudioGeneralPage.qml (82%) rename src/eden/{qml/config => Eden/Config}/pages/cpu/CpuGeneralPage.qml (82%) rename src/eden/{qml/config => Eden/Config}/pages/debug/DebugAdvancedPage.qml (83%) rename src/eden/{qml/config => Eden/Config}/pages/debug/DebugCpuPage.qml (82%) rename src/eden/{qml/config => Eden/Config}/pages/debug/DebugGeneralPage.qml (90%) rename src/eden/{qml/config => Eden/Config}/pages/debug/DebugGraphicsPage.qml (84%) rename src/eden/{qml/config => Eden/Config}/pages/general/UiGameListPage.qml (84%) rename src/eden/{qml/config => Eden/Config}/pages/general/UiGeneralPage.qml (89%) rename src/eden/{qml/config => Eden/Config}/pages/global/GlobalAudioPage.qml (88%) rename src/eden/{qml/config => Eden/Config}/pages/global/GlobalCpuPage.qml (88%) rename src/eden/{qml/config => Eden/Config}/pages/global/GlobalDebugPage.qml (92%) rename src/eden/{qml/config => Eden/Config}/pages/global/GlobalGeneralPage.qml (91%) rename src/eden/{qml/config => Eden/Config}/pages/global/GlobalGraphicsPage.qml (91%) rename src/eden/{qml/config => Eden/Config}/pages/global/GlobalSystemPage.qml (92%) rename src/eden/{qml/config => Eden/Config}/pages/global/GlobalTab.qml (95%) rename src/eden/{qml/config => Eden/Config}/pages/global/GlobalTabSwipeView.qml (90%) rename src/eden/{qml/config => Eden/Config}/pages/graphics/RendererAdvancedPage.qml (83%) rename src/eden/{qml/config => Eden/Config}/pages/graphics/RendererExtensionsPage.qml (83%) rename src/eden/{qml/config => Eden/Config}/pages/graphics/RendererPage.qml (82%) rename src/eden/{qml/config => Eden/Config}/pages/system/AppletsPage.qml (82%) rename src/eden/{qml/config => Eden/Config}/pages/system/FileSystemPage.qml (82%) rename src/eden/{qml/config => Eden/Config}/pages/system/SystemCorePage.qml (82%) rename src/eden/{qml/config => Eden/Config}/pages/system/SystemGeneralPage.qml (88%) rename src/eden/{qml/constants => Eden/Constants}/CMakeLists.txt (66%) rename src/eden/{qml/constants => Eden/Constants}/Constants.qml (100%) rename src/eden/{qml/items => Eden/Items}/AnimatedDialog.qml (98%) rename src/eden/{qml/items => Eden/Items}/BetterMenu.qml (98%) rename src/eden/{qml/items => Eden/Items}/BetterMenuBar.qml (95%) rename src/eden/{qml/items => Eden/Items}/CMakeLists.txt (80%) rename src/eden/{qml/items => Eden/Items}/IconButton.qml (93%) rename src/eden/{qml/items => Eden/Items}/SettingsTabButton.qml (96%) rename src/eden/{qml/items => Eden/Items}/StatusBarButton.qml (95%) rename src/eden/{qml/items => Eden/Items}/VerticalTabBar.qml (97%) rename src/eden/{qml/items => Eden/Items}/fields/BetterSpinBox.qml (97%) rename src/eden/{qml/items => Eden/Items}/fields/BetterTextField.qml (92%) rename src/eden/{qml/items => Eden/Items}/fields/FieldFooter.qml (92%) rename src/eden/{qml/main => Eden/Main}/CMakeLists.txt (71%) rename src/eden/{qml/main => Eden/Main}/GameCarousel.qml (57%) rename src/eden/{qml/main => Eden/Main}/GameCarouselCard.qml (95%) rename src/eden/{qml/main => Eden/Main}/GameGrid.qml (89%) rename src/eden/{qml/main => Eden/Main}/GameGridCard.qml (98%) rename src/eden/{qml/main => Eden/Main}/GameList.qml (85%) rename src/eden/{qml/main => Eden/Main}/Main.qml (98%) rename src/eden/{qml/main => Eden/Main}/MarqueeText.qml (100%) rename src/eden/{qml/main => Eden/Main}/StatusBar.qml (98%) create mode 100644 src/eden/Eden/Native/CMakeLists.txt rename src/eden/{gamepad => Eden/Native/Gamepad}/CMakeLists.txt (82%) rename src/eden/{gamepad => Eden/Native/Gamepad}/gamepad.cpp (98%) rename src/eden/{gamepad => Eden/Native/Gamepad}/gamepad.h (100%) create mode 100644 src/eden/Eden/Native/Interface/CMakeLists.txt rename src/eden/{interface => Eden/Native/Interface}/MetaObjectHelper.h (100%) rename src/eden/{interface => Eden/Native/Interface}/QMLConfig.h (91%) rename src/eden/{interface => Eden/Native/Interface}/QMLSetting.cpp (100%) rename src/eden/{interface => Eden/Native/Interface}/QMLSetting.h (100%) rename src/eden/{interface => Eden/Native/Interface}/SettingsInterface.cpp (99%) rename src/eden/{interface => Eden/Native/Interface}/SettingsInterface.h (96%) rename src/eden/{models => Eden/Native/Models}/CMakeLists.txt (62%) rename src/eden/{models => Eden/Native/Models}/GameListModel.cpp (100%) rename src/eden/{models => Eden/Native/Models}/GameListModel.h (100%) rename src/eden/{models => Eden/Native/Models}/SettingsModel.cpp (100%) rename src/eden/{models => Eden/Native/Models}/SettingsModel.h (95%) rename src/eden/{ => Eden/Native}/icons.qrc (100%) rename src/eden/{ => Eden/Native}/icons/audio.svg (100%) rename src/eden/{ => Eden/Native}/icons/back.svg (100%) rename src/eden/{ => Eden/Native}/icons/controls.svg (100%) rename src/eden/{ => Eden/Native}/icons/cpu.svg (100%) rename src/eden/{ => Eden/Native}/icons/debug.svg (100%) rename src/eden/{ => Eden/Native}/icons/forward.svg (100%) rename src/eden/{ => Eden/Native}/icons/general.svg (100%) rename src/eden/{ => Eden/Native}/icons/graphics.svg (100%) rename src/eden/{ => Eden/Native}/icons/help.svg (100%) rename src/eden/{ => Eden/Native}/icons/system.svg (100%) rename src/eden/{ => Eden/Native}/main.cpp (85%) rename src/eden/{qml/util => Eden/Util}/CMakeLists.txt (69%) rename src/eden/{qml/util => Eden/Util}/Util.qml (100%) delete mode 100644 src/eden/interface/CMakeLists.txt delete mode 100644 src/eden/interface/qt_config.cpp delete mode 100644 src/eden/interface/qt_config.h delete mode 100644 src/eden/interface/shared_translation.cpp delete mode 100644 src/eden/interface/shared_translation.h delete mode 100644 src/eden/interface/uisettings.cpp delete mode 100644 src/eden/interface/uisettings.h delete mode 100644 src/eden/qml/CMakeLists.txt diff --git a/src/eden/CMakeLists.txt b/src/eden/CMakeLists.txt index 50d9b30db7..329b07bae7 100644 --- a/src/eden/CMakeLists.txt +++ b/src/eden/CMakeLists.txt @@ -6,78 +6,4 @@ find_package(Qt6 REQUIRED COMPONENTS Widgets Core Gui Quick QuickControls2) qt_standard_project_setup(REQUIRES 6.7) -qt_add_executable(yuzu - main.cpp - icons.qrc -) - -add_subdirectory(qml) -add_subdirectory(interface) -add_subdirectory(models) - -set(PLUGINS - edenMainplugin - edenItemsplugin - edenConfigplugin - edenInterfaceplugin - edenConstantsplugin - edenUtilplugin -) - -if (ENABLE_SDL2) - add_subdirectory(gamepad) - set(PLUGINS ${PLUGINS} edenGamepadplugin) -endif() - -target_link_libraries(yuzu - PRIVATE - Qt6::Core - Qt6::Widgets - Qt6::Gui - Qt6::Quick - Qt6::QuickControls2 - edenModels - - # Explicitly link to static plugins - ${PLUGINS} -) - -set(NATIVE_MODULES yuzu edenInterface) - -foreach(MODULE ${NATIVE_MODULES}) - target_link_libraries(${MODULE} PRIVATE common core input_common frontend_common network video_core) - target_link_libraries(${MODULE} PRIVATE Boost::headers glad fmt) - target_link_libraries(${MODULE} PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) - - target_link_libraries(${MODULE} PRIVATE Vulkan::Headers) - - if (NOT WIN32) - target_include_directories(${MODULE} PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) - endif() - if (UNIX AND NOT APPLE) - target_link_libraries(${MODULE} PRIVATE Qt6::DBus) - endif() - - target_compile_definitions(${MODULE} PRIVATE - # Use QStringBuilder for string concatenation to reduce - # the overall number of temporary strings created. - -DQT_USE_QSTRINGBUILDER - - # Disable implicit type narrowing in signal/slot connect() calls. - -DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT - - # Disable unsafe overloads of QProcess' start() function. - -DQT_NO_PROCESS_COMBINED_ARGUMENT_START - - # Disable implicit QString->QUrl conversions to enforce use of proper resolving functions. - -DQT_NO_URL_CAST_FROM_STRING - ) -endforeach() - -set_target_properties(yuzu PROPERTIES OUTPUT_NAME "eden") -include(GNUInstallDirs) -install(TARGETS yuzu - BUNDLE DESTINATION . - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} -) +add_subdirectory(Eden) diff --git a/src/eden/Eden/CMakeLists.txt b/src/eden/Eden/CMakeLists.txt new file mode 100644 index 0000000000..c3904c36d0 --- /dev/null +++ b/src/eden/Eden/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories(AFTER "${CMAKE_CURRENT_SOURCE_DIR}") + +add_subdirectory(Config) +add_subdirectory(Constants) +add_subdirectory(Items) +add_subdirectory(Util) +add_subdirectory(Main) + +add_subdirectory(Native) diff --git a/src/eden/qml/config/CMakeLists.txt b/src/eden/Eden/Config/CMakeLists.txt similarity index 95% rename from src/eden/qml/config/CMakeLists.txt rename to src/eden/Eden/Config/CMakeLists.txt index 94b0bf7a0e..d5aefc012b 100644 --- a/src/eden/qml/config/CMakeLists.txt +++ b/src/eden/Eden/Config/CMakeLists.txt @@ -1,8 +1,8 @@ set(CMAKE_AUTOMOC ON) -qt_add_library(edenConfig STATIC) -qt_add_qml_module(edenConfig - URI org.eden_emu.config +qt_add_library(EdenConfig STATIC) +qt_add_qml_module(EdenConfig + URI Eden.Config VERSION 1.0 QML_FILES GlobalConfigureDialog.qml diff --git a/src/eden/qml/config/GlobalConfigureDialog.qml b/src/eden/Eden/Config/GlobalConfigureDialog.qml similarity index 93% rename from src/eden/qml/config/GlobalConfigureDialog.qml rename to src/eden/Eden/Config/GlobalConfigureDialog.qml index 50d81a5469..3d4ad2c955 100644 --- a/src/eden/qml/config/GlobalConfigureDialog.qml +++ b/src/eden/Eden/Config/GlobalConfigureDialog.qml @@ -2,10 +2,10 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import org.eden_emu.constants -import org.eden_emu.items -import org.eden_emu.interface -import org.eden_emu.util +import Eden.Constants +import Eden.Items +import Eden.Native.Interface +import Eden.Util AnimatedDialog { property list configs diff --git a/src/eden/qml/config/SectionHeader.qml b/src/eden/Eden/Config/SectionHeader.qml similarity index 71% rename from src/eden/qml/config/SectionHeader.qml rename to src/eden/Eden/Config/SectionHeader.qml index 2a69504bd2..47da4fb070 100644 --- a/src/eden/qml/config/SectionHeader.qml +++ b/src/eden/Eden/Config/SectionHeader.qml @@ -1,6 +1,6 @@ import QtQuick -import org.eden_emu.constants +import Eden.Constants Text { color: Constants.text diff --git a/src/eden/qml/config/Setting.qml b/src/eden/Eden/Config/Setting.qml similarity index 98% rename from src/eden/qml/config/Setting.qml rename to src/eden/Eden/Config/Setting.qml index 5da913689c..8f2518c7e9 100644 --- a/src/eden/qml/config/Setting.qml +++ b/src/eden/Eden/Config/Setting.qml @@ -2,7 +2,7 @@ import QtQuick import Qt.labs.qmlmodels -import org.eden_emu.config +import Eden.Config // TODO: make settings independently available (model vs setting? DelegateChooser { diff --git a/src/eden/qml/config/TestSetting.qml b/src/eden/Eden/Config/TestSetting.qml similarity index 96% rename from src/eden/qml/config/TestSetting.qml rename to src/eden/Eden/Config/TestSetting.qml index e8d6e36d50..9029f8dc4b 100644 --- a/src/eden/qml/config/TestSetting.qml +++ b/src/eden/Eden/Config/TestSetting.qml @@ -1,7 +1,7 @@ import QtQuick import QtQuick.Layouts -import org.eden_emu.constants +import Eden.Constants Column { topPadding: 5 * Constants.scalar diff --git a/src/eden/qml/config/fields/BaseField.qml b/src/eden/Eden/Config/fields/BaseField.qml similarity index 97% rename from src/eden/qml/config/fields/BaseField.qml rename to src/eden/Eden/Config/fields/BaseField.qml index dc9f22d92b..23973e29d9 100644 --- a/src/eden/qml/config/fields/BaseField.qml +++ b/src/eden/Eden/Config/fields/BaseField.qml @@ -1,9 +1,9 @@ import QtQuick import QtQuick.Layouts -import org.eden_emu.items -import org.eden_emu.config -import org.eden_emu.constants +import Eden.Items +import Eden.Config +import Eden.Constants Item { id: field diff --git a/src/eden/qml/config/fields/ConfigCheckbox.qml b/src/eden/Eden/Config/fields/ConfigCheckbox.qml similarity index 95% rename from src/eden/qml/config/fields/ConfigCheckbox.qml rename to src/eden/Eden/Config/fields/ConfigCheckbox.qml index e40d28833b..8b41ae5b8a 100644 --- a/src/eden/qml/config/fields/ConfigCheckbox.qml +++ b/src/eden/Eden/Config/fields/ConfigCheckbox.qml @@ -2,7 +2,7 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import org.eden_emu.constants +import Eden.Constants BaseField { forceCheckbox: true diff --git a/src/eden/qml/config/fields/ConfigComboBox.qml b/src/eden/Eden/Config/fields/ConfigComboBox.qml similarity index 94% rename from src/eden/qml/config/fields/ConfigComboBox.qml rename to src/eden/Eden/Config/fields/ConfigComboBox.qml index c4762813b7..bf555d279a 100644 --- a/src/eden/qml/config/fields/ConfigComboBox.qml +++ b/src/eden/Eden/Config/fields/ConfigComboBox.qml @@ -3,8 +3,8 @@ import QtQuick.Controls.Material import QtQuick.Layouts import QtQuick.Controls.Material.impl -import org.eden_emu.constants -import org.eden_emu.config +import Eden.Constants +import Eden.Config BaseField { contentItem: ComboBox { diff --git a/src/eden/qml/config/fields/ConfigHexEdit.qml b/src/eden/Eden/Config/fields/ConfigHexEdit.qml similarity index 85% rename from src/eden/qml/config/fields/ConfigHexEdit.qml rename to src/eden/Eden/Config/fields/ConfigHexEdit.qml index 0e4a3c1974..043b48ec42 100644 --- a/src/eden/qml/config/fields/ConfigHexEdit.qml +++ b/src/eden/Eden/Config/fields/ConfigHexEdit.qml @@ -1,9 +1,9 @@ import QtQuick import QtQuick.Layouts -import org.eden_emu.items -import org.eden_emu.config -import org.eden_emu.constants +import Eden.Items +import Eden.Config +import Eden.Constants BaseField { contentItem: BetterTextField { diff --git a/src/eden/qml/config/fields/ConfigIntLine.qml b/src/eden/Eden/Config/fields/ConfigIntLine.qml similarity index 85% rename from src/eden/qml/config/fields/ConfigIntLine.qml rename to src/eden/Eden/Config/fields/ConfigIntLine.qml index 6f48b72492..5dc45343ec 100644 --- a/src/eden/qml/config/fields/ConfigIntLine.qml +++ b/src/eden/Eden/Config/fields/ConfigIntLine.qml @@ -1,9 +1,9 @@ import QtQuick import QtQuick.Layouts -import org.eden_emu.items -import org.eden_emu.config -import org.eden_emu.constants +import Eden.Items +import Eden.Config +import Eden.Constants BaseField { contentItem: BetterTextField { diff --git a/src/eden/qml/config/fields/ConfigIntSlider.qml b/src/eden/Eden/Config/fields/ConfigIntSlider.qml similarity index 89% rename from src/eden/qml/config/fields/ConfigIntSlider.qml rename to src/eden/Eden/Config/fields/ConfigIntSlider.qml index 9428a0c791..7693ad824e 100644 --- a/src/eden/qml/config/fields/ConfigIntSlider.qml +++ b/src/eden/Eden/Config/fields/ConfigIntSlider.qml @@ -2,9 +2,9 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import org.eden_emu.items -import org.eden_emu.config -import org.eden_emu.constants +import Eden.Items +import Eden.Config +import Eden.Constants // Lots of cancer but idrc BaseField { diff --git a/src/eden/qml/config/fields/ConfigIntSpin.qml b/src/eden/Eden/Config/fields/ConfigIntSpin.qml similarity index 83% rename from src/eden/qml/config/fields/ConfigIntSpin.qml rename to src/eden/Eden/Config/fields/ConfigIntSpin.qml index 3fe0a82183..8e8c23f76f 100644 --- a/src/eden/qml/config/fields/ConfigIntSpin.qml +++ b/src/eden/Eden/Config/fields/ConfigIntSpin.qml @@ -1,9 +1,9 @@ import QtQuick import QtQuick.Layouts -import org.eden_emu.items -import org.eden_emu.config -import org.eden_emu.constants +import Eden.Items +import Eden.Config +import Eden.Constants BaseField { id: field diff --git a/src/eden/qml/config/fields/ConfigStringEdit.qml b/src/eden/Eden/Config/fields/ConfigStringEdit.qml similarity index 80% rename from src/eden/qml/config/fields/ConfigStringEdit.qml rename to src/eden/Eden/Config/fields/ConfigStringEdit.qml index 11c58ac7a3..beae2b0362 100644 --- a/src/eden/qml/config/fields/ConfigStringEdit.qml +++ b/src/eden/Eden/Config/fields/ConfigStringEdit.qml @@ -1,9 +1,9 @@ import QtQuick import QtQuick.Layouts -import org.eden_emu.items -import org.eden_emu.config -import org.eden_emu.constants +import Eden.Items +import Eden.Config +import Eden.Constants BaseField { contentItem: BetterTextField { diff --git a/src/eden/qml/config/fields/ConfigTimeEdit.qml b/src/eden/Eden/Config/fields/ConfigTimeEdit.qml similarity index 85% rename from src/eden/qml/config/fields/ConfigTimeEdit.qml rename to src/eden/Eden/Config/fields/ConfigTimeEdit.qml index 66c731c7ed..01ebc6d6b1 100644 --- a/src/eden/qml/config/fields/ConfigTimeEdit.qml +++ b/src/eden/Eden/Config/fields/ConfigTimeEdit.qml @@ -1,9 +1,9 @@ import QtQuick import QtQuick.Layouts -import org.eden_emu.items -import org.eden_emu.config -import org.eden_emu.constants +import Eden.Items +import Eden.Config +import Eden.Constants BaseField { // TODO: real impl diff --git a/src/eden/qml/config/fields/FieldCheckbox.qml b/src/eden/Eden/Config/fields/FieldCheckbox.qml similarity index 93% rename from src/eden/qml/config/fields/FieldCheckbox.qml rename to src/eden/Eden/Config/fields/FieldCheckbox.qml index 0e4e00d6a8..531f2bb624 100644 --- a/src/eden/qml/config/fields/FieldCheckbox.qml +++ b/src/eden/Eden/Config/fields/FieldCheckbox.qml @@ -2,7 +2,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import org.eden_emu.constants +import Eden.Constants CheckBox { property bool force: false diff --git a/src/eden/qml/config/fields/FieldLabel.qml b/src/eden/Eden/Config/fields/FieldLabel.qml similarity index 90% rename from src/eden/qml/config/fields/FieldLabel.qml rename to src/eden/Eden/Config/fields/FieldLabel.qml index 71ef3ad228..d94ee58c92 100644 --- a/src/eden/qml/config/fields/FieldLabel.qml +++ b/src/eden/Eden/Config/fields/FieldLabel.qml @@ -2,7 +2,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import org.eden_emu.constants +import Eden.Constants Text { property var setting diff --git a/src/eden/qml/config/icons.qrc b/src/eden/Eden/Config/icons.qrc similarity index 100% rename from src/eden/qml/config/icons.qrc rename to src/eden/Eden/Config/icons.qrc diff --git a/src/eden/qml/config/pages/SettingsList.qml b/src/eden/Eden/Config/pages/SettingsList.qml similarity index 91% rename from src/eden/qml/config/pages/SettingsList.qml rename to src/eden/Eden/Config/pages/SettingsList.qml index 13a1b4fdbf..73c6b27c76 100644 --- a/src/eden/qml/config/pages/SettingsList.qml +++ b/src/eden/Eden/Config/pages/SettingsList.qml @@ -1,9 +1,9 @@ import QtQuick import QtQuick.Layouts -import org.eden_emu.config -import org.eden_emu.constants -import org.eden_emu.interface +import Eden.Config +import Eden.Constants +import Eden.Native.Interface ColumnLayout { required property int category diff --git a/src/eden/qml/config/pages/audio/AudioGeneralPage.qml b/src/eden/Eden/Config/pages/audio/AudioGeneralPage.qml similarity index 82% rename from src/eden/qml/config/pages/audio/AudioGeneralPage.qml rename to src/eden/Eden/Config/pages/audio/AudioGeneralPage.qml index 83217cb420..9c86400a8c 100644 --- a/src/eden/qml/config/pages/audio/AudioGeneralPage.qml +++ b/src/eden/Eden/Config/pages/audio/AudioGeneralPage.qml @@ -2,8 +2,8 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import org.eden_emu.interface -import org.eden_emu.config +import Eden.Native.Interface +import Eden.Config ScrollView { id: scroll diff --git a/src/eden/qml/config/pages/cpu/CpuGeneralPage.qml b/src/eden/Eden/Config/pages/cpu/CpuGeneralPage.qml similarity index 82% rename from src/eden/qml/config/pages/cpu/CpuGeneralPage.qml rename to src/eden/Eden/Config/pages/cpu/CpuGeneralPage.qml index 49e52a87f9..a3c44e4892 100644 --- a/src/eden/qml/config/pages/cpu/CpuGeneralPage.qml +++ b/src/eden/Eden/Config/pages/cpu/CpuGeneralPage.qml @@ -2,8 +2,8 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import org.eden_emu.interface -import org.eden_emu.config +import Eden.Native.Interface +import Eden.Config ScrollView { id: scroll diff --git a/src/eden/qml/config/pages/debug/DebugAdvancedPage.qml b/src/eden/Eden/Config/pages/debug/DebugAdvancedPage.qml similarity index 83% rename from src/eden/qml/config/pages/debug/DebugAdvancedPage.qml rename to src/eden/Eden/Config/pages/debug/DebugAdvancedPage.qml index c5ee3b73b3..5d0443334f 100644 --- a/src/eden/qml/config/pages/debug/DebugAdvancedPage.qml +++ b/src/eden/Eden/Config/pages/debug/DebugAdvancedPage.qml @@ -2,8 +2,8 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import org.eden_emu.interface -import org.eden_emu.config +import Eden.Native.Interface +import Eden.Config ScrollView { id: scroll diff --git a/src/eden/qml/config/pages/debug/DebugCpuPage.qml b/src/eden/Eden/Config/pages/debug/DebugCpuPage.qml similarity index 82% rename from src/eden/qml/config/pages/debug/DebugCpuPage.qml rename to src/eden/Eden/Config/pages/debug/DebugCpuPage.qml index 67c9f612d1..aa58851cd7 100644 --- a/src/eden/qml/config/pages/debug/DebugCpuPage.qml +++ b/src/eden/Eden/Config/pages/debug/DebugCpuPage.qml @@ -2,8 +2,8 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import org.eden_emu.interface -import org.eden_emu.config +import Eden.Native.Interface +import Eden.Config ScrollView { id: scroll diff --git a/src/eden/qml/config/pages/debug/DebugGeneralPage.qml b/src/eden/Eden/Config/pages/debug/DebugGeneralPage.qml similarity index 90% rename from src/eden/qml/config/pages/debug/DebugGeneralPage.qml rename to src/eden/Eden/Config/pages/debug/DebugGeneralPage.qml index 7fa39e315e..0c0fb00f72 100644 --- a/src/eden/qml/config/pages/debug/DebugGeneralPage.qml +++ b/src/eden/Eden/Config/pages/debug/DebugGeneralPage.qml @@ -2,8 +2,8 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import org.eden_emu.interface -import org.eden_emu.config +import Eden.Native.Interface +import Eden.Config ScrollView { id: scroll diff --git a/src/eden/qml/config/pages/debug/DebugGraphicsPage.qml b/src/eden/Eden/Config/pages/debug/DebugGraphicsPage.qml similarity index 84% rename from src/eden/qml/config/pages/debug/DebugGraphicsPage.qml rename to src/eden/Eden/Config/pages/debug/DebugGraphicsPage.qml index 8f34c525ee..bcae356161 100644 --- a/src/eden/qml/config/pages/debug/DebugGraphicsPage.qml +++ b/src/eden/Eden/Config/pages/debug/DebugGraphicsPage.qml @@ -2,8 +2,8 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import org.eden_emu.interface -import org.eden_emu.config +import Eden.Native.Interface +import Eden.Config ScrollView { id: scroll diff --git a/src/eden/qml/config/pages/general/UiGameListPage.qml b/src/eden/Eden/Config/pages/general/UiGameListPage.qml similarity index 84% rename from src/eden/qml/config/pages/general/UiGameListPage.qml rename to src/eden/Eden/Config/pages/general/UiGameListPage.qml index 7ec92a11ba..930e4fe61b 100644 --- a/src/eden/qml/config/pages/general/UiGameListPage.qml +++ b/src/eden/Eden/Config/pages/general/UiGameListPage.qml @@ -2,8 +2,8 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import org.eden_emu.interface -import org.eden_emu.config +import Eden.Native.Interface +import Eden.Config ScrollView { id: scroll diff --git a/src/eden/qml/config/pages/general/UiGeneralPage.qml b/src/eden/Eden/Config/pages/general/UiGeneralPage.qml similarity index 89% rename from src/eden/qml/config/pages/general/UiGeneralPage.qml rename to src/eden/Eden/Config/pages/general/UiGeneralPage.qml index 06ad55d49c..16ee8a6ecc 100644 --- a/src/eden/qml/config/pages/general/UiGeneralPage.qml +++ b/src/eden/Eden/Config/pages/general/UiGeneralPage.qml @@ -2,8 +2,8 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import org.eden_emu.interface -import org.eden_emu.config +import Eden.Native.Interface +import Eden.Config ScrollView { id: scroll diff --git a/src/eden/qml/config/pages/global/GlobalAudioPage.qml b/src/eden/Eden/Config/pages/global/GlobalAudioPage.qml similarity index 88% rename from src/eden/qml/config/pages/global/GlobalAudioPage.qml rename to src/eden/Eden/Config/pages/global/GlobalAudioPage.qml index 73ed7f20fe..1edff2a9b4 100644 --- a/src/eden/qml/config/pages/global/GlobalAudioPage.qml +++ b/src/eden/Eden/Config/pages/global/GlobalAudioPage.qml @@ -1,6 +1,6 @@ import QtQuick -import org.eden_emu.config +import Eden.Config GlobalTab { property alias swipe: swipe diff --git a/src/eden/qml/config/pages/global/GlobalCpuPage.qml b/src/eden/Eden/Config/pages/global/GlobalCpuPage.qml similarity index 88% rename from src/eden/qml/config/pages/global/GlobalCpuPage.qml rename to src/eden/Eden/Config/pages/global/GlobalCpuPage.qml index 457565ede7..ead6fdd9c6 100644 --- a/src/eden/qml/config/pages/global/GlobalCpuPage.qml +++ b/src/eden/Eden/Config/pages/global/GlobalCpuPage.qml @@ -1,6 +1,6 @@ import QtQuick -import org.eden_emu.config +import Eden.Config GlobalTab { property alias swipe: swipe diff --git a/src/eden/qml/config/pages/global/GlobalDebugPage.qml b/src/eden/Eden/Config/pages/global/GlobalDebugPage.qml similarity index 92% rename from src/eden/qml/config/pages/global/GlobalDebugPage.qml rename to src/eden/Eden/Config/pages/global/GlobalDebugPage.qml index bbbbfbf29f..ee1f49a005 100644 --- a/src/eden/qml/config/pages/global/GlobalDebugPage.qml +++ b/src/eden/Eden/Config/pages/global/GlobalDebugPage.qml @@ -1,6 +1,6 @@ import QtQuick -import org.eden_emu.config +import Eden.Config GlobalTab { property alias swipe: swipe diff --git a/src/eden/qml/config/pages/global/GlobalGeneralPage.qml b/src/eden/Eden/Config/pages/global/GlobalGeneralPage.qml similarity index 91% rename from src/eden/qml/config/pages/global/GlobalGeneralPage.qml rename to src/eden/Eden/Config/pages/global/GlobalGeneralPage.qml index feae9cd482..e1e5a906a7 100644 --- a/src/eden/qml/config/pages/global/GlobalGeneralPage.qml +++ b/src/eden/Eden/Config/pages/global/GlobalGeneralPage.qml @@ -1,6 +1,6 @@ import QtQuick -import org.eden_emu.config +import Eden.Config GlobalTab { property alias swipe: swipe diff --git a/src/eden/qml/config/pages/global/GlobalGraphicsPage.qml b/src/eden/Eden/Config/pages/global/GlobalGraphicsPage.qml similarity index 91% rename from src/eden/qml/config/pages/global/GlobalGraphicsPage.qml rename to src/eden/Eden/Config/pages/global/GlobalGraphicsPage.qml index 67380be9e4..4e15cd01f6 100644 --- a/src/eden/qml/config/pages/global/GlobalGraphicsPage.qml +++ b/src/eden/Eden/Config/pages/global/GlobalGraphicsPage.qml @@ -1,6 +1,6 @@ import QtQuick -import org.eden_emu.config +import Eden.Config GlobalTab { property alias swipe: swipe diff --git a/src/eden/qml/config/pages/global/GlobalSystemPage.qml b/src/eden/Eden/Config/pages/global/GlobalSystemPage.qml similarity index 92% rename from src/eden/qml/config/pages/global/GlobalSystemPage.qml rename to src/eden/Eden/Config/pages/global/GlobalSystemPage.qml index 1fa34e0d26..b482f7b57f 100644 --- a/src/eden/qml/config/pages/global/GlobalSystemPage.qml +++ b/src/eden/Eden/Config/pages/global/GlobalSystemPage.qml @@ -1,6 +1,6 @@ import QtQuick -import org.eden_emu.config +import Eden.Config GlobalTab { property alias swipe: swipe diff --git a/src/eden/qml/config/pages/global/GlobalTab.qml b/src/eden/Eden/Config/pages/global/GlobalTab.qml similarity index 95% rename from src/eden/qml/config/pages/global/GlobalTab.qml rename to src/eden/Eden/Config/pages/global/GlobalTab.qml index 68a262aedc..463a7c2d83 100644 --- a/src/eden/qml/config/pages/global/GlobalTab.qml +++ b/src/eden/Eden/Config/pages/global/GlobalTab.qml @@ -1,7 +1,7 @@ import QtQuick 2.15 import QtQuick.Controls.Material -import org.eden_emu.constants +import Eden.Constants Item { required property list tabs diff --git a/src/eden/qml/config/pages/global/GlobalTabSwipeView.qml b/src/eden/Eden/Config/pages/global/GlobalTabSwipeView.qml similarity index 90% rename from src/eden/qml/config/pages/global/GlobalTabSwipeView.qml rename to src/eden/Eden/Config/pages/global/GlobalTabSwipeView.qml index b5f746d02e..eaa63c5265 100644 --- a/src/eden/qml/config/pages/global/GlobalTabSwipeView.qml +++ b/src/eden/Eden/Config/pages/global/GlobalTabSwipeView.qml @@ -1,7 +1,7 @@ import QtQuick 2.15 import QtQuick.Controls.Material -import org.eden_emu.constants +import Eden.Constants SwipeView { anchors { diff --git a/src/eden/qml/config/pages/graphics/RendererAdvancedPage.qml b/src/eden/Eden/Config/pages/graphics/RendererAdvancedPage.qml similarity index 83% rename from src/eden/qml/config/pages/graphics/RendererAdvancedPage.qml rename to src/eden/Eden/Config/pages/graphics/RendererAdvancedPage.qml index d9699a5120..f6e8983eae 100644 --- a/src/eden/qml/config/pages/graphics/RendererAdvancedPage.qml +++ b/src/eden/Eden/Config/pages/graphics/RendererAdvancedPage.qml @@ -2,8 +2,8 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import org.eden_emu.interface -import org.eden_emu.config +import Eden.Native.Interface +import Eden.Config ScrollView { id: scroll diff --git a/src/eden/qml/config/pages/graphics/RendererExtensionsPage.qml b/src/eden/Eden/Config/pages/graphics/RendererExtensionsPage.qml similarity index 83% rename from src/eden/qml/config/pages/graphics/RendererExtensionsPage.qml rename to src/eden/Eden/Config/pages/graphics/RendererExtensionsPage.qml index ce6f5536d7..be9efcbd28 100644 --- a/src/eden/qml/config/pages/graphics/RendererExtensionsPage.qml +++ b/src/eden/Eden/Config/pages/graphics/RendererExtensionsPage.qml @@ -2,8 +2,8 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import org.eden_emu.interface -import org.eden_emu.config +import Eden.Native.Interface +import Eden.Config ScrollView { id: scroll diff --git a/src/eden/qml/config/pages/graphics/RendererPage.qml b/src/eden/Eden/Config/pages/graphics/RendererPage.qml similarity index 82% rename from src/eden/qml/config/pages/graphics/RendererPage.qml rename to src/eden/Eden/Config/pages/graphics/RendererPage.qml index 99b95a2699..d1d63ff717 100644 --- a/src/eden/qml/config/pages/graphics/RendererPage.qml +++ b/src/eden/Eden/Config/pages/graphics/RendererPage.qml @@ -2,8 +2,8 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import org.eden_emu.interface -import org.eden_emu.config +import Eden.Native.Interface +import Eden.Config ScrollView { id: scroll diff --git a/src/eden/qml/config/pages/system/AppletsPage.qml b/src/eden/Eden/Config/pages/system/AppletsPage.qml similarity index 82% rename from src/eden/qml/config/pages/system/AppletsPage.qml rename to src/eden/Eden/Config/pages/system/AppletsPage.qml index 4759fe1546..b3171d9d8b 100644 --- a/src/eden/qml/config/pages/system/AppletsPage.qml +++ b/src/eden/Eden/Config/pages/system/AppletsPage.qml @@ -2,8 +2,8 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import org.eden_emu.interface -import org.eden_emu.config +import Eden.Native.Interface +import Eden.Config ScrollView { id: scroll diff --git a/src/eden/qml/config/pages/system/FileSystemPage.qml b/src/eden/Eden/Config/pages/system/FileSystemPage.qml similarity index 82% rename from src/eden/qml/config/pages/system/FileSystemPage.qml rename to src/eden/Eden/Config/pages/system/FileSystemPage.qml index ad0b230e5b..90f6395f8f 100644 --- a/src/eden/qml/config/pages/system/FileSystemPage.qml +++ b/src/eden/Eden/Config/pages/system/FileSystemPage.qml @@ -2,8 +2,8 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import org.eden_emu.interface -import org.eden_emu.config +import Eden.Native.Interface +import Eden.Config ScrollView { id: scroll diff --git a/src/eden/qml/config/pages/system/SystemCorePage.qml b/src/eden/Eden/Config/pages/system/SystemCorePage.qml similarity index 82% rename from src/eden/qml/config/pages/system/SystemCorePage.qml rename to src/eden/Eden/Config/pages/system/SystemCorePage.qml index 913e9a456f..562ba17d60 100644 --- a/src/eden/qml/config/pages/system/SystemCorePage.qml +++ b/src/eden/Eden/Config/pages/system/SystemCorePage.qml @@ -2,8 +2,8 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import org.eden_emu.interface -import org.eden_emu.config +import Eden.Native.Interface +import Eden.Config ScrollView { id: scroll diff --git a/src/eden/qml/config/pages/system/SystemGeneralPage.qml b/src/eden/Eden/Config/pages/system/SystemGeneralPage.qml similarity index 88% rename from src/eden/qml/config/pages/system/SystemGeneralPage.qml rename to src/eden/Eden/Config/pages/system/SystemGeneralPage.qml index dab840e5ad..2d2e02b2b4 100644 --- a/src/eden/qml/config/pages/system/SystemGeneralPage.qml +++ b/src/eden/Eden/Config/pages/system/SystemGeneralPage.qml @@ -2,8 +2,8 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import org.eden_emu.interface -import org.eden_emu.config +import Eden.Native.Interface +import Eden.Config ScrollView { id: scroll diff --git a/src/eden/qml/constants/CMakeLists.txt b/src/eden/Eden/Constants/CMakeLists.txt similarity index 66% rename from src/eden/qml/constants/CMakeLists.txt rename to src/eden/Eden/Constants/CMakeLists.txt index 27e8a6a6c1..3fb7aec6d0 100644 --- a/src/eden/qml/constants/CMakeLists.txt +++ b/src/eden/Eden/Constants/CMakeLists.txt @@ -7,9 +7,9 @@ set_source_files_properties(Constants.qml QT_QML_SINGLETON_TYPE true ) -qt_add_library(edenConstants STATIC) -qt_add_qml_module(edenConstants - URI org.eden_emu.constants +qt_add_library(EdenConstants STATIC) +qt_add_qml_module(EdenConstants + URI Eden.Constants OUTPUT_DIRECTORY EdenConstants VERSION 1.0 QML_FILES @@ -17,7 +17,7 @@ qt_add_qml_module(edenConstants Constants.qml ) -target_link_libraries(edenConstants +target_link_libraries(EdenConstants PRIVATE Qt6::Quick ) diff --git a/src/eden/qml/constants/Constants.qml b/src/eden/Eden/Constants/Constants.qml similarity index 100% rename from src/eden/qml/constants/Constants.qml rename to src/eden/Eden/Constants/Constants.qml diff --git a/src/eden/qml/items/AnimatedDialog.qml b/src/eden/Eden/Items/AnimatedDialog.qml similarity index 98% rename from src/eden/qml/items/AnimatedDialog.qml rename to src/eden/Eden/Items/AnimatedDialog.qml index 98fc2e8d9e..c623574ae1 100644 --- a/src/eden/qml/items/AnimatedDialog.qml +++ b/src/eden/Eden/Items/AnimatedDialog.qml @@ -1,7 +1,7 @@ import QtQuick import QtQuick.Controls.Material -import org.eden_emu.constants +import Eden.Constants Dialog { id: dia diff --git a/src/eden/qml/items/BetterMenu.qml b/src/eden/Eden/Items/BetterMenu.qml similarity index 98% rename from src/eden/qml/items/BetterMenu.qml rename to src/eden/Eden/Items/BetterMenu.qml index 51a38451e5..97bd3ca244 100644 --- a/src/eden/qml/items/BetterMenu.qml +++ b/src/eden/Eden/Items/BetterMenu.qml @@ -1,7 +1,7 @@ import QtQuick import QtQuick.Controls -import org.eden_emu.constants +import Eden.Constants Menu { background: Rectangle { diff --git a/src/eden/qml/items/BetterMenuBar.qml b/src/eden/Eden/Items/BetterMenuBar.qml similarity index 95% rename from src/eden/qml/items/BetterMenuBar.qml rename to src/eden/Eden/Items/BetterMenuBar.qml index 8b5fd10d9a..be35c7ded5 100644 --- a/src/eden/qml/items/BetterMenuBar.qml +++ b/src/eden/Eden/Items/BetterMenuBar.qml @@ -1,7 +1,7 @@ import QtQuick import QtQuick.Controls -import org.eden_emu.constants +import Eden.Constants MenuBar { background: Rectangle { diff --git a/src/eden/qml/items/CMakeLists.txt b/src/eden/Eden/Items/CMakeLists.txt similarity index 80% rename from src/eden/qml/items/CMakeLists.txt rename to src/eden/Eden/Items/CMakeLists.txt index 57ff683ec2..06764ee7bb 100644 --- a/src/eden/qml/items/CMakeLists.txt +++ b/src/eden/Eden/Items/CMakeLists.txt @@ -1,9 +1,9 @@ set(CMAKE_AUTOMOC ON) -qt_add_library(edenItems STATIC) +qt_add_library(EdenItems STATIC) -qt_add_qml_module(edenItems - URI org.eden_emu.items +qt_add_qml_module(EdenItems + URI Eden.Items VERSION 1.0 QML_FILES diff --git a/src/eden/qml/items/IconButton.qml b/src/eden/Eden/Items/IconButton.qml similarity index 93% rename from src/eden/qml/items/IconButton.qml rename to src/eden/Eden/Items/IconButton.qml index 14f28b3fff..70192e9ea7 100644 --- a/src/eden/qml/items/IconButton.qml +++ b/src/eden/Eden/Items/IconButton.qml @@ -1,7 +1,7 @@ import QtQuick import QtQuick.Controls.Material -import org.eden_emu.constants +import Eden.Constants Button { required property string label diff --git a/src/eden/qml/items/SettingsTabButton.qml b/src/eden/Eden/Items/SettingsTabButton.qml similarity index 96% rename from src/eden/qml/items/SettingsTabButton.qml rename to src/eden/Eden/Items/SettingsTabButton.qml index bdc0190aaa..e4d7bd0891 100644 --- a/src/eden/qml/items/SettingsTabButton.qml +++ b/src/eden/Eden/Items/SettingsTabButton.qml @@ -2,7 +2,7 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import org.eden_emu.constants +import Eden.Constants TabButton { required property string label diff --git a/src/eden/qml/items/StatusBarButton.qml b/src/eden/Eden/Items/StatusBarButton.qml similarity index 95% rename from src/eden/qml/items/StatusBarButton.qml rename to src/eden/Eden/Items/StatusBarButton.qml index 211795e337..47691bc8b4 100644 --- a/src/eden/qml/items/StatusBarButton.qml +++ b/src/eden/Eden/Items/StatusBarButton.qml @@ -2,7 +2,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import org.eden_emu.constants +import Eden.Constants MouseArea { id: button diff --git a/src/eden/qml/items/VerticalTabBar.qml b/src/eden/Eden/Items/VerticalTabBar.qml similarity index 97% rename from src/eden/qml/items/VerticalTabBar.qml rename to src/eden/Eden/Items/VerticalTabBar.qml index 2c4fe85886..b5d8b8c13f 100644 --- a/src/eden/qml/items/VerticalTabBar.qml +++ b/src/eden/Eden/Items/VerticalTabBar.qml @@ -1,7 +1,7 @@ import QtQuick import QtQuick.Controls.Material -import org.eden_emu.constants +import Eden.Constants TabBar { clip: true diff --git a/src/eden/qml/items/fields/BetterSpinBox.qml b/src/eden/Eden/Items/fields/BetterSpinBox.qml similarity index 97% rename from src/eden/qml/items/fields/BetterSpinBox.qml rename to src/eden/Eden/Items/fields/BetterSpinBox.qml index 709b7b75e0..0d4980506b 100644 --- a/src/eden/qml/items/fields/BetterSpinBox.qml +++ b/src/eden/Eden/Items/fields/BetterSpinBox.qml @@ -2,7 +2,7 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Controls.impl -import org.eden_emu.constants +import Eden.Constants SpinBox { id: control diff --git a/src/eden/qml/items/fields/BetterTextField.qml b/src/eden/Eden/Items/fields/BetterTextField.qml similarity index 92% rename from src/eden/qml/items/fields/BetterTextField.qml rename to src/eden/Eden/Items/fields/BetterTextField.qml index 5d32b4022e..a72865b18d 100644 --- a/src/eden/qml/items/fields/BetterTextField.qml +++ b/src/eden/Eden/Items/fields/BetterTextField.qml @@ -1,8 +1,8 @@ import QtQuick import QtQuick.Controls.Material -import org.eden_emu.constants -import org.eden_emu.items +import Eden.Constants +import Eden.Items TextField { property string suffix: "" diff --git a/src/eden/qml/items/fields/FieldFooter.qml b/src/eden/Eden/Items/fields/FieldFooter.qml similarity index 92% rename from src/eden/qml/items/fields/FieldFooter.qml rename to src/eden/Eden/Items/fields/FieldFooter.qml index 897785a21b..58d237d1ea 100644 --- a/src/eden/qml/items/fields/FieldFooter.qml +++ b/src/eden/Eden/Items/fields/FieldFooter.qml @@ -1,6 +1,6 @@ import QtQuick import QtQuick.Controls.Material -import org.eden_emu.constants +import Eden.Constants Rectangle { height: 2 * Constants.scalar diff --git a/src/eden/qml/main/CMakeLists.txt b/src/eden/Eden/Main/CMakeLists.txt similarity index 71% rename from src/eden/qml/main/CMakeLists.txt rename to src/eden/Eden/Main/CMakeLists.txt index c0441d539d..b802ab1b40 100644 --- a/src/eden/qml/main/CMakeLists.txt +++ b/src/eden/Eden/Main/CMakeLists.txt @@ -1,8 +1,8 @@ set(CMAKE_AUTOMOC ON) -qt_add_library(edenMain STATIC) -qt_add_qml_module(edenMain - URI org.eden_emu.main +qt_add_library(EdenMain STATIC) +qt_add_qml_module(EdenMain + URI Eden.Main VERSION 1.0 QML_FILES diff --git a/src/eden/qml/main/GameCarousel.qml b/src/eden/Eden/Main/GameCarousel.qml similarity index 57% rename from src/eden/qml/main/GameCarousel.qml rename to src/eden/Eden/Main/GameCarousel.qml index 7989d46d71..eb9d90a85c 100644 --- a/src/eden/qml/main/GameCarousel.qml +++ b/src/eden/Eden/Main/GameCarousel.qml @@ -3,8 +3,8 @@ import QtQuick.Controls import Qt.labs.platform import QtCore -import org.eden_emu.constants -import org.eden_emu.interface +import Eden.Constants +import Eden.Native.Interface ListView { id: carousel @@ -15,24 +15,42 @@ ListView { model: EdenGameList orientation: ListView.Horizontal clip: false - flickDeceleration: 1000 + flickDeceleration: 1500 snapMode: ListView.SnapToItem onHeightChanged: console.log(width, height) spacing: 20 - Keys.enabled: true - Keys.onRightPressed: incrementCurrentIndex() - Keys.onLeftPressed: decrementCurrentIndex() + keyNavigationWraps: true - onCurrentIndexChanged: scrollToCenter() + function increment() { + incrementCurrentIndex() + if (currentIndex === count) + currentIndex = 0 + } - highlight: Rectangle { + function decrement() { + decrementCurrentIndex() + if (currentIndex === -1) + currentIndex = count - 1 + } + + // TODO(crueter): handle move/displace/add (requires thread worker on game list and a bunch of other shit) + Rectangle { id: hg clip: false z: 3 + property var item: carousel.currentItem + + anchors { + centerIn: parent + } + + height: item === null ? 0 : item.height + 10 + width: item === null ? 0 : item.width + 10 + color: "transparent" border { color: "deepskyblue" @@ -48,9 +66,7 @@ ListView { ) + text.substring(1).toLowerCase()) } - property var item: carousel.currentItem - - text: toTitleCase(item.title) + text: hg.item === null ? "" : toTitleCase(hg.item.title) font.pixelSize: 22 * Constants.scalar color: "lightblue" @@ -67,28 +83,14 @@ ListView { } } - highlightFollowsCurrentItem: true - highlightMoveDuration: 300 - highlightMoveVelocity: -1 + highlightRangeMode: ListView.StrictlyEnforceRange + preferredHighlightBegin: currentItem === null ? 0 : x + width / 2 - currentItem.width / 2 + preferredHighlightEnd: currentItem === null ? 0 : x + width / 2 + currentItem.width / 2 + highlightMoveDuration: 300 delegate: GameCarouselCard { id: game width: 300 height: 300 } - - function scrollToCenter() { - let targetX = currentIndex * 320 - (width - 320) / 2 - let min = 0 - let max = contentWidth - - contentX = Math.max(min, Math.min(max, targetX)) - } - - Behavior on contentX { - NumberAnimation { - duration: 300 - easing.type: Easing.OutQuad - } - } } diff --git a/src/eden/qml/main/GameCarouselCard.qml b/src/eden/Eden/Main/GameCarouselCard.qml similarity index 95% rename from src/eden/qml/main/GameCarouselCard.qml rename to src/eden/Eden/Main/GameCarouselCard.qml index 7e7514f7ec..51cb3a1f23 100644 --- a/src/eden/qml/main/GameCarouselCard.qml +++ b/src/eden/Eden/Main/GameCarouselCard.qml @@ -3,7 +3,7 @@ import QtQuick.Controls import Qt.labs.platform import QtCore -import org.eden_emu.constants +import Eden.Constants Item { property string title: model.name.replace(/-/g, " ") diff --git a/src/eden/qml/main/GameGrid.qml b/src/eden/Eden/Main/GameGrid.qml similarity index 89% rename from src/eden/qml/main/GameGrid.qml rename to src/eden/Eden/Main/GameGrid.qml index 8094ae4cdd..9231d2b7a8 100644 --- a/src/eden/qml/main/GameGrid.qml +++ b/src/eden/Eden/Main/GameGrid.qml @@ -3,9 +3,9 @@ import QtQuick.Controls import Qt.labs.platform import QtCore -import org.eden_emu.constants -import org.eden_emu.interface -import org.eden_emu.gamepad +import Eden.Constants +import Eden.Native.Interface +import Eden.Native.Gamepad GridView { property var setting diff --git a/src/eden/qml/main/GameGridCard.qml b/src/eden/Eden/Main/GameGridCard.qml similarity index 98% rename from src/eden/qml/main/GameGridCard.qml rename to src/eden/Eden/Main/GameGridCard.qml index c1af89bce7..634c325974 100644 --- a/src/eden/qml/main/GameGridCard.qml +++ b/src/eden/Eden/Main/GameGridCard.qml @@ -3,7 +3,7 @@ import QtQuick.Controls import Qt.labs.platform import QtCore -import org.eden_emu.constants +import Eden.Constants Rectangle { id: wrapper diff --git a/src/eden/qml/main/GameList.qml b/src/eden/Eden/Main/GameList.qml similarity index 85% rename from src/eden/qml/main/GameList.qml rename to src/eden/Eden/Main/GameList.qml index 81937d1f87..7af19bbe88 100644 --- a/src/eden/qml/main/GameList.qml +++ b/src/eden/Eden/Main/GameList.qml @@ -3,9 +3,9 @@ import QtQuick.Controls import Qt.labs.platform import QtCore -import org.eden_emu.constants -import org.eden_emu.interface -import org.eden_emu.gamepad +import Eden.Constants +import Eden.Native.Interface +import Eden.Native.Gamepad Rectangle { id: root @@ -28,8 +28,8 @@ Rectangle { // onDownPressed: grid.moveCurrentIndexDown() // onLeftPressed: grid.moveCurrentIndexLeft() // onRightPressed: grid.moveCurrentIndexRight() - onLeftPressed: carousel.decrementCurrentIndex() - onRightPressed: carousel.incrementCurrentIndex() + onLeftPressed: carousel.decrement() + onRightPressed: carousel.increment() onAPressed: console.log("A pressed") onLeftStickMoved: (x, y) => { gx = x @@ -71,17 +71,6 @@ Rectangle { } } - // GameGrid { - // setting: parent.setting - - // id: grid - - // anchors.bottom: button.top - // anchors.left: parent.left - // anchors.margins: 8 - // anchors.right: parent.right - // anchors.top: parent.top - // } Item { id: view @@ -93,6 +82,13 @@ Rectangle { margins: 8 * Constants.scalar } + // GameGrid { + // setting: root.setting + + // id: grid + + // anchors.fill: parent + // } GameCarousel { id: carousel diff --git a/src/eden/qml/main/Main.qml b/src/eden/Eden/Main/Main.qml similarity index 98% rename from src/eden/qml/main/Main.qml rename to src/eden/Eden/Main/Main.qml index 071b052525..d0be3a27f5 100644 --- a/src/eden/qml/main/Main.qml +++ b/src/eden/Eden/Main/Main.qml @@ -1,9 +1,9 @@ import QtQuick import QtQuick.Controls.Material -import org.eden_emu.config -import org.eden_emu.items -import org.eden_emu.constants +import Eden.Config +import Eden.Items +import Eden.Constants ApplicationWindow { width: Constants.width diff --git a/src/eden/qml/main/MarqueeText.qml b/src/eden/Eden/Main/MarqueeText.qml similarity index 100% rename from src/eden/qml/main/MarqueeText.qml rename to src/eden/Eden/Main/MarqueeText.qml diff --git a/src/eden/qml/main/StatusBar.qml b/src/eden/Eden/Main/StatusBar.qml similarity index 98% rename from src/eden/qml/main/StatusBar.qml rename to src/eden/Eden/Main/StatusBar.qml index 39aeaed393..d47acd82ee 100644 --- a/src/eden/qml/main/StatusBar.qml +++ b/src/eden/Eden/Main/StatusBar.qml @@ -2,8 +2,8 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import org.eden_emu.constants -import org.eden_emu.items +import Eden.Constants +import Eden.Items ToolBar { id: toolbar diff --git a/src/eden/Eden/Native/CMakeLists.txt b/src/eden/Eden/Native/CMakeLists.txt new file mode 100644 index 0000000000..289504b4cf --- /dev/null +++ b/src/eden/Eden/Native/CMakeLists.txt @@ -0,0 +1,71 @@ +qt_add_executable(eden + main.cpp + icons.qrc +) + +add_subdirectory(Interface) +add_subdirectory(Models) + +set(PLUGINS + EdenUtilplugin + EdenItemsplugin + EdenConfigplugin + EdenInterfaceplugin + EdenConstantsplugin + EdenMainplugin +) + +if (ENABLE_SDL2) + add_subdirectory(Gamepad) + set(PLUGINS ${PLUGINS} edenGamepadplugin) +endif() + +target_link_libraries(eden + PRIVATE + Qt6::Core + Qt6::Widgets + Qt6::Gui + Qt6::Quick + Qt6::QuickControls2 + EdenModels + + # Explicitly link to static plugins + ${PLUGINS} +) + +set(NATIVE_MODULES eden EdenInterface) + +foreach(MODULE ${NATIVE_MODULES}) + target_link_libraries(${MODULE} PRIVATE common core input_common frontend_common qt_common network video_core) + target_link_libraries(${MODULE} PRIVATE Boost::headers glad fmt) + target_link_libraries(${MODULE} PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) + + target_link_libraries(${MODULE} PRIVATE Vulkan::Headers) + + if (UNIX AND NOT APPLE) + target_link_libraries(${MODULE} PRIVATE Qt6::DBus) + endif() + + target_compile_definitions(${MODULE} PRIVATE + # Use QStringBuilder for string concatenation to reduce + # the overall number of temporary strings created. + -DQT_USE_QSTRINGBUILDER + + # Disable implicit type narrowing in signal/slot connect() calls. + -DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT + + # Disable unsafe overloads of QProcess' start() function. + -DQT_NO_PROCESS_COMBINED_ARGUMENT_START + + # Disable implicit QString->QUrl conversions to enforce use of proper resolving functions. + -DQT_NO_URL_CAST_FROM_STRING + ) +endforeach() + +set_target_properties(eden PROPERTIES OUTPUT_NAME "eden") +include(GNUInstallDirs) +install(TARGETS eden + BUNDLE DESTINATION . + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) diff --git a/src/eden/gamepad/CMakeLists.txt b/src/eden/Eden/Native/Gamepad/CMakeLists.txt similarity index 82% rename from src/eden/gamepad/CMakeLists.txt rename to src/eden/Eden/Native/Gamepad/CMakeLists.txt index f4bbb7cf54..70a69b35ad 100644 --- a/src/eden/gamepad/CMakeLists.txt +++ b/src/eden/Eden/Native/Gamepad/CMakeLists.txt @@ -3,7 +3,7 @@ set(CMAKE_AUTOMOC ON) qt_add_library(edenGamepad STATIC) qt_add_qml_module(edenGamepad - URI org.eden_emu.gamepad + URI Eden.Native.Gamepad VERSION 1.0 SOURCES gamepad.h gamepad.cpp ) diff --git a/src/eden/gamepad/gamepad.cpp b/src/eden/Eden/Native/Gamepad/gamepad.cpp similarity index 98% rename from src/eden/gamepad/gamepad.cpp rename to src/eden/Eden/Native/Gamepad/gamepad.cpp index daba8e35e8..37e062dc50 100644 --- a/src/eden/gamepad/gamepad.cpp +++ b/src/eden/Eden/Native/Gamepad/gamepad.cpp @@ -1,5 +1,6 @@ #include "gamepad.h" +// TODO(crueter): This is just temporary Gamepad::Gamepad(QObject *parent) : QObject(parent) { diff --git a/src/eden/gamepad/gamepad.h b/src/eden/Eden/Native/Gamepad/gamepad.h similarity index 100% rename from src/eden/gamepad/gamepad.h rename to src/eden/Eden/Native/Gamepad/gamepad.h diff --git a/src/eden/Eden/Native/Interface/CMakeLists.txt b/src/eden/Eden/Native/Interface/CMakeLists.txt new file mode 100644 index 0000000000..3c35df6ce5 --- /dev/null +++ b/src/eden/Eden/Native/Interface/CMakeLists.txt @@ -0,0 +1,11 @@ +qt_add_library(EdenInterface STATIC) +qt_add_qml_module(EdenInterface + URI Eden.Native.Interface + VERSION 1.0 + SOURCES + SettingsInterface.h SettingsInterface.cpp + QMLSetting.h QMLSetting.cpp + MetaObjectHelper.h + SOURCES QMLConfig.h + +) diff --git a/src/eden/interface/MetaObjectHelper.h b/src/eden/Eden/Native/Interface/MetaObjectHelper.h similarity index 100% rename from src/eden/interface/MetaObjectHelper.h rename to src/eden/Eden/Native/Interface/MetaObjectHelper.h diff --git a/src/eden/interface/QMLConfig.h b/src/eden/Eden/Native/Interface/QMLConfig.h similarity index 91% rename from src/eden/interface/QMLConfig.h rename to src/eden/Eden/Native/Interface/QMLConfig.h index 83b7f174cb..e22926bb23 100644 --- a/src/eden/interface/QMLConfig.h +++ b/src/eden/Eden/Native/Interface/QMLConfig.h @@ -1,7 +1,7 @@ #ifndef QMLCONFIG_H #define QMLCONFIG_H -#include "eden/interface/qt_config.h" +#include "qt_common/qt_config.h" #include diff --git a/src/eden/interface/QMLSetting.cpp b/src/eden/Eden/Native/Interface/QMLSetting.cpp similarity index 100% rename from src/eden/interface/QMLSetting.cpp rename to src/eden/Eden/Native/Interface/QMLSetting.cpp diff --git a/src/eden/interface/QMLSetting.h b/src/eden/Eden/Native/Interface/QMLSetting.h similarity index 100% rename from src/eden/interface/QMLSetting.h rename to src/eden/Eden/Native/Interface/QMLSetting.h diff --git a/src/eden/interface/SettingsInterface.cpp b/src/eden/Eden/Native/Interface/SettingsInterface.cpp similarity index 99% rename from src/eden/interface/SettingsInterface.cpp rename to src/eden/Eden/Native/Interface/SettingsInterface.cpp index 0265440628..3760978f47 100644 --- a/src/eden/interface/SettingsInterface.cpp +++ b/src/eden/Eden/Native/Interface/SettingsInterface.cpp @@ -1,7 +1,7 @@ #include "SettingsInterface.h" #include "common/settings.h" #include "common/logging/log.h" -#include "uisettings.h" +#include "qt_common/uisettings.h" SettingsInterface::SettingsInterface(QObject* parent) : QObject{parent} diff --git a/src/eden/interface/SettingsInterface.h b/src/eden/Eden/Native/Interface/SettingsInterface.h similarity index 96% rename from src/eden/interface/SettingsInterface.h rename to src/eden/Eden/Native/Interface/SettingsInterface.h index c5a0617f26..5b31c02661 100644 --- a/src/eden/interface/SettingsInterface.h +++ b/src/eden/Eden/Native/Interface/SettingsInterface.h @@ -2,11 +2,11 @@ #define SETTINGSINTERFACE_H #include -#include +#include #include "QMLSetting.h" -#include "shared_translation.h" -#include "eden/models/SettingsModel.h" +#include "qt_common/shared_translation.h" +#include "Native/Models/SettingsModel.h" namespace SettingsCategories { Q_NAMESPACE diff --git a/src/eden/models/CMakeLists.txt b/src/eden/Eden/Native/Models/CMakeLists.txt similarity index 62% rename from src/eden/models/CMakeLists.txt rename to src/eden/Eden/Native/Models/CMakeLists.txt index f4e1f1f92f..3a86bed1c4 100644 --- a/src/eden/models/CMakeLists.txt +++ b/src/eden/Eden/Native/Models/CMakeLists.txt @@ -1,16 +1,16 @@ set(CMAKE_AUTOMOC ON) # TODO: This might not need to be exposed to QML? -qt_add_library(edenModels STATIC) -qt_add_qml_module(edenModels - URI org.eden_emu.models +qt_add_library(EdenModels STATIC) +qt_add_qml_module(EdenModels + URI Eden.Native.Models VERSION 1.0 SOURCES GameListModel.h GameListModel.cpp SettingsModel.h SettingsModel.cpp ) -target_link_libraries(edenModels +target_link_libraries(EdenModels PRIVATE Qt6::Gui ) diff --git a/src/eden/models/GameListModel.cpp b/src/eden/Eden/Native/Models/GameListModel.cpp similarity index 100% rename from src/eden/models/GameListModel.cpp rename to src/eden/Eden/Native/Models/GameListModel.cpp diff --git a/src/eden/models/GameListModel.h b/src/eden/Eden/Native/Models/GameListModel.h similarity index 100% rename from src/eden/models/GameListModel.h rename to src/eden/Eden/Native/Models/GameListModel.h diff --git a/src/eden/models/SettingsModel.cpp b/src/eden/Eden/Native/Models/SettingsModel.cpp similarity index 100% rename from src/eden/models/SettingsModel.cpp rename to src/eden/Eden/Native/Models/SettingsModel.cpp diff --git a/src/eden/models/SettingsModel.h b/src/eden/Eden/Native/Models/SettingsModel.h similarity index 95% rename from src/eden/models/SettingsModel.h rename to src/eden/Eden/Native/Models/SettingsModel.h index 4f7ff9860e..26729f45aa 100644 --- a/src/eden/models/SettingsModel.h +++ b/src/eden/Eden/Native/Models/SettingsModel.h @@ -2,7 +2,7 @@ #define SETTINGSMODEL_H #include -#include "eden/interface/QMLSetting.h" +#include "Native/Interface/QMLSetting.h" class SettingsModel : public QAbstractListModel { Q_OBJECT diff --git a/src/eden/icons.qrc b/src/eden/Eden/Native/icons.qrc similarity index 100% rename from src/eden/icons.qrc rename to src/eden/Eden/Native/icons.qrc diff --git a/src/eden/icons/audio.svg b/src/eden/Eden/Native/icons/audio.svg similarity index 100% rename from src/eden/icons/audio.svg rename to src/eden/Eden/Native/icons/audio.svg diff --git a/src/eden/icons/back.svg b/src/eden/Eden/Native/icons/back.svg similarity index 100% rename from src/eden/icons/back.svg rename to src/eden/Eden/Native/icons/back.svg diff --git a/src/eden/icons/controls.svg b/src/eden/Eden/Native/icons/controls.svg similarity index 100% rename from src/eden/icons/controls.svg rename to src/eden/Eden/Native/icons/controls.svg diff --git a/src/eden/icons/cpu.svg b/src/eden/Eden/Native/icons/cpu.svg similarity index 100% rename from src/eden/icons/cpu.svg rename to src/eden/Eden/Native/icons/cpu.svg diff --git a/src/eden/icons/debug.svg b/src/eden/Eden/Native/icons/debug.svg similarity index 100% rename from src/eden/icons/debug.svg rename to src/eden/Eden/Native/icons/debug.svg diff --git a/src/eden/icons/forward.svg b/src/eden/Eden/Native/icons/forward.svg similarity index 100% rename from src/eden/icons/forward.svg rename to src/eden/Eden/Native/icons/forward.svg diff --git a/src/eden/icons/general.svg b/src/eden/Eden/Native/icons/general.svg similarity index 100% rename from src/eden/icons/general.svg rename to src/eden/Eden/Native/icons/general.svg diff --git a/src/eden/icons/graphics.svg b/src/eden/Eden/Native/icons/graphics.svg similarity index 100% rename from src/eden/icons/graphics.svg rename to src/eden/Eden/Native/icons/graphics.svg diff --git a/src/eden/icons/help.svg b/src/eden/Eden/Native/icons/help.svg similarity index 100% rename from src/eden/icons/help.svg rename to src/eden/Eden/Native/icons/help.svg diff --git a/src/eden/icons/system.svg b/src/eden/Eden/Native/icons/system.svg similarity index 100% rename from src/eden/icons/system.svg rename to src/eden/Eden/Native/icons/system.svg diff --git a/src/eden/main.cpp b/src/eden/Eden/Native/main.cpp similarity index 85% rename from src/eden/main.cpp rename to src/eden/Eden/Native/main.cpp index 810d293c36..6fbf1e57d9 100644 --- a/src/eden/main.cpp +++ b/src/eden/Eden/Native/main.cpp @@ -2,9 +2,9 @@ #include #include #include "core/core.h" -#include "interface/QMLConfig.h" -#include "models/GameListModel.h" -#include "interface/SettingsInterface.h" +#include "Native/Interface/QMLConfig.h" +#include "Native/Models/GameListModel.h" +#include "Native/Interface/SettingsInterface.h" #include @@ -39,7 +39,7 @@ int main(int argc, char *argv[]) ctx->setContextProperty(QStringLiteral("QtConfig"), QVariant::fromValue(config)); // Enums - qmlRegisterUncreatableMetaObject(SettingsCategories::staticMetaObject, "org.eden_emu.interface", 1, 0, "SettingsCategories", QString()); + qmlRegisterUncreatableMetaObject(SettingsCategories::staticMetaObject, "Eden.Native.Interface", 1, 0, "SettingsCategories", QString()); // Directory List GameListModel *gameListModel = new GameListModel(&app); @@ -53,7 +53,7 @@ int main(int argc, char *argv[]) []() { QCoreApplication::exit(-1); }, Qt::QueuedConnection); - engine.loadFromModule("org.eden_emu.main", "Main"); + engine.loadFromModule("Eden.Main", "Main"); return app.exec(); } diff --git a/src/eden/qml/util/CMakeLists.txt b/src/eden/Eden/Util/CMakeLists.txt similarity index 69% rename from src/eden/qml/util/CMakeLists.txt rename to src/eden/Eden/Util/CMakeLists.txt index a2243aa611..5761da0b3f 100644 --- a/src/eden/qml/util/CMakeLists.txt +++ b/src/eden/Eden/Util/CMakeLists.txt @@ -7,9 +7,9 @@ set_source_files_properties(Util.qml QT_QML_SINGLETON_TYPE true ) -qt_add_library(edenUtil STATIC) -qt_add_qml_module(edenUtil - URI org.eden_emu.util +qt_add_library(EdenUtil STATIC) +qt_add_qml_module(EdenUtil + URI Eden.Util OUTPUT_DIRECTORY EdenUtil VERSION 1.0 QML_FILES @@ -17,7 +17,7 @@ qt_add_qml_module(edenUtil Util.qml ) -target_link_libraries(edenUtil +target_link_libraries(EdenUtil PRIVATE Qt6::Quick ) diff --git a/src/eden/qml/util/Util.qml b/src/eden/Eden/Util/Util.qml similarity index 100% rename from src/eden/qml/util/Util.qml rename to src/eden/Eden/Util/Util.qml diff --git a/src/eden/interface/CMakeLists.txt b/src/eden/interface/CMakeLists.txt deleted file mode 100644 index 290dec22b9..0000000000 --- a/src/eden/interface/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -qt_add_library(edenInterface STATIC) -qt_add_qml_module(edenInterface - URI org.eden_emu.interface - VERSION 1.0 - SOURCES - SettingsInterface.h SettingsInterface.cpp - uisettings.h uisettings.cpp - qt_config.h qt_config.cpp - shared_translation.h shared_translation.cpp - QMLSetting.h QMLSetting.cpp - MetaObjectHelper.h - SOURCES QMLConfig.h - -) diff --git a/src/eden/interface/qt_config.cpp b/src/eden/interface/qt_config.cpp deleted file mode 100644 index 463bbc72a8..0000000000 --- a/src/eden/interface/qt_config.cpp +++ /dev/null @@ -1,562 +0,0 @@ -// SPDX-FileCopyrightText: 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "qt_config.h" -#include "common/logging/log.h" -#include "input_common/main.h" -#include "uisettings.h" - -const std::array QtConfig::default_buttons = { - Qt::Key_C, Qt::Key_X, Qt::Key_V, Qt::Key_Z, Qt::Key_F, - Qt::Key_G, Qt::Key_Q, Qt::Key_E, Qt::Key_R, Qt::Key_T, - Qt::Key_M, Qt::Key_N, Qt::Key_Left, Qt::Key_Up, Qt::Key_Right, - Qt::Key_Down, Qt::Key_Q, Qt::Key_E, 0, 0, - Qt::Key_Q, Qt::Key_E, -}; - -const std::array QtConfig::default_motions = { - Qt::Key_7, - Qt::Key_8, -}; - -const std::array, Settings::NativeAnalog::NumAnalogs> QtConfig::default_analogs{{ - { - Qt::Key_W, - Qt::Key_S, - Qt::Key_A, - Qt::Key_D, - }, - { - Qt::Key_I, - Qt::Key_K, - Qt::Key_J, - Qt::Key_L, - }, -}}; - -const std::array QtConfig::default_stick_mod = { - Qt::Key_Shift, - 0, -}; - -const std::array QtConfig::default_ringcon_analogs{{ - Qt::Key_A, - Qt::Key_D, -}}; - -QtConfig::QtConfig(const std::string& config_name, const ConfigType config_type) - : Config(config_type) { - Initialize(config_name); - if (config_type != ConfigType::InputProfile) { - ReadQtValues(); - SaveQtValues(); - } -} - -QtConfig::~QtConfig() { - if (global) { - QtConfig::SaveAllValues(); - } -} - -void QtConfig::ReloadAllValues() { - Reload(); - ReadQtValues(); - SaveQtValues(); -} - -void QtConfig::SaveAllValues() { - SaveValues(); - SaveQtValues(); -} - -void QtConfig::ReadQtValues() { - if (global) { - ReadUIValues(); - } - ReadQtControlValues(); -} - -void QtConfig::ReadQtPlayerValues(const std::size_t player_index) { - std::string player_prefix; - if (type != ConfigType::InputProfile) { - player_prefix.append("player_").append(ToString(player_index)).append("_"); - } - - auto& player = Settings::values.players.GetValue()[player_index]; - if (IsCustomConfig()) { - const auto profile_name = - ReadStringSetting(std::string(player_prefix).append("profile_name")); - if (profile_name.empty()) { - // Use the global input config - player = Settings::values.players.GetValue(true)[player_index]; - player.profile_name = ""; - return; - } - } - - for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { - const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); - auto& player_buttons = player.buttons[i]; - - player_buttons = ReadStringSetting( - std::string(player_prefix).append(Settings::NativeButton::mapping[i]), default_param); - if (player_buttons.empty()) { - player_buttons = default_param; - } - } - - for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { - const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( - default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], - default_analogs[i][3], default_stick_mod[i], 0.5f); - auto& player_analogs = player.analogs[i]; - - player_analogs = ReadStringSetting( - std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), default_param); - if (player_analogs.empty()) { - player_analogs = default_param; - } - } - - for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { - const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); - auto& player_motions = player.motions[i]; - - player_motions = ReadStringSetting( - std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), default_param); - if (player_motions.empty()) { - player_motions = default_param; - } - } -} - -void QtConfig::ReadHidbusValues() { - const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( - 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); - auto& ringcon_analogs = Settings::values.ringcon_analogs; - - ringcon_analogs = ReadStringSetting(std::string("ring_controller"), default_param); - if (ringcon_analogs.empty()) { - ringcon_analogs = default_param; - } -} - -void QtConfig::ReadDebugControlValues() { - for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { - const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); - auto& debug_pad_buttons = Settings::values.debug_pad_buttons[i]; - - debug_pad_buttons = ReadStringSetting( - std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), default_param); - if (debug_pad_buttons.empty()) { - debug_pad_buttons = default_param; - } - } - - for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { - const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( - default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], - default_analogs[i][3], default_stick_mod[i], 0.5f); - auto& debug_pad_analogs = Settings::values.debug_pad_analogs[i]; - - debug_pad_analogs = ReadStringSetting( - std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), default_param); - if (debug_pad_analogs.empty()) { - debug_pad_analogs = default_param; - } - } -} - -void QtConfig::ReadQtControlValues() { - BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); - - Settings::values.players.SetGlobal(!IsCustomConfig()); - for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { - ReadQtPlayerValues(p); - } - if (IsCustomConfig()) { - EndGroup(); - return; - } - ReadDebugControlValues(); - ReadHidbusValues(); - - EndGroup(); -} - -void QtConfig::ReadPathValues() { - BeginGroup(Settings::TranslateCategory(Settings::Category::Paths)); - - UISettings::values.roms_path = ReadStringSetting(std::string("romsPath")); - UISettings::values.game_dir_deprecated = - ReadStringSetting(std::string("gameListRootDir"), std::string(".")); - UISettings::values.game_dir_deprecated_deepscan = - ReadBooleanSetting(std::string("gameListDeepScan"), std::make_optional(false)); - - const int gamedirs_size = BeginArray(std::string("gamedirs")); - for (int i = 0; i < gamedirs_size; ++i) { - SetArrayIndex(i); - UISettings::GameDir game_dir; - game_dir.path = ReadStringSetting(std::string("path")); - game_dir.deep_scan = - ReadBooleanSetting(std::string("deep_scan"), std::make_optional(false)); - game_dir.expanded = ReadBooleanSetting(std::string("expanded"), std::make_optional(true)); - UISettings::values.game_dirs.append(game_dir); - } - EndArray(); - - // Create NAND and SD card directories if empty, these are not removable through the UI, - // also carries over old game list settings if present - if (UISettings::values.game_dirs.empty()) { - UISettings::GameDir game_dir; - game_dir.path = std::string("SDMC"); - game_dir.expanded = true; - UISettings::values.game_dirs.append(game_dir); - game_dir.path = std::string("UserNAND"); - UISettings::values.game_dirs.append(game_dir); - game_dir.path = std::string("SysNAND"); - UISettings::values.game_dirs.append(game_dir); - if (UISettings::values.game_dir_deprecated != std::string(".")) { - game_dir.path = UISettings::values.game_dir_deprecated; - game_dir.deep_scan = UISettings::values.game_dir_deprecated_deepscan; - UISettings::values.game_dirs.append(game_dir); - } - } - UISettings::values.recent_files = - QString::fromStdString(ReadStringSetting(std::string("recentFiles"))) - .split(QStringLiteral(", "), Qt::SkipEmptyParts, Qt::CaseSensitive); - - ReadCategory(Settings::Category::Paths); - - EndGroup(); -} - -void QtConfig::ReadShortcutValues() { - BeginGroup(Settings::TranslateCategory(Settings::Category::Shortcuts)); - - for (const auto& [name, group, shortcut] : UISettings::default_hotkeys) { - BeginGroup(group); - BeginGroup(name); - - // No longer using ReadSetting for shortcut.second as it inaccurately returns a value of 1 - // for WidgetWithChildrenShortcut which is a value of 3. Needed to fix shortcuts the open - // a file dialog in windowed mode - UISettings::values.shortcuts.push_back( - {name, - group, - {ReadStringSetting(std::string("KeySeq"), shortcut.keyseq), - ReadStringSetting(std::string("Controller_KeySeq"), shortcut.controller_keyseq), - shortcut.context, - ReadBooleanSetting(std::string("Repeat"), std::optional(shortcut.repeat))}}); - - EndGroup(); // name - EndGroup(); // group - } - - EndGroup(); -} - -void QtConfig::ReadUIValues() { - BeginGroup(Settings::TranslateCategory(Settings::Category::Ui)); - - UISettings::values.theme = ReadStringSetting( - std::string("theme"), - std::string(UISettings::themes[static_cast(UISettings::default_theme)].second)); - - ReadUIGamelistValues(); - ReadUILayoutValues(); - ReadPathValues(); - ReadScreenshotValues(); - ReadShortcutValues(); - ReadMultiplayerValues(); - - ReadCategory(Settings::Category::Ui); - ReadCategory(Settings::Category::UiGeneral); - - EndGroup(); -} - -void QtConfig::ReadUIGamelistValues() { - BeginGroup(Settings::TranslateCategory(Settings::Category::UiGameList)); - - ReadCategory(Settings::Category::UiGameList); - - // const int favorites_size = BeginArray("favorites"); - // for (int i = 0; i < favorites_size; i++) { - // SetArrayIndex(i); - // UISettings::values.favorited_ids.append( - // ReadUnsignedIntegerSetting(std::string("program_id"))); - // } - // EndArray(); - - EndGroup(); -} - -void QtConfig::ReadUILayoutValues() { - BeginGroup(Settings::TranslateCategory(Settings::Category::UiGameList)); - - ReadCategory(Settings::Category::UiLayout); - - EndGroup(); -} - -void QtConfig::ReadMultiplayerValues() { - BeginGroup(Settings::TranslateCategory(Settings::Category::Multiplayer)); - - ReadCategory(Settings::Category::Multiplayer); - - // Read ban list back - int size = BeginArray(std::string("username_ban_list")); - UISettings::values.multiplayer_ban_list.first.resize(size); - for (int i = 0; i < size; ++i) { - SetArrayIndex(i); - UISettings::values.multiplayer_ban_list.first[i] = - ReadStringSetting(std::string("username"), std::string("")); - } - EndArray(); - - size = BeginArray(std::string("ip_ban_list")); - UISettings::values.multiplayer_ban_list.second.resize(size); - for (int i = 0; i < size; ++i) { - UISettings::values.multiplayer_ban_list.second[i] = - ReadStringSetting("username", std::string("")); - } - EndArray(); - - EndGroup(); -} - -void QtConfig::SaveQtValues() -{ - if (global) { - LOG_DEBUG(Config, "Saving global Qt configuration values"); - SaveUIValues(); - } else { - LOG_DEBUG(Config, "Saving Qt configuration values"); - } - SaveQtControlValues(); - - WriteToIni(); -} - -void QtConfig::SaveQtPlayerValues(const std::size_t player_index) { - std::string player_prefix; - if (type != ConfigType::InputProfile) { - player_prefix = std::string("player_").append(ToString(player_index)).append("_"); - } - - const auto& player = Settings::values.players.GetValue()[player_index]; - if (IsCustomConfig() && player.profile_name.empty()) { - // No custom profile selected - return; - } - - for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { - const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); - WriteStringSetting(std::string(player_prefix).append(Settings::NativeButton::mapping[i]), - player.buttons[i], std::make_optional(default_param)); - } - for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { - const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( - default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], - default_analogs[i][3], default_stick_mod[i], 0.5f); - WriteStringSetting(std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), - player.analogs[i], std::make_optional(default_param)); - } - for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { - const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); - WriteStringSetting(std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), - player.motions[i], std::make_optional(default_param)); - } -} - -void QtConfig::SaveDebugControlValues() { - for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { - const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); - WriteStringSetting(std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), - Settings::values.debug_pad_buttons[i], - std::make_optional(default_param)); - } - for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { - const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( - default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], - default_analogs[i][3], default_stick_mod[i], 0.5f); - WriteStringSetting(std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), - Settings::values.debug_pad_analogs[i], - std::make_optional(default_param)); - } -} - -void QtConfig::SaveHidbusValues() { - const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( - 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); - WriteStringSetting(std::string("ring_controller"), Settings::values.ringcon_analogs, - std::make_optional(default_param)); -} - -void QtConfig::SaveQtControlValues() { - BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); - - Settings::values.players.SetGlobal(!IsCustomConfig()); - for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { - SaveQtPlayerValues(p); - } - if (IsCustomConfig()) { - EndGroup(); - return; - } - SaveDebugControlValues(); - SaveHidbusValues(); - - EndGroup(); -} - -void QtConfig::SavePathValues() { - BeginGroup(Settings::TranslateCategory(Settings::Category::Paths)); - - WriteCategory(Settings::Category::Paths); - - WriteStringSetting(std::string("romsPath"), UISettings::values.roms_path); - BeginArray(std::string("gamedirs")); - for (int i = 0; i < UISettings::values.game_dirs.size(); ++i) { - SetArrayIndex(i); - const auto& game_dir = UISettings::values.game_dirs[i]; - WriteStringSetting(std::string("path"), game_dir.path); - WriteBooleanSetting(std::string("deep_scan"), game_dir.deep_scan, - std::make_optional(false)); - WriteBooleanSetting(std::string("expanded"), game_dir.expanded, std::make_optional(true)); - } - EndArray(); - - WriteStringSetting(std::string("recentFiles"), - UISettings::values.recent_files.join(QStringLiteral(", ")).toStdString()); - - EndGroup(); -} - -void QtConfig::SaveShortcutValues() { - BeginGroup(Settings::TranslateCategory(Settings::Category::Shortcuts)); - - // Lengths of UISettings::values.shortcuts & default_hotkeys are same. - // However, their ordering must also be the same. - for (std::size_t i = 0; i < UISettings::default_hotkeys.size(); i++) { - const auto& [name, group, shortcut] = UISettings::values.shortcuts[i]; - const auto& default_hotkey = UISettings::default_hotkeys[i].shortcut; - - BeginGroup(group); - BeginGroup(name); - - WriteStringSetting(std::string("KeySeq"), shortcut.keyseq, - std::make_optional(default_hotkey.keyseq)); - WriteStringSetting(std::string("Controller_KeySeq"), shortcut.controller_keyseq, - std::make_optional(default_hotkey.controller_keyseq)); - WriteIntegerSetting(std::string("Context"), shortcut.context, - std::make_optional(default_hotkey.context)); - WriteBooleanSetting(std::string("Repeat"), shortcut.repeat, - std::make_optional(default_hotkey.repeat)); - - EndGroup(); // name - EndGroup(); // group - } - - EndGroup(); -} - -void QtConfig::SaveUIValues() { - BeginGroup(Settings::TranslateCategory(Settings::Category::Ui)); - - WriteCategory(Settings::Category::Ui); - WriteCategory(Settings::Category::UiGeneral); - - WriteStringSetting( - std::string("theme"), UISettings::values.theme, - std::make_optional(std::string( - UISettings::themes[static_cast(UISettings::default_theme)].second))); - - SaveUIGamelistValues(); - SaveUILayoutValues(); - SavePathValues(); - SaveScreenshotValues(); - SaveShortcutValues(); - SaveMultiplayerValues(); - - EndGroup(); -} - -void QtConfig::SaveUIGamelistValues() -{ - BeginGroup(Settings::TranslateCategory(Settings::Category::UiGameList)); - - WriteCategory(Settings::Category::UiGameList); - - // BeginArray(std::string("favorites")); - // for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) { - // SetArrayIndex(i); - // WriteIntegerSetting(std::string("program_id"), UISettings::values.favorited_ids[i]); - // } - // EndArray(); // favorites - - EndGroup(); -} - -void QtConfig::SaveUILayoutValues() { - BeginGroup(Settings::TranslateCategory(Settings::Category::UiLayout)); - - WriteCategory(Settings::Category::UiLayout); - - EndGroup(); -} - -void QtConfig::SaveMultiplayerValues() { - BeginGroup(std::string("Multiplayer")); - - WriteCategory(Settings::Category::Multiplayer); - - // Write ban list - BeginArray(std::string("username_ban_list")); - for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.first.size(); ++i) { - SetArrayIndex(static_cast(i)); - WriteStringSetting(std::string("username"), - UISettings::values.multiplayer_ban_list.first[i]); - } - EndArray(); // username_ban_list - - BeginArray(std::string("ip_ban_list")); - for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.second.size(); ++i) { - SetArrayIndex(static_cast(i)); - WriteStringSetting(std::string("ip"), UISettings::values.multiplayer_ban_list.second[i]); - } - EndArray(); // ip_ban_list - - EndGroup(); -} - -std::vector& QtConfig::FindRelevantList(Settings::Category category) { - auto& map = Settings::values.linkage.by_category; - if (!map[category].empty()) { - return map[category]; - } - return UISettings::values.linkage.by_category[category]; -} - -void QtConfig::ReadQtControlPlayerValues(std::size_t player_index) { - BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); - - ReadPlayerValues(player_index); - ReadQtPlayerValues(player_index); - - EndGroup(); -} - -void QtConfig::SaveQtControlPlayerValues(std::size_t player_index) { - BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); - - LOG_DEBUG(Config, "Saving players control configuration values"); - SavePlayerValues(player_index); - SaveQtPlayerValues(player_index); - - EndGroup(); - - WriteToIni(); -} diff --git a/src/eden/interface/qt_config.h b/src/eden/interface/qt_config.h deleted file mode 100644 index dc2dceb4d7..0000000000 --- a/src/eden/interface/qt_config.h +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-FileCopyrightText: 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include - -#include "frontend_common/config.h" - -class QtConfig final : public Config { -public: - explicit QtConfig(const std::string& config_name = "qt-config", - ConfigType config_type = ConfigType::GlobalConfig); - ~QtConfig() override; - - void ReloadAllValues() override; - void SaveAllValues() override; - - void ReadQtControlPlayerValues(std::size_t player_index); - void SaveQtControlPlayerValues(std::size_t player_index); - -protected: - void ReadQtValues(); - void ReadQtPlayerValues(std::size_t player_index); - void ReadQtControlValues(); - void ReadHidbusValues() override; - void ReadDebugControlValues() override; - void ReadPathValues() override; - void ReadShortcutValues() override; - void ReadUIValues() override; - void ReadUIGamelistValues() override; - void ReadUILayoutValues() override; - void ReadMultiplayerValues() override; - - void SaveQtValues(); - void SaveQtPlayerValues(std::size_t player_index); - void SaveQtControlValues(); - void SaveHidbusValues() override; - void SaveDebugControlValues() override; - void SavePathValues() override; - void SaveShortcutValues() override; - void SaveUIValues() override; - void SaveUIGamelistValues() override; - void SaveUILayoutValues() override; - void SaveMultiplayerValues() override; - - std::vector& FindRelevantList(Settings::Category category) override; - -public: - static const std::array default_buttons; - static const std::array default_motions; - static const std::array, Settings::NativeAnalog::NumAnalogs> default_analogs; - static const std::array default_stick_mod; - static const std::array default_ringcon_analogs; -}; diff --git a/src/eden/interface/shared_translation.cpp b/src/eden/interface/shared_translation.cpp deleted file mode 100644 index 59c1011465..0000000000 --- a/src/eden/interface/shared_translation.cpp +++ /dev/null @@ -1,692 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "eden/interface/shared_translation.h" - -#include -#include "common/settings.h" -#include "common/settings_enums.h" -#include "common/settings_setting.h" -#include "common/time_zone.h" -#include "yuzu/uisettings.h" -#include -#include -#include -#include - -namespace ConfigurationShared { - -std::unique_ptr InitializeTranslations(QObject* parent) -{ - std::unique_ptr translations = std::make_unique(); - const auto& tr = [parent](const char* text) -> QString { return parent->tr(text); }; - -#define INSERT(SETTINGS, ID, NAME, TOOLTIP) \ - translations->insert(std::pair{SETTINGS::values.ID.Id(), std::pair{(NAME), (TOOLTIP)}}) - - // A setting can be ignored by giving it a blank name - - // Applets - INSERT(Settings, cabinet_applet_mode, tr("Amiibo editor"), QString()); - INSERT(Settings, controller_applet_mode, tr("Controller configuration"), QString()); - INSERT(Settings, data_erase_applet_mode, tr("Data erase"), QString()); - INSERT(Settings, error_applet_mode, tr("Error"), QString()); - INSERT(Settings, net_connect_applet_mode, tr("Net connect"), QString()); - INSERT(Settings, player_select_applet_mode, tr("Player select"), QString()); - INSERT(Settings, swkbd_applet_mode, tr("Software keyboard"), QString()); - INSERT(Settings, mii_edit_applet_mode, tr("Mii Edit"), QString()); - INSERT(Settings, web_applet_mode, tr("Online web"), QString()); - INSERT(Settings, shop_applet_mode, tr("Shop"), QString()); - INSERT(Settings, photo_viewer_applet_mode, tr("Photo viewer"), QString()); - INSERT(Settings, offline_web_applet_mode, tr("Offline web"), QString()); - INSERT(Settings, login_share_applet_mode, tr("Login share"), QString()); - INSERT(Settings, wifi_web_auth_applet_mode, tr("Wifi web auth"), QString()); - INSERT(Settings, my_page_applet_mode, tr("My page"), QString()); - - // Audio - INSERT(Settings, sink_id, tr("Output Engine:"), QString()); - INSERT(Settings, audio_output_device_id, tr("Output Device:"), QString()); - INSERT(Settings, audio_input_device_id, tr("Input Device:"), QString()); - INSERT(Settings, audio_muted, tr("Mute audio"), QString()); - INSERT(Settings, volume, tr("Volume:"), QString()); - INSERT(Settings, dump_audio_commands, QString(), QString()); - INSERT(UISettings, mute_when_in_background, tr("Mute audio when in background"), QString()); - - // Core - INSERT( - Settings, - use_multi_core, - tr("Multicore CPU Emulation"), - tr("This option increases CPU emulation thread use from 1 to the Switch’s maximum of 4.\n" - "This is mainly a debug option and shouldn’t be disabled.")); - INSERT( - Settings, - memory_layout_mode, - tr("Memory Layout"), - tr("Increases the amount of emulated RAM from the stock 4GB of the retail Switch to the " - "developer kit's 8/6GB.\nIt’s doesn’t improve stability or performance and is intended " - "to let big texture mods fit in emulated RAM.\nEnabling it will increase memory " - "use. It is not recommended to enable unless a specific game with a texture mod needs " - "it.")); - INSERT(Settings, use_speed_limit, QString(), QString()); - INSERT(Settings, - speed_limit, - tr("Limit Speed Percent"), - tr("Controls the game's maximum rendering speed, but it’s up to each game if it runs " - "faster or not.\n200% for a 30 FPS game is 60 FPS, and for a " - "60 FPS game it will be 120 FPS.\nDisabling it means unlocking the framerate to the " - "maximum your PC can reach.")); - INSERT(Settings, - sync_core_speed, - tr("Synchronize Core Speed"), - tr("Synchronizes CPU core speed with the game's maximum rendering speed to boost FPS " - "without affecting game speed (animations, physics, etc.).\n" - "Compatibility varies by game; many (especially older ones) may not respond well.\n" - "Can help reduce stuttering at lower framerates.")); - - // Cpu - INSERT(Settings, - cpu_accuracy, - tr("Accuracy:"), - tr("This setting controls the accuracy of the emulated CPU.\nDon't change this unless " - "you know what you are doing.")); - INSERT(Settings, cpu_backend, tr("Backend:"), QString()); - - INSERT(Settings, use_fast_cpu_time, QString(), QString()); - INSERT(Settings, - fast_cpu_time, - tr("Fast CPU Time"), - tr("Overclocks the emulated CPU to remove some FPS limiters. Weaker CPUs may see reduced performance, " - "and certain games may behave improperly.\nUse Boost (1700MHz) to run at the Switch's highest native " - "clock, or Fast (2000MHz) to run at 2x clock.")); - INSERT(Settings, cpu_backend, tr("Backend:"), QString()); - - // Cpu Debug - - // Cpu Unsafe - INSERT( - Settings, - cpuopt_unsafe_unfuse_fma, - tr("Unfuse FMA (improve performance on CPUs without FMA)"), - tr("This option improves speed by reducing accuracy of fused-multiply-add instructions on " - "CPUs without native FMA support.")); - INSERT( - Settings, - cpuopt_unsafe_reduce_fp_error, - tr("Faster FRSQRTE and FRECPE"), - tr("This option improves the speed of some approximate floating-point functions by using " - "less accurate native approximations.")); - INSERT(Settings, - cpuopt_unsafe_ignore_standard_fpcr, - tr("Faster ASIMD instructions (32 bits only)"), - tr("This option improves the speed of 32 bits ASIMD floating-point functions by running " - "with incorrect rounding modes.")); - INSERT(Settings, - cpuopt_unsafe_inaccurate_nan, - tr("Inaccurate NaN handling"), - tr("This option improves speed by removing NaN checking.\nPlease note this also reduces " - "accuracy of certain floating-point instructions.")); - INSERT(Settings, - cpuopt_unsafe_fastmem_check, - tr("Disable address space checks"), - tr("This option improves speed by eliminating a safety check before every memory " - "read/write in guest.\nDisabling it may allow a game to read/write the emulator's " - "memory.")); - INSERT( - Settings, - cpuopt_unsafe_ignore_global_monitor, - tr("Ignore global monitor"), - tr("This option improves speed by relying only on the semantics of cmpxchg to ensure " - "safety of exclusive access instructions.\nPlease note this may result in deadlocks and " - "other race conditions.")); - - // Renderer - INSERT( - Settings, - renderer_backend, - tr("API:"), - tr("Switches between the available graphics APIs.\nVulkan is recommended in most cases.")); - INSERT(Settings, - vulkan_device, - tr("Device:"), - tr("This setting selects the GPU to use with the Vulkan backend.")); - INSERT(Settings, - shader_backend, - tr("Shader Backend:"), - tr("The shader backend to use for the OpenGL renderer.\nGLSL is the fastest in " - "performance and the best in rendering accuracy.\n" - "GLASM is a deprecated NVIDIA-only backend that offers much better shader building " - "performance at the cost of FPS and rendering accuracy.\n" - "SPIR-V compiles the fastest, but yields poor results on most GPU drivers.")); - INSERT(Settings, - resolution_setup, - tr("Resolution:"), - tr("Forces the game to render at a different resolution.\nHigher resolutions require " - "much more VRAM and bandwidth.\n" - "Options lower than 1X can cause rendering issues.")); - INSERT(Settings, scaling_filter, tr("Window Adapting Filter:"), QString()); - INSERT(Settings, - fsr_sharpening_slider, - tr("FSR Sharpness:"), - tr("Determines how sharpened the image will look while using FSR’s dynamic contrast.")); - INSERT(Settings, - anti_aliasing, - tr("Anti-Aliasing Method:"), - tr("The anti-aliasing method to use.\nSMAA offers the best quality.\nFXAA has a " - "lower performance impact and can produce a better and more stable picture under " - "very low resolutions.")); - INSERT(Settings, - fullscreen_mode, - tr("Fullscreen Mode:"), - tr("The method used to render the window in fullscreen.\nBorderless offers the best " - "compatibility with the on-screen keyboard that some games request for " - "input.\nExclusive " - "fullscreen may offer better performance and better Freesync/Gsync support.")); - INSERT(Settings, - aspect_ratio, - tr("Aspect Ratio:"), - tr("Stretches the game to fit the specified aspect ratio.\nSwitch games only support " - "16:9, so custom game mods are required to get other ratios.\nAlso controls the " - "aspect ratio of captured screenshots.")); - INSERT(Settings, - use_disk_shader_cache, - tr("Use disk pipeline cache"), - tr("Allows saving shaders to storage for faster loading on following game " - "boots.\nDisabling " - "it is only intended for debugging.")); - INSERT(Settings, - optimize_spirv_output, - tr("Optimize SPIRV output shader"), - tr("Runs an additional optimization pass over generated SPIRV shaders.\n" - "Will increase time required for shader compilation.\nMay slightly improve " - "performance.\nThis feature is experimental.")); - INSERT( - Settings, - use_asynchronous_gpu_emulation, - tr("Use asynchronous GPU emulation"), - tr("Uses an extra CPU thread for rendering.\nThis option should always remain enabled.")); - INSERT(Settings, - nvdec_emulation, - tr("NVDEC emulation:"), - tr("Specifies how videos should be decoded.\nIt can either use the CPU or the GPU for " - "decoding, or perform no decoding at all (black screen on videos).\n" - "In most cases, GPU decoding provides the best performance.")); - INSERT(Settings, - accelerate_astc, - tr("ASTC Decoding Method:"), - tr("This option controls how ASTC textures should be decoded.\n" - "CPU: Use the CPU for decoding, slowest but safest method.\n" - "GPU: Use the GPU's compute shaders to decode ASTC textures, recommended for most " - "games and users.\n" - "CPU Asynchronously: Use the CPU to decode ASTC textures as they arrive. Completely " - "eliminates ASTC decoding\nstuttering at the cost of rendering issues while the " - "texture is being decoded.")); - INSERT( - Settings, - astc_recompression, - tr("ASTC Recompression Method:"), - tr("Almost all desktop and laptop dedicated GPUs lack support for ASTC textures, forcing " - "the emulator to decompress to an intermediate format any card supports, RGBA8.\n" - "This option recompresses RGBA8 to either the BC1 or BC3 format, saving VRAM but " - "negatively affecting image quality.")); - INSERT(Settings, - vram_usage_mode, - tr("VRAM Usage Mode:"), - tr("Selects whether the emulator should prefer to conserve memory or make maximum usage " - "of available video memory for performance. Has no effect on integrated graphics. " - "Aggressive mode may severely impact the performance of other applications such as " - "recording software.")); - INSERT( - Settings, - vsync_mode, - tr("VSync Mode:"), - tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen " - "refresh rate.\nFIFO Relaxed is similar to FIFO but allows tearing as it recovers from " - "a slow down.\nMailbox can have lower latency than FIFO and does not tear but may drop " - "frames.\nImmediate (no synchronization) just presents whatever is available and can " - "exhibit tearing.")); - INSERT(Settings, bg_red, QString(), QString()); - INSERT(Settings, bg_green, QString(), QString()); - INSERT(Settings, bg_blue, QString(), QString()); - - // Renderer (Advanced Graphics) - INSERT(Settings, - async_presentation, - tr("Enable asynchronous presentation (Vulkan only)"), - tr("Slightly improves performance by moving presentation to a separate CPU thread.")); - INSERT( - Settings, - renderer_force_max_clock, - tr("Force maximum clocks (Vulkan only)"), - tr("Runs work in the background while waiting for graphics commands to keep the GPU from " - "lowering its clock speed.")); - INSERT(Settings, - max_anisotropy, - tr("Anisotropic Filtering:"), - tr("Controls the quality of texture rendering at oblique angles.\nIt’s a light setting " - "and safe to set at 16x on most GPUs.")); - INSERT(Settings, - gpu_accuracy, - tr("Accuracy Level:"), - tr("GPU emulation accuracy.\nMost games render fine with Normal, but High is still " - "required for some.\nParticles tend to only render correctly with High " - "accuracy.\nExtreme should only be used for debugging.\nThis option can " - "be changed while playing.\nSome games may require booting on high to render " - "properly.")); - INSERT(Settings, - use_asynchronous_shaders, - tr("Use asynchronous shader building (Hack)"), - tr("Enables asynchronous shader compilation, which may reduce shader stutter.\nThis " - "feature " - "is experimental.")); - INSERT(Settings, use_fast_gpu_time, QString(), QString()); - INSERT(Settings, - fast_gpu_time, - tr("Fast GPU Time (Hack)"), - tr("Overclocks the emulated GPU to increase dynamic resolution and render " - "distance.\nUse 128 for maximal performance and 512 for maximal graphics fidelity.")); - - INSERT(Settings, - use_vulkan_driver_pipeline_cache, - tr("Use Vulkan pipeline cache"), - tr("Enables GPU vendor-specific pipeline cache.\nThis option can improve shader loading " - "time significantly in cases where the Vulkan driver does not store pipeline cache " - "files internally.")); - INSERT( - Settings, - enable_compute_pipelines, - tr("Enable Compute Pipelines (Intel Vulkan Only)"), - tr("Enable compute pipelines, required by some games.\nThis setting only exists for Intel " - "proprietary drivers, and may crash if enabled.\nCompute pipelines are always enabled " - "on all other drivers.")); - INSERT( - Settings, - use_reactive_flushing, - tr("Enable Reactive Flushing"), - tr("Uses reactive flushing instead of predictive flushing, allowing more accurate memory " - "syncing.")); - INSERT(Settings, - use_video_framerate, - tr("Sync to framerate of video playback"), - tr("Run the game at normal speed during video playback, even when the framerate is " - "unlocked.")); - INSERT(Settings, - barrier_feedback_loops, - tr("Barrier feedback loops"), - tr("Improves rendering of transparency effects in specific games.")); - - // Renderer (Extensions) - INSERT(Settings, - dyna_state, - tr("Extended Dynamic State"), - tr("Enables the VkExtendedDynamicState* extensions.\nHigher dynamic states will " - "generally improve " - "performance, but may cause issues on certain games or devices.")); - - INSERT(Settings, - provoking_vertex, - tr("Provoking Vertex"), - tr("Improves lighting and vertex handling in certain games.\n" - "Only Vulkan 1.0+ devices support this extension.")); - - INSERT(Settings, - descriptor_indexing, - tr("Descriptor Indexing"), - tr("Improves texture & buffer handling and the Maxwell translation layer.\n" - "Some Vulkan 1.1+ and all 1.2+ devices support this extension.")); - - // Renderer (Debug) - - // System - INSERT(Settings, - rng_seed, - tr("RNG Seed"), - tr("Controls the seed of the random number generator.\nMainly used for speedrunning " - "purposes.")); - INSERT(Settings, rng_seed_enabled, QString(), QString()); - INSERT(Settings, device_name, tr("Device Name"), tr("The name of the emulated Switch.")); - INSERT(Settings, - custom_rtc, - tr("Custom RTC Date:"), - tr("This option allows to change the emulated clock of the Switch.\n" - "Can be used to manipulate time in games.")); - INSERT(Settings, custom_rtc_enabled, QString(), QString()); - INSERT(Settings, - custom_rtc_offset, - QStringLiteral(" "), - QStringLiteral("The number of seconds from the current unix time")); - INSERT(Settings, - language_index, - tr("Language:"), - tr("Note: this can be overridden when region setting is auto-select")); - INSERT(Settings, region_index, tr("Region:"), tr("The region of the emulated Switch.")); - INSERT(Settings, time_zone_index, tr("Time Zone:"), tr("The time zone of the emulated Switch.")); - INSERT(Settings, sound_index, tr("Sound Output Mode:"), QString()); - INSERT(Settings, - use_docked_mode, - tr("Console Mode:"), - tr("Selects if the console is emulated in Docked or Handheld mode.\nGames will change " - "their resolution, details and supported controllers and depending on this setting.\n" - "Setting to Handheld can help improve performance for low end systems.")); - INSERT(Settings, current_user, QString(), QString()); - - // Controls - - // Data Storage - - // Debugging - - // Debugging Graphics - - // Network - - // Web Service - - // Ui - - // Ui General - INSERT(UISettings, - select_user_on_boot, - tr("Prompt for user on game boot"), - tr("Ask to select a user profile on each boot, useful if multiple people use eden on " - "the same PC.")); - INSERT(UISettings, - pause_when_in_background, - tr("Pause emulation when in background"), - tr("This setting pauses eden when focusing other windows.")); - INSERT(UISettings, - confirm_before_stopping, - tr("Confirm before stopping emulation"), - tr("This setting overrides game prompts asking to confirm stopping the game.\nEnabling " - "it bypasses such prompts and directly exits the emulation.")); - INSERT(UISettings, - hide_mouse, - tr("Hide mouse on inactivity"), - tr("This setting hides the mouse after 2.5s of inactivity.")); - INSERT(UISettings, - controller_applet_disabled, - tr("Disable controller applet"), - tr("Forcibly disables the use of the controller applet by guests.\nWhen a guest " - "attempts to open the controller applet, it is immediately closed.")); - INSERT(UISettings, - check_for_updates, - tr("Check for updates"), - tr("Whether or not to check for updates upon startup.")); - - // Linux - INSERT(Settings, enable_gamemode, tr("Enable Gamemode"), QString()); - - // Ui Debugging - - // Ui Multiplayer - - // Ui Games list - -#undef INSERT - - return translations; -} - -std::unique_ptr ComboboxEnumeration(QObject* parent) -{ - std::unique_ptr translations = std::make_unique(); - const auto& tr = [&](const char* text, const char* context = "") { - return parent->tr(text, context); - }; - -#define PAIR(ENUM, VALUE, TRANSLATION) {static_cast(Settings::ENUM::VALUE), (TRANSLATION)} - - // Intentionally skipping VSyncMode to let the UI fill that one out - translations->insert({Settings::EnumMetadata::Index(), - { - PAIR(AppletMode, HLE, tr("Custom frontend")), - PAIR(AppletMode, LLE, tr("Real applet")), - }}); - translations->insert({Settings::EnumMetadata::Index(), - { - PAIR(SpirvOptimizeMode, Never, tr("Never")), - PAIR(SpirvOptimizeMode, OnLoad, tr("On Load")), - PAIR(SpirvOptimizeMode, Always, tr("Always")), - }}); - translations->insert({Settings::EnumMetadata::Index(), - { - PAIR(AstcDecodeMode, Cpu, tr("CPU")), - PAIR(AstcDecodeMode, Gpu, tr("GPU")), - PAIR(AstcDecodeMode, CpuAsynchronous, tr("CPU Asynchronous")), - }}); - translations->insert( - {Settings::EnumMetadata::Index(), - { - PAIR(AstcRecompression, Uncompressed, tr("Uncompressed (Best quality)")), - PAIR(AstcRecompression, Bc1, tr("BC1 (Low quality)")), - PAIR(AstcRecompression, Bc3, tr("BC3 (Medium quality)")), - }}); - translations->insert({Settings::EnumMetadata::Index(), - { - PAIR(VramUsageMode, Conservative, tr("Conservative")), - PAIR(VramUsageMode, Aggressive, tr("Aggressive")), - }}); - translations->insert({Settings::EnumMetadata::Index(), - { -#ifdef HAS_OPENGL - PAIR(RendererBackend, OpenGL, tr("OpenGL")), -#endif - PAIR(RendererBackend, Vulkan, tr("Vulkan")), - PAIR(RendererBackend, Null, tr("Null")), - }}); - translations->insert( - {Settings::EnumMetadata::Index(), - { - PAIR(ShaderBackend, Glsl, tr("GLSL")), - PAIR(ShaderBackend, Glasm, tr("GLASM (Assembly Shaders, NVIDIA Only)")), - PAIR(ShaderBackend, SpirV, tr("SPIR-V (Experimental, AMD/Mesa Only)")), - }}); - translations->insert({Settings::EnumMetadata::Index(), - { - PAIR(GpuAccuracy, Normal, tr("Normal")), - PAIR(GpuAccuracy, High, tr("High")), - PAIR(GpuAccuracy, Extreme, tr("Extreme")), - }}); - translations->insert( - {Settings::EnumMetadata::Index(), - { - PAIR(CpuAccuracy, Auto, tr("Auto")), - PAIR(CpuAccuracy, Accurate, tr("Accurate")), - PAIR(CpuAccuracy, Unsafe, tr("Unsafe")), - PAIR(CpuAccuracy, Paranoid, tr("Paranoid (disables most optimizations)")), - }}); - translations->insert({Settings::EnumMetadata::Index(), - { - PAIR(CpuBackend, Dynarmic, tr("Dynarmic")), - PAIR(CpuBackend, Nce, tr("NCE")), - }}); - translations->insert({Settings::EnumMetadata::Index(), - { - PAIR(FullscreenMode, Borderless, tr("Borderless Windowed")), - PAIR(FullscreenMode, Exclusive, tr("Exclusive Fullscreen")), - }}); - translations->insert({Settings::EnumMetadata::Index(), - { - PAIR(NvdecEmulation, Off, tr("No Video Output")), - PAIR(NvdecEmulation, Cpu, tr("CPU Video Decoding")), - PAIR(NvdecEmulation, Gpu, tr("GPU Video Decoding (Default)")), - }}); - translations->insert( - {Settings::EnumMetadata::Index(), - { - PAIR(ResolutionSetup, Res1_4X, tr("0.25X (180p/270p) [EXPERIMENTAL]")), - PAIR(ResolutionSetup, Res1_2X, tr("0.5X (360p/540p) [EXPERIMENTAL]")), - PAIR(ResolutionSetup, Res3_4X, tr("0.75X (540p/810p) [EXPERIMENTAL]")), - PAIR(ResolutionSetup, Res1X, tr("1X (720p/1080p)")), - PAIR(ResolutionSetup, Res3_2X, tr("1.5X (1080p/1620p) [EXPERIMENTAL]")), - PAIR(ResolutionSetup, Res2X, tr("2X (1440p/2160p)")), - PAIR(ResolutionSetup, Res3X, tr("3X (2160p/3240p)")), - PAIR(ResolutionSetup, Res4X, tr("4X (2880p/4320p)")), - PAIR(ResolutionSetup, Res5X, tr("5X (3600p/5400p)")), - PAIR(ResolutionSetup, Res6X, tr("6X (4320p/6480p)")), - PAIR(ResolutionSetup, Res7X, tr("7X (5040p/7560p)")), - PAIR(ResolutionSetup, Res8X, tr("8X (5760p/8640p)")), - }}); - translations->insert({Settings::EnumMetadata::Index(), - { - PAIR(ScalingFilter, NearestNeighbor, tr("Nearest Neighbor")), - PAIR(ScalingFilter, Bilinear, tr("Bilinear")), - PAIR(ScalingFilter, Bicubic, tr("Bicubic")), - PAIR(ScalingFilter, Gaussian, tr("Gaussian")), - PAIR(ScalingFilter, ScaleForce, tr("ScaleForce")), - PAIR(ScalingFilter, Fsr, tr("AMD FidelityFX™️ Super Resolution")), - }}); - translations->insert({Settings::EnumMetadata::Index(), - { - PAIR(AntiAliasing, None, tr("None")), - PAIR(AntiAliasing, Fxaa, tr("FXAA")), - PAIR(AntiAliasing, Smaa, tr("SMAA")), - }}); - translations->insert({Settings::EnumMetadata::Index(), - { - PAIR(AspectRatio, R16_9, tr("Default (16:9)")), - PAIR(AspectRatio, R4_3, tr("Force 4:3")), - PAIR(AspectRatio, R21_9, tr("Force 21:9")), - PAIR(AspectRatio, R16_10, tr("Force 16:10")), - PAIR(AspectRatio, Stretch, tr("Stretch to Window")), - }}); - translations->insert({Settings::EnumMetadata::Index(), - { - PAIR(AnisotropyMode, Automatic, tr("Automatic")), - PAIR(AnisotropyMode, Default, tr("Default")), - PAIR(AnisotropyMode, X2, tr("2x")), - PAIR(AnisotropyMode, X4, tr("4x")), - PAIR(AnisotropyMode, X8, tr("8x")), - PAIR(AnisotropyMode, X16, tr("16x")), - }}); - translations->insert( - {Settings::EnumMetadata::Index(), - { - PAIR(Language, Japanese, tr("Japanese (日本語)")), - PAIR(Language, EnglishAmerican, tr("American English")), - PAIR(Language, French, tr("French (français)")), - PAIR(Language, German, tr("German (Deutsch)")), - PAIR(Language, Italian, tr("Italian (italiano)")), - PAIR(Language, Spanish, tr("Spanish (español)")), - PAIR(Language, Chinese, tr("Chinese")), - PAIR(Language, Korean, tr("Korean (한국어)")), - PAIR(Language, Dutch, tr("Dutch (Nederlands)")), - PAIR(Language, Portuguese, tr("Portuguese (português)")), - PAIR(Language, Russian, tr("Russian (Русский)")), - PAIR(Language, Taiwanese, tr("Taiwanese")), - PAIR(Language, EnglishBritish, tr("British English")), - PAIR(Language, FrenchCanadian, tr("Canadian French")), - PAIR(Language, SpanishLatin, tr("Latin American Spanish")), - PAIR(Language, ChineseSimplified, tr("Simplified Chinese")), - PAIR(Language, ChineseTraditional, tr("Traditional Chinese (正體中文)")), - PAIR(Language, PortugueseBrazilian, tr("Brazilian Portuguese (português do Brasil)")), - }}); - translations->insert({Settings::EnumMetadata::Index(), - { - PAIR(Region, Japan, tr("Japan")), - PAIR(Region, Usa, tr("USA")), - PAIR(Region, Europe, tr("Europe")), - PAIR(Region, Australia, tr("Australia")), - PAIR(Region, China, tr("China")), - PAIR(Region, Korea, tr("Korea")), - PAIR(Region, Taiwan, tr("Taiwan")), - }}); - translations->insert( - {Settings::EnumMetadata::Index(), - { - {static_cast(Settings::TimeZone::Auto), - tr("Auto (%1)", "Auto select time zone") - .arg(QString::fromStdString( - Settings::GetTimeZoneString(Settings::TimeZone::Auto)))}, - {static_cast(Settings::TimeZone::Default), - tr("Default (%1)", "Default time zone") - .arg(QString::fromStdString(Common::TimeZone::GetDefaultTimeZone()))}, - PAIR(TimeZone, Cet, tr("CET")), - PAIR(TimeZone, Cst6Cdt, tr("CST6CDT")), - PAIR(TimeZone, Cuba, tr("Cuba")), - PAIR(TimeZone, Eet, tr("EET")), - PAIR(TimeZone, Egypt, tr("Egypt")), - PAIR(TimeZone, Eire, tr("Eire")), - PAIR(TimeZone, Est, tr("EST")), - PAIR(TimeZone, Est5Edt, tr("EST5EDT")), - PAIR(TimeZone, Gb, tr("GB")), - PAIR(TimeZone, GbEire, tr("GB-Eire")), - PAIR(TimeZone, Gmt, tr("GMT")), - PAIR(TimeZone, GmtPlusZero, tr("GMT+0")), - PAIR(TimeZone, GmtMinusZero, tr("GMT-0")), - PAIR(TimeZone, GmtZero, tr("GMT0")), - PAIR(TimeZone, Greenwich, tr("Greenwich")), - PAIR(TimeZone, Hongkong, tr("Hongkong")), - PAIR(TimeZone, Hst, tr("HST")), - PAIR(TimeZone, Iceland, tr("Iceland")), - PAIR(TimeZone, Iran, tr("Iran")), - PAIR(TimeZone, Israel, tr("Israel")), - PAIR(TimeZone, Jamaica, tr("Jamaica")), - PAIR(TimeZone, Japan, tr("Japan")), - PAIR(TimeZone, Kwajalein, tr("Kwajalein")), - PAIR(TimeZone, Libya, tr("Libya")), - PAIR(TimeZone, Met, tr("MET")), - PAIR(TimeZone, Mst, tr("MST")), - PAIR(TimeZone, Mst7Mdt, tr("MST7MDT")), - PAIR(TimeZone, Navajo, tr("Navajo")), - PAIR(TimeZone, Nz, tr("NZ")), - PAIR(TimeZone, NzChat, tr("NZ-CHAT")), - PAIR(TimeZone, Poland, tr("Poland")), - PAIR(TimeZone, Portugal, tr("Portugal")), - PAIR(TimeZone, Prc, tr("PRC")), - PAIR(TimeZone, Pst8Pdt, tr("PST8PDT")), - PAIR(TimeZone, Roc, tr("ROC")), - PAIR(TimeZone, Rok, tr("ROK")), - PAIR(TimeZone, Singapore, tr("Singapore")), - PAIR(TimeZone, Turkey, tr("Turkey")), - PAIR(TimeZone, Uct, tr("UCT")), - PAIR(TimeZone, Universal, tr("Universal")), - PAIR(TimeZone, Utc, tr("UTC")), - PAIR(TimeZone, WSu, tr("W-SU")), - PAIR(TimeZone, Wet, tr("WET")), - PAIR(TimeZone, Zulu, tr("Zulu")), - }}); - translations->insert({Settings::EnumMetadata::Index(), - { - PAIR(AudioMode, Mono, tr("Mono")), - PAIR(AudioMode, Stereo, tr("Stereo")), - PAIR(AudioMode, Surround, tr("Surround")), - }}); - translations->insert({Settings::EnumMetadata::Index(), - { - PAIR(MemoryLayout, Memory_4Gb, tr("4GB DRAM (Default)")), - PAIR(MemoryLayout, Memory_6Gb, tr("6GB DRAM (Unsafe)")), - PAIR(MemoryLayout, Memory_8Gb, tr("8GB DRAM")), - PAIR(MemoryLayout, Memory_10Gb, tr("10GB DRAM (Unsafe)")), - PAIR(MemoryLayout, Memory_12Gb, tr("12GB DRAM (Unsafe)")), - }}); - translations->insert({Settings::EnumMetadata::Index(), - { - PAIR(ConsoleMode, Docked, tr("Docked")), - PAIR(ConsoleMode, Handheld, tr("Handheld")), - }}); - translations->insert({Settings::EnumMetadata::Index(), - { - PAIR(CpuClock, Boost, tr("Boost (1700MHz)")), - PAIR(CpuClock, Fast, tr("Fast (2000MHz)")), - }}); - translations->insert( - {Settings::EnumMetadata::Index(), - { - PAIR(ConfirmStop, Ask_Always, tr("Always ask (Default)")), - PAIR(ConfirmStop, Ask_Based_On_Game, tr("Only if game specifies not to stop")), - PAIR(ConfirmStop, Ask_Never, tr("Never ask")), - }}); - translations->insert({Settings::EnumMetadata::Index(), - { - PAIR(GpuOverclock, Low, tr("Low (128)")), - PAIR(GpuOverclock, Medium, tr("Medium (256)")), - PAIR(GpuOverclock, High, tr("High (512)")), - }}); - -#undef PAIR -#undef CTX_PAIR - - return translations; -} -} // namespace ConfigurationShared diff --git a/src/eden/interface/shared_translation.h b/src/eden/interface/shared_translation.h deleted file mode 100644 index bfd508372b..0000000000 --- a/src/eden/interface/shared_translation.h +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include -#include -#include -#include -#include "common/common_types.h" -#include "common/settings.h" - -namespace ConfigurationShared { -using TranslationMap = std::map>; -using ComboboxTranslations = std::vector>; -using ComboboxTranslationMap = std::map; - -std::unique_ptr InitializeTranslations(QObject *parent); - -std::unique_ptr ComboboxEnumeration(QObject *parent); - -static const std::map anti_aliasing_texts_map = { - {Settings::AntiAliasing::None, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "None"))}, - {Settings::AntiAliasing::Fxaa, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FXAA"))}, - {Settings::AntiAliasing::Smaa, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SMAA"))}, -}; - -static const std::map scaling_filter_texts_map = { - {Settings::ScalingFilter::NearestNeighbor, - QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Nearest"))}, - {Settings::ScalingFilter::Bilinear, - QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Bilinear"))}, - {Settings::ScalingFilter::Bicubic, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Bicubic"))}, - {Settings::ScalingFilter::Gaussian, - QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Gaussian"))}, - {Settings::ScalingFilter::ScaleForce, - QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "ScaleForce"))}, - {Settings::ScalingFilter::Fsr, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FSR"))}, -}; - -static const std::map use_docked_mode_texts_map = { - {Settings::ConsoleMode::Docked, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Docked"))}, - {Settings::ConsoleMode::Handheld, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Handheld"))}, -}; - -static const std::map gpu_accuracy_texts_map = { - {Settings::GpuAccuracy::Normal, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Normal"))}, - {Settings::GpuAccuracy::High, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "High"))}, - {Settings::GpuAccuracy::Extreme, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Extreme"))}, -}; - -static const std::map renderer_backend_texts_map = { - {Settings::RendererBackend::Vulkan, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Vulkan"))}, - {Settings::RendererBackend::OpenGL, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "OpenGL"))}, - {Settings::RendererBackend::Null, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Null"))}, -}; - -static const std::map shader_backend_texts_map = { - {Settings::ShaderBackend::Glsl, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLSL"))}, - {Settings::ShaderBackend::Glasm, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLASM"))}, - {Settings::ShaderBackend::SpirV, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SPIRV"))}, -}; - -} // namespace ConfigurationShared diff --git a/src/eden/interface/uisettings.cpp b/src/eden/interface/uisettings.cpp deleted file mode 100644 index f5203de421..0000000000 --- a/src/eden/interface/uisettings.cpp +++ /dev/null @@ -1,112 +0,0 @@ -// SPDX-FileCopyrightText: 2016 Citra Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "uisettings.h" -#include -#include "common/fs/fs.h" -#include "common/fs/path_util.h" - -#ifndef CANNOT_EXPLICITLY_INSTANTIATE -namespace Settings { -template class Setting; -template class Setting; -template class Setting; -template class Setting; -template class Setting; -template class Setting; -template class Setting; -} // namespace Settings -#endif - -namespace FS = Common::FS; - -namespace UISettings { - -const Themes themes{{ - {"Default", "default"}, - {"Default Colorful", "colorful"}, - {"Dark", "qdarkstyle"}, - {"Dark Colorful", "colorful_dark"}, - {"Midnight Blue", "qdarkstyle_midnight_blue"}, - {"Midnight Blue Colorful", "colorful_midnight_blue"}, -}}; - -bool IsDarkTheme() { - const auto& theme = UISettings::values.theme; - return theme == std::string("qdarkstyle") || theme == std::string("qdarkstyle_midnight_blue") || - theme == std::string("colorful_dark") || theme == std::string("colorful_midnight_blue"); -} - -Values values = {}; - -u32 CalculateWidth(u32 height, Settings::AspectRatio ratio) { - switch (ratio) { - case Settings::AspectRatio::R4_3: - return height * 4 / 3; - case Settings::AspectRatio::R21_9: - return height * 21 / 9; - case Settings::AspectRatio::R16_10: - return height * 16 / 10; - case Settings::AspectRatio::R16_9: - case Settings::AspectRatio::Stretch: - // TODO: Move this function wherever appropriate to implement Stretched aspect - break; - } - return height * 16 / 9; -} - -void SaveWindowState() { - const auto window_state_config_loc = - FS::PathToUTF8String(FS::GetEdenPath(FS::EdenPath::ConfigDir) / "window_state.ini"); - - void(FS::CreateParentDir(window_state_config_loc)); - QSettings config(QString::fromStdString(window_state_config_loc), QSettings::IniFormat); - - config.setValue(QStringLiteral("geometry"), values.geometry); - config.setValue(QStringLiteral("state"), values.state); - config.setValue(QStringLiteral("geometryRenderWindow"), values.renderwindow_geometry); - config.setValue(QStringLiteral("gameListHeaderState"), values.gamelist_header_state); - config.setValue(QStringLiteral("microProfileDialogGeometry"), values.microprofile_geometry); - - config.sync(); -} - -void RestoreWindowState(std::unique_ptr& qtConfig) { - const auto window_state_config_loc = - FS::PathToUTF8String(FS::GetEdenPath(FS::EdenPath::ConfigDir) / "window_state.ini"); - - // Migrate window state from old location - if (!FS::Exists(window_state_config_loc) && qtConfig->Exists("UI", "UILayout\\geometry")) { - const auto config_loc = - FS::PathToUTF8String(FS::GetEdenPath(FS::EdenPath::ConfigDir) / "qt-config.ini"); - QSettings config(QString::fromStdString(config_loc), QSettings::IniFormat); - - config.beginGroup(QStringLiteral("UI")); - config.beginGroup(QStringLiteral("UILayout")); - values.geometry = config.value(QStringLiteral("geometry")).toByteArray(); - values.state = config.value(QStringLiteral("state")).toByteArray(); - values.renderwindow_geometry = - config.value(QStringLiteral("geometryRenderWindow")).toByteArray(); - values.gamelist_header_state = - config.value(QStringLiteral("gameListHeaderState")).toByteArray(); - values.microprofile_geometry = - config.value(QStringLiteral("microProfileDialogGeometry")).toByteArray(); - config.endGroup(); - config.endGroup(); - return; - } - - void(FS::CreateParentDir(window_state_config_loc)); - const QSettings config(QString::fromStdString(window_state_config_loc), QSettings::IniFormat); - - values.geometry = config.value(QStringLiteral("geometry")).toByteArray(); - values.state = config.value(QStringLiteral("state")).toByteArray(); - values.renderwindow_geometry = - config.value(QStringLiteral("geometryRenderWindow")).toByteArray(); - values.gamelist_header_state = - config.value(QStringLiteral("gameListHeaderState")).toByteArray(); - values.microprofile_geometry = - config.value(QStringLiteral("microProfileDialogGeometry")).toByteArray(); -} - -} // namespace UISettings diff --git a/src/eden/interface/uisettings.h b/src/eden/interface/uisettings.h deleted file mode 100644 index aaedb99e8b..0000000000 --- a/src/eden/interface/uisettings.h +++ /dev/null @@ -1,288 +0,0 @@ -// SPDX-FileCopyrightText: 2016 Citra Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include -#include -#include -#include -#include "common/common_types.h" -#include "common/settings.h" -#include "common/settings_enums.h" -#include "qt_config.h" -#include -#include -#include - -using Settings::Category; -using Settings::ConfirmStop; -using Settings::Setting; -using Settings::SwitchableSetting; - -#ifndef CANNOT_EXPLICITLY_INSTANTIATE -namespace Settings { -extern template class Setting; -extern template class Setting; -extern template class Setting; -extern template class Setting; -extern template class Setting; -extern template class Setting; -extern template class Setting; -} // namespace Settings -#endif - -namespace UISettings { - -bool IsDarkTheme(); - -struct ContextualShortcut { - std::string keyseq; - std::string controller_keyseq; - int context; - bool repeat; -}; - -struct Shortcut { - std::string name; - std::string group; - ContextualShortcut shortcut; -}; - -enum class Theme { - Default, - DefaultColorful, - Dark, - DarkColorful, - MidnightBlue, - MidnightBlueColorful, -}; - -enum class GameView { - Grid, - List, - Carousel, -}; - -static constexpr Theme default_theme{ -#ifdef _WIN32 - Theme::DarkColorful -#else - Theme::DefaultColorful -#endif -}; - -using Themes = std::array, 6>; -extern const Themes themes; - -struct GameDir { - std::string path; - bool deep_scan = false; - bool expanded = false; - bool operator==(const GameDir& rhs) const { - return path == rhs.path; - } - bool operator!=(const GameDir& rhs) const { - return !operator==(rhs); - } -}; - -struct Values { - Settings::Linkage linkage{1000}; - - QByteArray geometry; - QByteArray state; - - QByteArray renderwindow_geometry; - - QByteArray gamelist_header_state; - - QByteArray microprofile_geometry; - Setting microprofile_visible{linkage, false, "microProfileDialogVisible", - Category::UiLayout}; - - Setting single_window_mode{linkage, true, "singleWindowMode", Category::Ui}; - Setting fullscreen{linkage, false, "fullscreen", Category::Ui}; - Setting display_titlebar{linkage, true, "displayTitleBars", Category::Ui}; - Setting show_filter_bar{linkage, true, "showFilterBar", Category::Ui}; - Setting show_status_bar{linkage, true, "showStatusBar", Category::Ui}; - - SwitchableSetting confirm_before_stopping{linkage, - ConfirmStop::Ask_Always, - "confirmStop", - Category::UiGeneral, - Settings::Specialization::Default, - true, - true}; - - Setting first_start{linkage, true, "firstStart", Category::Ui}; - Setting pause_when_in_background{linkage, - false, - "pauseWhenInBackground", - Category::UiGeneral, - Settings::Specialization::Default, - true, - true}; - Setting mute_when_in_background{linkage, - false, - "muteWhenInBackground", - Category::UiAudio, - Settings::Specialization::Default, - true, - true}; - Setting hide_mouse{ - linkage, true, "hideInactiveMouse", Category::UiGeneral, Settings::Specialization::Default, - true, true}; - Setting controller_applet_disabled{linkage, false, "disableControllerApplet", - Category::UiGeneral}; - // Set when Vulkan is known to crash the application - bool has_broken_vulkan = false; - - Setting select_user_on_boot{linkage, - false, - "select_user_on_boot", - Category::UiGeneral, - Settings::Specialization::Default, - true, - true}; - Setting disable_web_applet{linkage, true, "disable_web_applet", Category::Ui}; - - // Discord RPC - Setting enable_discord_presence{linkage, false, "enable_discord_presence", Category::Ui}; - - // logging - Setting show_console{linkage, false, "showConsole", Category::Ui}; - - // Screenshots - Setting enable_screenshot_save_as{linkage, true, "enable_screenshot_save_as", - Category::Screenshots}; - Setting screenshot_height{linkage, 0, "screenshot_height", Category::Screenshots}; - - std::string roms_path; - std::string game_dir_deprecated; - bool game_dir_deprecated_deepscan; - QVector game_dirs; - QStringList recent_files; - Setting language{linkage, {}, "language", Category::Paths}; - - std::string theme; - - // Shortcut name - std::vector shortcuts; - - Setting callout_flags{linkage, 0, "calloutFlags", Category::Ui}; - - // multiplayer settings - Setting multiplayer_nickname{linkage, {}, "nickname", Category::Multiplayer}; - Setting multiplayer_filter_text{linkage, {}, "filter_text", Category::Multiplayer}; - Setting multiplayer_filter_games_owned{linkage, false, "filter_games_owned", - Category::Multiplayer}; - Setting multiplayer_filter_hide_empty{linkage, false, "filter_games_hide_empty", - Category::Multiplayer}; - Setting multiplayer_filter_hide_full{linkage, false, "filter_games_hide_full", - Category::Multiplayer}; - Setting multiplayer_ip{linkage, {}, "ip", Category::Multiplayer}; - Setting multiplayer_port{linkage, 24872, 0, - UINT16_MAX, "port", Category::Multiplayer}; - Setting multiplayer_room_nickname{ - linkage, {}, "room_nickname", Category::Multiplayer}; - Setting multiplayer_room_name{linkage, {}, "room_name", Category::Multiplayer}; - Setting multiplayer_max_player{linkage, 8, 0, 8, "max_player", Category::Multiplayer}; - Setting multiplayer_room_port{linkage, 24872, 0, - UINT16_MAX, "room_port", Category::Multiplayer}; - Setting multiplayer_host_type{linkage, 0, 0, 1, "host_type", Category::Multiplayer}; - Setting multiplayer_game_id{linkage, {}, "game_id", Category::Multiplayer}; - Setting multiplayer_room_description{ - linkage, {}, "room_description", Category::Multiplayer}; - std::pair, std::vector> multiplayer_ban_list; - - // Game List - // Setting show_add_ons{linkage, true, "show_add_ons", Category::UiGameList}; - // Setting game_icon_size{linkage, 64, "game_icon_size", Category::UiGameList}; - // Setting folder_icon_size{linkage, 48, "folder_icon_size", Category::UiGameList}; - // Setting row_1_text_id{linkage, 3, "row_1_text_id", Category::UiGameList}; - // Setting row_2_text_id{linkage, 2, "row_2_text_id", Category::UiGameList}; - // std::atomic_bool is_game_list_reload_pending{false}; - // Setting cache_game_list{linkage, true, "cache_game_list", Category::UiGameList}; - // Setting favorites_expanded{linkage, true, "favorites_expanded", Category::UiGameList}; - // QVector favorited_ids; - - Setting grid_columns{linkage, 4, 1, 8, "grid_columns", Category::UiGameList}; - - // Compatibility List - Setting show_compat{linkage, false, "show_compat", Category::UiGameList}; - - // Size & File Types Column - Setting show_size{linkage, true, "show_size", Category::UiGameList}; - Setting show_types{linkage, true, "show_types", Category::UiGameList}; - - // Play time - Setting show_play_time{linkage, true, "show_play_time", Category::UiGameList}; - - bool configuration_applied; - bool reset_to_defaults; - bool shortcut_already_warned{false}; -}; - -extern Values values; - -u32 CalculateWidth(u32 height, Settings::AspectRatio ratio); - -void SaveWindowState(); -void RestoreWindowState(std::unique_ptr& qtConfig); - -// This shouldn't have anything except static initializers (no functions). So -// QKeySequence(...).toString() is NOT ALLOWED HERE. -// This must be in alphabetical order according to action name as it must have the same order as -// UISetting::values.shortcuts, which is alphabetically ordered. -// clang-format off -const std::array default_hotkeys{{ - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+M"), std::string("Home+Dpad_Right"), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("-"), std::string("Home+Dpad_Down"), Qt::ApplicationShortcut, true}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("="), std::string("Home+Dpad_Up"), Qt::ApplicationShortcut, true}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Capture Screenshot")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+P"), std::string("Screenshot"), Qt::WidgetWithChildrenShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Adapting Filter")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F8"), std::string("Home+L"), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Docked Mode")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F10"), std::string("Home+X"), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change GPU Accuracy")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F9"), std::string("Home+R"), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Continue/Pause Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F4"), std::string("Home+Plus"), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Esc"), std::string(""), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit eden")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+Q"), std::string("Home+Minus"), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F11"), std::string("Home+B"), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+O"), std::string(""), Qt::WidgetWithChildrenShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F2"), std::string("Home+A"), Qt::WidgetWithChildrenShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Browse Public Game Lobby")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+B"), std::string(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Create Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+N"), std::string(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Direct Connect to Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+C"), std::string(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Leave Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+L"), std::string(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Show Current Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+R"), std::string(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F6"), std::string("R+Plus+Minus"), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F5"), std::string("L+Plus+Minus"), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F7"), std::string(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Reset")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F6"), std::string(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Start/Stop")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F5"), std::string(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Filter Bar")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F"), std::string(""), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Framerate Limit")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+U"), std::string("Home+Y"), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Mouse Panning")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F9"), std::string(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Renderdoc Capture")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string(""), std::string(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+S"), std::string(""), Qt::WindowShortcut, false}}, -}}; -// clang-format on - -} // namespace UISettings - -Q_DECLARE_METATYPE(UISettings::GameDir*); - -// These metatype declarations cannot be in common/settings.h because core is devoid of QT -Q_DECLARE_METATYPE(Settings::CpuAccuracy); -Q_DECLARE_METATYPE(Settings::GpuAccuracy); -Q_DECLARE_METATYPE(Settings::FullscreenMode); -Q_DECLARE_METATYPE(Settings::NvdecEmulation); -Q_DECLARE_METATYPE(Settings::ResolutionSetup); -Q_DECLARE_METATYPE(Settings::ScalingFilter); -Q_DECLARE_METATYPE(Settings::AntiAliasing); -Q_DECLARE_METATYPE(Settings::RendererBackend); -Q_DECLARE_METATYPE(Settings::ShaderBackend); -Q_DECLARE_METATYPE(Settings::AstcRecompression); -Q_DECLARE_METATYPE(Settings::AstcDecodeMode); -Q_DECLARE_METATYPE(Settings::SpirvOptimizeMode); diff --git a/src/eden/qml/CMakeLists.txt b/src/eden/qml/CMakeLists.txt deleted file mode 100644 index 293061b88f..0000000000 --- a/src/eden/qml/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -add_subdirectory(config) -add_subdirectory(constants) -add_subdirectory(items) -add_subdirectory(util) - -add_subdirectory(main) diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index 615ec77d84..aebd11a52b 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -44,7 +44,6 @@ endif() add_subdirectory(externals) target_link_libraries(qt_common PRIVATE core Qt6::Core SimpleIni::SimpleIni QuaZip::QuaZip frozen::frozen) -target_link_libraries(qt_common PRIVATE Qt6::Core) if (NOT WIN32) target_include_directories(qt_common PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) diff --git a/src/qt_common/uisettings.h b/src/qt_common/uisettings.h index 4981d98dbf..b4e0c36dee 100644 --- a/src/qt_common/uisettings.h +++ b/src/qt_common/uisettings.h @@ -202,6 +202,8 @@ struct Values { Setting favorites_expanded{linkage, true, "favorites_expanded", Category::UiGameList}; QVector favorited_ids; + Setting grid_columns{linkage, 4, 1, 8, "grid_columns", Category::UiGameList}; + // Compatibility List Setting show_compat{linkage, false, "show_compat", Category::UiGameList}; From 1604c102eb3c1a17cc6ac7c04b8076b610e6d367 Mon Sep 17 00:00:00 2001 From: crueter Date: Thu, 7 Aug 2025 23:01:36 -0400 Subject: [PATCH 33/34] [eden] marquee text on carousel (grid todo) Signed-off-by: crueter --- src/eden/Eden/Main/GameCarousel.qml | 123 +++++++++++++++++++++++++--- 1 file changed, 111 insertions(+), 12 deletions(-) diff --git a/src/eden/Eden/Main/GameCarousel.qml b/src/eden/Eden/Main/GameCarousel.qml index eb9d90a85c..599310a15f 100644 --- a/src/eden/Eden/Main/GameCarousel.qml +++ b/src/eden/Eden/Main/GameCarousel.qml @@ -59,27 +59,126 @@ ListView { radius: 8 * Constants.scalar - // TODO: marquee - Text { + Item { + id: container + + anchors { + bottom: hg.top + + left: hg.left + right: hg.right + } + + height: txt.contentHeight + clip: true + function toTitleCase(str) { return str.replace(/\w\S*/g, text => text.charAt(0).toUpperCase( ) + text.substring(1).toLowerCase()) } - text: hg.item === null ? "" : toTitleCase(hg.item.title) - font.pixelSize: 22 * Constants.scalar - color: "lightblue" + property string text: hg.item === null ? "" : toTitleCase( + hg.item.title) + property string spacing: " " + property string combined: text + spacing + property string display: animate ? combined.substring( + step) + combined.substring( + 0, step) : text + property int step: 0 + property bool animate: txt.contentWidth > hg.width - anchors { - bottom: hg.top + Timer { + id: marquee - bottomMargin: 10 * Constants.scalar - left: hg.left - right: hg.right + interval: 150 + running: false + repeat: true + onTriggered: { + parent.step = (parent.step + 1) % parent.combined.length + if (parent.step === 0) { + stop() + delay.start() + } + } } - horizontalAlignment: Text.AlignHCenter - elide: Text.ElideRight + Timer { + id: delay + interval: 1500 + repeat: false + onTriggered: { + marquee.start() + } + } + + // fake container to gauge contentWidth + Text { + id: txt + visible: false + text: parent.text + font.pixelSize: 22 * Constants.scalar + font.family: "Monospace" + + onContentWidthChanged: { + if (txt.contentWidth > hg.width) { + container.step = 0 + delay.start() + } else { + delay.stop() + marquee.stop() + } + } + } + + Text { + anchors { + fill: parent + leftMargin: 10 + rightMargin: 10 + } + + color: "lightblue" + font.pixelSize: 22 * Constants.scalar + font.family: "Monospace" + text: parent.display + + horizontalAlignment: container.animate ? Text.AlignLeft : Text.AlignHCenter + } + + Rectangle { + anchors.fill: parent + z: 2 + + gradient: Gradient { + orientation: Gradient.Horizontal + GradientStop { + position: 0.0 + color: marquee.running ? Constants.bg : "transparent" + Behavior on color { + ColorAnimation { + duration: 200 + } + } + } + GradientStop { + position: 0.1 + color: "transparent" + } + GradientStop { + position: 0.9 + color: "transparent" + } + GradientStop { + position: 1.0 + color: marquee.running ? Constants.bg : "transparent" + Behavior on color { + ColorAnimation { + duration: 200 + } + } + } + } + } } } From 649d48c09618ac2519b12be7f85ec5d842c70ce9 Mon Sep 17 00:00:00 2001 From: crueter Date: Sun, 14 Sep 2025 16:00:54 -0400 Subject: [PATCH 34/34] [cmake, qml] refactor: cmake reorg, match grid behavior to carousel Signed-off-by: crueter --- CMakeModules/EdenModule.cmake | 47 +++++ src/CMakeLists.txt | 57 ++--- src/Eden/CMakeLists.txt | 22 ++ src/Eden/Config/CMakeLists.txt | 62 ++++++ .../Eden/Config/GlobalConfigureDialog.qml | 6 +- src/{eden => }/Eden/Config/SectionHeader.qml | 0 src/{eden => }/Eden/Config/Setting.qml | 0 src/{eden => }/Eden/Config/TestSetting.qml | 4 +- .../Eden/Config/fields/BaseField.qml | 8 +- .../Eden/Config/fields/ConfigCheckbox.qml | 8 +- .../Eden/Config/fields/ConfigComboBox.qml | 6 +- .../Eden/Config/fields/ConfigHexEdit.qml | 4 +- .../Eden/Config/fields/ConfigIntLine.qml | 4 +- .../Eden/Config/fields/ConfigIntSlider.qml | 6 +- .../Eden/Config/fields/ConfigIntSpin.qml | 4 +- .../Eden/Config/fields/ConfigStringEdit.qml | 4 +- .../Eden/Config/fields/ConfigTimeEdit.qml | 4 +- .../Eden/Config/fields/FieldCheckbox.qml | 4 +- .../Eden/Config/fields/FieldLabel.qml | 4 +- src/{eden => }/Eden/Config/icons.qrc | 0 .../Eden/Config/pages/SettingsList.qml | 6 +- .../Config/pages/audio/AudioGeneralPage.qml | 2 +- .../Eden/Config/pages/cpu/CpuGeneralPage.qml | 2 +- .../Config/pages/debug/DebugAdvancedPage.qml | 2 +- .../Eden/Config/pages/debug/DebugCpuPage.qml | 2 +- .../Config/pages/debug/DebugGeneralPage.qml | 2 +- .../Config/pages/debug/DebugGraphicsPage.qml | 2 +- .../Config/pages/general/UiGameListPage.qml | 2 +- .../Config/pages/general/UiGeneralPage.qml | 2 +- .../Config/pages/global/GlobalAudioPage.qml | 0 .../Config/pages/global/GlobalCpuPage.qml | 0 .../Config/pages/global/GlobalDebugPage.qml | 0 .../Config/pages/global/GlobalGeneralPage.qml | 0 .../pages/global/GlobalGraphicsPage.qml | 0 .../Config/pages/global/GlobalSystemPage.qml | 0 .../Eden/Config/pages/global/GlobalTab.qml | 4 +- .../pages/global/GlobalTabSwipeView.qml | 4 +- .../pages/graphics/RendererAdvancedPage.qml | 2 +- .../pages/graphics/RendererExtensionsPage.qml | 2 +- .../Config/pages/graphics/RendererPage.qml | 2 +- .../Eden/Config/pages/system/AppletsPage.qml | 2 +- .../Config/pages/system/FileSystemPage.qml | 2 +- .../Config/pages/system/SystemCorePage.qml | 2 +- .../Config/pages/system/SystemGeneralPage.qml | 2 +- src/Eden/Constants/CMakeLists.txt | 16 ++ src/{eden => }/Eden/Constants/Constants.qml | 0 src/Eden/Interface/CMakeLists.txt | 24 +++ .../Interface/MetaObjectHelper.h | 0 .../Native => Eden}/Interface/QMLConfig.h | 0 .../Native => Eden}/Interface/QMLSetting.cpp | 2 + .../Native => Eden}/Interface/QMLSetting.h | 1 - .../Interface/SettingsInterface.cpp | 4 +- .../Interface/SettingsInterface.h | 3 +- src/Eden/Interface/TitleManager.cpp | 40 ++++ src/Eden/Interface/TitleManager.h | 18 ++ src/{eden => }/Eden/Items/AnimatedDialog.qml | 0 src/{eden => }/Eden/Items/BetterMenu.qml | 0 src/{eden => }/Eden/Items/BetterMenuBar.qml | 0 src/Eden/Items/CMakeLists.txt | 22 ++ src/{eden => }/Eden/Items/IconButton.qml | 4 +- .../Eden/Items/SettingsTabButton.qml | 10 +- src/{eden => }/Eden/Items/StatusBarButton.qml | 2 +- src/{eden => }/Eden/Items/VerticalTabBar.qml | 6 +- .../Eden/Items/fields/BetterSpinBox.qml | 8 +- .../Eden/Items/fields/BetterTextField.qml | 4 +- .../Eden/Items/fields/FieldFooter.qml | 2 +- src/Eden/Main/CMakeLists.txt | 22 ++ src/Eden/Main/GameCarousel.qml | 87 ++++++++ src/{eden => }/Eden/Main/GameCarouselCard.qml | 4 +- src/{eden => }/Eden/Main/GameGrid.qml | 15 +- src/{eden => }/Eden/Main/GameGridCard.qml | 30 +-- src/Eden/Main/GameList.qml | 127 ++++++++++++ src/{eden => }/Eden/Main/Main.qml | 2 +- src/Eden/Main/MarqueeText.qml | 129 ++++++++++++ src/{eden => }/Eden/Main/StatusBar.qml | 0 src/Eden/Models/CMakeLists.txt | 17 ++ .../Native => Eden}/Models/GameListModel.cpp | 0 .../Native => Eden}/Models/GameListModel.h | 0 .../Native => Eden}/Models/SettingsModel.cpp | 0 .../Native => Eden}/Models/SettingsModel.h | 2 +- src/Eden/Native/CMakeLists.txt | 65 ++++++ src/Eden/Native/Gamepad/CMakeLists.txt | 11 + .../Eden/Native/Gamepad/gamepad.cpp | 0 src/{eden => }/Eden/Native/Gamepad/gamepad.h | 0 src/{eden => }/Eden/Native/icons.qrc | 1 + src/{eden => }/Eden/Native/icons/audio.svg | 0 src/{eden => }/Eden/Native/icons/back.svg | 0 src/{eden => }/Eden/Native/icons/controls.svg | 0 src/{eden => }/Eden/Native/icons/cpu.svg | 0 src/{eden => }/Eden/Native/icons/debug.svg | 0 src/{eden => }/Eden/Native/icons/forward.svg | 0 src/{eden => }/Eden/Native/icons/general.svg | 0 src/{eden => }/Eden/Native/icons/graphics.svg | 0 src/{eden => }/Eden/Native/icons/help.svg | 0 src/{eden => }/Eden/Native/icons/system.svg | 0 src/{eden => }/Eden/Native/main.cpp | 18 +- src/Eden/Util/CMakeLists.txt | 17 ++ src/{eden => }/Eden/Util/Util.qml | 0 src/eden/.gitignore | 82 -------- src/eden/CMakeLists.txt | 9 - src/eden/Eden/CMakeLists.txt | 9 - src/eden/Eden/Config/CMakeLists.txt | 57 ----- src/eden/Eden/Constants/CMakeLists.txt | 23 --- src/eden/Eden/Items/CMakeLists.txt | 22 -- src/eden/Eden/Main/CMakeLists.txt | 18 -- src/eden/Eden/Main/GameCarousel.qml | 195 ------------------ src/eden/Eden/Main/GameList.qml | 127 ------------ src/eden/Eden/Main/MarqueeText.qml | 43 ---- src/eden/Eden/Native/CMakeLists.txt | 71 ------- src/eden/Eden/Native/Gamepad/CMakeLists.txt | 9 - src/eden/Eden/Native/Interface/CMakeLists.txt | 11 - src/eden/Eden/Native/Models/CMakeLists.txt | 16 -- src/eden/Eden/Util/CMakeLists.txt | 23 --- src/qt_common/CMakeLists.txt | 6 - 114 files changed, 867 insertions(+), 865 deletions(-) create mode 100644 CMakeModules/EdenModule.cmake create mode 100644 src/Eden/CMakeLists.txt create mode 100644 src/Eden/Config/CMakeLists.txt rename src/{eden => }/Eden/Config/GlobalConfigureDialog.qml (93%) rename src/{eden => }/Eden/Config/SectionHeader.qml (100%) rename src/{eden => }/Eden/Config/Setting.qml (100%) rename src/{eden => }/Eden/Config/TestSetting.qml (90%) rename src/{eden => }/Eden/Config/fields/BaseField.qml (94%) rename src/{eden => }/Eden/Config/fields/ConfigCheckbox.qml (64%) rename src/{eden => }/Eden/Config/fields/ConfigComboBox.qml (84%) rename src/{eden => }/Eden/Config/fields/ConfigHexEdit.qml (82%) rename src/{eden => }/Eden/Config/fields/ConfigIntLine.qml (82%) rename src/{eden => }/Eden/Config/fields/ConfigIntSlider.qml (79%) rename src/{eden => }/Eden/Config/fields/ConfigIntSpin.qml (79%) rename src/{eden => }/Eden/Config/fields/ConfigStringEdit.qml (75%) rename src/{eden => }/Eden/Config/fields/ConfigTimeEdit.qml (81%) rename src/{eden => }/Eden/Config/fields/FieldCheckbox.qml (78%) rename src/{eden => }/Eden/Config/fields/FieldLabel.qml (75%) rename src/{eden => }/Eden/Config/icons.qrc (100%) rename src/{eden => }/Eden/Config/pages/SettingsList.qml (88%) rename src/{eden => }/Eden/Config/pages/audio/AudioGeneralPage.qml (90%) rename src/{eden => }/Eden/Config/pages/cpu/CpuGeneralPage.qml (90%) rename src/{eden => }/Eden/Config/pages/debug/DebugAdvancedPage.qml (91%) rename src/{eden => }/Eden/Config/pages/debug/DebugCpuPage.qml (90%) rename src/{eden => }/Eden/Config/pages/debug/DebugGeneralPage.qml (94%) rename src/{eden => }/Eden/Config/pages/debug/DebugGraphicsPage.qml (92%) rename src/{eden => }/Eden/Config/pages/general/UiGameListPage.qml (91%) rename src/{eden => }/Eden/Config/pages/general/UiGeneralPage.qml (94%) rename src/{eden => }/Eden/Config/pages/global/GlobalAudioPage.qml (100%) rename src/{eden => }/Eden/Config/pages/global/GlobalCpuPage.qml (100%) rename src/{eden => }/Eden/Config/pages/global/GlobalDebugPage.qml (100%) rename src/{eden => }/Eden/Config/pages/global/GlobalGeneralPage.qml (100%) rename src/{eden => }/Eden/Config/pages/global/GlobalGraphicsPage.qml (100%) rename src/{eden => }/Eden/Config/pages/global/GlobalSystemPage.qml (100%) rename src/{eden => }/Eden/Config/pages/global/GlobalTab.qml (85%) rename src/{eden => }/Eden/Config/pages/global/GlobalTabSwipeView.qml (72%) rename src/{eden => }/Eden/Config/pages/graphics/RendererAdvancedPage.qml (91%) rename src/{eden => }/Eden/Config/pages/graphics/RendererExtensionsPage.qml (91%) rename src/{eden => }/Eden/Config/pages/graphics/RendererPage.qml (90%) rename src/{eden => }/Eden/Config/pages/system/AppletsPage.qml (91%) rename src/{eden => }/Eden/Config/pages/system/FileSystemPage.qml (91%) rename src/{eden => }/Eden/Config/pages/system/SystemCorePage.qml (90%) rename src/{eden => }/Eden/Config/pages/system/SystemGeneralPage.qml (93%) create mode 100644 src/Eden/Constants/CMakeLists.txt rename src/{eden => }/Eden/Constants/Constants.qml (100%) create mode 100644 src/Eden/Interface/CMakeLists.txt rename src/{eden/Eden/Native => Eden}/Interface/MetaObjectHelper.h (100%) rename src/{eden/Eden/Native => Eden}/Interface/QMLConfig.h (100%) rename src/{eden/Eden/Native => Eden}/Interface/QMLSetting.cpp (99%) rename src/{eden/Eden/Native => Eden}/Interface/QMLSetting.h (98%) rename src/{eden/Eden/Native => Eden}/Interface/SettingsInterface.cpp (99%) rename src/{eden/Eden/Native => Eden}/Interface/SettingsInterface.h (98%) create mode 100644 src/Eden/Interface/TitleManager.cpp create mode 100644 src/Eden/Interface/TitleManager.h rename src/{eden => }/Eden/Items/AnimatedDialog.qml (100%) rename src/{eden => }/Eden/Items/BetterMenu.qml (100%) rename src/{eden => }/Eden/Items/BetterMenuBar.qml (100%) create mode 100644 src/Eden/Items/CMakeLists.txt rename src/{eden => }/Eden/Items/IconButton.qml (82%) rename src/{eden => }/Eden/Items/SettingsTabButton.qml (72%) rename src/{eden => }/Eden/Items/StatusBarButton.qml (92%) rename src/{eden => }/Eden/Items/VerticalTabBar.qml (88%) rename src/{eden => }/Eden/Items/fields/BetterSpinBox.qml (87%) rename src/{eden => }/Eden/Items/fields/BetterTextField.qml (88%) rename src/{eden => }/Eden/Items/fields/FieldFooter.qml (91%) create mode 100644 src/Eden/Main/CMakeLists.txt create mode 100644 src/Eden/Main/GameCarousel.qml rename src/{eden => }/Eden/Main/GameCarouselCard.qml (87%) rename src/{eden => }/Eden/Main/GameGrid.qml (63%) rename src/{eden => }/Eden/Main/GameGridCard.qml (70%) create mode 100644 src/Eden/Main/GameList.qml rename src/{eden => }/Eden/Main/Main.qml (99%) create mode 100644 src/Eden/Main/MarqueeText.qml rename src/{eden => }/Eden/Main/StatusBar.qml (100%) create mode 100644 src/Eden/Models/CMakeLists.txt rename src/{eden/Eden/Native => Eden}/Models/GameListModel.cpp (100%) rename src/{eden/Eden/Native => Eden}/Models/GameListModel.h (100%) rename src/{eden/Eden/Native => Eden}/Models/SettingsModel.cpp (100%) rename src/{eden/Eden/Native => Eden}/Models/SettingsModel.h (95%) create mode 100644 src/Eden/Native/CMakeLists.txt create mode 100644 src/Eden/Native/Gamepad/CMakeLists.txt rename src/{eden => }/Eden/Native/Gamepad/gamepad.cpp (100%) rename src/{eden => }/Eden/Native/Gamepad/gamepad.h (100%) rename src/{eden => }/Eden/Native/icons.qrc (84%) rename src/{eden => }/Eden/Native/icons/audio.svg (100%) rename src/{eden => }/Eden/Native/icons/back.svg (100%) rename src/{eden => }/Eden/Native/icons/controls.svg (100%) rename src/{eden => }/Eden/Native/icons/cpu.svg (100%) rename src/{eden => }/Eden/Native/icons/debug.svg (100%) rename src/{eden => }/Eden/Native/icons/forward.svg (100%) rename src/{eden => }/Eden/Native/icons/general.svg (100%) rename src/{eden => }/Eden/Native/icons/graphics.svg (100%) rename src/{eden => }/Eden/Native/icons/help.svg (100%) rename src/{eden => }/Eden/Native/icons/system.svg (100%) rename src/{eden => }/Eden/Native/main.cpp (72%) create mode 100644 src/Eden/Util/CMakeLists.txt rename src/{eden => }/Eden/Util/Util.qml (100%) delete mode 100644 src/eden/.gitignore delete mode 100644 src/eden/CMakeLists.txt delete mode 100644 src/eden/Eden/CMakeLists.txt delete mode 100644 src/eden/Eden/Config/CMakeLists.txt delete mode 100644 src/eden/Eden/Constants/CMakeLists.txt delete mode 100644 src/eden/Eden/Items/CMakeLists.txt delete mode 100644 src/eden/Eden/Main/CMakeLists.txt delete mode 100644 src/eden/Eden/Main/GameCarousel.qml delete mode 100644 src/eden/Eden/Main/GameList.qml delete mode 100644 src/eden/Eden/Main/MarqueeText.qml delete mode 100644 src/eden/Eden/Native/CMakeLists.txt delete mode 100644 src/eden/Eden/Native/Gamepad/CMakeLists.txt delete mode 100644 src/eden/Eden/Native/Interface/CMakeLists.txt delete mode 100644 src/eden/Eden/Native/Models/CMakeLists.txt delete mode 100644 src/eden/Eden/Util/CMakeLists.txt diff --git a/CMakeModules/EdenModule.cmake b/CMakeModules/EdenModule.cmake new file mode 100644 index 0000000000..2054456ede --- /dev/null +++ b/CMakeModules/EdenModule.cmake @@ -0,0 +1,47 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + +# SPDX-FileCopyrightText: Copyright 2025 crueter +# SPDX-License-Identifier: GPL-3.0-or-later + +cmake_minimum_required(VERSION 3.16) + +function(EdenModule) + set(oneValueArgs + NAME + URI + NATIVE + ) + + set(multiValueArgs + LIBRARIES + QML_FILES + SOURCES + ) + + cmake_parse_arguments(MODULE "" "${oneValueArgs}" "${multiValueArgs}" + "${ARGN}") + + set(LIB_NAME Eden${MODULE_NAME}) + + add_library(${LIB_NAME} STATIC) + + message(STATUS "URI for ${MODULE_NAME}: ${MODULE_URI}") + + qt_add_qml_module(${LIB_NAME} + URI ${MODULE_URI} + NO_PLUGIN + VERSION 0.1 + + QML_FILES ${MODULE_QML_FILES} + SOURCES ${MODULE_SOURCES} + + ${MODULE_UNPARSED_ARGUMENTS} + ) + + add_library(Eden::${MODULE_NAME} ALIAS ${LIB_NAME}) + + if (DEFINED MODULE_LIBRARIES) + target_link_libraries(${LIB_NAME} PRIVATE ${MODULE_LIBRARIES}) + endif() +endfunction() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f3d45bbfe2..525f14e8c5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -18,20 +18,20 @@ set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS $<$:_DEBUG> $<$>:NDEBUG>) # Set compilation flags -if (MSVC AND NOT CXX_CLANG) +if (MSVC) set(CMAKE_CONFIGURATION_TYPES Debug Release CACHE STRING "" FORCE) # Silence "deprecation" warnings - add_compile_definitions(_CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE _SCL_SECURE_NO_WARNINGS) + add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS) # Avoid windows.h junk - add_compile_definitions(NOMINMAX) + add_definitions(-DNOMINMAX) # Avoid windows.h from including some usually unused libs like winsocks.h, since this might cause some redefinition errors. - add_compile_definitions(WIN32_LEAN_AND_MEAN) + add_definitions(-DWIN32_LEAN_AND_MEAN) # Ensure that projects are built with Unicode support. - add_compile_definitions(UNICODE _UNICODE) + add_definitions(-DUNICODE -D_UNICODE) # /W4 - Level 4 warnings # /MP - Multi-threaded compilation @@ -69,6 +69,10 @@ if (MSVC AND NOT CXX_CLANG) /external:anglebrackets # Treats all headers included by #include
, where the header file is enclosed in angle brackets (< >), as external headers /external:W0 # Sets the default warning level to 0 for external headers, effectively disabling warnings for them. + # Warnings + /W4 + /WX- + /we4062 # Enumerator 'identifier' in a switch of enum 'enumeration' is not handled /we4189 # 'identifier': local variable is initialized but not referenced /we4265 # 'class': class has virtual functions, but destructor is not virtual @@ -93,14 +97,6 @@ if (MSVC AND NOT CXX_CLANG) /wd4702 # unreachable code (when used with LTO) ) - if (NOT CXX_CLANG) - add_compile_options( - # Warnings - /W4 - /WX- - ) - endif() - if (USE_CCACHE OR YUZU_USE_PRECOMPILED_HEADERS) # when caching, we need to use /Z7 to downgrade debug info to use an older but more cacheable format # Precompiled headers are deleted if not using /Z7. See https://github.com/nanoant/CMakePCHCompiler/issues/21 @@ -122,13 +118,9 @@ if (MSVC AND NOT CXX_CLANG) set(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG /MANIFEST:NO" CACHE STRING "" FORCE) set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/DEBUG /MANIFEST:NO /INCREMENTAL:NO /OPT:REF,ICF" CACHE STRING "" FORCE) else() - if (NOT MSVC) - add_compile_options( - -fwrapv - ) - endif() - add_compile_options( + -fwrapv + -Werror=all -Werror=extra -Werror=shadow @@ -140,19 +132,14 @@ else() -Wno-missing-field-initializers ) - if (CXX_CLANG OR CXX_ICC) # Clang or AppleClang - if (NOT MSVC) - add_compile_options( - -Werror=shadow-uncaptured-local - -Werror=implicit-fallthrough - -Werror=type-limits - ) - endif() - + if (CMAKE_CXX_COMPILER_ID MATCHES Clang OR CMAKE_CXX_COMPILER_ID MATCHES IntelLLVM) # Clang or AppleClang add_compile_options( -Wno-braced-scalar-init -Wno-unused-private-field -Wno-nullability-completeness + -Werror=shadow-uncaptured-local + -Werror=implicit-fallthrough + -Werror=type-limits ) endif() @@ -160,12 +147,12 @@ else() add_compile_options("-mcx16") endif() - if (APPLE AND CXX_CLANG) + if (APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL Clang) add_compile_options("-stdlib=libc++") endif() # GCC bugs - if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "11" AND CXX_GCC) + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "11" AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") # These diagnostics would be great if they worked, but are just completely broken # and produce bogus errors on external libraries like fmt. add_compile_options( @@ -181,15 +168,15 @@ else() # glibc, which may default to 32 bits. glibc allows this to be configured # by setting _FILE_OFFSET_BITS. if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR MINGW) - add_compile_definitions(_FILE_OFFSET_BITS=64) + add_definitions(-D_FILE_OFFSET_BITS=64) endif() if (MINGW) - add_compile_definitions(MINGW_HAS_SECURE_API) + add_definitions(-DMINGW_HAS_SECURE_API) add_compile_options("-msse4.1") if (MINGW_STATIC_BUILD) - add_compile_definitions(QT_STATICPLUGIN) + add_definitions(-DQT_STATICPLUGIN) add_compile_options("-static") endif() endif() @@ -235,7 +222,7 @@ endif() if (ENABLE_QT) add_definitions(-DYUZU_QT_WIDGETS) add_subdirectory(qt_common) - add_subdirectory(eden) + add_subdirectory(Eden) endif() if (ENABLE_WEB_SERVICE) @@ -246,5 +233,3 @@ if (ANDROID) add_subdirectory(android/app/src/main/jni) target_include_directories(yuzu-android PRIVATE android/app/src/main) endif() - -include(GenerateDepHashes) diff --git a/src/Eden/CMakeLists.txt b/src/Eden/CMakeLists.txt new file mode 100644 index 0000000000..d70bcdb90f --- /dev/null +++ b/src/Eden/CMakeLists.txt @@ -0,0 +1,22 @@ +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +find_package(Qt6 REQUIRED COMPONENTS Widgets Core Gui Quick QuickControls2) + +qt_standard_project_setup(REQUIRES 6.7) + +include(EdenModule) + +include_directories(AFTER "${CMAKE_CURRENT_SOURCE_DIR}") + +add_subdirectory(Interface) +add_subdirectory(Models) + +add_subdirectory(Config) +add_subdirectory(Constants) +add_subdirectory(Items) +add_subdirectory(Util) +add_subdirectory(Main) + +add_subdirectory(Native) diff --git a/src/Eden/Config/CMakeLists.txt b/src/Eden/Config/CMakeLists.txt new file mode 100644 index 0000000000..cb72511f1e --- /dev/null +++ b/src/Eden/Config/CMakeLists.txt @@ -0,0 +1,62 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + +# SPDX-FileCopyrightText: Copyright 2025 crueter +# SPDX-License-Identifier: GPL-3.0-or-later + +EdenModule( + NAME Config + URI Eden.Config + + QML_FILES + GlobalConfigureDialog.qml + Setting.qml + SectionHeader.qml + + pages/SettingsList.qml + pages/global/GlobalTab.qml + pages/global/GlobalTabSwipeView.qml + pages/global/GlobalGeneralPage.qml + pages/global/GlobalSystemPage.qml + pages/global/GlobalCpuPage.qml + pages/global/GlobalGraphicsPage.qml + pages/global/GlobalAudioPage.qml + + pages/general/UiGeneralPage.qml + pages/general/UiGameListPage.qml + + pages/graphics/RendererPage.qml + pages/graphics/RendererAdvancedPage.qml + pages/graphics/RendererExtensionsPage.qml + + pages/system/SystemGeneralPage.qml + pages/system/SystemCorePage.qml + pages/system/FileSystemPage.qml + pages/system/AppletsPage.qml + + pages/cpu/CpuGeneralPage.qml + + pages/audio/AudioGeneralPage.qml + + pages/global/GlobalDebugPage.qml + + pages/debug/DebugGeneralPage.qml + pages/debug/DebugGraphicsPage.qml + pages/debug/DebugAdvancedPage.qml + pages/debug/DebugCpuPage.qml + + fields/ConfigCheckbox.qml + fields/FieldLabel.qml + fields/ConfigComboBox.qml + fields/ConfigIntLine.qml + fields/ConfigTimeEdit.qml + fields/ConfigIntSpin.qml + fields/ConfigHexEdit.qml + fields/ConfigStringEdit.qml + fields/FieldCheckbox.qml + fields/ConfigIntSlider.qml + fields/BaseField.qml + + TestSetting.qml + LIBRARIES Eden::Interface +) diff --git a/src/eden/Eden/Config/GlobalConfigureDialog.qml b/src/Eden/Config/GlobalConfigureDialog.qml similarity index 93% rename from src/eden/Eden/Config/GlobalConfigureDialog.qml rename to src/Eden/Config/GlobalConfigureDialog.qml index 3d4ad2c955..5e5ef127a1 100644 --- a/src/eden/Eden/Config/GlobalConfigureDialog.qml +++ b/src/Eden/Config/GlobalConfigureDialog.qml @@ -4,7 +4,7 @@ import QtQuick.Layouts import Eden.Constants import Eden.Items -import Eden.Native.Interface +import Eden.Interface import Eden.Util AnimatedDialog { @@ -34,7 +34,7 @@ AnimatedDialog { anchors { top: parent.top - topMargin: 55 * Constants.scalar + topMargin: 55 left: parent.left bottom: parent.bottom @@ -65,7 +65,7 @@ AnimatedDialog { top: parent.top bottom: parent.bottom - leftMargin: 5 * Constants.scalar + leftMargin: 5 } clip: true diff --git a/src/eden/Eden/Config/SectionHeader.qml b/src/Eden/Config/SectionHeader.qml similarity index 100% rename from src/eden/Eden/Config/SectionHeader.qml rename to src/Eden/Config/SectionHeader.qml diff --git a/src/eden/Eden/Config/Setting.qml b/src/Eden/Config/Setting.qml similarity index 100% rename from src/eden/Eden/Config/Setting.qml rename to src/Eden/Config/Setting.qml diff --git a/src/eden/Eden/Config/TestSetting.qml b/src/Eden/Config/TestSetting.qml similarity index 90% rename from src/eden/Eden/Config/TestSetting.qml rename to src/Eden/Config/TestSetting.qml index 9029f8dc4b..e429723105 100644 --- a/src/eden/Eden/Config/TestSetting.qml +++ b/src/Eden/Config/TestSetting.qml @@ -4,8 +4,8 @@ import QtQuick.Layouts import Eden.Constants Column { - topPadding: 5 * Constants.scalar - leftPadding: 10 * Constants.scalar + topPadding: 5 + leftPadding: 10 RowLayout { uniformCellSizes: true diff --git a/src/eden/Eden/Config/fields/BaseField.qml b/src/Eden/Config/fields/BaseField.qml similarity index 94% rename from src/eden/Eden/Config/fields/BaseField.qml rename to src/Eden/Config/fields/BaseField.qml index 23973e29d9..359c7d5414 100644 --- a/src/eden/Eden/Config/fields/BaseField.qml +++ b/src/Eden/Config/fields/BaseField.qml @@ -36,7 +36,7 @@ Item { RowLayout { id: content - height: 50 * Constants.scalar + height: 50 spacing: 0 @@ -91,9 +91,9 @@ Item { anchors { left: parent.left - leftMargin: 20 * Constants.scalar + leftMargin: 20 right: parent.right - rightMargin: 20 * Constants.scalar + rightMargin: 20 top: content.bottom topMargin: -height @@ -103,7 +103,7 @@ Item { text: setting.tooltip color: Constants.subText - font.pixelSize: 12 * Constants.scalar + font.pixelSize: 12 wrapMode: Text.WordWrap visible: false diff --git a/src/eden/Eden/Config/fields/ConfigCheckbox.qml b/src/Eden/Config/fields/ConfigCheckbox.qml similarity index 64% rename from src/eden/Eden/Config/fields/ConfigCheckbox.qml rename to src/Eden/Config/fields/ConfigCheckbox.qml index 8b41ae5b8a..8d0f5428e6 100644 --- a/src/eden/Eden/Config/fields/ConfigCheckbox.qml +++ b/src/Eden/Config/fields/ConfigCheckbox.qml @@ -10,12 +10,12 @@ BaseField { // contentItem: CheckBox { // id: control - // Layout.rightMargin: 10 * Constants.scalar + // Layout.rightMargin: 10 // Layout.fillWidth: true - // font.pixelSize: 15 * Constants.scalar - // indicator.implicitHeight: 25 * Constants.scalar - // indicator.implicitWidth: 25 * Constants.scalar + // font.pixelSize: 15 + // indicator.implicitHeight: 25 + // indicator.implicitWidth: 25 // text: setting.label // checked: setting.value diff --git a/src/eden/Eden/Config/fields/ConfigComboBox.qml b/src/Eden/Config/fields/ConfigComboBox.qml similarity index 84% rename from src/eden/Eden/Config/fields/ConfigComboBox.qml rename to src/Eden/Config/fields/ConfigComboBox.qml index bf555d279a..1c22b2da42 100644 --- a/src/eden/Eden/Config/fields/ConfigComboBox.qml +++ b/src/Eden/Config/fields/ConfigComboBox.qml @@ -12,15 +12,15 @@ BaseField { enabled: enable Layout.fillWidth: true - Layout.rightMargin: 10 * Constants.scalar + Layout.rightMargin: 10 - font.pixelSize: 14 * Constants.scalar + font.pixelSize: 14 model: setting.combo currentIndex: value background: MaterialTextContainer { implicitWidth: 120 - implicitHeight: 40 * Constants.scalar + implicitHeight: 40 outlineColor: (enabled && control.hovered) ? control.Material.primaryTextColor : control.Material.hintTextColor diff --git a/src/eden/Eden/Config/fields/ConfigHexEdit.qml b/src/Eden/Config/fields/ConfigHexEdit.qml similarity index 82% rename from src/eden/Eden/Config/fields/ConfigHexEdit.qml rename to src/Eden/Config/fields/ConfigHexEdit.qml index 043b48ec42..c653f7b15f 100644 --- a/src/eden/Eden/Config/fields/ConfigHexEdit.qml +++ b/src/Eden/Config/fields/ConfigHexEdit.qml @@ -10,13 +10,13 @@ BaseField { enabled: enable Layout.fillWidth: true - Layout.rightMargin: 10 * Constants.scalar + Layout.rightMargin: 10 validator: RegularExpressionValidator { regularExpression: /[0-9a-fA-F]{0,8}/ } - font.pixelSize: 15 * Constants.scalar + font.pixelSize: 15 text: Number(value).toString(16) suffix: setting.suffix diff --git a/src/eden/Eden/Config/fields/ConfigIntLine.qml b/src/Eden/Config/fields/ConfigIntLine.qml similarity index 82% rename from src/eden/Eden/Config/fields/ConfigIntLine.qml rename to src/Eden/Config/fields/ConfigIntLine.qml index 5dc45343ec..9b18897208 100644 --- a/src/eden/Eden/Config/fields/ConfigIntLine.qml +++ b/src/Eden/Config/fields/ConfigIntLine.qml @@ -10,7 +10,7 @@ BaseField { enabled: enable Layout.fillWidth: true - Layout.rightMargin: 10 * Constants.scalar + Layout.rightMargin: 10 inputMethodHints: Qt.ImhDigitsOnly validator: IntValidator { @@ -18,7 +18,7 @@ BaseField { top: setting.max } - font.pixelSize: 15 * Constants.scalar + font.pixelSize: 15 text: value suffix: setting.suffix diff --git a/src/eden/Eden/Config/fields/ConfigIntSlider.qml b/src/Eden/Config/fields/ConfigIntSlider.qml similarity index 79% rename from src/eden/Eden/Config/fields/ConfigIntSlider.qml rename to src/Eden/Config/fields/ConfigIntSlider.qml index 7693ad824e..cb8a752669 100644 --- a/src/eden/Eden/Config/fields/ConfigIntSlider.qml +++ b/src/Eden/Config/fields/ConfigIntSlider.qml @@ -23,18 +23,18 @@ BaseField { onMoved: field.value = value - Layout.rightMargin: 10 * Constants.scalar + Layout.rightMargin: 10 snapMode: Slider.SnapAlways } Text { - font.pixelSize: 14 * Constants.scalar + font.pixelSize: 14 color: Constants.text text: field.value + setting.suffix - Layout.rightMargin: 10 * Constants.scalar + Layout.rightMargin: 10 } } } diff --git a/src/eden/Eden/Config/fields/ConfigIntSpin.qml b/src/Eden/Config/fields/ConfigIntSpin.qml similarity index 79% rename from src/eden/Eden/Config/fields/ConfigIntSpin.qml rename to src/Eden/Config/fields/ConfigIntSpin.qml index 8e8c23f76f..6e7d309f6f 100644 --- a/src/eden/Eden/Config/fields/ConfigIntSpin.qml +++ b/src/Eden/Config/fields/ConfigIntSpin.qml @@ -11,12 +11,12 @@ BaseField { enabled: enable Layout.fillWidth: true - Layout.rightMargin: 10 * Constants.scalar + Layout.rightMargin: 10 from: setting.min to: setting.max - font.pixelSize: 15 * Constants.scalar + font.pixelSize: 15 value: field.value label: setting.suffix diff --git a/src/eden/Eden/Config/fields/ConfigStringEdit.qml b/src/Eden/Config/fields/ConfigStringEdit.qml similarity index 75% rename from src/eden/Eden/Config/fields/ConfigStringEdit.qml rename to src/Eden/Config/fields/ConfigStringEdit.qml index beae2b0362..0100a589c5 100644 --- a/src/eden/Eden/Config/fields/ConfigStringEdit.qml +++ b/src/Eden/Config/fields/ConfigStringEdit.qml @@ -10,9 +10,9 @@ BaseField { enabled: enable Layout.fillWidth: true - Layout.rightMargin: 10 * Constants.scalar + Layout.rightMargin: 10 - font.pixelSize: 15 * Constants.scalar + font.pixelSize: 15 text: value suffix: setting.suffix diff --git a/src/eden/Eden/Config/fields/ConfigTimeEdit.qml b/src/Eden/Config/fields/ConfigTimeEdit.qml similarity index 81% rename from src/eden/Eden/Config/fields/ConfigTimeEdit.qml rename to src/Eden/Config/fields/ConfigTimeEdit.qml index 01ebc6d6b1..df932d36b4 100644 --- a/src/eden/Eden/Config/fields/ConfigTimeEdit.qml +++ b/src/Eden/Config/fields/ConfigTimeEdit.qml @@ -11,7 +11,7 @@ BaseField { enabled: enable Layout.fillWidth: true - Layout.rightMargin: 10 * Constants.scalar + Layout.rightMargin: 10 inputMethodHints: Qt.ImhDigitsOnly validator: IntValidator { @@ -19,7 +19,7 @@ BaseField { top: setting.max } - font.pixelSize: 15 * Constants.scalar + font.pixelSize: 15 text: value suffix: setting.suffix diff --git a/src/eden/Eden/Config/fields/FieldCheckbox.qml b/src/Eden/Config/fields/FieldCheckbox.qml similarity index 78% rename from src/eden/Eden/Config/fields/FieldCheckbox.qml rename to src/Eden/Config/fields/FieldCheckbox.qml index 531f2bb624..14da7d9505 100644 --- a/src/eden/Eden/Config/fields/FieldCheckbox.qml +++ b/src/Eden/Config/fields/FieldCheckbox.qml @@ -9,8 +9,8 @@ CheckBox { property var setting property var other: setting.other === null ? setting : setting.other - indicator.implicitHeight: 25 * Constants.scalar - indicator.implicitWidth: 25 * Constants.scalar + indicator.implicitHeight: 25 + indicator.implicitWidth: 25 checked: visible ? other.value : true onClicked: if (visible) diff --git a/src/eden/Eden/Config/fields/FieldLabel.qml b/src/Eden/Config/fields/FieldLabel.qml similarity index 75% rename from src/eden/Eden/Config/fields/FieldLabel.qml rename to src/Eden/Config/fields/FieldLabel.qml index d94ee58c92..813c9c392f 100644 --- a/src/eden/Eden/Config/fields/FieldLabel.qml +++ b/src/Eden/Config/fields/FieldLabel.qml @@ -9,9 +9,9 @@ Text { text: setting.label color: Constants.text - font.pixelSize: 14 * Constants.scalar + font.pixelSize: 14 - height: 50 * Constants.scalar + height: 50 ToolTip.text: setting.tooltip Layout.fillWidth: true diff --git a/src/eden/Eden/Config/icons.qrc b/src/Eden/Config/icons.qrc similarity index 100% rename from src/eden/Eden/Config/icons.qrc rename to src/Eden/Config/icons.qrc diff --git a/src/eden/Eden/Config/pages/SettingsList.qml b/src/Eden/Config/pages/SettingsList.qml similarity index 88% rename from src/eden/Eden/Config/pages/SettingsList.qml rename to src/Eden/Config/pages/SettingsList.qml index 73c6b27c76..df6447de7f 100644 --- a/src/eden/Eden/Config/pages/SettingsList.qml +++ b/src/Eden/Config/pages/SettingsList.qml @@ -3,7 +3,7 @@ import QtQuick.Layouts import Eden.Config import Eden.Constants -import Eden.Native.Interface +import Eden.Interface ColumnLayout { required property int category @@ -29,8 +29,8 @@ ColumnLayout { Layout.fillHeight: true Layout.fillWidth: true - Layout.leftMargin: 5 * Constants.scalar - spacing: 8 * Constants.scalar + Layout.leftMargin: 5 + spacing: 8 model: SettingsInterface.category(category, idInclude, idExclude) diff --git a/src/eden/Eden/Config/pages/audio/AudioGeneralPage.qml b/src/Eden/Config/pages/audio/AudioGeneralPage.qml similarity index 90% rename from src/eden/Eden/Config/pages/audio/AudioGeneralPage.qml rename to src/Eden/Config/pages/audio/AudioGeneralPage.qml index 9c86400a8c..e56a7afe38 100644 --- a/src/eden/Eden/Config/pages/audio/AudioGeneralPage.qml +++ b/src/Eden/Config/pages/audio/AudioGeneralPage.qml @@ -2,7 +2,7 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import Eden.Native.Interface +import Eden.Interface import Eden.Config ScrollView { diff --git a/src/eden/Eden/Config/pages/cpu/CpuGeneralPage.qml b/src/Eden/Config/pages/cpu/CpuGeneralPage.qml similarity index 90% rename from src/eden/Eden/Config/pages/cpu/CpuGeneralPage.qml rename to src/Eden/Config/pages/cpu/CpuGeneralPage.qml index a3c44e4892..0c78bf35ee 100644 --- a/src/eden/Eden/Config/pages/cpu/CpuGeneralPage.qml +++ b/src/Eden/Config/pages/cpu/CpuGeneralPage.qml @@ -2,7 +2,7 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import Eden.Native.Interface +import Eden.Interface import Eden.Config ScrollView { diff --git a/src/eden/Eden/Config/pages/debug/DebugAdvancedPage.qml b/src/Eden/Config/pages/debug/DebugAdvancedPage.qml similarity index 91% rename from src/eden/Eden/Config/pages/debug/DebugAdvancedPage.qml rename to src/Eden/Config/pages/debug/DebugAdvancedPage.qml index 5d0443334f..1709402485 100644 --- a/src/eden/Eden/Config/pages/debug/DebugAdvancedPage.qml +++ b/src/Eden/Config/pages/debug/DebugAdvancedPage.qml @@ -2,7 +2,7 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import Eden.Native.Interface +import Eden.Interface import Eden.Config ScrollView { diff --git a/src/eden/Eden/Config/pages/debug/DebugCpuPage.qml b/src/Eden/Config/pages/debug/DebugCpuPage.qml similarity index 90% rename from src/eden/Eden/Config/pages/debug/DebugCpuPage.qml rename to src/Eden/Config/pages/debug/DebugCpuPage.qml index aa58851cd7..b0656e288a 100644 --- a/src/eden/Eden/Config/pages/debug/DebugCpuPage.qml +++ b/src/Eden/Config/pages/debug/DebugCpuPage.qml @@ -2,7 +2,7 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import Eden.Native.Interface +import Eden.Interface import Eden.Config ScrollView { diff --git a/src/eden/Eden/Config/pages/debug/DebugGeneralPage.qml b/src/Eden/Config/pages/debug/DebugGeneralPage.qml similarity index 94% rename from src/eden/Eden/Config/pages/debug/DebugGeneralPage.qml rename to src/Eden/Config/pages/debug/DebugGeneralPage.qml index 0c0fb00f72..7862497cc8 100644 --- a/src/eden/Eden/Config/pages/debug/DebugGeneralPage.qml +++ b/src/Eden/Config/pages/debug/DebugGeneralPage.qml @@ -2,7 +2,7 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import Eden.Native.Interface +import Eden.Interface import Eden.Config ScrollView { diff --git a/src/eden/Eden/Config/pages/debug/DebugGraphicsPage.qml b/src/Eden/Config/pages/debug/DebugGraphicsPage.qml similarity index 92% rename from src/eden/Eden/Config/pages/debug/DebugGraphicsPage.qml rename to src/Eden/Config/pages/debug/DebugGraphicsPage.qml index bcae356161..9c585054e0 100644 --- a/src/eden/Eden/Config/pages/debug/DebugGraphicsPage.qml +++ b/src/Eden/Config/pages/debug/DebugGraphicsPage.qml @@ -2,7 +2,7 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import Eden.Native.Interface +import Eden.Interface import Eden.Config ScrollView { diff --git a/src/eden/Eden/Config/pages/general/UiGameListPage.qml b/src/Eden/Config/pages/general/UiGameListPage.qml similarity index 91% rename from src/eden/Eden/Config/pages/general/UiGameListPage.qml rename to src/Eden/Config/pages/general/UiGameListPage.qml index 930e4fe61b..29f8107e59 100644 --- a/src/eden/Eden/Config/pages/general/UiGameListPage.qml +++ b/src/Eden/Config/pages/general/UiGameListPage.qml @@ -2,7 +2,7 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import Eden.Native.Interface +import Eden.Interface import Eden.Config ScrollView { diff --git a/src/eden/Eden/Config/pages/general/UiGeneralPage.qml b/src/Eden/Config/pages/general/UiGeneralPage.qml similarity index 94% rename from src/eden/Eden/Config/pages/general/UiGeneralPage.qml rename to src/Eden/Config/pages/general/UiGeneralPage.qml index 16ee8a6ecc..7d53fb046a 100644 --- a/src/eden/Eden/Config/pages/general/UiGeneralPage.qml +++ b/src/Eden/Config/pages/general/UiGeneralPage.qml @@ -2,7 +2,7 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import Eden.Native.Interface +import Eden.Interface import Eden.Config ScrollView { diff --git a/src/eden/Eden/Config/pages/global/GlobalAudioPage.qml b/src/Eden/Config/pages/global/GlobalAudioPage.qml similarity index 100% rename from src/eden/Eden/Config/pages/global/GlobalAudioPage.qml rename to src/Eden/Config/pages/global/GlobalAudioPage.qml diff --git a/src/eden/Eden/Config/pages/global/GlobalCpuPage.qml b/src/Eden/Config/pages/global/GlobalCpuPage.qml similarity index 100% rename from src/eden/Eden/Config/pages/global/GlobalCpuPage.qml rename to src/Eden/Config/pages/global/GlobalCpuPage.qml diff --git a/src/eden/Eden/Config/pages/global/GlobalDebugPage.qml b/src/Eden/Config/pages/global/GlobalDebugPage.qml similarity index 100% rename from src/eden/Eden/Config/pages/global/GlobalDebugPage.qml rename to src/Eden/Config/pages/global/GlobalDebugPage.qml diff --git a/src/eden/Eden/Config/pages/global/GlobalGeneralPage.qml b/src/Eden/Config/pages/global/GlobalGeneralPage.qml similarity index 100% rename from src/eden/Eden/Config/pages/global/GlobalGeneralPage.qml rename to src/Eden/Config/pages/global/GlobalGeneralPage.qml diff --git a/src/eden/Eden/Config/pages/global/GlobalGraphicsPage.qml b/src/Eden/Config/pages/global/GlobalGraphicsPage.qml similarity index 100% rename from src/eden/Eden/Config/pages/global/GlobalGraphicsPage.qml rename to src/Eden/Config/pages/global/GlobalGraphicsPage.qml diff --git a/src/eden/Eden/Config/pages/global/GlobalSystemPage.qml b/src/Eden/Config/pages/global/GlobalSystemPage.qml similarity index 100% rename from src/eden/Eden/Config/pages/global/GlobalSystemPage.qml rename to src/Eden/Config/pages/global/GlobalSystemPage.qml diff --git a/src/eden/Eden/Config/pages/global/GlobalTab.qml b/src/Eden/Config/pages/global/GlobalTab.qml similarity index 85% rename from src/eden/Eden/Config/pages/global/GlobalTab.qml rename to src/Eden/Config/pages/global/GlobalTab.qml index 463a7c2d83..322797d30f 100644 --- a/src/eden/Eden/Config/pages/global/GlobalTab.qml +++ b/src/Eden/Config/pages/global/GlobalTab.qml @@ -21,14 +21,14 @@ Item { model: tabs TabButton { - font.pixelSize: 16 * Constants.scalar + font.pixelSize: 16 text: modelData } } background: Rectangle { color: tabBar.Material.backgroundColor - radius: 8 * Constants.scalar + radius: 8 } } } diff --git a/src/eden/Eden/Config/pages/global/GlobalTabSwipeView.qml b/src/Eden/Config/pages/global/GlobalTabSwipeView.qml similarity index 72% rename from src/eden/Eden/Config/pages/global/GlobalTabSwipeView.qml rename to src/Eden/Config/pages/global/GlobalTabSwipeView.qml index eaa63c5265..d0fd210e71 100644 --- a/src/eden/Eden/Config/pages/global/GlobalTabSwipeView.qml +++ b/src/Eden/Config/pages/global/GlobalTabSwipeView.qml @@ -10,7 +10,7 @@ SwipeView { right: parent.right bottom: parent.bottom - leftMargin: 20 * Constants.scalar - topMargin: 10 * Constants.scalar + leftMargin: 20 + topMargin: 10 } } diff --git a/src/eden/Eden/Config/pages/graphics/RendererAdvancedPage.qml b/src/Eden/Config/pages/graphics/RendererAdvancedPage.qml similarity index 91% rename from src/eden/Eden/Config/pages/graphics/RendererAdvancedPage.qml rename to src/Eden/Config/pages/graphics/RendererAdvancedPage.qml index f6e8983eae..31197adbe8 100644 --- a/src/eden/Eden/Config/pages/graphics/RendererAdvancedPage.qml +++ b/src/Eden/Config/pages/graphics/RendererAdvancedPage.qml @@ -2,7 +2,7 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import Eden.Native.Interface +import Eden.Interface import Eden.Config ScrollView { diff --git a/src/eden/Eden/Config/pages/graphics/RendererExtensionsPage.qml b/src/Eden/Config/pages/graphics/RendererExtensionsPage.qml similarity index 91% rename from src/eden/Eden/Config/pages/graphics/RendererExtensionsPage.qml rename to src/Eden/Config/pages/graphics/RendererExtensionsPage.qml index be9efcbd28..33cfedf3c7 100644 --- a/src/eden/Eden/Config/pages/graphics/RendererExtensionsPage.qml +++ b/src/Eden/Config/pages/graphics/RendererExtensionsPage.qml @@ -2,7 +2,7 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import Eden.Native.Interface +import Eden.Interface import Eden.Config ScrollView { diff --git a/src/eden/Eden/Config/pages/graphics/RendererPage.qml b/src/Eden/Config/pages/graphics/RendererPage.qml similarity index 90% rename from src/eden/Eden/Config/pages/graphics/RendererPage.qml rename to src/Eden/Config/pages/graphics/RendererPage.qml index d1d63ff717..80ed181ee7 100644 --- a/src/eden/Eden/Config/pages/graphics/RendererPage.qml +++ b/src/Eden/Config/pages/graphics/RendererPage.qml @@ -2,7 +2,7 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import Eden.Native.Interface +import Eden.Interface import Eden.Config ScrollView { diff --git a/src/eden/Eden/Config/pages/system/AppletsPage.qml b/src/Eden/Config/pages/system/AppletsPage.qml similarity index 91% rename from src/eden/Eden/Config/pages/system/AppletsPage.qml rename to src/Eden/Config/pages/system/AppletsPage.qml index b3171d9d8b..0f8bc8e2d7 100644 --- a/src/eden/Eden/Config/pages/system/AppletsPage.qml +++ b/src/Eden/Config/pages/system/AppletsPage.qml @@ -2,7 +2,7 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import Eden.Native.Interface +import Eden.Interface import Eden.Config ScrollView { diff --git a/src/eden/Eden/Config/pages/system/FileSystemPage.qml b/src/Eden/Config/pages/system/FileSystemPage.qml similarity index 91% rename from src/eden/Eden/Config/pages/system/FileSystemPage.qml rename to src/Eden/Config/pages/system/FileSystemPage.qml index 90f6395f8f..75a2b53f1c 100644 --- a/src/eden/Eden/Config/pages/system/FileSystemPage.qml +++ b/src/Eden/Config/pages/system/FileSystemPage.qml @@ -2,7 +2,7 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import Eden.Native.Interface +import Eden.Interface import Eden.Config ScrollView { diff --git a/src/eden/Eden/Config/pages/system/SystemCorePage.qml b/src/Eden/Config/pages/system/SystemCorePage.qml similarity index 90% rename from src/eden/Eden/Config/pages/system/SystemCorePage.qml rename to src/Eden/Config/pages/system/SystemCorePage.qml index 562ba17d60..20e74987ed 100644 --- a/src/eden/Eden/Config/pages/system/SystemCorePage.qml +++ b/src/Eden/Config/pages/system/SystemCorePage.qml @@ -2,7 +2,7 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import Eden.Native.Interface +import Eden.Interface import Eden.Config ScrollView { diff --git a/src/eden/Eden/Config/pages/system/SystemGeneralPage.qml b/src/Eden/Config/pages/system/SystemGeneralPage.qml similarity index 93% rename from src/eden/Eden/Config/pages/system/SystemGeneralPage.qml rename to src/Eden/Config/pages/system/SystemGeneralPage.qml index 2d2e02b2b4..07a166f51a 100644 --- a/src/eden/Eden/Config/pages/system/SystemGeneralPage.qml +++ b/src/Eden/Config/pages/system/SystemGeneralPage.qml @@ -2,7 +2,7 @@ import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts -import Eden.Native.Interface +import Eden.Interface import Eden.Config ScrollView { diff --git a/src/Eden/Constants/CMakeLists.txt b/src/Eden/Constants/CMakeLists.txt new file mode 100644 index 0000000000..52b0b69895 --- /dev/null +++ b/src/Eden/Constants/CMakeLists.txt @@ -0,0 +1,16 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + +# SPDX-FileCopyrightText: Copyright 2025 crueter +# SPDX-License-Identifier: GPL-3.0-or-later + +set_source_files_properties(Constants.qml + PROPERTIES + QT_QML_SINGLETON_TYPE true +) + +EdenModule( + NAME Constants + URI Eden.Constants + QML_FILES Constants.qml +) diff --git a/src/eden/Eden/Constants/Constants.qml b/src/Eden/Constants/Constants.qml similarity index 100% rename from src/eden/Eden/Constants/Constants.qml rename to src/Eden/Constants/Constants.qml diff --git a/src/Eden/Interface/CMakeLists.txt b/src/Eden/Interface/CMakeLists.txt new file mode 100644 index 0000000000..f5ef364bb3 --- /dev/null +++ b/src/Eden/Interface/CMakeLists.txt @@ -0,0 +1,24 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + +# SPDX-FileCopyrightText: Copyright 2025 crueter +# SPDX-License-Identifier: GPL-3.0-or-later + +find_package(Qt6 REQUIRED COMPONENTS Core) + +qt_add_library(EdenInterface STATIC) +qt_add_qml_module(EdenInterface + URI Eden.Interface + NO_PLUGIN + SOURCES + SettingsInterface.h SettingsInterface.cpp + QMLSetting.h QMLSetting.cpp + MetaObjectHelper.h + QMLConfig.h + SOURCES TitleManager.h TitleManager.cpp +) + +target_link_libraries(EdenInterface PUBLIC Qt6::Quick) +target_link_libraries(EdenInterface PRIVATE Qt6::Core) + +add_library(Eden::Interface ALIAS EdenInterface) diff --git a/src/eden/Eden/Native/Interface/MetaObjectHelper.h b/src/Eden/Interface/MetaObjectHelper.h similarity index 100% rename from src/eden/Eden/Native/Interface/MetaObjectHelper.h rename to src/Eden/Interface/MetaObjectHelper.h diff --git a/src/eden/Eden/Native/Interface/QMLConfig.h b/src/Eden/Interface/QMLConfig.h similarity index 100% rename from src/eden/Eden/Native/Interface/QMLConfig.h rename to src/Eden/Interface/QMLConfig.h diff --git a/src/eden/Eden/Native/Interface/QMLSetting.cpp b/src/Eden/Interface/QMLSetting.cpp similarity index 99% rename from src/eden/Eden/Native/Interface/QMLSetting.cpp rename to src/Eden/Interface/QMLSetting.cpp index 4e559df26b..36bf8c0ffe 100644 --- a/src/eden/Eden/Native/Interface/QMLSetting.cpp +++ b/src/Eden/Interface/QMLSetting.cpp @@ -1,6 +1,8 @@ #include "QMLSetting.h" #include "common/settings.h" +#include + QMLSetting::QMLSetting(Settings::BasicSetting *setting, QObject *parent, RequestType request) : QObject(parent) , m_setting(setting) diff --git a/src/eden/Eden/Native/Interface/QMLSetting.h b/src/Eden/Interface/QMLSetting.h similarity index 98% rename from src/eden/Eden/Native/Interface/QMLSetting.h rename to src/Eden/Interface/QMLSetting.h index 78349ae4f4..2dbca2b2d8 100644 --- a/src/eden/Eden/Native/Interface/QMLSetting.h +++ b/src/Eden/Interface/QMLSetting.h @@ -2,7 +2,6 @@ #define QMLSETTING_H #include -#include #include "common/settings_common.h" enum class RequestType { diff --git a/src/eden/Eden/Native/Interface/SettingsInterface.cpp b/src/Eden/Interface/SettingsInterface.cpp similarity index 99% rename from src/eden/Eden/Native/Interface/SettingsInterface.cpp rename to src/Eden/Interface/SettingsInterface.cpp index 3760978f47..495751a392 100644 --- a/src/eden/Eden/Native/Interface/SettingsInterface.cpp +++ b/src/Eden/Interface/SettingsInterface.cpp @@ -7,9 +7,9 @@ SettingsInterface::SettingsInterface(QObject* parent) : QObject{parent} , translations{ConfigurationShared::InitializeTranslations(parent)} , combobox_translations{ConfigurationShared::ComboboxEnumeration(parent)} -{} +{ +} -// TODO: idExclude SettingsModel *SettingsInterface::category(SettingsCategories::Category category, QList idInclude, QList idExclude) diff --git a/src/eden/Eden/Native/Interface/SettingsInterface.h b/src/Eden/Interface/SettingsInterface.h similarity index 98% rename from src/eden/Eden/Native/Interface/SettingsInterface.h rename to src/Eden/Interface/SettingsInterface.h index 5b31c02661..89c2a15f6b 100644 --- a/src/eden/Eden/Native/Interface/SettingsInterface.h +++ b/src/Eden/Interface/SettingsInterface.h @@ -6,7 +6,7 @@ #include "QMLSetting.h" #include "qt_common/shared_translation.h" -#include "Native/Models/SettingsModel.h" +#include "Models/SettingsModel.h" namespace SettingsCategories { Q_NAMESPACE @@ -53,7 +53,6 @@ Q_ENUM_NS(Category) class SettingsInterface : public QObject { Q_OBJECT - QML_SINGLETON QML_ELEMENT public: explicit SettingsInterface(QObject* parent = nullptr); diff --git a/src/Eden/Interface/TitleManager.cpp b/src/Eden/Interface/TitleManager.cpp new file mode 100644 index 0000000000..0a3b6eca53 --- /dev/null +++ b/src/Eden/Interface/TitleManager.cpp @@ -0,0 +1,40 @@ +#include "TitleManager.h" +#include "common/scm_rev.h" +#include + +TitleManager::TitleManager(QObject *parent) {} + +const QString TitleManager::title() const +{ + static const std::string description = std::string(Common::g_build_version); + static const std::string build_id = std::string(Common::g_build_id); + static const std::string compiler = std::string(Common::g_compiler_id); + + std::string yuzu_title; + if (Common::g_is_dev_build) { + yuzu_title = fmt::format("Eden Nightly | {}-{} | {}", description, build_id, compiler); + } else { + yuzu_title = fmt::format("Eden | {} | {}", description, compiler); + } + + const auto override_title = fmt::format(fmt::runtime( + std::string(Common::g_title_bar_format_idle)), + build_id); + const auto window_title = override_title.empty() ? yuzu_title : override_title; + + // TODO(crueter): Running + + return QString::fromStdString(window_title); + // if (title_name.empty()) { + // return QString::fromStdString(window_title); + // } else { + // const auto run_title = [window_title, title_name, title_version, gpu_vendor]() { + // if (title_version.empty()) { + // return fmt::format("{} | {} | {}", window_title, title_name, gpu_vendor); + // } + // return fmt::format("{} | {} | {} | {}", window_title, title_name, title_version, + // gpu_vendor); + // }(); + // setWindowTitle(QString::fromStdString(run_title)); + // } +} diff --git a/src/Eden/Interface/TitleManager.h b/src/Eden/Interface/TitleManager.h new file mode 100644 index 0000000000..41f0eba331 --- /dev/null +++ b/src/Eden/Interface/TitleManager.h @@ -0,0 +1,18 @@ +#ifndef TITLEMANAGER_H +#define TITLEMANAGER_H + +#include + +class TitleManager : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString title READ title NOTIFY titleChanged) +public: + explicit TitleManager(QObject *parent = nullptr); + + const QString title() const; +signals: + void titleChanged(); +}; + +#endif // TITLEMANAGER_H diff --git a/src/eden/Eden/Items/AnimatedDialog.qml b/src/Eden/Items/AnimatedDialog.qml similarity index 100% rename from src/eden/Eden/Items/AnimatedDialog.qml rename to src/Eden/Items/AnimatedDialog.qml diff --git a/src/eden/Eden/Items/BetterMenu.qml b/src/Eden/Items/BetterMenu.qml similarity index 100% rename from src/eden/Eden/Items/BetterMenu.qml rename to src/Eden/Items/BetterMenu.qml diff --git a/src/eden/Eden/Items/BetterMenuBar.qml b/src/Eden/Items/BetterMenuBar.qml similarity index 100% rename from src/eden/Eden/Items/BetterMenuBar.qml rename to src/Eden/Items/BetterMenuBar.qml diff --git a/src/Eden/Items/CMakeLists.txt b/src/Eden/Items/CMakeLists.txt new file mode 100644 index 0000000000..b757cd0f5d --- /dev/null +++ b/src/Eden/Items/CMakeLists.txt @@ -0,0 +1,22 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + +# SPDX-FileCopyrightText: Copyright 2025 crueter +# SPDX-License-Identifier: GPL-3.0-or-later + +EdenModule( + NAME Items + URI Eden.Items + QML_FILES + StatusBarButton.qml + BetterMenu.qml + AnimatedDialog.qml + BetterMenuBar.qml + + SettingsTabButton.qml + IconButton.qml + VerticalTabBar.qml + fields/BetterSpinBox.qml + fields/BetterTextField.qml + fields/FieldFooter.qml +) diff --git a/src/eden/Eden/Items/IconButton.qml b/src/Eden/Items/IconButton.qml similarity index 82% rename from src/eden/Eden/Items/IconButton.qml rename to src/Eden/Items/IconButton.qml index 70192e9ea7..09c7894923 100644 --- a/src/eden/Eden/Items/IconButton.qml +++ b/src/Eden/Items/IconButton.qml @@ -8,8 +8,8 @@ Button { bottomInset: 0 topInset: 0 - leftPadding: 5 * Constants.scalar - rightPadding: 5 * Constants.scalar + leftPadding: 5 + rightPadding: 5 width: icon.width height: icon.height diff --git a/src/eden/Eden/Items/SettingsTabButton.qml b/src/Eden/Items/SettingsTabButton.qml similarity index 72% rename from src/eden/Eden/Items/SettingsTabButton.qml rename to src/Eden/Items/SettingsTabButton.qml index e4d7bd0891..aa7955e059 100644 --- a/src/eden/Eden/Items/SettingsTabButton.qml +++ b/src/Eden/Items/SettingsTabButton.qml @@ -9,15 +9,15 @@ TabButton { id: button - implicitHeight: 100 * Constants.scalar - width: 95 * Constants.scalar + implicitHeight: 100 + width: 95 contentItem: ColumnLayout { IconButton { label: button.label - Layout.maximumHeight: 60 * Constants.scalar - Layout.maximumWidth: 65 * Constants.scalar + Layout.maximumHeight: 60 + Layout.maximumWidth: 65 Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter @@ -25,7 +25,7 @@ TabButton { } Text { - font.pixelSize: 16 * Constants.scalar + font.pixelSize: 16 text: label Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter diff --git a/src/eden/Eden/Items/StatusBarButton.qml b/src/Eden/Items/StatusBarButton.qml similarity index 92% rename from src/eden/Eden/Items/StatusBarButton.qml rename to src/Eden/Items/StatusBarButton.qml index 47691bc8b4..e4037f0996 100644 --- a/src/eden/Eden/Items/StatusBarButton.qml +++ b/src/Eden/Items/StatusBarButton.qml @@ -25,7 +25,7 @@ MouseArea { Text { id: txt - font.pixelSize: 12 * Constants.scalar + font.pixelSize: 12 leftPadding: 4 rightPadding: 4 diff --git a/src/eden/Eden/Items/VerticalTabBar.qml b/src/Eden/Items/VerticalTabBar.qml similarity index 88% rename from src/eden/Eden/Items/VerticalTabBar.qml rename to src/Eden/Items/VerticalTabBar.qml index b5d8b8c13f..ca15f195e7 100644 --- a/src/eden/Eden/Items/VerticalTabBar.qml +++ b/src/Eden/Items/VerticalTabBar.qml @@ -25,14 +25,14 @@ TabBar { highlight: Item { z: 2 Rectangle { - radius: 5 * Constants.scalar + radius: 5 anchors { right: parent.right verticalCenter: parent.verticalCenter } height: parent.height / 2 - width: 5 * Constants.scalar + width: 5 color: Constants.accent } @@ -41,6 +41,6 @@ TabBar { background: Rectangle { color: control.Material.backgroundColor - radius: 8 * Constants.scalar + radius: 8 } } diff --git a/src/eden/Eden/Items/fields/BetterSpinBox.qml b/src/Eden/Items/fields/BetterSpinBox.qml similarity index 87% rename from src/eden/Eden/Items/fields/BetterSpinBox.qml rename to src/Eden/Items/fields/BetterSpinBox.qml index 0d4980506b..0dd1d76989 100644 --- a/src/eden/Eden/Items/fields/BetterSpinBox.qml +++ b/src/Eden/Items/fields/BetterSpinBox.qml @@ -38,8 +38,8 @@ SpinBox { x: control.mirrored ? 0 : control.width - width - implicitWidth: 40 * Constants.scalar - implicitHeight: 40 * Constants.scalar + implicitWidth: 40 + implicitHeight: 40 height: parent.height width: height / 2 @@ -52,8 +52,8 @@ SpinBox { x: control.mirrored ? control.width - width : 0 - implicitWidth: 40 * Constants.scalar - implicitHeight: 40 * Constants.scalar + implicitWidth: 40 + implicitHeight: 40 height: parent.height width: height / 2 diff --git a/src/eden/Eden/Items/fields/BetterTextField.qml b/src/Eden/Items/fields/BetterTextField.qml similarity index 88% rename from src/eden/Eden/Items/fields/BetterTextField.qml rename to src/Eden/Items/fields/BetterTextField.qml index a72865b18d..22a10097ba 100644 --- a/src/eden/Eden/Items/fields/BetterTextField.qml +++ b/src/Eden/Items/fields/BetterTextField.qml @@ -24,13 +24,13 @@ TextField { id: txt text: suffix - font.pixelSize: 14 * Constants.scalar + font.pixelSize: 14 anchors { verticalCenter: parent.verticalCenter right: parent.right - rightMargin: 5 * Constants.scalar + rightMargin: 5 } color: "gray" diff --git a/src/eden/Eden/Items/fields/FieldFooter.qml b/src/Eden/Items/fields/FieldFooter.qml similarity index 91% rename from src/eden/Eden/Items/fields/FieldFooter.qml rename to src/Eden/Items/fields/FieldFooter.qml index 58d237d1ea..2e5b24715f 100644 --- a/src/eden/Eden/Items/fields/FieldFooter.qml +++ b/src/Eden/Items/fields/FieldFooter.qml @@ -3,7 +3,7 @@ import QtQuick.Controls.Material import Eden.Constants Rectangle { - height: 2 * Constants.scalar + height: 2 color: enabled ? Constants.text : Qt.darker(Constants.text, 1.5) width: parent.width diff --git a/src/Eden/Main/CMakeLists.txt b/src/Eden/Main/CMakeLists.txt new file mode 100644 index 0000000000..7c9ceb19db --- /dev/null +++ b/src/Eden/Main/CMakeLists.txt @@ -0,0 +1,22 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + +# SPDX-FileCopyrightText: Copyright 2025 crueter +# SPDX-License-Identifier: GPL-3.0-or-later + +EdenModule( + NAME Main + URI Eden.Main + QML_FILES + Main.qml + StatusBar.qml + GameList.qml + + GameGridCard.qml + GameGrid.qml + MarqueeText.qml + + GameCarouselCard.qml + GameCarousel.qml + LIBRARIES Eden::Interface +) diff --git a/src/Eden/Main/GameCarousel.qml b/src/Eden/Main/GameCarousel.qml new file mode 100644 index 0000000000..09995b6786 --- /dev/null +++ b/src/Eden/Main/GameCarousel.qml @@ -0,0 +1,87 @@ +import QtQuick +import QtQuick.Controls +import Qt.labs.platform +import QtCore + +import Eden.Constants +import Eden.Interface + +ListView { + id: carousel + + focus: true + focusPolicy: Qt.StrongFocus + + model: EdenGameList + orientation: ListView.Horizontal + clip: false + flickDeceleration: 1500 + snapMode: ListView.SnapToItem + + spacing: 20 + + keyNavigationWraps: true + + function increment() { + incrementCurrentIndex() + if (currentIndex === count) + currentIndex = 0 + } + + function decrement() { + decrementCurrentIndex() + if (currentIndex === -1) + currentIndex = count - 1 + } + + // TODO(crueter): handle move/displace/add (requires thread worker on game list and a bunch of other shit) + Rectangle { + id: hg + clip: false + z: 3 + + property var item: carousel.currentItem + + anchors { + centerIn: parent + } + + height: item === null ? 0 : item.height + 10 + width: item === null ? 0 : item.width + 10 + + color: "transparent" + border { + color: "deepskyblue" + width: 4 + } + + radius: 8 + + MarqueeText { + id: container + anchors.bottom: hg.top + anchors.left: hg.left + anchors.right: hg.right + + canMarquee: true + text: hg.item === null ? "" : toTitleCase(hg.item.title) + + font.pixelSize: 22 + font.family: "Monospace" + + color: "lightblue" + background: Constants.bg + } + } + + highlightRangeMode: ListView.StrictlyEnforceRange + preferredHighlightBegin: currentItem === null ? 0 : x + width / 2 - currentItem.width / 2 + preferredHighlightEnd: currentItem === null ? 0 : x + width / 2 + currentItem.width / 2 + + highlightMoveDuration: 300 + delegate: GameCarouselCard { + id: game + width: 300 + height: 300 + } +} diff --git a/src/eden/Eden/Main/GameCarouselCard.qml b/src/Eden/Main/GameCarouselCard.qml similarity index 87% rename from src/eden/Eden/Main/GameCarouselCard.qml rename to src/Eden/Main/GameCarouselCard.qml index 51cb3a1f23..ef0e7e30bd 100644 --- a/src/eden/Eden/Main/GameCarouselCard.qml +++ b/src/Eden/Main/GameCarouselCard.qml @@ -17,7 +17,7 @@ Item { anchors.fill: parent color: "transparent" border { - width: 4 * Constants.scalar + width: 4 color: PathView.isCurrentItem ? "deepskyblue" : "transparent" } @@ -32,7 +32,7 @@ Item { anchors { fill: parent - margins: 10 * Constants.scalar + margins: 10 } } } diff --git a/src/eden/Eden/Main/GameGrid.qml b/src/Eden/Main/GameGrid.qml similarity index 63% rename from src/eden/Eden/Main/GameGrid.qml rename to src/Eden/Main/GameGrid.qml index 9231d2b7a8..2c9118607e 100644 --- a/src/eden/Eden/Main/GameGrid.qml +++ b/src/Eden/Main/GameGrid.qml @@ -4,8 +4,7 @@ import Qt.labs.platform import QtCore import Eden.Constants -import Eden.Native.Interface -import Eden.Native.Gamepad +import Eden.Interface GridView { property var setting @@ -17,25 +16,25 @@ GridView { clip: true cellWidth: cellSize - cellHeight: cellSize + 60 * Constants.scalar + cellHeight: cellSize + 20 model: EdenGameList delegate: GameGridCard { id: game - width: grid.cellSize - 20 * Constants.scalar - height: grid.cellHeight - 20 * Constants.scalar + width: grid.cellSize - 20 + height: grid.cellHeight - 20 } highlight: Rectangle { color: "transparent" z: 5 - radius: 16 * Constants.scalar + radius: 16 border { - color: Constants.text - width: 3 + color: "deepskyblue" + width: 4 } } diff --git a/src/eden/Eden/Main/GameGridCard.qml b/src/Eden/Main/GameGridCard.qml similarity index 70% rename from src/eden/Eden/Main/GameGridCard.qml rename to src/Eden/Main/GameGridCard.qml index 634c325974..3e379c1d11 100644 --- a/src/eden/Eden/Main/GameGridCard.qml +++ b/src/Eden/Main/GameGridCard.qml @@ -9,7 +9,7 @@ Rectangle { id: wrapper color: Constants.dialog - radius: 16 * Constants.scalar + radius: 16 Image { id: image @@ -21,13 +21,14 @@ Rectangle { anchors { top: parent.top + bottom: nameText.top left: parent.left right: parent.right - margins: 4 * Constants.scalar + margins: 10 } - height: parent.height - 40 * Constants.scalar + height: parent.height MouseArea { id: mouseArea @@ -50,28 +51,29 @@ Rectangle { } } - Text { + MarqueeText { id: nameText + clip: true anchors { bottom: parent.bottom - bottomMargin: 5 * Constants.scalar + bottomMargin: 5 left: parent.left right: parent.right + + leftMargin: 5 + rightMargin: 5 } - style: Text.Outline - styleColor: Constants.bg + text: toTitleCase(model.name.replace(/-/g, " ")) - text: model.name.replace(/-/g, " ") - wrapMode: Text.WordWrap - horizontalAlignment: Qt.AlignHCenter + font.pixelSize: 18 + font.family: "Monospace" - font { - pixelSize: 15 * Constants.scalar - } + color: "lightblue" + background: Constants.dialog - color: "white" + canMarquee: wrapper.GridView.isCurrentItem } } diff --git a/src/Eden/Main/GameList.qml b/src/Eden/Main/GameList.qml new file mode 100644 index 0000000000..dedcb33f4d --- /dev/null +++ b/src/Eden/Main/GameList.qml @@ -0,0 +1,127 @@ +import QtQuick +import QtQuick.Controls +import Qt.labs.platform +import QtCore + +import Eden.Constants +import Eden.Interface + +// import Eden.Native.Gamepad +Rectangle { + id: root + + property var setting: SettingsInterface.setting("grid_columns") + + property int gx: 0 + property int gy: 0 + + readonly property int deadzone: 8000 + readonly property int repeatTimeMs: 125 + + color: Constants.bg + + // TODO: use the original yuzu backend for dis + // Gamepad { + // id: gamepad + + // // onUpPressed: grid.moveCurrentIndexUp() + // // onDownPressed: grid.moveCurrentIndexDown() + // // onLeftPressed: grid.moveCurrentIndexLeft() + // // onRightPressed: grid.moveCurrentIndexRight() + // onLeftPressed: carousel.decrement() + // onRightPressed: carousel.increment() + // onAPressed: console.log("A pressed") + // onLeftStickMoved: (x, y) => { + // gx = x + // gy = y + // } + // } + + // Timer { + // interval: repeatTimeMs + // running: true + // repeat: true + // onTriggered: { + // if (gx > deadzone) { + // gamepad.rightPressed() + // } else if (gx < -deadzone) { + // gamepad.leftPressed() + // } + + // if (gy > deadzone) { + // gamepad.downPressed() + // } else if (gy < -deadzone) { + // gamepad.upPressed() + // } + // } + // } + // Timer { + // interval: 16 + // running: true + // repeat: true + // onTriggered: gamepad.pollEvents() + // } + FolderDialog { + id: openDir + folder: StandardPaths.writableLocation(StandardPaths.HomeLocation) + onAccepted: { + button.visible = false + view.anchors.bottom = root.bottom + EdenGameList.addDir(folder) + } + } + + Item { + id: view + + anchors { + bottom: button.top + left: parent.left + right: parent.right + top: parent.top + margins: 8 + } + + GameGrid { + setting: root.setting + + id: grid + + anchors.fill: parent + } + // GameCarousel { + // id: carousel + + // height: 300 + + // anchors { + // right: view.right + // left: view.left + + // verticalCenter: view.verticalCenter + // } + // } + } + + Button { + id: button + font.pixelSize: 25 + + anchors { + left: parent.left + right: parent.right + + bottom: parent.bottom + + margins: 8 + } + + text: "Add Directory" + onClicked: openDir.open() + + background: Rectangle { + color: button.pressed ? Constants.accentPressed : Constants.accent + radius: 5 + } + } +} diff --git a/src/eden/Eden/Main/Main.qml b/src/Eden/Main/Main.qml similarity index 99% rename from src/eden/Eden/Main/Main.qml rename to src/Eden/Main/Main.qml index d0be3a27f5..66323ce2d2 100644 --- a/src/eden/Eden/Main/Main.qml +++ b/src/Eden/Main/Main.qml @@ -9,7 +9,7 @@ ApplicationWindow { width: Constants.width height: Constants.height visible: true - title: qsTr("eden") + title: TitleManager.title Material.theme: Material.Dark Material.accent: Material.Red diff --git a/src/Eden/Main/MarqueeText.qml b/src/Eden/Main/MarqueeText.qml new file mode 100644 index 0000000000..2b46dc13fc --- /dev/null +++ b/src/Eden/Main/MarqueeText.qml @@ -0,0 +1,129 @@ +import QtQuick +import QtQuick.Controls + +import Eden.Constants + +Item { + id: container + + anchors {} + + height: txt.contentHeight + clip: true + + // TODO(crueter): util? + function toTitleCase(str) { + return str.replace(/\w\S*/g, text => text.charAt(0).toUpperCase( + ) + text.substring(1).toLowerCase()) + } + + property string text + property string spacing: " " + property string combined: text + spacing + property string display: animate ? combined.substring( + step) + combined.substring( + 0, step) : text + property int step: 0 + property bool animate: canMarquee && txt.contentWidth > parent.width + + property bool canMarquee: false + + property font font + property color color + property color background + + onCanMarqueeChanged: checkMarquee() + + function checkMarquee() { + if (canMarquee && txt.contentWidth > width) { + step = 0 + delay.start() + } else { + delay.stop() + marquee.stop() + } + } + + Timer { + id: marquee + + interval: 150 + running: false + repeat: true + onTriggered: { + parent.step = (parent.step + 1) % parent.combined.length + if (parent.step === 0) { + stop() + delay.start() + } + } + } + + Timer { + id: delay + interval: 1500 + repeat: false + onTriggered: { + marquee.start() + } + } + + // fake container to gauge contentWidth + Text { + id: txt + visible: false + text: parent.text + font: container.font + + onContentWidthChanged: container.checkMarquee() + } + + Text { + anchors { + fill: parent + leftMargin: 10 + rightMargin: 10 + } + + color: container.color + font: container.font + text: parent.display + + horizontalAlignment: Text.AlignLeft + } + + Rectangle { + anchors.fill: parent + z: 2 + + gradient: Gradient { + orientation: Gradient.Horizontal + GradientStop { + position: 0.0 + color: marquee.running ? container.background : "transparent" + Behavior on color { + ColorAnimation { + duration: 200 + } + } + } + GradientStop { + position: 0.1 + color: "transparent" + } + GradientStop { + position: 0.9 + color: "transparent" + } + GradientStop { + position: 1.0 + color: marquee.running ? container.background : "transparent" + Behavior on color { + ColorAnimation { + duration: 200 + } + } + } + } + } +} diff --git a/src/eden/Eden/Main/StatusBar.qml b/src/Eden/Main/StatusBar.qml similarity index 100% rename from src/eden/Eden/Main/StatusBar.qml rename to src/Eden/Main/StatusBar.qml diff --git a/src/Eden/Models/CMakeLists.txt b/src/Eden/Models/CMakeLists.txt new file mode 100644 index 0000000000..f71aa78fe4 --- /dev/null +++ b/src/Eden/Models/CMakeLists.txt @@ -0,0 +1,17 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + +# SPDX-FileCopyrightText: Copyright 2025 crueter +# SPDX-License-Identifier: GPL-3.0-or-later + +qt_add_library(EdenModels STATIC + GameListModel.h GameListModel.cpp + SettingsModel.h SettingsModel.cpp +) + +target_link_libraries(EdenModels + PRIVATE + Qt6::Gui +) + +add_library(Eden::Models ALIAS EdenModels) diff --git a/src/eden/Eden/Native/Models/GameListModel.cpp b/src/Eden/Models/GameListModel.cpp similarity index 100% rename from src/eden/Eden/Native/Models/GameListModel.cpp rename to src/Eden/Models/GameListModel.cpp diff --git a/src/eden/Eden/Native/Models/GameListModel.h b/src/Eden/Models/GameListModel.h similarity index 100% rename from src/eden/Eden/Native/Models/GameListModel.h rename to src/Eden/Models/GameListModel.h diff --git a/src/eden/Eden/Native/Models/SettingsModel.cpp b/src/Eden/Models/SettingsModel.cpp similarity index 100% rename from src/eden/Eden/Native/Models/SettingsModel.cpp rename to src/Eden/Models/SettingsModel.cpp diff --git a/src/eden/Eden/Native/Models/SettingsModel.h b/src/Eden/Models/SettingsModel.h similarity index 95% rename from src/eden/Eden/Native/Models/SettingsModel.h rename to src/Eden/Models/SettingsModel.h index 26729f45aa..215ce32b00 100644 --- a/src/eden/Eden/Native/Models/SettingsModel.h +++ b/src/Eden/Models/SettingsModel.h @@ -2,7 +2,7 @@ #define SETTINGSMODEL_H #include -#include "Native/Interface/QMLSetting.h" +#include "Interface/QMLSetting.h" class SettingsModel : public QAbstractListModel { Q_OBJECT diff --git a/src/Eden/Native/CMakeLists.txt b/src/Eden/Native/CMakeLists.txt new file mode 100644 index 0000000000..c3367c3cd0 --- /dev/null +++ b/src/Eden/Native/CMakeLists.txt @@ -0,0 +1,65 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + +# SPDX-FileCopyrightText: Copyright 2025 crueter +# SPDX-License-Identifier: GPL-3.0-or-later + +qt_add_executable(eden + main.cpp + icons.qrc +) + +set(MODULES + Eden::Util + Eden::Items + Eden::Config + Eden::Interface + Eden::Constants + Eden::Main + Eden::Models +) + +# if (ENABLE_SDL2) +# add_subdirectory(Gamepad) +# set(MODULES ${MODULES} Eden::Gamepad) +# endif() + +target_link_libraries(eden + PRIVATE + Qt6::Core + Qt6::Widgets + Qt6::Gui + Qt6::Quick + Qt6::QuickControls2 + + ${MODULES} +) + +target_link_libraries(eden PRIVATE common core input_common frontend_common qt_common network video_core) +target_link_libraries(eden PRIVATE Boost::headers glad fmt) +target_link_libraries(eden PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) + +target_link_libraries(eden PRIVATE Vulkan::Headers) + +target_compile_definitions(eden PRIVATE + # Use QStringBuilder for string concatenation to reduce + # the overall number of temporary strings created. + -DQT_USE_QSTRINGBUILDER + + # Disable implicit type narrowing in signal/slot connect() calls. + -DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT + + # Disable unsafe overloads of QProcess' start() function. + -DQT_NO_PROCESS_COMBINED_ARGUMENT_START + + # Disable implicit QString->QUrl conversions to enforce use of proper resolving functions. + -DQT_NO_URL_CAST_FROM_STRING +) + +set_target_properties(eden PROPERTIES OUTPUT_NAME "eden") +include(GNUInstallDirs) +install(TARGETS eden + BUNDLE DESTINATION . + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) diff --git a/src/Eden/Native/Gamepad/CMakeLists.txt b/src/Eden/Native/Gamepad/CMakeLists.txt new file mode 100644 index 0000000000..c81555db2f --- /dev/null +++ b/src/Eden/Native/Gamepad/CMakeLists.txt @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + +# SPDX-FileCopyrightText: Copyright 2025 crueter +# SPDX-License-Identifier: GPL-3.0-or-later + +EdenModule( + NAME Gamepad + URI Eden.Native.Gamepad + SOURCES gamepad.h gamepad.cpp +) diff --git a/src/eden/Eden/Native/Gamepad/gamepad.cpp b/src/Eden/Native/Gamepad/gamepad.cpp similarity index 100% rename from src/eden/Eden/Native/Gamepad/gamepad.cpp rename to src/Eden/Native/Gamepad/gamepad.cpp diff --git a/src/eden/Eden/Native/Gamepad/gamepad.h b/src/Eden/Native/Gamepad/gamepad.h similarity index 100% rename from src/eden/Eden/Native/Gamepad/gamepad.h rename to src/Eden/Native/Gamepad/gamepad.h diff --git a/src/eden/Eden/Native/icons.qrc b/src/Eden/Native/icons.qrc similarity index 84% rename from src/eden/Eden/Native/icons.qrc rename to src/Eden/Native/icons.qrc index 9844c5ff9e..21c212b6a1 100644 --- a/src/eden/Eden/Native/icons.qrc +++ b/src/Eden/Native/icons.qrc @@ -10,5 +10,6 @@ icons/forward.svg icons/back.svg icons/help.svg + ../../../dist/dev.eden_emu.eden.svg diff --git a/src/eden/Eden/Native/icons/audio.svg b/src/Eden/Native/icons/audio.svg similarity index 100% rename from src/eden/Eden/Native/icons/audio.svg rename to src/Eden/Native/icons/audio.svg diff --git a/src/eden/Eden/Native/icons/back.svg b/src/Eden/Native/icons/back.svg similarity index 100% rename from src/eden/Eden/Native/icons/back.svg rename to src/Eden/Native/icons/back.svg diff --git a/src/eden/Eden/Native/icons/controls.svg b/src/Eden/Native/icons/controls.svg similarity index 100% rename from src/eden/Eden/Native/icons/controls.svg rename to src/Eden/Native/icons/controls.svg diff --git a/src/eden/Eden/Native/icons/cpu.svg b/src/Eden/Native/icons/cpu.svg similarity index 100% rename from src/eden/Eden/Native/icons/cpu.svg rename to src/Eden/Native/icons/cpu.svg diff --git a/src/eden/Eden/Native/icons/debug.svg b/src/Eden/Native/icons/debug.svg similarity index 100% rename from src/eden/Eden/Native/icons/debug.svg rename to src/Eden/Native/icons/debug.svg diff --git a/src/eden/Eden/Native/icons/forward.svg b/src/Eden/Native/icons/forward.svg similarity index 100% rename from src/eden/Eden/Native/icons/forward.svg rename to src/Eden/Native/icons/forward.svg diff --git a/src/eden/Eden/Native/icons/general.svg b/src/Eden/Native/icons/general.svg similarity index 100% rename from src/eden/Eden/Native/icons/general.svg rename to src/Eden/Native/icons/general.svg diff --git a/src/eden/Eden/Native/icons/graphics.svg b/src/Eden/Native/icons/graphics.svg similarity index 100% rename from src/eden/Eden/Native/icons/graphics.svg rename to src/Eden/Native/icons/graphics.svg diff --git a/src/eden/Eden/Native/icons/help.svg b/src/Eden/Native/icons/help.svg similarity index 100% rename from src/eden/Eden/Native/icons/help.svg rename to src/Eden/Native/icons/help.svg diff --git a/src/eden/Eden/Native/icons/system.svg b/src/Eden/Native/icons/system.svg similarity index 100% rename from src/eden/Eden/Native/icons/system.svg rename to src/Eden/Native/icons/system.svg diff --git a/src/eden/Eden/Native/main.cpp b/src/Eden/Native/main.cpp similarity index 72% rename from src/eden/Eden/Native/main.cpp rename to src/Eden/Native/main.cpp index 6fbf1e57d9..5dd0446fec 100644 --- a/src/eden/Eden/Native/main.cpp +++ b/src/Eden/Native/main.cpp @@ -1,10 +1,11 @@ #include #include #include +#include "Interface/QMLConfig.h" +#include "Interface/SettingsInterface.h" +#include "Interface/TitleManager.h" +#include "Models/GameListModel.h" #include "core/core.h" -#include "Native/Interface/QMLConfig.h" -#include "Native/Models/GameListModel.h" -#include "Native/Interface/SettingsInterface.h" #include @@ -17,6 +18,7 @@ int main(int argc, char *argv[]) QCoreApplication::setOrganizationName(QStringLiteral("eden-emu")); QCoreApplication::setApplicationName(QStringLiteral("eden")); QApplication::setDesktopFileName(QStringLiteral("org.eden-emu.eden")); + QGuiApplication::setWindowIcon(QIcon(":/icons/eden.svg")); /// Settings, etc Settings::SetConfiguringGlobal(true); @@ -39,12 +41,20 @@ int main(int argc, char *argv[]) ctx->setContextProperty(QStringLiteral("QtConfig"), QVariant::fromValue(config)); // Enums - qmlRegisterUncreatableMetaObject(SettingsCategories::staticMetaObject, "Eden.Native.Interface", 1, 0, "SettingsCategories", QString()); + qmlRegisterUncreatableMetaObject(SettingsCategories::staticMetaObject, "Eden.Interface", 1, 0, "SettingsCategories", QString()); // Directory List GameListModel *gameListModel = new GameListModel(&app); ctx->setContextProperty(QStringLiteral("EdenGameList"), gameListModel); + // Settings Interface + SettingsInterface *interface = new SettingsInterface(&engine); + ctx->setContextProperty(QStringLiteral("SettingsInterface"), interface); + + // Title Manager + TitleManager *title = new TitleManager(&engine); + ctx->setContextProperty(QStringLiteral("TitleManager"), title); + /// LOAD QObject::connect( &engine, diff --git a/src/Eden/Util/CMakeLists.txt b/src/Eden/Util/CMakeLists.txt new file mode 100644 index 0000000000..f2841da2c1 --- /dev/null +++ b/src/Eden/Util/CMakeLists.txt @@ -0,0 +1,17 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + +# SPDX-FileCopyrightText: Copyright 2025 crueter +# SPDX-License-Identifier: GPL-3.0-or-later + +set_source_files_properties(Util.qml + PROPERTIES + QT_QML_SINGLETON_TYPE true +) + +EdenModule( + NAME Util + URI Eden.Util + QML_FILES + Util.qml +) diff --git a/src/eden/Eden/Util/Util.qml b/src/Eden/Util/Util.qml similarity index 100% rename from src/eden/Eden/Util/Util.qml rename to src/Eden/Util/Util.qml diff --git a/src/eden/.gitignore b/src/eden/.gitignore deleted file mode 100644 index aa3808c5a9..0000000000 --- a/src/eden/.gitignore +++ /dev/null @@ -1,82 +0,0 @@ -# This file is used to ignore files which are generated -# ---------------------------------------------------------------------------- - -*~ -*.autosave -*.a -*.core -*.moc -*.o -*.obj -*.orig -*.rej -*.so -*.so.* -*_pch.h.cpp -*_resource.rc -*.qm -.#* -*.*# -core -!core/ -tags -.DS_Store -.directory -*.debug -Makefile* -*.prl -*.app -moc_*.cpp -ui_*.h -qrc_*.cpp -Thumbs.db -*.res -*.rc -/.qmake.cache -/.qmake.stash - -# qtcreator generated files -*.pro.user* -*.qbs.user* -CMakeLists.txt.user* - -# xemacs temporary files -*.flc - -# Vim temporary files -.*.swp - -# Visual Studio generated files -*.ib_pdb_index -*.idb -*.ilk -*.pdb -*.sln -*.suo -*.vcproj -*vcproj.*.*.user -*.ncb -*.sdf -*.opensdf -*.vcxproj -*vcxproj.* - -# MinGW generated files -*.Debug -*.Release - -# Python byte code -*.pyc - -# Binaries -# -------- -*.dll -*.exe - -# Directories with generated files -.moc/ -.obj/ -.pch/ -.rcc/ -.uic/ -/build*/ diff --git a/src/eden/CMakeLists.txt b/src/eden/CMakeLists.txt deleted file mode 100644 index 329b07bae7..0000000000 --- a/src/eden/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -set(CMAKE_AUTOMOC ON) -set(CMAKE_AUTORCC ON) -set(CMAKE_INCLUDE_CURRENT_DIR ON) - -find_package(Qt6 REQUIRED COMPONENTS Widgets Core Gui Quick QuickControls2) - -qt_standard_project_setup(REQUIRES 6.7) - -add_subdirectory(Eden) diff --git a/src/eden/Eden/CMakeLists.txt b/src/eden/Eden/CMakeLists.txt deleted file mode 100644 index c3904c36d0..0000000000 --- a/src/eden/Eden/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -include_directories(AFTER "${CMAKE_CURRENT_SOURCE_DIR}") - -add_subdirectory(Config) -add_subdirectory(Constants) -add_subdirectory(Items) -add_subdirectory(Util) -add_subdirectory(Main) - -add_subdirectory(Native) diff --git a/src/eden/Eden/Config/CMakeLists.txt b/src/eden/Eden/Config/CMakeLists.txt deleted file mode 100644 index d5aefc012b..0000000000 --- a/src/eden/Eden/Config/CMakeLists.txt +++ /dev/null @@ -1,57 +0,0 @@ -set(CMAKE_AUTOMOC ON) - -qt_add_library(EdenConfig STATIC) -qt_add_qml_module(EdenConfig - URI Eden.Config - VERSION 1.0 - - QML_FILES GlobalConfigureDialog.qml - QML_FILES Setting.qml - QML_FILES SectionHeader.qml - - QML_FILES pages/SettingsList.qml - - QML_FILES pages/global/GlobalTab.qml - QML_FILES pages/global/GlobalTabSwipeView.qml - QML_FILES pages/global/GlobalGeneralPage.qml - - QML_FILES pages/global/GlobalSystemPage.qml - QML_FILES pages/global/GlobalCpuPage.qml - QML_FILES pages/global/GlobalGraphicsPage.qml - QML_FILES pages/global/GlobalAudioPage.qml - - QML_FILES pages/general/UiGeneralPage.qml - QML_FILES pages/general/UiGameListPage.qml - QML_FILES - - QML_FILES pages/graphics/RendererPage.qml - QML_FILES pages/graphics/RendererAdvancedPage.qml - QML_FILES pages/graphics/RendererExtensionsPage.qml - - QML_FILES pages/system/SystemGeneralPage.qml - QML_FILES - QML_FILES pages/system/FileSystemPage.qml - QML_FILES pages/system/AppletsPage.qml - - QML_FILES pages/cpu/CpuGeneralPage.qml - - QML_FILES pages/audio/AudioGeneralPage.qml - QML_FILES pages/global/GlobalDebugPage.qml - QML_FILES pages/debug/DebugGeneralPage.qml - QML_FILES pages/debug/DebugGraphicsPage.qml - QML_FILES pages/debug/DebugAdvancedPage.qml - QML_FILES pages/debug/DebugCpuPage.qml - QML_FILES fields/ConfigCheckbox.qml - QML_FILES fields/FieldLabel.qml - QML_FILES fields/ConfigComboBox.qml - QML_FILES TestSetting.qml - QML_FILES fields/ConfigIntLine.qml - QML_FILES fields/ConfigTimeEdit.qml - QML_FILES fields/ConfigIntSpin.qml - QML_FILES fields/ConfigHexEdit.qml - QML_FILES fields/ConfigStringEdit.qml - QML_FILES fields/FieldCheckbox.qml - QML_FILES fields/ConfigIntSlider.qml - QML_FILES pages/system/SystemCorePage.qml - QML_FILES fields/BaseField.qml -) diff --git a/src/eden/Eden/Constants/CMakeLists.txt b/src/eden/Eden/Constants/CMakeLists.txt deleted file mode 100644 index 3fb7aec6d0..0000000000 --- a/src/eden/Eden/Constants/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -set(CMAKE_AUTOMOC ON) - -find_package(Qt6 REQUIRED COMPONENTS Quick) - -set_source_files_properties(Constants.qml - PROPERTIES - QT_QML_SINGLETON_TYPE true -) - -qt_add_library(EdenConstants STATIC) -qt_add_qml_module(EdenConstants - URI Eden.Constants - OUTPUT_DIRECTORY EdenConstants - VERSION 1.0 - QML_FILES - - Constants.qml -) - -target_link_libraries(EdenConstants - PRIVATE - Qt6::Quick -) diff --git a/src/eden/Eden/Items/CMakeLists.txt b/src/eden/Eden/Items/CMakeLists.txt deleted file mode 100644 index 06764ee7bb..0000000000 --- a/src/eden/Eden/Items/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -set(CMAKE_AUTOMOC ON) - -qt_add_library(EdenItems STATIC) - -qt_add_qml_module(EdenItems - URI Eden.Items - VERSION 1.0 - QML_FILES - - StatusBarButton.qml - BetterMenu.qml - AnimatedDialog.qml - BetterMenuBar.qml - - SettingsTabButton.qml - IconButton.qml - QML_FILES VerticalTabBar.qml - QML_FILES - QML_FILES fields/BetterSpinBox.qml - QML_FILES fields/BetterTextField.qml - QML_FILES fields/FieldFooter.qml -) diff --git a/src/eden/Eden/Main/CMakeLists.txt b/src/eden/Eden/Main/CMakeLists.txt deleted file mode 100644 index b802ab1b40..0000000000 --- a/src/eden/Eden/Main/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -set(CMAKE_AUTOMOC ON) - -qt_add_library(EdenMain STATIC) -qt_add_qml_module(EdenMain - URI Eden.Main - VERSION 1.0 - QML_FILES - - Main.qml - StatusBar.qml - GameList.qml - GameGridCard.qml - MarqueeText.qml - GameGrid.qml - - GameCarouselCard.qml - GameCarousel.qml -) diff --git a/src/eden/Eden/Main/GameCarousel.qml b/src/eden/Eden/Main/GameCarousel.qml deleted file mode 100644 index 599310a15f..0000000000 --- a/src/eden/Eden/Main/GameCarousel.qml +++ /dev/null @@ -1,195 +0,0 @@ -import QtQuick -import QtQuick.Controls -import Qt.labs.platform -import QtCore - -import Eden.Constants -import Eden.Native.Interface - -ListView { - id: carousel - - focus: true - focusPolicy: Qt.StrongFocus - - model: EdenGameList - orientation: ListView.Horizontal - clip: false - flickDeceleration: 1500 - snapMode: ListView.SnapToItem - - onHeightChanged: console.log(width, height) - - spacing: 20 - - keyNavigationWraps: true - - function increment() { - incrementCurrentIndex() - if (currentIndex === count) - currentIndex = 0 - } - - function decrement() { - decrementCurrentIndex() - if (currentIndex === -1) - currentIndex = count - 1 - } - - // TODO(crueter): handle move/displace/add (requires thread worker on game list and a bunch of other shit) - Rectangle { - id: hg - clip: false - z: 3 - - property var item: carousel.currentItem - - anchors { - centerIn: parent - } - - height: item === null ? 0 : item.height + 10 - width: item === null ? 0 : item.width + 10 - - color: "transparent" - border { - color: "deepskyblue" - width: 4 * Constants.scalar - } - - radius: 8 * Constants.scalar - - Item { - id: container - - anchors { - bottom: hg.top - - left: hg.left - right: hg.right - } - - height: txt.contentHeight - clip: true - - function toTitleCase(str) { - return str.replace(/\w\S*/g, text => text.charAt(0).toUpperCase( - ) + text.substring(1).toLowerCase()) - } - - property string text: hg.item === null ? "" : toTitleCase( - hg.item.title) - property string spacing: " " - property string combined: text + spacing - property string display: animate ? combined.substring( - step) + combined.substring( - 0, step) : text - property int step: 0 - property bool animate: txt.contentWidth > hg.width - - Timer { - id: marquee - - interval: 150 - running: false - repeat: true - onTriggered: { - parent.step = (parent.step + 1) % parent.combined.length - if (parent.step === 0) { - stop() - delay.start() - } - } - } - - Timer { - id: delay - interval: 1500 - repeat: false - onTriggered: { - marquee.start() - } - } - - // fake container to gauge contentWidth - Text { - id: txt - visible: false - text: parent.text - font.pixelSize: 22 * Constants.scalar - font.family: "Monospace" - - onContentWidthChanged: { - if (txt.contentWidth > hg.width) { - container.step = 0 - delay.start() - } else { - delay.stop() - marquee.stop() - } - } - } - - Text { - anchors { - fill: parent - leftMargin: 10 - rightMargin: 10 - } - - color: "lightblue" - font.pixelSize: 22 * Constants.scalar - font.family: "Monospace" - text: parent.display - - horizontalAlignment: container.animate ? Text.AlignLeft : Text.AlignHCenter - } - - Rectangle { - anchors.fill: parent - z: 2 - - gradient: Gradient { - orientation: Gradient.Horizontal - GradientStop { - position: 0.0 - color: marquee.running ? Constants.bg : "transparent" - Behavior on color { - ColorAnimation { - duration: 200 - } - } - } - GradientStop { - position: 0.1 - color: "transparent" - } - GradientStop { - position: 0.9 - color: "transparent" - } - GradientStop { - position: 1.0 - color: marquee.running ? Constants.bg : "transparent" - Behavior on color { - ColorAnimation { - duration: 200 - } - } - } - } - } - } - } - - highlightRangeMode: ListView.StrictlyEnforceRange - preferredHighlightBegin: currentItem === null ? 0 : x + width / 2 - currentItem.width / 2 - preferredHighlightEnd: currentItem === null ? 0 : x + width / 2 + currentItem.width / 2 - - highlightMoveDuration: 300 - delegate: GameCarouselCard { - id: game - width: 300 - height: 300 - } -} diff --git a/src/eden/Eden/Main/GameList.qml b/src/eden/Eden/Main/GameList.qml deleted file mode 100644 index 7af19bbe88..0000000000 --- a/src/eden/Eden/Main/GameList.qml +++ /dev/null @@ -1,127 +0,0 @@ -import QtQuick -import QtQuick.Controls -import Qt.labs.platform -import QtCore - -import Eden.Constants -import Eden.Native.Interface -import Eden.Native.Gamepad - -Rectangle { - id: root - - property var setting: SettingsInterface.setting("grid_columns") - - property int gx: 0 - property int gy: 0 - - readonly property int deadzone: 8000 - readonly property int repeatTimeMs: 125 - - color: Constants.bg - - // TODO: use the original yuzu backend for dis - Gamepad { - id: gamepad - - // onUpPressed: grid.moveCurrentIndexUp() - // onDownPressed: grid.moveCurrentIndexDown() - // onLeftPressed: grid.moveCurrentIndexLeft() - // onRightPressed: grid.moveCurrentIndexRight() - onLeftPressed: carousel.decrement() - onRightPressed: carousel.increment() - onAPressed: console.log("A pressed") - onLeftStickMoved: (x, y) => { - gx = x - gy = y - } - } - - Timer { - interval: repeatTimeMs - running: true - repeat: true - onTriggered: { - if (gx > deadzone) { - gamepad.rightPressed() - } else if (gx < -deadzone) { - gamepad.leftPressed() - } - - if (gy > deadzone) { - gamepad.downPressed() - } else if (gy < -deadzone) { - gamepad.upPressed() - } - } - } - Timer { - interval: 16 - running: true - repeat: true - onTriggered: gamepad.pollEvents() - } - FolderDialog { - id: openDir - folder: StandardPaths.writableLocation(StandardPaths.HomeLocation) - onAccepted: { - button.visible = false - view.anchors.bottom = root.bottom - EdenGameList.addDir(folder) - } - } - - Item { - id: view - - anchors { - bottom: button.top - left: parent.left - right: parent.right - top: parent.top - margins: 8 * Constants.scalar - } - - // GameGrid { - // setting: root.setting - - // id: grid - - // anchors.fill: parent - // } - GameCarousel { - id: carousel - - height: 300 - - anchors { - right: view.right - left: view.left - - verticalCenter: view.verticalCenter - } - } - } - - Button { - id: button - font.pixelSize: 25 - - anchors { - left: parent.left - right: parent.right - - bottom: parent.bottom - - margins: 8 - } - - text: "Add Directory" - onClicked: openDir.open() - - background: Rectangle { - color: button.pressed ? Constants.accentPressed : Constants.accent - radius: 5 - } - } -} diff --git a/src/eden/Eden/Main/MarqueeText.qml b/src/eden/Eden/Main/MarqueeText.qml deleted file mode 100644 index 7a70c53141..0000000000 --- a/src/eden/Eden/Main/MarqueeText.qml +++ /dev/null @@ -1,43 +0,0 @@ -import QtQuick - -Item { - required property string text - - property int spacing: 30 - property int startDelay: 2000 - property int speed: 40 - - property alias font: t1.font - property alias color: t1.color - - id: root - - width: t1.width + spacing - height: t1.height - clip: true - - Text { - id: t1 - - SequentialAnimation on x { - loops: Animation.Infinite - running: true - - PauseAnimation { - duration: root.startDelay - } - - NumberAnimation { - from: root.width - to: -t1.width - duration: (root.width + t1.width) * 1000 / root.speed - easing.type: Easing.Linear - } - } - - Text { - x: root.width - text: t1.text - } - } -} diff --git a/src/eden/Eden/Native/CMakeLists.txt b/src/eden/Eden/Native/CMakeLists.txt deleted file mode 100644 index 289504b4cf..0000000000 --- a/src/eden/Eden/Native/CMakeLists.txt +++ /dev/null @@ -1,71 +0,0 @@ -qt_add_executable(eden - main.cpp - icons.qrc -) - -add_subdirectory(Interface) -add_subdirectory(Models) - -set(PLUGINS - EdenUtilplugin - EdenItemsplugin - EdenConfigplugin - EdenInterfaceplugin - EdenConstantsplugin - EdenMainplugin -) - -if (ENABLE_SDL2) - add_subdirectory(Gamepad) - set(PLUGINS ${PLUGINS} edenGamepadplugin) -endif() - -target_link_libraries(eden - PRIVATE - Qt6::Core - Qt6::Widgets - Qt6::Gui - Qt6::Quick - Qt6::QuickControls2 - EdenModels - - # Explicitly link to static plugins - ${PLUGINS} -) - -set(NATIVE_MODULES eden EdenInterface) - -foreach(MODULE ${NATIVE_MODULES}) - target_link_libraries(${MODULE} PRIVATE common core input_common frontend_common qt_common network video_core) - target_link_libraries(${MODULE} PRIVATE Boost::headers glad fmt) - target_link_libraries(${MODULE} PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) - - target_link_libraries(${MODULE} PRIVATE Vulkan::Headers) - - if (UNIX AND NOT APPLE) - target_link_libraries(${MODULE} PRIVATE Qt6::DBus) - endif() - - target_compile_definitions(${MODULE} PRIVATE - # Use QStringBuilder for string concatenation to reduce - # the overall number of temporary strings created. - -DQT_USE_QSTRINGBUILDER - - # Disable implicit type narrowing in signal/slot connect() calls. - -DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT - - # Disable unsafe overloads of QProcess' start() function. - -DQT_NO_PROCESS_COMBINED_ARGUMENT_START - - # Disable implicit QString->QUrl conversions to enforce use of proper resolving functions. - -DQT_NO_URL_CAST_FROM_STRING - ) -endforeach() - -set_target_properties(eden PROPERTIES OUTPUT_NAME "eden") -include(GNUInstallDirs) -install(TARGETS eden - BUNDLE DESTINATION . - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} -) diff --git a/src/eden/Eden/Native/Gamepad/CMakeLists.txt b/src/eden/Eden/Native/Gamepad/CMakeLists.txt deleted file mode 100644 index 70a69b35ad..0000000000 --- a/src/eden/Eden/Native/Gamepad/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -set(CMAKE_AUTOMOC ON) - -qt_add_library(edenGamepad STATIC) - -qt_add_qml_module(edenGamepad - URI Eden.Native.Gamepad - VERSION 1.0 - SOURCES gamepad.h gamepad.cpp -) diff --git a/src/eden/Eden/Native/Interface/CMakeLists.txt b/src/eden/Eden/Native/Interface/CMakeLists.txt deleted file mode 100644 index 3c35df6ce5..0000000000 --- a/src/eden/Eden/Native/Interface/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -qt_add_library(EdenInterface STATIC) -qt_add_qml_module(EdenInterface - URI Eden.Native.Interface - VERSION 1.0 - SOURCES - SettingsInterface.h SettingsInterface.cpp - QMLSetting.h QMLSetting.cpp - MetaObjectHelper.h - SOURCES QMLConfig.h - -) diff --git a/src/eden/Eden/Native/Models/CMakeLists.txt b/src/eden/Eden/Native/Models/CMakeLists.txt deleted file mode 100644 index 3a86bed1c4..0000000000 --- a/src/eden/Eden/Native/Models/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -set(CMAKE_AUTOMOC ON) - -# TODO: This might not need to be exposed to QML? -qt_add_library(EdenModels STATIC) -qt_add_qml_module(EdenModels - URI Eden.Native.Models - VERSION 1.0 - SOURCES - GameListModel.h GameListModel.cpp - SettingsModel.h SettingsModel.cpp -) - -target_link_libraries(EdenModels - PRIVATE - Qt6::Gui -) diff --git a/src/eden/Eden/Util/CMakeLists.txt b/src/eden/Eden/Util/CMakeLists.txt deleted file mode 100644 index 5761da0b3f..0000000000 --- a/src/eden/Eden/Util/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -set(CMAKE_AUTOMOC ON) - -find_package(Qt6 REQUIRED COMPONENTS Quick) - -set_source_files_properties(Util.qml - PROPERTIES - QT_QML_SINGLETON_TYPE true -) - -qt_add_library(EdenUtil STATIC) -qt_add_qml_module(EdenUtil - URI Eden.Util - OUTPUT_DIRECTORY EdenUtil - VERSION 1.0 - QML_FILES - - Util.qml -) - -target_link_libraries(EdenUtil - PRIVATE - Qt6::Quick -) diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index aebd11a52b..a5fec0ffaf 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -4,9 +4,6 @@ # SPDX-FileCopyrightText: 2023 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later -find_package(Qt6 REQUIRED COMPONENTS Core) -find_package(Qt6 REQUIRED COMPONENTS Core) - add_library(qt_common STATIC qt_common.h qt_common.cpp @@ -32,7 +29,6 @@ add_library(qt_common STATIC # Extra deps add_subdirectory(externals) -target_link_libraries(qt_common PUBLIC QuaZip::QuaZip) create_target_directory_groups(qt_common) @@ -41,8 +37,6 @@ if (ENABLE_QT) target_link_libraries(qt_common PRIVATE Qt6::Widgets) endif() -add_subdirectory(externals) - target_link_libraries(qt_common PRIVATE core Qt6::Core SimpleIni::SimpleIni QuaZip::QuaZip frozen::frozen) if (NOT WIN32)