mirror of
git://projects.qi-hardware.com/gmenu2x.git
synced 2024-11-25 22:06:17 +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:
parent
eb63294231
commit
46386a2054
@ -21,6 +21,8 @@ AC_ARG_WITH(sdl-gfx-prefix,
|
||||
|
||||
AC_CHECK_LIB(SDL_gfx, rotozoomSurfaceXY,,check_sdl_gfx="no")
|
||||
|
||||
AC_CHECK_LIB(SDL_ttf, TTF_OpenFont)
|
||||
|
||||
# Check for libpng
|
||||
AC_CHECK_LIB(png, png_read_image,,check_png="no")
|
||||
|
||||
|
239
src/asfont.cpp
239
src/asfont.cpp
@ -1,150 +1,67 @@
|
||||
#include "asfont.h"
|
||||
#include "imageio.h"
|
||||
#include "debug.h"
|
||||
#include "surface.h"
|
||||
#include "utilities.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <SDL.h>
|
||||
#include <SDL_ttf.h>
|
||||
#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)
|
||||
: characters(SFONTPLUS_CHARSET)
|
||||
using namespace std;
|
||||
|
||||
ASFont::ASFont(const string &path)
|
||||
{
|
||||
surface = loadPNG(fontImagePath);
|
||||
if (!surface) {
|
||||
if (!TTF_WasInit() && TTF_Init() < 0) {
|
||||
ERROR("Unable to init SDL_ttf library\n");
|
||||
return;
|
||||
}
|
||||
assert(surface->format->BytesPerPixel == 4);
|
||||
|
||||
SDL_LockSurface(surface);
|
||||
|
||||
// Determine character widths.
|
||||
Uint32 pink = SDL_MapRGB(surface->format, 255, 0, 255);
|
||||
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++;
|
||||
font = TTF_OpenFont(TTF_FONT, TTF_FONT_SIZE);
|
||||
if (!font) {
|
||||
ERROR("Unable to open font\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Scan height of "0" glyph.
|
||||
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);
|
||||
fontheight = TTF_FontHeight(font);
|
||||
}
|
||||
|
||||
ASFont::~ASFont() {
|
||||
if (surface) {
|
||||
SDL_FreeSurface(surface);
|
||||
ASFont::~ASFont()
|
||||
{
|
||||
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) {
|
||||
return (c>=194 && c<=198) || c==208 || c==209;
|
||||
//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) {
|
||||
void ASFont::writeLine(Surface *surface, const char *text,
|
||||
int x, int y, HAlign halign, VAlign valign)
|
||||
{
|
||||
switch (halign) {
|
||||
case HAlignLeft:
|
||||
break;
|
||||
@ -155,46 +72,46 @@ void ASFont::writeLine(Surface* surface, const std::string& text, int x, int y,
|
||||
x -= getTextWidth(text);
|
||||
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) {
|
||||
case VAlignTop:
|
||||
break;
|
||||
case VAlignMiddle:
|
||||
y -= getHeight() / 2;
|
||||
y -= fontheight / 2;
|
||||
break;
|
||||
case VAlignBottom:
|
||||
y -= getHeight();
|
||||
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();
|
||||
y -= fontheight;
|
||||
break;
|
||||
}
|
||||
|
||||
for (std::vector<std::string>::const_iterator it = text.begin(); it != text.end(); ++it) {
|
||||
write(surface, *it, x, y, halign);
|
||||
y += getHeight();
|
||||
}
|
||||
}
|
||||
SDL_Color color = { 0, 0, 0, 0 };
|
||||
SDL_Surface *s = TTF_RenderUTF8_Blended(font, text, color);
|
||||
|
||||
void ASFont::write(Surface* surface, const std::string& text, int x, int y, HAlign halign, VAlign valign) {
|
||||
if (text.find("\n", 0) != std::string::npos) {
|
||||
std::vector<std::string> textArr;
|
||||
split(textArr, text, "\n");
|
||||
writeLine(surface, textArr, x, y, halign, valign);
|
||||
} else
|
||||
writeLine(surface, text, x, y, halign, valign);
|
||||
SDL_Rect rect = { (Sint16) x, (Sint16) (y - 1), 0, 0 };
|
||||
SDL_BlitSurface(s, NULL, surface->raw, &rect);
|
||||
|
||||
/* Note: rect.x / rect.y are reset everytime because SDL_BlitSurface
|
||||
* will modify them if negative */
|
||||
rect.x = x;
|
||||
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);
|
||||
}
|
||||
|
39
src/asfont.h
39
src/asfont.h
@ -6,7 +6,7 @@
|
||||
#ifndef ASFONT_H
|
||||
#define ASFONT_H
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL_ttf.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -20,30 +20,33 @@ public:
|
||||
ASFont(const std::string &font);
|
||||
~ASFont();
|
||||
|
||||
bool utf8Code(unsigned char c);
|
||||
|
||||
int getTextWidth(const char *text);
|
||||
int getTextWidth(const std::string& text);
|
||||
|
||||
int getHeight() {
|
||||
return surface->h - 1;
|
||||
}
|
||||
int getLineHeight() {
|
||||
return lineHeight;
|
||||
int getTextWidth(const std::string& text)
|
||||
{
|
||||
return getTextWidth(text.c_str());
|
||||
}
|
||||
|
||||
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:
|
||||
void writeLine(Surface *surface, const std::string &text, int x, int y);
|
||||
void writeLine(Surface *surface, const std::string &text, int x, int y, HAlign halign);
|
||||
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);
|
||||
void writeLine(Surface *surface, const char *text,
|
||||
int x, int y, HAlign halign, VAlign valign);
|
||||
|
||||
SDL_Surface *surface;
|
||||
std::vector<Uint16> charpos;
|
||||
std::string characters;
|
||||
int lineHeight;
|
||||
TTF_Font *font;
|
||||
unsigned int fontheight;
|
||||
};
|
||||
|
||||
#endif /* ASFONT_H */
|
||||
|
@ -647,7 +647,7 @@ void GMenu2X::main() {
|
||||
uint linksPerPage = linkColumns*linkRows;
|
||||
int linkSpacingX = (resX-10 - linkColumns*skinConfInt["linkWidth"])/linkColumns;
|
||||
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;
|
||||
int x,y;
|
||||
|
@ -137,7 +137,7 @@ void Link::setPosition(int x, int y) {
|
||||
|
||||
void Link::recalcCoordinates() {
|
||||
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() {
|
||||
|
Loading…
Reference in New Issue
Block a user