imtk

changeset 6:38609a9f7586

reorganizing ...
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 14 Apr 2011 14:22:42 +0300
parents 09b6e8a5dc14
children 6d35e6c7b2ca
files src/button.c src/checkbox.c src/draw.c src/draw.h src/slider.c src/state.c src/state.h src/textbox.c
diffstat 8 files changed, 623 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/button.c	Thu Apr 14 14:22:42 2011 +0300
     1.3 @@ -0,0 +1,69 @@
     1.4 +#include <assert.h>
     1.5 +#include "imtk.h"
     1.6 +#include "state.h"
     1.7 +#include "draw.h"
     1.8 +
     1.9 +static void calc_button_size(const char *label, int *wret, int *hret);
    1.10 +static void draw_button(int id, const char *label, int x, int y);
    1.11 +
    1.12 +int imtk_button(int id, const char *label, int x, int y)
    1.13 +{
    1.14 +	int w, h, res = 0;
    1.15 +	int over = 0;
    1.16 +
    1.17 +	assert(id >= 0);
    1.18 +
    1.19 +	calc_button_size(label, &w, &h);
    1.20 +
    1.21 +	if(imtk_hit_test(x, y, w, h)) {
    1.22 +		imtk_set_hot(id);
    1.23 +		over = 1;
    1.24 +	}
    1.25 +
    1.26 +	if(imtk_button_state(IMTK_LEFT_BUTTON)) {
    1.27 +		if(over) {
    1.28 +			imtk_set_active(id);
    1.29 +		}
    1.30 +	} else { /* mouse button up */
    1.31 +		if(imtk_is_active(id)) {
    1.32 +			imtk_set_active(-1);
    1.33 +			if(imtk_is_hot(id) && over) {
    1.34 +				res = 1;
    1.35 +			}
    1.36 +		}
    1.37 +	}
    1.38 +
    1.39 +	draw_button(id, label, x, y);
    1.40 +	return res;
    1.41 +}
    1.42 +
    1.43 +static void draw_button(int id, const char *label, int x, int y)
    1.44 +{
    1.45 +	int width, height;
    1.46 +
    1.47 +	calc_button_size(label, &width, &height);
    1.48 +
    1.49 +	glBegin(GL_QUADS);
    1.50 +	if(imtk_hit_test(x, y, width, height)) {
    1.51 +		glColor4fv(imtk_get_color(IMTK_FOCUS_COLOR));
    1.52 +	} else {
    1.53 +		glColor4fv(imtk_get_color(IMTK_BASE_COLOR));
    1.54 +	}
    1.55 +	glVertex2f(x, y);
    1.56 +	glVertex2f(x + width, y);
    1.57 +	glVertex2f(x + width, y + height);
    1.58 +	glVertex2f(x, y + height);
    1.59 +	glEnd();
    1.60 +
    1.61 +	imtk_draw_frame(x, y, width, height, imtk_is_active(id) ? FRAME_INSET : FRAME_OUTSET);
    1.62 +
    1.63 +	glColor4fv(imtk_get_color(IMTK_TEXT_COLOR));
    1.64 +	imtk_draw_string(x + 20, y + 15, label);
    1.65 +}
    1.66 +
    1.67 +static void calc_button_size(const char *label, int *wret, int *hret)
    1.68 +{
    1.69 +	int strsz = imtk_string_size(label);
    1.70 +	if(wret) *wret = strsz + 40;
    1.71 +	if(hret) *hret = 20;
    1.72 +}
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/src/checkbox.c	Thu Apr 14 14:22:42 2011 +0300
     2.3 @@ -0,0 +1,78 @@
     2.4 +#include <assert.h>
     2.5 +#include "imtk.h"
     2.6 +#include "state.h"
     2.7 +#include "draw.h"
     2.8 +
     2.9 +
    2.10 +#define CHECKBOX_SIZE	14
    2.11 +
    2.12 +
    2.13 +static void draw_checkbox(int id, const char *label, int x, int y, int state);
    2.14 +
    2.15 +
    2.16 +int imtk_checkbox(int id, const char *label, int x, int y, int state)
    2.17 +{
    2.18 +	int sz = CHECKBOX_SIZE;
    2.19 +	int over = 0;
    2.20 +
    2.21 +	assert(id >= 0);
    2.22 +
    2.23 +	if(imtk_hit_test(x, y, sz, sz)) {
    2.24 +		imtk_set_hot(id);
    2.25 +		over = 1;
    2.26 +	}
    2.27 +
    2.28 +	if(imtk_button_state(IMTK_LEFT_BUTTON)) {
    2.29 +		if(over) {
    2.30 +			imtk_set_active(id);
    2.31 +		}
    2.32 +	} else { /* mouse button up */
    2.33 +		if(imtk_is_active(id)) {
    2.34 +			imtk_set_active(-1);
    2.35 +			if(imtk_is_hot(id) && over) {
    2.36 +				state = !state;
    2.37 +			}
    2.38 +		}
    2.39 +	}
    2.40 +
    2.41 +	draw_checkbox(id, label, x, y, state);
    2.42 +	return state;
    2.43 +}
    2.44 +
    2.45 +static void draw_checkbox(int id, const char *label, int x, int y, int state)
    2.46 +{
    2.47 +	static const int sz = CHECKBOX_SIZE;
    2.48 +
    2.49 +	if(imtk_hit_test(x, y, sz, sz)) {
    2.50 +		glColor4fv(imtk_get_color(IMTK_FOCUS_COLOR));
    2.51 +	} else {
    2.52 +		glColor4fv(imtk_get_color(IMTK_BASE_COLOR));
    2.53 +	}
    2.54 +
    2.55 +	glBegin(GL_QUADS);
    2.56 +	glVertex2f(x, y);
    2.57 +	glVertex2f(x + sz, y);
    2.58 +	glVertex2f(x + sz, y + sz);
    2.59 +	glVertex2f(x, y + sz);
    2.60 +	glEnd();
    2.61 +
    2.62 +	imtk_draw_frame(x, y, sz, sz, FRAME_INSET);
    2.63 +
    2.64 +	glColor4fv(imtk_get_color(IMTK_TEXT_COLOR));
    2.65 +	if(state) {
    2.66 +		glPushAttrib(GL_LINE_BIT);
    2.67 +		glLineWidth(2);
    2.68 +
    2.69 +		glBegin(GL_LINES);
    2.70 +		glVertex2f(x + 2, y + 2);
    2.71 +		glVertex2f(x + sz - 2, y + sz - 2);
    2.72 +		glVertex2f(x + sz - 2, y + 2);
    2.73 +		glVertex2f(x + 2, y + sz - 2);
    2.74 +		glEnd();
    2.75 +
    2.76 +		glPopAttrib();
    2.77 +	}
    2.78 +
    2.79 +	imtk_draw_string(x + sz + 5, y + sz - 2, label);
    2.80 +}
    2.81 +
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/draw.c	Thu Apr 14 14:22:42 2011 +0300
     3.3 @@ -0,0 +1,72 @@
     3.4 +#include <string.h>
     3.5 +#include <assert.h>
     3.6 +#include "draw.h"
     3.7 +#include "imtk.h"
     3.8 +
     3.9 +/* default colors, can be changed with imtk_set_color */
    3.10 +static float colors[][4] = {
    3.11 +	{0.0, 0.0, 0.0, 1.0},		/* text color */
    3.12 +	{0.7, 0.7, 0.7, 1.0},		/* base color */
    3.13 +	{0.85, 0.85, 0.85, 1.0},	/* focus color */
    3.14 +	{1.0, 1.0, 1.0, 1.0},		/* lit bevel */
    3.15 +	{0.3, 0.3, 0.3, 1.0}		/* shadowed bevel */
    3.16 +};
    3.17 +
    3.18 +void imtk_set_color(int col, float r, float g, float b, float a)
    3.19 +{
    3.20 +	assert(col >= 0 && col < sizeof colors / sizeof *colors);
    3.21 +
    3.22 +	colors[col][0] = r;
    3.23 +	colors[col][1] = g;
    3.24 +	colors[col][2] = b;
    3.25 +	colors[col][3] = a;
    3.26 +}
    3.27 +
    3.28 +float *imtk_get_color(int col)
    3.29 +{
    3.30 +	return colors[col];
    3.31 +}
    3.32 +
    3.33 +void imtk_draw_frame(int x, int y, int w, int h, int style)
    3.34 +{
    3.35 +	float tcol[4], bcol[4];
    3.36 +
    3.37 +	switch(style) {
    3.38 +	case FRAME_INSET:
    3.39 +		memcpy(tcol, colors[IMTK_BEVEL_SHAD_COLOR], sizeof tcol);
    3.40 +		memcpy(bcol, colors[IMTK_BEVEL_LIT_COLOR], sizeof bcol);
    3.41 +		break;
    3.42 +
    3.43 +	case FRAME_OUTSET:
    3.44 +	default:
    3.45 +		memcpy(tcol, colors[IMTK_BEVEL_LIT_COLOR], sizeof tcol);
    3.46 +		memcpy(bcol, colors[IMTK_BEVEL_SHAD_COLOR], sizeof bcol);
    3.47 +	}
    3.48 +
    3.49 +	glBegin(GL_LINES);
    3.50 +	glColor4fv(tcol);
    3.51 +	glVertex2f(x, y + h);
    3.52 +	glVertex2f(x, y);
    3.53 +	glVertex2f(x, y);
    3.54 +	glVertex2f(x + w, y);
    3.55 +	glColor4fv(bcol);
    3.56 +	glVertex2f(x + w, y);
    3.57 +	glVertex2f(x + w, y + h);
    3.58 +	glVertex2f(x + w, y + h);
    3.59 +	glVertex2f(x, y + h);
    3.60 +	glEnd();
    3.61 +
    3.62 +}
    3.63 +
    3.64 +void imtk_draw_string(int x, int y, const char *str)
    3.65 +{
    3.66 +	glRasterPos2i(x, y);
    3.67 +	while(*str) {
    3.68 +		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, *str++);
    3.69 +	}
    3.70 +}
    3.71 +
    3.72 +int imtk_string_size(const char *str)
    3.73 +{
    3.74 +	return glutBitmapLength(GLUT_BITMAP_HELVETICA_12, (const unsigned char*)str);
    3.75 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/draw.h	Thu Apr 14 14:22:42 2011 +0300
     4.3 @@ -0,0 +1,30 @@
     4.4 +#ifndef DRAW_H_
     4.5 +#define DRAW_H_
     4.6 +
     4.7 +#ifndef __APPLE__
     4.8 +#include <GL/glut.h>
     4.9 +#else
    4.10 +#include <GLUT/glut.h>
    4.11 +#endif
    4.12 +
    4.13 +enum {
    4.14 +	IMTK_TEXT_COLOR,
    4.15 +	IMTK_BASE_COLOR,
    4.16 +	IMTK_FOCUS_COLOR,
    4.17 +	IMTK_BEVEL_LIT_COLOR,
    4.18 +	IMTK_BEVEL_SHAD_COLOR
    4.19 +};
    4.20 +
    4.21 +
    4.22 +enum {
    4.23 +	FRAME_OUTSET,
    4.24 +	FRAME_INSET
    4.25 +};
    4.26 +
    4.27 +void imtk_set_color(int col, float r, float g, float b, float a);
    4.28 +float *imtk_get_color(int col);
    4.29 +void imtk_draw_frame(int x, int y, int w, int h, int style);
    4.30 +void imtk_draw_string(int x, int y, const char *str);
    4.31 +int imtk_string_size(const char *str);
    4.32 +
    4.33 +#endif	/* DRAW_H_ */
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/slider.c	Thu Apr 14 14:22:42 2011 +0300
     5.3 @@ -0,0 +1,105 @@
     5.4 +#include <stdio.h>
     5.5 +#include <assert.h>
     5.6 +#include "imtk.h"
     5.7 +#include "state.h"
     5.8 +#include "draw.h"
     5.9 +
    5.10 +#define SLIDER_SIZE		100
    5.11 +#define THUMB_WIDTH		10
    5.12 +#define THUMB_HEIGHT	20
    5.13 +
    5.14 +static void draw_slider(int id, float pos, float min, float max, int x, int y);
    5.15 +
    5.16 +float imtk_slider(int id, float pos, float min, float max, int x, int y)
    5.17 +{
    5.18 +	int mousex, mousey, thumb_x, thumb_y, over = 0;
    5.19 +	float range = max - min;
    5.20 +
    5.21 +	assert(id >= 0);
    5.22 +
    5.23 +	imtk_get_mouse(&mousex, &mousey);
    5.24 +
    5.25 +	pos = (pos - min) / range;
    5.26 +	if(pos < 0.0) pos = 0.0;
    5.27 +	if(pos > 1.0) pos = 1.0;
    5.28 +
    5.29 +	thumb_x = x + SLIDER_SIZE * pos - THUMB_WIDTH / 2;
    5.30 +	thumb_y = y - THUMB_HEIGHT / 2;
    5.31 +
    5.32 +	if(imtk_hit_test(thumb_x, thumb_y, THUMB_WIDTH, THUMB_HEIGHT)) {
    5.33 +		imtk_set_hot(id);
    5.34 +		over = 1;
    5.35 +	}
    5.36 +
    5.37 +	if(imtk_button_state(IMTK_LEFT_BUTTON)) {
    5.38 +		if(over && imtk_is_hot(id)) {
    5.39 +			if(!imtk_is_active(id)) {
    5.40 +				imtk_set_prev_mouse(mousex, mousey);
    5.41 +			}
    5.42 +			imtk_set_active(id);
    5.43 +		}
    5.44 +	} else {
    5.45 +		if(imtk_is_active(id)) {
    5.46 +			imtk_set_active(-1);
    5.47 +		}
    5.48 +	}
    5.49 +
    5.50 +	if(imtk_is_active(id)) {
    5.51 +		int prevx;
    5.52 +		float dx;
    5.53 +
    5.54 +		imtk_get_prev_mouse(&prevx, 0);
    5.55 +
    5.56 +		dx = (float)(mousex - prevx) / (float)SLIDER_SIZE;
    5.57 +		pos += dx;
    5.58 +		prevx = mousex;
    5.59 +
    5.60 +		if(pos < 0.0) pos = 0.0;
    5.61 +		if(pos > 1.0) pos = 1.0;
    5.62 +	}
    5.63 +
    5.64 +	draw_slider(id, pos, min, max, x, y);
    5.65 +	return pos * range + min;
    5.66 +}
    5.67 +
    5.68 +
    5.69 +static void draw_slider(int id, float pos, float min, float max, int x, int y)
    5.70 +{
    5.71 +	float range = max - min;
    5.72 +	int thumb_x, thumb_y;
    5.73 +	char buf[32];
    5.74 +
    5.75 +	thumb_x = x + SLIDER_SIZE * pos - THUMB_WIDTH / 2;
    5.76 +	thumb_y = y - THUMB_HEIGHT / 2;
    5.77 +
    5.78 +	/* draw trough */
    5.79 +	glBegin(GL_QUADS);
    5.80 +	glColor4fv(imtk_get_color(IMTK_BASE_COLOR));
    5.81 +	glVertex2f(x, y - 2);
    5.82 +	glVertex2f(x + SLIDER_SIZE, y - 2);
    5.83 +	glVertex2f(x + SLIDER_SIZE, y + 2);
    5.84 +	glVertex2f(x, y + 2);
    5.85 +	glEnd();
    5.86 +	imtk_draw_frame(x, y - 2, SLIDER_SIZE, 4, FRAME_INSET);
    5.87 +
    5.88 +	if(imtk_hit_test(thumb_x, thumb_y, THUMB_WIDTH, THUMB_HEIGHT)) {
    5.89 +		glColor4fv(imtk_get_color(IMTK_FOCUS_COLOR));
    5.90 +	} else {
    5.91 +		glColor4fv(imtk_get_color(IMTK_BASE_COLOR));
    5.92 +	}
    5.93 +
    5.94 +	/* draw handle */
    5.95 +	glBegin(GL_QUADS);
    5.96 +	glVertex2f(thumb_x, thumb_y);
    5.97 +	glVertex2f(thumb_x + THUMB_WIDTH, thumb_y);
    5.98 +	glVertex2f(thumb_x + THUMB_WIDTH, thumb_y + THUMB_HEIGHT);
    5.99 +	glVertex2f(thumb_x, thumb_y + THUMB_HEIGHT);
   5.100 +	glEnd();
   5.101 +	imtk_draw_frame(thumb_x, thumb_y, THUMB_WIDTH, THUMB_HEIGHT, FRAME_OUTSET);
   5.102 +
   5.103 +	/* draw display */
   5.104 +	sprintf(buf, "%.3f", pos * range + min);
   5.105 +	glColor4fv(imtk_get_color(IMTK_TEXT_COLOR));
   5.106 +	imtk_draw_string(x + SLIDER_SIZE + THUMB_WIDTH / 2 + 2, y + 4, buf);
   5.107 +}
   5.108 +
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/state.c	Thu Apr 14 14:22:42 2011 +0300
     6.3 @@ -0,0 +1,148 @@
     6.4 +#include "state.h"
     6.5 +#include "imtk.h"
     6.6 +
     6.7 +struct key_node {
     6.8 +	int key;
     6.9 +	struct key_node *next;
    6.10 +};
    6.11 +
    6.12 +
    6.13 +struct imtk_state st = {
    6.14 +	1, 1,			/* scr_width/scr_height */
    6.15 +	0, 0, 0, 0, 0,	/* mousex/mousey, prevx, prevy, mouse_bnmask */
    6.16 +	-1, -1, -1, -1	/* active, hot, input, prev_active */
    6.17 +};
    6.18 +
    6.19 +static struct key_node *key_list, *key_tail;
    6.20 +
    6.21 +
    6.22 +
    6.23 +void imtk_inp_key(int key, int state)
    6.24 +{
    6.25 +	if(state == IMTK_DOWN) {
    6.26 +		struct key_node *node;
    6.27 +
    6.28 +		if(!(node = malloc(sizeof *node))) {
    6.29 +			return;
    6.30 +		}
    6.31 +		node->key = key;
    6.32 +		node->next = 0;
    6.33 +
    6.34 +		if(key_list) {
    6.35 +			key_tail->next = node;
    6.36 +			key_tail = node;
    6.37 +		} else {
    6.38 +			key_list = key_tail = node;
    6.39 +		}
    6.40 +	}
    6.41 +
    6.42 +	imtk_post_redisplay();
    6.43 +}
    6.44 +
    6.45 +void imtk_inp_mouse(int bn, int state)
    6.46 +{
    6.47 +	if(state == IMTK_DOWN) {
    6.48 +		st.mouse_bnmask |= 1 << bn;
    6.49 +	} else {
    6.50 +		st.mouse_bnmask &= ~(1 << bn);
    6.51 +	}
    6.52 +	imtk_post_redisplay();
    6.53 +}
    6.54 +
    6.55 +void imtk_inp_motion(int x, int y)
    6.56 +{
    6.57 +	st.mousex = x;
    6.58 +	st.mousey = y;
    6.59 +
    6.60 +	imtk_post_redisplay();
    6.61 +}
    6.62 +
    6.63 +void imtk_inp_reshape(int x, int y)
    6.64 +{
    6.65 +	st.scr_width = x;
    6.66 +	st.scr_height = y;
    6.67 +}
    6.68 +
    6.69 +
    6.70 +void imtk_set_active(int id)
    6.71 +{
    6.72 +	if(id == -1 || st.hot == id) {
    6.73 +		st.prev_active = st.active;
    6.74 +		st.active = id;
    6.75 +	}
    6.76 +}
    6.77 +
    6.78 +int imtk_is_active(int id)
    6.79 +{
    6.80 +	return st.active == id;
    6.81 +}
    6.82 +
    6.83 +int imtk_set_hot(int id)
    6.84 +{
    6.85 +	if(st.active == -1) {
    6.86 +		st.hot = id;
    6.87 +		return 1;
    6.88 +	}
    6.89 +	return 0;
    6.90 +}
    6.91 +
    6.92 +int imtk_is_hot(int id)
    6.93 +{
    6.94 +	return st.hot == id;
    6.95 +}
    6.96 +
    6.97 +void imtk_set_focus(int id)
    6.98 +{
    6.99 +	st.input = id;
   6.100 +}
   6.101 +
   6.102 +int imtk_has_focus(int id)
   6.103 +{
   6.104 +	return st.input == id;
   6.105 +}
   6.106 +
   6.107 +int imtk_hit_test(int x, int y, int w, int h)
   6.108 +{
   6.109 +	return st.mousex >= x && st.mousex < (x + w) &&
   6.110 +		st.mousey >= y && st.mousey < (y + h);
   6.111 +}
   6.112 +
   6.113 +void imtk_get_mouse(int *xptr, int *yptr)
   6.114 +{
   6.115 +	if(xptr) *xptr = st.mousex;
   6.116 +	if(yptr) *yptr = st.mousey;
   6.117 +}
   6.118 +
   6.119 +void imtk_set_prev_mouse(int x, int y)
   6.120 +{
   6.121 +	st.prevx = x;
   6.122 +	st.prevy = y;
   6.123 +}
   6.124 +
   6.125 +void imtk_get_prev_mouse(int *xptr, int *yptr)
   6.126 +{
   6.127 +	if(xptr) *xptr = st.prevx;
   6.128 +	if(yptr) *yptr = st.prevy;
   6.129 +}
   6.130 +
   6.131 +int imtk_button_state(int bn)
   6.132 +{
   6.133 +	return st.mouse_bnmask & (1 << bn);
   6.134 +}
   6.135 +
   6.136 +
   6.137 +int imtk_get_key(void)
   6.138 +{
   6.139 +	int key = -1;
   6.140 +	struct key_node *node = key_list;
   6.141 +
   6.142 +	if(node) {
   6.143 +		key = node->key;
   6.144 +		key_list = node->next;
   6.145 +		if(!key_list) {
   6.146 +			key_tail = 0;
   6.147 +		}
   6.148 +		free(node);
   6.149 +	}
   6.150 +	return key;
   6.151 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/state.h	Thu Apr 14 14:22:42 2011 +0300
     7.3 @@ -0,0 +1,26 @@
     7.4 +#ifndef STATE_H_
     7.5 +#define STATE_H_
     7.6 +
     7.7 +struct imtk_state {
     7.8 +	int scr_width, scr_height;
     7.9 +	int mousex, mousey, prevx, prevy, mouse_bnmask;
    7.10 +	int active, hot, input, prev_active;
    7.11 +};
    7.12 +
    7.13 +void imtk_set_active(int id);
    7.14 +int imtk_is_active(int id);
    7.15 +int imtk_set_hot(int id);
    7.16 +int imtk_is_hot(int id);
    7.17 +void imtk_set_focus(int id);
    7.18 +int imtk_has_focus(int id);
    7.19 +int imtk_hit_test(int x, int y, int w, int h);
    7.20 +
    7.21 +void imtk_get_mouse(int *xptr, int *yptr);
    7.22 +void imtk_set_prev_mouse(int x, int y);
    7.23 +void imtk_get_prev_mouse(int *xptr, int *yptr);
    7.24 +int imtk_button_state(int bn);
    7.25 +
    7.26 +int imtk_get_key(void);
    7.27 +
    7.28 +
    7.29 +#endif	/* STATE_H_ */
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/textbox.c	Thu Apr 14 14:22:42 2011 +0300
     8.3 @@ -0,0 +1,95 @@
     8.4 +#include <string.h>
     8.5 +#include <ctype.h>
     8.6 +#include <assert.h>
     8.7 +#include "imtk.h"
     8.8 +#include "state.h"
     8.9 +#include "draw.h"
    8.10 +
    8.11 +#define TEXTBOX_SIZE	100
    8.12 +
    8.13 +static void draw_textbox(int id, const char *text, int x, int y);
    8.14 +
    8.15 +
    8.16 +void imtk_textbox(int id, char *textbuf, size_t buf_sz, int x, int y)
    8.17 +{
    8.18 +	int len, over = 0;
    8.19 +
    8.20 +	assert(id >= 0);
    8.21 +
    8.22 +	if(imtk_hit_test(x, y, TEXTBOX_SIZE, 20)) {
    8.23 +		imtk_set_hot(id);
    8.24 +		over = 1;
    8.25 +	}
    8.26 +
    8.27 +	if(imtk_button_state(IMTK_LEFT_BUTTON)) {
    8.28 +		if(over) {
    8.29 +			imtk_set_active(id);
    8.30 +		}
    8.31 +	} else {
    8.32 +		if(imtk_is_active(id)) {
    8.33 +			imtk_set_active(-1);
    8.34 +			if(imtk_is_hot(id) && over) {
    8.35 +				imtk_set_focus(id);
    8.36 +			}
    8.37 +		}
    8.38 +	}
    8.39 +
    8.40 +	if(imtk_has_focus(id)) {
    8.41 +		int key;
    8.42 +		len = strlen(textbuf);
    8.43 +
    8.44 +		while((key = imtk_get_key()) != -1) {
    8.45 +			if(isprint(key)) {
    8.46 +				if(len < buf_sz) {
    8.47 +					textbuf[len++] = (char)key;
    8.48 +				}
    8.49 +			} else {
    8.50 +				switch(key) {
    8.51 +				case '\b':
    8.52 +					if(len > 0) {
    8.53 +						textbuf[--len] = 0;
    8.54 +					}
    8.55 +					break;
    8.56 +
    8.57 +				default:
    8.58 +					break;
    8.59 +				}
    8.60 +			}
    8.61 +		}
    8.62 +	}
    8.63 +
    8.64 +	draw_textbox(id, textbuf, x, y);
    8.65 +}
    8.66 +
    8.67 +
    8.68 +static void draw_textbox(int id, const char *text, int x, int y)
    8.69 +{
    8.70 +	int strsz = imtk_string_size(text);
    8.71 +
    8.72 +	if(imtk_hit_test(x, y, TEXTBOX_SIZE, 20)) {
    8.73 +		glColor4fv(imtk_get_color(IMTK_FOCUS_COLOR));
    8.74 +	} else {
    8.75 +		glColor4fv(imtk_get_color(IMTK_BASE_COLOR));
    8.76 +	}
    8.77 +
    8.78 +	glBegin(GL_QUADS);
    8.79 +	glVertex2f(x, y);
    8.80 +	glVertex2f(x + TEXTBOX_SIZE, y);
    8.81 +	glVertex2f(x + TEXTBOX_SIZE, y + 20);
    8.82 +	glVertex2f(x, y + 20);
    8.83 +	glEnd();
    8.84 +
    8.85 +	glColor4fv(imtk_get_color(IMTK_TEXT_COLOR));
    8.86 +
    8.87 +	if(imtk_has_focus(id)) {
    8.88 +		glBegin(GL_LINES);
    8.89 +		glVertex2f(x + strsz + 2, y + 2);
    8.90 +		glVertex2f(x + strsz + 2, y + 18);
    8.91 +		glEnd();
    8.92 +	}
    8.93 +
    8.94 +	imtk_draw_string(x + 2, y + 15, text);
    8.95 +
    8.96 +	imtk_draw_frame(x, y, TEXTBOX_SIZE, 20, FRAME_INSET);
    8.97 +}
    8.98 +