From 979f3570e99959e510b55523c6789be8dc769102 Mon Sep 17 00:00:00 2001 From: pineappleEA Date: Thu, 24 Aug 2023 22:11:26 +0200 Subject: [PATCH] early-access version 3832 --- README.md | 2 +- src/android/app/src/main/jni/config.cpp | 5 +- src/android/app/src/main/jni/native.cpp | 2 +- src/common/settings.cpp | 5 ++ src/common/settings.h | 10 ++- src/common/settings_common.h | 1 + src/common/settings_enums.h | 2 + src/core/frontend/applets/controller.cpp | 4 +- src/core/frontend/framebuffer_layout.cpp | 3 +- src/core/hle/service/am/am.cpp | 5 +- src/core/hle/service/apm/apm_controller.cpp | 4 +- .../hle/service/filesystem/filesystem.cpp | 11 ++- .../hle/service/hid/controllers/gesture.cpp | 2 +- src/core/hle/service/hid/controllers/npad.cpp | 2 +- src/core/hle/service/vi/vi.cpp | 2 +- src/core/telemetry_session.cpp | 3 +- src/yuzu/applets/qt_controller.cpp | 14 ++-- src/yuzu/bootmanager.cpp | 4 +- src/yuzu/configuration/config.cpp | 9 +-- src/yuzu/configuration/config.h | 3 +- src/yuzu/configuration/configure_input.cpp | 14 ++-- src/yuzu/configuration/configure_per_game.cpp | 7 ++ src/yuzu/configuration/configure_system.cpp | 5 ++ src/yuzu/configuration/shared_translation.cpp | 5 +- src/yuzu/configuration/shared_widget.cpp | 68 ++++++++++++++++++- src/yuzu/configuration/shared_widget.h | 6 ++ src/yuzu/main.cpp | 55 ++++++++++++--- src/yuzu/main.h | 1 + 28 files changed, 212 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 797e6485b..cbc107b2b 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 3831. +This is the source code for early-access 3832. ## Legal Notice diff --git a/src/android/app/src/main/jni/config.cpp b/src/android/app/src/main/jni/config.cpp index 5e1f10f99..9de9bd93e 100755 --- a/src/android/app/src/main/jni/config.cpp +++ b/src/android/app/src/main/jni/config.cpp @@ -11,6 +11,7 @@ #include "common/fs/path_util.h" #include "common/logging/log.h" #include "common/settings.h" +#include "common/settings_enums.h" #include "core/hle/service/acc/profile_manager.h" #include "input_common/main.h" #include "jni/config.h" @@ -144,7 +145,9 @@ void Config::ReadValues() { Service::Account::MAX_USERS - 1); // Disable docked mode by default on Android - Settings::values.use_docked_mode = config->GetBoolean("System", "use_docked_mode", false); + Settings::values.use_docked_mode.SetValue(config->GetBoolean("System", "use_docked_mode", false) + ? Settings::ConsoleMode::Docked + : Settings::ConsoleMode::Handheld); const auto rng_seed_enabled = config->GetBoolean("System", "rng_seed_enabled", false); if (rng_seed_enabled) { diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index c23b2f19e..6e9dbee95 100755 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -377,7 +377,7 @@ public: return false; } - return !Settings::values.use_docked_mode.GetValue(); + return !Settings::IsDockedMode(); } void SetDeviceType([[maybe_unused]] int index, int type) { diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 6af15298b..7c24c13c2 100755 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include +#include "common/settings_enums.h" #if __cpp_lib_chrono >= 201907L #include #include @@ -149,6 +150,10 @@ bool IsFastmemEnabled() { return true; } +bool IsDockedMode() { + return values.use_docked_mode.GetValue() == Settings::ConsoleMode::Docked; +} + float Volume() { if (values.audio_muted) { return 0.0f; diff --git a/src/common/settings.h b/src/common/settings.h index 6f37304f4..d4c1598c1 100755 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -380,7 +380,13 @@ struct Values { Setting current_user{linkage, 0, "current_user", Category::System}; - SwitchableSetting use_docked_mode{linkage, true, "use_docked_mode", Category::System}; + SwitchableSetting use_docked_mode{linkage, + ConsoleMode::Docked, + "use_docked_mode", + Category::System, + Specialization::Radio, + true, + true}; // Controls InputSetting> players; @@ -521,6 +527,8 @@ bool IsGPULevelHigh(); bool IsFastmemEnabled(); +bool IsDockedMode(); + float Volume(); std::string GetTimeZoneString(TimeZone time_zone); diff --git a/src/common/settings_common.h b/src/common/settings_common.h index 2efb329b0..3082e0ce1 100755 --- a/src/common/settings_common.h +++ b/src/common/settings_common.h @@ -56,6 +56,7 @@ enum Specialization : u8 { Scalar = 5, // Values are continuous Countable = 6, // Can be stepped through Paired = 7, // Another setting is associated with this setting + Radio = 8, // Setting should be presented in a radio group Percentage = (1 << SpecializationAttributeOffset), // Should be represented as a percentage }; diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h index e7cb59ea5..815cafe15 100755 --- a/src/common/settings_enums.h +++ b/src/common/settings_enums.h @@ -146,6 +146,8 @@ ENUM(AntiAliasing, None, Fxaa, Smaa, MaxEnum); ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch); +ENUM(ConsoleMode, Handheld, Docked); + template inline std::string CanonicalizeEnum(Type id) { const auto group = EnumMetadata::Canonicalizations(); diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp index 5e7b8d2fc..be644535c 100755 --- a/src/core/frontend/applets/controller.cpp +++ b/src/core/frontend/applets/controller.cpp @@ -3,6 +3,8 @@ #include "common/assert.h" #include "common/logging/log.h" +#include "common/settings.h" +#include "common/settings_enums.h" #include "core/frontend/applets/controller.h" #include "core/hid/emulated_controller.h" #include "core/hid/hid_core.h" @@ -62,7 +64,7 @@ void DefaultControllerApplet::ReconfigureControllers(ReconfigureCallback callbac controller->Connect(true); } } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld && - !Settings::values.use_docked_mode.GetValue()) { + !Settings::IsDockedMode()) { // We should *never* reach here under any normal circumstances. controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); controller->Connect(true); diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp index 958df0fc9..d3b2f99c5 100755 --- a/src/core/frontend/framebuffer_layout.cpp +++ b/src/core/frontend/framebuffer_layout.cpp @@ -5,6 +5,7 @@ #include "common/assert.h" #include "common/settings.h" +#include "common/settings_enums.h" #include "core/frontend/framebuffer_layout.h" namespace Layout { @@ -49,7 +50,7 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height) { } FramebufferLayout FrameLayoutFromResolutionScale(f32 res_scale) { - const bool is_docked = Settings::values.use_docked_mode.GetValue(); + const bool is_docked = Settings::IsDockedMode(); const u32 screen_width = is_docked ? ScreenDocked::Width : ScreenUndocked::Width; const u32 screen_height = is_docked ? ScreenDocked::Height : ScreenUndocked::Height; diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 2bf1ed802..302f24642 100755 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -6,6 +6,7 @@ #include #include #include "common/settings.h" +#include "common/settings_enums.h" #include "core/core.h" #include "core/file_sys/control_metadata.h" #include "core/file_sys/patch_manager.h" @@ -833,7 +834,7 @@ void ICommonStateGetter::GetDefaultDisplayResolution(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); - if (Settings::values.use_docked_mode.GetValue()) { + if (Settings::IsDockedMode()) { rb.Push(static_cast(Service::VI::DisplayResolution::DockedWidth)); rb.Push(static_cast(Service::VI::DisplayResolution::DockedHeight)); } else { @@ -921,7 +922,7 @@ void IStorage::Open(HLERequestContext& ctx) { } void ICommonStateGetter::GetOperationMode(HLERequestContext& ctx) { - const bool use_docked_mode{Settings::values.use_docked_mode.GetValue()}; + const bool use_docked_mode{Settings::IsDockedMode()}; LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode); IPC::ResponseBuilder rb{ctx, 3}; diff --git a/src/core/hle/service/apm/apm_controller.cpp b/src/core/hle/service/apm/apm_controller.cpp index 512e0e8e8..8c9a86557 100755 --- a/src/core/hle/service/apm/apm_controller.cpp +++ b/src/core/hle/service/apm/apm_controller.cpp @@ -7,6 +7,7 @@ #include "common/logging/log.h" #include "common/settings.h" +#include "common/settings_enums.h" #include "core/core_timing.h" #include "core/hle/service/apm/apm_controller.h" @@ -67,8 +68,7 @@ void Controller::SetFromCpuBoostMode(CpuBoostMode mode) { } PerformanceMode Controller::GetCurrentPerformanceMode() const { - return Settings::values.use_docked_mode.GetValue() ? PerformanceMode::Boost - : PerformanceMode::Normal; + return Settings::IsDockedMode() ? PerformanceMode::Boost : PerformanceMode::Normal; } PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(PerformanceMode mode) { diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index c6ba217ed..d637b2cb8 100755 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -4,6 +4,7 @@ #include #include "common/assert.h" +#include "common/fs/fs.h" #include "common/fs/path_util.h" #include "common/settings.h" #include "core/core.h" @@ -154,10 +155,18 @@ Result VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_, std::string src_path(Common::FS::SanitizePath(src_path_)); std::string dest_path(Common::FS::SanitizePath(dest_path_)); auto src = backing->GetFileRelative(src_path); + auto dst = backing->GetFileRelative(dest_path); if (Common::FS::GetParentPath(src_path) == Common::FS::GetParentPath(dest_path)) { // Use more-optimized vfs implementation rename. - if (src == nullptr) + if (src == nullptr) { return FileSys::ERROR_PATH_NOT_FOUND; + } + + if (dst && Common::FS::Exists(dst->GetFullPath())) { + LOG_ERROR(Service_FS, "File at new_path={} already exists", dst->GetFullPath()); + return FileSys::ERROR_PATH_ALREADY_EXISTS; + } + if (!src->Rename(Common::FS::GetFilename(dest_path))) { // TODO(DarkLordZach): Find a better error code for this return ResultUnknown; diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index e27cbd9ba..b874d688e 100755 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp @@ -331,7 +331,7 @@ Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() }; // Hack: There is no touch in docked but games still allow it - if (Settings::values.use_docked_mode.GetValue()) { + if (Settings::IsDockedMode()) { gesture.points[id] = { .x = static_cast(active_x * Layout::ScreenDocked::Width), .y = static_cast(active_y * Layout::ScreenDocked::Height), diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index d33a6d521..ebe9d9d5b 100755 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -1518,7 +1518,7 @@ bool Controller_NPad::IsControllerSupported(Core::HID::NpadStyleIndex controller return false; } // Handheld shouldn't be supported in docked mode - if (Settings::values.use_docked_mode.GetValue()) { + if (Settings::IsDockedMode()) { return false; } diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 5758fe63f..aba6259b2 100755 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -217,7 +217,7 @@ private: IPC::ResponseBuilder rb{ctx, 6}; rb.Push(ResultSuccess); - if (Settings::values.use_docked_mode.GetValue()) { + if (Settings::IsDockedMode()) { rb.Push(static_cast(Service::VI::DisplayResolution::DockedWidth)); rb.Push(static_cast(Service::VI::DisplayResolution::DockedHeight)); } else { diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index c2058b608..1f7f60ebe 100755 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -14,6 +14,7 @@ #include "common/logging/log.h" #include "common/settings.h" +#include "common/settings_enums.h" #include "core/file_sys/control_metadata.h" #include "core/file_sys/patch_manager.h" #include "core/loader/loader.h" @@ -275,7 +276,7 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader, static_cast(Settings::values.shader_backend.GetValue())); AddField(field_type, "Renderer_UseAsynchronousShaders", Settings::values.use_asynchronous_shaders.GetValue()); - AddField(field_type, "System_UseDockedMode", Settings::values.use_docked_mode.GetValue()); + AddField(field_type, "System_UseDockedMode", Settings::IsDockedMode()); } bool TelemetrySession::SubmitTestcase() { diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp index 111e4109e..edd3d9fa3 100755 --- a/src/yuzu/applets/qt_controller.cpp +++ b/src/yuzu/applets/qt_controller.cpp @@ -5,6 +5,8 @@ #include #include "common/assert.h" +#include "common/settings.h" +#include "common/settings_enums.h" #include "common/string_util.h" #include "core/core.h" #include "core/hid/emulated_controller.h" @@ -226,9 +228,11 @@ int QtControllerSelectorDialog::exec() { } void QtControllerSelectorDialog::ApplyConfiguration() { - const bool pre_docked_mode = Settings::values.use_docked_mode.GetValue(); - Settings::values.use_docked_mode.SetValue(ui->radioDocked->isChecked()); - OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode.GetValue(), system); + const bool pre_docked_mode = Settings::IsDockedMode(); + const bool docked_mode_selected = ui->radioDocked->isChecked(); + Settings::values.use_docked_mode.SetValue( + docked_mode_selected ? Settings::ConsoleMode::Docked : Settings::ConsoleMode::Handheld); + OnDockedModeChanged(pre_docked_mode, docked_mode_selected, system); Settings::values.vibration_enabled.SetValue(ui->vibrationGroup->isChecked()); Settings::values.motion_enabled.SetValue(ui->motionGroup->isChecked()); @@ -616,8 +620,8 @@ void QtControllerSelectorDialog::UpdateDockedState(bool is_handheld) { ui->radioDocked->setEnabled(!is_handheld); ui->radioUndocked->setEnabled(!is_handheld); - ui->radioDocked->setChecked(Settings::values.use_docked_mode.GetValue()); - ui->radioUndocked->setChecked(!Settings::values.use_docked_mode.GetValue()); + ui->radioDocked->setChecked(Settings::IsDockedMode()); + ui->radioUndocked->setChecked(!Settings::IsDockedMode()); // Also force into undocked mode if the controller type is handheld. if (is_handheld) { diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index b8c431b4c..32474c1d1 100755 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -928,8 +928,8 @@ void GRenderWindow::CaptureScreenshot(const QString& screenshot_path) { const Layout::FramebufferLayout layout{[]() { u32 height = UISettings::values.screenshot_height.GetValue(); if (height == 0) { - height = Settings::values.use_docked_mode.GetValue() ? Layout::ScreenDocked::Height - : Layout::ScreenUndocked::Height; + height = Settings::IsDockedMode() ? Layout::ScreenDocked::Height + : Layout::ScreenUndocked::Height; height *= Settings::values.resolution_info.up_factor; } const u32 width = diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 7a794aba8..1352704ed 100755 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -9,6 +9,7 @@ #include "common/fs/path_util.h" #include "common/settings.h" #include "common/settings_common.h" +#include "common/settings_enums.h" #include "core/core.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/hid/controllers/npad.h" @@ -85,9 +86,9 @@ const std::map Config::scaling_filter_texts_ma {Settings::ScalingFilter::Fsr, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FSR"))}, }; -const std::map Config::use_docked_mode_texts_map = { - {true, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Docked"))}, - {false, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Handheld"))}, +const std::map Config::use_docked_mode_texts_map = { + {Settings::ConsoleMode::Docked, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Docked"))}, + {Settings::ConsoleMode::Handheld, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Handheld"))}, }; const std::map Config::gpu_accuracy_texts_map = { @@ -376,7 +377,7 @@ void Config::ReadControlValues() { const auto controller_type = Settings::values.players.GetValue()[0].controller_type; if (controller_type == Settings::ControllerType::Handheld) { Settings::values.use_docked_mode.SetGlobal(!IsCustomConfig()); - Settings::values.use_docked_mode.SetValue(false); + Settings::values.use_docked_mode.SetValue(Settings::ConsoleMode::Handheld); } if (IsCustomConfig()) { diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index c4d4fb10d..0a9cdc0cc 100755 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h @@ -9,6 +9,7 @@ #include #include #include "common/settings.h" +#include "common/settings_enums.h" #include "yuzu/uisettings.h" class QSettings; @@ -51,7 +52,7 @@ public: static const std::map anti_aliasing_texts_map; static const std::map scaling_filter_texts_map; - static const std::map use_docked_mode_texts_map; + static const std::map use_docked_mode_texts_map; static const std::map gpu_accuracy_texts_map; static const std::map renderer_backend_texts_map; static const std::map shader_backend_texts_map; diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index c00d5a7da..28c6367da 100755 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -4,6 +4,8 @@ #include #include +#include "common/settings.h" +#include "common/settings_enums.h" #include "core/core.h" #include "core/hid/emulated_controller.h" #include "core/hid/hid_core.h" @@ -197,9 +199,11 @@ void ConfigureInput::ApplyConfiguration() { advanced->ApplyConfiguration(); - const bool pre_docked_mode = Settings::values.use_docked_mode.GetValue(); - Settings::values.use_docked_mode.SetValue(ui->radioDocked->isChecked()); - OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode.GetValue(), system); + const bool pre_docked_mode = Settings::IsDockedMode(); + const bool docked_mode_selected = ui->radioDocked->isChecked(); + Settings::values.use_docked_mode.SetValue( + docked_mode_selected ? Settings::ConsoleMode::Docked : Settings::ConsoleMode::Handheld); + OnDockedModeChanged(pre_docked_mode, docked_mode_selected, system); Settings::values.vibration_enabled.SetValue(ui->vibrationGroup->isChecked()); Settings::values.motion_enabled.SetValue(ui->motionGroup->isChecked()); @@ -267,8 +271,8 @@ void ConfigureInput::UpdateDockedState(bool is_handheld) { ui->radioDocked->setEnabled(!is_handheld); ui->radioUndocked->setEnabled(!is_handheld); - ui->radioDocked->setChecked(Settings::values.use_docked_mode.GetValue()); - ui->radioUndocked->setChecked(!Settings::values.use_docked_mode.GetValue()); + ui->radioDocked->setChecked(Settings::IsDockedMode()); + ui->radioUndocked->setChecked(!Settings::IsDockedMode()); // Also force into undocked mode if the controller type is handheld. if (is_handheld) { diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp index 33cf9b0ed..2da39dd65 100755 --- a/src/yuzu/configuration/configure_per_game.cpp +++ b/src/yuzu/configuration/configure_per_game.cpp @@ -18,6 +18,7 @@ #include "common/fs/fs_util.h" #include "common/settings_enums.h" +#include "common/settings_input.h" #include "configuration/shared_widget.h" #include "core/core.h" #include "core/file_sys/control_metadata.h" @@ -98,6 +99,12 @@ void ConfigurePerGame::ApplyConfiguration() { addons_tab->ApplyConfiguration(); input_tab->ApplyConfiguration(); + if (Settings::IsDockedMode() && Settings::values.players.GetValue()[0].controller_type == + Settings::ControllerType::Handheld) { + Settings::values.use_docked_mode.SetValue(Settings::ConsoleMode::Handheld); + Settings::values.use_docked_mode.SetGlobal(true); + } + system.ApplySettings(); Settings::LogSettings(); diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp index 8529c7399..4c4c541bb 100755 --- a/src/yuzu/configuration/configure_system.cpp +++ b/src/yuzu/configuration/configure_system.cpp @@ -106,6 +106,11 @@ void ConfigureSystem::Setup(const ConfigurationShared::Builder& builder) { push(Settings::values.linkage.by_category[Settings::Category::System]); for (auto setting : settings) { + if (setting->Id() == Settings::values.use_docked_mode.Id() && + Settings::IsConfiguringGlobal()) { + continue; + } + ConfigurationShared::Widget* widget = builder.BuildWidget(setting, apply_funcs); if (widget == nullptr) { diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp index 335810788..276bdbaba 100755 --- a/src/yuzu/configuration/shared_translation.cpp +++ b/src/yuzu/configuration/shared_translation.cpp @@ -135,7 +135,7 @@ std::unique_ptr InitializeTranslations(QWidget* parent) { INSERT(Settings, region_index, "Region:", ""); INSERT(Settings, time_zone_index, "Time Zone:", ""); INSERT(Settings, sound_index, "Sound Output Mode:", ""); - INSERT(Settings, use_docked_mode, "", ""); + INSERT(Settings, use_docked_mode, "Console Mode:", ""); INSERT(Settings, current_user, "", ""); // Controls @@ -379,6 +379,9 @@ std::unique_ptr ComboboxEnumeration(QWidget* parent) { PAIR(MemoryLayout, Memory_6Gb, "6GB DRAM (Unsafe)"), PAIR(MemoryLayout, Memory_8Gb, "8GB DRAM (Unsafe)"), }}); + translations->insert( + {Settings::EnumMetadata::Index(), + {PAIR(ConsoleMode, Docked, "Docked"), PAIR(ConsoleMode, Handheld, "Handheld")}}); #undef PAIR #undef CTX_PAIR diff --git a/src/yuzu/configuration/shared_widget.cpp b/src/yuzu/configuration/shared_widget.cpp index bdb38c8ea..36d8da5a5 100755 --- a/src/yuzu/configuration/shared_widget.cpp +++ b/src/yuzu/configuration/shared_widget.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -171,6 +172,65 @@ QWidget* Widget::CreateCombobox(std::function& serializer, return combobox; } +QWidget* Widget::CreateRadioGroup(std::function& serializer, + std::function& restore_func, + const std::function& touch) { + const auto type = setting.EnumIndex(); + + QWidget* group = new QWidget(this); + QHBoxLayout* layout = new QHBoxLayout(group); + layout->setContentsMargins(0, 0, 0, 0); + group->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + + const ComboboxTranslations* enumeration{nullptr}; + if (combobox_enumerations.contains(type)) { + enumeration = &combobox_enumerations.at(type); + for (const auto& [id, name] : *enumeration) { + QRadioButton* radio_button = new QRadioButton(name, group); + layout->addWidget(radio_button); + radio_buttons.push_back({id, radio_button}); + } + } else { + return group; + } + + const auto get_selected = [=]() -> u32 { + for (const auto& [id, button] : radio_buttons) { + if (button->isChecked()) { + return id; + } + } + return -1; + }; + + const auto set_index = [=](u32 value) { + for (const auto& [id, button] : radio_buttons) { + button->setChecked(id == value); + } + }; + + const u32 setting_value = std::stoi(setting.ToString()); + set_index(setting_value); + + serializer = [get_selected]() { + int current = get_selected(); + return std::to_string(current); + }; + + restore_func = [this, set_index]() { + const u32 global_value = std::stoi(RelevantDefault(setting)); + set_index(global_value); + }; + + if (!Settings::IsConfiguringGlobal()) { + for (const auto& [id, button] : radio_buttons) { + QObject::connect(button, &QAbstractButton::clicked, [touch]() { touch(); }); + } + } + + return group; +} + QWidget* Widget::CreateLineEdit(std::function& serializer, std::function& restore_func, const std::function& touch, bool managed) { @@ -410,6 +470,8 @@ void Widget::SetupComponent(const QString& label, std::function& load_fu return RequestType::Slider; case Settings::Specialization::Countable: return RequestType::SpinBox; + case Settings::Specialization::Radio: + return RequestType::RadioGroup; default: break; } @@ -438,7 +500,11 @@ void Widget::SetupComponent(const QString& label, std::function& load_fu if (setting.TypeId() == typeid(bool)) { data_component = CreateCheckBox(&setting, label, serializer, restore_func, touch); } else if (setting.IsEnum()) { - data_component = CreateCombobox(serializer, restore_func, touch); + if (request == RequestType::RadioGroup) { + data_component = CreateRadioGroup(serializer, restore_func, touch); + } else { + data_component = CreateCombobox(serializer, restore_func, touch); + } } else if (type == typeid(u32) || type == typeid(int) || type == typeid(u16) || type == typeid(s64) || type == typeid(u8)) { switch (request) { diff --git a/src/yuzu/configuration/shared_widget.h b/src/yuzu/configuration/shared_widget.h index e64693bab..5303dd898 100755 --- a/src/yuzu/configuration/shared_widget.h +++ b/src/yuzu/configuration/shared_widget.h @@ -22,6 +22,7 @@ class QObject; class QPushButton; class QSlider; class QSpinBox; +class QRadioButton; namespace Settings { class BasicSetting; @@ -38,6 +39,7 @@ enum class RequestType { LineEdit, HexEdit, DateTimeEdit, + RadioGroup, MaxEnum, }; @@ -91,6 +93,7 @@ public: QSlider* slider{}; QComboBox* combobox{}; QDateTimeEdit* date_time_edit{}; + std::vector> radio_buttons{}; private: void SetupComponent(const QString& label, std::function& load_func, bool managed, @@ -106,6 +109,9 @@ private: QWidget* CreateCombobox(std::function& serializer, std::function& restore_func, const std::function& touch); + QWidget* CreateRadioGroup(std::function& serializer, + std::function& restore_func, + const std::function& touch); QWidget* CreateLineEdit(std::function& serializer, std::function& restore_func, const std::function& touch, bool managed = true); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 44f387798..d67c3ded9 100755 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1158,9 +1158,9 @@ void GMainWindow::InitializeWidgets() { [this](const QPoint& menu_location) { QMenu context_menu; - for (auto const& docked_mode_pair : Config::use_docked_mode_texts_map) { - context_menu.addAction(docked_mode_pair.second, [this, docked_mode_pair] { - if (docked_mode_pair.first != Settings::values.use_docked_mode.GetValue()) { + for (auto const& pair : Config::use_docked_mode_texts_map) { + context_menu.addAction(pair.second, [this, &pair] { + if (pair.first != Settings::values.use_docked_mode.GetValue()) { OnToggleDockedMode(); } }); @@ -1811,6 +1811,43 @@ bool GMainWindow::SelectAndSetCurrentUser( return true; } +void GMainWindow::ConfigureFilesystemProvider(const std::string& filepath) { + // Ensure all NCAs are registered before launching the game + const auto file = vfs->OpenFile(filepath, FileSys::Mode::Read); + if (!file) { + return; + } + + auto loader = Loader::GetLoader(*system, file); + if (!loader) { + return; + } + + const auto file_type = loader->GetFileType(); + if (file_type == Loader::FileType::Unknown || file_type == Loader::FileType::Error) { + return; + } + + 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, + FileSys::GetCRTypeFromNCAType(FileSys::NCA{file}.GetType()), program_id, + file); + } else if (res2 == Loader::ResultStatus::Success && + (file_type == Loader::FileType::XCI || file_type == Loader::FileType::NSP)) { + const auto nsp = file_type == Loader::FileType::NSP + ? std::make_shared(file) + : 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, + entry.second->GetBaseFile()); + } + } + } +} + void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t program_index, StartGameType type) { LOG_INFO(Frontend, "yuzu starting..."); @@ -1825,6 +1862,7 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t 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, program_id, program_index); @@ -3636,7 +3674,7 @@ void GMainWindow::OnTasReset() { } void GMainWindow::OnToggleDockedMode() { - const bool is_docked = Settings::values.use_docked_mode.GetValue(); + 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); @@ -3650,7 +3688,8 @@ void GMainWindow::OnToggleDockedMode() { controller_dialog->refreshConfiguration(); } - Settings::values.use_docked_mode.SetValue(!is_docked); + Settings::values.use_docked_mode.SetValue(is_docked ? Settings::ConsoleMode::Handheld + : Settings::ConsoleMode::Docked); UpdateDockedButton(); OnDockedModeChanged(is_docked, !is_docked, *system); } @@ -4080,10 +4119,10 @@ void GMainWindow::UpdateGPUAccuracyButton() { } void GMainWindow::UpdateDockedButton() { - const bool is_docked = Settings::values.use_docked_mode.GetValue(); - dock_status_button->setChecked(is_docked); + const auto console_mode = Settings::values.use_docked_mode.GetValue(); + dock_status_button->setChecked(Settings::IsDockedMode()); dock_status_button->setText( - Config::use_docked_mode_texts_map.find(is_docked)->second.toUpper()); + Config::use_docked_mode_texts_map.find(console_mode)->second.toUpper()); } void GMainWindow::UpdateAPIText() { diff --git a/src/yuzu/main.h b/src/yuzu/main.h index a7c0cf08b..d6abf3a7d 100755 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -399,6 +399,7 @@ private: void OpenPerGameConfiguration(u64 title_id, const std::string& file_name); bool CheckDarkMode(); bool CheckSystemArchiveDecryption(); + void ConfigureFilesystemProvider(const std::string& filepath); QString GetTasStateDescription() const; bool CreateShortcut(const std::string& shortcut_path, const std::string& title,