imtk

view src/imtk.c @ 2:3d661dd17af3

- initial textbox implementation added - made the test program slightly more interesting
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 31 Dec 2010 01:54:53 +0200
parents dfbd12d1f566
children 038e5577d527
line source
1 #include <stdlib.h>
2 #include <string.h>
3 #include <ctype.h>
4 #include <assert.h>
5 #ifndef __APPLE__
6 #include <GL/glut.h>
7 #else
8 #include <GLUT/glut.h>
9 #endif
10 #include "imtk.h"
12 #define CHECKBOX_SIZE 14
13 #define TEXTBOX_SIZE 100
15 enum {
16 FRAME_OUTSET,
17 FRAME_INSET
18 };
20 struct key_node {
21 int key;
22 struct key_node *next;
23 };
25 static void set_active(int id);
26 static int set_hot(int id);
27 static int hit_test(int x, int y, int w, int h);
29 static void draw_button(int id, const char *label, int x, int y);
30 static void calc_button_size(const char *label, int *wret, int *hret);
31 static void draw_checkbox(int id, const char *label, int x, int y, int state);
32 static void draw_textbox(int id, const char *text, int x, int y);
33 static void draw_string(int x, int y, const char *str);
34 static int string_size(const char *str);
35 static void draw_frame(int x, int y, int w, int h, int style);
38 /* default colors, can be changed with imtk_set_color */
39 static float colors[][4] = {
40 {0.0, 0.0, 0.0}, /* text color */
41 {0.7, 0.7, 0.7}, /* base color */
42 {0.85, 0.85, 0.85}, /* focus color */
43 {1.0, 1.0, 1.0}, /* lit bevel */
44 {0.3, 0.3, 0.3} /* shadowed bevel */
45 };
47 static int scr_width = 1, scr_height = 1;
48 static int mousex, mousey, mouse_bnmask;
49 static int active = -1, hot = -1, input = -1;
51 static struct key_node *key_list, *key_tail;
54 void imtk_set_color(int col, float r, float g, float b)
55 {
56 assert(col >= 0 && col < sizeof colors / sizeof *colors);
58 colors[col][0] = r;
59 colors[col][1] = g;
60 colors[col][2] = b;
61 }
63 void imtk_inp_key(int key, int state)
64 {
65 if(state == IMTK_DOWN) {
66 struct key_node *node;
68 if(!(node = malloc(sizeof *node))) {
69 return;
70 }
71 node->key = key;
72 node->next = 0;
74 if(key_list) {
75 key_tail->next = node;
76 key_tail = node;
77 } else {
78 key_list = key_tail = node;
79 }
80 }
82 glutPostRedisplay();
83 }
85 void imtk_inp_mouse(int bn, int state)
86 {
87 if(state == IMTK_DOWN) {
88 mouse_bnmask |= 1 << bn;
89 } else {
90 mouse_bnmask &= ~(1 << bn);
91 }
92 glutPostRedisplay();
93 }
95 void imtk_inp_motion(int x, int y)
96 {
97 mousex = x;
98 mousey = y;
100 glutPostRedisplay();
101 }
103 void imtk_inp_reshape(int x, int y)
104 {
105 scr_width = x;
106 scr_height = y;
107 }
109 void imtk_begin(void)
110 {
111 glMatrixMode(GL_PROJECTION);
112 glPushMatrix();
113 glLoadIdentity();
114 glTranslatef(-1, 1, 0);
115 glScalef(2.0 / scr_width, -2.0 / scr_height, 1.0);
117 glMatrixMode(GL_MODELVIEW);
118 glPushMatrix();
119 glLoadIdentity();
121 glPushAttrib(GL_ENABLE_BIT);
122 glDisable(GL_DEPTH_TEST);
123 glDisable(GL_CULL_FACE);
124 glDisable(GL_LIGHTING);
125 }
127 void imtk_end(void)
128 {
129 glPopAttrib();
131 glMatrixMode(GL_PROJECTION);
132 glPopMatrix();
133 glMatrixMode(GL_MODELVIEW);
134 glPopMatrix();
135 }
137 int imtk_button(int id, const char *label, int x, int y)
138 {
139 int w, h, res = 0;
140 int over = 0;
142 assert(id >= 0);
144 calc_button_size(label, &w, &h);
146 if(hit_test(x, y, w, h)) {
147 set_hot(id);
148 over = 1;
149 }
151 if(mouse_bnmask & (1 << IMTK_LEFT_BUTTON)) {
152 if(over) {
153 set_active(id);
154 }
155 } else { /* mouse button up */
156 if(active == id) {
157 set_active(-1);
158 if(hot == id && over) {
159 res = 1;
160 }
161 }
162 }
164 draw_button(id, label, x, y);
165 return res;
166 }
168 int imtk_checkbox(int id, const char *label, int x, int y, int state)
169 {
170 int sz = CHECKBOX_SIZE;
171 int over = 0;
173 assert(id >= 0);
175 if(hit_test(x, y, sz, sz)) {
176 set_hot(id);
177 over = 1;
178 }
180 if(mouse_bnmask & (1 << IMTK_LEFT_BUTTON)) {
181 if(over) {
182 set_active(id);
183 }
184 } else { /* mouse button up */
185 if(active == id) {
186 set_active(-1);
187 if(hot == id && over) {
188 state = !state;
189 }
190 }
191 }
193 draw_checkbox(id, label, x, y, state);
194 return state;
195 }
197 void imtk_textbox(int id, char *textbuf, size_t buf_sz, int x, int y)
198 {
199 int len, over = 0;
201 assert(id >= 0);
203 if(hit_test(x, y, TEXTBOX_SIZE, 20)) {
204 set_hot(id);
205 over = 1;
206 }
208 if(mouse_bnmask & (1 << IMTK_LEFT_BUTTON)) {
209 if(over) {
210 set_active(id);
211 }
212 } else {
213 if(active == id) {
214 set_active(-1);
215 if(hot == id && over) {
216 input = id;
217 }
218 }
219 }
221 if(input == id) {
222 len = strlen(textbuf);
223 while(key_list) {
224 struct key_node *node = key_list;
225 key_list = key_list->next;
227 if(isprint(node->key)) {
228 if(len < buf_sz) {
229 textbuf[len++] = (char)node->key;
230 }
231 } else {
232 switch(node->key) {
233 case '\b':
234 if(len > 0) {
235 textbuf[--len] = 0;
236 }
237 break;
239 default:
240 break;
241 }
242 }
244 free(node);
245 }
246 key_list = key_tail = 0;
247 }
249 draw_textbox(id, textbuf, x, y);
250 }
252 static void set_active(int id)
253 {
254 active = id;
255 }
257 static int set_hot(int id)
258 {
259 if(active == -1) {
260 hot = id;
261 return 1;
262 }
263 return 0;
264 }
266 static int hit_test(int x, int y, int w, int h)
267 {
268 return mousex >= x && mousex < (x + w) &&
269 mousey >= y && mousey < (y + h);
270 }
272 static void draw_button(int id, const char *label, int x, int y)
273 {
274 int width, height;
276 calc_button_size(label, &width, &height);
278 glBegin(GL_QUADS);
279 if(hit_test(x, y, width, height)) {
280 glColor3fv(colors[IMTK_FOCUS_COLOR]);
281 } else {
282 glColor3fv(colors[IMTK_BASE_COLOR]);
283 }
284 glVertex2f(x, y);
285 glVertex2f(x + width, y);
286 glVertex2f(x + width, y + height);
287 glVertex2f(x, y + height);
288 glEnd();
290 draw_frame(x, y, width, height, active == id ? FRAME_INSET : FRAME_OUTSET);
292 glColor3fv(colors[IMTK_TEXT_COLOR]);
293 draw_string(x + 20, y + 15, label);
294 }
296 static void calc_button_size(const char *label, int *wret, int *hret)
297 {
298 int strsz = string_size(label);
299 if(wret) *wret = strsz + 40;
300 if(hret) *hret = 20;
301 }
303 static void draw_checkbox(int id, const char *label, int x, int y, int state)
304 {
305 static const int sz = CHECKBOX_SIZE;
307 if(hit_test(x, y, sz, sz)) {
308 glColor3fv(colors[IMTK_FOCUS_COLOR]);
309 } else {
310 glColor3fv(colors[IMTK_BASE_COLOR]);
311 }
313 glBegin(GL_QUADS);
314 glVertex2f(x, y);
315 glVertex2f(x + sz, y);
316 glVertex2f(x + sz, y + sz);
317 glVertex2f(x, y + sz);
318 glEnd();
320 draw_frame(x, y, sz, sz, FRAME_INSET);
322 glColor3fv(colors[IMTK_TEXT_COLOR]);
323 if(state) {
324 glPushAttrib(GL_LINE_BIT);
325 glLineWidth(2);
327 glBegin(GL_LINES);
328 glVertex2f(x + 2, y + 2);
329 glVertex2f(x + sz - 2, y + sz - 2);
330 glVertex2f(x + sz - 2, y + 2);
331 glVertex2f(x + 2, y + sz - 2);
332 glEnd();
334 glPopAttrib();
335 }
337 draw_string(x + sz + 5, y + sz - 2, label);
338 }
340 static void draw_textbox(int id, const char *text, int x, int y)
341 {
342 int strsz = string_size(text);
344 if(hit_test(x, y, TEXTBOX_SIZE, 20)) {
345 glColor3fv(colors[IMTK_FOCUS_COLOR]);
346 } else {
347 glColor3fv(colors[IMTK_BASE_COLOR]);
348 }
350 glBegin(GL_QUADS);
351 glVertex2f(x, y);
352 glVertex2f(x + TEXTBOX_SIZE, y);
353 glVertex2f(x + TEXTBOX_SIZE, y + 20);
354 glVertex2f(x, y + 20);
355 glEnd();
357 glColor3fv(colors[IMTK_TEXT_COLOR]);
359 if(input == id) {
360 glBegin(GL_LINES);
361 glVertex2f(x + strsz + 2, y + 2);
362 glVertex2f(x + strsz + 2, y + 18);
363 glEnd();
364 }
366 draw_string(x + 2, y + 15, text);
368 draw_frame(x, y, TEXTBOX_SIZE, 20, FRAME_INSET);
369 }
371 static void draw_string(int x, int y, const char *str)
372 {
373 glRasterPos2i(x, y);
374 while(*str) {
375 glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, *str++);
376 }
377 }
379 static int string_size(const char *str)
380 {
381 return glutBitmapLength(GLUT_BITMAP_HELVETICA_12, (const unsigned char*)str);
382 }
384 static void draw_frame(int x, int y, int w, int h, int style)
385 {
386 float tcol[3], bcol[3];
388 switch(style) {
389 case FRAME_INSET:
390 memcpy(tcol, colors[IMTK_BEVEL_SHAD_COLOR], sizeof tcol);
391 memcpy(bcol, colors[IMTK_BEVEL_LIT_COLOR], sizeof bcol);
392 break;
394 case FRAME_OUTSET:
395 default:
396 memcpy(tcol, colors[IMTK_BEVEL_LIT_COLOR], sizeof tcol);
397 memcpy(bcol, colors[IMTK_BEVEL_SHAD_COLOR], sizeof bcol);
398 }
400 glBegin(GL_LINES);
401 glColor3fv(tcol);
402 glVertex2f(x, y + h);
403 glVertex2f(x, y);
404 glVertex2f(x, y);
405 glVertex2f(x + w, y);
406 glColor3fv(bcol);
407 glVertex2f(x + w, y);
408 glVertex2f(x + w, y + h);
409 glVertex2f(x + w, y + h);
410 glVertex2f(x, y + h);
411 glEnd();
412 }