X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=share%2Fgui.c;h=9da7434930ef5a8522a012614fd72a1da7e12e99;hb=d9f6f8642b9a4f326c0854efe969195a8d0d2e2a;hp=7f7b091f02b85d5199e5e29279e8e57b2905404e;hpb=bdbe02e7fd69e48a627654a5ca276733f873a9a4;p=neverball diff --git a/share/gui.c b/share/gui.c index 7f7b091..9da7434 100644 --- a/share/gui.c +++ b/share/gui.c @@ -17,11 +17,15 @@ #include #include "config.h" +#include "video.h" #include "glext.h" #include "image.h" #include "vec3.h" -#include "text.h" #include "gui.h" +#include "common.h" + +#include "fs.h" +#include "fs_rwops.h" /*---------------------------------------------------------------------------*/ @@ -63,6 +67,11 @@ struct widget const GLfloat *color1; GLfloat scale; + + int text_obj_w; + int text_obj_h; + + enum trunc trunc; }; /*---------------------------------------------------------------------------*/ @@ -82,6 +91,10 @@ static int active; static int radius; static TTF_Font *font[3] = { NULL, NULL, NULL }; +static void *fontdata; +static int fontdatalen; +static SDL_RWops *fontrwops; + static GLuint digit_text[3][11]; static GLuint digit_list[3][11]; static int digit_w[3][11]; @@ -177,10 +190,10 @@ static GLuint gui_rect(int x, int y, int w, int h, int f, int r) float Ya = y + h + ((f & GUI_NW) ? (s - r) : 0); float Yb = y + ((f & GUI_SW) ? (r - s) : 0); - glTexCoord2f((X - x) / w, 1 - (Ya - y) / h); + glTexCoord2f((X - x) / w, (Ya - y) / h); glVertex2f(X, Ya); - glTexCoord2f((X - x) / w, 1 - (Yb - y) / h); + glTexCoord2f((X - x) / w, (Yb - y) / h); glVertex2f(X, Yb); } @@ -196,10 +209,10 @@ static GLuint gui_rect(int x, int y, int w, int h, int f, int r) float Ya = y + h + ((f & GUI_NE) ? (c - r) : 0); float Yb = y + ((f & GUI_SE) ? (r - c) : 0); - glTexCoord2f((X - x) / w, 1 - (Ya - y) / h); + glTexCoord2f((X - x) / w, (Ya - y) / h); glVertex2f(X, Ya); - glTexCoord2f((X - x) / w, 1 - (Yb - y) / h); + glTexCoord2f((X - x) / w, (Yb - y) / h); glVertex2f(X, Yb); } } @@ -212,6 +225,23 @@ static GLuint gui_rect(int x, int y, int w, int h, int f, int r) /*---------------------------------------------------------------------------*/ +static const char *pick_font_path(void) +{ + const char *path; + + path = _(GUI_FACE); + + if (!fs_exists(path)) + { + fprintf(stderr, _("Font '%s' doesn't exist, trying default font.\n"), + path); + + path = GUI_FACE; + } + + return path; +} + void gui_init(void) { const float *c0 = gui_yel; @@ -225,17 +255,37 @@ void gui_init(void) if (TTF_Init() == 0) { + const char *fontpath = pick_font_path(); + int s0 = s / 26; int s1 = s / 13; int s2 = s / 7; memset(widget, 0, sizeof (struct widget) * MAXWIDGET); + /* Load the font. */ + + if (!(fontdata = fs_load(fontpath, &fontdatalen))) + { + fprintf(stderr, _("Could not load font '%s'.\n"), fontpath); + /* Return or no return, we'll probably crash now. */ + return; + } + + fontrwops = SDL_RWFromConstMem(fontdata, fontdatalen); + /* Load small, medium, and large typefaces. */ - font[GUI_SML] = TTF_OpenFont(config_data(GUI_FACE), s0); - font[GUI_MED] = TTF_OpenFont(config_data(GUI_FACE), s1); - font[GUI_LRG] = TTF_OpenFont(config_data(GUI_FACE), s2); + font[GUI_SML] = TTF_OpenFontRW(fontrwops, 0, s0); + + SDL_RWseek(fontrwops, 0, SEEK_SET); + font[GUI_MED] = TTF_OpenFontRW(fontrwops, 0, s1); + + SDL_RWseek(fontrwops, 0, SEEK_SET); + font[GUI_LRG] = TTF_OpenFontRW(fontrwops, 0, s2); + + /* fontrwops remains open. */ + radius = s / 60; /* Initialize digit glyphs and lists for counters and clocks. */ @@ -319,6 +369,9 @@ void gui_free(void) if (font[GUI_MED]) TTF_CloseFont(font[GUI_MED]); if (font[GUI_SML]) TTF_CloseFont(font[GUI_SML]); + if (fontrwops) SDL_RWclose(fontrwops); + if (fontdata) free(fontdata); + TTF_Quit(); } @@ -348,6 +401,10 @@ static int gui_widget(int pd, int type) widget[id].color0 = gui_wht; widget[id].color1 = gui_wht; widget[id].scale = 1.0f; + widget[id].trunc = TRUNC_NONE; + + widget[id].text_obj_w = 0; + widget[id].text_obj_h = 0; /* Insert the new widget into the parent's widget list. */ @@ -379,6 +436,101 @@ int gui_filler(int pd) { return gui_widget(pd, GUI_FILLER); } /*---------------------------------------------------------------------------*/ +struct size +{ + int w, h; +}; + + +static struct size gui_measure(const char *text, TTF_Font *font) +{ + struct size size = { 0, 0 }; + TTF_SizeUTF8(font, text, &size.w, &size.h); + return size; +} + +static char *gui_trunc_head(const char *text, + const int maxwidth, + TTF_Font *font) +{ + int left, right, mid; + char *str = NULL; + + left = 0; + right = strlen(text); + + while (right - left > 1) + { + mid = (left + right) / 2; + + str = concat_string("...", text + mid, NULL); + + if (gui_measure(str, font).w <= maxwidth) + right = mid; + else + left = mid; + + free(str); + } + + return concat_string("...", text + right, NULL); +} + +static char *gui_trunc_tail(const char *text, + const int maxwidth, + TTF_Font *font) +{ + int left, right, mid; + char *str = NULL; + + left = 0; + right = strlen(text); + + while (right - left > 1) + { + mid = (left + right) / 2; + + str = malloc(mid + sizeof ("...")); + + memcpy(str, text, mid); + memcpy(str + mid, "...", sizeof ("...")); + + if (gui_measure(str, font).w <= maxwidth) + left = mid; + else + right = mid; + + free(str); + } + + str = malloc(left + sizeof ("...")); + + memcpy(str, text, left); + memcpy(str + left, "...", sizeof ("...")); + + return str; +} + +static char *gui_truncate(const char *text, + const int maxwidth, + TTF_Font *font, + enum trunc trunc) +{ + if (gui_measure(text, font).w <= maxwidth) + return strdup(text); + + switch (trunc) + { + case TRUNC_NONE: return strdup(text); break; + case TRUNC_HEAD: return gui_trunc_head(text, maxwidth, font); break; + case TRUNC_TAIL: return gui_trunc_tail(text, maxwidth, font); break; + } + + return NULL; +} + +/*---------------------------------------------------------------------------*/ + void gui_set_image(int id, const char *file) { if (glIsTexture(widget[id].text_img)) @@ -396,10 +548,19 @@ void gui_set_label(int id, const char *text) if (glIsList(widget[id].text_obj)) glDeleteLists(widget[id].text_obj, 1); + text = gui_truncate(text, widget[id].w - radius, + font[widget[id].size], + widget[id].trunc); + widget[id].text_img = make_image_from_font(NULL, NULL, &w, &h, text, font[widget[id].size]); widget[id].text_obj = gui_list(-w / 2, -h / 2, w, h, widget[id].color0, widget[id].color1); + + widget[id].text_obj_w = w; + widget[id].text_obj_h = h; + + free((void *) text); } void gui_set_count(int id, int value) @@ -415,8 +576,31 @@ void gui_set_clock(int id, int value) void gui_set_color(int id, const float *c0, const float *c1) { - widget[id].color0 = c0 ? c0 : gui_yel; - widget[id].color1 = c1 ? c1 : gui_red; + if (id) + { + c0 = c0 ? c0 : gui_yel; + c1 = c1 ? c1 : gui_red; + + if (widget[id].color0 != c0 || widget[id].color1 != c1) + { + widget[id].color0 = c0; + widget[id].color1 = c1; + + if (glIsList(widget[id].text_obj)) + { + int w, h; + + glDeleteLists(widget[id].text_obj, 1); + + w = widget[id].text_obj_w; + h = widget[id].text_obj_h; + + widget[id].text_obj = gui_list(-w / 2, -h / 2, w, h, + widget[id].color0, + widget[id].color1); + } + } + } } void gui_set_multi(int id, const char *text) @@ -444,6 +628,11 @@ void gui_set_multi(int id, const char *text) gui_set_label(jd, s[i]); } +void gui_set_trunc(int id, enum trunc trunc) +{ + widget[id].trunc = trunc; +} + /*---------------------------------------------------------------------------*/ int gui_image(int pd, const char *file, int w, int h) @@ -696,19 +885,25 @@ static void gui_button_up(int id) { /* Store width and height for later use in text rendering. */ - widget[id].x = widget[id].w; - widget[id].y = widget[id].h; + widget[id].text_obj_w = widget[id].w; + widget[id].text_obj_h = widget[id].h; if (widget[id].w < widget[id].h && widget[id].w > 0) widget[id].w = widget[id].h; - /* Padded text elements look a little nicer. */ if (widget[id].w < config_get_d(CONFIG_WIDTH)) widget[id].w += radius; if (widget[id].h < config_get_d(CONFIG_HEIGHT)) widget[id].h += radius; + + /* A button should be at least wide enough to accomodate the rounding. */ + + if (widget[id].w < 2 * radius) + widget[id].w = 2 * radius; + if (widget[id].h < 2 * radius) + widget[id].h = 2 * radius; } static void gui_widget_up(int id) @@ -720,6 +915,7 @@ static void gui_widget_up(int id) case GUI_VARRAY: gui_varray_up(id); break; case GUI_HSTACK: gui_hstack_up(id); break; case GUI_VSTACK: gui_vstack_up(id); break; + case GUI_FILLER: break; default: gui_button_up(id); break; } } @@ -859,8 +1055,8 @@ static void gui_button_dn(int id, int x, int y, int w, int h) { /* Recall stored width and height for text rendering. */ - int W = widget[id].x; - int H = widget[id].y; + int W = widget[id].text_obj_w; + int H = widget[id].text_obj_h; int R = widget[id].rect; const float *c0 = widget[id].color0; @@ -1258,7 +1454,7 @@ void gui_paint(int id) { if (id) { - config_push_ortho(); + video_push_ortho(); { glEnable(GL_COLOR_MATERIAL); glDisable(GL_LIGHTING); @@ -1276,7 +1472,7 @@ void gui_paint(int id) glEnable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); } - config_pop_matrix(); + video_pop_matrix(); } }