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 }
|