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