diff options
Diffstat (limited to 'src/yuzu')
53 files changed, 2038 insertions, 2361 deletions
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 33e1fb663..90278052a 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -38,8 +38,6 @@ add_executable(yuzu compatdb.ui compatibility_list.cpp compatibility_list.h - configuration/config.cpp - configuration/config.h configuration/configuration_shared.cpp configuration/configuration_shared.h configuration/configure.ui @@ -147,6 +145,8 @@ add_executable(yuzu 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 @@ -252,6 +252,7 @@ file(GLOB_RECURSE THEMES ${PROJECT_SOURCE_DIR}/dist/qt_themes/*) if (ENABLE_QT_TRANSLATION) set(YUZU_QT_LANGUAGES "${PROJECT_SOURCE_DIR}/dist/languages" CACHE PATH "Path to the translation bundle for the Qt frontend") option(GENERATE_QT_TRANSLATION "Generate en.ts as the translation source file" OFF) + option(WORKAROUND_BROKEN_LUPDATE "Run lupdate directly through CMake if Qt's convenience wrappers don't work" OFF) # Update source TS file if enabled if (GENERATE_QT_TRANSLATION) @@ -259,19 +260,51 @@ if (ENABLE_QT_TRANSLATION) # these calls to qt_create_translation also creates a rule to generate en.qm which conflicts with providing english plurals # so we have to set a OUTPUT_LOCATION so that we don't have multiple rules to generate en.qm set_source_files_properties(${YUZU_QT_LANGUAGES}/en.ts PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/translations") - qt_create_translation(QM_FILES - ${SRCS} - ${UIS} - ${YUZU_QT_LANGUAGES}/en.ts - OPTIONS - -source-language en_US - -target-language en_US - ) + if (WORKAROUND_BROKEN_LUPDATE) + add_custom_command(OUTPUT ${YUZU_QT_LANGUAGES}/en.ts + COMMAND lupdate + -source-language en_US + -target-language en_US + ${SRCS} + ${UIS} + -ts ${YUZU_QT_LANGUAGES}/en.ts + DEPENDS + ${SRCS} + ${UIS} + WORKING_DIRECTORY + ${CMAKE_CURRENT_SOURCE_DIR} + ) + else() + qt_create_translation(QM_FILES + ${SRCS} + ${UIS} + ${YUZU_QT_LANGUAGES}/en.ts + OPTIONS + -source-language en_US + -target-language en_US + ) + endif() # Generate plurals into dist/english_plurals/generated_en.ts so it can be used to revise dist/english_plurals/en.ts set(GENERATED_PLURALS_FILE ${PROJECT_SOURCE_DIR}/dist/english_plurals/generated_en.ts) set_source_files_properties(${GENERATED_PLURALS_FILE} PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/plurals") - qt_create_translation(QM_FILES ${SRCS} ${UIS} ${GENERATED_PLURALS_FILE} OPTIONS -pluralonly -source-language en_US -target-language en_US) + if (WORKAROUND_BROKEN_LUPDATE) + add_custom_command(OUTPUT ${GENERATED_PLURALS_FILE} + COMMAND lupdate + -source-language en_US + -target-language en_US + ${SRCS} + ${UIS} + -ts ${GENERATED_PLURALS_FILE} + DEPENDS + ${SRCS} + ${UIS} + WORKING_DIRECTORY + ${CMAKE_CURRENT_SOURCE_DIR} + ) + else() + qt_create_translation(QM_FILES ${SRCS} ${UIS} ${GENERATED_PLURALS_FILE} OPTIONS -pluralonly -source-language en_US -target-language en_US) + endif() add_custom_target(translation ALL DEPENDS ${YUZU_QT_LANGUAGES}/en.ts ${GENERATED_PLURALS_FILE}) endif() @@ -344,7 +377,7 @@ endif() create_target_directory_groups(yuzu) -target_link_libraries(yuzu PRIVATE common core input_common network video_core) +target_link_libraries(yuzu PRIVATE common core input_common frontend_common network video_core) target_link_libraries(yuzu PRIVATE Boost::headers glad Qt${QT_MAJOR_VERSION}::Widgets) target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp index 515cb7ce6..9e5319716 100644 --- a/src/yuzu/applets/qt_controller.cpp +++ b/src/yuzu/applets/qt_controller.cpp @@ -13,7 +13,6 @@ #include "core/hid/hid_core.h" #include "core/hid/hid_types.h" #include "core/hle/service/hid/controllers/npad.h" -#include "core/hle/service/hid/hid.h" #include "core/hle/service/sm/sm.h" #include "ui_qt_controller.h" #include "yuzu/applets/qt_controller.h" diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp deleted file mode 100644 index baa3e55f3..000000000 --- a/src/yuzu/configuration/config.cpp +++ /dev/null @@ -1,1306 +0,0 @@ -// SPDX-FileCopyrightText: 2014 Citra Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include <algorithm> -#include <array> -#include <QKeySequence> -#include <QSettings> -#include "common/fs/fs.h" -#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" -#include "input_common/main.h" -#include "network/network.h" -#include "yuzu/configuration/config.h" - -namespace FS = Common::FS; - -Config::Config(const std::string& config_name, ConfigType config_type) - : type(config_type), global{config_type == ConfigType::GlobalConfig} { - Initialize(config_name); -} - -Config::~Config() { - if (global) { - Save(); - } -} - -const std::array<int, Settings::NativeButton::NumButtons> Config::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, -}; - -const std::array<int, Settings::NativeMotion::NumMotions> Config::default_motions = { - Qt::Key_7, - Qt::Key_8, -}; - -const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> Config::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<int, 2> Config::default_stick_mod = { - Qt::Key_Shift, - 0, -}; - -const std::array<int, 2> Config::default_ringcon_analogs{{ - Qt::Key_A, - Qt::Key_D, -}}; - -const std::map<Settings::AntiAliasing, QString> Config::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"))}, -}; - -const std::map<Settings::ScalingFilter, QString> Config::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"))}, -}; - -const std::map<Settings::ConsoleMode, QString> 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<Settings::GpuAccuracy, QString> Config::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"))}, -}; - -const std::map<Settings::RendererBackend, QString> Config::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"))}, -}; - -const std::map<Settings::ShaderBackend, QString> Config::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"))}, -}; - -// 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<UISettings::Shortcut, 23> Config::default_hotkeys{{ - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+M"), QStringLiteral("Home+Dpad_Right"), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("-"), QStringLiteral("Home+Dpad_Down"), Qt::ApplicationShortcut, true}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("="), QStringLiteral("Home+Dpad_Up"), Qt::ApplicationShortcut, true}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Capture Screenshot")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+P"), QStringLiteral("Screenshot"), Qt::WidgetWithChildrenShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Adapting Filter")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F8"), QStringLiteral("Home+L"), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Docked Mode")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F10"), QStringLiteral("Home+X"), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change GPU Accuracy")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F9"), QStringLiteral("Home+R"), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Continue/Pause Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F4"), QStringLiteral("Home+Plus"), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit Fullscreen")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Esc"), QStringLiteral(""), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit yuzu")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+Q"), QStringLiteral("Home+Minus"), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F11"), QStringLiteral("Home+B"), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+O"), QStringLiteral(""), Qt::WidgetWithChildrenShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F2"), QStringLiteral("Home+A"), Qt::WidgetWithChildrenShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F6"), QStringLiteral("R+Plus+Minus"), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F5"), QStringLiteral("L+Plus+Minus"), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F7"), QStringLiteral(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Reset")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F6"), QStringLiteral(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Start/Stop")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F5"), QStringLiteral(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Filter Bar")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F"), QStringLiteral(""), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Framerate Limit")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+U"), QStringLiteral("Home+Y"), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Mouse Panning")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F9"), QStringLiteral(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Renderdoc Capture")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral(""), QStringLiteral(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+S"), QStringLiteral(""), Qt::WindowShortcut, false}}, -}}; -// clang-format on - -void Config::Initialize(const std::string& config_name) { - const auto fs_config_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir); - const auto config_file = fmt::format("{}.ini", config_name); - - switch (type) { - case ConfigType::GlobalConfig: - qt_config_loc = FS::PathToUTF8String(fs_config_loc / config_file); - void(FS::CreateParentDir(qt_config_loc)); - qt_config = std::make_unique<QSettings>(QString::fromStdString(qt_config_loc), - QSettings::IniFormat); - Reload(); - break; - case ConfigType::PerGameConfig: - qt_config_loc = - FS::PathToUTF8String(fs_config_loc / "custom" / FS::ToU8String(config_file)); - void(FS::CreateParentDir(qt_config_loc)); - qt_config = std::make_unique<QSettings>(QString::fromStdString(qt_config_loc), - QSettings::IniFormat); - Reload(); - break; - case ConfigType::InputProfile: - qt_config_loc = FS::PathToUTF8String(fs_config_loc / "input" / config_file); - void(FS::CreateParentDir(qt_config_loc)); - qt_config = std::make_unique<QSettings>(QString::fromStdString(qt_config_loc), - QSettings::IniFormat); - break; - } -} - -bool Config::IsCustomConfig() { - return type == ConfigType::PerGameConfig; -} - -void Config::ReadPlayerValue(std::size_t player_index) { - const QString player_prefix = [this, player_index] { - if (type == ConfigType::InputProfile) { - return QString{}; - } else { - return QStringLiteral("player_%1_").arg(player_index); - } - }(); - - auto& player = Settings::values.players.GetValue()[player_index]; - if (IsCustomConfig()) { - const auto profile_name = - qt_config->value(QStringLiteral("%1profile_name").arg(player_prefix), QString{}) - .toString() - .toStdString(); - if (profile_name.empty()) { - // Use the global input config - player = Settings::values.players.GetValue(true)[player_index]; - return; - } - player.profile_name = profile_name; - } - - if (player_prefix.isEmpty() && Settings::IsConfiguringGlobal()) { - const auto controller = static_cast<Settings::ControllerType>( - qt_config - ->value(QStringLiteral("%1type").arg(player_prefix), - static_cast<u8>(Settings::ControllerType::ProController)) - .toUInt()); - - if (controller == Settings::ControllerType::LeftJoycon || - controller == Settings::ControllerType::RightJoycon) { - player.controller_type = controller; - } - } else { - player.connected = - ReadSetting(QStringLiteral("%1connected").arg(player_prefix), player_index == 0) - .toBool(); - - player.controller_type = static_cast<Settings::ControllerType>( - qt_config - ->value(QStringLiteral("%1type").arg(player_prefix), - static_cast<u8>(Settings::ControllerType::ProController)) - .toUInt()); - - player.vibration_enabled = - qt_config->value(QStringLiteral("%1vibration_enabled").arg(player_prefix), true) - .toBool(); - - player.vibration_strength = - qt_config->value(QStringLiteral("%1vibration_strength").arg(player_prefix), 100) - .toInt(); - - player.body_color_left = qt_config - ->value(QStringLiteral("%1body_color_left").arg(player_prefix), - Settings::JOYCON_BODY_NEON_BLUE) - .toUInt(); - player.body_color_right = - qt_config - ->value(QStringLiteral("%1body_color_right").arg(player_prefix), - Settings::JOYCON_BODY_NEON_RED) - .toUInt(); - player.button_color_left = - qt_config - ->value(QStringLiteral("%1button_color_left").arg(player_prefix), - Settings::JOYCON_BUTTONS_NEON_BLUE) - .toUInt(); - player.button_color_right = - qt_config - ->value(QStringLiteral("%1button_color_right").arg(player_prefix), - Settings::JOYCON_BUTTONS_NEON_RED) - .toUInt(); - } - - 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 = qt_config - ->value(QStringLiteral("%1").arg(player_prefix) + - QString::fromUtf8(Settings::NativeButton::mapping[i]), - QString::fromStdString(default_param)) - .toString() - .toStdString(); - 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 = qt_config - ->value(QStringLiteral("%1").arg(player_prefix) + - QString::fromUtf8(Settings::NativeAnalog::mapping[i]), - QString::fromStdString(default_param)) - .toString() - .toStdString(); - 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 = qt_config - ->value(QStringLiteral("%1").arg(player_prefix) + - QString::fromUtf8(Settings::NativeMotion::mapping[i]), - QString::fromStdString(default_param)) - .toString() - .toStdString(); - if (player_motions.empty()) { - player_motions = default_param; - } - } -} - -void Config::ReadDebugValues() { - 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 = qt_config - ->value(QStringLiteral("debug_pad_") + - QString::fromUtf8(Settings::NativeButton::mapping[i]), - QString::fromStdString(default_param)) - .toString() - .toStdString(); - 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 = qt_config - ->value(QStringLiteral("debug_pad_") + - QString::fromUtf8(Settings::NativeAnalog::mapping[i]), - QString::fromStdString(default_param)) - .toString() - .toStdString(); - if (debug_pad_analogs.empty()) { - debug_pad_analogs = default_param; - } - } -} - -void Config::ReadTouchscreenValues() { - Settings::values.touchscreen.enabled = - ReadSetting(QStringLiteral("touchscreen_enabled"), true).toBool(); - - Settings::values.touchscreen.rotation_angle = - ReadSetting(QStringLiteral("touchscreen_angle"), 0).toUInt(); - Settings::values.touchscreen.diameter_x = - ReadSetting(QStringLiteral("touchscreen_diameter_x"), 15).toUInt(); - Settings::values.touchscreen.diameter_y = - ReadSetting(QStringLiteral("touchscreen_diameter_y"), 15).toUInt(); -} - -void Config::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 = - qt_config->value(QStringLiteral("ring_controller"), QString::fromStdString(default_param)) - .toString() - .toStdString(); - if (ringcon_analogs.empty()) { - ringcon_analogs = default_param; - } -} - -void Config::ReadAudioValues() { - qt_config->beginGroup(QStringLiteral("Audio")); - - ReadCategory(Settings::Category::Audio); - - qt_config->endGroup(); -} - -void Config::ReadControlValues() { - qt_config->beginGroup(QStringLiteral("Controls")); - - ReadCategory(Settings::Category::Controls); - - Settings::values.players.SetGlobal(!IsCustomConfig()); - for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { - ReadPlayerValue(p); - } - - // Disable docked mode if handheld is selected - 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(Settings::ConsoleMode::Handheld); - } - - if (IsCustomConfig()) { - qt_config->endGroup(); - return; - } - ReadDebugValues(); - ReadTouchscreenValues(); - ReadMotionTouchValues(); - ReadHidbusValues(); - - qt_config->endGroup(); -} - -void Config::ReadMotionTouchValues() { - int num_touch_from_button_maps = - qt_config->beginReadArray(QStringLiteral("touch_from_button_maps")); - - if (num_touch_from_button_maps > 0) { - const auto append_touch_from_button_map = [this] { - Settings::TouchFromButtonMap map; - map.name = ReadSetting(QStringLiteral("name"), QStringLiteral("default")) - .toString() - .toStdString(); - const int num_touch_maps = qt_config->beginReadArray(QStringLiteral("entries")); - map.buttons.reserve(num_touch_maps); - for (int i = 0; i < num_touch_maps; i++) { - qt_config->setArrayIndex(i); - std::string touch_mapping = - ReadSetting(QStringLiteral("bind")).toString().toStdString(); - map.buttons.emplace_back(std::move(touch_mapping)); - } - qt_config->endArray(); // entries - Settings::values.touch_from_button_maps.emplace_back(std::move(map)); - }; - - for (int i = 0; i < num_touch_from_button_maps; ++i) { - qt_config->setArrayIndex(i); - append_touch_from_button_map(); - } - } else { - Settings::values.touch_from_button_maps.emplace_back( - Settings::TouchFromButtonMap{"default", {}}); - num_touch_from_button_maps = 1; - } - qt_config->endArray(); - - Settings::values.touch_from_button_map_index = std::clamp( - Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1); -} - -void Config::ReadCoreValues() { - qt_config->beginGroup(QStringLiteral("Core")); - - ReadCategory(Settings::Category::Core); - - qt_config->endGroup(); -} - -void Config::ReadDataStorageValues() { - qt_config->beginGroup(QStringLiteral("Data Storage")); - - FS::SetYuzuPath( - FS::YuzuPath::NANDDir, - qt_config - ->value(QStringLiteral("nand_directory"), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::NANDDir))) - .toString() - .toStdString()); - FS::SetYuzuPath( - FS::YuzuPath::SDMCDir, - qt_config - ->value(QStringLiteral("sdmc_directory"), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::SDMCDir))) - .toString() - .toStdString()); - FS::SetYuzuPath( - FS::YuzuPath::LoadDir, - qt_config - ->value(QStringLiteral("load_directory"), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::LoadDir))) - .toString() - .toStdString()); - FS::SetYuzuPath( - FS::YuzuPath::DumpDir, - qt_config - ->value(QStringLiteral("dump_directory"), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::DumpDir))) - .toString() - .toStdString()); - FS::SetYuzuPath(FS::YuzuPath::TASDir, - qt_config - ->value(QStringLiteral("tas_directory"), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::TASDir))) - .toString() - .toStdString()); - - ReadCategory(Settings::Category::DataStorage); - - qt_config->endGroup(); -} - -void Config::ReadDebuggingValues() { - qt_config->beginGroup(QStringLiteral("Debugging")); - - // Intentionally not using the QT default setting as this is intended to be changed in the ini - Settings::values.record_frame_times = - qt_config->value(QStringLiteral("record_frame_times"), false).toBool(); - - ReadCategory(Settings::Category::Debugging); - ReadCategory(Settings::Category::DebuggingGraphics); - - qt_config->endGroup(); -} - -void Config::ReadServiceValues() { - qt_config->beginGroup(QStringLiteral("Services")); - - ReadCategory(Settings::Category::Services); - - qt_config->endGroup(); -} - -void Config::ReadDisabledAddOnValues() { - const auto size = qt_config->beginReadArray(QStringLiteral("DisabledAddOns")); - - for (int i = 0; i < size; ++i) { - qt_config->setArrayIndex(i); - const auto title_id = ReadSetting(QStringLiteral("title_id"), 0).toULongLong(); - std::vector<std::string> out; - const auto d_size = qt_config->beginReadArray(QStringLiteral("disabled")); - for (int j = 0; j < d_size; ++j) { - qt_config->setArrayIndex(j); - out.push_back(ReadSetting(QStringLiteral("d"), QString{}).toString().toStdString()); - } - qt_config->endArray(); - Settings::values.disabled_addons.insert_or_assign(title_id, out); - } - - qt_config->endArray(); -} - -void Config::ReadMiscellaneousValues() { - qt_config->beginGroup(QStringLiteral("Miscellaneous")); - - ReadCategory(Settings::Category::Miscellaneous); - - qt_config->endGroup(); -} - -void Config::ReadPathValues() { - qt_config->beginGroup(QStringLiteral("Paths")); - - UISettings::values.roms_path = ReadSetting(QStringLiteral("romsPath")).toString(); - UISettings::values.symbols_path = ReadSetting(QStringLiteral("symbolsPath")).toString(); - UISettings::values.game_dir_deprecated = - ReadSetting(QStringLiteral("gameListRootDir"), QStringLiteral(".")).toString(); - UISettings::values.game_dir_deprecated_deepscan = - ReadSetting(QStringLiteral("gameListDeepScan"), false).toBool(); - const int gamedirs_size = qt_config->beginReadArray(QStringLiteral("gamedirs")); - for (int i = 0; i < gamedirs_size; ++i) { - qt_config->setArrayIndex(i); - UISettings::GameDir game_dir; - game_dir.path = ReadSetting(QStringLiteral("path")).toString(); - game_dir.deep_scan = ReadSetting(QStringLiteral("deep_scan"), false).toBool(); - game_dir.expanded = ReadSetting(QStringLiteral("expanded"), true).toBool(); - UISettings::values.game_dirs.append(game_dir); - } - qt_config->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.isEmpty()) { - UISettings::GameDir game_dir; - game_dir.path = QStringLiteral("SDMC"); - game_dir.expanded = true; - UISettings::values.game_dirs.append(game_dir); - game_dir.path = QStringLiteral("UserNAND"); - UISettings::values.game_dirs.append(game_dir); - game_dir.path = QStringLiteral("SysNAND"); - UISettings::values.game_dirs.append(game_dir); - if (UISettings::values.game_dir_deprecated != QStringLiteral(".")) { - 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 = ReadSetting(QStringLiteral("recentFiles")).toStringList(); - UISettings::values.language = ReadSetting(QStringLiteral("language"), QString{}).toString(); - - qt_config->endGroup(); -} - -void Config::ReadCpuValues() { - qt_config->beginGroup(QStringLiteral("Cpu")); - - ReadCategory(Settings::Category::Cpu); - ReadCategory(Settings::Category::CpuDebug); - ReadCategory(Settings::Category::CpuUnsafe); - - qt_config->endGroup(); -} - -void Config::ReadRendererValues() { - qt_config->beginGroup(QStringLiteral("Renderer")); - - ReadCategory(Settings::Category::Renderer); - ReadCategory(Settings::Category::RendererAdvanced); - ReadCategory(Settings::Category::RendererDebug); - - qt_config->endGroup(); -} - -void Config::ReadScreenshotValues() { - qt_config->beginGroup(QStringLiteral("Screenshots")); - - ReadCategory(Settings::Category::Screenshots); - FS::SetYuzuPath( - FS::YuzuPath::ScreenshotsDir, - qt_config - ->value(QStringLiteral("screenshot_path"), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::ScreenshotsDir))) - .toString() - .toStdString()); - - qt_config->endGroup(); -} - -void Config::ReadShortcutValues() { - qt_config->beginGroup(QStringLiteral("Shortcuts")); - - for (const auto& [name, group, shortcut] : default_hotkeys) { - qt_config->beginGroup(group); - qt_config->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, - {ReadSetting(QStringLiteral("KeySeq"), shortcut.keyseq).toString(), - ReadSetting(QStringLiteral("Controller_KeySeq"), shortcut.controller_keyseq) - .toString(), - shortcut.context, ReadSetting(QStringLiteral("Repeat"), shortcut.repeat).toBool()}}); - qt_config->endGroup(); - qt_config->endGroup(); - } - - qt_config->endGroup(); -} - -void Config::ReadSystemValues() { - qt_config->beginGroup(QStringLiteral("System")); - - ReadCategory(Settings::Category::System); - ReadCategory(Settings::Category::SystemAudio); - - qt_config->endGroup(); -} - -void Config::ReadUIValues() { - qt_config->beginGroup(QStringLiteral("UI")); - - UISettings::values.theme = - ReadSetting( - QStringLiteral("theme"), - QString::fromUtf8(UISettings::themes[static_cast<size_t>(default_theme)].second)) - .toString(); - - ReadUIGamelistValues(); - ReadUILayoutValues(); - ReadPathValues(); - ReadScreenshotValues(); - ReadShortcutValues(); - ReadMultiplayerValues(); - - ReadCategory(Settings::Category::Ui); - ReadCategory(Settings::Category::UiGeneral); - - qt_config->endGroup(); -} - -void Config::ReadUIGamelistValues() { - qt_config->beginGroup(QStringLiteral("UIGameList")); - - ReadCategory(Settings::Category::UiGameList); - - const int favorites_size = qt_config->beginReadArray(QStringLiteral("favorites")); - for (int i = 0; i < favorites_size; i++) { - qt_config->setArrayIndex(i); - UISettings::values.favorited_ids.append( - ReadSetting(QStringLiteral("program_id")).toULongLong()); - } - qt_config->endArray(); - - qt_config->endGroup(); -} - -void Config::ReadUILayoutValues() { - qt_config->beginGroup(QStringLiteral("UILayout")); - - UISettings::values.geometry = ReadSetting(QStringLiteral("geometry")).toByteArray(); - UISettings::values.state = ReadSetting(QStringLiteral("state")).toByteArray(); - UISettings::values.renderwindow_geometry = - ReadSetting(QStringLiteral("geometryRenderWindow")).toByteArray(); - UISettings::values.gamelist_header_state = - ReadSetting(QStringLiteral("gameListHeaderState")).toByteArray(); - UISettings::values.microprofile_geometry = - ReadSetting(QStringLiteral("microProfileDialogGeometry")).toByteArray(); - - ReadCategory(Settings::Category::UiLayout); - - qt_config->endGroup(); -} - -void Config::ReadWebServiceValues() { - qt_config->beginGroup(QStringLiteral("WebService")); - - ReadCategory(Settings::Category::WebService); - - qt_config->endGroup(); -} - -void Config::ReadMultiplayerValues() { - qt_config->beginGroup(QStringLiteral("Multiplayer")); - - ReadCategory(Settings::Category::Multiplayer); - - // Read ban list back - int size = qt_config->beginReadArray(QStringLiteral("username_ban_list")); - UISettings::values.multiplayer_ban_list.first.resize(size); - for (int i = 0; i < size; ++i) { - qt_config->setArrayIndex(i); - UISettings::values.multiplayer_ban_list.first[i] = - ReadSetting(QStringLiteral("username")).toString().toStdString(); - } - qt_config->endArray(); - size = qt_config->beginReadArray(QStringLiteral("ip_ban_list")); - UISettings::values.multiplayer_ban_list.second.resize(size); - for (int i = 0; i < size; ++i) { - qt_config->setArrayIndex(i); - UISettings::values.multiplayer_ban_list.second[i] = - ReadSetting(QStringLiteral("ip")).toString().toStdString(); - } - qt_config->endArray(); - - qt_config->endGroup(); -} - -void Config::ReadNetworkValues() { - qt_config->beginGroup(QString::fromStdString("Services")); - - ReadCategory(Settings::Category::Network); - - qt_config->endGroup(); -} - -void Config::ReadValues() { - if (global) { - ReadDataStorageValues(); - ReadDebuggingValues(); - ReadDisabledAddOnValues(); - ReadNetworkValues(); - ReadServiceValues(); - ReadUIValues(); - ReadWebServiceValues(); - ReadMiscellaneousValues(); - } - ReadControlValues(); - ReadCoreValues(); - ReadCpuValues(); - ReadRendererValues(); - ReadAudioValues(); - ReadSystemValues(); -} - -void Config::SavePlayerValue(std::size_t player_index) { - const QString player_prefix = [this, player_index] { - if (type == ConfigType::InputProfile) { - return QString{}; - } else { - return QStringLiteral("player_%1_").arg(player_index); - } - }(); - - const auto& player = Settings::values.players.GetValue()[player_index]; - if (IsCustomConfig()) { - if (player.profile_name.empty()) { - // No custom profile selected - return; - } - WriteSetting(QStringLiteral("%1profile_name").arg(player_prefix), - QString::fromStdString(player.profile_name), QString{}); - } - - WriteSetting(QStringLiteral("%1type").arg(player_prefix), - static_cast<u8>(player.controller_type), - static_cast<u8>(Settings::ControllerType::ProController)); - - if (!player_prefix.isEmpty() || !Settings::IsConfiguringGlobal()) { - WriteSetting(QStringLiteral("%1connected").arg(player_prefix), player.connected, - player_index == 0); - WriteSetting(QStringLiteral("%1vibration_enabled").arg(player_prefix), - player.vibration_enabled, true); - WriteSetting(QStringLiteral("%1vibration_strength").arg(player_prefix), - player.vibration_strength, 100); - WriteSetting(QStringLiteral("%1body_color_left").arg(player_prefix), player.body_color_left, - Settings::JOYCON_BODY_NEON_BLUE); - WriteSetting(QStringLiteral("%1body_color_right").arg(player_prefix), - player.body_color_right, Settings::JOYCON_BODY_NEON_RED); - WriteSetting(QStringLiteral("%1button_color_left").arg(player_prefix), - player.button_color_left, Settings::JOYCON_BUTTONS_NEON_BLUE); - WriteSetting(QStringLiteral("%1button_color_right").arg(player_prefix), - player.button_color_right, Settings::JOYCON_BUTTONS_NEON_RED); - } - - for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { - const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); - WriteSetting(QStringLiteral("%1").arg(player_prefix) + - QString::fromStdString(Settings::NativeButton::mapping[i]), - QString::fromStdString(player.buttons[i]), - QString::fromStdString(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); - WriteSetting(QStringLiteral("%1").arg(player_prefix) + - QString::fromStdString(Settings::NativeAnalog::mapping[i]), - QString::fromStdString(player.analogs[i]), - QString::fromStdString(default_param)); - } - for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { - const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); - WriteSetting(QStringLiteral("%1").arg(player_prefix) + - QString::fromStdString(Settings::NativeMotion::mapping[i]), - QString::fromStdString(player.motions[i]), - QString::fromStdString(default_param)); - } -} - -void Config::SaveDebugValues() { - for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { - const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); - WriteSetting(QStringLiteral("debug_pad_") + - QString::fromStdString(Settings::NativeButton::mapping[i]), - QString::fromStdString(Settings::values.debug_pad_buttons[i]), - QString::fromStdString(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); - WriteSetting(QStringLiteral("debug_pad_") + - QString::fromStdString(Settings::NativeAnalog::mapping[i]), - QString::fromStdString(Settings::values.debug_pad_analogs[i]), - QString::fromStdString(default_param)); - } -} - -void Config::SaveTouchscreenValues() { - const auto& touchscreen = Settings::values.touchscreen; - - WriteSetting(QStringLiteral("touchscreen_enabled"), touchscreen.enabled, true); - - WriteSetting(QStringLiteral("touchscreen_angle"), touchscreen.rotation_angle, 0); - WriteSetting(QStringLiteral("touchscreen_diameter_x"), touchscreen.diameter_x, 15); - WriteSetting(QStringLiteral("touchscreen_diameter_y"), touchscreen.diameter_y, 15); -} - -void Config::SaveMotionTouchValues() { - qt_config->beginWriteArray(QStringLiteral("touch_from_button_maps")); - for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) { - qt_config->setArrayIndex(static_cast<int>(p)); - WriteSetting(QStringLiteral("name"), - QString::fromStdString(Settings::values.touch_from_button_maps[p].name), - QStringLiteral("default")); - qt_config->beginWriteArray(QStringLiteral("entries")); - for (std::size_t q = 0; q < Settings::values.touch_from_button_maps[p].buttons.size(); - ++q) { - qt_config->setArrayIndex(static_cast<int>(q)); - WriteSetting( - QStringLiteral("bind"), - QString::fromStdString(Settings::values.touch_from_button_maps[p].buttons[q])); - } - qt_config->endArray(); - } - qt_config->endArray(); -} - -void Config::SaveHidbusValues() { - const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( - 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); - WriteSetting(QStringLiteral("ring_controller"), - QString::fromStdString(Settings::values.ringcon_analogs), - QString::fromStdString(default_param)); -} - -void Config::SaveValues() { - if (global) { - SaveDataStorageValues(); - SaveDebuggingValues(); - SaveDisabledAddOnValues(); - SaveNetworkValues(); - SaveUIValues(); - SaveWebServiceValues(); - SaveMiscellaneousValues(); - } - SaveControlValues(); - SaveCoreValues(); - SaveCpuValues(); - SaveRendererValues(); - SaveAudioValues(); - SaveSystemValues(); - - qt_config->sync(); -} - -void Config::SaveAudioValues() { - qt_config->beginGroup(QStringLiteral("Audio")); - - WriteCategory(Settings::Category::Audio); - - qt_config->endGroup(); -} - -void Config::SaveControlValues() { - qt_config->beginGroup(QStringLiteral("Controls")); - - WriteCategory(Settings::Category::Controls); - - Settings::values.players.SetGlobal(!IsCustomConfig()); - for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { - SavePlayerValue(p); - } - if (IsCustomConfig()) { - qt_config->endGroup(); - return; - } - SaveDebugValues(); - SaveTouchscreenValues(); - SaveMotionTouchValues(); - SaveHidbusValues(); - - qt_config->endGroup(); -} - -void Config::SaveCoreValues() { - qt_config->beginGroup(QStringLiteral("Core")); - - WriteCategory(Settings::Category::Core); - - qt_config->endGroup(); -} - -void Config::SaveDataStorageValues() { - qt_config->beginGroup(QStringLiteral("Data Storage")); - - WriteSetting(QStringLiteral("nand_directory"), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::NANDDir)), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::NANDDir))); - WriteSetting(QStringLiteral("sdmc_directory"), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::SDMCDir)), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::SDMCDir))); - WriteSetting(QStringLiteral("load_directory"), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::LoadDir)), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::LoadDir))); - WriteSetting(QStringLiteral("dump_directory"), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::DumpDir)), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::DumpDir))); - WriteSetting(QStringLiteral("tas_directory"), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::TASDir)), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::TASDir))); - - WriteCategory(Settings::Category::DataStorage); - - qt_config->endGroup(); -} - -void Config::SaveDebuggingValues() { - qt_config->beginGroup(QStringLiteral("Debugging")); - - // Intentionally not using the QT default setting as this is intended to be changed in the ini - qt_config->setValue(QStringLiteral("record_frame_times"), Settings::values.record_frame_times); - - WriteCategory(Settings::Category::Debugging); - WriteCategory(Settings::Category::DebuggingGraphics); - - qt_config->endGroup(); -} - -void Config::SaveNetworkValues() { - qt_config->beginGroup(QStringLiteral("Services")); - - WriteCategory(Settings::Category::Network); - - qt_config->endGroup(); -} - -void Config::SaveDisabledAddOnValues() { - qt_config->beginWriteArray(QStringLiteral("DisabledAddOns")); - - int i = 0; - for (const auto& elem : Settings::values.disabled_addons) { - qt_config->setArrayIndex(i); - WriteSetting(QStringLiteral("title_id"), QVariant::fromValue<u64>(elem.first), 0); - qt_config->beginWriteArray(QStringLiteral("disabled")); - for (std::size_t j = 0; j < elem.second.size(); ++j) { - qt_config->setArrayIndex(static_cast<int>(j)); - WriteSetting(QStringLiteral("d"), QString::fromStdString(elem.second[j]), QString{}); - } - qt_config->endArray(); - ++i; - } - - qt_config->endArray(); -} - -void Config::SaveMiscellaneousValues() { - qt_config->beginGroup(QStringLiteral("Miscellaneous")); - - WriteCategory(Settings::Category::Miscellaneous); - - qt_config->endGroup(); -} - -void Config::SavePathValues() { - qt_config->beginGroup(QStringLiteral("Paths")); - - WriteSetting(QStringLiteral("romsPath"), UISettings::values.roms_path); - WriteSetting(QStringLiteral("symbolsPath"), UISettings::values.symbols_path); - qt_config->beginWriteArray(QStringLiteral("gamedirs")); - for (int i = 0; i < UISettings::values.game_dirs.size(); ++i) { - qt_config->setArrayIndex(i); - const auto& game_dir = UISettings::values.game_dirs[i]; - WriteSetting(QStringLiteral("path"), game_dir.path); - WriteSetting(QStringLiteral("deep_scan"), game_dir.deep_scan, false); - WriteSetting(QStringLiteral("expanded"), game_dir.expanded, true); - } - qt_config->endArray(); - WriteSetting(QStringLiteral("recentFiles"), UISettings::values.recent_files); - WriteSetting(QStringLiteral("language"), UISettings::values.language, QString{}); - - qt_config->endGroup(); -} - -void Config::SaveCpuValues() { - qt_config->beginGroup(QStringLiteral("Cpu")); - - WriteCategory(Settings::Category::Cpu); - WriteCategory(Settings::Category::CpuDebug); - WriteCategory(Settings::Category::CpuUnsafe); - - qt_config->endGroup(); -} - -void Config::SaveRendererValues() { - qt_config->beginGroup(QStringLiteral("Renderer")); - - WriteCategory(Settings::Category::Renderer); - WriteCategory(Settings::Category::RendererAdvanced); - WriteCategory(Settings::Category::RendererDebug); - - qt_config->endGroup(); -} - -void Config::SaveScreenshotValues() { - qt_config->beginGroup(QStringLiteral("Screenshots")); - - WriteSetting(QStringLiteral("screenshot_path"), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::ScreenshotsDir))); - WriteCategory(Settings::Category::Screenshots); - - qt_config->endGroup(); -} - -void Config::SaveShortcutValues() { - qt_config->beginGroup(QStringLiteral("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 < default_hotkeys.size(); i++) { - const auto& [name, group, shortcut] = UISettings::values.shortcuts[i]; - const auto& default_hotkey = default_hotkeys[i].shortcut; - - qt_config->beginGroup(group); - qt_config->beginGroup(name); - WriteSetting(QStringLiteral("KeySeq"), shortcut.keyseq, default_hotkey.keyseq); - WriteSetting(QStringLiteral("Controller_KeySeq"), shortcut.controller_keyseq, - default_hotkey.controller_keyseq); - WriteSetting(QStringLiteral("Context"), shortcut.context, default_hotkey.context); - WriteSetting(QStringLiteral("Repeat"), shortcut.repeat, default_hotkey.repeat); - qt_config->endGroup(); - qt_config->endGroup(); - } - - qt_config->endGroup(); -} - -void Config::SaveSystemValues() { - qt_config->beginGroup(QStringLiteral("System")); - - WriteCategory(Settings::Category::System); - WriteCategory(Settings::Category::SystemAudio); - - qt_config->endGroup(); -} - -void Config::SaveUIValues() { - qt_config->beginGroup(QStringLiteral("UI")); - - WriteCategory(Settings::Category::Ui); - WriteCategory(Settings::Category::UiGeneral); - - WriteSetting(QStringLiteral("theme"), UISettings::values.theme, - QString::fromUtf8(UISettings::themes[static_cast<size_t>(default_theme)].second)); - - SaveUIGamelistValues(); - SaveUILayoutValues(); - SavePathValues(); - SaveScreenshotValues(); - SaveShortcutValues(); - SaveMultiplayerValues(); - - qt_config->endGroup(); -} - -void Config::SaveUIGamelistValues() { - qt_config->beginGroup(QStringLiteral("UIGameList")); - - WriteCategory(Settings::Category::UiGameList); - - qt_config->beginWriteArray(QStringLiteral("favorites")); - for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) { - qt_config->setArrayIndex(i); - WriteSetting(QStringLiteral("program_id"), - QVariant::fromValue(UISettings::values.favorited_ids[i])); - } - qt_config->endArray(); - - qt_config->endGroup(); -} - -void Config::SaveUILayoutValues() { - qt_config->beginGroup(QStringLiteral("UILayout")); - - WriteSetting(QStringLiteral("geometry"), UISettings::values.geometry); - WriteSetting(QStringLiteral("state"), UISettings::values.state); - WriteSetting(QStringLiteral("geometryRenderWindow"), UISettings::values.renderwindow_geometry); - WriteSetting(QStringLiteral("gameListHeaderState"), UISettings::values.gamelist_header_state); - WriteSetting(QStringLiteral("microProfileDialogGeometry"), - UISettings::values.microprofile_geometry); - - WriteCategory(Settings::Category::UiLayout); - - qt_config->endGroup(); -} - -void Config::SaveWebServiceValues() { - qt_config->beginGroup(QStringLiteral("WebService")); - - WriteCategory(Settings::Category::WebService); - - qt_config->endGroup(); -} - -void Config::SaveMultiplayerValues() { - qt_config->beginGroup(QStringLiteral("Multiplayer")); - - WriteCategory(Settings::Category::Multiplayer); - - // Write ban list - qt_config->beginWriteArray(QStringLiteral("username_ban_list")); - for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.first.size(); ++i) { - qt_config->setArrayIndex(static_cast<int>(i)); - WriteSetting(QStringLiteral("username"), - QString::fromStdString(UISettings::values.multiplayer_ban_list.first[i])); - } - qt_config->endArray(); - qt_config->beginWriteArray(QStringLiteral("ip_ban_list")); - for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.second.size(); ++i) { - qt_config->setArrayIndex(static_cast<int>(i)); - WriteSetting(QStringLiteral("ip"), - QString::fromStdString(UISettings::values.multiplayer_ban_list.second[i])); - } - qt_config->endArray(); - - qt_config->endGroup(); -} - -QVariant Config::ReadSetting(const QString& name) const { - return qt_config->value(name); -} - -QVariant Config::ReadSetting(const QString& name, const QVariant& default_value) const { - QVariant result; - if (qt_config->value(name + QStringLiteral("/default"), false).toBool()) { - result = default_value; - } else { - result = qt_config->value(name, default_value); - } - return result; -} - -void Config::WriteSetting(const QString& name, const QVariant& value) { - qt_config->setValue(name, value); -} - -void Config::WriteSetting(const QString& name, const QVariant& value, - const QVariant& default_value) { - qt_config->setValue(name + QStringLiteral("/default"), value == default_value); - qt_config->setValue(name, value); -} - -void Config::WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value, - bool use_global) { - if (!global) { - qt_config->setValue(name + QStringLiteral("/use_global"), use_global); - } - if (global || !use_global) { - qt_config->setValue(name + QStringLiteral("/default"), value == default_value); - qt_config->setValue(name, value); - } -} - -void Config::Reload() { - ReadValues(); - // To apply default value changes - SaveValues(); -} - -void Config::Save() { - SaveValues(); -} - -void Config::ReadControlPlayerValue(std::size_t player_index) { - qt_config->beginGroup(QStringLiteral("Controls")); - ReadPlayerValue(player_index); - qt_config->endGroup(); -} - -void Config::SaveControlPlayerValue(std::size_t player_index) { - qt_config->beginGroup(QStringLiteral("Controls")); - SavePlayerValue(player_index); - qt_config->endGroup(); -} - -void Config::ClearControlPlayerValues() { - qt_config->beginGroup(QStringLiteral("Controls")); - // If key is an empty string, all keys in the current group() are removed. - qt_config->remove(QString{}); - qt_config->endGroup(); -} - -const std::string& Config::GetConfigFilePath() const { - return qt_config_loc; -} - -static auto 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 Config::ReadCategory(Settings::Category category) { - const auto& settings = FindRelevantList(category); - std::for_each(settings.begin(), settings.end(), - [&](const auto& setting) { ReadSettingGeneric(setting); }); -} - -void Config::WriteCategory(Settings::Category category) { - const auto& settings = FindRelevantList(category); - std::for_each(settings.begin(), settings.end(), - [&](const auto& setting) { WriteSettingGeneric(setting); }); -} - -void Config::ReadSettingGeneric(Settings::BasicSetting* const setting) { - if (!setting->Save() || (!setting->Switchable() && !global)) { - return; - } - const QString name = QString::fromStdString(setting->GetLabel()); - const auto default_value = - QVariant::fromValue<QString>(QString::fromStdString(setting->DefaultToString())); - - bool use_global = true; - if (setting->Switchable() && !global) { - use_global = qt_config->value(name + QStringLiteral("/use_global"), true).value<bool>(); - setting->SetGlobal(use_global); - } - - if (global || !use_global) { - const bool is_default = - qt_config->value(name + QStringLiteral("/default"), true).value<bool>(); - if (!is_default) { - setting->LoadString( - qt_config->value(name, default_value).value<QString>().toStdString()); - } else { - // Empty string resets the Setting to default - setting->LoadString(""); - } - } -} - -void Config::WriteSettingGeneric(Settings::BasicSetting* const setting) const { - if (!setting->Save()) { - return; - } - const QVariant value = QVariant::fromValue(QString::fromStdString(setting->ToString())); - const QVariant default_value = - QVariant::fromValue(QString::fromStdString(setting->DefaultToString())); - const QString label = QString::fromStdString(setting->GetLabel()); - if (setting->Switchable()) { - if (!global) { - qt_config->setValue(label + QStringLiteral("/use_global"), setting->UsingGlobal()); - } - if (global || !setting->UsingGlobal()) { - qt_config->setValue(label + QStringLiteral("/default"), value == default_value); - qt_config->setValue(label, value); - } - } else if (global) { - qt_config->setValue(label + QStringLiteral("/default"), value == default_value); - qt_config->setValue(label, value); - } -} diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h deleted file mode 100644 index 74ec4f771..000000000 --- a/src/yuzu/configuration/config.h +++ /dev/null @@ -1,179 +0,0 @@ -// SPDX-FileCopyrightText: 2014 Citra Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <array> -#include <memory> -#include <string> -#include <QMetaType> -#include <QVariant> -#include "common/settings.h" -#include "common/settings_enums.h" -#include "yuzu/uisettings.h" - -class QSettings; - -namespace Core { -class System; -} - -class Config { -public: - enum class ConfigType { - GlobalConfig, - PerGameConfig, - InputProfile, - }; - - explicit Config(const std::string& config_name = "qt-config", - ConfigType config_type = ConfigType::GlobalConfig); - ~Config(); - - void Reload(); - void Save(); - - void ReadControlPlayerValue(std::size_t player_index); - void SaveControlPlayerValue(std::size_t player_index); - void ClearControlPlayerValues(); - - const std::string& GetConfigFilePath() const; - - static const std::array<int, Settings::NativeButton::NumButtons> default_buttons; - static const std::array<int, Settings::NativeMotion::NumMotions> default_motions; - static const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> default_analogs; - static const std::array<int, 2> default_stick_mod; - static const std::array<int, 2> default_ringcon_analogs; - static const std::array<int, Settings::NativeMouseButton::NumMouseButtons> - default_mouse_buttons; - static const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> default_keyboard_keys; - static const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> default_keyboard_mods; - static const std::array<UISettings::Shortcut, 23> default_hotkeys; - - static const std::map<Settings::AntiAliasing, QString> anti_aliasing_texts_map; - static const std::map<Settings::ScalingFilter, QString> scaling_filter_texts_map; - static const std::map<Settings::ConsoleMode, QString> use_docked_mode_texts_map; - static const std::map<Settings::GpuAccuracy, QString> gpu_accuracy_texts_map; - static const std::map<Settings::RendererBackend, QString> renderer_backend_texts_map; - static const std::map<Settings::ShaderBackend, QString> shader_backend_texts_map; - - static constexpr UISettings::Theme default_theme{ -#ifdef _WIN32 - UISettings::Theme::DarkColorful -#else - UISettings::Theme::DefaultColorful -#endif - }; - -private: - void Initialize(const std::string& config_name); - bool IsCustomConfig(); - - void ReadValues(); - void ReadPlayerValue(std::size_t player_index); - void ReadDebugValues(); - void ReadKeyboardValues(); - void ReadMouseValues(); - void ReadTouchscreenValues(); - void ReadMotionTouchValues(); - void ReadHidbusValues(); - void ReadIrCameraValues(); - - // Read functions bases off the respective config section names. - void ReadAudioValues(); - void ReadControlValues(); - void ReadCoreValues(); - void ReadDataStorageValues(); - void ReadDebuggingValues(); - void ReadServiceValues(); - void ReadDisabledAddOnValues(); - void ReadMiscellaneousValues(); - void ReadPathValues(); - void ReadCpuValues(); - void ReadRendererValues(); - void ReadScreenshotValues(); - void ReadShortcutValues(); - void ReadSystemValues(); - void ReadUIValues(); - void ReadUIGamelistValues(); - void ReadUILayoutValues(); - void ReadWebServiceValues(); - void ReadMultiplayerValues(); - void ReadNetworkValues(); - - void SaveValues(); - void SavePlayerValue(std::size_t player_index); - void SaveDebugValues(); - void SaveMouseValues(); - void SaveTouchscreenValues(); - void SaveMotionTouchValues(); - void SaveHidbusValues(); - void SaveIrCameraValues(); - - // Save functions based off the respective config section names. - void SaveAudioValues(); - void SaveControlValues(); - void SaveCoreValues(); - void SaveDataStorageValues(); - void SaveDebuggingValues(); - void SaveNetworkValues(); - void SaveDisabledAddOnValues(); - void SaveMiscellaneousValues(); - void SavePathValues(); - void SaveCpuValues(); - void SaveRendererValues(); - void SaveScreenshotValues(); - void SaveShortcutValues(); - void SaveSystemValues(); - void SaveUIValues(); - void SaveUIGamelistValues(); - void SaveUILayoutValues(); - void SaveWebServiceValues(); - void SaveMultiplayerValues(); - - /** - * Reads a setting from the qt_config. - * - * @param name The setting's identifier - * @param default_value The value to use when the setting is not already present in the config - */ - QVariant ReadSetting(const QString& name) const; - QVariant ReadSetting(const QString& name, const QVariant& default_value) const; - - /** - * Writes a setting to the qt_config. - * - * @param name The setting's idetentifier - * @param value Value of the setting - * @param default_value Default of the setting if not present in qt_config - * @param use_global Specifies if the custom or global config should be in use, for custom - * configs - */ - void WriteSetting(const QString& name, const QVariant& value); - void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value); - void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value, - bool use_global); - - void ReadCategory(Settings::Category category); - void WriteCategory(Settings::Category category); - void ReadSettingGeneric(Settings::BasicSetting* const setting); - void WriteSettingGeneric(Settings::BasicSetting* const setting) const; - - const ConfigType type; - std::unique_ptr<QSettings> qt_config; - std::string qt_config_loc; - const bool global; -}; - -// 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); diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp index 81dd51ad3..9b6ef47a7 100644 --- a/src/yuzu/configuration/configure_audio.cpp +++ b/src/yuzu/configuration/configure_audio.cpp @@ -38,17 +38,21 @@ void ConfigureAudio::Setup(const ConfigurationShared::Builder& builder) { std::map<u32, QWidget*> hold; - auto push = [&](Settings::Category category) { + auto push_settings = [&](Settings::Category category) { for (auto* setting : Settings::values.linkage.by_category[category]) { settings.push_back(setting); } + }; + + auto push_ui_settings = [&](Settings::Category category) { for (auto* setting : UISettings::values.linkage.by_category[category]) { settings.push_back(setting); } }; - push(Settings::Category::Audio); - push(Settings::Category::SystemAudio); + push_settings(Settings::Category::Audio); + push_settings(Settings::Category::SystemAudio); + push_ui_settings(Settings::Category::UiAudio); for (auto* setting : settings) { auto* widget = builder.BuildWidget(setting, apply_funcs); diff --git a/src/yuzu/configuration/configure_camera.cpp b/src/yuzu/configuration/configure_camera.cpp index d95e96696..3368f53f3 100644 --- a/src/yuzu/configuration/configure_camera.cpp +++ b/src/yuzu/configuration/configure_camera.cpp @@ -10,10 +10,10 @@ #include <QStandardItemModel> #include <QTimer> +#include "common/settings.h" #include "input_common/drivers/camera.h" #include "input_common/main.h" #include "ui_configure_camera.h" -#include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_camera.h" ConfigureCamera::ConfigureCamera(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_) diff --git a/src/yuzu/configuration/configure_camera.h b/src/yuzu/configuration/configure_camera.h index 9a90512b3..3d822da7b 100644 --- a/src/yuzu/configuration/configure_camera.h +++ b/src/yuzu/configuration/configure_camera.h @@ -1,4 +1,4 @@ -// Text : Copyright 2022 yuzu Emulator Project +// Text : Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later #pragma once diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index ef421c754..1010038b7 100644 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp @@ -51,6 +51,8 @@ void ConfigureDebug::SetConfiguration() { ui->enable_all_controllers->setChecked(Settings::values.enable_all_controllers.GetValue()); ui->enable_renderdoc_hotkey->setEnabled(runtime_lock); ui->enable_renderdoc_hotkey->setChecked(Settings::values.enable_renderdoc_hotkey.GetValue()); + ui->disable_buffer_reorder->setEnabled(runtime_lock); + ui->disable_buffer_reorder->setChecked(Settings::values.disable_buffer_reorder.GetValue()); ui->enable_graphics_debugging->setEnabled(runtime_lock); ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug.GetValue()); ui->enable_shader_feedback->setEnabled(runtime_lock); @@ -96,6 +98,7 @@ void ConfigureDebug::ApplyConfiguration() { Settings::values.enable_all_controllers = ui->enable_all_controllers->isChecked(); Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked(); Settings::values.enable_renderdoc_hotkey = ui->enable_renderdoc_hotkey->isChecked(); + Settings::values.disable_buffer_reorder = ui->disable_buffer_reorder->isChecked(); Settings::values.renderer_shader_feedback = ui->enable_shader_feedback->isChecked(); Settings::values.cpu_debug_mode = ui->enable_cpu_debugging->isChecked(); Settings::values.enable_nsight_aftermath = ui->enable_nsight_aftermath->isChecked(); diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui index 76fe98924..22b51f39c 100644 --- a/src/yuzu/configuration/configure_debug.ui +++ b/src/yuzu/configuration/configure_debug.ui @@ -271,19 +271,6 @@ </widget> </item> <item row="8" column="0"> - <widget class="QCheckBox" name="disable_macro_hle"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="toolTip"> - <string>When checked, it disables the macro HLE functions. Enabling this makes games run slower</string> - </property> - <property name="text"> - <string>Disable Macro HLE</string> - </property> - </widget> - </item> - <item row="7" column="0"> <widget class="QCheckBox" name="dump_macros"> <property name="enabled"> <bool>true</bool> @@ -306,17 +293,27 @@ </property> </widget> </item> - <item row="2" column="0"> - <widget class="QCheckBox" name="enable_shader_feedback"> + <item row="6" column="0"> + <widget class="QCheckBox" name="dump_shaders"> + <property name="enabled"> + <bool>true</bool> + </property> <property name="toolTip"> - <string>When checked, yuzu will log statistics about the compiled pipeline cache</string> + <string>When checked, it will dump all the original assembler shaders from the disk shader cache or game as found</string> </property> <property name="text"> - <string>Enable Shader Feedback</string> + <string>Dump Game Shaders</string> </property> </widget> </item> - <item row="6" column="0"> + <item row="1" column="0"> + <widget class="QCheckBox" name="enable_renderdoc_hotkey"> + <property name="text"> + <string>Enable Renderdoc Hotkey</string> + </property> + </widget> + </item> + <item row="7" column="0"> <widget class="QCheckBox" name="disable_macro_jit"> <property name="enabled"> <bool>true</bool> @@ -330,20 +327,17 @@ </widget> </item> <item row="9" column="0"> - <spacer name="verticalSpacer_5"> - <property name="orientation"> - <enum>Qt::Vertical</enum> + <widget class="QCheckBox" name="disable_macro_hle"> + <property name="enabled"> + <bool>true</bool> </property> - <property name="sizeType"> - <enum>QSizePolicy::Preferred</enum> + <property name="toolTip"> + <string>When checked, it disables the macro HLE functions. Enabling this makes games run slower</string> </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>0</height> - </size> + <property name="text"> + <string>Disable Macro HLE</string> </property> - </spacer> + </widget> </item> <item row="0" column="0"> <widget class="QCheckBox" name="enable_graphics_debugging"> @@ -358,23 +352,39 @@ </property> </widget> </item> - <item row="5" column="0"> - <widget class="QCheckBox" name="dump_shaders"> - <property name="enabled"> - <bool>true</bool> + <item row="10" column="0"> + <spacer name="verticalSpacer_5"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Preferred</enum> </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="0"> + <widget class="QCheckBox" name="enable_shader_feedback"> <property name="toolTip"> - <string>When checked, it will dump all the original assembler shaders from the disk shader cache or game as found</string> + <string>When checked, yuzu will log statistics about the compiled pipeline cache</string> </property> <property name="text"> - <string>Dump Game Shaders</string> + <string>Enable Shader Feedback</string> </property> </widget> </item> - <item row="1" column="0"> - <widget class="QCheckBox" name="enable_renderdoc_hotkey"> + <item row="5" column="0"> + <widget class="QCheckBox" name="disable_buffer_reorder"> + <property name="toolTip"> + <string><html><head/><body><p>When checked, disables reording of mapped memory uploads which allows to associate uploads with specific draws. May reduce performance in some cases.</p></body></html></string> + </property> <property name="text"> - <string>Enable Renderdoc Hotkey</string> + <string>Disable Buffer Reorder</string> </property> </widget> </item> diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 0ad95cc02..aab54a1cc 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -8,7 +8,6 @@ #include "core/core.h" #include "ui_configure.h" #include "vk_device_info.h" -#include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_audio.h" #include "yuzu/configuration/configure_cpu.h" #include "yuzu/configuration/configure_debug_tab.h" diff --git a/src/yuzu/configuration/configure_hotkeys.cpp b/src/yuzu/configuration/configure_hotkeys.cpp index 68e21cd84..76fc33e49 100644 --- a/src/yuzu/configuration/configure_hotkeys.cpp +++ b/src/yuzu/configuration/configure_hotkeys.cpp @@ -9,10 +9,11 @@ #include "core/hid/emulated_controller.h" #include "core/hid/hid_core.h" +#include "frontend_common/config.h" #include "ui_configure_hotkeys.h" -#include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_hotkeys.h" #include "yuzu/hotkeys.h" +#include "yuzu/uisettings.h" #include "yuzu/util/sequence_dialog/sequence_dialog.h" constexpr int name_column = 0; @@ -62,18 +63,21 @@ ConfigureHotkeys::~ConfigureHotkeys() = default; void ConfigureHotkeys::Populate(const HotkeyRegistry& registry) { for (const auto& group : registry.hotkey_groups) { + QString parent_item_data = QString::fromStdString(group.first); auto* parent_item = - new QStandardItem(QCoreApplication::translate("Hotkeys", qPrintable(group.first))); + new QStandardItem(QCoreApplication::translate("Hotkeys", qPrintable(parent_item_data))); parent_item->setEditable(false); - parent_item->setData(group.first); + parent_item->setData(parent_item_data); for (const auto& hotkey : group.second) { - auto* action = - new QStandardItem(QCoreApplication::translate("Hotkeys", qPrintable(hotkey.first))); + QString hotkey_action_data = QString::fromStdString(hotkey.first); + auto* action = new QStandardItem( + QCoreApplication::translate("Hotkeys", qPrintable(hotkey_action_data))); auto* keyseq = new QStandardItem(hotkey.second.keyseq.toString(QKeySequence::NativeText)); - auto* controller_keyseq = new QStandardItem(hotkey.second.controller_keyseq); + auto* controller_keyseq = + new QStandardItem(QString::fromStdString(hotkey.second.controller_keyseq)); action->setEditable(false); - action->setData(hotkey.first); + action->setData(hotkey_action_data); keyseq->setEditable(false); controller_keyseq->setEditable(false); parent_item->appendRow({action, keyseq, controller_keyseq}); @@ -301,13 +305,13 @@ void ConfigureHotkeys::ApplyConfiguration(HotkeyRegistry& registry) { const QStandardItem* controller_keyseq = parent->child(key_column_id, controller_column); for (auto& [group, sub_actions] : registry.hotkey_groups) { - if (group != parent->data()) + if (group != parent->data().toString().toStdString()) continue; for (auto& [action_name, hotkey] : sub_actions) { - if (action_name != action->data()) + if (action_name != action->data().toString().toStdString()) continue; hotkey.keyseq = QKeySequence(keyseq->text()); - hotkey.controller_keyseq = controller_keyseq->text(); + hotkey.controller_keyseq = controller_keyseq->text().toStdString(); } } } @@ -319,7 +323,7 @@ void ConfigureHotkeys::ApplyConfiguration(HotkeyRegistry& registry) { void ConfigureHotkeys::RestoreDefaults() { for (int r = 0; r < model->rowCount(); ++r) { const QStandardItem* parent = model->item(r, 0); - const int hotkey_size = static_cast<int>(Config::default_hotkeys.size()); + const int hotkey_size = static_cast<int>(UISettings::default_hotkeys.size()); if (hotkey_size != parent->rowCount()) { QMessageBox::warning(this, tr("Invalid hotkey settings"), @@ -330,10 +334,11 @@ void ConfigureHotkeys::RestoreDefaults() { for (int r2 = 0; r2 < parent->rowCount(); ++r2) { model->item(r, 0) ->child(r2, hotkey_column) - ->setText(Config::default_hotkeys[r2].shortcut.keyseq); + ->setText(QString::fromStdString(UISettings::default_hotkeys[r2].shortcut.keyseq)); model->item(r, 0) ->child(r2, controller_column) - ->setText(Config::default_hotkeys[r2].shortcut.controller_keyseq); + ->setText(QString::fromStdString( + UISettings::default_hotkeys[r2].shortcut.controller_keyseq)); } } } @@ -379,7 +384,7 @@ void ConfigureHotkeys::PopupContextMenu(const QPoint& menu_location) { void ConfigureHotkeys::RestoreControllerHotkey(QModelIndex index) { const QString& default_key_sequence = - Config::default_hotkeys[index.row()].shortcut.controller_keyseq; + QString::fromStdString(UISettings::default_hotkeys[index.row()].shortcut.controller_keyseq); const auto [key_sequence_used, used_action] = IsUsedControllerKey(default_key_sequence); if (key_sequence_used && default_key_sequence != model->data(index).toString()) { @@ -393,7 +398,8 @@ void ConfigureHotkeys::RestoreControllerHotkey(QModelIndex index) { void ConfigureHotkeys::RestoreHotkey(QModelIndex index) { const QKeySequence& default_key_sequence = QKeySequence::fromString( - Config::default_hotkeys[index.row()].shortcut.keyseq, QKeySequence::NativeText); + QString::fromStdString(UISettings::default_hotkeys[index.row()].shortcut.keyseq), + QKeySequence::NativeText); const auto [key_sequence_used, used_action] = IsUsedKey(default_key_sequence); if (key_sequence_used && default_key_sequence != QKeySequence(model->data(index).toString())) { diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 3dcad2701..02e23cce6 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -152,7 +152,7 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem, connect(player_controllers[0], &ConfigureInputPlayer::HandheldStateChanged, [this](bool is_handheld) { UpdateDockedState(is_handheld); }); - advanced = new ConfigureInputAdvanced(this); + advanced = new ConfigureInputAdvanced(hid_core, this); ui->tabAdvanced->setLayout(new QHBoxLayout(ui->tabAdvanced)); ui->tabAdvanced->layout()->addWidget(advanced); diff --git a/src/yuzu/configuration/configure_input.h b/src/yuzu/configuration/configure_input.h index 136cd3a0a..beb503dae 100644 --- a/src/yuzu/configuration/configure_input.h +++ b/src/yuzu/configuration/configure_input.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2016 Citra Emulator Project +// SPDX-FileCopyrightText: 2016 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp index 3cfd5d439..441cea3f6 100644 --- a/src/yuzu/configuration/configure_input_advanced.cpp +++ b/src/yuzu/configuration/configure_input_advanced.cpp @@ -4,11 +4,13 @@ #include <QColorDialog> #include "common/settings.h" #include "core/core.h" +#include "core/hid/emulated_controller.h" +#include "core/hid/hid_core.h" #include "ui_configure_input_advanced.h" #include "yuzu/configuration/configure_input_advanced.h" -ConfigureInputAdvanced::ConfigureInputAdvanced(QWidget* parent) - : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputAdvanced>()) { +ConfigureInputAdvanced::ConfigureInputAdvanced(Core::HID::HIDCore& hid_core_, QWidget* parent) + : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputAdvanced>()), hid_core{hid_core_} { ui->setupUi(this); controllers_color_buttons = {{ @@ -123,6 +125,8 @@ void ConfigureInputAdvanced::ApplyConfiguration() { player.button_color_left = colors[1]; player.body_color_right = colors[2]; player.button_color_right = colors[3]; + + hid_core.GetEmulatedControllerByIndex(player_idx)->ReloadColorsFromSettings(); } Settings::values.debug_pad_enabled = ui->debug_enabled->isChecked(); diff --git a/src/yuzu/configuration/configure_input_advanced.h b/src/yuzu/configuration/configure_input_advanced.h index fc1230284..41f822c4a 100644 --- a/src/yuzu/configuration/configure_input_advanced.h +++ b/src/yuzu/configuration/configure_input_advanced.h @@ -14,11 +14,15 @@ namespace Ui { class ConfigureInputAdvanced; } +namespace Core::HID { +class HIDCore; +} // namespace Core::HID + class ConfigureInputAdvanced : public QWidget { Q_OBJECT public: - explicit ConfigureInputAdvanced(QWidget* parent = nullptr); + explicit ConfigureInputAdvanced(Core::HID::HIDCore& hid_core_, QWidget* parent = nullptr); ~ConfigureInputAdvanced() override; void ApplyConfiguration(); @@ -44,4 +48,6 @@ private: std::array<std::array<QColor, 4>, 8> controllers_colors; std::array<std::array<QPushButton*, 4>, 8> controllers_color_buttons; + + Core::HID::HIDCore& hid_core; }; diff --git a/src/yuzu/configuration/configure_input_per_game.cpp b/src/yuzu/configuration/configure_input_per_game.cpp index 78e65d468..8d9f65a05 100644 --- a/src/yuzu/configuration/configure_input_per_game.cpp +++ b/src/yuzu/configuration/configure_input_per_game.cpp @@ -5,12 +5,12 @@ #include "core/core.h" #include "core/hid/emulated_controller.h" #include "core/hid/hid_core.h" +#include "frontend_common/config.h" #include "ui_configure_input_per_game.h" -#include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_input_per_game.h" #include "yuzu/configuration/input_profiles.h" -ConfigureInputPerGame::ConfigureInputPerGame(Core::System& system_, Config* config_, +ConfigureInputPerGame::ConfigureInputPerGame(Core::System& system_, QtConfig* config_, QWidget* parent) : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputPerGame>()), profiles(std::make_unique<InputProfiles>()), system{system_}, config{config_} { @@ -110,6 +110,6 @@ void ConfigureInputPerGame::SaveConfiguration() { // Clear all controls from the config in case the user reverted back to globals config->ClearControlPlayerValues(); for (size_t index = 0; index < Settings::values.players.GetValue().size(); ++index) { - config->SaveControlPlayerValue(index); + config->SaveQtControlPlayerValues(index); } } diff --git a/src/yuzu/configuration/configure_input_per_game.h b/src/yuzu/configuration/configure_input_per_game.h index 660faf574..4420e856c 100644 --- a/src/yuzu/configuration/configure_input_per_game.h +++ b/src/yuzu/configuration/configure_input_per_game.h @@ -9,6 +9,7 @@ #include "ui_configure_input_per_game.h" #include "yuzu/configuration/input_profiles.h" +#include "yuzu/configuration/qt_config.h" class QComboBox; @@ -22,7 +23,7 @@ class ConfigureInputPerGame : public QWidget { Q_OBJECT public: - explicit ConfigureInputPerGame(Core::System& system_, Config* config_, + explicit ConfigureInputPerGame(Core::System& system_, QtConfig* config_, QWidget* parent = nullptr); /// Load and Save configurations to settings file. @@ -41,5 +42,5 @@ private: std::array<QComboBox*, 8> profile_comboboxes; Core::System& system; - Config* config; + QtConfig* config; }; diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 576f5b571..0f7b3714e 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -12,15 +12,16 @@ #include <QTimer> #include "common/assert.h" #include "common/param_package.h" +#include "configuration/qt_config.h" #include "core/hid/emulated_controller.h" #include "core/hid/hid_core.h" #include "core/hid/hid_types.h" +#include "frontend_common/config.h" #include "input_common/drivers/keyboard.h" #include "input_common/drivers/mouse.h" #include "input_common/main.h" #include "ui_configure_input_player.h" #include "yuzu/bootmanager.h" -#include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_input_player.h" #include "yuzu/configuration/configure_input_player_widget.h" #include "yuzu/configuration/configure_mouse_panning.h" @@ -322,11 +323,12 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i setFocusPolicy(Qt::ClickFocus); button_map = { - ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY, - ui->buttonLStick, ui->buttonRStick, ui->buttonL, ui->buttonR, - ui->buttonZL, ui->buttonZR, ui->buttonPlus, ui->buttonMinus, - ui->buttonDpadLeft, ui->buttonDpadUp, ui->buttonDpadRight, ui->buttonDpadDown, - ui->buttonSL, ui->buttonSR, ui->buttonHome, ui->buttonScreenshot, + ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY, + ui->buttonLStick, ui->buttonRStick, ui->buttonL, ui->buttonR, + ui->buttonZL, ui->buttonZR, ui->buttonPlus, ui->buttonMinus, + ui->buttonDpadLeft, ui->buttonDpadUp, ui->buttonDpadRight, ui->buttonDpadDown, + ui->buttonSLLeft, ui->buttonSRLeft, ui->buttonHome, ui->buttonScreenshot, + ui->buttonSLRight, ui->buttonSRRight, }; analog_map_buttons = {{ @@ -1181,10 +1183,13 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() { // List of all the widgets that will be hidden by any of the following layouts that need // "unhidden" after the controller type changes - const std::array<QWidget*, 11> layout_show = { - ui->buttonShoulderButtonsSLSR, + const std::array<QWidget*, 14> layout_show = { + ui->buttonShoulderButtonsSLSRLeft, + ui->buttonShoulderButtonsSLSRRight, ui->horizontalSpacerShoulderButtonsWidget, ui->horizontalSpacerShoulderButtonsWidget2, + ui->horizontalSpacerShoulderButtonsWidget3, + ui->horizontalSpacerShoulderButtonsWidget4, ui->buttonShoulderButtonsLeft, ui->buttonMiscButtonsMinusScreenshot, ui->bottomLeft, @@ -1202,16 +1207,19 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() { std::vector<QWidget*> layout_hidden; switch (layout) { case Core::HID::NpadStyleIndex::ProController: - case Core::HID::NpadStyleIndex::JoyconDual: case Core::HID::NpadStyleIndex::Handheld: layout_hidden = { - ui->buttonShoulderButtonsSLSR, + ui->buttonShoulderButtonsSLSRLeft, + ui->buttonShoulderButtonsSLSRRight, ui->horizontalSpacerShoulderButtonsWidget2, + ui->horizontalSpacerShoulderButtonsWidget4, }; break; case Core::HID::NpadStyleIndex::JoyconLeft: layout_hidden = { + ui->buttonShoulderButtonsSLSRRight, ui->horizontalSpacerShoulderButtonsWidget2, + ui->horizontalSpacerShoulderButtonsWidget3, ui->buttonShoulderButtonsRight, ui->buttonMiscButtonsPlusHome, ui->bottomRight, @@ -1219,16 +1227,17 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() { break; case Core::HID::NpadStyleIndex::JoyconRight: layout_hidden = { - ui->horizontalSpacerShoulderButtonsWidget, - ui->buttonShoulderButtonsLeft, - ui->buttonMiscButtonsMinusScreenshot, - ui->bottomLeft, + ui->buttonShoulderButtonsSLSRLeft, ui->horizontalSpacerShoulderButtonsWidget, + ui->horizontalSpacerShoulderButtonsWidget4, ui->buttonShoulderButtonsLeft, + ui->buttonMiscButtonsMinusScreenshot, ui->bottomLeft, }; break; case Core::HID::NpadStyleIndex::GameCube: layout_hidden = { - ui->buttonShoulderButtonsSLSR, + ui->buttonShoulderButtonsSLSRLeft, + ui->buttonShoulderButtonsSLSRRight, ui->horizontalSpacerShoulderButtonsWidget2, + ui->horizontalSpacerShoulderButtonsWidget4, ui->buttonMiscButtonsMinusGroup, ui->buttonMiscButtonsScreenshotGroup, }; @@ -1389,25 +1398,25 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() { for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) { emulated_controller->SetButtonParam( button_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam( - Config::default_buttons[button_id])}); + QtConfig::default_buttons[button_id])}); } for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) { Common::ParamPackage analog_param{}; for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) { Common::ParamPackage params{InputCommon::GenerateKeyboardParam( - Config::default_analogs[analog_id][sub_button_id])}; + QtConfig::default_analogs[analog_id][sub_button_id])}; SetAnalogParam(params, analog_param, analog_sub_buttons[sub_button_id]); } analog_param.Set("modifier", InputCommon::GenerateKeyboardParam( - Config::default_stick_mod[analog_id])); + QtConfig::default_stick_mod[analog_id])); emulated_controller->SetStickParam(analog_id, analog_param); } for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) { emulated_controller->SetMotionParam( motion_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam( - Config::default_motions[motion_id])}); + QtConfig::default_motions[motion_id])}); } // If mouse is selected we want to override with mappings from the driver diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h index d3255d2b4..fda09e925 100644 --- a/src/yuzu/configuration/configure_input_player.h +++ b/src/yuzu/configuration/configure_input_player.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2016 Citra Emulator Project +// SPDX-FileCopyrightText: 2016 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once diff --git a/src/yuzu/configuration/configure_input_player.ui b/src/yuzu/configuration/configure_input_player.ui index 611a79477..5518cccd1 100644 --- a/src/yuzu/configuration/configure_input_player.ui +++ b/src/yuzu/configuration/configure_input_player.ui @@ -1208,6 +1208,159 @@ <property name="spacing"> <number>3</number> </property> + <item> + <widget class="QWidget" name="buttonShoulderButtonsSLSRLeft" native="true"> + <layout class="QVBoxLayout" name="buttonShoulderButtonsSLSRLeftVerticalLayout"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item alignment="Qt::AlignHCenter"> + <widget class="QGroupBox" name="buttonShoulderButtonsSLLeftGroup"> + <property name="title"> + <string>SL</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <layout class="QVBoxLayout" name="buttonShoulderButtonsSLLeftVerticalLayout"> + <property name="spacing"> + <number>3</number> + </property> + <property name="leftMargin"> + <number>3</number> + </property> + <property name="topMargin"> + <number>3</number> + </property> + <property name="rightMargin"> + <number>3</number> + </property> + <property name="bottomMargin"> + <number>3</number> + </property> + <item> + <widget class="QPushButton" name="buttonSLLeft"> + <property name="minimumSize"> + <size> + <width>68</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>68</width> + <height>16777215</height> + </size> + </property> + <property name="styleSheet"> + <string notr="true">min-width: 68px;</string> + </property> + <property name="text"> + <string>SL</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item alignment="Qt::AlignHCenter"> + <widget class="QGroupBox" name="buttonShoulderButtonsSRLeftGroup"> + <property name="title"> + <string>SR</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <layout class="QVBoxLayout" name="buttonShoulderButtonsSRLeftVerticalLayout"> + <property name="spacing"> + <number>3</number> + </property> + <property name="leftMargin"> + <number>3</number> + </property> + <property name="topMargin"> + <number>3</number> + </property> + <property name="rightMargin"> + <number>3</number> + </property> + <property name="bottomMargin"> + <number>3</number> + </property> + <item> + <widget class="QPushButton" name="buttonSRLeft"> + <property name="minimumSize"> + <size> + <width>68</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>68</width> + <height>16777215</height> + </size> + </property> + <property name="styleSheet"> + <string notr="true">min-width: 68px;</string> + </property> + <property name="text"> + <string>SR</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QWidget" name="horizontalSpacerShoulderButtonsWidget4" native="true"> + <layout class="QHBoxLayout" name="horizontalSpacerShoulderButtonsWidget4Layout"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <spacer name="horizontalSpacerShoulderButtons5"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> <item> <widget class="QWidget" name="buttonShoulderButtonsLeft" native="true"> <layout class="QVBoxLayout" name="buttonShoulderButtonsLeftVerticalLayout"> @@ -1830,125 +1983,125 @@ </layout> </widget> </item> - <item> - <widget class="QWidget" name="buttonShoulderButtonsSLSR" native="true"> - <layout class="QVBoxLayout" name="buttonShoulderButtonsSLSRVerticalLayout"> - <property name="spacing"> - <number>0</number> - </property> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item alignment="Qt::AlignHCenter"> - <widget class="QGroupBox" name="buttonShoulderButtonsSLGroup"> - <property name="title"> - <string>SL</string> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - <layout class="QVBoxLayout" name="buttonShoulderButtonsSLVerticalLayout"> - <property name="spacing"> - <number>3</number> - </property> - <property name="leftMargin"> - <number>3</number> - </property> - <property name="topMargin"> - <number>3</number> - </property> - <property name="rightMargin"> - <number>3</number> - </property> - <property name="bottomMargin"> - <number>3</number> - </property> - <item> - <widget class="QPushButton" name="buttonSL"> - <property name="minimumSize"> - <size> - <width>68</width> - <height>0</height> - </size> - </property> - <property name="maximumSize"> - <size> - <width>68</width> - <height>16777215</height> - </size> - </property> - <property name="styleSheet"> - <string notr="true">min-width: 68px;</string> - </property> - <property name="text"> - <string>SL</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item alignment="Qt::AlignHCenter"> - <widget class="QGroupBox" name="buttonShoulderButtonsSRGroup"> - <property name="title"> - <string>SR</string> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - <layout class="QVBoxLayout" name="buttonShoulderButtonsSRVerticalLayout"> - <property name="spacing"> - <number>3</number> - </property> - <property name="leftMargin"> - <number>3</number> - </property> - <property name="topMargin"> - <number>3</number> - </property> - <property name="rightMargin"> - <number>3</number> - </property> - <property name="bottomMargin"> - <number>3</number> - </property> - <item> - <widget class="QPushButton" name="buttonSR"> - <property name="minimumSize"> - <size> - <width>68</width> - <height>0</height> - </size> - </property> - <property name="maximumSize"> - <size> - <width>68</width> - <height>16777215</height> - </size> - </property> - <property name="styleSheet"> - <string notr="true">min-width: 68px;</string> - </property> - <property name="text"> - <string>SR</string> - </property> - </widget> - </item> + <item> + <widget class="QWidget" name="buttonShoulderButtonsSLSRRight" native="true"> + <layout class="QVBoxLayout" name="buttonShoulderButtonsSLSRRightVerticalLayout"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item alignment="Qt::AlignHCenter"> + <widget class="QGroupBox" name="buttonShoulderButtonsSLRightGroup"> + <property name="title"> + <string>SL</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <layout class="QVBoxLayout" name="buttonShoulderButtonsSLRightVerticalLayout"> + <property name="spacing"> + <number>3</number> + </property> + <property name="leftMargin"> + <number>3</number> + </property> + <property name="topMargin"> + <number>3</number> + </property> + <property name="rightMargin"> + <number>3</number> + </property> + <property name="bottomMargin"> + <number>3</number> + </property> + <item> + <widget class="QPushButton" name="buttonSLRight"> + <property name="minimumSize"> + <size> + <width>68</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>68</width> + <height>16777215</height> + </size> + </property> + <property name="styleSheet"> + <string notr="true">min-width: 68px;</string> + </property> + <property name="text"> + <string>SL</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item alignment="Qt::AlignHCenter"> + <widget class="QGroupBox" name="buttonShoulderButtonsSRRightGroup"> + <property name="title"> + <string>SR</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <layout class="QVBoxLayout" name="buttonShoulderButtonsSRRightVerticalLayout"> + <property name="spacing"> + <number>3</number> + </property> + <property name="leftMargin"> + <number>3</number> + </property> + <property name="topMargin"> + <number>3</number> + </property> + <property name="rightMargin"> + <number>3</number> + </property> + <property name="bottomMargin"> + <number>3</number> + </property> + <item> + <widget class="QPushButton" name="buttonSRRight"> + <property name="minimumSize"> + <size> + <width>68</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>68</width> + <height>16777215</height> + </size> + </property> + <property name="styleSheet"> + <string notr="true">min-width: 68px;</string> + </property> + <property name="text"> + <string>SR</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> </layout> - </widget> - </item> - </layout> - </widget> - </item> + </widget> + </item> </layout> </item> <item> diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index a188eef92..550cff9a0 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -297,8 +297,8 @@ void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center) // Sideview SL and SR buttons button_color = colors.slider_button; - DrawRoundButton(p, center + QPoint(59, 52), button_values[SR], 5, 12, Direction::Left); - DrawRoundButton(p, center + QPoint(59, -69), button_values[SL], 5, 12, Direction::Left); + DrawRoundButton(p, center + QPoint(59, 52), button_values[SRLeft], 5, 12, Direction::Left); + DrawRoundButton(p, center + QPoint(59, -69), button_values[SLLeft], 5, 12, Direction::Left); DrawLeftBody(p, center); @@ -353,8 +353,10 @@ void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center) // SR and SL buttons p.setPen(colors.outline); button_color = colors.slider_button; - DrawRoundButton(p, center + QPoint(155, 52), button_values[SR], 5.2f, 12, Direction::None, 4); - DrawRoundButton(p, center + QPoint(155, -69), button_values[SL], 5.2f, 12, Direction::None, 4); + DrawRoundButton(p, center + QPoint(155, 52), button_values[SRLeft], 5.2f, 12, Direction::None, + 4); + DrawRoundButton(p, center + QPoint(155, -69), button_values[SLLeft], 5.2f, 12, Direction::None, + 4); // SR and SL text p.setPen(colors.transparent); @@ -428,8 +430,10 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center // Sideview SL and SR buttons button_color = colors.slider_button; - DrawRoundButton(p, center + QPoint(-59, 52), button_values[SL], 5, 11, Direction::Right); - DrawRoundButton(p, center + QPoint(-59, -69), button_values[SR], 5, 11, Direction::Right); + DrawRoundButton(p, center + QPoint(-59, 52), button_values[SLRight], 5, 11, + Direction::Right); + DrawRoundButton(p, center + QPoint(-59, -69), button_values[SRRight], 5, 11, + Direction::Right); DrawRightBody(p, center); @@ -484,8 +488,10 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center // SR and SL buttons p.setPen(colors.outline); button_color = colors.slider_button; - DrawRoundButton(p, center + QPoint(-155, 52), button_values[SL], 5, 12, Direction::None, 4.0f); - DrawRoundButton(p, center + QPoint(-155, -69), button_values[SR], 5, 12, Direction::None, 4.0f); + DrawRoundButton(p, center + QPoint(-155, 52), button_values[SLRight], 5, 12, Direction::None, + 4.0f); + DrawRoundButton(p, center + QPoint(-155, -69), button_values[SRRight], 5, 12, Direction::None, + 4.0f); // SR and SL text p.setPen(colors.transparent); @@ -557,6 +563,19 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center) DrawRoundButton(p, center + QPoint(-154, -72), button_values[Minus], 7, 4, Direction::Up, 1); + // Left SR and SL sideview buttons + button_color = colors.slider_button; + DrawRoundButton(p, center + QPoint(-20, -62), button_values[SLLeft], 4, 11, + Direction::Left); + DrawRoundButton(p, center + QPoint(-20, 47), button_values[SRLeft], 4, 11, Direction::Left); + + // Right SR and SL sideview buttons + button_color = colors.slider_button; + DrawRoundButton(p, center + QPoint(20, 47), button_values[SLRight], 4, 11, + Direction::Right); + DrawRoundButton(p, center + QPoint(20, -62), button_values[SRRight], 4, 11, + Direction::Right); + DrawDualBody(p, center); // Right trigger top view @@ -1792,16 +1811,6 @@ void PlayerControlPreview::DrawDualBody(QPainter& p, const QPointF center) { p.setBrush(colors.right); DrawPolygon(p, qright_joycon_topview); - // Right SR and SL sideview buttons - p.setPen(colors.outline); - p.setBrush(colors.slider_button); - DrawRoundRectangle(p, center + QPoint(19, 47), 7, 22, 1); - DrawRoundRectangle(p, center + QPoint(19, -62), 7, 22, 1); - - // Left SR and SL sideview buttons - DrawRoundRectangle(p, center + QPoint(-19, 47), 7, 22, 1); - DrawRoundRectangle(p, center + QPoint(-19, -62), 7, 22, 1); - // Right Sideview body p.setBrush(colors.slider); DrawPolygon(p, qright_joycon_slider); diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp index b91d6ad4a..b274a3321 100644 --- a/src/yuzu/configuration/configure_per_game.cpp +++ b/src/yuzu/configuration/configure_per_game.cpp @@ -25,8 +25,8 @@ #include "core/file_sys/patch_manager.h" #include "core/file_sys/xts_archive.h" #include "core/loader/loader.h" +#include "frontend_common/config.h" #include "ui_configure_per_game.h" -#include "yuzu/configuration/config.h" #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_audio.h" #include "yuzu/configuration/configure_cpu.h" @@ -50,8 +50,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st const auto file_path = std::filesystem::path(Common::FS::ToU8String(file_name)); const auto config_file_name = title_id == 0 ? Common::FS::PathToUTF8String(file_path.filename()) : fmt::format("{:016X}", title_id); - game_config = std::make_unique<Config>(config_file_name, Config::ConfigType::PerGameConfig); - + game_config = std::make_unique<QtConfig>(config_file_name, Config::ConfigType::PerGameConfig); addons_tab = std::make_unique<ConfigurePerGameAddons>(system_, this); audio_tab = std::make_unique<ConfigureAudio>(system_, tab_group, *builder, this); cpu_tab = std::make_unique<ConfigureCpu>(system_, tab_group, *builder, this); @@ -108,7 +107,7 @@ void ConfigurePerGame::ApplyConfiguration() { system.ApplySettings(); Settings::LogSettings(); - game_config->Save(); + game_config->SaveAllValues(); } void ConfigurePerGame::changeEvent(QEvent* event) { diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h index 1a727f32c..c8ee46c04 100644 --- a/src/yuzu/configuration/configure_per_game.h +++ b/src/yuzu/configuration/configure_per_game.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -12,9 +12,10 @@ #include "configuration/shared_widget.h" #include "core/file_sys/vfs_types.h" +#include "frontend_common/config.h" #include "vk_device_info.h" -#include "yuzu/configuration/config.h" #include "yuzu/configuration/configuration_shared.h" +#include "yuzu/configuration/qt_config.h" #include "yuzu/configuration/shared_translation.h" namespace Core { @@ -72,7 +73,7 @@ private: QGraphicsScene* scene; - std::unique_ptr<Config> game_config; + std::unique_ptr<QtConfig> game_config; Core::System& system; std::unique_ptr<ConfigurationShared::Builder> builder; diff --git a/src/yuzu/configuration/configure_per_game_addons.cpp b/src/yuzu/configuration/configure_per_game_addons.cpp index 674a75a62..140a7fe5d 100644 --- a/src/yuzu/configuration/configure_per_game_addons.cpp +++ b/src/yuzu/configuration/configure_per_game_addons.cpp @@ -19,7 +19,6 @@ #include "core/file_sys/xts_archive.h" #include "core/loader/loader.h" #include "ui_configure_per_game_addons.h" -#include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_input.h" #include "yuzu/configuration/configure_per_game_addons.h" #include "yuzu/uisettings.h" diff --git a/src/yuzu/configuration/configure_profile_manager.cpp b/src/yuzu/configuration/configure_profile_manager.cpp index a47089988..6d2219bf5 100644 --- a/src/yuzu/configuration/configure_profile_manager.cpp +++ b/src/yuzu/configuration/configure_profile_manager.cpp @@ -306,10 +306,10 @@ void ConfigureProfileManager::SetUserImage() { return; } - // Some games crash when the profile image is too big. Resize any image bigger than 256x256 + // Profile image must be 256x256 QImage image(image_path); - if (image.width() > 256 || image.height() > 256) { - image = image.scaled(256, 256, Qt::KeepAspectRatio); + if (image.width() != 256 || image.height() != 256) { + image = image.scaled(256, 256, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); if (!image.save(image_path)) { QMessageBox::warning(this, tr("Error resizing user image"), tr("Unable to resize image")); diff --git a/src/yuzu/configuration/configure_ringcon.cpp b/src/yuzu/configuration/configure_ringcon.cpp index f83705544..9572ff43c 100644 --- a/src/yuzu/configuration/configure_ringcon.cpp +++ b/src/yuzu/configuration/configure_ringcon.cpp @@ -8,6 +8,7 @@ #include <QTimer> #include <fmt/format.h> +#include "configuration/qt_config.h" #include "core/hid/emulated_controller.h" #include "core/hid/hid_core.h" #include "input_common/drivers/keyboard.h" @@ -15,7 +16,6 @@ #include "input_common/main.h" #include "ui_configure_ringcon.h" #include "yuzu/bootmanager.h" -#include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_ringcon.h" const std::array<std::string, ConfigureRingController::ANALOG_SUB_BUTTONS_NUM> @@ -270,7 +270,7 @@ void ConfigureRingController::LoadConfiguration() { void ConfigureRingController::RestoreDefaults() { const std::string default_ring_string = InputCommon::GenerateAnalogParamFromKeys( - 0, 0, Config::default_ringcon_analogs[0], Config::default_ringcon_analogs[1], 0, 0.05f); + 0, 0, QtConfig::default_ringcon_analogs[0], QtConfig::default_ringcon_analogs[1], 0, 0.05f); emulated_controller->SetRingParam(Common::ParamPackage(default_ring_string)); UpdateUI(); } diff --git a/src/yuzu/configuration/configure_ringcon.h b/src/yuzu/configuration/configure_ringcon.h index b23c27906..6fd95e2b8 100644 --- a/src/yuzu/configuration/configure_ringcon.h +++ b/src/yuzu/configuration/configure_ringcon.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp index 0c8e5c8b4..7cbf43775 100644 --- a/src/yuzu/configuration/configure_system.cpp +++ b/src/yuzu/configuration/configure_system.cpp @@ -16,7 +16,6 @@ #include "core/core.h" #include "core/hle/service/time/time_manager.h" #include "ui_configure_system.h" -#include "yuzu/configuration/config.h" #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_system.h" #include "yuzu/configuration/shared_widget.h" diff --git a/src/yuzu/configuration/configure_tas.h b/src/yuzu/configuration/configure_tas.h index 4a6b0ba4e..a91891906 100644 --- a/src/yuzu/configuration/configure_tas.h +++ b/src/yuzu/configuration/configure_tas.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once diff --git a/src/yuzu/configuration/configure_touchscreen_advanced.cpp b/src/yuzu/configuration/configure_touchscreen_advanced.cpp index 5a03e48df..94df6d9d3 100644 --- a/src/yuzu/configuration/configure_touchscreen_advanced.cpp +++ b/src/yuzu/configuration/configure_touchscreen_advanced.cpp @@ -2,8 +2,8 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include <memory> +#include "common/settings.h" #include "ui_configure_touchscreen_advanced.h" -#include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_touchscreen_advanced.h" ConfigureTouchscreenAdvanced::ConfigureTouchscreenAdvanced(QWidget* parent) diff --git a/src/yuzu/configuration/configure_touchscreen_advanced.h b/src/yuzu/configuration/configure_touchscreen_advanced.h index 034dc0d46..b6fdffdc8 100644 --- a/src/yuzu/configuration/configure_touchscreen_advanced.h +++ b/src/yuzu/configuration/configure_touchscreen_advanced.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2016 Citra Emulator Project +// SPDX-FileCopyrightText: 2016 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp index 82f3b6e78..dd43f0a0e 100644 --- a/src/yuzu/configuration/configure_ui.cpp +++ b/src/yuzu/configuration/configure_ui.cpp @@ -164,7 +164,7 @@ ConfigureUi::~ConfigureUi() = default; void ConfigureUi::ApplyConfiguration() { UISettings::values.theme = - ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString(); + ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString().toStdString(); UISettings::values.show_add_ons = ui->show_add_ons->isChecked(); UISettings::values.show_compat = ui->show_compat->isChecked(); UISettings::values.show_size = ui->show_size->isChecked(); @@ -191,9 +191,10 @@ void ConfigureUi::RequestGameListUpdate() { } void ConfigureUi::SetConfiguration() { - ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme)); + ui->theme_combobox->setCurrentIndex( + ui->theme_combobox->findData(QString::fromStdString(UISettings::values.theme))); ui->language_combobox->setCurrentIndex( - ui->language_combobox->findData(UISettings::values.language)); + ui->language_combobox->findData(QString::fromStdString(UISettings::values.language))); ui->show_add_ons->setChecked(UISettings::values.show_add_ons.GetValue()); ui->show_compat->setChecked(UISettings::values.show_compat.GetValue()); ui->show_size->setChecked(UISettings::values.show_size.GetValue()); diff --git a/src/yuzu/configuration/input_profiles.cpp b/src/yuzu/configuration/input_profiles.cpp index 41ef4250a..716efbccd 100644 --- a/src/yuzu/configuration/input_profiles.cpp +++ b/src/yuzu/configuration/input_profiles.cpp @@ -5,7 +5,7 @@ #include "common/fs/fs.h" #include "common/fs/path_util.h" -#include "yuzu/configuration/config.h" +#include "frontend_common/config.h" #include "yuzu/configuration/input_profiles.h" namespace FS = Common::FS; @@ -44,7 +44,7 @@ InputProfiles::InputProfiles() { if (IsINI(filename) && IsProfileNameValid(name_without_ext)) { map_profiles.insert_or_assign( name_without_ext, - std::make_unique<Config>(name_without_ext, Config::ConfigType::InputProfile)); + std::make_unique<QtConfig>(name_without_ext, Config::ConfigType::InputProfile)); } return true; @@ -85,7 +85,7 @@ bool InputProfiles::CreateProfile(const std::string& profile_name, std::size_t p } map_profiles.insert_or_assign( - profile_name, std::make_unique<Config>(profile_name, Config::ConfigType::InputProfile)); + profile_name, std::make_unique<QtConfig>(profile_name, Config::ConfigType::InputProfile)); return SaveProfile(profile_name, player_index); } @@ -113,7 +113,7 @@ bool InputProfiles::LoadProfile(const std::string& profile_name, std::size_t pla return false; } - map_profiles[profile_name]->ReadControlPlayerValue(player_index); + map_profiles[profile_name]->ReadQtControlPlayerValues(player_index); return true; } @@ -122,7 +122,7 @@ bool InputProfiles::SaveProfile(const std::string& profile_name, std::size_t pla return false; } - map_profiles[profile_name]->SaveControlPlayerValue(player_index); + map_profiles[profile_name]->SaveQtControlPlayerValues(player_index); return true; } diff --git a/src/yuzu/configuration/input_profiles.h b/src/yuzu/configuration/input_profiles.h index 2bf3e4250..023ec74a6 100644 --- a/src/yuzu/configuration/input_profiles.h +++ b/src/yuzu/configuration/input_profiles.h @@ -6,6 +6,8 @@ #include <string> #include <unordered_map> +#include "configuration/qt_config.h" + namespace Core { class System; } @@ -30,5 +32,5 @@ public: private: bool ProfileExistsInMap(const std::string& profile_name) const; - std::unordered_map<std::string, std::unique_ptr<Config>> map_profiles; + std::unordered_map<std::string, std::unique_ptr<QtConfig>> map_profiles; }; diff --git a/src/yuzu/configuration/qt_config.cpp b/src/yuzu/configuration/qt_config.cpp new file mode 100644 index 000000000..5a8e69aa9 --- /dev/null +++ b/src/yuzu/configuration/qt_config.cpp @@ -0,0 +1,549 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "input_common/main.h" +#include "qt_config.h" +#include "uisettings.h" + +const std::array<int, Settings::NativeButton::NumButtons> 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<int, Settings::NativeMotion::NumMotions> QtConfig::default_motions = { + Qt::Key_7, + Qt::Key_8, +}; + +const std::array<std::array<int, 4>, 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<int, 2> QtConfig::default_stick_mod = { + Qt::Key_Shift, + 0, +}; + +const std::array<int, 2> 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() { + Save(); + 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]; + 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.symbols_path = ReadStringSetting(std::string("symbolsPath")); + 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); + UISettings::values.language = ReadStringSetting(std::string("language"), std::string("")); + + 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<size_t>(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) { + SaveUIValues(); + } + 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]); + WriteSetting(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); + WriteSetting(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]); + WriteSetting(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]); + WriteSetting(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); + WriteSetting(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); + WriteSetting(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)); + + WriteSetting(std::string("romsPath"), UISettings::values.roms_path); + WriteSetting(std::string("symbolsPath"), UISettings::values.symbols_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]; + WriteSetting(std::string("path"), game_dir.path); + WriteSetting(std::string("deep_scan"), game_dir.deep_scan, std::make_optional(false)); + WriteSetting(std::string("expanded"), game_dir.expanded, std::make_optional(true)); + } + EndArray(); + + WriteSetting(std::string("recentFiles"), + UISettings::values.recent_files.join(QStringLiteral(", ")).toStdString()); + WriteSetting(std::string("language"), UISettings::values.language); + + 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); + + WriteSetting(std::string("KeySeq"), shortcut.keyseq, + std::make_optional(default_hotkey.keyseq)); + WriteSetting(std::string("Controller_KeySeq"), shortcut.controller_keyseq, + std::make_optional(default_hotkey.controller_keyseq)); + WriteSetting(std::string("Context"), shortcut.context, + std::make_optional(default_hotkey.context)); + WriteSetting(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); + + WriteSetting(std::string("theme"), UISettings::values.theme, + std::make_optional(std::string( + UISettings::themes[static_cast<size_t>(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); + WriteSetting(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<int>(i)); + WriteSetting(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<int>(i)); + WriteSetting(std::string("ip"), UISettings::values.multiplayer_ban_list.second[i]); + } + EndArray(); // ip_ban_list + + EndGroup(); +} + +std::vector<Settings::BasicSetting*>& 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)); + + SavePlayerValues(player_index); + SaveQtPlayerValues(player_index); + + EndGroup(); + + WriteToIni(); +} diff --git a/src/yuzu/configuration/qt_config.h b/src/yuzu/configuration/qt_config.h new file mode 100644 index 000000000..dc2dceb4d --- /dev/null +++ b/src/yuzu/configuration/qt_config.h @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <QMetaType> + +#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<Settings::BasicSetting*>& FindRelevantList(Settings::Category category) override; + +public: + static const std::array<int, Settings::NativeButton::NumButtons> default_buttons; + static const std::array<int, Settings::NativeMotion::NumMotions> default_motions; + static const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> default_analogs; + static const std::array<int, 2> default_stick_mod; + static const std::array<int, 2> default_ringcon_analogs; +}; diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp index 3fe448f27..a7b5def32 100644 --- a/src/yuzu/configuration/shared_translation.cpp +++ b/src/yuzu/configuration/shared_translation.cpp @@ -1,17 +1,18 @@ // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "common/time_zone.h" #include "yuzu/configuration/shared_translation.h" #include <map> #include <memory> #include <tuple> #include <utility> +#include <QCoreApplication> #include <QWidget> #include "common/settings.h" #include "common/settings_enums.h" #include "common/settings_setting.h" +#include "common/time_zone.h" #include "yuzu/uisettings.h" namespace ConfigurationShared { @@ -21,123 +22,135 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) { 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{tr((NAME)), tr((TOOLTIP))}}) + translations->insert(std::pair{SETTINGS::values.ID.Id(), std::pair{(NAME), (TOOLTIP)}}) // A setting can be ignored by giving it a blank name // Audio - INSERT(Settings, sink_id, "Output Engine:", ""); - INSERT(Settings, audio_output_device_id, "Output Device:", ""); - INSERT(Settings, audio_input_device_id, "Input Device:", ""); - INSERT(Settings, audio_muted, "Mute audio", ""); - INSERT(Settings, volume, "Volume:", ""); - INSERT(Settings, dump_audio_commands, "", ""); - INSERT(UISettings, mute_when_in_background, "Mute audio when in background", ""); + INSERT(Settings, sink_id, tr("Output Engine:"), QStringLiteral()); + INSERT(Settings, audio_output_device_id, tr("Output Device:"), QStringLiteral()); + INSERT(Settings, audio_input_device_id, tr("Input Device:"), QStringLiteral()); + INSERT(Settings, audio_muted, tr("Mute audio"), QStringLiteral()); + INSERT(Settings, volume, tr("Volume:"), QStringLiteral()); + INSERT(Settings, dump_audio_commands, QStringLiteral(), QStringLiteral()); + INSERT(UISettings, mute_when_in_background, tr("Mute audio when in background"), + QStringLiteral()); // Core - INSERT(Settings, use_multi_core, "Multicore CPU Emulation", ""); - INSERT(Settings, memory_layout_mode, "Memory Layout", ""); - INSERT(Settings, use_speed_limit, "", ""); - INSERT(Settings, speed_limit, "Limit Speed Percent", ""); + INSERT(Settings, use_multi_core, tr("Multicore CPU Emulation"), QStringLiteral()); + INSERT(Settings, memory_layout_mode, tr("Memory Layout"), QStringLiteral()); + INSERT(Settings, use_speed_limit, QStringLiteral(), QStringLiteral()); + INSERT(Settings, speed_limit, tr("Limit Speed Percent"), QStringLiteral()); // Cpu - INSERT(Settings, cpu_accuracy, "Accuracy:", ""); + INSERT(Settings, cpu_accuracy, tr("Accuracy:"), QStringLiteral()); // Cpu Debug // Cpu Unsafe - INSERT(Settings, cpuopt_unsafe_unfuse_fma, - "Unfuse FMA (improve performance on CPUs without FMA)", - "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, "Faster FRSQRTE and FRECPE", - "This option improves the speed of some approximate floating-point functions by using " - "less accurate native approximations."); - INSERT(Settings, cpuopt_unsafe_ignore_standard_fpcr, "Faster ASIMD instructions (32 bits only)", - "This option improves the speed of 32 bits ASIMD floating-point functions by running " - "with incorrect rounding modes."); - INSERT(Settings, cpuopt_unsafe_inaccurate_nan, "Inaccurate NaN handling", - "This option improves speed by removing NaN checking. Please note this also reduces " - "accuracy of certain floating-point instructions."); INSERT( - Settings, cpuopt_unsafe_fastmem_check, "Disable address space checks", - "This option improves speed by eliminating a safety check before every memory read/write " - "in guest. Disabling it may allow a game to read/write the emulator's memory."); - INSERT(Settings, cpuopt_unsafe_ignore_global_monitor, "Ignore global monitor", - "This option improves speed by relying only on the semantics of cmpxchg to ensure " + 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. Please 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. Disabling 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. Please note this may result in deadlocks and " - "other race conditions."); + "other race conditions.")); // Renderer - INSERT(Settings, renderer_backend, "API:", ""); - INSERT(Settings, vulkan_device, "Device:", ""); - INSERT(Settings, shader_backend, "Shader Backend:", ""); - INSERT(Settings, resolution_setup, "Resolution:", ""); - INSERT(Settings, scaling_filter, "Window Adapting Filter:", ""); - INSERT(Settings, fsr_sharpening_slider, "FSR Sharpness:", ""); - INSERT(Settings, anti_aliasing, "Anti-Aliasing Method:", ""); - INSERT(Settings, fullscreen_mode, "Fullscreen Mode:", ""); - INSERT(Settings, aspect_ratio, "Aspect Ratio:", ""); - INSERT(Settings, use_disk_shader_cache, "Use disk pipeline cache", ""); - INSERT(Settings, use_asynchronous_gpu_emulation, "Use asynchronous GPU emulation", ""); - INSERT(Settings, nvdec_emulation, "NVDEC emulation:", ""); - INSERT(Settings, accelerate_astc, "ASTC Decoding Method:", ""); - INSERT(Settings, astc_recompression, "ASTC Recompression Method:", ""); - INSERT(Settings, vsync_mode, "VSync Mode:", - "FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen " + INSERT(Settings, renderer_backend, tr("API:"), QStringLiteral()); + INSERT(Settings, vulkan_device, tr("Device:"), QStringLiteral()); + INSERT(Settings, shader_backend, tr("Shader Backend:"), QStringLiteral()); + INSERT(Settings, resolution_setup, tr("Resolution:"), QStringLiteral()); + INSERT(Settings, scaling_filter, tr("Window Adapting Filter:"), QStringLiteral()); + INSERT(Settings, fsr_sharpening_slider, tr("FSR Sharpness:"), QStringLiteral()); + INSERT(Settings, anti_aliasing, tr("Anti-Aliasing Method:"), QStringLiteral()); + INSERT(Settings, fullscreen_mode, tr("Fullscreen Mode:"), QStringLiteral()); + INSERT(Settings, aspect_ratio, tr("Aspect Ratio:"), QStringLiteral()); + INSERT(Settings, use_disk_shader_cache, tr("Use disk pipeline cache"), QStringLiteral()); + INSERT(Settings, use_asynchronous_gpu_emulation, tr("Use asynchronous GPU emulation"), + QStringLiteral()); + INSERT(Settings, nvdec_emulation, tr("NVDEC emulation:"), QStringLiteral()); + INSERT(Settings, accelerate_astc, tr("ASTC Decoding Method:"), QStringLiteral()); + INSERT(Settings, astc_recompression, tr("ASTC Recompression Method:"), QStringLiteral()); + 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, "", ""); - INSERT(Settings, bg_green, "", ""); - INSERT(Settings, bg_blue, "", ""); + "exhibit tearing.")); + INSERT(Settings, bg_red, QStringLiteral(), QStringLiteral()); + INSERT(Settings, bg_green, QStringLiteral(), QStringLiteral()); + INSERT(Settings, bg_blue, QStringLiteral(), QStringLiteral()); // Renderer (Advanced Graphics) - INSERT(Settings, async_presentation, "Enable asynchronous presentation (Vulkan only)", ""); - INSERT(Settings, renderer_force_max_clock, "Force maximum clocks (Vulkan only)", - "Runs work in the background while waiting for graphics commands to keep the GPU from " - "lowering its clock speed."); - INSERT(Settings, max_anisotropy, "Anisotropic Filtering:", ""); - INSERT(Settings, gpu_accuracy, "Accuracy Level:", ""); - INSERT(Settings, use_asynchronous_shaders, "Use asynchronous shader building (Hack)", - "Enables asynchronous shader compilation, which may reduce shader stutter. This feature " - "is experimental."); - INSERT(Settings, use_fast_gpu_time, "Use Fast GPU Time (Hack)", - "Enables Fast GPU Time. This option will force most games to run at their highest " - "native resolution."); - INSERT(Settings, use_vulkan_driver_pipeline_cache, "Use Vulkan pipeline cache", - "Enables GPU vendor-specific pipeline cache. This 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, "Enable Compute Pipelines (Intel Vulkan Only)", - "Enable compute pipelines, required by some games.\nThis setting only exists for Intel " + INSERT(Settings, async_presentation, tr("Enable asynchronous presentation (Vulkan only)"), + QStringLiteral()); + 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:"), QStringLiteral()); + INSERT(Settings, gpu_accuracy, tr("Accuracy Level:"), QStringLiteral()); + INSERT( + Settings, use_asynchronous_shaders, tr("Use asynchronous shader building (Hack)"), + tr("Enables asynchronous shader compilation, which may reduce shader stutter. This 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. This 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, "Enable Reactive Flushing", - "Uses reactive flushing instead of predictive flushing, allowing more accurate memory " - "syncing."); - INSERT(Settings, use_video_framerate, "Sync to framerate of video playback", - "Run the game at normal speed during video playback, even when the framerate is " - "unlocked."); - INSERT(Settings, barrier_feedback_loops, "Barrier feedback loops", - "Improves rendering of transparency effects in specific games."); + "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 (Debug) // System - INSERT(Settings, rng_seed, "RNG Seed", ""); - INSERT(Settings, rng_seed_enabled, "", ""); - INSERT(Settings, device_name, "Device Name", ""); - INSERT(Settings, custom_rtc, "Custom RTC", ""); - INSERT(Settings, custom_rtc_enabled, "", ""); - INSERT(Settings, language_index, - "Language:", "Note: this can be overridden when region setting is auto-select"); - INSERT(Settings, region_index, "Region:", ""); - INSERT(Settings, time_zone_index, "Time Zone:", ""); - INSERT(Settings, sound_index, "Sound Output Mode:", ""); - INSERT(Settings, use_docked_mode, "Console Mode:", ""); - INSERT(Settings, current_user, "", ""); + INSERT(Settings, rng_seed, tr("RNG Seed"), QStringLiteral()); + INSERT(Settings, rng_seed_enabled, QStringLiteral(), QStringLiteral()); + INSERT(Settings, device_name, tr("Device Name"), QStringLiteral()); + INSERT(Settings, custom_rtc, tr("Custom RTC"), QStringLiteral()); + INSERT(Settings, custom_rtc_enabled, QStringLiteral(), QStringLiteral()); + INSERT(Settings, language_index, tr("Language:"), + tr("Note: this can be overridden when region setting is auto-select")); + INSERT(Settings, region_index, tr("Region:"), QStringLiteral()); + INSERT(Settings, time_zone_index, tr("Time Zone:"), QStringLiteral()); + INSERT(Settings, sound_index, tr("Sound Output Mode:"), QStringLiteral()); + INSERT(Settings, use_docked_mode, tr("Console Mode:"), QStringLiteral()); + INSERT(Settings, current_user, QStringLiteral(), QStringLiteral()); // Controls @@ -154,12 +167,14 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) { // Ui // Ui General - INSERT(UISettings, select_user_on_boot, "Prompt for user on game boot", ""); - INSERT(UISettings, pause_when_in_background, "Pause emulation when in background", ""); - INSERT(UISettings, confirm_before_closing, "Confirm exit while emulation is running", ""); - INSERT(UISettings, confirm_before_stopping, "Confirm before stopping emulation", ""); - INSERT(UISettings, hide_mouse, "Hide mouse on inactivity", ""); - INSERT(UISettings, controller_applet_disabled, "Disable controller applet", ""); + INSERT(UISettings, select_user_on_boot, tr("Prompt for user on game boot"), QStringLiteral()); + INSERT(UISettings, pause_when_in_background, tr("Pause emulation when in background"), + QStringLiteral()); + INSERT(UISettings, confirm_before_stopping, tr("Confirm before stopping emulation"), + QStringLiteral()); + INSERT(UISettings, hide_mouse, tr("Hide mouse on inactivity"), QStringLiteral()); + INSERT(UISettings, controller_applet_disabled, tr("Disable controller applet"), + QStringLiteral()); // Ui Debugging @@ -179,140 +194,141 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) { return parent->tr(text, context); }; -#define PAIR(ENUM, VALUE, TRANSLATION) \ - { static_cast<u32>(Settings::ENUM::VALUE), tr(TRANSLATION) } -#define CTX_PAIR(ENUM, VALUE, TRANSLATION, CONTEXT) \ - { static_cast<u32>(Settings::ENUM::VALUE), tr(TRANSLATION, CONTEXT) } +#define PAIR(ENUM, VALUE, TRANSLATION) {static_cast<u32>(Settings::ENUM::VALUE), (TRANSLATION)} // Intentionally skipping VSyncMode to let the UI fill that one out translations->insert({Settings::EnumMetadata<Settings::AstcDecodeMode>::Index(), { - PAIR(AstcDecodeMode, Cpu, "CPU"), - PAIR(AstcDecodeMode, Gpu, "GPU"), - PAIR(AstcDecodeMode, CpuAsynchronous, "CPU Asynchronous"), - }}); - translations->insert({Settings::EnumMetadata<Settings::AstcRecompression>::Index(), - { - PAIR(AstcRecompression, Uncompressed, "Uncompressed (Best quality)"), - PAIR(AstcRecompression, Bc1, "BC1 (Low quality)"), - PAIR(AstcRecompression, Bc3, "BC3 (Medium quality)"), + PAIR(AstcDecodeMode, Cpu, tr("CPU")), + PAIR(AstcDecodeMode, Gpu, tr("GPU")), + PAIR(AstcDecodeMode, CpuAsynchronous, tr("CPU Asynchronous")), }}); + translations->insert( + {Settings::EnumMetadata<Settings::AstcRecompression>::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<Settings::RendererBackend>::Index(), { #ifdef HAS_OPENGL - PAIR(RendererBackend, OpenGL, "OpenGL"), + PAIR(RendererBackend, OpenGL, tr("OpenGL")), #endif - PAIR(RendererBackend, Vulkan, "Vulkan"), - PAIR(RendererBackend, Null, "Null"), - }}); - translations->insert({Settings::EnumMetadata<Settings::ShaderBackend>::Index(), - { - PAIR(ShaderBackend, Glsl, "GLSL"), - PAIR(ShaderBackend, Glasm, "GLASM (Assembly Shaders, NVIDIA Only)"), - PAIR(ShaderBackend, SpirV, "SPIR-V (Experimental, Mesa Only)"), + PAIR(RendererBackend, Vulkan, tr("Vulkan")), + PAIR(RendererBackend, Null, tr("Null")), }}); + translations->insert( + {Settings::EnumMetadata<Settings::ShaderBackend>::Index(), + { + PAIR(ShaderBackend, Glsl, tr("GLSL")), + PAIR(ShaderBackend, Glasm, tr("GLASM (Assembly Shaders, NVIDIA Only)")), + PAIR(ShaderBackend, SpirV, tr("SPIR-V (Experimental, Mesa Only)")), + }}); translations->insert({Settings::EnumMetadata<Settings::GpuAccuracy>::Index(), { - PAIR(GpuAccuracy, Normal, "Normal"), - PAIR(GpuAccuracy, High, "High"), - PAIR(GpuAccuracy, Extreme, "Extreme"), - }}); - translations->insert({Settings::EnumMetadata<Settings::CpuAccuracy>::Index(), - { - PAIR(CpuAccuracy, Auto, "Auto"), - PAIR(CpuAccuracy, Accurate, "Accurate"), - PAIR(CpuAccuracy, Unsafe, "Unsafe"), - PAIR(CpuAccuracy, Paranoid, "Paranoid (disables most optimizations)"), + PAIR(GpuAccuracy, Normal, tr("Normal")), + PAIR(GpuAccuracy, High, tr("High")), + PAIR(GpuAccuracy, Extreme, tr("Extreme")), }}); + translations->insert( + {Settings::EnumMetadata<Settings::CpuAccuracy>::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<Settings::FullscreenMode>::Index(), { - PAIR(FullscreenMode, Borderless, "Borderless Windowed"), - PAIR(FullscreenMode, Exclusive, "Exclusive Fullscreen"), + PAIR(FullscreenMode, Borderless, tr("Borderless Windowed")), + PAIR(FullscreenMode, Exclusive, tr("Exclusive Fullscreen")), }}); translations->insert({Settings::EnumMetadata<Settings::NvdecEmulation>::Index(), { - PAIR(NvdecEmulation, Off, "No Video Output"), - PAIR(NvdecEmulation, Cpu, "CPU Video Decoding"), - PAIR(NvdecEmulation, Gpu, "GPU Video Decoding (Default)"), - }}); - translations->insert({Settings::EnumMetadata<Settings::ResolutionSetup>::Index(), - { - PAIR(ResolutionSetup, Res1_2X, "0.5X (360p/540p) [EXPERIMENTAL]"), - PAIR(ResolutionSetup, Res3_4X, "0.75X (540p/810p) [EXPERIMENTAL]"), - PAIR(ResolutionSetup, Res1X, "1X (720p/1080p)"), - PAIR(ResolutionSetup, Res3_2X, "1.5X (1080p/1620p) [EXPERIMENTAL]"), - PAIR(ResolutionSetup, Res2X, "2X (1440p/2160p)"), - PAIR(ResolutionSetup, Res3X, "3X (2160p/3240p)"), - PAIR(ResolutionSetup, Res4X, "4X (2880p/4320p)"), - PAIR(ResolutionSetup, Res5X, "5X (3600p/5400p)"), - PAIR(ResolutionSetup, Res6X, "6X (4320p/6480p)"), - PAIR(ResolutionSetup, Res7X, "7X (5040p/7560p)"), - PAIR(ResolutionSetup, Res8X, "8X (5760p/8640p)"), + 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<Settings::ResolutionSetup>::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<Settings::ScalingFilter>::Index(), { - PAIR(ScalingFilter, NearestNeighbor, "Nearest Neighbor"), - PAIR(ScalingFilter, Bilinear, "Bilinear"), - PAIR(ScalingFilter, Bicubic, "Bicubic"), - PAIR(ScalingFilter, Gaussian, "Gaussian"), - PAIR(ScalingFilter, ScaleForce, "ScaleForce"), - PAIR(ScalingFilter, Fsr, "AMD FidelityFX™️ Super Resolution"), + 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<Settings::AntiAliasing>::Index(), { - PAIR(AntiAliasing, None, "None"), - PAIR(AntiAliasing, Fxaa, "FXAA"), - PAIR(AntiAliasing, Smaa, "SMAA"), + PAIR(AntiAliasing, None, tr("None")), + PAIR(AntiAliasing, Fxaa, tr("FXAA")), + PAIR(AntiAliasing, Smaa, tr("SMAA")), }}); translations->insert({Settings::EnumMetadata<Settings::AspectRatio>::Index(), { - PAIR(AspectRatio, R16_9, "Default (16:9)"), - PAIR(AspectRatio, R4_3, "Force 4:3"), - PAIR(AspectRatio, R21_9, "Force 21:9"), - PAIR(AspectRatio, R16_10, "Force 16:10"), - PAIR(AspectRatio, Stretch, "Stretch to Window"), + 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<Settings::AnisotropyMode>::Index(), { - PAIR(AnisotropyMode, Automatic, "Automatic"), - PAIR(AnisotropyMode, Default, "Default"), - PAIR(AnisotropyMode, X2, "2x"), - PAIR(AnisotropyMode, X4, "4x"), - PAIR(AnisotropyMode, X8, "8x"), - PAIR(AnisotropyMode, X16, "16x"), + 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<Settings::Language>::Index(), { - PAIR(Language, Japanese, "Japanese (日本語)"), - PAIR(Language, EnglishAmerican, "American English"), - PAIR(Language, French, "French (français)"), - PAIR(Language, German, "German (Deutsch)"), - PAIR(Language, Italian, "Italian (italiano)"), - PAIR(Language, Spanish, "Spanish (español)"), - PAIR(Language, Chinese, "Chinese"), - PAIR(Language, Korean, "Korean (한국어)"), - PAIR(Language, Dutch, "Dutch (Nederlands)"), - PAIR(Language, Portuguese, "Portuguese (português)"), - PAIR(Language, Russian, "Russian (Русский)"), - PAIR(Language, Taiwanese, "Taiwanese"), - PAIR(Language, EnglishBritish, "British English"), - PAIR(Language, FrenchCanadian, "Canadian French"), - PAIR(Language, SpanishLatin, "Latin American Spanish"), - PAIR(Language, ChineseSimplified, "Simplified Chinese"), - PAIR(Language, ChineseTraditional, "Traditional Chinese (正體中文)"), - PAIR(Language, PortugueseBrazilian, "Brazilian Portuguese (português do Brasil)"), + 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<Settings::Region>::Index(), { - PAIR(Region, Japan, "Japan"), - PAIR(Region, Usa, "USA"), - PAIR(Region, Europe, "Europe"), - PAIR(Region, Australia, "Australia"), - PAIR(Region, China, "China"), - PAIR(Region, Korea, "Korea"), - PAIR(Region, Taiwan, "Taiwan"), + 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<Settings::TimeZone>::Index(), @@ -324,72 +340,74 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) { {static_cast<u32>(Settings::TimeZone::Default), tr("Default (%1)", "Default time zone") .arg(QString::fromStdString(Common::TimeZone::GetDefaultTimeZone()))}, - PAIR(TimeZone, Cet, "CET"), - PAIR(TimeZone, Cst6Cdt, "CST6CDT"), - PAIR(TimeZone, Cuba, "Cuba"), - PAIR(TimeZone, Eet, "EET"), - PAIR(TimeZone, Egypt, "Egypt"), - PAIR(TimeZone, Eire, "Eire"), - PAIR(TimeZone, Est, "EST"), - PAIR(TimeZone, Est5Edt, "EST5EDT"), - PAIR(TimeZone, Gb, "GB"), - PAIR(TimeZone, GbEire, "GB-Eire"), - PAIR(TimeZone, Gmt, "GMT"), - PAIR(TimeZone, GmtPlusZero, "GMT+0"), - PAIR(TimeZone, GmtMinusZero, "GMT-0"), - PAIR(TimeZone, GmtZero, "GMT0"), - PAIR(TimeZone, Greenwich, "Greenwich"), - PAIR(TimeZone, Hongkong, "Hongkong"), - PAIR(TimeZone, Hst, "HST"), - PAIR(TimeZone, Iceland, "Iceland"), - PAIR(TimeZone, Iran, "Iran"), - PAIR(TimeZone, Israel, "Israel"), - PAIR(TimeZone, Jamaica, "Jamaica"), - PAIR(TimeZone, Japan, "Japan"), - PAIR(TimeZone, Kwajalein, "Kwajalein"), - PAIR(TimeZone, Libya, "Libya"), - PAIR(TimeZone, Met, "MET"), - PAIR(TimeZone, Mst, "MST"), - PAIR(TimeZone, Mst7Mdt, "MST7MDT"), - PAIR(TimeZone, Navajo, "Navajo"), - PAIR(TimeZone, Nz, "NZ"), - PAIR(TimeZone, NzChat, "NZ-CHAT"), - PAIR(TimeZone, Poland, "Poland"), - PAIR(TimeZone, Portugal, "Portugal"), - PAIR(TimeZone, Prc, "PRC"), - PAIR(TimeZone, Pst8Pdt, "PST8PDT"), - PAIR(TimeZone, Roc, "ROC"), - PAIR(TimeZone, Rok, "ROK"), - PAIR(TimeZone, Singapore, "Singapore"), - PAIR(TimeZone, Turkey, "Turkey"), - PAIR(TimeZone, Uct, "UCT"), - PAIR(TimeZone, Universal, "Universal"), - PAIR(TimeZone, Utc, "UTC"), - PAIR(TimeZone, WSu, "W-SU"), - PAIR(TimeZone, Wet, "WET"), - PAIR(TimeZone, Zulu, "Zulu"), + 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<Settings::AudioMode>::Index(), { - PAIR(AudioMode, Mono, "Mono"), - PAIR(AudioMode, Stereo, "Stereo"), - PAIR(AudioMode, Surround, "Surround"), + PAIR(AudioMode, Mono, tr("Mono")), + PAIR(AudioMode, Stereo, tr("Stereo")), + PAIR(AudioMode, Surround, tr("Surround")), }}); translations->insert({Settings::EnumMetadata<Settings::MemoryLayout>::Index(), { - PAIR(MemoryLayout, Memory_4Gb, "4GB DRAM (Default)"), - PAIR(MemoryLayout, Memory_6Gb, "6GB DRAM (Unsafe)"), - PAIR(MemoryLayout, Memory_8Gb, "8GB DRAM (Unsafe)"), + PAIR(MemoryLayout, Memory_4Gb, tr("4GB DRAM (Default)")), + PAIR(MemoryLayout, Memory_6Gb, tr("6GB DRAM (Unsafe)")), + PAIR(MemoryLayout, Memory_8Gb, tr("8GB DRAM (Unsafe)")), + }}); + translations->insert({Settings::EnumMetadata<Settings::ConsoleMode>::Index(), + { + PAIR(ConsoleMode, Docked, tr("Docked")), + PAIR(ConsoleMode, Handheld, tr("Handheld")), }}); - translations->insert( - {Settings::EnumMetadata<Settings::ConsoleMode>::Index(), - {PAIR(ConsoleMode, Docked, "Docked"), PAIR(ConsoleMode, Handheld, "Handheld")}}); translations->insert( {Settings::EnumMetadata<Settings::ConfirmStop>::Index(), { - PAIR(ConfirmStop, Ask_Always, "Always ask (Default)"), - PAIR(ConfirmStop, Ask_Based_On_Game, "Only if game specifies not to stop"), - PAIR(ConfirmStop, Ask_Never, "Never ask"), + 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 diff --git a/src/yuzu/configuration/shared_translation.h b/src/yuzu/configuration/shared_translation.h index 99a0e808c..d5fc3b8de 100644 --- a/src/yuzu/configuration/shared_translation.h +++ b/src/yuzu/configuration/shared_translation.h @@ -10,6 +10,7 @@ #include <vector> #include <QString> #include "common/common_types.h" +#include "common/settings.h" class QWidget; @@ -22,4 +23,46 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent); std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent); +static const std::map<Settings::AntiAliasing, QString> 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<Settings::ScalingFilter, QString> 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<Settings::ConsoleMode, QString> 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<Settings::GpuAccuracy, QString> 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<Settings::RendererBackend, QString> 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<Settings::ShaderBackend, QString> 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/yuzu/configuration/shared_widget.cpp b/src/yuzu/configuration/shared_widget.cpp index ea8d7add4..941683a43 100644 --- a/src/yuzu/configuration/shared_widget.cpp +++ b/src/yuzu/configuration/shared_widget.cpp @@ -194,7 +194,7 @@ QWidget* Widget::CreateRadioGroup(std::function<std::string()>& serializer, return group; } - const auto get_selected = [=]() -> int { + const auto get_selected = [this]() -> int { for (const auto& [id, button] : radio_buttons) { if (button->isChecked()) { return id; @@ -203,7 +203,7 @@ QWidget* Widget::CreateRadioGroup(std::function<std::string()>& serializer, return -1; }; - const auto set_index = [=](u32 value) { + const auto set_index = [this](u32 value) { for (const auto& [id, button] : radio_buttons) { button->setChecked(id == value); } diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 7049c57b6..6d227ef8d 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -36,10 +36,8 @@ constexpr std::array<std::array<Qt::GlobalColor, 2>, 10> WaitTreeColors{{ bool IsDarkTheme() { const auto& theme = UISettings::values.theme; - return theme == QStringLiteral("qdarkstyle") || - theme == QStringLiteral("qdarkstyle_midnight_blue") || - theme == QStringLiteral("colorful_dark") || - theme == QStringLiteral("colorful_midnight_blue"); + return theme == std::string("qdarkstyle") || theme == std::string("qdarkstyle_midnight_blue") || + theme == std::string("colorful_dark") || theme == std::string("colorful_midnight_blue"); } } // namespace diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 7e7d8e252..59b317135 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -278,7 +278,7 @@ void GameList::OnUpdateThemedIcons() { case GameListItemType::CustomDir: { const UISettings::GameDir& game_dir = UISettings::values.game_dirs[child->data(GameListDir::GameDirRole).toInt()]; - const QString icon_name = QFileInfo::exists(game_dir.path) + const QString icon_name = QFileInfo::exists(QString::fromStdString(game_dir.path)) ? QStringLiteral("folder") : QStringLiteral("bad_folder"); child->setData( @@ -567,9 +567,10 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri QAction* verify_integrity = context_menu.addAction(tr("Verify Integrity")); QAction* copy_tid = context_menu.addAction(tr("Copy Title ID to Clipboard")); QAction* navigate_to_gamedb_entry = context_menu.addAction(tr("Navigate to GameDB entry")); +// TODO: Implement shortcut creation for macOS +#if !defined(__APPLE__) QMenu* shortcut_menu = context_menu.addMenu(tr("Create Shortcut")); QAction* create_desktop_shortcut = shortcut_menu->addAction(tr("Add to Desktop")); -#ifndef WIN32 QAction* create_applications_menu_shortcut = shortcut_menu->addAction(tr("Add to Applications Menu")); #endif @@ -647,10 +648,11 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri connect(navigate_to_gamedb_entry, &QAction::triggered, [this, program_id]() { emit NavigateToGamedbEntryRequested(program_id, compatibility_list); }); +// 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); }); -#ifndef WIN32 connect(create_applications_menu_shortcut, &QAction::triggered, [this, program_id, path]() { emit CreateShortcut(program_id, path, GameListShortcutTarget::Applications); }); @@ -725,7 +727,8 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) { }); connect(open_directory_location, &QAction::triggered, [this, game_dir_index] { - emit OpenDirectory(UISettings::values.game_dirs[game_dir_index].path); + emit OpenDirectory( + QString::fromStdString(UISettings::values.game_dirs[game_dir_index].path)); }); } @@ -867,7 +870,7 @@ const QStringList GameList::supported_file_extensions = { QStringLiteral("xci"), QStringLiteral("nsp"), QStringLiteral("kip")}; void GameList::RefreshGameDirectory() { - if (!UISettings::values.game_dirs.isEmpty() && current_worker != nullptr) { + if (!UISettings::values.game_dirs.empty() && current_worker != nullptr) { LOG_INFO(Frontend, "Change detected in the games directory. Reloading game list."); PopulateAsync(UISettings::values.game_dirs); } diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index 86a0c41d9..c330b574f 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h @@ -286,13 +286,13 @@ public: setData(QObject::tr("System Titles"), Qt::DisplayRole); break; case GameListItemType::CustomDir: { - const QString icon_name = QFileInfo::exists(game_dir->path) - ? QStringLiteral("folder") - : QStringLiteral("bad_folder"); + const QString path = QString::fromStdString(game_dir->path); + const QString icon_name = + QFileInfo::exists(path) ? QStringLiteral("folder") : QStringLiteral("bad_folder"); setData(QIcon::fromTheme(icon_name).pixmap(icon_size).scaled( icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::DecorationRole); - setData(game_dir->path, Qt::DisplayRole); + setData(path, Qt::DisplayRole); break; } default: diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp index 69be21027..dc006832e 100644 --- a/src/yuzu/game_list_worker.cpp +++ b/src/yuzu/game_list_worker.cpp @@ -456,29 +456,29 @@ void GameListWorker::run() { break; } - if (game_dir.path == QStringLiteral("SDMC")) { + if (game_dir.path == std::string("SDMC")) { auto* const game_list_dir = new GameListDir(game_dir, GameListItemType::SdmcDir); DirEntryReady(game_list_dir); AddTitlesToGameList(game_list_dir); - } else if (game_dir.path == QStringLiteral("UserNAND")) { + } else if (game_dir.path == std::string("UserNAND")) { auto* const game_list_dir = new GameListDir(game_dir, GameListItemType::UserNandDir); DirEntryReady(game_list_dir); AddTitlesToGameList(game_list_dir); - } else if (game_dir.path == QStringLiteral("SysNAND")) { + } else if (game_dir.path == std::string("SysNAND")) { auto* const game_list_dir = new GameListDir(game_dir, GameListItemType::SysNandDir); DirEntryReady(game_list_dir); AddTitlesToGameList(game_list_dir); } else { - watch_list.append(game_dir.path); + watch_list.append(QString::fromStdString(game_dir.path)); auto* const game_list_dir = new GameListDir(game_dir); DirEntryReady(game_list_dir); - ScanFileSystem(ScanTarget::FillManualContentProvider, game_dir.path.toStdString(), - game_dir.deep_scan, game_list_dir); - ScanFileSystem(ScanTarget::PopulateGameList, game_dir.path.toStdString(), - game_dir.deep_scan, game_list_dir); + ScanFileSystem(ScanTarget::FillManualContentProvider, game_dir.path, game_dir.deep_scan, + game_list_dir); + ScanFileSystem(ScanTarget::PopulateGameList, game_dir.path, game_dir.deep_scan, + game_list_dir); } } - RecordEvent([=](GameList* game_list) { game_list->DonePopulating(watch_list); }); + RecordEvent([this](GameList* game_list) { game_list->DonePopulating(watch_list); }); processing_completed.Set(); } diff --git a/src/yuzu/hotkeys.cpp b/src/yuzu/hotkeys.cpp index 6530186c1..eebfbf155 100644 --- a/src/yuzu/hotkeys.cpp +++ b/src/yuzu/hotkeys.cpp @@ -19,7 +19,7 @@ void HotkeyRegistry::SaveHotkeys() { for (const auto& hotkey : group.second) { UISettings::values.shortcuts.push_back( {hotkey.first, group.first, - UISettings::ContextualShortcut({hotkey.second.keyseq.toString(), + UISettings::ContextualShortcut({hotkey.second.keyseq.toString().toStdString(), hotkey.second.controller_keyseq, hotkey.second.context, hotkey.second.repeat})}); } @@ -31,12 +31,12 @@ void HotkeyRegistry::LoadHotkeys() { // beginGroup() for (auto shortcut : UISettings::values.shortcuts) { Hotkey& hk = hotkey_groups[shortcut.group][shortcut.name]; - if (!shortcut.shortcut.keyseq.isEmpty()) { - hk.keyseq = - QKeySequence::fromString(shortcut.shortcut.keyseq, QKeySequence::NativeText); + if (!shortcut.shortcut.keyseq.empty()) { + hk.keyseq = QKeySequence::fromString(QString::fromStdString(shortcut.shortcut.keyseq), + QKeySequence::NativeText); hk.context = static_cast<Qt::ShortcutContext>(shortcut.shortcut.context); } - if (!shortcut.shortcut.controller_keyseq.isEmpty()) { + if (!shortcut.shortcut.controller_keyseq.empty()) { hk.controller_keyseq = shortcut.shortcut.controller_keyseq; } if (hk.shortcut) { @@ -51,7 +51,8 @@ void HotkeyRegistry::LoadHotkeys() { } } -QShortcut* HotkeyRegistry::GetHotkey(const QString& group, const QString& action, QWidget* widget) { +QShortcut* HotkeyRegistry::GetHotkey(const std::string& group, const std::string& action, + QWidget* widget) { Hotkey& hk = hotkey_groups[group][action]; if (!hk.shortcut) { @@ -62,7 +63,8 @@ QShortcut* HotkeyRegistry::GetHotkey(const QString& group, const QString& action return hk.shortcut; } -ControllerShortcut* HotkeyRegistry::GetControllerHotkey(const QString& group, const QString& action, +ControllerShortcut* HotkeyRegistry::GetControllerHotkey(const std::string& group, + const std::string& action, Core::HID::EmulatedController* controller) { Hotkey& hk = hotkey_groups[group][action]; @@ -74,12 +76,12 @@ ControllerShortcut* HotkeyRegistry::GetControllerHotkey(const QString& group, co return hk.controller_shortcut; } -QKeySequence HotkeyRegistry::GetKeySequence(const QString& group, const QString& action) { +QKeySequence HotkeyRegistry::GetKeySequence(const std::string& group, const std::string& action) { return hotkey_groups[group][action].keyseq; } -Qt::ShortcutContext HotkeyRegistry::GetShortcutContext(const QString& group, - const QString& action) { +Qt::ShortcutContext HotkeyRegistry::GetShortcutContext(const std::string& group, + const std::string& action) { return hotkey_groups[group][action].context; } @@ -101,10 +103,10 @@ void ControllerShortcut::SetKey(const ControllerButtonSequence& buttons) { button_sequence = buttons; } -void ControllerShortcut::SetKey(const QString& buttons_shortcut) { +void ControllerShortcut::SetKey(const std::string& buttons_shortcut) { ControllerButtonSequence sequence{}; - name = buttons_shortcut.toStdString(); - std::istringstream command_line(buttons_shortcut.toStdString()); + name = buttons_shortcut; + std::istringstream command_line(buttons_shortcut); std::string line; while (std::getline(command_line, line, '+')) { if (line.empty()) { diff --git a/src/yuzu/hotkeys.h b/src/yuzu/hotkeys.h index 56eee8d82..e11332d2e 100644 --- a/src/yuzu/hotkeys.h +++ b/src/yuzu/hotkeys.h @@ -33,7 +33,7 @@ public: ~ControllerShortcut(); void SetKey(const ControllerButtonSequence& buttons); - void SetKey(const QString& buttons_shortcut); + void SetKey(const std::string& buttons_shortcut); ControllerButtonSequence ButtonSequence() const; @@ -88,8 +88,8 @@ public: * will be the same. Thus, you shouldn't rely on the caller really being the * QShortcut's parent. */ - QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widget); - ControllerShortcut* GetControllerHotkey(const QString& group, const QString& action, + QShortcut* GetHotkey(const std::string& group, const std::string& action, QWidget* widget); + ControllerShortcut* GetControllerHotkey(const std::string& group, const std::string& action, Core::HID::EmulatedController* controller); /** @@ -98,7 +98,7 @@ public: * @param group General group this hotkey belongs to (e.g. "Main Window", "Debugger"). * @param action Name of the action (e.g. "Start Emulation", "Load Image"). */ - QKeySequence GetKeySequence(const QString& group, const QString& action); + QKeySequence GetKeySequence(const std::string& group, const std::string& action); /** * Returns a Qt::ShortcutContext object who can be connected to other @@ -108,20 +108,20 @@ public: * "Debugger"). * @param action Name of the action (e.g. "Start Emulation", "Load Image"). */ - Qt::ShortcutContext GetShortcutContext(const QString& group, const QString& action); + Qt::ShortcutContext GetShortcutContext(const std::string& group, const std::string& action); private: struct Hotkey { QKeySequence keyseq; - QString controller_keyseq; + std::string controller_keyseq; QShortcut* shortcut = nullptr; ControllerShortcut* controller_shortcut = nullptr; Qt::ShortcutContext context = Qt::WindowShortcut; bool repeat; }; - using HotkeyMap = std::map<QString, Hotkey>; - using HotkeyGroupMap = std::map<QString, HotkeyMap>; + using HotkeyMap = std::map<std::string, Hotkey>; + using HotkeyGroupMap = std::map<std::string, HotkeyMap>; HotkeyGroupMap hotkey_groups; }; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 0df163029..dcf68460a 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -10,6 +10,7 @@ #include <thread> #include "core/loader/nca.h" #include "core/tools/renderdoc.h" + #ifdef __APPLE__ #include <unistd.h> // for chdir #endif @@ -46,6 +47,7 @@ #include "core/hle/service/am/applet_ae.h" #include "core/hle/service/am/applet_oe.h" #include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/set/set_sys.h" #include "yuzu/multiplayer/state.h" #include "yuzu/util/controller_navigation.h" @@ -127,6 +129,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "core/loader/loader.h" #include "core/perf_stats.h" #include "core/telemetry_session.h" +#include "frontend_common/config.h" #include "input_common/drivers/tas_input.h" #include "input_common/drivers/virtual_amiibo.h" #include "input_common/main.h" @@ -139,9 +142,9 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "yuzu/bootmanager.h" #include "yuzu/compatdb.h" #include "yuzu/compatibility_list.h" -#include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_dialog.h" #include "yuzu/configuration/configure_input_per_game.h" +#include "yuzu/configuration/qt_config.h" #include "yuzu/debugger/console.h" #include "yuzu/debugger/controller.h" #include "yuzu/debugger/profiler.h" @@ -310,7 +313,7 @@ bool GMainWindow::CheckDarkMode() { #endif // __unix__ } -GMainWindow::GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan) +GMainWindow::GMainWindow(std::unique_ptr<QtConfig> config_, bool has_broken_vulkan) : ui{std::make_unique<Ui::MainWindow>()}, system{std::make_unique<Core::System>()}, input_subsystem{std::make_shared<InputCommon::InputSubsystem>()}, config{std::move(config_)}, vfs{std::make_shared<FileSys::RealVfsFilesystem>()}, @@ -675,7 +678,7 @@ void GMainWindow::ControllerSelectorReconfigureControllers( // Don't forget to apply settings. system->HIDCore().DisableAllControllerConfiguration(); system->ApplySettings(); - config->Save(); + config->SaveAllValues(); UpdateStatusButtons(); @@ -1046,7 +1049,12 @@ void GMainWindow::InitializeWidgets() { statusBar()->addPermanentWidget(label); } - // TODO (flTobi): Add the widget when multiplayer is fully implemented + firmware_label = new QLabel(); + firmware_label->setObjectName(QStringLiteral("FirmwareLabel")); + firmware_label->setVisible(false); + firmware_label->setFocusPolicy(Qt::NoFocus); + statusBar()->addPermanentWidget(firmware_label); + statusBar()->addPermanentWidget(multiplayer_state->GetStatusText(), 0); statusBar()->addPermanentWidget(multiplayer_state->GetStatusIcon(), 0); @@ -1064,12 +1072,6 @@ void GMainWindow::InitializeWidgets() { volume_slider->setObjectName(QStringLiteral("volume_slider")); volume_slider->setMaximum(200); volume_slider->setPageStep(5); - connect(volume_slider, &QSlider::valueChanged, this, [this](int percentage) { - Settings::values.audio_muted = false; - const auto volume = static_cast<u8>(percentage); - Settings::values.volume.SetValue(volume); - UpdateVolumeUI(); - }); volume_popup->layout()->addWidget(volume_slider); volume_button = new VolumeButton(); @@ -1077,6 +1079,12 @@ void GMainWindow::InitializeWidgets() { volume_button->setFocusPolicy(Qt::NoFocus); volume_button->setCheckable(true); UpdateVolumeUI(); + connect(volume_slider, &QSlider::valueChanged, this, [this](int percentage) { + Settings::values.audio_muted = false; + const auto volume = static_cast<u8>(percentage); + Settings::values.volume.SetValue(volume); + UpdateVolumeUI(); + }); connect(volume_button, &QPushButton::clicked, this, [&] { UpdateVolumeUI(); volume_popup->setVisible(!volume_popup->isVisible()); @@ -1128,7 +1136,7 @@ void GMainWindow::InitializeWidgets() { connect(aa_status_button, &QPushButton::customContextMenuRequested, [this](const QPoint& menu_location) { QMenu context_menu; - for (auto const& aa_text_pair : Config::anti_aliasing_texts_map) { + for (auto const& aa_text_pair : ConfigurationShared::anti_aliasing_texts_map) { context_menu.addAction(aa_text_pair.second, [this, aa_text_pair] { Settings::values.anti_aliasing.SetValue(aa_text_pair.first); UpdateAAText(); @@ -1152,7 +1160,7 @@ void GMainWindow::InitializeWidgets() { connect(filter_status_button, &QPushButton::customContextMenuRequested, [this](const QPoint& menu_location) { QMenu context_menu; - for (auto const& filter_text_pair : Config::scaling_filter_texts_map) { + for (auto const& filter_text_pair : ConfigurationShared::scaling_filter_texts_map) { context_menu.addAction(filter_text_pair.second, [this, filter_text_pair] { Settings::values.scaling_filter.SetValue(filter_text_pair.first); UpdateFilterText(); @@ -1175,7 +1183,7 @@ void GMainWindow::InitializeWidgets() { [this](const QPoint& menu_location) { QMenu context_menu; - for (auto const& pair : Config::use_docked_mode_texts_map) { + for (auto const& pair : ConfigurationShared::use_docked_mode_texts_map) { context_menu.addAction(pair.second, [this, &pair] { if (pair.first != Settings::values.use_docked_mode.GetValue()) { OnToggleDockedMode(); @@ -1199,7 +1207,7 @@ void GMainWindow::InitializeWidgets() { [this](const QPoint& menu_location) { QMenu context_menu; - for (auto const& gpu_accuracy_pair : Config::gpu_accuracy_texts_map) { + for (auto const& gpu_accuracy_pair : ConfigurationShared::gpu_accuracy_texts_map) { if (gpu_accuracy_pair.first == Settings::GpuAccuracy::Extreme) { continue; } @@ -1228,7 +1236,8 @@ void GMainWindow::InitializeWidgets() { [this](const QPoint& menu_location) { QMenu context_menu; - for (auto const& renderer_backend_pair : Config::renderer_backend_texts_map) { + for (auto const& renderer_backend_pair : + ConfigurationShared::renderer_backend_texts_map) { if (renderer_backend_pair.first == Settings::RendererBackend::Null) { continue; } @@ -1293,16 +1302,17 @@ void GMainWindow::InitializeRecentFileMenuActions() { void GMainWindow::LinkActionShortcut(QAction* action, const QString& action_name, const bool tas_allowed) { - static const QString main_window = QStringLiteral("Main Window"); - action->setShortcut(hotkey_registry.GetKeySequence(main_window, action_name)); - action->setShortcutContext(hotkey_registry.GetShortcutContext(main_window, action_name)); + static const auto main_window = std::string("Main Window"); + action->setShortcut(hotkey_registry.GetKeySequence(main_window, action_name.toStdString())); + action->setShortcutContext( + hotkey_registry.GetShortcutContext(main_window, action_name.toStdString())); action->setAutoRepeat(false); this->addAction(action); auto* controller = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); const auto* controller_hotkey = - hotkey_registry.GetControllerHotkey(main_window, action_name, controller); + hotkey_registry.GetControllerHotkey(main_window, action_name.toStdString(), controller); connect( controller_hotkey, &ControllerShortcut::Activated, this, [action, tas_allowed, this] { @@ -1334,10 +1344,11 @@ void GMainWindow::InitializeHotkeys() { static const QString main_window = QStringLiteral("Main Window"); const auto connect_shortcut = [&]<typename Fn>(const QString& action_name, const Fn& function) { - const auto* hotkey = hotkey_registry.GetHotkey(main_window, action_name, this); + const auto* hotkey = + hotkey_registry.GetHotkey(main_window.toStdString(), action_name.toStdString(), this); auto* controller = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); - const auto* controller_hotkey = - hotkey_registry.GetControllerHotkey(main_window, action_name, controller); + const auto* controller_hotkey = hotkey_registry.GetControllerHotkey( + main_window.toStdString(), action_name.toStdString(), controller); connect(hotkey, &QShortcut::activated, this, function); connect(controller_hotkey, &ControllerShortcut::Activated, this, function, Qt::QueuedConnection); @@ -1574,6 +1585,7 @@ void GMainWindow::ConnectMenuEvents() { connect_menu(ui->action_Load_Cabinet_Formatter, [this]() { OnCabinet(Service::NFP::CabinetMode::StartFormatter); }); connect_menu(ui->action_Load_Mii_Edit, &GMainWindow::OnMiiEdit); + connect_menu(ui->action_Open_Controller_Menu, &GMainWindow::OnOpenControllerMenu); connect_menu(ui->action_Capture_Screenshot, &GMainWindow::OnCaptureScreenshot); // TAS @@ -1601,14 +1613,13 @@ void GMainWindow::UpdateMenuState() { ui->action_Pause, }; - const std::array applet_actions{ - ui->action_Load_Album, - ui->action_Load_Cabinet_Nickname_Owner, - ui->action_Load_Cabinet_Eraser, - ui->action_Load_Cabinet_Restorer, - ui->action_Load_Cabinet_Formatter, - ui->action_Load_Mii_Edit, - }; + const std::array applet_actions{ui->action_Load_Album, + ui->action_Load_Cabinet_Nickname_Owner, + ui->action_Load_Cabinet_Eraser, + ui->action_Load_Cabinet_Restorer, + ui->action_Load_Cabinet_Formatter, + ui->action_Load_Mii_Edit, + ui->action_Open_Controller_Menu}; for (QAction* action : running_actions) { action->setEnabled(emulation_running); @@ -1908,12 +1919,16 @@ void GMainWindow::ConfigureFilesystemProvider(const std::string& filepath) { void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t program_index, StartGameType type, AmLaunchType launch_type) { LOG_INFO(Frontend, "yuzu starting..."); - StoreRecentFile(filename); // Put the filename on top of the list + + if (program_id == 0 || + program_id > static_cast<u64>(Service::AM::Applets::AppletProgramId::MaxProgramId)) { + StoreRecentFile(filename); // Put the filename on top of the list + } // Save configurations UpdateUISettings(); game_list->SaveInterfaceLayout(); - config->Save(); + config->SaveAllValues(); u64 title_id{0}; @@ -1931,7 +1946,7 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t const auto config_file_name = title_id == 0 ? Common::FS::PathToUTF8String(file_path.filename()) : fmt::format("{:016X}", title_id); - Config per_game_config(config_file_name, Config::ConfigType::PerGameConfig); + QtConfig per_game_config(config_file_name, Config::ConfigType::PerGameConfig); system->HIDCore().ReloadInputDevices(); system->ApplySettings(); } @@ -2156,6 +2171,10 @@ void GMainWindow::OnEmulationStopped() { emu_frametime_label->setVisible(false); renderer_status_button->setEnabled(!UISettings::values.has_broken_vulkan); + if (!firmware_label->text().isEmpty()) { + firmware_label->setVisible(true); + } + current_game_path.clear(); // When closing the game, destroy the GLWindow to clear the context after the game is closed @@ -2174,6 +2193,7 @@ void GMainWindow::ShutdownGame() { return; } + play_time_manager->Stop(); OnShutdownBegin(); OnEmulationStopTimeExpired(); OnEmulationStopped(); @@ -2737,7 +2757,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa return; } - const auto extracted = FileSys::ExtractRomFS(romfs, FileSys::RomFSExtractionType::Full); + const auto extracted = FileSys::ExtractRomFS(romfs); if (extracted == nullptr) { failed(); return; @@ -2842,170 +2862,259 @@ void GMainWindow::OnGameListNavigateToGamedbEntry(u64 program_id, QDesktopServices::openUrl(QUrl(QStringLiteral("https://yuzu-emu.org/game/") + directory)); } -void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path, - GameListShortcutTarget target) { - // Get path to yuzu executable - const QStringList args = QApplication::arguments(); - std::filesystem::path yuzu_command = args[0].toStdString(); - - // If relative path, make it an absolute path - if (yuzu_command.c_str()[0] == '.') { - yuzu_command = Common::FS::GetCurrentDir() / yuzu_command; +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 { +#if defined(__linux__) || defined(__FreeBSD__) // Linux and FreeBSD + 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; } - -#if defined(__linux__) - // Warn once if we are making a shortcut to a volatile AppImage - const std::string appimage_ending = - std::string(Common::g_scm_rev).substr(0, 9).append(".AppImage"); - if (yuzu_command.string().ends_with(appimage_ending) && - !UISettings::values.shortcut_already_warned) { - if (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?"), - QMessageBox::StandardButton::Ok | - QMessageBox::StandardButton::Cancel) == - QMessageBox::StandardButton::Cancel) { - return; + // 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; +#elif defined(_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(); } - UISettings::values.shortcut_already_warned = true; + if (ps1 != nullptr) { + ps1->Release(); + } + }); + HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW, + reinterpret_cast<void**>(&ps1)); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to create IShellLinkW instance"); + return false; } -#endif // __linux__ - - std::filesystem::path target_directory{}; - - switch (target) { - case GameListShortcutTarget::Desktop: { - const QString desktop_path = - QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); - target_directory = desktop_path.toUtf8().toStdString(); - break; + hres = ps1->SetPath(command.c_str()); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to set path"); + return false; } - case GameListShortcutTarget::Applications: { - const QString applications_path = - QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation); - if (applications_path.isEmpty()) { - const char* home = std::getenv("HOME"); - if (home != nullptr) { - target_directory = std::filesystem::path(home) / ".local/share/applications"; - } - } else { - target_directory = applications_path.toUtf8().toStdString(); + if (!arguments.empty()) { + hres = ps1->SetArguments(Common::UTF8ToUTF16W(arguments).data()); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to set arguments"); + return false; } - break; } - default: - return; + if (!comment.empty()) { + hres = ps1->SetDescription(Common::UTF8ToUTF16W(comment).data()); + if (FAILED(hres)) { + LOG_ERROR(Frontend, "Failed to set description"); + return false; + } } - - const QDir dir(QString::fromStdString(target_directory.generic_string())); - if (!dir.exists()) { - QMessageBox::critical(this, tr("Create Shortcut"), - tr("Cannot create shortcut. Path \"%1\" does not exist.") - .arg(QString::fromStdString(target_directory.generic_string())), - QMessageBox::StandardButton::Ok); - return; + 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<void**>(&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; +#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 +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; + } +} - const std::string game_file_name = std::filesystem::path(game_path).filename().string(); - // Determine full paths for icon and shortcut -#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) - const char* home = std::getenv("HOME"); - const std::filesystem::path home_path = (home == nullptr ? "~" : home); - const char* xdg_data_home = std::getenv("XDG_DATA_HOME"); - - std::filesystem::path system_icons_path = - (xdg_data_home == nullptr ? home_path / ".local/share/" - : std::filesystem::path(xdg_data_home)) / - "icons/hicolor/256x256"; - if (!Common::FS::CreateDirs(system_icons_path)) { +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::GetYuzuPath(Common::FS::YuzuPath::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)) { QMessageBox::critical( this, tr("Create Icon"), tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.") - .arg(QString::fromStdString(system_icons_path)), + .arg(QString::fromStdString(out_icon_path.string())), QMessageBox::StandardButton::Ok); - return; + out_icon_path.clear(); + return false; } - std::filesystem::path icon_path = - system_icons_path / (program_id == 0 ? fmt::format("yuzu-{}.png", game_file_name) - : fmt::format("yuzu-{:016X}.png", program_id)); - const std::filesystem::path shortcut_path = - target_directory / (program_id == 0 ? fmt::format("yuzu-{}.desktop", game_file_name) - : fmt::format("yuzu-{:016X}.desktop", program_id)); -#elif defined(WIN32) - std::filesystem::path icons_path = - Common::FS::GetYuzuPathString(Common::FS::YuzuPath::IconsDir); - std::filesystem::path icon_path = - icons_path / ((program_id == 0 ? fmt::format("yuzu-{}.ico", game_file_name) - : fmt::format("yuzu-{:016X}.ico", program_id))); -#else - std::string icon_extension; -#endif - - // Get title from game file - const FileSys::PatchManager pm{program_id, system->GetFileSystemController(), - system->GetContentProvider()}; - const auto control = pm.GetControlMetadata(); - const auto loader = Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::Mode::Read)); - std::string title{fmt::format("{:016X}", program_id)}; - - if (control.first != nullptr) { - title = control.first->GetApplicationName(); - } else { - loader->ReadTitle(title); - } + // Create icon file path + out_icon_path /= (program_id == 0 ? fmt::format("yuzu-{}.{}", game_file_name, ico_extension) + : fmt::format("yuzu-{:016X}.{}", program_id, ico_extension)); + return true; +} - // Get icon from game file - std::vector<u8> 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); +void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path, + GameListShortcutTarget target) { + std::string game_title; + QString qt_game_title; + std::filesystem::path out_icon_path; + // Get path to yuzu executable + const QStringList args = QApplication::arguments(); + std::filesystem::path yuzu_command = args[0].toStdString(); + // If relative path, make it an absolute path + if (yuzu_command.c_str()[0] == '.') { + yuzu_command = Common::FS::GetCurrentDir() / yuzu_command; } - - QImage icon_data = - QImage::fromData(icon_image_file.data(), static_cast<int>(icon_image_file.size())); -#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) - // Convert and write the icon as a PNG - if (!icon_data.save(QString::fromStdString(icon_path.string()))) { - LOG_ERROR(Frontend, "Could not write icon as PNG to file"); + // Shortcut path + 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(); + } + // Icon path and title + if (std::filesystem::exists(shortcut_path)) { + // Get title from game file + const FileSys::PatchManager pm{program_id, system->GetFileSystemController(), + system->GetContentProvider()}; + const auto control = pm.GetControlMetadata(); + const auto loader = + Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::Mode::Read)); + game_title = fmt::format("{:016X}", program_id); + if (control.first != nullptr) { + game_title = control.first->GetApplicationName(); + } else { + loader->ReadTitle(game_title); + } + // Delete illegal characters from 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); + } + } + qt_game_title = QString::fromStdString(game_title); + // Get icon from game file + std::vector<u8> 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<int>(icon_image_file.size())); + if (GMainWindow::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 { - LOG_INFO(Frontend, "Wrote an icon to {}", icon_path.string()); - } -#elif defined(WIN32) - if (!SaveIconToFile(icon_path.string(), icon_data)) { - LOG_ERROR(Frontend, "Could not write icon to file"); + GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR, + qt_game_title); + LOG_ERROR(Frontend, "Invalid shortcut target"); return; } +#if defined(__linux__) + // Special case for AppImages + // Warn once if we are making a shortcut to a volatile AppImage + const std::string appimage_ending = + std::string(Common::g_scm_rev).substr(0, 9).append(".AppImage"); + if (yuzu_command.string().ends_with(appimage_ending) && + !UISettings::values.shortcut_already_warned) { + if (GMainWindow::CreateShortcutMessagesGUI( + this, GMainWindow::CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING, qt_game_title)) { + return; + } + UISettings::values.shortcut_already_warned = true; + } #endif // __linux__ - -#ifdef _WIN32 - // Replace characters that are illegal in Windows filenames by a dash - const std::string illegal_chars = "<>:\"/\\|?*"; - for (char c : illegal_chars) { - std::replace(title.begin(), title.end(), c, '_'); + // Create shortcut + std::string arguments = fmt::format("-g \"{:s}\"", game_path); + if (GMainWindow::CreateShortcutMessagesGUI( + this, GMainWindow::CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, qt_game_title)) { + arguments = "-f " + arguments; } - const std::filesystem::path shortcut_path = target_directory / (title + ".lnk").c_str(); -#endif - - const std::string comment = - tr("Start %1 with the yuzu Emulator").arg(QString::fromStdString(title)).toStdString(); - const std::string arguments = fmt::format("-g \"{:s}\"", game_path); + const std::string comment = fmt::format("Start {:s} with the yuzu Emulator", game_title); const std::string categories = "Game;Emulator;Qt;"; const std::string keywords = "Switch;Nintendo;"; - if (!CreateShortcut(shortcut_path.string(), title, comment, icon_path.string(), - yuzu_command.string(), arguments, categories, keywords)) { - QMessageBox::critical(this, tr("Create Shortcut"), - tr("Failed to create a shortcut at %1") - .arg(QString::fromStdString(shortcut_path.string()))); + if (GMainWindow::CreateShortcutLink(shortcut_path, comment, out_icon_path, yuzu_command, + arguments, categories, keywords, game_title)) { + GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS, + qt_game_title); return; } - - LOG_INFO(Frontend, "Wrote a shortcut to {}", shortcut_path.string()); - QMessageBox::information( - this, tr("Create Shortcut"), - tr("Successfully created a shortcut to %1").arg(QString::fromStdString(title))); + GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR, + qt_game_title); } void GMainWindow::OnGameListOpenDirectory(const QString& directory) { @@ -3040,7 +3149,7 @@ void GMainWindow::OnGameListAddDirectory() { return; } - UISettings::GameDir game_dir{dir_path, false, true}; + UISettings::GameDir game_dir{dir_path.toStdString(), false, true}; if (!UISettings::values.game_dirs.contains(game_dir)) { UISettings::values.game_dirs.append(game_dir); game_list->PopulateAsync(UISettings::values.game_dirs); @@ -3086,14 +3195,14 @@ void GMainWindow::OnMenuLoadFile() { "%1 is an identifier for the Switch executable file extensions.") .arg(extensions); const QString filename = QFileDialog::getOpenFileName( - this, tr("Load File"), UISettings::values.roms_path, file_filter); + this, tr("Load File"), QString::fromStdString(UISettings::values.roms_path), file_filter); is_load_file_select_active = false; if (filename.isEmpty()) { return; } - UISettings::values.roms_path = QFileInfo(filename).path(); + UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); BootGame(filename); } @@ -3126,7 +3235,8 @@ void GMainWindow::OnMenuInstallToNAND() { "Image (*.xci)"); QStringList filenames = QFileDialog::getOpenFileNames( - this, tr("Install Files"), UISettings::values.roms_path, file_filter); + this, tr("Install Files"), QString::fromStdString(UISettings::values.roms_path), + file_filter); if (filenames.isEmpty()) { return; @@ -3144,7 +3254,7 @@ void GMainWindow::OnMenuInstallToNAND() { } // Save folder location of the first selected file - UISettings::values.roms_path = QFileInfo(filenames[0]).path(); + UISettings::values.roms_path = QFileInfo(filenames[0]).path().toStdString(); int remaining = filenames.size(); @@ -3484,12 +3594,12 @@ void GMainWindow::OnExecuteProgram(std::size_t program_index) { } void GMainWindow::OnExit() { - OnStopGame(); + ShutdownGame(); } void GMainWindow::OnSaveConfig() { system->ApplySettings(); - config->Save(); + config->SaveAllValues(); } void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) { @@ -3745,7 +3855,7 @@ void GMainWindow::OnConfigure() { Settings::values.disabled_addons.clear(); - config = std::make_unique<Config>(); + config = std::make_unique<QtConfig>(); UISettings::values.reset_to_defaults = false; UISettings::values.game_dirs = std::move(old_game_dirs); @@ -3780,7 +3890,7 @@ void GMainWindow::OnConfigure() { UISettings::values.configuration_applied = false; - config->Save(); + config->SaveAllValues(); if ((UISettings::values.hide_mouse || Settings::values.mouse_panning) && emulation_running) { render_window->installEventFilter(render_window); @@ -3996,68 +4106,8 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file UISettings::values.configuration_applied = false; if (!is_powered_on) { - config->Save(); - } -} - -bool GMainWindow::CreateShortcut(const std::string& shortcut_path, const std::string& title, - const std::string& comment, const std::string& icon_path, - const std::string& command, const std::string& arguments, - const std::string& categories, const std::string& keywords) { -#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) - // This desktop file template was writing referencing - // https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html - std::string shortcut_contents{}; - shortcut_contents.append("[Desktop Entry]\n"); - shortcut_contents.append("Type=Application\n"); - shortcut_contents.append("Version=1.0\n"); - shortcut_contents.append(fmt::format("Name={:s}\n", title)); - shortcut_contents.append(fmt::format("Comment={:s}\n", comment)); - shortcut_contents.append(fmt::format("Icon={:s}\n", icon_path)); - shortcut_contents.append(fmt::format("TryExec={:s}\n", command)); - shortcut_contents.append(fmt::format("Exec={:s} {:s}\n", command, arguments)); - shortcut_contents.append(fmt::format("Categories={:s}\n", categories)); - shortcut_contents.append(fmt::format("Keywords={:s}\n", keywords)); - - std::ofstream shortcut_stream(shortcut_path); - if (!shortcut_stream.is_open()) { - LOG_WARNING(Common, "Failed to create file {:s}", shortcut_path); - return false; + config->SaveAllValues(); } - shortcut_stream << shortcut_contents; - shortcut_stream.close(); - - return true; -#elif defined(WIN32) - IShellLinkW* shell_link; - auto hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, - (void**)&shell_link); - if (FAILED(hres)) { - return false; - } - shell_link->SetPath( - Common::UTF8ToUTF16W(command).data()); // Path to the object we are referring to - shell_link->SetArguments(Common::UTF8ToUTF16W(arguments).data()); - shell_link->SetDescription(Common::UTF8ToUTF16W(comment).data()); - shell_link->SetIconLocation(Common::UTF8ToUTF16W(icon_path).data(), 0); - - IPersistFile* persist_file; - hres = shell_link->QueryInterface(IID_IPersistFile, (void**)&persist_file); - if (FAILED(hres)) { - return false; - } - - hres = persist_file->Save(Common::UTF8ToUTF16W(shortcut_path).data(), TRUE); - if (FAILED(hres)) { - return false; - } - - persist_file->Release(); - shell_link->Release(); - - return true; -#endif - return false; } void GMainWindow::OnLoadAmiibo() { @@ -4098,7 +4148,6 @@ void GMainWindow::OnLoadAmiibo() { bool GMainWindow::question(QWidget* parent, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { - QMessageBox* box_dialog = new QMessageBox(parent); box_dialog->setWindowTitle(title); box_dialog->setText(text); @@ -4272,7 +4321,7 @@ void GMainWindow::OnToggleStatusBar() { } void GMainWindow::OnAlbum() { - constexpr u64 AlbumId = 0x010000000000100Dull; + constexpr u64 AlbumId = static_cast<u64>(Service::AM::Applets::AppletProgramId::PhotoViewer); auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), @@ -4290,12 +4339,12 @@ void GMainWindow::OnAlbum() { system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::PhotoViewer); const auto filename = QString::fromStdString(album_nca->GetFullPath()); - UISettings::values.roms_path = QFileInfo(filename).path(); - BootGame(filename); + UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); + BootGame(filename, AlbumId); } void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { - constexpr u64 CabinetId = 0x0100000000001002ull; + constexpr u64 CabinetId = static_cast<u64>(Service::AM::Applets::AppletProgramId::Cabinet); auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), @@ -4314,12 +4363,12 @@ void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { system->GetAppletManager().SetCabinetMode(mode); const auto filename = QString::fromStdString(cabinet_nca->GetFullPath()); - UISettings::values.roms_path = QFileInfo(filename).path(); - BootGame(filename); + UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); + BootGame(filename, CabinetId); } void GMainWindow::OnMiiEdit() { - constexpr u64 MiiEditId = 0x0100000000001009ull; + constexpr u64 MiiEditId = static_cast<u64>(Service::AM::Applets::AppletProgramId::MiiEdit); auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { QMessageBox::warning(this, tr("No firmware available"), @@ -4337,8 +4386,33 @@ void GMainWindow::OnMiiEdit() { system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::MiiEdit); const auto filename = QString::fromStdString((mii_applet_nca->GetFullPath())); - UISettings::values.roms_path = QFileInfo(filename).path(); - BootGame(filename); + UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); + BootGame(filename, MiiEditId); +} + +void GMainWindow::OnOpenControllerMenu() { + constexpr u64 ControllerAppletId = + static_cast<u64>(Service::AM::Applets::AppletProgramId::Controller); + 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.")); + return; + } + + auto controller_applet_nca = + bis_system->GetEntry(ControllerAppletId, FileSys::ContentRecordType::Program); + if (!controller_applet_nca) { + QMessageBox::warning(this, tr("Controller Applet"), + tr("Controller Menu is not available. Please reinstall firmware.")); + return; + } + + system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::Controller); + + const auto filename = QString::fromStdString((controller_applet_nca->GetFullPath())); + UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); + BootGame(filename, ControllerAppletId); } void GMainWindow::OnCaptureScreenshot() { @@ -4527,11 +4601,13 @@ void GMainWindow::UpdateStatusBar() { emu_speed_label->setVisible(!Settings::values.use_multi_core.GetValue()); game_fps_label->setVisible(true); emu_frametime_label->setVisible(true); + firmware_label->setVisible(false); } void GMainWindow::UpdateGPUAccuracyButton() { const auto gpu_accuracy = Settings::values.gpu_accuracy.GetValue(); - const auto gpu_accuracy_text = Config::gpu_accuracy_texts_map.find(gpu_accuracy)->second; + const auto gpu_accuracy_text = + ConfigurationShared::gpu_accuracy_texts_map.find(gpu_accuracy)->second; gpu_accuracy_button->setText(gpu_accuracy_text.toUpper()); gpu_accuracy_button->setChecked(gpu_accuracy != Settings::GpuAccuracy::Normal); } @@ -4540,31 +4616,32 @@ void GMainWindow::UpdateDockedButton() { 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(console_mode)->second.toUpper()); + ConfigurationShared::use_docked_mode_texts_map.find(console_mode)->second.toUpper()); } void GMainWindow::UpdateAPIText() { const auto api = Settings::values.renderer_backend.GetValue(); - const auto renderer_status_text = Config::renderer_backend_texts_map.find(api)->second; + const auto renderer_status_text = + ConfigurationShared::renderer_backend_texts_map.find(api)->second; renderer_status_button->setText( api == Settings::RendererBackend::OpenGL - ? tr("%1 %2").arg( - renderer_status_text.toUpper(), - Config::shader_backend_texts_map.find(Settings::values.shader_backend.GetValue()) - ->second) + ? tr("%1 %2").arg(renderer_status_text.toUpper(), + ConfigurationShared::shader_backend_texts_map + .find(Settings::values.shader_backend.GetValue()) + ->second) : renderer_status_text.toUpper()); } void GMainWindow::UpdateFilterText() { const auto filter = Settings::values.scaling_filter.GetValue(); - const auto filter_text = Config::scaling_filter_texts_map.find(filter)->second; + const auto filter_text = ConfigurationShared::scaling_filter_texts_map.find(filter)->second; filter_status_button->setText(filter == Settings::ScalingFilter::Fsr ? tr("FSR") : filter_text.toUpper()); } void GMainWindow::UpdateAAText() { const auto aa_mode = Settings::values.anti_aliasing.GetValue(); - const auto aa_text = Config::anti_aliasing_texts_map.find(aa_mode)->second; + const auto aa_text = ConfigurationShared::anti_aliasing_texts_map.find(aa_mode)->second; aa_status_button->setText(aa_mode == Settings::AntiAliasing::None ? QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "NO AA")) : aa_text.toUpper()); @@ -4744,6 +4821,8 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { "games.")); } + SetFirmwareVersion(); + if (behavior == ReinitializeKeyBehavior::Warning) { game_list->PopulateAsync(UISettings::values.game_dirs); } @@ -4771,7 +4850,7 @@ bool GMainWindow::CheckSystemArchiveDecryption() { } bool GMainWindow::CheckFirmwarePresence() { - constexpr u64 MiiEditId = 0x0100000000001009ull; + constexpr u64 MiiEditId = static_cast<u64>(Service::AM::Applets::AppletProgramId::MiiEdit); auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); if (!bis_system) { @@ -4786,6 +4865,28 @@ bool GMainWindow::CheckFirmwarePresence() { return true; } +void GMainWindow::SetFirmwareVersion() { + Service::Set::FirmwareVersionFormat firmware_data{}; + const auto result = Service::Set::GetFirmwareVersionImpl( + firmware_data, *system, Service::Set::GetFirmwareVersionType::Version2); + + if (result.IsError() || !CheckFirmwarePresence()) { + LOG_INFO(Frontend, "Installed firmware: No firmware available"); + firmware_label->setVisible(false); + return; + } + + firmware_label->setVisible(true); + + const std::string display_version(firmware_data.display_version.data()); + const std::string display_title(firmware_data.display_title.data()); + + LOG_INFO(Frontend, "Installed firmware: {}", display_title); + + firmware_label->setText(QString::fromStdString(display_version)); + firmware_label->setToolTip(QString::fromStdString(display_title)); +} + bool GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installed, u64 program_id, u64* selected_title_id, u8* selected_content_record_type) { using ContentInfo = std::tuple<u64, FileSys::TitleType, FileSys::ContentRecordType>; @@ -4847,7 +4948,12 @@ bool GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installe } bool GMainWindow::ConfirmClose() { - if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) { + if (emu_thread == nullptr || + UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Never) { + return true; + } + if (!system->GetExitLocked() && + UISettings::values.confirm_before_stopping.GetValue() == ConfirmStop::Ask_Based_On_Game) { return true; } const auto text = tr("Are you sure you want to close yuzu?"); @@ -4862,6 +4968,7 @@ void GMainWindow::closeEvent(QCloseEvent* event) { UpdateUISettings(); game_list->SaveInterfaceLayout(); + UISettings::SaveWindowState(); hotkey_registry.SaveHotkeys(); // Unload controllers early @@ -4952,7 +5059,7 @@ bool GMainWindow::ConfirmChangeGame() { } bool GMainWindow::ConfirmForceLockedExit() { - if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) { + if (emu_thread == nullptr) { return true; } const auto text = tr("The currently running application has requested yuzu to not exit.\n\n" @@ -5016,9 +5123,9 @@ static void AdjustLinkColor() { } void GMainWindow::UpdateUITheme() { - const QString default_theme = - QString::fromUtf8(UISettings::themes[static_cast<size_t>(Config::default_theme)].second); - QString current_theme = UISettings::values.theme; + const QString default_theme = QString::fromUtf8( + UISettings::themes[static_cast<size_t>(UISettings::default_theme)].second); + QString current_theme = QString::fromStdString(UISettings::values.theme); if (current_theme.isEmpty()) { current_theme = default_theme; @@ -5046,7 +5153,7 @@ void GMainWindow::UpdateUITheme() { QFile f(theme_uri); if (!f.open(QFile::ReadOnly | QFile::Text)) { LOG_ERROR(Frontend, "Unable to open style \"{}\", fallback to the default theme", - UISettings::values.theme.toStdString()); + UISettings::values.theme); current_theme = default_theme; } } @@ -5059,7 +5166,7 @@ void GMainWindow::UpdateUITheme() { setStyleSheet(ts.readAll()); } else { LOG_ERROR(Frontend, "Unable to set style \"{}\", stylesheet file not found", - UISettings::values.theme.toStdString()); + UISettings::values.theme); qApp->setStyleSheet({}); setStyleSheet({}); } @@ -5068,27 +5175,28 @@ void GMainWindow::UpdateUITheme() { void GMainWindow::LoadTranslation() { bool loaded; - if (UISettings::values.language.isEmpty()) { + if (UISettings::values.language.empty()) { // If the selected language is empty, use system locale loaded = translator.load(QLocale(), {}, {}, QStringLiteral(":/languages/")); } else { // Otherwise load from the specified file - loaded = translator.load(UISettings::values.language, QStringLiteral(":/languages/")); + loaded = translator.load(QString::fromStdString(UISettings::values.language), + QStringLiteral(":/languages/")); } if (loaded) { qApp->installTranslator(&translator); } else { - UISettings::values.language = QStringLiteral("en"); + UISettings::values.language = std::string("en"); } } void GMainWindow::OnLanguageChanged(const QString& locale) { - if (UISettings::values.language != QStringLiteral("en")) { + if (UISettings::values.language != std::string("en")) { qApp->removeTranslator(&translator); } - UISettings::values.language = locale; + UISettings::values.language = locale.toStdString(); LoadTranslation(); ui->retranslateUi(this); multiplayer_state->retranslateUi(); @@ -5114,7 +5222,7 @@ void GMainWindow::changeEvent(QEvent* event) { // UpdateUITheme is a decent work around if (event->type() == QEvent::PaletteChange) { const QPalette test_palette(qApp->palette()); - const QString current_theme = UISettings::values.theme; + const QString current_theme = QString::fromStdString(UISettings::values.theme); // Keeping eye on QPalette::Window to avoid looping. QPalette::Text might be useful too static QColor last_window_color; const QColor window_color = test_palette.color(QPalette::Active, QPalette::Window); @@ -5208,7 +5316,8 @@ static void SetHighDPIAttributes() { } int main(int argc, char* argv[]) { - std::unique_ptr<Config> config = std::make_unique<Config>(); + std::unique_ptr<QtConfig> config = std::make_unique<QtConfig>(); + UISettings::RestoreWindowState(config); bool has_broken_vulkan = false; bool is_child = false; if (CheckEnvVars(&is_child)) { diff --git a/src/yuzu/main.h b/src/yuzu/main.h index f9c6efe4f..e99d58995 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -6,6 +6,7 @@ #include <memory> #include <optional> +#include <filesystem> #include <QMainWindow> #include <QMessageBox> #include <QPushButton> @@ -14,6 +15,7 @@ #include "common/announce_multiplayer_room.h" #include "common/common_types.h" +#include "configuration/qt_config.h" #include "input_common/drivers/tas_input.h" #include "yuzu/compatibility_list.h" #include "yuzu/hotkeys.h" @@ -25,7 +27,7 @@ #include <QtDBus/QtDBus> #endif -class Config; +class QtConfig; class ClickableLabel; class EmuThread; class GameList; @@ -174,10 +176,17 @@ class GMainWindow : public QMainWindow { UI_EMU_STOPPING, }; + 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(); - explicit GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan); + explicit GMainWindow(std::unique_ptr<QtConfig> config_, bool has_broken_vulkan); ~GMainWindow() override; bool DropAction(QDropEvent* event); @@ -402,6 +411,7 @@ private slots: void OnAlbum(); void OnCabinet(Service::NFP::CabinetMode mode); void OnMiiEdit(); + void OnOpenControllerMenu(); void OnCaptureScreenshot(); void OnReinitializeKeys(ReinitializeKeyBehavior behavior); void OnLanguageChanged(const QString& locale); @@ -448,6 +458,7 @@ private: bool CheckDarkMode(); bool CheckSystemArchiveDecryption(); bool CheckFirmwarePresence(); + void SetFirmwareVersion(); void ConfigureFilesystemProvider(const std::string& filepath); /** * Open (or not) the right confirm dialog based on current setting and game exit lock @@ -456,11 +467,14 @@ private: bool ConfirmShutdownGame(); QString GetTasStateDescription() const; - bool CreateShortcut(const std::string& shortcut_path, const std::string& title, - const std::string& comment, const std::string& icon_path, - const std::string& command, const std::string& arguments, - const std::string& categories, const std::string& keywords); - + 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); /** * Mimic the behavior of QMessageBox::question but link controller navigation to the dialog * The only difference is that it returns a boolean. @@ -499,6 +513,7 @@ private: QLabel* game_fps_label = nullptr; QLabel* emu_frametime_label = nullptr; QLabel* tas_label = nullptr; + QLabel* firmware_label = nullptr; QPushButton* gpu_accuracy_button = nullptr; QPushButton* renderer_status_button = nullptr; QPushButton* dock_status_button = nullptr; @@ -509,7 +524,7 @@ private: QSlider* volume_slider = nullptr; QTimer status_bar_update_timer; - std::unique_ptr<Config> config; + std::unique_ptr<QtConfig> config; // Whether emulation is currently running in yuzu. bool emulation_running = false; diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui index 88684ffb5..e53f9951e 100644 --- a/src/yuzu/main.ui +++ b/src/yuzu/main.ui @@ -25,7 +25,7 @@ </property> <widget class="QWidget" name="centralwidget"> <layout class="QHBoxLayout" name="horizontalLayout"> - <property name="margin"> + <property name="margin" stdset="0"> <number>0</number> </property> </layout> @@ -36,7 +36,7 @@ <x>0</x> <y>0</y> <width>1280</width> - <height>26</height> + <height>21</height> </rect> </property> <widget class="QMenu" name="menu_File"> @@ -162,6 +162,7 @@ <addaction name="menu_cabinet_applet"/> <addaction name="action_Load_Album"/> <addaction name="action_Load_Mii_Edit"/> + <addaction name="action_Open_Controller_Menu"/> <addaction name="separator"/> <addaction name="action_Capture_Screenshot"/> <addaction name="menuTAS"/> @@ -382,9 +383,9 @@ </property> </action> <action name="action_Load_Album"> - <property name="text"> - <string>Open &Album</string> - </property> + <property name="text"> + <string>Open &Album</string> + </property> </action> <action name="action_Load_Cabinet_Nickname_Owner"> <property name="text"> @@ -407,9 +408,9 @@ </property> </action> <action name="action_Load_Mii_Edit"> - <property name="text"> - <string>Open &Mii Editor</string> - </property> + <property name="text"> + <string>Open &Mii Editor</string> + </property> </action> <action name="action_Configure_Tas"> <property name="text"> @@ -454,6 +455,11 @@ <string>R&ecord</string> </property> </action> + <action name="action_Open_Controller_Menu"> + <property name="text"> + <string>Open &Controller Menu</string> + </property> + </action> </widget> <resources> <include location="yuzu.qrc"/> diff --git a/src/yuzu/uisettings.cpp b/src/yuzu/uisettings.cpp index 1c833767b..7bb7e95af 100644 --- a/src/yuzu/uisettings.cpp +++ b/src/yuzu/uisettings.cpp @@ -1,6 +1,9 @@ // SPDX-FileCopyrightText: 2016 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include <QSettings> +#include "common/fs/fs.h" +#include "common/fs/path_util.h" #include "yuzu/uisettings.h" #ifndef CANNOT_EXPLICITLY_INSTANTIATE @@ -15,6 +18,8 @@ template class Setting<unsigned long long>; } // namespace Settings #endif +namespace FS = Common::FS; + namespace UISettings { const Themes themes{{ @@ -28,10 +33,8 @@ const Themes themes{{ bool IsDarkTheme() { const auto& theme = UISettings::values.theme; - return theme == QStringLiteral("qdarkstyle") || - theme == QStringLiteral("qdarkstyle_midnight_blue") || - theme == QStringLiteral("colorful_dark") || - theme == QStringLiteral("colorful_midnight_blue"); + return theme == std::string("qdarkstyle") || theme == std::string("qdarkstyle_midnight_blue") || + theme == std::string("colorful_dark") || theme == std::string("colorful_midnight_blue"); } Values values = {}; @@ -52,4 +55,58 @@ u32 CalculateWidth(u32 height, Settings::AspectRatio ratio) { return height * 16 / 9; } +void SaveWindowState() { + const auto window_state_config_loc = + FS::PathToUTF8String(FS::GetYuzuPath(FS::YuzuPath::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>& qtConfig) { + const auto window_state_config_loc = + FS::PathToUTF8String(FS::GetYuzuPath(FS::YuzuPath::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::GetYuzuPath(FS::YuzuPath::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/yuzu/uisettings.h b/src/yuzu/uisettings.h index b62ff620c..549a39e1b 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h @@ -14,6 +14,7 @@ #include "common/common_types.h" #include "common/settings.h" #include "common/settings_enums.h" +#include "configuration/qt_config.h" using Settings::Category; using Settings::ConfirmStop; @@ -37,15 +38,15 @@ namespace UISettings { bool IsDarkTheme(); struct ContextualShortcut { - QString keyseq; - QString controller_keyseq; + std::string keyseq; + std::string controller_keyseq; int context; bool repeat; }; struct Shortcut { - QString name; - QString group; + std::string name; + std::string group; ContextualShortcut shortcut; }; @@ -58,11 +59,19 @@ enum class Theme { MidnightBlueColorful, }; +static constexpr Theme default_theme{ +#ifdef _WIN32 + Theme::DarkColorful +#else + Theme::DefaultColorful +#endif +}; + using Themes = std::array<std::pair<const char*, const char*>, 6>; extern const Themes themes; struct GameDir { - QString path; + std::string path; bool deep_scan = false; bool expanded = false; bool operator==(const GameDir& rhs) const { @@ -93,10 +102,6 @@ struct Values { Setting<bool> show_filter_bar{linkage, true, "showFilterBar", Category::Ui}; Setting<bool> show_status_bar{linkage, true, "showStatusBar", Category::Ui}; - Setting<bool> confirm_before_closing{ - linkage, true, "confirmClose", Category::UiGeneral, Settings::Specialization::Default, - true, true}; - SwitchableSetting<ConfirmStop> confirm_before_stopping{linkage, ConfirmStop::Ask_Always, "confirmStop", @@ -113,9 +118,13 @@ struct Values { Settings::Specialization::Default, true, true}; - Setting<bool> mute_when_in_background{ - linkage, false, "muteWhenInBackground", Category::Audio, Settings::Specialization::Default, - true, true}; + Setting<bool> mute_when_in_background{linkage, + false, + "muteWhenInBackground", + Category::UiAudio, + Settings::Specialization::Default, + true, + true}; Setting<bool> hide_mouse{ linkage, true, "hideInactiveMouse", Category::UiGeneral, Settings::Specialization::Default, true, true}; @@ -144,15 +153,15 @@ struct Values { Category::Screenshots}; Setting<u32> screenshot_height{linkage, 0, "screenshot_height", Category::Screenshots}; - QString roms_path; - QString symbols_path; - QString game_dir_deprecated; + std::string roms_path; + std::string symbols_path; + std::string game_dir_deprecated; bool game_dir_deprecated_deepscan; - QVector<UISettings::GameDir> game_dirs; + QVector<GameDir> game_dirs; QStringList recent_files; - QString language; + std::string language; - QString theme; + std::string theme; // Shortcut name <Shortcut, context> std::vector<Shortcut> shortcuts; @@ -206,6 +215,54 @@ extern Values values; u32 CalculateWidth(u32 height, Settings::AspectRatio ratio); +void SaveWindowState(); +void RestoreWindowState(std::unique_ptr<QtConfig>& 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<Shortcut, 23> 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 yuzu")).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", "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); diff --git a/src/yuzu/util/util.cpp b/src/yuzu/util/util.cpp index f2854c8ec..e22cf84bf 100644 --- a/src/yuzu/util/util.cpp +++ b/src/yuzu/util/util.cpp @@ -4,7 +4,10 @@ #include <array> #include <cmath> #include <QPainter> + +#include "common/logging/log.h" #include "yuzu/util/util.h" + #ifdef _WIN32 #include <windows.h> #include "common/fs/file.h" @@ -42,7 +45,7 @@ QPixmap CreateCirclePixmapFromColor(const QColor& color) { return circle_pixmap; } -bool SaveIconToFile(const std::string_view path, const QImage& image) { +bool SaveIconToFile(const std::filesystem::path& icon_path, const QImage& image) { #if defined(WIN32) #pragma pack(push, 2) struct IconDir { @@ -73,7 +76,7 @@ bool SaveIconToFile(const std::string_view path, const QImage& image) { .id_count = static_cast<WORD>(scale_sizes.size()), }; - Common::FS::IOFile icon_file(path, Common::FS::FileAccessMode::Write, + Common::FS::IOFile icon_file(icon_path.string(), Common::FS::FileAccessMode::Write, Common::FS::FileType::BinaryFile); if (!icon_file.IsOpen()) { return false; @@ -135,6 +138,14 @@ bool SaveIconToFile(const std::string_view path, const QImage& image) { icon_file.Close(); return true; +#elif defined(__linux__) || defined(__FreeBSD__) + // Convert and write the icon as a PNG + if (!image.save(QString::fromStdString(icon_path.string()))) { + LOG_ERROR(Frontend, "Could not write icon as PNG to file"); + } else { + LOG_INFO(Frontend, "Wrote an icon to {}", icon_path.string()); + } + return true; #else return false; #endif diff --git a/src/yuzu/util/util.h b/src/yuzu/util/util.h index 09c14ce3f..4094cf6c2 100644 --- a/src/yuzu/util/util.h +++ b/src/yuzu/util/util.h @@ -3,6 +3,7 @@ #pragma once +#include <filesystem> #include <QFont> #include <QString> @@ -25,4 +26,4 @@ * @param image The image to save * @return bool If the operation succeeded */ -[[nodiscard]] bool SaveIconToFile(const std::string_view path, const QImage& image); +[[nodiscard]] bool SaveIconToFile(const std::filesystem::path& icon_path, const QImage& image); diff --git a/src/yuzu/vk_device_info.cpp b/src/yuzu/vk_device_info.cpp index 92f10d315..ab0d39c25 100644 --- a/src/yuzu/vk_device_info.cpp +++ b/src/yuzu/vk_device_info.cpp @@ -31,6 +31,7 @@ void PopulateRecords(std::vector<Record>& records, QWindow* window) try { // Create a test window with a Vulkan surface type for checking present modes. QWindow test_window(window); test_window.setSurfaceType(QWindow::VulkanSurface); + test_window.create(); auto wsi = QtCommon::GetWindowSystemInfo(&test_window); vk::InstanceDispatch dld; |