X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=share%2Fgui.c;h=6f589d6fc8b6bfd51e292ad3bfd44d0f8199164b;hb=1745b6a90dfd9e626e5c40d20c6aa595ec41d888;hp=b30c561217ab7697443f6e5ab418c331790aa7ce;hpb=80f3c54424cc0bb3625edec10d4c7b728358b039;p=neverball diff --git a/share/gui.c b/share/gui.c index b30c561..6f589d6 100644 --- a/share/gui.c +++ b/share/gui.c @@ -20,6 +20,7 @@ #include "glext.h" #include "image.h" #include "vec3.h" +#include "text.h" #include "gui.h" /*---------------------------------------------------------------------------*/ @@ -40,7 +41,6 @@ #define GUI_COUNT 16 #define GUI_CLOCK 18 #define GUI_SPACE 20 -#define GUI_PAUSE 22 struct widget { @@ -81,15 +81,12 @@ static struct widget widget[MAXWIDGET]; static int active; static int radius; static TTF_Font *font[3] = { NULL, NULL, NULL }; -static int scale[3] = { 1, 1, 1 }; static GLuint digit_text[3][11]; static GLuint digit_list[3][11]; static int digit_w[3][11]; static int digit_h[3][11]; -static int pause_id; - /*---------------------------------------------------------------------------*/ static int gui_hot(int id) @@ -101,7 +98,7 @@ static int gui_hot(int id) /* * Initialize a display list containing a rectangle (x, y, w, h) to * which a rendered-font texture may be applied. Colors c0 and c1 - * determine the top-to-bottom color gradiant of the text. + * determine the top-to-bottom color gradient of the text. */ static GLuint gui_list(int x, int y, @@ -112,14 +109,17 @@ static GLuint gui_list(int x, int y, GLfloat s0, t0; GLfloat s1, t1; - int W, H, d = h / 16; + int W, H, ww, hh, d = h / 16; /* Assume the applied texture size is rect size rounded to power-of-two. */ image_size(&W, &H, w, h); - s0 = 0.5f * (W - w) / W; - t0 = 0.5f * (H - h) / H; + ww = ((W - w) % 2) ? w + 1 : w; + hh = ((H - h) % 2) ? h + 1 : h; + + s0 = 0.5f * (W - ww) / W; + t0 = 0.5f * (H - hh) / H; s1 = 1.0f - s0; t1 = 1.0f - t0; @@ -128,18 +128,18 @@ static GLuint gui_list(int x, int y, glBegin(GL_QUADS); { glColor4f(0.0f, 0.0f, 0.0f, 0.5f); - glTexCoord2f(s0, t1); glVertex2i(x + d, y - d); - glTexCoord2f(s1, t1); glVertex2i(x + w + d, y - d); - glTexCoord2f(s1, t0); glVertex2i(x + w + d, y + h - d); - glTexCoord2f(s0, t0); glVertex2i(x + d, y + h - d); + glTexCoord2f(s0, t1); glVertex2i(x + d, y - d); + glTexCoord2f(s1, t1); glVertex2i(x + ww + d, y - d); + glTexCoord2f(s1, t0); glVertex2i(x + ww + d, y + hh - d); + glTexCoord2f(s0, t0); glVertex2i(x + d, y + hh - d); glColor4fv(c0); - glTexCoord2f(s0, t1); glVertex2i(x, y); - glTexCoord2f(s1, t1); glVertex2i(x + w, y); + glTexCoord2f(s0, t1); glVertex2i(x, y); + glTexCoord2f(s1, t1); glVertex2i(x + ww, y); glColor4fv(c1); - glTexCoord2f(s1, t0); glVertex2i(x + w, y + h); - glTexCoord2f(s0, t0); glVertex2i(x, y + h); + glTexCoord2f(s1, t0); glVertex2i(x + ww, y + hh); + glTexCoord2f(s0, t0); glVertex2i(x, y + hh); } glEnd(); } @@ -177,10 +177,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 +196,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); } } @@ -226,21 +226,8 @@ void gui_init(void) if (TTF_Init() == 0) { int s0 = s / 26; - int s1 = s / 12; - int s2 = s / 6; - int m; - - /* Make sure text size doesn't exceed the maximum texture size. */ - - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m); - - scale[0] = 1; - scale[1] = 1; - scale[2] = 1; - - while (s0 > m) { s0 /= 2; scale[0] *= 2; } - while (s1 > m) { s1 /= 2; scale[1] *= 2; } - while (s2 > m) { s2 /= 2; scale[2] *= 2; } + int s1 = s / 13; + int s2 = s / 7; memset(widget, 0, sizeof (struct widget) * MAXWIDGET); @@ -251,18 +238,13 @@ void gui_init(void) font[GUI_LRG] = TTF_OpenFont(config_data(GUI_FACE), s2); radius = s / 60; - /* Initialize the global pause GUI. */ - - if ((pause_id = gui_pause(0))) - gui_layout(pause_id, 0, 0); - /* Initialize digit glyphs and lists for counters and clocks. */ for (i = 0; i < 3; i++) { char text[2]; - /* Draw digits 0 throught 9. */ + /* Draw digits 0 through 9. */ for (j = 0; j < 10; j++) { @@ -272,7 +254,7 @@ void gui_init(void) digit_text[i][j] = make_image_from_font(NULL, NULL, &digit_w[i][j], &digit_h[i][j], - text, font[i], scale[i]); + text, font[i]); digit_list[i][j] = gui_list(-digit_w[i][j] / 2, -digit_h[i][j] / 2, +digit_w[i][j], @@ -284,7 +266,7 @@ void gui_init(void) digit_text[i][j] = make_image_from_font(NULL, NULL, &digit_w[i][10], &digit_h[i][10], - ":", font[i], scale[i]); + ":", font[i]); digit_list[i][j] = gui_list(-digit_w[i][10] / 2, -digit_h[i][10] / 2, +digit_w[i][10], @@ -367,7 +349,7 @@ static int gui_widget(int pd, int type) widget[id].color1 = gui_wht; widget[id].scale = 1.0f; - /* Insert the new widget into the parents's widget list. */ + /* Insert the new widget into the parent's widget list. */ if (pd) { @@ -402,7 +384,7 @@ void gui_set_image(int id, const char *file) if (glIsTexture(widget[id].text_img)) glDeleteTextures(1, &widget[id].text_img); - widget[id].text_img = make_image_from_file(NULL, NULL, NULL, NULL, file); + widget[id].text_img = make_image_from_file(file); } void gui_set_label(int id, const char *text) @@ -415,8 +397,7 @@ void gui_set_label(int id, const char *text) glDeleteLists(widget[id].text_obj, 1); widget[id].text_img = make_image_from_font(NULL, NULL, &w, &h, - text, font[widget[id].size], - scale[widget[id].size]); + text, font[widget[id].size]); widget[id].text_obj = gui_list(-w / 2, -h / 2, w, h, widget[id].color0, widget[id].color1); } @@ -471,10 +452,9 @@ int gui_image(int pd, const char *file, int w, int h) if ((id = gui_widget(pd, GUI_IMAGE))) { - widget[id].text_img = make_image_from_file(NULL, NULL, - NULL, NULL, file); - widget[id].w = w; - widget[id].h = h; + widget[id].text_img = make_image_from_file(file); + widget[id].w = w; + widget[id].h = h; } return id; } @@ -498,8 +478,7 @@ int gui_state(int pd, const char *text, int size, int token, int value) widget[id].text_img = make_image_from_font(NULL, NULL, &widget[id].w, &widget[id].h, - text, font[size], - scale[size]); + text, font[size]); widget[id].size = size; widget[id].token = token; widget[id].value = value; @@ -517,8 +496,7 @@ int gui_label(int pd, const char *text, int size, int rect, const float *c0, widget[id].text_img = make_image_from_font(NULL, NULL, &widget[id].w, &widget[id].h, - text, font[size], - scale[size]); + text, font[size]); widget[id].size = size; widget[id].color0 = c0 ? c0 : gui_yel; widget[id].color1 = c1 ? c1 : gui_red; @@ -575,32 +553,11 @@ int gui_space(int pd) return id; } -int gui_pause(int pd) -{ - const char *text = "Paused"; - int id; - - if ((id = gui_widget(pd, GUI_PAUSE))) - { - widget[id].text_img = make_image_from_font(NULL, NULL, - &widget[id].w, - &widget[id].h, - text, font[GUI_LRG], - scale[GUI_LRG]); - widget[id].color0 = gui_wht; - widget[id].color1 = gui_wht; - widget[id].value = 0; - widget[id].size = GUI_LRG; - widget[id].rect = GUI_ALL; - } - return id; -} - /*---------------------------------------------------------------------------*/ /* * Create a multi-line text box using a vertical array of labels. * Parse the text for '\' characters and treat them as line-breaks. - * Preserve the rect specifation across the entire array. + * Preserve the rect specification across the entire array. */ int gui_multi(int pd, const char *text, int size, int rect, const float *c0, @@ -735,19 +692,6 @@ static void gui_vstack_up(int id) } } -static void gui_paused_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; - - /* The pause widget fills the screen. */ - - widget[id].w = config_get_d(CONFIG_WIDTH); - widget[id].h = config_get_d(CONFIG_HEIGHT); -} - static void gui_button_up(int id) { /* Store width and height for later use in text rendering. */ @@ -758,13 +702,19 @@ static void gui_button_up(int id) 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) @@ -776,7 +726,6 @@ 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_PAUSE: gui_paused_up(id); break; default: gui_button_up(id); break; } } @@ -919,7 +868,6 @@ static void gui_button_dn(int id, int x, int y, int w, int h) int W = widget[id].x; int H = widget[id].y; int R = widget[id].rect; - int r = ((widget[id].type & GUI_TYPE) == GUI_PAUSE ? radius * 4 : radius); const float *c0 = widget[id].color0; const float *c1 = widget[id].color1; @@ -932,7 +880,7 @@ static void gui_button_dn(int id, int x, int y, int w, int h) /* Create display lists for the text area and rounded rectangle. */ widget[id].text_obj = gui_list(-W / 2, -H / 2, W, H, c0, c1); - widget[id].rect_obj = gui_rect(-w / 2, -h / 2, w, h, R, r); + widget[id].rect_obj = gui_rect(-w / 2, -h / 2, w, h, R, radius); } static void gui_widget_dn(int id, int x, int y, int w, int h) @@ -1168,7 +1116,7 @@ static void gui_paint_count(int id) widget[id].scale, widget[id].scale); - if (widget[id].value) + if (widget[id].value > 0) { /* Translate left by half the total width of the rendered value. */ @@ -1186,7 +1134,7 @@ static void gui_paint_count(int id) glTranslatef((GLfloat) -digit_w[i][j % 10], 0.0f, 0.0f); } } - else + else if (widget[id].value == 0) { /* If the value is zero, just display a zero in place. */ @@ -1210,6 +1158,9 @@ static void gui_paint_clock(int id) GLfloat dx_large = (GLfloat) digit_w[i][0]; GLfloat dx_small = (GLfloat) digit_w[i][0] * 0.75f; + if (widget[id].value < 0) + return; + glPushMatrix(); { glColor4fv(gui_wht); @@ -1313,37 +1264,28 @@ void gui_paint(int id) { if (id) { - glPushAttrib(GL_LIGHTING_BIT | - GL_COLOR_BUFFER_BIT | - GL_DEPTH_BUFFER_BIT); config_push_ortho(); { - glEnable(GL_BLEND); glEnable(GL_COLOR_MATERIAL); glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); - - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glPushAttrib(GL_TEXTURE_BIT); { glDisable(GL_TEXTURE_2D); gui_paint_rect(id, 0); - } - glPopAttrib(); - gui_paint_text(id); + glEnable(GL_TEXTURE_2D); + gui_paint_text(id); + + glColor4fv(gui_wht); + } + glEnable(GL_DEPTH_TEST); + glEnable(GL_LIGHTING); + glDisable(GL_COLOR_MATERIAL); } config_pop_matrix(); - glPopAttrib(); } } -void gui_blank(void) -{ - gui_paint(pause_id); -} - /*---------------------------------------------------------------------------*/ void gui_dump(int id, int d) @@ -1430,6 +1372,11 @@ int gui_point(int id, int x, int y) return active = jd; } +void gui_focus(int i) +{ + active = i; +} + int gui_click(void) { return active; @@ -1452,122 +1399,174 @@ void gui_toggle(int id) /*---------------------------------------------------------------------------*/ -static int gui_vert_test(int id, int jd) +static int gui_vert_offset(int id, int jd) { - /* Determine whether widget id is in vertical contact with widget jd. */ - - if (id && gui_hot(id) && jd && gui_hot(jd)) - { - int i0 = widget[id].x; - int i1 = widget[id].x + widget[id].w; - int j0 = widget[jd].x; - int j1 = widget[jd].x + widget[jd].w; + /* Vertical offset between bottom of id and top of jd */ - /* Is widget id's top edge is in contact with jd's bottom edge? */ + return widget[id].y - (widget[jd].y + widget[jd].h); +} - if (widget[id].y + widget[id].h == widget[jd].y) - { - /* Do widgets id and jd overlap horizontally? */ +static int gui_horz_offset(int id, int jd) +{ + /* Horizontal offset between left of id and right of jd */ - if (j0 <= i0 && i0 < j1) return 1; - if (j0 < i1 && i1 <= j1) return 1; - if (i0 <= j0 && j0 < i1) return 1; - if (i0 < j1 && j1 <= i1) return 1; - } - } - return 0; + return widget[id].x - (widget[jd].x + widget[jd].w); } -static int gui_horz_test(int id, int jd) +static int gui_vert_dist(int id, int jd) { - /* Determine whether widget id is in horizontal contact with widget jd. */ + /* Vertical distance between the tops of id and jd */ - if (id && gui_hot(id) && jd && gui_hot(jd)) - { - int i0 = widget[id].y; - int i1 = widget[id].y + widget[id].h; - int j0 = widget[jd].y; - int j1 = widget[jd].y + widget[jd].h; - - /* Is widget id's right edge in contact with jd's left edge? */ + return abs((widget[id].y + widget[id].h) - (widget[jd].y + widget[jd].h)); +} - if (widget[id].x + widget[id].w == widget[jd].x) - { - /* Do widgets id and jd overlap vertically? */ +static int gui_horz_dist(int id, int jd) +{ + /* Horizontal distance between the left sides of id and jd */ - if (j0 <= i0 && i0 < j1) return 1; - if (j0 < i1 && i1 <= j1) return 1; - if (i0 <= j0 && j0 < i1) return 1; - if (i0 < j1 && j1 <= i1) return 1; - } - } - return 0; + return abs(widget[id].x - widget[jd].x); } /*---------------------------------------------------------------------------*/ static int gui_stick_L(int id, int dd) { - int jd, kd; + int jd, kd, hd; + int o, omin, d, dmin; - /* Find a widget to the left of widget dd. */ + /* Find the closest "hot" widget to the left of dd (and inside id) */ - if (gui_horz_test(id, dd)) + if (id && gui_hot(id)) return id; + hd = 0; + omin = widget[dd].x - widget[id].x + 1; + dmin = widget[dd].y + widget[dd].h + widget[id].y + widget[id].h; + for (jd = widget[id].car; jd; jd = widget[jd].cdr) - if ((kd = gui_stick_L(jd, dd))) - return kd; + { + kd = gui_stick_L(jd, dd); - return 0; + if (kd && kd != dd) + { + o = gui_horz_offset(dd, kd); + d = gui_vert_dist(dd, kd); + + if (0 <= o && o <= omin && d <= dmin) + { + hd = kd; + omin = o; + dmin = d; + } + } + } + + return hd; } static int gui_stick_R(int id, int dd) { - int jd, kd; + int jd, kd, hd; + int o, omin, d, dmin; - /* Find a widget to the right of widget dd. */ + /* Find the closest "hot" widget to the right of dd (and inside id) */ - if (gui_horz_test(dd, id)) + if (id && gui_hot(id)) return id; + hd = 0; + omin = (widget[id].x + widget[id].w) - (widget[dd].x + widget[dd].w) + 1; + dmin = widget[dd].y + widget[dd].h + widget[id].y + widget[id].h; + for (jd = widget[id].car; jd; jd = widget[jd].cdr) - if ((kd = gui_stick_R(jd, dd))) - return kd; + { + kd = gui_stick_R(jd, dd); - return 0; + if (kd && kd != dd) + { + o = gui_horz_offset(kd, dd); + d = gui_vert_dist(dd, kd); + + if (0 <= o && o <= omin && d <= dmin) + { + hd = kd; + omin = o; + dmin = d; + } + } + } + + return hd; } static int gui_stick_D(int id, int dd) { - int jd, kd; + int jd, kd, hd; + int o, omin, d, dmin; - /* Find a widget below widget dd. */ + /* Find the closest "hot" widget below dd (and inside id) */ - if (gui_vert_test(id, dd)) + if (id && gui_hot(id)) return id; + hd = 0; + omin = widget[dd].y - widget[id].y + 1; + dmin = widget[dd].x + widget[dd].w + widget[id].x + widget[id].w; + for (jd = widget[id].car; jd; jd = widget[jd].cdr) - if ((kd = gui_stick_D(jd, dd))) - return kd; + { + kd = gui_stick_D(jd, dd); - return 0; + if (kd && kd != dd) + { + o = gui_vert_offset(dd, kd); + d = gui_horz_dist(dd, kd); + + if (0 <= o && o <= omin && d <= dmin) + { + hd = kd; + omin = o; + dmin = d; + } + } + } + + return hd; } static int gui_stick_U(int id, int dd) { - int jd, kd; + int jd, kd, hd; + int o, omin, d, dmin; - /* Find a widget above widget dd. */ + /* Find the closest "hot" widget above dd (and inside id) */ - if (gui_vert_test(dd, id)) + if (id && gui_hot(id)) return id; + hd = 0; + omin = (widget[id].y + widget[id].h) - (widget[dd].y + widget[dd].h) + 1; + dmin = widget[dd].x + widget[dd].w + widget[id].x + widget[id].w; + for (jd = widget[id].car; jd; jd = widget[jd].cdr) - if ((kd = gui_stick_U(jd, dd))) - return kd; + { + kd = gui_stick_U(jd, dd); - return 0; + if (kd && kd != dd) + { + o = gui_vert_offset(kd, dd); + d = gui_horz_dist(dd, kd); + + if (0 <= o && o <= omin && d <= dmin) + { + hd = kd; + omin = o; + dmin = d; + } + } + } + + return hd; } /*---------------------------------------------------------------------------*/ @@ -1618,13 +1617,21 @@ static int gui_wrap_D(int id, int dd) /*---------------------------------------------------------------------------*/ -int gui_stick(int id, int x, int y) +/* Flag the axes to prevent uncontrolled scrolling. */ + +static int xflag = 1; +static int yflag = 1; + +void gui_stuck() { - /* Flag the axes to prevent uncontrolled scrolling. */ + /* Force the user to recenter the joystick before the next GUI action. */ - static int xflag = 1; - static int yflag = 1; + xflag = 0; + yflag = 0; +} +int gui_stick(int id, int x, int y) +{ int jd = 0; /* Find a new active widget in the direction of joystick motion. */