Date: | 2013-07-05 20:07:46 (10 years 8 months ago) |
---|---|
Author: | Paul Cercueil |
Commit: | 46386a2054dfd7d302af65cc6434cf3410fc8fad |
Message: | Drop the bitmap font; use a TTF font instead This allows to display UTF-8 characters, and is as such a good step towards full internationalization. |
Files: |
configure.in (1 diff) src/asfont.cpp (2 diffs) src/asfont.h (2 diffs) src/gmenu2x.cpp (1 diff) src/link.cpp (1 diff) |
Change Details
configure.in | ||
---|---|---|
21 | 21 | |
22 | 22 | AC_CHECK_LIB(SDL_gfx, rotozoomSurfaceXY,,check_sdl_gfx="no") |
23 | 23 | |
24 | AC_CHECK_LIB(SDL_ttf, TTF_OpenFont) | |
25 | ||
24 | 26 | # Check for libpng |
25 | 27 | AC_CHECK_LIB(png, png_read_image,,check_png="no") |
26 | 28 |
src/asfont.cpp | ||
---|---|---|
1 | 1 | #include "asfont.h" |
2 | #include "imageio.h" | |
2 | #include "debug.h" | |
3 | 3 | #include "surface.h" |
4 | 4 | #include "utilities.h" |
5 | 5 | |
6 | #include <algorithm> | |
7 | #include <cassert> | |
8 | #include <cstring> | |
6 | #include <SDL.h> | |
7 | #include <SDL_ttf.h> | |
8 | #include <vector> | |
9 | 9 | |
10 | #define SFONTPLUS_CHARSET "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~¡¿ÀÁÈÉÌÍÒÓÙÚÝÄËÏÖÜŸÂÊÎÔÛÅÃÕÑÆÇČĎĚĽĹŇÔŘŔŠŤŮŽàáèéìíòóùúýäëïöüÿâêîôûåãõñæçčďěľĺňôřŕšťžůðßÐÞþАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюяØøąćęłńśżźĄĆĘŁŃŚŻŹ" | |
10 | /* TODO: Let the theme choose the font and font size */ | |
11 | #define TTF_FONT "/usr/share/fonts/truetype/dejavu/DejaVuSansCondensed.ttf" | |
12 | #define TTF_FONT_SIZE 12 | |
11 | 13 | |
12 | ASFont::ASFont(const std::string &fontImagePath) | |
13 | : characters(SFONTPLUS_CHARSET) | |
14 | using namespace std; | |
15 | ||
16 | ASFont::ASFont(const string &path) | |
14 | 17 | { |
15 | surface = loadPNG(fontImagePath); | |
16 | if (!surface) { | |
18 | if (!TTF_WasInit() && TTF_Init() < 0) { | |
19 | ERROR("Unable to init SDL_ttf library\n"); | |
17 | 20 | return; |
18 | 21 | } |
19 | assert(surface->format->BytesPerPixel == 4); | |
20 | ||
21 | SDL_LockSurface(surface); | |
22 | ||
23 | // Determine character widths. | |
24 | Uint32 pink = SDL_MapRGB(surface->format, 255, 0, 255); | |
25 | Uint32 *topLine = static_cast<Uint32 *>(surface->pixels); | |
26 | const unsigned width = surface->w; | |
27 | unsigned x = 0; | |
28 | unsigned c = 0; | |
29 | while (c < characters.length()) { | |
30 | while (x < width && topLine[x] != pink) x++; | |
31 | unsigned startx = x; | |
32 | x++; | |
33 | while (x < width && topLine[x] == pink) x++; | |
34 | ||
35 | charpos.push_back(startx); | |
36 | charpos.push_back(x); | |
37 | if (c > 0 && utf8Code(characters[c - 1])) { | |
38 | // UTF8 character | |
39 | charpos.push_back(startx); | |
40 | charpos.push_back(x); | |
41 | c++; | |
42 | } | |
43 | c++; | |
44 | } | |
45 | 22 | |
46 | // Scan height of "0" glyph. | |
47 | std::string::size_type pos = characters.find("0") * 2; | |
48 | SDL_Rect srcrect = { | |
49 | static_cast<Sint16>(charpos[pos]), | |
50 | 1, | |
51 | static_cast<Uint16>(charpos[pos + 2] - charpos[pos]), | |
52 | static_cast<Uint16>(surface->h - 1) | |
53 | }; | |
54 | const unsigned alphaMask = surface->format->Amask; | |
55 | unsigned y = srcrect.h; | |
56 | bool nonTransparentFound = false; | |
57 | while (!nonTransparentFound && y-- > 0) { | |
58 | Uint32 *line = reinterpret_cast<Uint32 *>( | |
59 | reinterpret_cast<Uint8 *>(surface->pixels) | |
60 | + (srcrect.y + y) * surface->pitch | |
61 | ); | |
62 | for (unsigned x = 0; !nonTransparentFound && x < srcrect.w; x++) { | |
63 | nonTransparentFound = (line[srcrect.x + x] & alphaMask) != 0; | |
64 | } | |
23 | font = TTF_OpenFont(TTF_FONT, TTF_FONT_SIZE); | |
24 | if (!font) { | |
25 | ERROR("Unable to open font\n"); | |
26 | return; | |
65 | 27 | } |
66 | lineHeight = y + 1; | |
67 | 28 | |
68 | SDL_UnlockSurface(surface); | |
29 | fontheight = TTF_FontHeight(font); | |
69 | 30 | } |
70 | 31 | |
71 | ASFont::~ASFont() { | |
72 | if (surface) { | |
73 | SDL_FreeSurface(surface); | |
74 | } | |
32 | ASFont::~ASFont() | |
33 | { | |
34 | TTF_CloseFont(font); | |
35 | TTF_Quit(); | |
75 | 36 | } |
76 | 37 | |
77 | bool ASFont::utf8Code(unsigned char c) { | |
78 | return (c>=194 && c<=198) || c==208 || c==209; | |
79 | //return c>=194; | |
38 | int ASFont::getTextWidth(const char *text) | |
39 | { | |
40 | int w, h; | |
41 | TTF_SizeUTF8(font, text, &w, &h); | |
42 | return w; | |
80 | 43 | } |
81 | 44 | |
82 | void ASFont::writeLine(Surface *s, const std::string &text, int x, int y) { | |
83 | if (text.empty()) return; | |
84 | ||
85 | std::string::size_type pos; | |
86 | SDL_Rect srcrect, dstrect; | |
87 | ||
88 | // these values won't change in the loop | |
89 | srcrect.y = 1; | |
90 | dstrect.y = y; | |
91 | srcrect.h = dstrect.h = surface->h-1; | |
92 | ||
93 | for(unsigned i=0; i<text.length() && x<surface->w; i++) { | |
94 | //Utf8 characters | |
95 | if (utf8Code(text[i]) && i+1<text.length()) { | |
96 | pos = characters.find(text.substr(i,2)); | |
97 | i++; | |
98 | } else | |
99 | pos = characters.find(text[i]); | |
100 | if (pos == std::string::npos) { | |
101 | x += charpos[2]-charpos[1]; | |
102 | continue; | |
103 | } | |
104 | ||
105 | pos *= 2; | |
106 | ||
107 | srcrect.x = charpos[pos]; | |
108 | srcrect.w = charpos[pos+2] - charpos[pos]; | |
109 | dstrect.x = x - charpos[pos+1] + charpos[pos]; | |
110 | ||
111 | SDL_BlitSurface(surface, &srcrect, s->raw, &dstrect); | |
112 | ||
113 | x += charpos[pos+2] - charpos[pos+1]; | |
45 | void ASFont::write(Surface *surface, const string &text, | |
46 | int x, int y, HAlign halign, VAlign valign) | |
47 | { | |
48 | if (text.find("\n", 0) == string::npos) { | |
49 | writeLine(surface, text.c_str(), x, y, halign, valign); | |
50 | return; | |
114 | 51 | } |
115 | } | |
116 | 52 | |
117 | int ASFont::getTextWidth(const char *text) { | |
118 | int maxWidth = 0, width = 0; | |
119 | while (char ch = *text++) { | |
120 | if (ch == '\n') { | |
121 | // New line. | |
122 | maxWidth = std::max(width, maxWidth); | |
123 | width = 0; | |
124 | } else { | |
125 | std::string::size_type pos; | |
126 | if (utf8Code(ch) && *text) { | |
127 | // 2-byte character. | |
128 | pos = characters.find(std::string(&text[-1], 2)); | |
129 | text++; | |
130 | } else { | |
131 | // 1-byte character. | |
132 | pos = characters.find(ch); | |
133 | } | |
134 | if (pos == std::string::npos) { | |
135 | pos = 0; | |
136 | } | |
137 | width += charpos[pos * 2 + 2] - charpos[pos * 2 + 1]; | |
138 | } | |
139 | } | |
140 | return std::max(width, maxWidth); | |
141 | } | |
53 | vector<string> v; | |
54 | split(v, text, "\n"); | |
142 | 55 | |
143 | int ASFont::getTextWidth(const std::string& text) { | |
144 | return getTextWidth(text.c_str()); | |
56 | for (vector<string>::const_iterator it = v.begin(); it != v.end(); it++) { | |
57 | writeLine(surface, it->c_str(), x, y, halign, valign); | |
58 | y += fontheight; | |
59 | } | |
145 | 60 | } |
146 | 61 | |
147 | void ASFont::writeLine(Surface* surface, const std::string& text, int x, int y, HAlign halign) { | |
62 | void ASFont::writeLine(Surface *surface, const char *text, | |
63 | int x, int y, HAlign halign, VAlign valign) | |
64 | { | |
148 | 65 | switch (halign) { |
149 | 66 | case HAlignLeft: |
150 | 67 | break; |
... | ... | |
155 | 72 | x -= getTextWidth(text); |
156 | 73 | break; |
157 | 74 | } |
158 | writeLine(surface, text, x, y); | |
159 | } | |
160 | 75 | |
161 | void ASFont::writeLine(Surface* surface, const std::string& text, int x, int y, HAlign halign, VAlign valign) { | |
162 | 76 | switch (valign) { |
163 | 77 | case VAlignTop: |
164 | 78 | break; |
165 | 79 | case VAlignMiddle: |
166 | y -= getHeight() / 2; | |
80 | y -= fontheight / 2; | |
167 | 81 | break; |
168 | 82 | case VAlignBottom: |
169 | y -= getHeight(); | |
83 | y -= fontheight; | |
170 | 84 | break; |
171 | 85 | } |
172 | writeLine(surface, text, x, y, halign); | |
173 | } | |
174 | 86 | |
175 | void ASFont::writeLine(Surface* surface, const std::vector<std::string> &text, int x, int y, HAlign halign, VAlign valign) { | |
176 | switch (valign) { | |
177 | case VAlignTop: | |
178 | break; | |
179 | case VAlignMiddle: | |
180 | y -= (getHeight() / 2) * text.size(); | |
181 | break; | |
182 | case VAlignBottom: | |
183 | y -= getHeight() * text.size(); | |
184 | break; | |
185 | } | |
87 | SDL_Color color = { 0, 0, 0, 0 }; | |
88 | SDL_Surface *s = TTF_RenderUTF8_Blended(font, text, color); | |
186 | 89 | |
187 | for (std::vector<std::string>::const_iterator it = text.begin(); it != text.end(); ++it) { | |
188 | write(surface, *it, x, y, halign); | |
189 | y += getHeight(); | |
190 | } | |
191 | } | |
90 | SDL_Rect rect = { (Sint16) x, (Sint16) (y - 1), 0, 0 }; | |
91 | SDL_BlitSurface(s, NULL, surface->raw, &rect); | |
92 | ||
93 | /* Note: rect.x / rect.y are reset everytime because SDL_BlitSurface | |
94 | * will modify them if negative */ | |
95 | rect.x = x; | |
96 | rect.y = y + 1; | |
97 | SDL_BlitSurface(s, NULL, surface->raw, &rect); | |
98 | ||
99 | rect.x = x - 1; | |
100 | rect.y = y; | |
101 | SDL_BlitSurface(s, NULL, surface->raw, &rect); | |
102 | ||
103 | rect.x = x + 1; | |
104 | rect.y = y; | |
105 | SDL_BlitSurface(s, NULL, surface->raw, &rect); | |
106 | SDL_FreeSurface(s); | |
107 | ||
108 | rect.x = x; | |
109 | rect.y = y; | |
110 | color.r = 0xff; | |
111 | color.g = 0xff; | |
112 | color.b = 0xff; | |
192 | 113 | |
193 | void ASFont::write(Surface* surface, const std::string& text, int x, int y, HAlign halign, VAlign valign) { | |
194 | if (text.find("\n", 0) != std::string::npos) { | |
195 | std::vector<std::string> textArr; | |
196 | split(textArr, text, "\n"); | |
197 | writeLine(surface, textArr, x, y, halign, valign); | |
198 | } else | |
199 | writeLine(surface, text, x, y, halign, valign); | |
114 | s = TTF_RenderUTF8_Blended(font, text, color); | |
115 | SDL_BlitSurface(s, NULL, surface->raw, &rect); | |
116 | SDL_FreeSurface(s); | |
200 | 117 | } |
src/asfont.h | ||
---|---|---|
6 | 6 | #ifndef ASFONT_H |
7 | 7 | #define ASFONT_H |
8 | 8 | |
9 | #include <SDL.h> | |
9 | #include <SDL_ttf.h> | |
10 | 10 | #include <string> |
11 | 11 | #include <vector> |
12 | 12 | |
... | ... | |
20 | 20 | ASFont(const std::string &font); |
21 | 21 | ~ASFont(); |
22 | 22 | |
23 | bool utf8Code(unsigned char c); | |
24 | ||
25 | 23 | int getTextWidth(const char *text); |
26 | int getTextWidth(const std::string& text); | |
27 | 24 | |
28 | int getHeight() { | |
29 | return surface->h - 1; | |
25 | int getTextWidth(const std::string& text) | |
26 | { | |
27 | return getTextWidth(text.c_str()); | |
30 | 28 | } |
31 | int getLineHeight() { | |
32 | return lineHeight; | |
29 | ||
30 | bool utf8Code(unsigned char c) | |
31 | { | |
32 | return (c>=194 && c<=198) || c==208 || c==209; | |
33 | 33 | } |
34 | 34 | |
35 | void write(Surface* surface, const std::string& text, int x, int y, HAlign halign = HAlignLeft, VAlign valign = VAlignTop); | |
35 | int getHeight() | |
36 | { | |
37 | return fontheight; | |
38 | } | |
39 | ||
40 | void write(Surface *surface, | |
41 | const std::string &text, int x, int y, | |
42 | HAlign halign = HAlignLeft, VAlign valign = VAlignTop); | |
36 | 43 | |
37 | 44 | private: |
38 | void writeLine(Surface *surface, const std::string &text, int x, int y); | |
39 | void writeLine(Surface *surface, const std::string &text, int x, int y, HAlign halign); | |
40 | void writeLine(Surface *surface, const std::string &text, int x, int y, HAlign halign, VAlign valign); | |
41 | void writeLine(Surface *surface, const std::vector<std::string> &text, int x, int y, HAlign halign, VAlign valign); | |
42 | ||
43 | SDL_Surface *surface; | |
44 | std::vector<Uint16> charpos; | |
45 | std::string characters; | |
46 | int lineHeight; | |
45 | void writeLine(Surface *surface, const char *text, | |
46 | int x, int y, HAlign halign, VAlign valign); | |
47 | ||
48 | TTF_Font *font; | |
49 | unsigned int fontheight; | |
47 | 50 | }; |
48 | 51 | |
49 | 52 | #endif /* ASFONT_H */ |
src/gmenu2x.cpp | ||
---|---|---|
647 | 647 | uint linksPerPage = linkColumns*linkRows; |
648 | 648 | int linkSpacingX = (resX-10 - linkColumns*skinConfInt["linkWidth"])/linkColumns; |
649 | 649 | int linkSpacingY = (resY-35 - skinConfInt["topBarHeight"] - linkRows*skinConfInt["linkHeight"])/linkRows; |
650 | uint sectionLinkPadding = (skinConfInt["topBarHeight"] - 32 - font->getLineHeight()) / 3; | |
650 | uint sectionLinkPadding = (skinConfInt["topBarHeight"] - 32 - font->getHeight()) / 3; | |
651 | 651 | |
652 | 652 | bool quit = false; |
653 | 653 | int x,y; |
src/link.cpp | ||
---|---|---|
137 | 137 | |
138 | 138 | void Link::recalcCoordinates() { |
139 | 139 | iconX = rect.x+(rect.w-32)/2; |
140 | padding = (gmenu2x->skinConfInt["linkHeight"] - 32 - gmenu2x->font->getLineHeight()) / 3; | |
140 | padding = (gmenu2x->skinConfInt["linkHeight"] - 32 - gmenu2x->font->getHeight()) / 3; | |
141 | 141 | } |
142 | 142 | |
143 | 143 | void Link::run() { |
Branches:
install_locations
master
opkrun
packages