glamtk

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