diff --git a/data b/data index 031f41c..c3fb5da 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 031f41c969d81eb5fd74bd66fda086c9c1860fce +Subproject commit c3fb5da7ac7e7cf776dd00296ecb865fcf4b7b1e diff --git a/lib/emergent b/lib/emergent index b69db97..10c8ba8 160000 --- a/lib/emergent +++ b/lib/emergent @@ -1 +1 @@ -Subproject commit b69db97c5eaf02a34bb7af3a3ef8dcb92597cb51 +Subproject commit 10c8ba83a87c6042fd9671a8aaac1699e7b47b1d diff --git a/src/application.cpp b/src/application.cpp index 1b24c0a..7f1cf63 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -205,6 +205,71 @@ Application::Application(int argc, char* argv[]): resolution = resolutions[windowedResolutionIndex]; } + // Get requested language + languageIndex = 0; + std::string requestedLanguage; + settings.get("language", &requestedLanguage); + + // Find available languages + { + std::string stringsDirectory = appDataPath + "strings/"; + + // Open strings directory + DIR* dir = opendir(stringsDirectory.c_str()); + if (dir == nullptr) + { + std::cout << "Failed to open strings directory \"" << stringsDirectory << "\"" << std::endl; + close(EXIT_FAILURE); + return; + } + + // Scan directory for .txt files + for (struct dirent* entry = readdir(dir); entry != nullptr; entry = readdir(dir)) + { + if (entry->d_type == DT_DIR || *entry->d_name == '.') + { + continue; + } + + std::string filename = entry->d_name; + std::string::size_type delimeter = filename.find_last_of('.'); + if (delimeter == std::string::npos) + { + continue; + } + + std::string extension = filename.substr(delimeter + 1); + if (extension != "txt") + { + continue; + } + + // Add language + std::string language = filename.substr(0, delimeter); + languages.push_back(language); + + if (language == requestedLanguage) + { + languageIndex = languages.size() - 1; + } + } + + // Close biomes directory + closedir(dir); + } + + // Load strings + std::string stringsFile = appDataPath + "strings/" + languages[languageIndex] + ".txt"; + std::cout << "Loading strings from \"" << stringsFile << "\"... "; + if (!strings.load(stringsFile)) + { + std::cout << "failed" << std::endl; + } + else + { + std::cout << "success" << std::endl; + } + // Get window title string std::string title; strings.get("title", &title); @@ -322,71 +387,6 @@ Application::Application(int argc, char* argv[]): // Print font size std::cout << "Base font size is " << fontSizePT << "pt (" << fontSizePX << "px)" << std::endl; - // Get requested language - languageIndex = 0; - std::string requestedLanguage; - settings.get("language", &requestedLanguage); - - // Find available languages - { - std::string stringsDirectory = appDataPath + "strings/"; - - // Open strings directory - DIR* dir = opendir(stringsDirectory.c_str()); - if (dir == nullptr) - { - std::cout << "Failed to open strings directory \"" << stringsDirectory << "\"" << std::endl; - close(EXIT_FAILURE); - return; - } - - // Scan directory for .txt files - for (struct dirent* entry = readdir(dir); entry != nullptr; entry = readdir(dir)) - { - if (entry->d_type == DT_DIR || *entry->d_name == '.') - { - continue; - } - - std::string filename = entry->d_name; - std::string::size_type delimeter = filename.find_last_of('.'); - if (delimeter == std::string::npos) - { - continue; - } - - std::string extension = filename.substr(delimeter + 1); - if (extension != "txt") - { - continue; - } - - // Add language - std::string language = filename.substr(0, delimeter); - languages.push_back(language); - - if (language == requestedLanguage) - { - languageIndex = languages.size() - 1; - } - } - - // Close biomes directory - closedir(dir); - } - - // Load strings - std::string stringsFile = appDataPath + "strings/" + languages[languageIndex] + ".txt"; - std::cout << "Loading strings from \"" << stringsFile << "\"... "; - if (!strings.load(stringsFile)) - { - std::cout << "failed" << std::endl; - } - else - { - std::cout << "success" << std::endl; - } - // Setup input inputManager = new SDLInputManager(); keyboard = (*inputManager->getKeyboards()).front(); @@ -525,12 +525,14 @@ int Application::execute() // Update frame time label if (frameTimeLabel->isVisible()) { - std::string frameTimeString; - std::stringstream stream; + /* + std::u32string frameTimeString; + std::basic_stringstream stream; stream.precision(2); stream << std::fixed << meanFrameTime; stream >> frameTimeString; frameTimeLabel->setText(frameTimeString); + */ } } @@ -812,19 +814,19 @@ bool Application::loadUI() FontLoader* fontLoader = new FontLoader(); menuFont = new Font(512, 512); - if (!fontLoader->load("data/fonts/Varela-Regular.ttf", static_cast(fontSizePX + 0.5f), menuFont)) + if (!fontLoader->load("data/fonts/NotoSansCJKsc-Regular.otf", static_cast(fontSizePX + 0.5f), {UnicodeRange::BASIC_LATIN}, menuFont)) { std::cerr << "Failed to load menu font" << std::endl; } copyrightFont = new Font(256, 256); - if (!fontLoader->load("data/fonts/Varela-Regular.ttf", static_cast(fontSizePX * 0.8f + 0.5f), copyrightFont)) + if (!fontLoader->load("data/fonts/Varela-Regular.ttf", static_cast(fontSizePX * 0.8f + 0.5f), {UnicodeRange::BASIC_LATIN}, copyrightFont)) { std::cerr << "Failed to load copyright font" << std::endl; } levelNameFont = new Font(512, 512); - if (!fontLoader->load("data/fonts/Vollkorn-Regular.ttf", static_cast(fontSizePX * 2.0f + 0.5f), levelNameFont)) + if (!fontLoader->load("data/fonts/Vollkorn-Regular.ttf", static_cast(fontSizePX * 2.0f + 0.5f), {UnicodeRange::BASIC_LATIN}, levelNameFont)) { std::cerr << "Failed to load level name font" << std::endl; } @@ -925,10 +927,8 @@ bool Application::loadUI() frameTimeLabel = new UILabel(); frameTimeLabel->setAnchor(Vector2(0.0f, 0.0f)); frameTimeLabel->setLayerOffset(99); - frameTimeLabel->setFont(copyrightFont); frameTimeLabel->setTranslation(Vector2(0.0f)); frameTimeLabel->setTintColor(Vector4(1.0f, 1.0f, 0.0f, 1.0f)); - frameTimeLabel->setText(""); frameTimeLabel->setVisible(false); uiRootElement->addChild(frameTimeLabel); @@ -939,7 +939,6 @@ bool Application::loadUI() // Create "Press any key" element anyKeyLabel = new UILabel(); anyKeyLabel->setAnchor(Vector2(0.5f, 1.0f)); - anyKeyLabel->setFont(menuFont); anyKeyLabel->setTranslation(Vector2(0.0f, (int)(-resolution.y * (1.0f / 4.0f) - menuFont->getMetrics().getHeight() * 0.5f))); anyKeyLabel->setVisible(false); uiRootElement->addChild(anyKeyLabel); @@ -979,7 +978,6 @@ bool Application::loadUI() // Create level name label levelNameLabel = new UILabel(); levelNameLabel->setAnchor(Vector2(0.5f, 0.5f)); - levelNameLabel->setFont(levelNameFont); levelNameLabel->setVisible(false); levelNameLabel->setLayerOffset(ANTKEEPER_UI_LAYER_HUD); uiRootElement->addChild(levelNameLabel); @@ -1091,7 +1089,6 @@ bool Application::loadUI() // Main menu { - mainMenu->setFont(menuFont); mainMenu->getUIContainer()->setAnchor(Vector2(0.5f, 0.8f)); mainMenu->getUIContainer()->setLayerOffset(ANTKEEPER_UI_LAYER_MENU); mainMenu->setLineSpacing(1.0f); @@ -1121,7 +1118,6 @@ bool Application::loadUI() // Levels menu { - levelsMenu->setFont(menuFont); levelsMenu->getUIContainer()->setAnchor(Vector2(0.5f, 0.8f)); levelsMenu->getUIContainer()->setLayerOffset(ANTKEEPER_UI_LAYER_MENU); levelsMenu->setLineSpacing(1.0f); @@ -1170,11 +1166,10 @@ bool Application::loadUI() // Options menu { - optionsMenu->setFont(menuFont); optionsMenu->getUIContainer()->setAnchor(Vector2(0.5f, 0.8f)); optionsMenu->getUIContainer()->setLayerOffset(ANTKEEPER_UI_LAYER_MENU); optionsMenu->setLineSpacing(1.0f); - optionsMenu->setColumnMargin(menuFont->getWidth("MM")); + optionsMenu->setColumnMargin(menuFont->getWidth(U"MM")); optionsMenuWindowedResolutionItem = optionsMenu->addItem(); optionsMenuFullscreenResolutionItem = optionsMenu->addItem(); @@ -1231,7 +1226,6 @@ bool Application::loadUI() // Pause menu { - pauseMenu->setFont(menuFont); pauseMenu->getUIContainer()->setAnchor(Vector2(0.5f, 0.5f)); pauseMenu->getUIContainer()->setLayerOffset(ANTKEEPER_UI_LAYER_MENU); pauseMenu->setLineSpacing(1.0f); @@ -1422,55 +1416,95 @@ void Application::resizeUI() void Application::restringUI() { - // Get strings - std::string pressAnyKeyString; - std::string backString; - std::string onString; - std::string offString; - std::string continueString; - std::string newGameString; - std::string levelsString; - std::string sandboxString; - std::string optionsString; - std::string exitString; - std::string windowedResolutionString; - std::string fullscreenResolutionString; - std::string fullscreenString; - std::string verticalSyncString; - std::string languageString; - std::string controlsString; - std::string resumeString; - std::string mainMenuString; - - strings.get("press-any-key", &pressAnyKeyString); - strings.get("back", &backString); - strings.get("on", &onString); - strings.get("off", &offString); - strings.get("continue", &continueString); - strings.get("new-game", &newGameString); - strings.get("levels", &levelsString); - strings.get("sandbox", &sandboxString); - strings.get("options", &optionsString); - strings.get("exit", &exitString); - strings.get("windowed-resolution", &windowedResolutionString); - strings.get("fullscreen-resolution", &fullscreenResolutionString); - strings.get("fullscreen", &fullscreenString); - strings.get("vertical-sync", &verticalSyncString); - strings.get("language", &languageString); - strings.get("controls", &controlsString); - strings.get("resume", &resumeString); - strings.get("main-menu", &mainMenuString); + // Build map of UTF-8 string names to UTF-32 string values + std::map stringMap; + const std::map* stringParameters = strings.getParameters(); + for (auto it = stringParameters->begin(); it != stringParameters->end(); ++it) + { + std::u32string u32value; + strings.get(it->first, &stringMap[it->first]); + } + + // Build set of Unicode characters which encompass all strings + std::set unicodeSet; + for (auto it = stringMap.begin(); it != stringMap.end(); ++it) + { + for (char32_t charcode: it->second) + { + unicodeSet.insert(charcode); + } + } + + // Insert basic latin Unicode block + for (char32_t charcode = UnicodeRange::BASIC_LATIN.start; charcode <= UnicodeRange::BASIC_LATIN.end; ++charcode) + { + unicodeSet.insert(charcode); + } + + // Transform character set into character ranges + std::vector unicodeRanges; + for (auto it = unicodeSet.begin(); it != unicodeSet.end(); ++it) + { + char32_t charcode = *it; + unicodeRanges.push_back(UnicodeRange(charcode)); + } + + // Delete previously loaded fonts + delete menuFont; + delete copyrightFont; + delete levelNameFont; + + // Determine fonts for current language + std::string menuFontBasename; + std::string copyrightFontBasename; + std::string levelNameFontBasename; + strings.get("menu-font", &menuFontBasename); + strings.get("copyright-font", ©rightFontBasename); + strings.get("level-name-font", &levelNameFontBasename); + std::string fontsDirectory = appDataPath + "fonts/"; + + // Load fonts with the custom Unicode ranges + FontLoader* fontLoader = new FontLoader(); + + menuFont = new Font(512, 512); + if (!fontLoader->load(fontsDirectory + menuFontBasename, static_cast(fontSizePX + 0.5f), unicodeRanges, menuFont)) + { + std::cerr << "Failed to load menu font" << std::endl; + } + + copyrightFont = new Font(256, 256); + if (!fontLoader->load(fontsDirectory + copyrightFontBasename, static_cast(fontSizePX * 0.8f + 0.5f), unicodeRanges, copyrightFont)) + { + std::cerr << "Failed to load copyright font" << std::endl; + } + + levelNameFont = new Font(512, 512); + if (!fontLoader->load(fontsDirectory + levelNameFontBasename, static_cast(fontSizePX * 2.0f + 0.5f), unicodeRanges, levelNameFont)) + { + std::cerr << "Failed to load level name font" << std::endl; + } + + delete fontLoader; + + // Set fonts + levelNameLabel->setFont(levelNameFont); + frameTimeLabel->setFont(copyrightFont); + anyKeyLabel->setFont(menuFont); + mainMenu->setFont(menuFont); + levelsMenu->setFont(menuFont); + optionsMenu->setFont(menuFont); + pauseMenu->setFont(menuFont); // Title screen - anyKeyLabel->setText(pressAnyKeyString); + anyKeyLabel->setText(stringMap["press-any-key"]); // Main menu - mainMenuContinueItem->setName(continueString); - mainMenuLevelsItem->setName(levelsString); - mainMenuNewGameItem->setName(newGameString); - mainMenuSandboxItem->setName(sandboxString); - mainMenuOptionsItem->setName(optionsString); - mainMenuExitItem->setName(exitString); + mainMenuContinueItem->setName(stringMap["continue"]); + mainMenuLevelsItem->setName(stringMap["levels"]); + mainMenuNewGameItem->setName(stringMap["new-game"]); + mainMenuSandboxItem->setName(stringMap["sandbox"]); + mainMenuOptionsItem->setName(stringMap["options"]); + mainMenuExitItem->setName(stringMap["exit"]); // Levels menu std::size_t levelItemIndex = 0; @@ -1479,59 +1513,63 @@ void Application::restringUI() for (std::size_t level = 0; level < campaign.getLevelCount(world); ++level) { // Look up level name - std::string levelName = getLevelName(world, level); + std::u32string levelName = getLevelName(world, level); // Create label + /* + std::u32string label; std::stringstream stream; - stream << (world + 1) << "-" << (level + 1) << ": " << levelName; + stream << (world + 1) << "-" << (level + 1) << ": "; + label = std::wstring_convert, char32_t>().from_bytes(stream.str()) + levelName; + */ // Set item name MenuItem* levelItem = levelsMenu->getItem(levelItemIndex); - levelItem->setName(stream.str()); + levelItem->setName(levelName); ++levelItemIndex; } } - levelsMenuBackItem->setName(backString); + levelsMenuBackItem->setName(stringMap["back"]); // Options menu - optionsMenuWindowedResolutionItem->setName(windowedResolutionString); - optionsMenuFullscreenResolutionItem->setName(fullscreenResolutionString); + optionsMenuWindowedResolutionItem->setName(stringMap["windowed-resolution"]); + optionsMenuFullscreenResolutionItem->setName(stringMap["fullscreen-resolution"]); std::size_t resolutionIndex = 0; for (std::size_t i = 0; i < resolutions.size(); ++i) { + std::u32string label; std::stringstream stream; stream << resolutions[i].x << "x" << resolutions[i].y; + std::string streamstring = stream.str(); + label.assign(streamstring.begin(), streamstring.end()); - optionsMenuWindowedResolutionItem->setValueName(i, stream.str()); - optionsMenuFullscreenResolutionItem->setValueName(i, stream.str()); + optionsMenuWindowedResolutionItem->setValueName(i, label); + optionsMenuFullscreenResolutionItem->setValueName(i, label); } - optionsMenuFullscreenItem->setName(fullscreenString); - optionsMenuFullscreenItem->setValueName(0, offString); - optionsMenuFullscreenItem->setValueName(1, onString); - optionsMenuVSyncItem->setName(verticalSyncString); - optionsMenuVSyncItem->setValueName(0, offString); - optionsMenuVSyncItem->setValueName(1, onString); + optionsMenuFullscreenItem->setName(stringMap["fullscreen"]); + optionsMenuFullscreenItem->setValueName(0, stringMap["off"]); + optionsMenuFullscreenItem->setValueName(1, stringMap["on"]); + optionsMenuVSyncItem->setName(stringMap["vertical-sync"]); + optionsMenuVSyncItem->setValueName(0, stringMap["off"]); + optionsMenuVSyncItem->setValueName(1, stringMap["on"]); - optionsMenuLanguageItem->setName(languageString); + optionsMenuLanguageItem->setName(stringMap["language"]); for (std::size_t i = 0; i < languages.size(); ++i) { - std::string languageName; - strings.get(languages[i], &languageName); - - optionsMenuLanguageItem->setValueName(i, languageName); + optionsMenuLanguageItem->setValueName(i, stringMap[languages[i]]); } - optionsMenuControlsItem->setName(controlsString); - optionsMenuBackItem->setName(backString); + optionsMenuControlsItem->setName(stringMap["controls"]); + optionsMenuBackItem->setName(stringMap["back"]); // Pause menu - pauseMenuResumeItem->setName(resumeString); - pauseMenuLevelsItem->setName(levelsString); - pauseMenuOptionsItem->setName(optionsString); - pauseMenuMainMenuItem->setName(mainMenuString); - pauseMenuExitItem->setName(exitString); + pauseMenuResumeItem->setName(stringMap["resume"]); + pauseMenuLevelsItem->setName(stringMap["levels"]); + pauseMenuOptionsItem->setName(stringMap["options"]); + pauseMenuMainMenuItem->setName(stringMap["main-menu"]); + pauseMenuExitItem->setName(stringMap["exit"]); } void Application::openMenu(Menu* menu) @@ -1780,7 +1818,7 @@ void Application::setDisplayDebugInfo(bool display) depthTextureImage->setVisible(displayDebugInfo); } -std::string Application::getLevelName(std::size_t world, std::size_t level) const +std::u32string Application::getLevelName(std::size_t world, std::size_t level) const { // Form level ID string char levelIDBuffer[6]; @@ -1788,7 +1826,7 @@ std::string Application::getLevelName(std::size_t world, std::size_t level) cons std::string levelID(levelIDBuffer); // Look up level name - std::string levelName; + std::u32string levelName; strings.get(levelIDBuffer, &levelName); return levelName; @@ -1951,6 +1989,11 @@ void Application::selectLanguage(std::size_t index) settings.set("language", languages[languageIndex]); saveUserSettings(); + // Change window title + std::string title; + strings.get("title", &title); + SDL_SetWindowTitle(window, title.c_str()); + // Restring UI restringUI(); } diff --git a/src/application.hpp b/src/application.hpp index d199a1c..bc37a24 100644 --- a/src/application.hpp +++ b/src/application.hpp @@ -112,7 +112,7 @@ public: void setDisplayDebugInfo(bool display); - std::string getLevelName(std::size_t world, std::size_t level) const; + std::u32string getLevelName(std::size_t world, std::size_t level) const; // Options menu functions void selectWindowedResolution(std::size_t index); diff --git a/src/settings.hpp b/src/settings.hpp index 2b4e8ee..02d9c03 100644 --- a/src/settings.hpp +++ b/src/settings.hpp @@ -20,6 +20,8 @@ #ifndef SETTINGS_HPP #define SETTINGS_HPP +#include +#include #include #include #include @@ -36,6 +38,8 @@ public: bool load(const std::string& filename); bool save(const std::string& filename); void clear(); + + const std::map* getParameters() const; private: std::map parameters; @@ -69,6 +73,33 @@ inline bool ParameterDict::get(const std::string& name, std::string return true; } +template <> +inline bool ParameterDict::get(const std::string& name, std::u32string* value) const +{ + auto it = parameters.find(name); + if (it == parameters.end()) + return false; + + // Convert UTF-8 string to UTF-32 string + #if _MSC_VER >= 1900 + //std::wstring_convert, uint32_t> convert; + //*value = convert.from_bytes(it->second); + std::wstring_convert, uint32_t> convert; + auto uint32string = convert.from_bytes(it->second); + + value->resize(uint32string.size()); + for (std::size_t i = 0; i < uint32string.size(); ++i) + { + (*value)[i] = static_cast(uint32string[i]); + } + #else + std::wstring_convert, char32_t> convert; + *value = convert.from_bytes(it->second); + #endif + + return true; +} + template void ParameterDict::set(const std::string& name, const T& value) { @@ -77,5 +108,10 @@ void ParameterDict::set(const std::string& name, const T& value) parameters[name] = stream.str(); } +inline const std::map*ParameterDict:: getParameters() const +{ + return ¶meters; +} + #endif diff --git a/src/ui/menu.cpp b/src/ui/menu.cpp index 894f275..e2b7edf 100644 --- a/src/ui/menu.cpp +++ b/src/ui/menu.cpp @@ -101,7 +101,7 @@ void MenuItem::setValueChangedCallback(std::function callback this->valueChangedCallback = callback; } -void MenuItem::setName(const std::string& text) +void MenuItem::setName(const std::u32string& text) { nameLabel->setText(text); parent->resize(); @@ -109,7 +109,7 @@ void MenuItem::setName(const std::string& text) std::size_t MenuItem::addValue() { - values.push_back(std::string()); + values.push_back(std::u32string()); return (values.size() - 1); } @@ -117,11 +117,11 @@ void MenuItem::removeValues() { values.clear(); valueIndex = 0; - valueLabel->setText(std::string()); + valueLabel->setText(std::u32string()); parent->resize(); } -void MenuItem::setValueName(std::size_t index, const std::string& text) +void MenuItem::setValueName(std::size_t index, const std::u32string& text) { values[index] = text; diff --git a/src/ui/menu.hpp b/src/ui/menu.hpp index f7a8478..202e26c 100644 --- a/src/ui/menu.hpp +++ b/src/ui/menu.hpp @@ -39,14 +39,14 @@ public: void setActivatedCallback(std::function callback); void setValueChangedCallback(std::function callback); - void setName(const std::string& text); + void setName(const std::u32string& text); std::size_t addValue(); void removeValues(); - void setValueName(std::size_t index, const std::string& text); + void setValueName(std::size_t index, const std::u32string& text); void setValueIndex(std::size_t index); std::size_t getValueCount() const; - const std::string& getValue(std::size_t index) const; + const std::u32string& getValue(std::size_t index) const; std::size_t getValueIndex() const; @@ -68,7 +68,7 @@ private: std::function deselectedCallback; std::function activatedCallback; std::function valueChangedCallback; - std::vector values; + std::vector values; std::size_t valueIndex; UILabel* nameLabel; UILabel* valueLabel; @@ -85,7 +85,7 @@ inline std::size_t MenuItem::getValueCount() const return values.size(); } -inline const std::string& MenuItem::getValue(std::size_t index) const +inline const std::u32string& MenuItem::getValue(std::size_t index) const { return values[index]; } diff --git a/src/ui/ui.cpp b/src/ui/ui.cpp index 74103d1..5c3dd48 100644 --- a/src/ui/ui.cpp +++ b/src/ui/ui.cpp @@ -222,7 +222,7 @@ void UILabel::setFont(Font* font) calculateDimensions(); } -void UILabel::setText(const std::string& text) +void UILabel::setText(const std::u32string& text) { this->text = text; calculateDimensions(); @@ -232,7 +232,7 @@ void UILabel::calculateDimensions() { if (font != nullptr && !text.empty()) { - float width = font->getWidth(text.c_str()); + float width = font->getWidth(text); float height = font->getMetrics().getHeight(); setDimensions(Vector2(width, height)); } @@ -363,7 +363,7 @@ void UIBatcher::batchLabel(BillboardBatch* result, const UILabel* label) const Font* font = label->getFont(); std::size_t index = range->start + range->length; std::size_t count = 0; - font->puts(result, origin, label->getText().c_str(), label->getColor(), index, &count); + font->puts(result, origin, label->getText(), label->getColor(), index, &count); // Increment range length range->length += count; diff --git a/src/ui/ui.hpp b/src/ui/ui.hpp index 04117ff..e1e7bf6 100644 --- a/src/ui/ui.hpp +++ b/src/ui/ui.hpp @@ -351,17 +351,17 @@ public: virtual UIElement::Type getElementType() const; void setFont(Font* font); - void setText(const std::string& text); + void setText(const std::u32string& text); const Font* getFont() const; Font* getFont(); - const std::string& getText() const; + const std::u32string& getText() const; private: void calculateDimensions(); Font* font; - std::string text; + std::u32string text; }; inline UIElement::Type UILabel::getElementType() const @@ -379,7 +379,7 @@ inline Font* UILabel::getFont() return font; } -inline const std::string& UILabel::getText() const +inline const std::u32string& UILabel::getText() const { return text; }