mirror of
git://projects.qi-hardware.com/gmenu2x.git
synced 2024-11-26 02:51:53 +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_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")
|
||||||
|
|
||||||
|
239
src/asfont.cpp
239
src/asfont.cpp
@ -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);
|
||||||
}
|
}
|
||||||
|
39
src/asfont.h
39
src/asfont.h
@ -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 */
|
||||||
|
@ -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;
|
||||||
|
@ -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() {
|
||||||
|
Loading…
Reference in New Issue
Block a user