1 /***************************************************************************
2
3 file : guiscrollist.cpp
4 created : Mon Aug 23 19:22:49 CEST 1999
5 copyright : (C) 1999 by Eric Espie
6 email : torcs@free.fr
7 version : $Id: guiscrollist.cpp,v 1.4.2.3 2012/05/20 11:59:33 berniw Exp $
8
9 ***************************************************************************/
10
11 /***************************************************************************
12 * *
13 * This program is free software; you can redistribute it and/or modify *
14 * it under the terms of the GNU General Public License as published by *
15 * the Free Software Foundation; either version 2 of the License, or *
16 * (at your option) any later version. *
17 * *
18 ***************************************************************************/
19
20 /** @file
21 GUI scroll-list management.
22 @author <a href=mailto:torcs@free.fr>Eric Espie</a>
23 @version $Id: guiscrollist.cpp,v 1.4.2.3 2012/05/20 11:59:33 berniw Exp $
24 @ingroup gui
25 */
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #ifdef WIN32
30 #include <windows.h>
31 #endif
32 #include <tgfclient.h>
33 #include "gui.h"
34 #include "guifont.h"
35 #include <portability.h>
36
37 void
gfuiScrListInit(void)38 gfuiScrListInit(void)
39 {
40 }
41
42 static void
gfuiScroll(tScrollBarInfo * sinfo)43 gfuiScroll(tScrollBarInfo *sinfo)
44 {
45 tGfuiObject *object;
46 tGfuiScrollList *scrollist;
47
48 object = (tGfuiObject *) sinfo->userData;
49 //object = gfuiGetObject(GfuiScreen, (long)(sinfo->userData));
50
51 if(object == NULL) {
52 return;
53 }
54
55 if(object->widget != GFUI_SCROLLIST) {
56 return;
57 }
58
59 scrollist = &(object->u.scrollist);
60
61 scrollist->firstVisible = sinfo->pos;
62
63 if((scrollist->selectedElt < scrollist->firstVisible) ||
64 (scrollist->selectedElt > scrollist->firstVisible + scrollist->nbVisible)) {
65 scrollist->selectedElt = -1;
66 }
67 }
68
69 void
gfuiScrollListNextElt(tGfuiObject * object)70 gfuiScrollListNextElt(tGfuiObject *object)
71 {
72 tGfuiScrollList *scrollist;
73
74 scrollist = &(object->u.scrollist);
75
76 scrollist->selectedElt++;
77
78 if(scrollist->selectedElt == scrollist->nbElts) {
79 scrollist->selectedElt = scrollist->nbElts - 1;
80 return;
81 }
82
83 if(scrollist->onSelect) {
84 scrollist->onSelect(scrollist->userDataOnSelect);
85 }
86
87 if(scrollist->selectedElt == scrollist->firstVisible + scrollist->nbVisible) {
88 /* Scroll down */
89 if(scrollist->firstVisible + scrollist->nbVisible < scrollist->nbElts) {
90 scrollist->firstVisible++;
91
92 if(scrollist->scrollBar) {
93 GfuiScrollBarPosSet(GfuiScreen, scrollist->scrollBar, 0, MAX(scrollist->nbElts - scrollist->nbVisible, 0),
94 scrollist->nbVisible, scrollist->firstVisible);
95 }
96 }
97 }
98 }
99
100 void
gfuiScrollListPrevElt(tGfuiObject * object)101 gfuiScrollListPrevElt(tGfuiObject *object)
102 {
103 tGfuiScrollList *scrollist;
104
105 scrollist = &(object->u.scrollist);
106
107 scrollist->selectedElt--;
108
109 if(scrollist->selectedElt < 0) {
110 scrollist->selectedElt = 0;
111 return;
112 }
113
114 if(scrollist->onSelect) {
115 scrollist->onSelect(scrollist->userDataOnSelect);
116 }
117
118 if(scrollist->selectedElt < scrollist->firstVisible) {
119 /* Scroll down */
120 if(scrollist->firstVisible > 0) {
121 scrollist->firstVisible--;
122
123 if(scrollist->scrollBar) {
124 GfuiScrollBarPosSet(GfuiScreen, scrollist->scrollBar, 0, MAX(scrollist->nbElts - scrollist->nbVisible, 0),
125 scrollist->nbVisible, scrollist->firstVisible);
126 }
127 }
128 }
129 }
130
131
132 /** Create a new scroll list.
133 @ingroup gui
134 @param scr Current screen
135 @param font Current font
136 @param x X Position
137 @param y Y Position
138 @param align Box Alignement (Horizontal and Vertical)
139 @param width Width of the box
140 @param height Height of the box
141 @param scrollBarPos Position of the scrollbar:
142 <br>GFUI_SB_NONE No scroll bar
143 <br>GFUI_SB_RIGHT Right scroll bar
144 <br>GFUI_SB_LEFT Left scroll bar
145 @param userDataOnSelect User data to pass to the onSelect callback
146 @param onSelect Callback when the selection is done
147 @return Scroll List Id
148 */
149 int
GfuiScrollListCreate(void * scr,int font,int x,int y,int align,int width,int height,int scrollBarPos,void * userDataOnSelect,tfuiCallback onSelect)150 GfuiScrollListCreate(void *scr, int font, int x, int y, int align, int width, int height,
151 int scrollBarPos, void *userDataOnSelect, tfuiCallback onSelect)
152 {
153 tGfuiScrollList *scrollist;
154 tGfuiObject *object;
155 tGfuiScreen *screen = (tGfuiScreen *)scr;
156
157 object = (tGfuiObject *)calloc(1, sizeof(tGfuiObject));
158 object->widget = GFUI_SCROLLIST;
159 object->focusMode = GFUI_FOCUS_MOUSE_MOVE;
160 object->id = screen->curId++;
161 object->visible = 1;
162
163 object->xmin = x;
164 object->xmax = x + width;
165 object->ymin = y;
166 object->ymax = y + height;
167
168 scrollist = &(object->u.scrollist);
169 scrollist->fgColor[0] = &(GfuiColor[GFUI_FGSCROLLIST][0]);
170 scrollist->bgColor[0] = &(GfuiColor[GFUI_BGSCROLLIST][0]);
171 scrollist->fgSelectColor[0] = &(GfuiColor[GFUI_FGSELSCROLLIST][0]);
172 scrollist->bgSelectColor[0] = &(GfuiColor[GFUI_BGSELSCROLLIST][0]);
173 scrollist->font = gfuiFont[font];
174 scrollist->nbVisible = height / (scrollist->font->getDescender() + scrollist->font->getHeight());
175 scrollist->selectedElt = -1;
176 scrollist->userDataOnSelect = userDataOnSelect;
177 scrollist->onSelect = onSelect;
178
179 switch(scrollBarPos) {
180 case GFUI_SB_NONE:
181 break;
182 case GFUI_SB_RIGHT:
183 scrollist->scrollBar = GfuiScrollBarCreate(scr, x + width, y, GFUI_ALIGN_HL_VB, height, GFUI_VERT_SCROLLBAR,
184 0, 10, 10, 10, (void *)(object), gfuiScroll);
185 break;
186 case GFUI_SB_LEFT:
187 scrollist->scrollBar = GfuiScrollBarCreate(scr, x, y, GFUI_ALIGN_HR_VB, height, GFUI_VERT_SCROLLBAR,
188 0, 10, 10, 10, (void *)(object), gfuiScroll);
189 break;
190 }
191
192 gfuiAddObject(screen, object);
193 return object->id;
194 }
195
196 static void
gfuiScrollListInsElt(tGfuiScrollList * scrollist,tGfuiListElement * elt,int index)197 gfuiScrollListInsElt(tGfuiScrollList *scrollist, tGfuiListElement *elt, int index)
198 {
199 tGfuiListElement *cur;
200 int i;
201
202 if(scrollist->elts == NULL) {
203 scrollist->elts = elt;
204 elt->next = elt;
205 elt->prev = elt;
206 } else {
207 cur = scrollist->elts;
208 i = 0;
209
210 do {
211 if(i == index) {
212 break;
213 }
214
215 cur = cur->next;
216 i++;
217 } while(cur != scrollist->elts);
218
219 elt->next = cur->next;
220 cur->next = elt;
221 elt->prev = cur;
222 elt->next->prev = elt;
223
224 if((cur == scrollist->elts) && (index != 0)) {
225 scrollist->elts = elt;
226 }
227 }
228 }
229
230 static tGfuiListElement *
gfuiScrollListRemElt(tGfuiScrollList * scrollist,int index)231 gfuiScrollListRemElt(tGfuiScrollList *scrollist, int index)
232 {
233 tGfuiListElement *cur;
234 int i;
235
236 if(scrollist->elts == NULL) {
237 return (tGfuiListElement *)NULL;
238 }
239
240 cur = scrollist->elts;
241 i = 0;
242
243 do {
244 cur = cur->next;
245
246 if(i == index) {
247 break;
248 }
249
250 i++;
251 } while(cur != scrollist->elts);
252
253 cur->next->prev = cur->prev;
254 cur->prev->next = cur->next;
255
256 if(cur == scrollist->elts) {
257 if(cur->next == cur) {
258 scrollist->elts = (tGfuiListElement *)NULL;
259 } else {
260 scrollist->elts = cur->prev;
261 }
262 }
263
264 return cur;
265 }
266
267 /** Get the selected element from the scroll list.
268 @ingroup gui
269 @param scr Current screen
270 @param Id Scroll list Id
271 @param userData address of the userData of the element to retrieve
272 @return Name of the retrieved element
273 <br>NULL if Error
274 */
275 char *
GfuiScrollListGetSelectedElement(void * scr,int Id,void ** userData)276 GfuiScrollListGetSelectedElement(void *scr, int Id, void **userData)
277 {
278 tGfuiObject *object;
279 tGfuiScrollList *scrollist;
280 tGfuiListElement *elt;
281 char *name;
282 int i;
283
284
285 object = gfuiGetObject(scr, Id);
286
287 if(object == NULL) {
288 return (char *)NULL;
289 }
290
291 if(object->widget != GFUI_SCROLLIST) {
292 return (char *)NULL;
293 }
294
295 scrollist = &(object->u.scrollist);
296
297 if(scrollist->selectedElt == -1) {
298 return (char *)NULL;
299 }
300
301 if(scrollist->elts == NULL) {
302 return (char *)NULL;
303 }
304
305 elt = scrollist->elts;
306 i = 0;
307
308 do {
309 elt = elt->next;
310
311 if(i == scrollist->selectedElt) {
312 break;
313 }
314
315 i++;
316 } while(elt != scrollist->elts);
317
318 name = elt->name;
319 *userData = elt->userData;
320
321 return name;
322 }
323
324 /** Get the specified element from the scroll list.
325 @ingroup gui
326 @param scr Current screen
327 @param Id Scroll list Id
328 @param index Position where to get the element
329 @param userData address of the userData of the element to retrieve
330 @return Name of the retrieved element
331 <br>NULL if Error
332 */
333 char *
GfuiScrollListGetElement(void * scr,int Id,int index,void ** userData)334 GfuiScrollListGetElement(void *scr, int Id, int index, void **userData)
335 {
336 tGfuiObject *object;
337 tGfuiScrollList *scrollist;
338 tGfuiListElement *elt;
339 char *name;
340 int i;
341
342 object = gfuiGetObject(scr, Id);
343
344 if(object == NULL) {
345 return (char *)NULL;
346 }
347
348 if(object->widget != GFUI_SCROLLIST) {
349 return (char *)NULL;
350 }
351
352 scrollist = &(object->u.scrollist);
353
354 if((index < 0) || (index > scrollist->nbElts - 1)) {
355 return (char *)NULL;
356 }
357
358 if(scrollist->elts == NULL) {
359 return (char *)NULL;
360 }
361
362 elt = scrollist->elts;
363 i = 0;
364
365 do {
366 elt = elt->next;
367
368 if(i == index) {
369 break;
370 }
371
372 i++;
373 } while(elt != scrollist->elts);
374
375 name = elt->name;
376 *userData = elt->userData;
377
378 return name;
379 }
380
381 /** Extract the selected element from the scroll list (removed).
382 @ingroup gui
383 @param scr Current screen
384 @param Id Scroll list Id
385 @param userData address of the userData of the element to retrieve
386 @return Name of the extracted element
387 <br>NULL if Error
388 */
389 char *
GfuiScrollListExtractSelectedElement(void * scr,int Id,void ** userData)390 GfuiScrollListExtractSelectedElement(void *scr, int Id, void **userData)
391 {
392 tGfuiObject *object;
393 tGfuiScrollList *scrollist;
394 tGfuiListElement *elt;
395 char *name;
396
397 object = gfuiGetObject(scr, Id);
398
399 if(object == NULL) {
400 return (char *)NULL;
401 }
402
403 if(object->widget != GFUI_SCROLLIST) {
404 return (char *)NULL;
405 }
406
407 scrollist = &(object->u.scrollist);
408
409 if(scrollist->selectedElt == -1) {
410 return (char *)NULL;
411 }
412
413 elt = gfuiScrollListRemElt(scrollist, scrollist->selectedElt);
414
415 scrollist->nbElts--;
416
417 if(scrollist->selectedElt > scrollist->nbElts - 1) {
418 scrollist->selectedElt--;
419 }
420
421 name = elt->name;
422 *userData = elt->userData;
423 free(elt);
424
425 return name;
426 }
427
428 /** Extract the specified element from the scroll list.
429 @ingroup gui
430 @param scr Current screen
431 @param Id Scroll list Id
432 @param index Position where to extract the element
433 @param userData address of the userData of the element to retrieve
434 @return Name of the extracted element
435 <br>NULL if Error
436 */
437 char *
GfuiScrollListExtractElement(void * scr,int Id,int index,void ** userData)438 GfuiScrollListExtractElement(void *scr, int Id, int index, void **userData)
439 {
440 tGfuiObject *object;
441 tGfuiScrollList *scrollist;
442 tGfuiListElement *elt;
443 char *name;
444
445 object = gfuiGetObject(scr, Id);
446
447 if(object == NULL) {
448 return (char *)NULL;
449 }
450
451 if(object->widget != GFUI_SCROLLIST) {
452 return (char *)NULL;
453 }
454
455 scrollist = &(object->u.scrollist);
456
457 if((index < 0) || (index > scrollist->nbElts - 1)) {
458 return (char *)NULL;
459 }
460
461 elt = gfuiScrollListRemElt(scrollist, index);
462
463 scrollist->nbElts--;
464
465 if(scrollist->selectedElt > scrollist->nbElts - 1) {
466 scrollist->selectedElt--;
467 }
468
469 name = elt->name;
470 *userData = elt->userData;
471 free(elt);
472
473 return name;
474 }
475
476
477 /** Insert an element in a scroll list.
478 @ingroup gui
479 @param scr Current screen
480 @param Id Scroll list Id
481 @param element New element
482 @param index Position where to insert the element
483 @param userData User defined data
484 @return <tt>0 ... </tt>Ok
485 <br><tt>-1 .. </tt>Error
486 */
487 int
GfuiScrollListInsertElement(void * scr,int Id,char * element,int index,void * userData)488 GfuiScrollListInsertElement(void *scr, int Id, char *element, int index, void *userData)
489 {
490 tGfuiObject *object;
491 tGfuiScrollList *scrollist;
492 tGfuiListElement *elt;
493
494 object = gfuiGetObject(scr, Id);
495
496 if(object == NULL) {
497 return -1;
498 }
499
500 if(object->widget != GFUI_SCROLLIST) {
501 return -1;
502 }
503
504 scrollist = &(object->u.scrollist);
505
506 elt = (tGfuiListElement *)calloc(1, sizeof(tGfuiListElement));
507 elt->name = element;
508 elt->label = elt->name; /* TODO LENGTH !!!!!*/
509 elt->userData = userData;
510 elt->index = index;
511
512 gfuiScrollListInsElt(scrollist, elt, index);
513
514 scrollist->nbElts++;
515
516 if(scrollist->scrollBar) {
517 GfuiScrollBarPosSet(scr, scrollist->scrollBar, 0, MAX(scrollist->nbElts - scrollist->nbVisible, 0),
518 scrollist->nbVisible, scrollist->firstVisible);
519 }
520
521 return 0;
522 }
523
524
525 void
gfuiDrawScrollist(tGfuiObject * obj)526 gfuiDrawScrollist(tGfuiObject *obj)
527 {
528 tGfuiScrollList *scrollist;
529 tGfuiListElement *elt;
530 float *fgColor;
531 float *bgColor;
532 const int BUFSIZE = 256;
533 char buf[BUFSIZE];
534 int w, h, x, y;
535 int index;
536
537 scrollist = &(obj->u.scrollist);
538
539 fgColor = scrollist->fgColor[0];
540 bgColor = scrollist->bgColor[0];
541
542 if(bgColor[3] != 0.0) {
543 glBegin(GL_QUADS);
544 glColor4fv(bgColor);
545 glVertex2i(obj->xmin, obj->ymin);
546 glVertex2i(obj->xmin, obj->ymax);
547 glVertex2i(obj->xmax, obj->ymax);
548 glVertex2i(obj->xmax, obj->ymin);
549 glEnd();
550 }
551
552 glBegin(GL_LINE_STRIP);
553 glColor4fv(fgColor);
554 glVertex2i(obj->xmin, obj->ymin);
555 glVertex2i(obj->xmin, obj->ymax);
556 glVertex2i(obj->xmax, obj->ymax);
557 glVertex2i(obj->xmax, obj->ymin);
558 glVertex2i(obj->xmin, obj->ymin);
559 glEnd();
560
561
562 h = scrollist->font->getDescender() + scrollist->font->getHeight();
563 x = obj->xmin;
564 y = obj->ymax;
565 index = 0;
566 elt = scrollist->elts;
567
568 if(elt != NULL) {
569 if(scrollist->nbElts < 100) {
570 snprintf(buf, BUFSIZE, " 00 ");
571 } else {
572 snprintf(buf, BUFSIZE, " 000 ");
573 }
574
575 w = scrollist->font->getWidth((const char *)buf);
576
577 do {
578 elt = elt->next;
579
580 if(index < scrollist->firstVisible) {
581 index++;
582 continue;
583 }
584
585 if(index == scrollist->selectedElt) {
586 glColor4fv(scrollist->fgSelectColor[0]);
587 } else {
588 glColor4fv(scrollist->fgColor[0]);
589 }
590
591 index++;
592
593 if(index > (scrollist->firstVisible + scrollist->nbVisible)) {
594 break;
595 }
596
597 y -= h;
598 snprintf(buf, BUFSIZE, " %d", index);
599 gfuiPrintString(x, y, scrollist->font, buf);
600 gfuiPrintString(x + w, y, scrollist->font, elt->label);
601 } while(elt != scrollist->elts);
602 }
603
604
605 }
606
607 void
gfuiScrollListDeselectAll(void)608 gfuiScrollListDeselectAll(void)
609 {
610 tGfuiObject *curObject;
611
612 curObject = GfuiScreen->objects;
613
614 if(curObject != NULL) {
615 do {
616 curObject = curObject->next;
617
618 if(curObject->widget == GFUI_SCROLLIST) {
619 curObject->u.scrollist.selectedElt = -1;
620 }
621 } while(curObject != GfuiScreen->objects);
622 }
623
624 }
625
626
627 void
gfuiScrollListAction(int mouse)628 gfuiScrollListAction(int mouse)
629 {
630 tGfuiObject *object;
631 tGfuiScrollList *scrollist;
632 int relY;
633
634 if(mouse == 0) {
635 /* button down */
636 gfuiScrollListDeselectAll();
637 object = GfuiScreen->hasFocus;
638 scrollist = &(object->u.scrollist);
639 relY = object->ymax - GfuiMouse.Y;
640 relY = scrollist->firstVisible + relY / (scrollist->font->getDescender() + scrollist->font->getHeight()) + 1;
641
642 if(relY > scrollist->nbElts) {
643 scrollist->selectedElt = -1;
644 return;
645 }
646
647 scrollist->selectedElt = relY - 1;
648
649 if(scrollist->onSelect) {
650 scrollist->onSelect(scrollist->userDataOnSelect);
651 }
652 }
653 }
654
655 /** Move the selected element within the scroll list.
656 @ingroup gui
657 @param scr Current screen
658 @param Id Scroll list Id
659 @param delta displacement
660 @return <tt>0 ... </tt>Ok
661 <br><tt>-1 .. </tt>Error
662 */
663 int
GfuiScrollListMoveSelectedElement(void * scr,int Id,int delta)664 GfuiScrollListMoveSelectedElement(void *scr, int Id, int delta)
665 {
666 tGfuiObject *object;
667 tGfuiScrollList *scrollist;
668 int newPos;
669 tGfuiListElement *elt;
670
671 object = gfuiGetObject(scr, Id);
672
673 if(object == NULL) {
674 return -1;
675 }
676
677 if(object->widget != GFUI_SCROLLIST) {
678 return -1;
679 }
680
681 scrollist = &(object->u.scrollist);
682
683 if(scrollist->selectedElt == -1) {
684 return -1;
685 }
686
687 newPos = scrollist->selectedElt + delta;
688
689 if((newPos < 0) || (newPos > scrollist->nbElts - 1)) {
690 return -1;
691 }
692
693 elt = gfuiScrollListRemElt(scrollist, scrollist->selectedElt);
694
695 gfuiScrollListInsElt(scrollist, elt, newPos);
696
697 scrollist->selectedElt = newPos;
698
699 if(scrollist->selectedElt == scrollist->firstVisible + scrollist->nbVisible) {
700 /* Scroll down */
701 if(scrollist->firstVisible + scrollist->nbVisible < scrollist->nbElts) {
702 scrollist->firstVisible++;
703
704 if(scrollist->scrollBar) {
705 GfuiScrollBarPosSet(GfuiScreen, scrollist->scrollBar, 0, MAX(scrollist->nbElts - scrollist->nbVisible, 0),
706 scrollist->nbVisible, scrollist->firstVisible);
707 }
708 }
709 } else if(scrollist->selectedElt < scrollist->firstVisible) {
710 /* Scroll down */
711 if(scrollist->firstVisible > 0) {
712 scrollist->firstVisible--;
713
714 if(scrollist->scrollBar) {
715 GfuiScrollBarPosSet(GfuiScreen, scrollist->scrollBar, 0, MAX(scrollist->nbElts - scrollist->nbVisible, 0),
716 scrollist->nbVisible, scrollist->firstVisible);
717 }
718 }
719 }
720
721 return 0;
722 }
723
724
725 void
gfuiReleaseScrollist(tGfuiObject * curObject)726 gfuiReleaseScrollist(tGfuiObject *curObject)
727 {
728 tGfuiScrollList *scrollist;
729 tGfuiListElement *elt;
730
731 scrollist = &(curObject->u.scrollist);
732
733 while((elt = gfuiScrollListRemElt(scrollist, 0)) != NULL) {
734 free(elt);
735 }
736
737 free(curObject);
738 }
739
740