diff --git a/rpcs3/Emu/Audio/audio_utils.cpp b/rpcs3/Emu/Audio/audio_utils.cpp index 2db2e1a0ed..9df1d6ff1d 100644 --- a/rpcs3/Emu/Audio/audio_utils.cpp +++ b/rpcs3/Emu/Audio/audio_utils.cpp @@ -52,6 +52,6 @@ namespace audio g_cfg.audio.volume.set(std::clamp(new_volume, g_cfg.audio.volume.min, g_cfg.audio.volume.max)); Emu.GetCallbacks().update_emu_settings(); - rsx::overlays::queue_message(get_localized_string(localized_string_id::AUDIO_CHANGED, fmt::format("%d%%", g_cfg.audio.volume.get()).c_str()), 3'000'000); + rsx::overlays::queue_message(localized_string(localized_string_id::AUDIO_CHANGED, "%d%%", g_cfg.audio.volume.get()), 3'000'000, {}, rsx::overlays::message_pin_location::top_left, {}, true, true); } } // namespace audio diff --git a/rpcs3/Emu/Cell/Modules/cellGame.cpp b/rpcs3/Emu/Cell/Modules/cellGame.cpp index 17e190898d..7c31007793 100644 --- a/rpcs3/Emu/Cell/Modules/cellGame.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGame.cpp @@ -550,7 +550,7 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr dirName case CELL_HDDGAME_CBRESULT_ERR_NOSPACE: cellGame.error("cellHddGameCheck(): callback returned CELL_HDDGAME_CBRESULT_ERR_NOSPACE. Space Needed: %d KB", result->errNeedSizeKB); - error_msg = get_localized_string(localized_string_id::CELL_HDD_GAME_CHECK_NOSPACE, fmt::format("%d", result->errNeedSizeKB).c_str()); + error_msg = get_localized_string(localized_string_id::CELL_HDD_GAME_CHECK_NOSPACE, "%d", result->errNeedSizeKB); break; case CELL_HDDGAME_CBRESULT_ERR_BROKEN: @@ -565,12 +565,12 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr dirName case CELL_HDDGAME_CBRESULT_ERR_INVALID: cellGame.error("cellHddGameCheck(): callback returned CELL_HDDGAME_CBRESULT_ERR_INVALID. Error message: %s", result->invalidMsg); - error_msg = get_localized_string(localized_string_id::CELL_HDD_GAME_CHECK_INVALID, fmt::format("%s", result->invalidMsg).c_str()); + error_msg = get_localized_string(localized_string_id::CELL_HDD_GAME_CHECK_INVALID, "%s", result->invalidMsg); break; default: cellGame.error("cellHddGameCheck(): callback returned unknown error (code=0x%x). Error message: %s", result->invalidMsg); - error_msg = get_localized_string(localized_string_id::CELL_HDD_GAME_CHECK_INVALID, fmt::format("%s", result->invalidMsg).c_str()); + error_msg = get_localized_string(localized_string_id::CELL_HDD_GAME_CHECK_INVALID, "%s", result->invalidMsg); break; } @@ -1169,7 +1169,7 @@ error_code cellGameDataCheckCreate2(ppu_thread& ppu, u32 version, vm::cptr } case CELL_GAMEDATA_CBRESULT_ERR_NOSPACE: cellGame.error("cellGameDataCheckCreate2(): callback returned CELL_GAMEDATA_CBRESULT_ERR_NOSPACE. Space Needed: %d KB", cbResult->errNeedSizeKB); - error_msg = get_localized_string(localized_string_id::CELL_GAMEDATA_CHECK_NOSPACE, fmt::format("%d", cbResult->errNeedSizeKB).c_str()); + error_msg = get_localized_string(localized_string_id::CELL_GAMEDATA_CHECK_NOSPACE, "%d", cbResult->errNeedSizeKB); break; case CELL_GAMEDATA_CBRESULT_ERR_BROKEN: @@ -1184,12 +1184,12 @@ error_code cellGameDataCheckCreate2(ppu_thread& ppu, u32 version, vm::cptr case CELL_GAMEDATA_CBRESULT_ERR_INVALID: cellGame.error("cellGameDataCheckCreate2(): callback returned CELL_GAMEDATA_CBRESULT_ERR_INVALID. Error message: %s", cbResult->invalidMsg); - error_msg = get_localized_string(localized_string_id::CELL_GAMEDATA_CHECK_INVALID, fmt::format("%s", cbResult->invalidMsg).c_str()); + error_msg = get_localized_string(localized_string_id::CELL_GAMEDATA_CHECK_INVALID, "%s", cbResult->invalidMsg); break; default: cellGame.error("cellGameDataCheckCreate2(): callback returned unknown error (code=0x%x). Error message: %s", cbResult->invalidMsg); - error_msg = get_localized_string(localized_string_id::CELL_GAMEDATA_CHECK_INVALID, fmt::format("%s", cbResult->invalidMsg).c_str()); + error_msg = get_localized_string(localized_string_id::CELL_GAMEDATA_CHECK_INVALID, "%s", cbResult->invalidMsg); break; } @@ -1686,7 +1686,7 @@ error_code cellGameContentErrorDialog(s32 type, s32 errNeedSizeKB, vm::cptr CELL_GAME_ERRDIALOG_NOSPACE, msg_dialog_source::_cellGame); diff --git a/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp b/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp index 2b433e999c..875472a352 100644 --- a/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp @@ -506,7 +506,7 @@ error_code cellMsgDialogOpenErrorCode(u32 errorCode, vm::ptrselect_entry(selected_index); } - m_description->set_text(get_localized_string(localized_string_id::HOME_MENU_TROPHY_LIST_TITLE, fmt::format("%d%% (%d/%d)", percentage, unlocked_trophies, all_trophies).c_str())); + m_description->set_text(get_localized_string(localized_string_id::HOME_MENU_TROPHY_LIST_TITLE, "%d%% (%d/%d)", percentage, unlocked_trophies, all_trophies)); m_description->auto_resize(); } } // namespace overlays diff --git a/rpcs3/Emu/RSX/Overlays/overlay_controls.cpp b/rpcs3/Emu/RSX/Overlays/overlay_controls.cpp index 23e7fccb55..9d16842332 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_controls.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_controls.cpp @@ -402,6 +402,11 @@ namespace rsx set_unicode_text(get_localized_u32string(id)); } + void overlay_element::set_text(const localized_string& container) + { + set_text(container.str); + } + void overlay_element::set_font(const char* font_name, u16 font_size) { font_ref = fontmgr::get(font_name, font_size); diff --git a/rpcs3/Emu/RSX/Overlays/overlay_controls.h b/rpcs3/Emu/RSX/Overlays/overlay_controls.h index f39a25f2a4..96090d1597 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_controls.h +++ b/rpcs3/Emu/RSX/Overlays/overlay_controls.h @@ -206,6 +206,7 @@ namespace rsx virtual void set_text(const std::string& text); virtual void set_unicode_text(const std::u32string& text); void set_text(localized_string_id id); + void set_text(const localized_string& container); virtual void set_font(const char* font_name, u16 font_size); virtual void align_text(text_align align); virtual void set_wrap_text(bool state); diff --git a/rpcs3/Emu/RSX/Overlays/overlay_message.cpp b/rpcs3/Emu/RSX/Overlays/overlay_message.cpp index 218f7a2a3a..f4de82949f 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_message.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_message.cpp @@ -19,6 +19,15 @@ namespace rsx template message_item::message_item(const T& msg_id, u64 expiration, std::shared_ptr> refs, std::shared_ptr icon) { + if constexpr (std::is_same_v) + { + m_loc_id = msg_id; + } + else if constexpr (std::is_same_v) + { + m_loc_id = msg_id.id; + } + m_visible_duration = expiration; m_refs = std::move(refs); @@ -54,6 +63,7 @@ namespace rsx } template message_item::message_item(const std::string& msg_id, u64, std::shared_ptr>, std::shared_ptr); template message_item::message_item(const localized_string_id& msg_id, u64, std::shared_ptr>, std::shared_ptr); + template message_item::message_item(const localized_string& msg_id, u64, std::shared_ptr>, std::shared_ptr); void message_item::reset_expiration() { @@ -75,11 +85,22 @@ namespace rsx } } + bool message_item::id_matches(localized_string_id id) const + { + return m_loc_id == id; + } + bool message_item::text_matches(const std::u32string& text) const { return m_text.text == text; } + void message_item::set_label_text(const std::string& text) + { + m_text.set_text(text); + m_is_compiled = false; + } + void message_item::set_pos(s16 _x, s16 _y) { rounded_rect::set_pos(_x, _y); @@ -277,33 +298,9 @@ namespace rsx return cr; } - bool message::message_exists(message_pin_location location, localized_string_id id, bool allow_refresh) + bool message::check_lists(message_pin_location location, std::function& list)> check_list) { - return message_exists(location, get_localized_u32string(id), allow_refresh); - } - - bool message::message_exists(message_pin_location location, const std::string& msg, bool allow_refresh) - { - return message_exists(location, utf8_to_u32string(msg), allow_refresh); - } - - bool message::message_exists(message_pin_location location, const std::u32string& msg, bool allow_refresh) - { - auto check_list = [&](std::deque& list) - { - return std::any_of(list.begin(), list.end(), [&](message_item& item) - { - if (item.text_matches(msg)) - { - if (allow_refresh) - { - item.reset_expiration(); - } - return true; - } - return false; - }); - }; + if (!check_list) return false; switch (location) { @@ -320,6 +317,80 @@ namespace rsx return false; } + bool message::message_exists(message_pin_location location, localized_string_id id, bool allow_refresh, bool /*compare_id*/) + { + const auto check_list = [&](std::deque& list) + { + return std::any_of(list.begin(), list.end(), [&](message_item& item) + { + if (item.id_matches(id)) + { + if (allow_refresh) + { + item.reset_expiration(); + } + return true; + } + return false; + }); + }; + + return check_lists(location, check_list); + } + + bool message::message_exists(message_pin_location location, const std::string& msg, bool allow_refresh, bool compare_id) + { + return message_exists(location, utf8_to_u32string(msg), allow_refresh, compare_id); + } + + bool message::message_exists(message_pin_location location, const std::u32string& msg, bool allow_refresh, bool /*compare_id*/) + { + const auto check_list = [&](std::deque& list) + { + return std::any_of(list.begin(), list.end(), [&](message_item& item) + { + if (item.text_matches(msg)) + { + if (allow_refresh) + { + item.reset_expiration(); + } + return true; + } + return false; + }); + }; + + return check_lists(location, check_list); + } + + bool message::message_exists(message_pin_location location, const localized_string& container, bool allow_refresh, bool compare_id) + { + if (compare_id) + { + const auto check_list = [&](std::deque& list) + { + return std::any_of(list.begin(), list.end(), [&](message_item& item) + { + if (item.id_matches(container.id)) + { + if (allow_refresh) + { + item.set_label_text(container.str); + item.reset_expiration(); + } + return true; + } + return false; + }); + }; + + return check_lists(location, check_list); + } + + return message_exists(location, utf8_to_u32string(container.str), allow_refresh, compare_id); + } + void refresh_message_queue() { if (auto manager = g_fxo->try_get()) diff --git a/rpcs3/Emu/RSX/Overlays/overlay_message.h b/rpcs3/Emu/RSX/Overlays/overlay_message.h index 9d3e10d358..219103e843 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_message.h +++ b/rpcs3/Emu/RSX/Overlays/overlay_message.h @@ -30,9 +30,13 @@ namespace rsx void ensure_expired(); compiled_resource& get_compiled() override; + bool id_matches(localized_string_id id) const; bool text_matches(const std::u32string& text) const; + void set_label_text(const std::string& text); + private: + localized_string_id m_loc_id = localized_string_id::INVALID; label m_text{}; std::shared_ptr m_icon{}; animation_color_interpolate m_fade_in_animation; @@ -59,7 +63,8 @@ namespace rsx std::shared_ptr> refs, message_pin_location location = message_pin_location::top_left, std::shared_ptr icon = {}, - bool allow_refresh = false) + bool allow_refresh = false, + bool compare_id = false) { std::lock_guard lock(m_mutex_queue); @@ -85,13 +90,13 @@ namespace rsx { for (auto id : msg_id) { - if (!message_exists(location, id, allow_refresh)) + if (!message_exists(location, id, allow_refresh, compare_id)) { queue->emplace_back(id, expiration, refs, icon); } } } - else if (!message_exists(location, msg_id, allow_refresh)) + else if (!message_exists(location, msg_id, allow_refresh, compare_id)) { queue->emplace_back(msg_id, expiration, std::move(refs), icon); } @@ -119,9 +124,11 @@ namespace rsx void update_queue(std::deque& vis_set, std::deque& ready_set, message_pin_location origin); // Stacking. Extends the lifetime of a message instead of inserting a duplicate - bool message_exists(message_pin_location location, localized_string_id id, bool allow_refresh); - bool message_exists(message_pin_location location, const std::string& msg, bool allow_refresh); - bool message_exists(message_pin_location location, const std::u32string& msg, bool allow_refresh); + bool check_lists(message_pin_location location, std::function& list)> check_list); + bool message_exists(message_pin_location location, localized_string_id id, bool allow_refresh, bool compare_id); + bool message_exists(message_pin_location location, const std::string& msg, bool allow_refresh, bool compare_id); + bool message_exists(message_pin_location location, const std::u32string& msg, bool allow_refresh, bool compare_id); + bool message_exists(message_pin_location location, const localized_string& container, bool allow_refresh, bool compare_id); }; template @@ -131,7 +138,8 @@ namespace rsx std::shared_ptr> refs = {}, message_pin_location location = message_pin_location::top_left, std::shared_ptr icon = {}, - bool allow_refresh = false) + bool allow_refresh = false, + bool compare_id = false) { if (auto manager = g_fxo->try_get()) { @@ -141,7 +149,7 @@ namespace rsx msg_overlay = std::make_shared(); msg_overlay = manager->add(msg_overlay); } - msg_overlay->queue_message(msg_id, expiration, std::move(refs), location, std::move(icon), allow_refresh); + msg_overlay->queue_message(msg_id, expiration, std::move(refs), location, std::move(icon), allow_refresh, compare_id); } } diff --git a/rpcs3/Emu/localized_string.h b/rpcs3/Emu/localized_string.h index 35df711105..08168b1ad3 100644 --- a/rpcs3/Emu/localized_string.h +++ b/rpcs3/Emu/localized_string.h @@ -1,7 +1,27 @@ #pragma once -#include #include "localized_string_id.h" +#include "Utilities/StrFmt.h" std::string get_localized_string(localized_string_id id, const char* args = ""); std::u32string get_localized_u32string(localized_string_id id, const char* args = ""); + +template +requires (sizeof...(Args) > 0) +std::string get_localized_string(localized_string_id id, const CharT(&fmt)[N], const Args&... args) +{ + return get_localized_string(id, fmt::format(fmt, args...).c_str()); +} + +struct localized_string +{ + template + requires (sizeof...(Args) > 0) + localized_string(localized_string_id _id, const CharT(&fmt)[N], const Args&... args) + : id(_id), str(get_localized_string(id, fmt, args...)) + { + } + + localized_string_id id = localized_string_id::INVALID; + std::string str; +};