Chesto 0.9
A declarative and element-based library for creating GUIs on homebrew'd consoles
TextElement.cpp
1#include "TextElement.hpp"
2#include "RootDisplay.hpp"
3#include <fstream>
4#include <ctime> // std::time
5
6const char *TextElement::fontPaths[] = {
7 RAMFS "./res/fonts/OpenSans-Regular.ttf", // 0 = NORMAL
8 RAMFS "./res/fonts/UbuntuMono-Regular.ttf", // 1 = MONOSPACED
9 RAMFS "./res/fonts/oldmono.ttf", // 2 = OLD_MONOSPACED
10 RAMFS "./res/fonts/PTSerif-Regular.ttf", // 3 = SERIF
11 RAMFS "./res/fonts/NotoSansSC-Regular.ttf", // 4 = SIMPLIFIED_CHINESE
12};
13
14std::unordered_map<std::string, std::string> TextElement::i18nCache = {};
15
16bool TextElement::useSimplifiedChineseFont = false;
17
18TextElement::TextElement()
19{
20}
21
22// static method to load i18n cache
23void TextElement::loadI18nCache(std::string locale) {
24 // en-us, zh-cn
25 std::string localePath = RAMFS "res/i18n/" + locale + ".ini";
26 std::ifstream file(localePath);
27 // printf("Loading i18n cache from %s\n", localePath.c_str());
28 if (file.is_open()) {
29 std::string line;
30 while (std::getline(file, line)) {
31 size_t pos = line.find(" =");
32 if (pos == std::string::npos) {
33 continue; // bad format
34 }
35 std::string key = line.substr(0, pos);
36 pos = line.find("= ");
37 if (pos == std::string::npos) {
38 continue;
39 }
40 std::string value = line.substr(pos + 2);
41 TextElement::i18nCache[key] = value;
42 // printf("Loaded i18n key %s with value %s\n", key.c_str(), value.c_str());
43 }
44 file.close();
45
46 // if locale is zh-cn, we need to force the simple chinese font
47 if (locale == "zh-cn") {
48 printf("Overriding font choice\n");
49 TextElement::useSimplifiedChineseFont = true;
50 }
51 }
52}
53
54TextElement::TextElement(std::string text, int size, CST_Color* color, int font_type, int wrapped_width)
55{
56 std::string sText = text;
57 setText(sText);
58 setSize(size);
59 if (color) setColor(*color);
60 setFont(font_type);
61 setWrappedWidth(wrapped_width);
62 update();
63}
64
65void TextElement::setText(const std::string& text)
66{
67 this->text = text;
68}
69
70void TextElement::setSize(int size)
71{
72 this->textSize = size;
73}
74
75void TextElement::setColor(const CST_Color& color)
76{
77 this->textColor = color;
78}
79
80void TextElement::setFont(int font_type)
81{
82 this->textFont = font_type;
83}
84
85void TextElement::setWrappedWidth(int wrapped_width)
86{
87 this->textWrappedWidth = wrapped_width;
88}
89
90void TextElement::update(bool forceUpdate)
91{
92 std::string key = text + std::to_string(textSize);
93
94 clear();
95
96 if (!loadFromCache(key) || forceUpdate)
97 {
98 if (TextElement::useSimplifiedChineseFont && textFont == NORMAL) {
99 textFont = SIMPLIFIED_CHINESE;
100 }
101 auto fontPath = fontPaths[textFont % 5];
102 if (customFontPath != "") {
103 fontPath = customFontPath.c_str();
104 }
105 TTF_Font* font = TTF_OpenFont(fontPath, textSize);
106
107 CST_Surface *textSurface = ((textFont == ICON) || (textWrappedWidth == 0)) ?
108 TTF_RenderUTF8_Blended(font, text.c_str(), textColor) :
109 TTF_RenderUTF8_Blended_Wrapped(font, text.c_str(), textColor, textWrappedWidth);
110 if(textSurface==NULL) printf("TTF_GetError: %s\n", TTF_GetError());
111
112 loadFromSurfaceSaveToCache(key, textSurface);
113
114 CST_FreeSurface(textSurface);
115 TTF_CloseFont(font);
116 }
117
118 getTextureSize(&width, &height);
119}
120
121std::string i18n(std::string key) {
122 if (const auto& keyItr = TextElement::i18nCache.find(key); keyItr != TextElement::i18nCache.end()) {
123 return keyItr->second;
124 }
125 return key;
126}
127
128std::string i18n_number(int number) {
129 std::string decimalSeparator = i18n("number.decimal");
130 std::string thousandsSeparator = i18n("number.thousands");
131 if (decimalSeparator.empty()) {
132 decimalSeparator = ".";
133 }
134 if (thousandsSeparator.empty()) {
135 thousandsSeparator = ",";
136 }
137 std::string numberString = std::to_string(number);
138 size_t decimalPos = numberString.find(".");
139 if (decimalPos == std::string::npos) {
140 decimalPos = numberString.length();
141 }
142 std::string integerPart = numberString.substr(0, decimalPos);
143 std::string decimalPart = numberString.substr(decimalPos);
144 if (decimalPart.length() > 0) {
145 decimalPart = decimalSeparator + decimalPart.substr(1);
146 }
147 for (int i = integerPart.length() - 3; i > 0; i -= 3) {
148 integerPart.insert(i, thousandsSeparator);
149 }
150 return integerPart + decimalPart;
151}
152
153std::string i18n_date(int timestamp) {
154 std::string dateFormatString = i18n("date.format");
155 if (dateFormatString.empty()) {
156 dateFormatString = "%Y-%m-%d";
157 }
158 // convert int to time_t
159 time_t timestamp2 = static_cast<time_t>(timestamp);
160
161 struct tm* timeinfo = localtime(&timestamp2);
162 char buffer[256];
163 strftime(buffer, sizeof(buffer), dateFormatString.c_str(), timeinfo);
164 return std::string(buffer);
165}
int width
width and height of this element (must be manually set, isn't usually calculated (but is in some case...
Definition: Element.hpp:123
void update(bool forceUpdate=false)
update TextElement with changes
Definition: TextElement.cpp:90
void getTextureSize(int *w, int *h)
Return texture's original size.
Definition: Texture.cpp:199
bool loadFromSurfaceSaveToCache(std::string &key, CST_Surface *surface)
Loads the texture from a surface and saves the results in caches Returns true if successful.
Definition: Texture.cpp:92
bool loadFromCache(std::string &key)
Loads the texture from caches Returns true if successful.
Definition: Texture.cpp:77
void clear(void)
Reinitialize Texture Resets texture content, size and color.
Definition: Texture.cpp:9