1#include "TextElement.hpp"
2#include "RootDisplay.hpp"
11const char *TextElement::fontPaths[] = {
12 RAMFS
"./res/fonts/OpenSans-Regular.ttf",
13 RAMFS
"./res/fonts/UbuntuMono-Regular.ttf",
14 RAMFS
"./res/fonts/oldmono.ttf",
15 RAMFS
"./res/fonts/PTSerif-Regular.ttf",
16 RAMFS
"./res/fonts/NotoSansSC-Regular.ttf",
17 RAMFS
"./res/fonts/NotoSansKR-Regular.ttf",
18 RAMFS
"./res/fonts/NotoSansJP-Regular.ttf",
21std::map<std::string, std::string> TextElement::i18nCache = {};
22std::string TextElement::curLang =
"en-us";
24bool TextElement::useSimplifiedChineseFont =
false;
25bool TextElement::useKoreanFont =
false;
26bool TextElement::useJapaneseFont =
false;
29std::map<std::string, int> TextElement::forcedLangFonts = {};
31TextElement::TextElement()
36std::vector<std::pair<std::string, std::string>> TextElement::getAvailableLanguages() {
37 std::vector<std::pair<std::string, std::string>> languages;
39 std::string i18nPath = RAMFS
"res/i18n/";
40 DIR* dir = opendir(i18nPath.c_str());
43 while ((entry = readdir(dir)) != NULL) {
44 std::string fileName = entry->d_name;;
45 if (fileName.length() > 4 && fileName.substr(fileName.length() - 4) ==
".ini") {
46 std::string locale = fileName.substr(0, fileName.length() - 4);
48 std::transform(locale.begin(), locale.end(), locale.begin(), ::tolower);
50 std::ifstream file(i18nPath + fileName);
53 while (std::getline(file, line)) {
54 if (line.find(
"meta.lang.name = ") == 0) {
55 std::string langName = line.substr(strlen(
"meta.lang.name = "));
56 languages.push_back({locale, langName});
59 if (locale ==
"zh-cn") {
60 forcedLangFonts[langName] = SIMPLIFIED_CHINESE;
61 }
else if (locale ==
"ko-kr") {
62 forcedLangFonts[langName] = KOREAN;
63 }
else if (locale ==
"ja-jp") {
64 forcedLangFonts[langName] = JAPANESE;
66 forcedLangFonts[langName] = NORMAL;
81static void loadI18nFile(
const std::string& filePath, std::map<std::string, std::string>& cache) {
82 std::ifstream file(filePath);
85 while (std::getline(file, line)) {
86 size_t pos = line.find(
" =");
87 if (pos == std::string::npos) {
90 std::string key = line.substr(0, pos);
91 pos = line.find(
"= ");
92 if (pos == std::string::npos) {
95 std::string value = line.substr(pos + 2);
103void TextElement::loadI18nCache(std::string locale) {
104 std::transform(locale.begin(), locale.end(), locale.begin(), ::tolower);
105 TextElement::curLang = locale;
108 TextElement::i18nCache.clear();
111 std::string englishPath = RAMFS
"res/i18n/en-us.ini";
112 loadI18nFile(englishPath, TextElement::i18nCache);
115 if (locale !=
"en-us") {
116 std::string localePath = RAMFS
"res/i18n/" + locale +
".ini";
117 loadI18nFile(localePath, TextElement::i18nCache);
120 TextElement::useSimplifiedChineseFont =
false;
121 TextElement::useKoreanFont =
false;
122 TextElement::useJapaneseFont =
false;
124 if (locale ==
"zh-cn") {
125 printf(
"Overriding font choice for Simplified Chinese\n");
126 TextElement::useSimplifiedChineseFont =
true;
128 if (locale ==
"ko-kr") {
129 printf(
"Overriding font choice for Korean\n");
130 TextElement::useKoreanFont =
true;
132 if (locale ==
"ja-jp") {
133 printf(
"Overriding font choice for Japanese\n");
134 TextElement::useJapaneseFont =
true;
138TextElement::TextElement(std::string text,
int size, CST_Color* color,
int font_type,
int wrapped_width)
140 std::string sText = text;
143 if (color) setColor(*color);
145 setWrappedWidth(wrapped_width);
149void TextElement::setText(
const std::string& text)
154void TextElement::setSize(
int size)
156 this->textSize = size;
159void TextElement::setColor(
const CST_Color& color)
161 this->textColor = color;
164void TextElement::setFont(
int font_type)
166 this->textFont = font_type;
169void TextElement::setWrappedWidth(
int wrapped_width)
171 this->textWrappedWidth = wrapped_width;
176 std::string key = Texture::textElemPrefix + text + std::to_string(textSize);
182 int actualFont = textFont;
183 if (TextElement::useSimplifiedChineseFont && textFont == NORMAL) {
184 actualFont = SIMPLIFIED_CHINESE;
186 if (TextElement::useKoreanFont && textFont == NORMAL) {
189 if (TextElement::useJapaneseFont && textFont == NORMAL) {
190 actualFont = JAPANESE;
194 if (forcedLangFonts.find(text) != forcedLangFonts.end()) {
195 actualFont = forcedLangFonts[text];
198 auto fontPath = fontPaths[actualFont % 7];
199 if (customFontPath !=
"") {
200 fontPath = customFontPath.c_str();
203 TTF_Font* font = TTF_OpenFont(fontPath, textSize);
206 printf(
"TTF_OpenFont failed for '%s' at size %d: %s\n", fontPath, textSize, TTF_GetError());
212 CST_Surface *textSurface = ((actualFont == ICON) || (textWrappedWidth == 0)) ?
213 TTF_RenderUTF8_Blended(font, text.c_str(), textColor) :
214 TTF_RenderUTF8_Blended_Wrapped(font, text.c_str(), textColor, textWrappedWidth);
215 if(textSurface==NULL) printf(
"TTF_GetError: %s\n", TTF_GetError());
219 CST_FreeSurface(textSurface);
226std::string i18n(std::string key) {
227 if (
const auto& keyItr = TextElement::i18nCache.find(key); keyItr != TextElement::i18nCache.end()) {
228 return keyItr->second;
233std::string i18n_number(
int number) {
234 std::string decimalSeparator = i18n(
"number.decimal");
235 std::string thousandsSeparator = i18n(
"number.thousands");
236 if (decimalSeparator.empty()) {
237 decimalSeparator =
".";
239 if (thousandsSeparator.empty()) {
240 thousandsSeparator =
",";
242 std::string numberString = std::to_string(number);
243 size_t decimalPos = numberString.find(
".");
244 if (decimalPos == std::string::npos) {
245 decimalPos = numberString.length();
247 std::string integerPart = numberString.substr(0, decimalPos);
248 std::string decimalPart = numberString.substr(decimalPos);
249 if (decimalPart.length() > 0) {
250 decimalPart = decimalSeparator + decimalPart.substr(1);
252 for (
int i = integerPart.length() - 3; i > 0; i -= 3) {
253 integerPart.insert(i, thousandsSeparator);
255 return integerPart + decimalPart;
258std::string i18n_date(
int timestamp) {
259 std::string dateFormatString = i18n(
"date.format");
260 if (dateFormatString.empty()) {
261 dateFormatString =
"%Y-%m-%d";
264 time_t timestamp2 =
static_cast<time_t
>(timestamp);
266 struct tm* timeinfo = localtime(×tamp2);
268 strftime(buffer,
sizeof(buffer), dateFormatString.c_str(), timeinfo);
269 return std::string(buffer);
int width
width and height of this element (must be manually set, isn't usually calculated (but is in some case...
void update(bool forceUpdate=false)
update TextElement with changes
bool loadFromSurfaceSaveToCache(std::string &key, CST_Surface *surface)
Loads the texture from a surface and saves the results in caches Returns true if successful.
void clear(void)
Reinitialize Texture Resets texture content, size and color.
bool loadFromCache(std::string &key)
Loads the texture from caches Returns true if successful.
void getTextureSize(int *w, int *h)
Return texture's original size.