From 070add461ff753e1a9f881c786d59c741df67252 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Thu, 14 Nov 2024 23:48:51 +0100 Subject: [PATCH] overlays: get localized values in home menu settings --- Utilities/Config.cpp | 6 +- Utilities/Config.h | 11 +++ .../HomeMenu/overlay_home_menu_components.h | 4 +- .../HomeMenu/overlay_home_menu_settings.cpp | 2 - .../HomeMenu/overlay_home_menu_settings.h | 2 +- rpcs3/Emu/System.h | 6 ++ rpcs3/headless_application.cpp | 1 + rpcs3/rpcs3qt/emu_settings.cpp | 86 ++++++++++++++++++- rpcs3/rpcs3qt/emu_settings.h | 16 ++++ rpcs3/rpcs3qt/emu_settings_type.h | 4 + rpcs3/rpcs3qt/gui_application.cpp | 6 ++ rpcs3/rpcs3qt/settings_dialog.cpp | 8 +- 12 files changed, 139 insertions(+), 13 deletions(-) diff --git a/Utilities/Config.cpp b/Utilities/Config.cpp index 19f2e7577b..8bf7d910d7 100644 --- a/Utilities/Config.cpp +++ b/Utilities/Config.cpp @@ -15,8 +15,10 @@ void fmt_class_string::format(std::string& out, u64 arg) namespace cfg { + u32 _base::id_counter = 0; + _base::_base(type _type) - : m_type(_type) + : m_type(_type), m_id(id_counter++) { if (_type != type::node) { @@ -25,7 +27,7 @@ namespace cfg } _base::_base(type _type, node* owner, std::string name, bool dynamic) - : m_type(_type), m_dynamic(dynamic), m_name(std::move(name)) + : m_type(_type), m_parent(owner), m_dynamic(dynamic), m_name(std::move(name)), m_id(id_counter++) { for (const auto& node : owner->m_nodes) { diff --git a/Utilities/Config.h b/Utilities/Config.h index 84b1f02e80..c0ca78a9d7 100644 --- a/Utilities/Config.h +++ b/Utilities/Config.h @@ -51,9 +51,13 @@ namespace cfg const type m_type{}; protected: + _base* m_parent = nullptr; bool m_dynamic = true; const std::string m_name{}; + static u32 id_counter; + u32 m_id = 0; + // Ownerless entry constructor _base(type _type); @@ -67,9 +71,16 @@ namespace cfg virtual ~_base() = default; + // Get unique ID + u32 get_id() const { return m_id; } + + // Get parent + _base* get_parent() const { return m_parent; } + // Get type type get_type() const { return m_type; } + // Get name const std::string& get_name() const { return m_name; } // Get dynamic property for reloading configs during games diff --git a/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_components.h b/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_components.h index 644402bc3d..186f67c3fe 100644 --- a/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_components.h +++ b/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_components.h @@ -1,6 +1,7 @@ #pragma once #include "Emu/RSX/Overlays/overlays.h" +#include "Emu/System.h" #include "Utilities/Config.h" namespace rsx @@ -102,7 +103,8 @@ namespace rsx if (!this->is_compiled) { - m_dropdown.set_text(fmt::format("%s", this->m_last_value)); + const std::string value_text = Emu.GetCallbacks().get_localized_setting(home_menu_setting>::m_setting, static_cast(this->m_last_value)); + m_dropdown.set_text(value_text); m_dropdown.set_pos(m_dropdown.x, this->y + (this->h - m_dropdown.h) / 2); this->compiled_resources = horizontal_layout::get_compiled(); diff --git a/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_settings.cpp b/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_settings.cpp index 628d06f320..50d690d56a 100644 --- a/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_settings.cpp +++ b/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_settings.cpp @@ -3,8 +3,6 @@ #include "overlay_home_menu_components.h" #include "Emu/system_config.h" -// TODO: Localization of the dropdown values - namespace rsx { namespace overlays diff --git a/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_settings.h b/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_settings.h index f8f0be719e..9e54cfd441 100644 --- a/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_settings.h +++ b/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_settings.h @@ -61,7 +61,7 @@ namespace rsx if (setting) { usz new_index = 0; - T value = setting->get(); + const T value = setting->get(); const std::string val = fmt::format("%s", value); const std::vector list = setting->to_list(); diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index 51e1e96654..74793a6b9b 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -24,6 +24,11 @@ class spu_thread; template class named_thread; +namespace cfg +{ + class _base; +} + enum class system_state : u32 { stopped, @@ -93,6 +98,7 @@ struct EmuCallbacks std::function()> get_trophy_notification_dialog; std::function get_localized_string; std::function get_localized_u32string; + std::function get_localized_setting; std::function play_sound; std::function get_image_info; // (filename, sub_type, width, height, CellSearchOrientation) std::function get_scaled_image; // (filename, target_width, target_height, width, height, dst, force_fit) diff --git a/rpcs3/headless_application.cpp b/rpcs3/headless_application.cpp index 1204ba85ef..d7270d0802 100644 --- a/rpcs3/headless_application.cpp +++ b/rpcs3/headless_application.cpp @@ -161,6 +161,7 @@ void headless_application::InitializeCallbacks() callbacks.get_localized_string = [](localized_string_id, const char*) -> std::string { return {}; }; callbacks.get_localized_u32string = [](localized_string_id, const char*) -> std::u32string { return {}; }; + callbacks.get_localized_setting = [](const cfg::_base*, u32) -> std::string { return {}; }; callbacks.play_sound = [](const std::string&){}; callbacks.add_breakpoint = [](u32 /*addr*/){}; diff --git a/rpcs3/rpcs3qt/emu_settings.cpp b/rpcs3/rpcs3qt/emu_settings.cpp index 8df69eea33..5a80174198 100644 --- a/rpcs3/rpcs3qt/emu_settings.cpp +++ b/rpcs3/rpcs3qt/emu_settings.cpp @@ -189,7 +189,7 @@ bool emu_settings::ValidateSettings(bool cleanup) for (const auto& yml_entry : yml_node) { - const std::string key = yml_entry.first.Scalar(); + const std::string& key = yml_entry.first.Scalar(); cfg::_base* cfg_node = nullptr; keys.resize(next_level); @@ -253,13 +253,13 @@ bool emu_settings::ValidateSettings(bool cleanup) } }; - cfg_root root; + std::unique_ptr root = std::make_unique(); std::vector keys; do { is_clean = true; - search_level(0, m_current_settings, keys, &root); + search_level(0, m_current_settings, keys, root.get()); } while (cleanup && !is_clean); @@ -885,6 +885,64 @@ void emu_settings::SetSetting(emu_settings_type type, const std::string& val) co cfg_adapter::get_node(m_current_settings, ::at32(settings_location, type)) = val; } +emu_settings_type emu_settings::FindSettingsType(const cfg::_base* node) const +{ + // Add key and value to static map on first use + static std::map id_to_type; + static std::mutex mtx; + std::lock_guard lock(mtx); + + if (!node) [[unlikely]] + { + // Provoke error. Don't use ensure or we will get a nullptr deref warning in VS + return ::at32(id_to_type, umax); + } + + std::vector node_location; + if (!id_to_type.contains(node->get_id())) + { + for (const cfg::_base* n = node; n; n = n->get_parent()) + { + if (!n->get_name().empty()) + { + node_location.push_back(n->get_name()); + } + } + + std::reverse(node_location.begin(), node_location.end()); + + for (const auto& [type, loc]: settings_location) + { + if (node_location.size() != loc.size()) + { + continue; + } + + bool is_match = true; + for (usz i = 0; i < node_location.size(); i++) + { + if (node_location[i] != loc[i]) + { + is_match = false; + break; + } + } + + if (is_match && !id_to_type.try_emplace(node->get_id(), type).second) + { + cfg_log.error("'%s' already exists", loc.back()); + } + } + } + + if (!id_to_type.contains(node->get_id())) + { + fmt::throw_exception("Node '%s' not represented in emu_settings_type", node->get_name()); + } + + return ::at32(id_to_type, node->get_id()); +} + void emu_settings::OpenCorrectionDialog(QWidget* parent) { if (!m_broken_types.empty() && QMessageBox::question(parent, tr("Fix invalid settings?"), @@ -1166,6 +1224,16 @@ QString emu_settings::GetLocalizedSetting(const QString& original, emu_settings_ case detail_level::high: return tr("High", "Detail Level"); } break; + case emu_settings_type::PerfOverlayFramerateDetailLevel: + case emu_settings_type::PerfOverlayFrametimeDetailLevel: + switch (static_cast(index)) + { + case perf_graph_detail_level::minimal: return tr("Minimal", "Perf Graph Detail Level"); + case perf_graph_detail_level::show_min_max: return tr("Show Min And Max", "Perf Graph Detail Level"); + case perf_graph_detail_level::show_one_percent_avg: return tr("Show 1% Low And Average", "Perf Graph Detail Level"); + case perf_graph_detail_level::show_all: return tr("Show All", "Perf Graph Detail Level"); + } + break; case emu_settings_type::PerfOverlayPosition: switch (static_cast(index)) { @@ -1386,3 +1454,15 @@ QString emu_settings::GetLocalizedSetting(const QString& original, emu_settings_ return original; } + +std::string emu_settings::GetLocalizedSetting(const std::string& original, emu_settings_type type, int index, bool strict) const +{ + return GetLocalizedSetting(QString::fromStdString(original), type, index, strict).toStdString(); +} + +std::string emu_settings::GetLocalizedSetting(const cfg::_base* node, u32 index) const +{ + const emu_settings_type type = FindSettingsType(node); + const std::vector settings = GetSettingOptions(type); + return GetLocalizedSetting(::at32(settings, index), type, index, true); +} diff --git a/rpcs3/rpcs3qt/emu_settings.h b/rpcs3/rpcs3qt/emu_settings.h index 73e369245f..4cd3da262d 100644 --- a/rpcs3/rpcs3qt/emu_settings.h +++ b/rpcs3/rpcs3qt/emu_settings.h @@ -18,6 +18,13 @@ #include #include +namespace cfg +{ + class _base; +} + +constexpr auto qstr = QString::fromStdString; + class emu_settings : public QObject { /** A settings class for Emulator specific settings. This class is a refactored version of the wx version. It is much nicer @@ -76,6 +83,9 @@ public: /** Sets the setting type to a given value.*/ void SetSetting(emu_settings_type type, const std::string& val) const; + /** Try to find the settings type for a given string.*/ + emu_settings_type FindSettingsType(const cfg::_base* node) const; + /** Gets all the renderer info for gpu settings.*/ render_creator* m_render_creator = nullptr; @@ -94,6 +104,12 @@ public: /** Get a localized and therefore freely adjustable version of the string used in config.yml.*/ QString GetLocalizedSetting(const QString& original, emu_settings_type type, int index, bool strict) const; + /** Get a localized and therefore freely adjustable version of the string used in config.yml.*/ + std::string GetLocalizedSetting(const std::string& original, emu_settings_type type, int index, bool strict) const; + + /** Get a localized and therefore freely adjustable version of the string used in config.yml.*/ + std::string GetLocalizedSetting(const cfg::_base* node, u32 index) const; + /** Validates the settings and logs unused entries or cleans up the yaml*/ bool ValidateSettings(bool cleanup); diff --git a/rpcs3/rpcs3qt/emu_settings_type.h b/rpcs3/rpcs3qt/emu_settings_type.h index 82e89f105a..f6b6268bd3 100644 --- a/rpcs3/rpcs3qt/emu_settings_type.h +++ b/rpcs3/rpcs3qt/emu_settings_type.h @@ -111,6 +111,8 @@ enum class emu_settings_type PerfOverlayFramerateDatapoints, PerfOverlayFrametimeDatapoints, PerfOverlayDetailLevel, + PerfOverlayFramerateDetailLevel, + PerfOverlayFrametimeDetailLevel, PerfOverlayPosition, PerfOverlayUpdateInterval, PerfOverlayFontSize, @@ -306,6 +308,8 @@ inline static const std::map settings_location { emu_settings_type::PerfOverlayFramerateDatapoints, { "Video", "Performance Overlay", "Framerate datapoints" } }, { emu_settings_type::PerfOverlayFrametimeDatapoints, { "Video", "Performance Overlay", "Frametime datapoints" } }, { emu_settings_type::PerfOverlayDetailLevel, { "Video", "Performance Overlay", "Detail level" } }, + { emu_settings_type::PerfOverlayFramerateDetailLevel, { "Video", "Performance Overlay", "Framerate graph detail level" } }, + { emu_settings_type::PerfOverlayFrametimeDetailLevel, { "Video", "Performance Overlay", "Frametime graph detail level" } }, { emu_settings_type::PerfOverlayPosition, { "Video", "Performance Overlay", "Position" } }, { emu_settings_type::PerfOverlayUpdateInterval, { "Video", "Performance Overlay", "Metrics update interval (ms)" } }, { emu_settings_type::PerfOverlayFontSize, { "Video", "Performance Overlay", "Font size (px)" } }, diff --git a/rpcs3/rpcs3qt/gui_application.cpp b/rpcs3/rpcs3qt/gui_application.cpp index 831ec24686..365a2d30ec 100644 --- a/rpcs3/rpcs3qt/gui_application.cpp +++ b/rpcs3/rpcs3qt/gui_application.cpp @@ -606,6 +606,12 @@ void gui_application::InitializeCallbacks() return localized_emu::get_u32string(id, args); }; + callbacks.get_localized_setting = [this](const cfg::_base* node, u32 enum_index) -> std::string + { + ensure(!!m_emu_settings); + return m_emu_settings->GetLocalizedSetting(node, enum_index); + }; + callbacks.play_sound = [this](const std::string& path) { Emu.CallFromMainThread([this, path]() diff --git a/rpcs3/rpcs3qt/settings_dialog.cpp b/rpcs3/rpcs3qt/settings_dialog.cpp index 1b5cc421a7..aa3245ba8d 100644 --- a/rpcs3/rpcs3qt/settings_dialog.cpp +++ b/rpcs3/rpcs3qt/settings_dialog.cpp @@ -448,9 +448,9 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std r_creator->update_names( { - m_emu_settings->GetLocalizedSetting("Vulkan", emu_settings_type::Renderer, static_cast(video_renderer::vulkan), true), - m_emu_settings->GetLocalizedSetting("OpenGl", emu_settings_type::Renderer, static_cast(video_renderer::opengl), true), - m_emu_settings->GetLocalizedSetting("Null", emu_settings_type::Renderer, static_cast(video_renderer::null), true) + m_emu_settings->GetLocalizedSetting(QString("Vulkan"), emu_settings_type::Renderer, static_cast(video_renderer::vulkan), true), + m_emu_settings->GetLocalizedSetting(QString("OpenGl"), emu_settings_type::Renderer, static_cast(video_renderer::opengl), true), + m_emu_settings->GetLocalizedSetting(QString("Null"), emu_settings_type::Renderer, static_cast(video_renderer::null), true) }); // Comboboxes @@ -1098,7 +1098,7 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std }; for (const audio_format_flag& audio_fmt : audio_formats) { - const QString audio_format_name = m_emu_settings->GetLocalizedSetting("", emu_settings_type::AudioFormats, static_cast(audio_fmt), true); + const QString audio_format_name = m_emu_settings->GetLocalizedSetting(QString(), emu_settings_type::AudioFormats, static_cast(audio_fmt), true); QListWidgetItem* item = new QListWidgetItem(audio_format_name, ui->list_audio_formats); item->setData(Qt::UserRole, static_cast(audio_fmt)); if (audio_fmt == audio_format_flag::lpcm_2_48khz)