1
0
mirror of git://projects.qi-hardware.com/gmenu2x.git synced 2024-11-29 17:17:31 +02:00

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.
This commit is contained in:
Paul Cercueil 2013-07-05 14:07:46 -04:00
parent eb63294231
commit 46386a2054
5 changed files with 103 additions and 181 deletions

View File

@ -21,6 +21,8 @@ AC_ARG_WITH(sdl-gfx-prefix,
AC_CHECK_LIB(SDL_gfx, rotozoomSurfaceXY,,check_sdl_gfx="no") AC_CHECK_LIB(SDL_gfx, rotozoomSurfaceXY,,check_sdl_gfx="no")
AC_CHECK_LIB(SDL_ttf, TTF_OpenFont)
# Check for libpng # Check for libpng
AC_CHECK_LIB(png, png_read_image,,check_png="no") AC_CHECK_LIB(png, png_read_image,,check_png="no")

View File

@ -1,150 +1,67 @@
#include "asfont.h" #include "asfont.h"
#include "imageio.h" #include "debug.h"
#include "surface.h" #include "surface.h"
#include "utilities.h" #include "utilities.h"
#include <algorithm> #include <SDL.h>
#include <cassert> #include <SDL_ttf.h>
#include <cstring> #include <vector>
#define SFONTPLUS_CHARSET "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~¡¿ÀÁÈÉÌÍÒÓÙÚÝÄËÏÖÜŸÂÊÎÔÛÅÃÕÑÆÇČĎĚĽĹŇÔŘŔŠŤŮŽàáèéìíòóùúýäëïöüÿâêîôûåãõñæçčďěľĺňôřŕšťžůðßÐÞþАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюяØøąćęłńśżźĄĆĘŁŃŚŻŹ" /* TODO: Let the theme choose the font and font size */
#define TTF_FONT "/usr/share/fonts/truetype/dejavu/DejaVuSansCondensed.ttf"
#define TTF_FONT_SIZE 12
ASFont::ASFont(const std::string &fontImagePath) using namespace std;
: characters(SFONTPLUS_CHARSET)
ASFont::ASFont(const string &path)
{ {
surface = loadPNG(fontImagePath); if (!TTF_WasInit() && TTF_Init() < 0) {
if (!surface) { ERROR("Unable to init SDL_ttf library\n");
return; return;
} }
assert(surface->format->BytesPerPixel == 4);
SDL_LockSurface(surface); font = TTF_OpenFont(TTF_FONT, TTF_FONT_SIZE);
if (!font) {
// Determine character widths. ERROR("Unable to open font\n");
Uint32 pink = SDL_MapRGB(surface->format, 255, 0, 255); return;
Uint32 *topLine = static_cast<Uint32 *>(surface->pixels);
const unsigned width = surface->w;
unsigned x = 0;
unsigned c = 0;
while (c < characters.length()) {
while (x < width && topLine[x] != pink) x++;
unsigned startx = x;
x++;
while (x < width && topLine[x] == pink) x++;
charpos.push_back(startx);
charpos.push_back(x);
if (c > 0 && utf8Code(characters[c - 1])) {
// UTF8 character
charpos.push_back(startx);
charpos.push_back(x);
c++;
}
c++;
} }
// Scan height of "0" glyph. fontheight = TTF_FontHeight(font);
std::string::size_type pos = characters.find("0") * 2;
SDL_Rect srcrect = {
static_cast<Sint16>(charpos[pos]),
1,
static_cast<Uint16>(charpos[pos + 2] - charpos[pos]),
static_cast<Uint16>(surface->h - 1)
};
const unsigned alphaMask = surface->format->Amask;
unsigned y = srcrect.h;
bool nonTransparentFound = false;
while (!nonTransparentFound && y-- > 0) {
Uint32 *line = reinterpret_cast<Uint32 *>(
reinterpret_cast<Uint8 *>(surface->pixels)
+ (srcrect.y + y) * surface->pitch
);
for (unsigned x = 0; !nonTransparentFound && x < srcrect.w; x++) {
nonTransparentFound = (line[srcrect.x + x] & alphaMask) != 0;
}
}
lineHeight = y + 1;
SDL_UnlockSurface(surface);
} }
ASFont::~ASFont() { ASFont::~ASFont()
if (surface) { {
SDL_FreeSurface(surface); TTF_CloseFont(font);
TTF_Quit();
}
int ASFont::getTextWidth(const char *text)
{
int w, h;
TTF_SizeUTF8(font, text, &w, &h);
return w;
}
void ASFont::write(Surface *surface, const string &text,
int x, int y, HAlign halign, VAlign valign)
{
if (text.find("\n", 0) == string::npos) {
writeLine(surface, text.c_str(), x, y, halign, valign);
return;
}
vector<string> v;
split(v, text, "\n");
for (vector<string>::const_iterator it = v.begin(); it != v.end(); it++) {
writeLine(surface, it->c_str(), x, y, halign, valign);
y += fontheight;
} }
} }
bool ASFont::utf8Code(unsigned char c) { void ASFont::writeLine(Surface *surface, const char *text,
return (c>=194 && c<=198) || c==208 || c==209; int x, int y, HAlign halign, VAlign valign)
//return c>=194; {
}
void ASFont::writeLine(Surface *s, const std::string &text, int x, int y) {
if (text.empty()) return;
std::string::size_type pos;
SDL_Rect srcrect, dstrect;
// these values won't change in the loop
srcrect.y = 1;
dstrect.y = y;
srcrect.h = dstrect.h = surface->h-1;
for(unsigned i=0; i<text.length() && x<surface->w; i++) {
//Utf8 characters
if (utf8Code(text[i]) && i+1<text.length()) {
pos = characters.find(text.substr(i,2));
i++;
} else
pos = characters.find(text[i]);
if (pos == std::string::npos) {
x += charpos[2]-charpos[1];
continue;
}
pos *= 2;
srcrect.x = charpos[pos];
srcrect.w = charpos[pos+2] - charpos[pos];
dstrect.x = x - charpos[pos+1] + charpos[pos];
SDL_BlitSurface(surface, &srcrect, s->raw, &dstrect);
x += charpos[pos+2] - charpos[pos+1];
}
}
int ASFont::getTextWidth(const char *text) {
int maxWidth = 0, width = 0;
while (char ch = *text++) {
if (ch == '\n') {
// New line.
maxWidth = std::max(width, maxWidth);
width = 0;
} else {
std::string::size_type pos;
if (utf8Code(ch) && *text) {
// 2-byte character.
pos = characters.find(std::string(&text[-1], 2));
text++;
} else {
// 1-byte character.
pos = characters.find(ch);
}
if (pos == std::string::npos) {
pos = 0;
}
width += charpos[pos * 2 + 2] - charpos[pos * 2 + 1];
}
}
return std::max(width, maxWidth);
}
int ASFont::getTextWidth(const std::string& text) {
return getTextWidth(text.c_str());
}
void ASFont::writeLine(Surface* surface, const std::string& text, int x, int y, HAlign halign) {
switch (halign) { switch (halign) {
case HAlignLeft: case HAlignLeft:
break; break;
@ -155,46 +72,46 @@ void ASFont::writeLine(Surface* surface, const std::string& text, int x, int y,
x -= getTextWidth(text); x -= getTextWidth(text);
break; break;
} }
writeLine(surface, text, x, y);
}
void ASFont::writeLine(Surface* surface, const std::string& text, int x, int y, HAlign halign, VAlign valign) {
switch (valign) { switch (valign) {
case VAlignTop: case VAlignTop:
break; break;
case VAlignMiddle: case VAlignMiddle:
y -= getHeight() / 2; y -= fontheight / 2;
break; break;
case VAlignBottom: case VAlignBottom:
y -= getHeight(); y -= fontheight;
break;
}
writeLine(surface, text, x, y, halign);
}
void ASFont::writeLine(Surface* surface, const std::vector<std::string> &text, int x, int y, HAlign halign, VAlign valign) {
switch (valign) {
case VAlignTop:
break;
case VAlignMiddle:
y -= (getHeight() / 2) * text.size();
break;
case VAlignBottom:
y -= getHeight() * text.size();
break; break;
} }
for (std::vector<std::string>::const_iterator it = text.begin(); it != text.end(); ++it) { SDL_Color color = { 0, 0, 0, 0 };
write(surface, *it, x, y, halign); SDL_Surface *s = TTF_RenderUTF8_Blended(font, text, color);
y += getHeight();
}
}
void ASFont::write(Surface* surface, const std::string& text, int x, int y, HAlign halign, VAlign valign) { SDL_Rect rect = { (Sint16) x, (Sint16) (y - 1), 0, 0 };
if (text.find("\n", 0) != std::string::npos) { SDL_BlitSurface(s, NULL, surface->raw, &rect);
std::vector<std::string> textArr;
split(textArr, text, "\n"); /* Note: rect.x / rect.y are reset everytime because SDL_BlitSurface
writeLine(surface, textArr, x, y, halign, valign); * will modify them if negative */
} else rect.x = x;
writeLine(surface, text, x, y, halign, valign); rect.y = y + 1;
SDL_BlitSurface(s, NULL, surface->raw, &rect);
rect.x = x - 1;
rect.y = y;
SDL_BlitSurface(s, NULL, surface->raw, &rect);
rect.x = x + 1;
rect.y = y;
SDL_BlitSurface(s, NULL, surface->raw, &rect);
SDL_FreeSurface(s);
rect.x = x;
rect.y = y;
color.r = 0xff;
color.g = 0xff;
color.b = 0xff;
s = TTF_RenderUTF8_Blended(font, text, color);
SDL_BlitSurface(s, NULL, surface->raw, &rect);
SDL_FreeSurface(s);
} }

View File

@ -6,7 +6,7 @@
#ifndef ASFONT_H #ifndef ASFONT_H
#define ASFONT_H #define ASFONT_H
#include <SDL.h> #include <SDL_ttf.h>
#include <string> #include <string>
#include <vector> #include <vector>
@ -20,30 +20,33 @@ public:
ASFont(const std::string &font); ASFont(const std::string &font);
~ASFont(); ~ASFont();
bool utf8Code(unsigned char c);
int getTextWidth(const char *text); int getTextWidth(const char *text);
int getTextWidth(const std::string& text);
int getHeight() { int getTextWidth(const std::string& text)
return surface->h - 1; {
} return getTextWidth(text.c_str());
int getLineHeight() {
return lineHeight;
} }
void write(Surface* surface, const std::string& text, int x, int y, HAlign halign = HAlignLeft, VAlign valign = VAlignTop); bool utf8Code(unsigned char c)
{
return (c>=194 && c<=198) || c==208 || c==209;
}
int getHeight()
{
return fontheight;
}
void write(Surface *surface,
const std::string &text, int x, int y,
HAlign halign = HAlignLeft, VAlign valign = VAlignTop);
private: private:
void writeLine(Surface *surface, const std::string &text, int x, int y); void writeLine(Surface *surface, const char *text,
void writeLine(Surface *surface, const std::string &text, int x, int y, HAlign halign); int x, int y, HAlign halign, VAlign valign);
void writeLine(Surface *surface, const std::string &text, int x, int y, HAlign halign, VAlign valign);
void writeLine(Surface *surface, const std::vector<std::string> &text, int x, int y, HAlign halign, VAlign valign);
SDL_Surface *surface; TTF_Font *font;
std::vector<Uint16> charpos; unsigned int fontheight;
std::string characters;
int lineHeight;
}; };
#endif /* ASFONT_H */ #endif /* ASFONT_H */

