diff --git a/src/openrct2-ui/scripting/CustomWindow.cpp b/src/openrct2-ui/scripting/CustomWindow.cpp index a79cf825db..6a6f3e929f 100644 --- a/src/openrct2-ui/scripting/CustomWindow.cpp +++ b/src/openrct2-ui/scripting/CustomWindow.cpp @@ -17,6 +17,7 @@ # include # include # include +# include # include # include # include @@ -109,28 +110,10 @@ namespace OpenRCT2::Ui::Windows static std::string ProcessString(const DukValue& value) { if (value.type() == DukValue::Type::STRING) - return ProcessString(value.as_string()); + return language_convert_string(value.as_string()); return {}; } - static std::string ProcessString(const std::string_view& s) - { - std::string result; - result.reserve(s.size()); - for (char c : s) - { - if (c == '\n') - { - result.push_back(FORMAT_NEWLINE); - } - else - { - result.push_back(c); - } - } - return result; - } - static CustomWidgetDesc FromDukValue(DukValue desc) { CustomWidgetDesc result; @@ -228,7 +211,7 @@ namespace OpenRCT2::Ui::Windows result.MaxWidth = GetOptionalInt(desc["maxWidth"]); result.MinHeight = GetOptionalInt(desc["minHeight"]); result.MaxHeight = GetOptionalInt(desc["maxHeight"]); - result.Title = desc["title"].as_string(); + result.Title = language_convert_string(desc["title"].as_string()); result.Id = GetOptionalInt(desc["id"]); if (desc["widgets"].is_array()) @@ -742,6 +725,25 @@ namespace OpenRCT2::Ui::Windows } } + std::string GetWindowTitle(rct_window* w) + { + if (w->custom_info != nullptr) + { + auto& customInfo = GetInfo(w); + return customInfo.Desc.Title; + } + return {}; + } + + void UpdateWindowTitle(rct_window* w, const std::string_view& value) + { + if (w->custom_info != nullptr) + { + auto& customInfo = GetInfo(w); + customInfo.Desc.Title = value; + } + } + void UpdateWidgetText(rct_window* w, rct_widgetindex widgetIndex, const std::string_view& value) { if (w->custom_info != nullptr) @@ -750,7 +752,7 @@ namespace OpenRCT2::Ui::Windows auto customWidgetInfo = customInfo.GetCustomWidgetDesc(widgetIndex); if (customWidgetInfo != nullptr) { - customWidgetInfo->Text = CustomWidgetDesc::ProcessString(value); + customWidgetInfo->Text = language_convert_string(value); w->widgets[widgetIndex].string = customWidgetInfo->Text.data(); widget_invalidate(w, widgetIndex); } diff --git a/src/openrct2-ui/scripting/CustomWindow.h b/src/openrct2-ui/scripting/CustomWindow.h index f63ecfcfec..5709d6ee9c 100644 --- a/src/openrct2-ui/scripting/CustomWindow.h +++ b/src/openrct2-ui/scripting/CustomWindow.h @@ -18,6 +18,8 @@ namespace OpenRCT2::Ui::Windows { + std::string GetWindowTitle(rct_window* w); + void UpdateWindowTitle(rct_window* w, const std::string_view& value); void UpdateWidgetText(rct_window* w, rct_widgetindex widget, const std::string_view& string_view); rct_window* FindCustomWindowByClassification(const std::string_view& classification); std::optional FindWidgetIndexByName(rct_window* w, const std::string_view& name); diff --git a/src/openrct2-ui/scripting/ScWindow.hpp b/src/openrct2-ui/scripting/ScWindow.hpp index 7c81653972..33bffc2b7e 100644 --- a/src/openrct2-ui/scripting/ScWindow.hpp +++ b/src/openrct2-ui/scripting/ScWindow.hpp @@ -16,6 +16,7 @@ # include # include # include +# include # include namespace OpenRCT2::Scripting @@ -125,6 +126,24 @@ namespace OpenRCT2::Scripting } } + std::string title_get() + { + auto w = GetWindow(); + if (w != nullptr && w->classification == WC_CUSTOM) + { + return GetWindowTitle(w); + } + return {}; + } + void title_set(std::string value) + { + auto w = GetWindow(); + if (w != nullptr && w->classification == WC_CUSTOM) + { + UpdateWindowTitle(w, language_convert_string(value)); + } + } + void close() { auto w = GetWindow(); @@ -169,6 +188,7 @@ namespace OpenRCT2::Scripting dukglue_register_property(ctx, &ScWindow::isSticky_get, nullptr, "isSticky"); dukglue_register_property(ctx, &ScWindow::widgets_get, nullptr, "widgets"); dukglue_register_property(ctx, &ScWindow::colours_get, &ScWindow::colours_set, "colours"); + dukglue_register_property(ctx, &ScWindow::title_get, &ScWindow::title_set, "title"); dukglue_register_method(ctx, &ScWindow::close, "close"); dukglue_register_method(ctx, &ScWindow::findWidget, "findWidget"); diff --git a/src/openrct2/localisation/Language.cpp b/src/openrct2/localisation/Language.cpp index f7cc78bea6..adde094cf3 100644 --- a/src/openrct2/localisation/Language.cpp +++ b/src/openrct2/localisation/Language.cpp @@ -136,3 +136,78 @@ rct_string_id language_allocate_object_string(const std::string& target) auto& localisationService = OpenRCT2::GetContext()->GetLocalisationService(); return localisationService.AllocateObjectString(target); } + +std::string language_convert_string(const std::string_view& s) +{ + enum class PARSE_STATE + { + DEFAULT, + CR, + TOKEN, + }; + + std::string result; + std::string token; + PARSE_STATE state{}; + token.reserve(64); + result.reserve(s.size() * 2); + for (char c : s) + { + switch (state) + { + case PARSE_STATE::CR: + result.push_back(FORMAT_NEWLINE); + state = PARSE_STATE::DEFAULT; + [[fallthrough]]; + case PARSE_STATE::DEFAULT: + switch (c) + { + case '\r': + state = PARSE_STATE::CR; + break; + case '\n': + result.push_back(FORMAT_NEWLINE); + break; + case '{': + token.clear(); + state = PARSE_STATE::TOKEN; + break; + default: + if (c >= 32) + { + result.push_back(c); + } + break; + } + break; + case PARSE_STATE::TOKEN: + if (c == '}') + { + auto code = format_get_code(token.c_str()); + if (code == 0) + { + int32_t number{}; + if (sscanf(token.c_str(), "%d", &number) == 1) + { + auto b = static_cast(std::clamp(number, 0, 255)); + token.push_back(b); + } + } + else + { + char buffer[8]{}; + utf8_write_codepoint(buffer, code); + result.append(buffer); + } + state = PARSE_STATE::DEFAULT; + } + else + { + token.push_back(c); + } + break; + } + } + result.shrink_to_fit(); + return result; +} diff --git a/src/openrct2/localisation/Language.h b/src/openrct2/localisation/Language.h index ef10e08e2b..ada81173cc 100644 --- a/src/openrct2/localisation/Language.h +++ b/src/openrct2/localisation/Language.h @@ -107,6 +107,7 @@ bool language_get_localised_scenario_strings(const utf8* scenarioFilename, rct_s void language_free_object_string(rct_string_id stringId); rct_string_id language_get_object_override_string_id(const char* identifier, uint8_t index); rct_string_id language_allocate_object_string(const std::string& target); +std::string language_convert_string(const std::string_view& s); constexpr utf8* utf8_write_codepoint(utf8* dst, uint32_t codepoint) {