glamtk

view src/imtk.c @ 7:a115dff39a54

rounded crappy buttons
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 11 Mar 2011 02:25:49 +0200
parents 00a4ea4ee6dc
children cd00a5775373
line source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <stdarg.h>
6 #include <assert.h>
7 #ifndef __APPLE__
8 #include <GL/glut.h>
9 #else
10 #include <GLUT/glut.h>
11 #endif
12 #include "imtk.h"
13 #include "draw.h"
15 #define CHECKBOX_SIZE 14
16 #define TEXTBOX_SIZE 100
17 #define SLIDER_SIZE 100
18 #define THUMB_WIDTH 10
19 #define THUMB_HEIGHT 20
21 enum {
22 FRAME_OUTSET,
23 FRAME_INSET
24 };
26 struct key_node {
27 int key;
28 struct key_node *next;
29 };
31 static void set_active(int id);
32 static int set_hot(int id);
33 static int hit_test(int x, int y, int w, int h);
35 static void draw_button(int id, const char *label, int x, int y);
36 static void calc_button_size(const char *label, int *wret, int *hret);
37 static void draw_checkbox(int id, const char *label, int x, int y, int state);
38 static void draw_textbox(int id, const char *text, int x, int y);
39 static void draw_slider(int id, float pos, float min, float max, int x, int y);
40 static void draw_progress(int id, float pos, int x, int y);
41 static void draw_string(int x, int y, const char *str);
42 static int string_size(const char *str);
43 static void draw_frame(int x, int y, int w, int h, int style);
46 /* default colors, can be changed with imtk_set_color */
47 static float colors[][4] = {
48 {0.0, 0.0, 0.0, 0.7}, /* text color */
49 {0.6, 0.6, 0.6, 0.7}, /* base color */
50 {0.7, 0.7, 0.7, 0.7}, /* focus color */
51 {1.0, 1.0, 1.0, 1.0}, /* lit bevel */
52 {0.3, 0.3, 0.3, 1.0} /* shadowed bevel */
53 };
55 static int scr_width = 1, scr_height = 1;
56 static int mousex, mousey, prevx, mouse_bnmask;
57 static int active = -1, hot = -1, input = -1, prev_active = -1;
59 static struct key_node *key_list, *key_tail;
62 void imtk_set_color(int col, float r, float g, float b)
63 {
64 assert(col >= 0 && col < sizeof colors / sizeof *colors);
66 colors[col][0] = r;
67 colors[col][1] = g;
68 colors[col][2] = b;
69 }
71 void imtk_inp_key(int key, int state)
72 {
73 if(state == IMTK_DOWN) {
74 struct key_node *node;
76 if(!(node = malloc(sizeof *node))) {
77 return;
78 }
79 node->key = key;
80 node->next = 0;
82 if(key_list) {
83 key_tail->next = node;
84 key_tail = node;
85 } else {
86 key_list = key_tail = node;
87 }
88 }
90 glutPostRedisplay();
91 }
93 void imtk_inp_mouse(int bn, int state)
94 {
95 if(state == IMTK_DOWN) {
96 mouse_bnmask |= 1 << bn;
97 } else {
98 mouse_bnmask &= ~(1 << bn);
99 }
100 glutPostRedisplay();
101 }
103 void imtk_inp_motion(int x, int y)
104 {
105 mousex = x;
106 mousey = y;
108 glutPostRedisplay();
109 }
111 void imtk_inp_reshape(int x, int y)
112 {
113 scr_width = x;
114 scr_height = y;
115 }
117 void imtk_begin(void)
118 {
119 glMatrixMode(GL_PROJECTION);
120 glPushMatrix();
121 glLoadIdentity();
122 glTranslatef(-1, 1, 0);
123 glScalef(2.0 / scr_width, -2.0 / scr_height, 1.0);
125 glMatrixMode(GL_MODELVIEW);
126 glPushMatrix();
127 glLoadIdentity();
129 glPushAttrib(GL_ENABLE_BIT);
130 glDisable(GL_DEPTH_TEST);
131 glDisable(GL_CULL_FACE);
132 glDisable(GL_LIGHTING);
133 }
135 void imtk_end(void)
136 {
137 glPopAttrib();
139 glMatrixMode(GL_PROJECTION);
140 glPopMatrix();
141 glMatrixMode(GL_MODELVIEW);
142 glPopMatrix();
143 }
145 int imtk_button(int id, const char *label, int x, int y)
146 {
147 int w, h, res = 0;
148 int over = 0;
150 assert(id >= 0);
152 calc_button_size(label, &w, &h);
154 if(hit_test(x, y, w, h)) {
155 set_hot(id);
156 over = 1;
157 }
159 if(mouse_bnmask & (1 << IMTK_LEFT_BUTTON)) {
160 if(over) {
161 set_active(id);
162 }
163 } else { /* mouse button up */
164 if(active == id) {
165 set_active(-1);
166 if(hot == id && over) {
167 res = 1;
168 }
169 }
170 }
172 draw_button(id, label, x, y);
173 return res;
174 }
176 int imtk_checkbox(int id, const char *label, int x, int y, int state)
177 {
178 int sz = CHECKBOX_SIZE;
179 int over = 0;
181 assert(id >= 0);
183 if(hit_test(x, y, sz, sz)) {
184 set_hot(id);
185 over = 1;
186 }
188 if(mouse_bnmask & (1 << IMTK_LEFT_BUTTON)) {
189 if(over) {
190 set_active(id);
191 }
192 } else { /* mouse button up */
193 if(active == id) {
194 set_active(-1);
195 if(hot == id && over) {
196 state = !state;
197 }
198 }
199 }
201 draw_checkbox(id, label, x, y, state);
202 return state;
203 }
205 void imtk_textbox(int id, char *textbuf, size_t buf_sz, int x, int y)
206 {
207 int len, over = 0;
209 assert(id >= 0);
211 if(hit_test(x, y, TEXTBOX_SIZE, 20)) {
212 set_hot(id);
213 over = 1;
214 }
216 if(mouse_bnmask & (1 << IMTK_LEFT_BUTTON)) {
217 if(over) {
218 set_active(id);
219 }
220 } else {
221 if(active == id) {
222 set_active(-1);
223 if(hot == id && over) {
224 input = id;
225 }
226 }
227 }
229 if(input == id) {
230 len = strlen(textbuf);
231 while(key_list) {
232 struct key_node *node = key_list;
233 key_list = key_list->next;
235 if(isprint(node->key)) {
236 if(len < buf_sz) {
237 textbuf[len++] = (char)node->key;
238 }
239 } else {
240 switch(node->key) {
241 case '\b':
242 if(len > 0) {
243 textbuf[--len] = 0;
244 }
245 break;
247 default:
248 break;
249 }
250 }
252 free(node);
253 }
254 key_list = key_tail = 0;
255 }
257 draw_textbox(id, textbuf, x, y);
258 }
260 float imtk_slider(int id, float pos, float min, float max, int x, int y)
261 {
262 int thumb_x, thumb_y, over = 0;
263 float range = max - min;
265 assert(id >= 0);
267 pos = (pos - min) / range;
268 if(pos < 0.0) pos = 0.0;
269 if(pos > 1.0) pos = 1.0;
271 thumb_x = x + SLIDER_SIZE * pos - THUMB_WIDTH / 2;
272 thumb_y = y - THUMB_HEIGHT / 2;
274 if(hit_test(thumb_x, thumb_y, THUMB_WIDTH, THUMB_HEIGHT)) {
275 set_hot(id);
276 over = 1;
277 }
279 if(mouse_bnmask & (1 << IMTK_LEFT_BUTTON)) {
280 if(over && hot == id) {
281 if(active != id) {
282 prevx = mousex;
283 }
284 set_active(id);
285 }
286 } else {
287 if(active == id) {
288 set_active(-1);
289 }
290 }
292 if(active == id) {
293 float dx = (float)(mousex - prevx) / (float)SLIDER_SIZE;
294 pos += dx;
295 prevx = mousex;
297 if(pos < 0.0) pos = 0.0;
298 if(pos > 1.0) pos = 1.0;
299 }
301 draw_slider(id, pos, min, max, x, y);
302 return pos * range + min;
303 }
305 void imtk_progress(int id, float pos, int x, int y)
306 {
307 draw_progress(id, pos, x, y);
308 }
310 int imtk_listbox(int id, const char *list, int sel, int x, int y)
311 {
312 int i;
313 assert(id >= 0);
315 if(!list) {
316 return -1;
317 }
319 if(id & 1) {
320 id++;
321 }
323 for(i=0; *list; i++) {
324 if(imtk_button(id + i * 2 + 1, list, x, y + i * 20)) {
325 sel = i;
326 }
327 list += strlen(list) + 1;
328 }
329 return sel;
330 }
332 int imtk_combobox(int id, char *textbuf, size_t buf_sz, const char *list, int sel, int x, int y)
333 {
334 imtk_textbox(id + 1, textbuf, buf_sz, x, y);
335 imtk_button(id + 3, "V", x + TEXTBOX_SIZE, y);
337 if(prev_active == id + 3) {
338 sel = imtk_listbox(id + 5, list, sel, x, y + 20);
339 }
340 return sel;
341 }
343 char *imtk_create_list(const char *first, ...)
344 {
345 int sz;
346 char *buf, *item;
347 va_list ap;
349 if(!first) {
350 return 0;
351 }
353 sz = strlen(first) + 2;
354 if(!(buf = malloc(sz))) {
355 return 0;
356 }
357 memcpy(buf, first, sz - 2);
358 buf[sz - 1] = buf[sz - 2] = 0;
360 va_start(ap, first);
361 while((item = va_arg(ap, char*))) {
362 int len = strlen(item);
363 char *tmp = realloc(buf, sz + len + 1);
364 if(!tmp) {
365 free(buf);
366 return 0;
367 }
368 buf = tmp;
370 memcpy(buf + sz - 1, item, len);
371 sz += len + 1;
372 buf[sz - 1] = buf[sz - 2] = 0;
373 }
374 va_end(ap);
376 return buf;
377 }
379 void imtk_free_list(char *list)
380 {
381 free(list);
382 }
384 static void set_active(int id)
385 {
386 if(id == -1 || hot == id) {
387 prev_active = active;
388 active = id;
389 }
390 }
392 static int set_hot(int id)
393 {
394 if(active == -1) {
395 hot = id;
396 return 1;
397 }
398 return 0;
399 }
401 static int hit_test(int x, int y, int w, int h)
402 {
403 return mousex >= x && mousex < (x + w) &&
404 mousey >= y && mousey < (y + h);
405 }
407 static void draw_button(int id, const char *label, int x, int y)
408 {
409 int width, height;
411 calc_button_size(label, &width, &height);
413 /*
414 glBegin(GL_QUADS);
415 if(hit_test(x, y, width, height)) {
416 glColor3fv(colors[IMTK_FOCUS_COLOR]);
417 } else {
418 glColor3fv(colors[IMTK_BASE_COLOR]);
419 }
420 glVertex2f(x, y);
421 glVertex2f(x + width, y);
422 glVertex2f(x + width, y + height);
423 glVertex2f(x, y + height);
424 glEnd();
426 draw_frame(x, y, width, height, active == id ? FRAME_INSET : FRAME_OUTSET);
427 */
429 if(hit_test(x, y, width, height)) {
430 imtk_draw_backgroundv(colors[IMTK_FOCUS_COLOR]);
431 } else {
432 imtk_draw_backgroundv(colors[IMTK_BASE_COLOR]);
433 }
434 imtk_draw_rect(x, y, width, height, 8);
436 glColor3fv(colors[IMTK_TEXT_COLOR]);
437 draw_string(x + 20, y + 15, label);
438 }
440 static void calc_button_size(const char *label, int *wret, int *hret)
441 {
442 int strsz = string_size(label);
443 if(wret) *wret = strsz + 40;
444 if(hret) *hret = 20;
445 }
447 static void draw_checkbox(int id, const char *label, int x, int y, int state)
448 {
449 static const int sz = CHECKBOX_SIZE;
451 if(hit_test(x, y, sz, sz)) {
452 glColor3fv(colors[IMTK_FOCUS_COLOR]);
453 } else {
454 glColor3fv(colors[IMTK_BASE_COLOR]);
455 }
457 glBegin(GL_QUADS);
458 glVertex2f(x, y);
459 glVertex2f(x + sz, y);
460 glVertex2f(x + sz, y + sz);
461 glVertex2f(x, y + sz);
462 glEnd();
464 draw_frame(x, y, sz, sz, FRAME_INSET);
466 glColor3fv(colors[IMTK_TEXT_COLOR]);
467 if(state) {
468 glPushAttrib(GL_LINE_BIT);
469 glLineWidth(2);
471 glBegin(GL_LINES);
472 glVertex2f(x + 2, y + 2);
473 glVertex2f(x + sz - 2, y + sz - 2);
474 glVertex2f(x + sz - 2, y + 2);
475 glVertex2f(x + 2, y + sz - 2);
476 glEnd();
478 glPopAttrib();
479 }
481 draw_string(x + sz + 5, y + sz - 2, label);
482 }
484 static void draw_textbox(int id, const char *text, int x, int y)
485 {
486 int strsz = string_size(text);
488 if(hit_test(x, y, TEXTBOX_SIZE, 20)) {
489 glColor3fv(colors[IMTK_FOCUS_COLOR]);
490 } else {
491 glColor3fv(colors[IMTK_BASE_COLOR]);
492 }
494 glBegin(GL_QUADS);
495 glVertex2f(x, y);
496 glVertex2f(x + TEXTBOX_SIZE, y);
497 glVertex2f(x + TEXTBOX_SIZE, y + 20);
498 glVertex2f(x, y + 20);
499 glEnd();
501 glColor3fv(colors[IMTK_TEXT_COLOR]);
503 if(input == id) {
504 glBegin(GL_LINES);
505 glVertex2f(x + strsz + 2, y + 2);
506 glVertex2f(x + strsz + 2, y + 18);
507 glEnd();
508 }
510 draw_string(x + 2, y + 15, text);
512 draw_frame(x, y, TEXTBOX_SIZE, 20, FRAME_INSET);
513 }
515 static void draw_slider(int id, float pos, float min, float max, int x, int y)
516 {
517 float range = max - min;
518 int thumb_x, thumb_y;
519 char buf[32];
521 thumb_x = x + SLIDER_SIZE * pos - THUMB_WIDTH / 2;
522 thumb_y = y - THUMB_HEIGHT / 2;
524 /* draw trough */
525 glBegin(GL_QUADS);
526 glColor3fv(colors[IMTK_BASE_COLOR]);
527 glVertex2f(x, y - 2);
528 glVertex2f(x + SLIDER_SIZE, y - 2);
529 glVertex2f(x + SLIDER_SIZE, y + 2);
530 glVertex2f(x, y + 2);
531 glEnd();
532 draw_frame(x, y - 2, SLIDER_SIZE, 4, FRAME_INSET);
534 if(hit_test(thumb_x, thumb_y, THUMB_WIDTH, THUMB_HEIGHT)) {
535 glColor3fv(colors[IMTK_FOCUS_COLOR]);
536 } else {
537 glColor3fv(colors[IMTK_BASE_COLOR]);
538 }
540 /* draw handle */
541 glBegin(GL_QUADS);
542 glVertex2f(thumb_x, thumb_y);
543 glVertex2f(thumb_x + THUMB_WIDTH, thumb_y);
544 glVertex2f(thumb_x + THUMB_WIDTH, thumb_y + THUMB_HEIGHT);
545 glVertex2f(thumb_x, thumb_y + THUMB_HEIGHT);
546 glEnd();
547 draw_frame(thumb_x, thumb_y, THUMB_WIDTH, THUMB_HEIGHT, FRAME_OUTSET);
549 /* draw display */
550 sprintf(buf, "%.3f", pos * range + min);
551 glColor3fv(colors[IMTK_TEXT_COLOR]);
552 draw_string(x + SLIDER_SIZE + THUMB_WIDTH / 2 + 2, y + 4, buf);
553 }
555 static void draw_progress(int id, float pos, int x, int y)
556 {
557 int bar_size = SLIDER_SIZE * pos;
559 if(pos < 0.0) pos = 0.0;
560 if(pos > 1.0) pos = 1.0;
562 /* through */
563 glBegin(GL_QUADS);
564 glColor3fv(colors[IMTK_BASE_COLOR]);
565 glVertex2f(x - 1, y - 1);
566 glVertex2f(x + SLIDER_SIZE + 1, y - 1);
567 glVertex2f(x + SLIDER_SIZE + 1, y + 17);
568 glVertex2f(x - 1, y + 17);
569 glEnd();
570 draw_frame(x - 1, y - 1, SLIDER_SIZE + 2, 17, FRAME_INSET);
572 if(pos > 0.0) {
573 /* bar */
574 glBegin(GL_QUADS);
575 glColor3fv(colors[IMTK_BASE_COLOR]);
576 glVertex2f(x, y);
577 glVertex2f(x + bar_size, y);
578 glVertex2f(x + bar_size, y + 15);
579 glVertex2f(x, y + 15);
580 glEnd();
581 draw_frame(x, y, bar_size, 15, FRAME_OUTSET);
582 }
583 }
585 static void draw_string(int x, int y, const char *str)
586 {
587 glRasterPos2i(x, y);
588 while(*str) {
589 glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, *str++);
590 }
591 }
593 static int string_size(const char *str)
594 {
595 return glutBitmapLength(GLUT_BITMAP_HELVETICA_12, (const unsigned char*)str);
596 }
598 static void draw_frame(int x, int y, int w, int h, int style)
599 {
600 float tcol[3], bcol[3];
602 switch(style) {
603 case FRAME_INSET:
604 memcpy(tcol, colors[IMTK_BEVEL_SHAD_COLOR], sizeof tcol);
605 memcpy(bcol, colors[IMTK_BEVEL_LIT_COLOR], sizeof bcol);
606 break;
608 case FRAME_OUTSET:
609 default:
610 memcpy(tcol, colors[IMTK_BEVEL_LIT_COLOR], sizeof tcol);
611 memcpy(bcol, colors[IMTK_BEVEL_SHAD_COLOR], sizeof bcol);
612 }
614 glBegin(GL_LINES);
615 glColor3fv(tcol);
616 glVertex2f(x, y + h);
617 glVertex2f(x, y);
618 glVertex2f(x, y);
619 glVertex2f(x + w, y);
620 glColor3fv(bcol);
621 glVertex2f(x + w, y);
622 glVertex2f(x + w, y + h);
623 glVertex2f(x + w, y + h);
624 glVertex2f(x, y + h);
625 glEnd();
626 }