1 /***************************************************************************
2 gui.cpp -- gui
3 -------------------
4 created : Fri Aug 13 22:01:33 CEST 1999
5 copyright : (C) 1999 by Eric Espie
6 email : torcs@free.fr
7 version : $Id: gui.cpp,v 1.7.2.8 2014/02/10 18:31:28 berniw Exp $
8 ***************************************************************************/
9
10 /***************************************************************************
11 * *
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU General Public License as published by *
14 * the Free Software Foundation; either version 2 of the License, or *
15 * (at your option) any later version. *
16 * *
17 ***************************************************************************/
18
19 /** @file
20 This API is used to manage all the menu screens.
21 @author <a href=mailto:torcs@free.fr>Eric Espie</a>
22 @version $Id: gui.cpp,v 1.7.2.8 2014/02/10 18:31:28 berniw Exp $
23 @ingroup gui
24 */
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <time.h>
29
30 #include <tgfclient.h>
31 #include "gui.h"
32
33 #include <portability.h>
34
35 tGfuiScreen *GfuiScreen; /* current screen */
36 static int GfuiMouseVisible = 1;
37 tMouseInfo GfuiMouse;
38
39 int GfuiMouseHW = 0;
40
41 float GfuiColor[GFUI_COLORNB][4];
42
43 static int ScrW, ScrH, ViewW, ViewH;
44
45 static tdble DelayRepeat;
46 static double LastTimeClick;
47 #define REPEAT1 1.0
48 #define REPEAT2 0.2
49
50 static void
gfuiColorInit(void)51 gfuiColorInit(void)
52 {
53 const int BUFSIZE = 1024;
54 char buf[BUFSIZE];
55
56 void *hdle;
57 int i, j;
58 const char *rgba[4] = {GFSCR_ATTR_RED, GFSCR_ATTR_GREEN, GFSCR_ATTR_BLUE, GFSCR_ATTR_ALPHA};
59 const char *clr[GFUI_COLORNB] = {
60 GFSCR_ELT_BGCOLOR, GFSCR_ELT_TITLECOLOR, GFSCR_ELT_BGBTNFOCUS, GFSCR_ELT_BGBTNCLICK,
61 GFSCR_ELT_BGBTNENABLED, GFSCR_ELT_BGBTNDISABLED, GFSCR_ELT_BTNFOCUS, GFSCR_ELT_BTNCLICK,
62 GFSCR_ELT_BTNENABLED, GFSCR_ELT_BTNDISABLED, GFSCR_ELT_LABELCOLOR, GFSCR_ELT_TIPCOLOR,
63 GFSCR_ELT_MOUSECOLOR1, GFSCR_ELT_MOUSECOLOR2, GFSCR_ELT_HELPCOLOR1, GFSCR_ELT_HELPCOLOR2,
64 GFSCR_ELT_BGSCROLLIST, GFSCR_ELT_SCROLLIST, GFSCR_ELT_BGSELSCROLLIST, GFSCR_ELT_SELSCROLLIST,
65 GFSCR_ELT_EDITCURSORCLR
66 };
67
68 snprintf(buf, BUFSIZE, "%s%s", GetLocalDir(), GFSCR_CONF_FILE);
69 hdle = GfParmReadFile(buf, GFPARM_RMODE_STD | GFPARM_RMODE_CREAT);
70
71 for (i = 0; i < GFUI_COLORNB; i++) {
72 for (j = 0; j < 4; j++) {
73 snprintf(buf, BUFSIZE, "%s/%s/%s", GFSCR_SECT_MENUCOL, GFSCR_LIST_COLORS, clr[i]);
74 GfuiColor[i][j] = GfParmGetNum(hdle, buf, rgba[j], (char*)NULL, 1.0);
75 }
76 }
77
78 GfParmReleaseHandle(hdle);
79
80 /* Remove the X11/Windows cursor */
81 if (!GfuiMouseHW) {
82 glutSetCursor(GLUT_CURSOR_NONE);
83 }
84
85 GfuiMouseVisible = 1;
86 }
87
88
89 void
gfuiInit(void)90 gfuiInit(void)
91 {
92 gfuiButtonInit();
93 gfuiHelpInit();
94 gfuiLabelInit();
95 gfuiObjectInit();
96 gfuiColorInit();
97 gfuiLoadFonts();
98
99 /* glutSetKeyRepeat(GLUT_KEY_REPEAT_OFF); */
100 }
101
102
103 /** Dummy display function for glut.
104 Declare this function to glut if nothing is to be displayed by the redisplay mechanism.
105 @ingroup gui
106 */
107 void
GfuiDisplayNothing(void)108 GfuiDisplayNothing(void)
109 {
110 }
111
112 /** Idle function for the GUI to be called during Idle loop of glut.
113 @ingroup gui
114 */
115 void
GfuiIdle(void)116 GfuiIdle(void)
117 {
118 double curtime = GfTimeClock();
119
120 if ((curtime - LastTimeClick) > DelayRepeat) {
121 DelayRepeat = REPEAT2;
122 LastTimeClick = curtime;
123 if (GfuiScreen->mouse == 1) {
124 /* button down */
125 gfuiUpdateFocus();
126 gfuiMouseAction((void*)0);
127 glutPostRedisplay();
128 }
129 }
130 }
131
132 /** Display function for the GUI to be called during redisplay of glut.
133 @ingroup gui
134 */
135 void
GfuiDisplay(void)136 GfuiDisplay(void)
137 {
138 tGfuiObject *curObj;
139
140 glDisable(GL_DEPTH_TEST);
141 glDisable(GL_LIGHTING);
142 glDisable(GL_TEXTURE_2D);
143 glDisable(GL_CULL_FACE);
144 glDisable(GL_ALPHA_TEST);
145 glEnable(GL_BLEND);
146 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
147
148 GfScrGetSize(&ScrW, &ScrH, &ViewW, &ViewH);
149
150 glViewport((ScrW-ViewW) / 2, (ScrH-ViewH) / 2, ViewW, ViewH);
151 glMatrixMode(GL_PROJECTION);
152 glLoadIdentity();
153 gluOrtho2D(0, GfuiScreen->width, 0, GfuiScreen->height);
154 glMatrixMode(GL_MODELVIEW);
155 glLoadIdentity();
156
157 if (GfuiScreen->bgColor[3] != 0.0) {
158 glClearColor(GfuiScreen->bgColor[0],
159 GfuiScreen->bgColor[1],
160 GfuiScreen->bgColor[2],
161 GfuiScreen->bgColor[3]);
162 glClear(GL_COLOR_BUFFER_BIT);
163 }
164
165 if (glIsTexture(GfuiScreen->bgImage) == GL_TRUE) {
166 GLfloat tx1 = 0.0f, tx2 = 1.0f, ty1 = 0.0f, ty2 = 1.0f;
167
168 // All background images are 16:10 images which are stored as quadratic images.
169 // Compute texture coordinates to ensure proper unskewed/unstretched display of
170 // image content.
171 tdble rfactor = (16.0f*ViewH)/(10.0f*ViewW);
172 if (rfactor >= 1.0f) {
173 // Aspect ratio of view is smaller than 16:10, "cut off" sides
174 tdble tdx = (1.0f-1.0f/rfactor)/2.0f;
175 tx1 += tdx;
176 tx2 -= tdx;
177 } else {
178 // Aspect ratio of view is larger than 16:10, "cut off" top and bottom
179 tdble tdy = (1.0f-rfactor)/2.0f;
180 ty1 += tdy;
181 ty2 -= tdy;
182 }
183
184 glDisable(GL_BLEND);
185 glEnable(GL_TEXTURE_2D);
186 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
187 glColor3f(0.0, 0.0, 1.0);
188 glBindTexture(GL_TEXTURE_2D, GfuiScreen->bgImage);
189 glBegin(GL_QUADS);
190 glTexCoord2f(tx1, ty1); glVertex3f(0.0, 0.0, 0.0);
191 glTexCoord2f(tx1, ty2); glVertex3f(0.0, GfuiScreen->height, 0.0);
192 glTexCoord2f(tx2, ty2); glVertex3f(GfuiScreen->width, GfuiScreen->height, 0.0);
193 glTexCoord2f(tx2, ty1); glVertex3f(GfuiScreen->width, 0.0, 0.0);
194 glEnd();
195 glDisable(GL_TEXTURE_2D);
196 glEnable(GL_BLEND);
197 }
198
199 curObj = GfuiScreen->objects;
200 if (curObj) {
201 do {
202 curObj = curObj->next;
203 GfuiDraw(curObj);
204 } while (curObj != GfuiScreen->objects);
205 }
206
207 if (!GfuiMouseHW && GfuiMouseVisible && GfuiScreen->mouseAllowed) {
208 GfuiDrawCursor();
209 }
210
211 glDisable(GL_BLEND);
212 glutSwapBuffers();
213 }
214
215 /** Hide the mouse cursor
216 @ingroup gui
217 @return none
218 */
219 void
GfuiMouseHide(void)220 GfuiMouseHide(void)
221 {
222 GfuiScreen->mouseAllowed = 0;
223 }
224
225 /** Show the mouse cursor
226 @ingroup gui
227 @return none
228 */
229 void
GfuiMouseShow(void)230 GfuiMouseShow(void)
231 {
232 GfuiScreen->mouseAllowed = 1;
233 }
234
235 /** Force the hardware mouse pointer
236 @ingroup ctrl
237 @return <tt>0 ... </tt>Ok
238 <br><tt>-1 .. </tt>Error
239 */
240 void
GfuiMouseSetHWPresent(void)241 GfuiMouseSetHWPresent(void)
242 {
243 GfuiMouseHW = 1;
244 }
245
246 static void
gfuiKeyboard(unsigned char key,int,int)247 gfuiKeyboard(unsigned char key, int /* x */, int /* y */)
248 {
249 tGfuiKey *curKey;
250 int modifier;
251 tGfuiObject *obj;
252
253 modifier = glutGetModifiers();
254
255 /* user preempt key */
256 if (GfuiScreen->onKeyAction && GfuiScreen->onKeyAction(key, modifier, GFUI_KEY_DOWN)) {
257 return;
258 }
259
260 /* now see the user's defined keys */
261 if (GfuiScreen->userKeys != NULL) {
262 curKey = GfuiScreen->userKeys;
263 do {
264 curKey = curKey->next;
265 if ((curKey->key == key) && ((curKey->modifier == 0) || (curKey->modifier & modifier) != 0)) {
266 if (curKey->onPress) curKey->onPress(curKey->userData);
267 break;
268 }
269 } while (curKey != GfuiScreen->userKeys);
270 }
271
272 obj = GfuiScreen->hasFocus;
273 if (obj != NULL) {
274 switch (obj->widget) {
275 case GFUI_EDITBOX:
276 gfuiEditboxKey(obj, (int)key, modifier);
277 break;
278 }
279 }
280 glutPostRedisplay();
281 }
282
283 static void
gfuiSpecial(int key,int,int)284 gfuiSpecial(int key, int /* x */, int /* y */)
285 {
286 tGfuiKey *curKey;
287 int modifier;
288 tGfuiObject *obj;
289
290 modifier = glutGetModifiers();
291
292 /* user preempt key */
293 if (GfuiScreen->onSKeyAction && GfuiScreen->onSKeyAction(key, modifier, GFUI_KEY_DOWN)) {
294 return;
295 }
296
297 /* now see the user's defined keys */
298 if (GfuiScreen->userSpecKeys != NULL) {
299 curKey = GfuiScreen->userSpecKeys;
300 do {
301 curKey = curKey->next;
302 if ((curKey->specialkey == key) && ((curKey->modifier == 0) || (curKey->modifier & modifier) != 0)) {
303 if (curKey->onPress) curKey->onPress(curKey->userData);
304 break;
305 }
306 } while (curKey != GfuiScreen->userSpecKeys);
307 }
308
309 obj = GfuiScreen->hasFocus;
310 if (obj != NULL) {
311 switch (obj->widget) {
312 case GFUI_EDITBOX:
313 gfuiEditboxKey(obj, key + 256, modifier);
314 break;
315 }
316 }
317 glutPostRedisplay();
318 }
319
320 static void
gfuiKeyboardUp(unsigned char key,int,int)321 gfuiKeyboardUp(unsigned char key, int /* x */, int /* y */)
322 {
323 tGfuiKey *curKey;
324 int modifier;
325
326 modifier = glutGetModifiers();
327
328 /* user preempt key */
329 if (GfuiScreen->onKeyAction && GfuiScreen->onKeyAction(key, modifier, GFUI_KEY_UP)) {
330 return;
331 }
332
333 /* now see the user's defined keys */
334 if (GfuiScreen->userKeys != NULL) {
335 curKey = GfuiScreen->userKeys;
336 do {
337 curKey = curKey->next;
338 if ((curKey->key == key) && ((curKey->modifier == 0) || (curKey->modifier & modifier) != 0)) {
339 if (curKey->onRelease) curKey->onRelease(curKey->userData);
340 break;
341 }
342 } while (curKey != GfuiScreen->userKeys);
343 }
344
345 glutPostRedisplay();
346 }
347
348 static void
gfuiSpecialUp(int key,int,int)349 gfuiSpecialUp(int key, int /* x */, int /* y */)
350 {
351 tGfuiKey *curKey;
352 int modifier;
353
354 modifier = glutGetModifiers();
355
356 /* user preempt key */
357 if (GfuiScreen->onSKeyAction && GfuiScreen->onSKeyAction(key, modifier, GFUI_KEY_UP)) {
358 return;
359 }
360
361 /* now see the user's defined keys */
362 if (GfuiScreen->userSpecKeys != NULL) {
363 curKey = GfuiScreen->userSpecKeys;
364 do {
365 curKey = curKey->next;
366 if ((curKey->specialkey == key) && ((curKey->modifier == 0) || (curKey->modifier & modifier) != 0)) {
367 if (curKey->onRelease) curKey->onRelease(curKey->userData);
368 break;
369 }
370 } while (curKey != GfuiScreen->userSpecKeys);
371 }
372
373 glutPostRedisplay();
374 }
375
376 /** Get the mouse information (position and buttons)
377 @ingroup gui
378 @return mouse information
379 */
GfuiMouseInfo(void)380 tMouseInfo *GfuiMouseInfo(void)
381 {
382 return &GfuiMouse;
383 }
384
385 /** Set the mouse position
386 @ingroup gui
387 @param x mouse x pos
388 @param y mouse y pos
389 @return none
390 */
GfuiMouseSetPos(int x,int y)391 void GfuiMouseSetPos(int x, int y)
392 {
393 glutWarpPointer(x, y);
394 }
395
396
397 static void
gfuiMouse(int button,int state,int x,int y)398 gfuiMouse(int button, int state, int x, int y)
399 {
400 // Check array range of button array!
401 if (button > -1 && button < 3) {
402 GfuiMouse.X = (x - (ScrW - ViewW)/2) * (int)GfuiScreen->width / ViewW;
403 GfuiMouse.Y = (ViewH - y + (ScrH - ViewH)/2) * (int)GfuiScreen->height / ViewH;
404
405 GfuiMouse.button[button] = 1 - state;
406
407 DelayRepeat = REPEAT1;
408 LastTimeClick = GfTimeClock();
409 if (state == GLUT_DOWN) {
410 if (button == GLUT_RIGHT_BUTTON) {
411 GfuiScreen->mouse = 0;
412 /* GfuiMouseVisible = 1 - GfuiMouseVisible; */
413 gfuiUpdateFocus();
414 } else {
415 GfuiScreen->mouse = 1;
416 gfuiUpdateFocus();
417 gfuiMouseAction((void*)0);
418 }
419 } else {
420 GfuiScreen->mouse = 0;
421 gfuiUpdateFocus();
422 if (button != GLUT_RIGHT_BUTTON) {
423 gfuiMouseAction((void*)1);
424 }
425 }
426 glutPostRedisplay();
427 }
428 }
429
430 static void
gfuiMotion(int x,int y)431 gfuiMotion(int x, int y)
432 {
433 GfuiMouse.X = (x - (ScrW - ViewW)/2) * (int)GfuiScreen->width / ViewW;
434 GfuiMouse.Y = (ViewH - y + (ScrH - ViewH)/2) * (int)GfuiScreen->height / ViewH;
435 gfuiUpdateFocus();
436 gfuiMouseAction((void*)(1 - GfuiScreen->mouse));
437 glutPostRedisplay();
438 DelayRepeat = REPEAT1;
439 }
440
441 static void
gfuiPassiveMotion(int x,int y)442 gfuiPassiveMotion(int x, int y)
443 {
444 GfuiMouse.X = (x - (ScrW - ViewW)/2) * (int)GfuiScreen->width / ViewW;
445 GfuiMouse.Y = (ViewH - y + (ScrH - ViewH)/2) * (int)GfuiScreen->height / ViewH;
446 gfuiUpdateFocus();
447 glutPostRedisplay();
448 }
449
450 /** Tell if the screen is active or not.
451 @ingroup gui
452 @param screen Screen to activate
453 @return 1 if active and 0 if not.
454 */
455 int
GfuiScreenIsActive(void * screen)456 GfuiScreenIsActive(void *screen)
457 {
458 return (GfuiScreen == screen);
459 }
460
461 /** Activate a screen and make it current.
462 @ingroup gui
463 @param screen Screen to activate
464 @warning The current screen at the call time is deactivated.
465 */
466 void
GfuiScreenActivate(void * screen)467 GfuiScreenActivate(void *screen)
468 {
469 if ((GfuiScreen) && (GfuiScreen->onDeactivate)) GfuiScreen->onDeactivate(GfuiScreen->userDeactData);
470
471 GfuiScreen = (tGfuiScreen*)screen;
472
473 glutKeyboardFunc(gfuiKeyboard);
474 glutSpecialFunc(gfuiSpecial);
475 glutKeyboardUpFunc(gfuiKeyboardUp);
476 glutSpecialUpFunc(gfuiSpecialUp);
477 glutMouseFunc(gfuiMouse);
478 glutMotionFunc(gfuiMotion);
479 glutPassiveMotionFunc(gfuiPassiveMotion);
480 glutIdleFunc((void(*)(void))NULL);
481
482 if (GfuiScreen->onlyCallback == 0) {
483 if (GfuiScreen->hasFocus == NULL) {
484 gfuiSelectNext(NULL);
485 }
486 glutDisplayFunc(GfuiDisplay);
487 } else {
488 glutDisplayFunc(GfuiDisplayNothing);
489 }
490
491 if (GfuiScreen->onActivate) GfuiScreen->onActivate(GfuiScreen->userActData);
492
493 if (GfuiScreen->onlyCallback == 0) {
494 GfuiDisplay();
495 glutPostRedisplay();
496 }
497 }
498
499
500 /** Activate a screen and make it current plus release the current screen.
501 @ingroup gui
502 @param screen Screen to activate
503 @warning The current screen at the call time is deactivated.
504 */
505 void
GfuiScreenReplace(void * screen)506 GfuiScreenReplace(void *screen)
507 {
508 tGfuiScreen *oldScreen = GfuiScreen;
509
510 if (oldScreen) {
511 GfuiScreenRelease(oldScreen);
512 }
513 GfuiScreenActivate(screen);
514 }
515
516 /** Deactivate the current screen.
517 @ingroup gui
518 */
519 void
GfuiScreenDeactivate(void)520 GfuiScreenDeactivate(void)
521 {
522 if (GfuiScreen->onDeactivate) GfuiScreen->onDeactivate(GfuiScreen->userDeactData);
523
524 GfuiScreen = (tGfuiScreen*)NULL;
525
526 glutKeyboardFunc((void(*)(unsigned char,int,int))NULL);
527 glutSpecialFunc((void(*)(int,int,int))NULL);
528 glutKeyboardUpFunc((void(*)(unsigned char,int,int))NULL);
529 glutSpecialUpFunc((void(*)(int,int,int))NULL);
530 glutMouseFunc((void(*)(int,int,int,int))NULL);
531 glutMotionFunc((void(*)(int,int))NULL);
532 glutPassiveMotionFunc((void(*)(int,int))NULL);
533 glutIdleFunc((void(*)(void))NULL);
534 glutDisplayFunc(GfuiDisplayNothing);
535 }
536
537 /** Create a new screen.
538 @ingroup gui
539 @return New screen instance
540 <br>NULL if Error
541 */
542 void *
GfuiScreenCreate(void)543 GfuiScreenCreate(void)
544 {
545 tGfuiScreen *screen;
546
547 screen = (tGfuiScreen*)calloc(1, sizeof(tGfuiScreen));
548
549 screen->width = 640.0;
550 screen->height = 480.0;
551
552 screen->bgColor = (float*)calloc(4, sizeof(float));
553 int i;
554 for(i = 0; i < 4; i++) {
555 screen->bgColor[i] = GfuiColor[GFUI_BGCOLOR][i];
556 }
557
558 screen->mouseColor[0] = &(GfuiColor[GFUI_MOUSECOLOR1][0]);
559 screen->mouseColor[1] = &(GfuiColor[GFUI_MOUSECOLOR2][0]);
560 screen->mouseAllowed = 1;
561
562 return (void*)screen;
563 }
564
565 /** Create a screen.
566 @ingroup gui
567 @param bgColor pointer on color array (RGBA) (if NULL default color is used)
568 @param userDataOnActivate Parameter to the activate function
569 @param onActivate Function called when the screen is activated
570 @param userDataOnDeactivate Parameter to the deactivate function
571 @param onDeactivate Function called when the screen is deactivated
572 @param mouseAllowed Flag to tell if the mouse cursor can be displayed
573 @return New screen instance
574 <br>NULL if Error
575 @bug Only black background work well
576 */
577 void *
GfuiScreenCreateEx(float * bgColor,void * userDataOnActivate,tfuiCallback onActivate,void * userDataOnDeactivate,tfuiCallback onDeactivate,int mouseAllowed)578 GfuiScreenCreateEx(float *bgColor,
579 void *userDataOnActivate, tfuiCallback onActivate,
580 void *userDataOnDeactivate, tfuiCallback onDeactivate,
581 int mouseAllowed)
582 {
583 int i;
584 tGfuiScreen *screen;
585
586 screen = (tGfuiScreen*)calloc(1, sizeof(tGfuiScreen));
587
588 screen->width = 640.0;
589 screen->height = 480.0;
590
591 screen->bgColor = (float*)calloc(4, sizeof(float));
592 for(i = 0; i < 4; i++) {
593 if (bgColor != NULL) {
594 screen->bgColor[i] = bgColor[i];
595 } else {
596 screen->bgColor[i] = GfuiColor[GFUI_BGCOLOR][i];
597 }
598 }
599
600 screen->mouseColor[0] = &(GfuiColor[GFUI_MOUSECOLOR1][0]);
601 screen->mouseColor[1] = &(GfuiColor[GFUI_MOUSECOLOR2][0]);
602 screen->onActivate = onActivate;
603 screen->userActData = userDataOnActivate;
604 screen->onDeactivate = onDeactivate;
605 screen->userDeactData = userDataOnDeactivate;
606
607 screen->mouseAllowed = mouseAllowed;
608
609 return (void*)screen;
610 }
611
612 /** Release the given screen.
613 @ingroup gui
614 @param scr Screen to release
615 @warning If the screen was activated, it is deactivated.
616 */
617 void
GfuiScreenRelease(void * scr)618 GfuiScreenRelease(void *scr)
619 {
620 tGfuiObject *curObject;
621 tGfuiObject *nextObject;
622 tGfuiKey *curKey;
623 tGfuiKey *nextKey;
624 tGfuiScreen *screen = (tGfuiScreen*)scr;
625
626 if (GfuiScreen == screen) {
627 GfuiScreenDeactivate();
628 }
629
630 if (glIsTexture(screen->bgImage) == GL_TRUE) {
631 glDeleteTextures(1, &screen->bgImage);
632 }
633
634 if (screen->bgColor != NULL) {
635 free(screen->bgColor);
636 screen->bgColor = NULL;
637 }
638
639 curObject = screen->objects;
640 if (curObject != NULL) {
641 do {
642 nextObject = curObject->next;
643 gfuiReleaseObject(curObject);
644 curObject = nextObject;
645 } while (curObject != screen->objects);
646 }
647
648 curKey = screen->userKeys;
649 if (curKey != NULL) {
650 do {
651 nextKey = curKey->next;
652 free(curKey->name);
653 free(curKey->descr);
654 free(curKey);
655 curKey = nextKey;
656 } while (curKey != screen->userKeys);
657 }
658 curKey = screen->userSpecKeys;
659 if (curKey != NULL) {
660 do {
661 nextKey = curKey->next;
662 free(curKey->name);
663 free(curKey->descr);
664 free(curKey);
665 curKey = nextKey;
666 } while (curKey != screen->userSpecKeys);
667 }
668 free(screen);
669 }
670
671 /** Create a callback hook.
672 @ingroup gui
673 @param userDataOnActivate Parameter to the activate function
674 @param onActivate Function called when the screen is activated
675 @return New hook instance
676 <br>NULL if Error
677 */
678 void *
GfuiHookCreate(void * userDataOnActivate,tfuiCallback onActivate)679 GfuiHookCreate(void *userDataOnActivate, tfuiCallback onActivate)
680 {
681 tGfuiScreen *screen;
682
683 screen = (tGfuiScreen*)calloc(1, sizeof(tGfuiScreen));
684 screen->onActivate = onActivate;
685 screen->userActData = userDataOnActivate;
686 screen->onlyCallback = 1;
687
688 return (void*)screen;
689 }
690
691 /** Release the given hook.
692 @ingroup gui
693 @param hook Hook to release
694 */
695 void
GfuiHookRelease(void * hook)696 GfuiHookRelease(void *hook)
697 {
698 free(hook);
699 }
700
701 void
GfuiKeyEventRegister(void * scr,tfuiKeyCallback onKeyAction)702 GfuiKeyEventRegister(void *scr, tfuiKeyCallback onKeyAction)
703 {
704 tGfuiScreen *screen = (tGfuiScreen*)scr;
705
706 screen->onKeyAction = onKeyAction;
707 }
708
709
710 void
GfuiSKeyEventRegister(void * scr,tfuiSKeyCallback onSKeyAction)711 GfuiSKeyEventRegister(void *scr, tfuiSKeyCallback onSKeyAction)
712 {
713 tGfuiScreen *screen = (tGfuiScreen*)scr;
714
715 screen->onSKeyAction = onSKeyAction;
716 }
717
718 void
GfuiKeyEventRegisterCurrent(tfuiKeyCallback onKeyAction)719 GfuiKeyEventRegisterCurrent(tfuiKeyCallback onKeyAction)
720 {
721 GfuiScreen->onKeyAction = onKeyAction;
722 }
723
724
725 void
GfuiSKeyEventRegisterCurrent(tfuiSKeyCallback onSKeyAction)726 GfuiSKeyEventRegisterCurrent(tfuiSKeyCallback onSKeyAction)
727 {
728 GfuiScreen->onSKeyAction = onSKeyAction;
729 }
730
731
732 /** Add a Keyboard callback to a screen.
733 @ingroup gui
734 @param scr Screen
735 @param key Key code (glut value)
736 @param descr Description for help screen
737 @param userData Parameter to the callback function
738 @param onKeyPressed Callback function
739 @param onKeyReleased Callback function
740 */
741 void
GfuiAddKey(void * scr,unsigned char key,const char * descr,void * userData,tfuiCallback onKeyPressed,tfuiCallback onKeyReleased)742 GfuiAddKey(void *scr, unsigned char key, const char *descr, void *userData, tfuiCallback onKeyPressed, tfuiCallback onKeyReleased)
743 {
744 tGfuiKey *curKey;
745 tGfuiScreen *screen = (tGfuiScreen*)scr;
746 const int BUFSIZE = 16;
747 char buf[BUFSIZE];
748
749 curKey = (tGfuiKey*)calloc(1, sizeof(tGfuiKey));
750 curKey->key = key;
751 curKey->userData = userData;
752 curKey->onPress = onKeyPressed;
753
754 if (descr == NULL) {
755 curKey->descr = strdup("");
756 } else {
757 curKey->descr = strdup(descr);
758 }
759
760 switch(key){
761 case 8:
762 curKey->name = strdup("backspace");
763 break;
764 case 9:
765 curKey->name = strdup("tab");
766 break;
767 case 13:
768 curKey->name = strdup("enter");
769 break;
770 case 27:
771 curKey->name = strdup("esc");
772 break;
773 case ' ':
774 curKey->name = strdup("space");
775 break;
776 default:
777 snprintf(buf, BUFSIZE, "%c", key);
778 curKey->name = strdup(buf);
779 break;
780 }
781
782 if (screen->userKeys == NULL) {
783 screen->userKeys = curKey;
784 curKey->next = curKey;
785 } else {
786 curKey->next = screen->userKeys->next;
787 screen->userKeys->next = curKey;
788 }
789 }
790
791 /** Add a Keyboard callback to the current screen.
792 @ingroup gui
793 @param key Key code (glut value)
794 @param descr Description for help screen
795 @param userData Parameter to the callback function
796 @param onKeyPressed Callback function called when the specified key is pressed
797 @param onKeyReleased Callback function
798 */
799 void
GfuiRegisterKey(unsigned char key,char * descr,void * userData,tfuiCallback onKeyPressed,tfuiCallback onKeyReleased)800 GfuiRegisterKey(unsigned char key, char *descr, void *userData, tfuiCallback onKeyPressed, tfuiCallback onKeyReleased)
801 {
802 GfuiAddKey(GfuiScreen, key, descr, userData, onKeyPressed, onKeyReleased);
803 }
804
805 /** Add a Special Keyboard shortcut to the screen.
806 (see glut for normal and special keys)
807 @ingroup gui
808 @param scr Screen
809 @param key Key code (glut value)
810 @param descr Description for help screen
811 @param userData Parameter to the callback function
812 @param onKeyPressed Callback function
813 @param onKeyReleased Callback function
814 */
815 void
GfuiAddSKey(void * scr,int key,const char * descr,void * userData,tfuiCallback onKeyPressed,tfuiCallback onKeyReleased)816 GfuiAddSKey(void *scr, int key, const char *descr, void *userData, tfuiCallback onKeyPressed, tfuiCallback onKeyReleased)
817 {
818 tGfuiKey *curKey;
819 tGfuiScreen *screen = (tGfuiScreen*)scr;
820
821 curKey = (tGfuiKey*)calloc(1, sizeof(tGfuiKey));
822 curKey->specialkey = key;
823 curKey->userData = userData;
824 curKey->onPress = onKeyPressed;
825
826 if (descr == NULL) {
827 curKey->descr = strdup("");
828 } else {
829 curKey->descr = strdup(descr);
830 }
831
832 switch(key) {
833 case GLUT_KEY_F1:
834 curKey->name = strdup("F1");
835 break;
836 case GLUT_KEY_F2:
837 curKey->name = strdup("F2");
838 break;
839 case GLUT_KEY_F3:
840 curKey->name = strdup("F3");
841 break;
842 case GLUT_KEY_F4:
843 curKey->name = strdup("F4");
844 break;
845 case GLUT_KEY_F5:
846 curKey->name = strdup("F5");
847 break;
848 case GLUT_KEY_F6:
849 curKey->name = strdup("F6");
850 break;
851 case GLUT_KEY_F7:
852 curKey->name = strdup("F7");
853 break;
854 case GLUT_KEY_F8:
855 curKey->name = strdup("F8");
856 break;
857 case GLUT_KEY_F9:
858 curKey->name = strdup("F9");
859 break;
860 case GLUT_KEY_F10:
861 curKey->name = strdup("F10");
862 break;
863 case GLUT_KEY_F11:
864 curKey->name = strdup("F11");
865 break;
866 case GLUT_KEY_F12:
867 curKey->name = strdup("F12");
868 break;
869 case GLUT_KEY_LEFT:
870 curKey->name = strdup("Left Arrow");
871 break;
872 case GLUT_KEY_UP:
873 curKey->name = strdup("Up Arrow");
874 break;
875 case GLUT_KEY_RIGHT:
876 curKey->name = strdup("Right Arrow");
877 break;
878 case GLUT_KEY_DOWN:
879 curKey->name = strdup("Down Arrow");
880 break;
881 case GLUT_KEY_PAGE_UP:
882 curKey->name = strdup("Page Up");
883 break;
884 case GLUT_KEY_PAGE_DOWN:
885 curKey->name = strdup("Page Down");
886 break;
887 case GLUT_KEY_HOME:
888 curKey->name = strdup("Home");
889 break;
890 case GLUT_KEY_END:
891 curKey->name = strdup("End");
892 break;
893 case GLUT_KEY_INSERT:
894 curKey->name = strdup("Insert");
895 break;
896 }
897
898
899 if (screen->userSpecKeys == NULL) {
900 screen->userSpecKeys = curKey;
901 curKey->next = curKey;
902 } else {
903 curKey->next = screen->userSpecKeys->next;
904 screen->userSpecKeys->next = curKey;
905 screen->userSpecKeys = curKey;
906 }
907 }
908
909 /** Save a screen shot in png format.
910 @ingroup screen
911 */
912 void
GfuiScreenShot(void *)913 GfuiScreenShot(void * /* notused */)
914 {
915 unsigned char *img;
916 const int BUFSIZE = 1024;
917 char buf[BUFSIZE];
918 struct tm *stm;
919 time_t t;
920 int sw, sh, vw, vh;
921 char path[BUFSIZE];
922
923 snprintf(path, BUFSIZE, "%sscreenshots", GetLocalDir());
924 // Ensure that screenshot directory exists.
925 if (GfCreateDir(path) == GF_DIR_CREATED) {
926
927 GfScrGetSize(&sw, &sh, &vw, &vh);
928 img = (unsigned char*)malloc(vw * vh * 3);
929 if (img == NULL) {
930 return;
931 }
932
933 glPixelStorei(GL_PACK_ROW_LENGTH, 0);
934 glPixelStorei(GL_PACK_ALIGNMENT, 1);
935 glReadBuffer(GL_FRONT);
936 glReadPixels((sw-vw)/2, (sh-vh)/2, vw, vh, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*)img);
937
938 t = time(NULL);
939 stm = localtime(&t);
940 snprintf(buf, BUFSIZE, "%s/torcs-%4d%02d%02d%02d%02d%02d.png",
941 path,
942 stm->tm_year+1900,
943 stm->tm_mon+1,
944 stm->tm_mday,
945 stm->tm_hour,
946 stm->tm_min,
947 stm->tm_sec);
948 GfImgWritePng(img, buf, vw, vh);
949
950 free(img);
951 }
952 }
953
954 /** Add an image background to a screen.
955 @ingroup gui
956 @param scr Screen
957 @param filename file name of the bg image
958 @return None.
959 */
960 void
GfuiScreenAddBgImg(void * scr,const char * filename)961 GfuiScreenAddBgImg(void *scr, const char *filename)
962 {
963 tGfuiScreen *screen = (tGfuiScreen*)scr;
964 void *handle;
965 float screen_gamma;
966 GLbyte *tex;
967 int w,h;
968 const int BUFSIZE = 1024;
969 char buf[BUFSIZE];
970
971 if (glIsTexture(screen->bgImage) == GL_TRUE) {
972 glDeleteTextures(1, &screen->bgImage);
973 }
974
975 snprintf(buf, BUFSIZE, "%s%s", GetLocalDir(), GFSCR_CONF_FILE);
976 handle = GfParmReadFile(buf, GFPARM_RMODE_STD | GFPARM_RMODE_CREAT);
977 screen_gamma = (float)GfParmGetNum(handle, GFSCR_SECT_PROP, GFSCR_ATT_GAMMA, (char*)NULL, 2.0);
978 tex = (GLbyte*)GfImgReadPng(filename, &w, &h, screen_gamma);
979 if (!tex) {
980 GfParmReleaseHandle(handle);
981 return;
982 }
983
984 glGenTextures(1, &screen->bgImage);
985 glBindTexture(GL_TEXTURE_2D, screen->bgImage);
986 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
987 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
988 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *)(tex));
989 free(tex);
990 GfParmReleaseHandle(handle);
991 }
992
993
994