#include "glext.h"
#include "image.h"
#include "vec3.h"
+#include "text.h"
#include "gui.h"
/*---------------------------------------------------------------------------*/
#define GUI_COUNT 16
#define GUI_CLOCK 18
#define GUI_SPACE 20
-#define GUI_PAUSE 22
struct widget
{
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)
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;
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();
}
int s0 = s / 26;
int s1 = s / 13;
int s2 = s / 7;
- 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; }
memset(widget, 0, sizeof (struct widget) * MAXWIDGET);
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++)
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],
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],
return id;
}
- fprintf(stderr, _("Out of widget IDs\n"));
+ fprintf(stderr, "Out of widget IDs\n");
return 0;
}
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)
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);
}
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;
}
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;
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;
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.
}
}
-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. */
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;
}
}
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;
/* 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)
}
}
-void gui_blank(void)
-{
- gui_paint(pause_id);
-}
-
/*---------------------------------------------------------------------------*/
void gui_dump(int id, int d)
/*---------------------------------------------------------------------------*/
-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. */
+ /* Vertical offset between bottom of id and top of 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;
-
- /* 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. */
-
- 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;
+ /* Vertical distance between the tops of id and jd */
- /* 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;
}
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
-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. */