View File

@ -647,7 +647,7 @@ void GMenu2X::main() {
uint linksPerPage = linkColumns*linkRows; uint linksPerPage = linkColumns*linkRows;
int linkSpacingX = (resX-10 - linkColumns*skinConfInt["linkWidth"])/linkColumns; int linkSpacingX = (resX-10 - linkColumns*skinConfInt["linkWidth"])/linkColumns;
int linkSpacingY = (resY-35 - skinConfInt["topBarHeight"] - linkRows*skinConfInt["linkHeight"])/linkRows; int linkSpacingY = (resY-35 - skinConfInt["topBarHeight"] - linkRows*skinConfInt["linkHeight"])/linkRows;
uint sectionLinkPadding = (skinConfInt["topBarHeight"] - 32 - font->getLineHeight()) / 3; uint sectionLinkPadding = (skinConfInt["topBarHeight"] - 32 - font->getHeight()) / 3;
bool quit = false; bool quit = false;
int x,y; int x,y;

View File

@ -137,7 +137,7 @@ void Link::setPosition(int x, int y) {
void Link::recalcCoordinates() { void Link::recalcCoordinates() {
iconX = rect.x+(rect.w-32)/2; iconX = rect.x+(rect.w-32)/2;
padding = (gmenu2x->skinConfInt["linkHeight"] - 32 - gmenu2x->font->getLineHeight()) / 3; padding = (gmenu2x->skinConfInt["linkHeight"] - 32 - gmenu2x->font->getHeight()) / 3;
} }
void Link::run() { void Link::run() {