1 /*
2  * XPilotNG/SDL, an SDL/OpenGL XPilot client.
3  *
4  * Copyright (C) 2003-2004 Erik Andersson <maximan@users.sourceforge.net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 
21 #include "xpclient_sdl.h"
22 
23 #include "sdlpaint.h"
24 #include "images.h"
25 #include "text.h"
26 #include "glwidgets.h"
27 #include "scrap.h"
28 
29 /****************************************************/
30 /* BEGIN: Main GLWidget stuff	    	    	    */
31 /****************************************************/
32 
33 static void option_callback( void *opt, const char *value );
34 static void confmenu_callback( void );
35 static void hover_optionWidget( int over, Uint16 x , Uint16 y , void *data );
36 static void clear_eventTarget( GLWidget *widget );
37 
38 static char *scrap = NULL;
39 static GLWidget *scraptarget = NULL;
40 
Init_EmptyBaseGLWidget(void)41 GLWidget *Init_EmptyBaseGLWidget( void )
42 {
43     GLWidget *tmp = XMALLOC(GLWidget, 1);
44     if ( !tmp ) return NULL;
45     tmp->WIDGET     	= -1;
46     tmp->bounds.x   	= 0;
47     tmp->bounds.y   	= 0;
48     tmp->bounds.w   	= 0;
49     tmp->bounds.h   	= 0;
50     tmp->wid_info   	= NULL;
51     tmp->Draw	    	= NULL;
52     tmp->Close	    	= NULL;
53     tmp->SetBounds  	= NULL;
54     tmp->button     	= NULL;
55     tmp->buttondata 	= NULL;
56     tmp->motion     	= NULL;
57     tmp->motiondata 	= NULL;
58     tmp->hover	    	= NULL;
59     tmp->hoverdata  	= NULL;
60     tmp->list   	= NULL;
61     tmp->children   	= NULL;
62     tmp->next	    	= NULL;
63     return tmp;
64 }
65 
clear_eventTarget(GLWidget * widget)66 static void clear_eventTarget( GLWidget *widget )
67 {
68     int i;
69 
70     if (!widget) {
71     	error("NULL passed to clear_eventTarget!");
72     	return;
73     }
74 
75     for (i=0;i<NUM_MOUSE_BUTTONS;++i)
76     	if (widget == clicktarget[i]) clicktarget[i]=NULL;
77     if (widget == hovertarget) hovertarget=NULL;
78     if (widget == scraptarget) scraptarget=NULL;
79 
80 }
81 
82 /* only supposed to take care of mallocs done on behalf of the
83  * appropriate Init_<foo> function
84  */
Close_WidgetTree(GLWidget ** widget)85 static void Close_WidgetTree ( GLWidget **widget )
86 {
87     if (!widget) return;
88     if (!(*widget)) return;
89 
90     Close_WidgetTree ( &((*widget)->next) );
91     Close_WidgetTree ( &((*widget)->children) );
92 
93     if ((*widget)->Close) (*widget)->Close(*widget);
94 
95     clear_eventTarget(*widget);
96 
97     if ((*widget)->wid_info) free((*widget)->wid_info);
98     free(*widget);
99     *widget = NULL;
100 }
101 
Close_Widget(GLWidget ** widget)102 void Close_Widget ( GLWidget **widget )
103 {
104     GLWidget *tmp;
105 
106     if (!widget) {
107     	error("NULL passed to Close_Widget!");
108 	return;
109     }
110     if (!(*widget)) {
111     	error("pointer passed to Close_Widget points to NULL !");
112 	return;
113     }
114 
115     Close_WidgetTree( &((*widget)->children) );
116 
117     if ((*widget)->Close) (*widget)->Close(*widget);
118 
119     clear_eventTarget(*widget);
120 
121     tmp = *widget;
122     *widget = (*widget)->next;
123     free(tmp);
124 }
125 
126 /* IMPORTANT: compound widgets need to edit this function */
SetBounds_GLWidget(GLWidget * widget,SDL_Rect * b)127 void SetBounds_GLWidget( GLWidget *widget, SDL_Rect *b )
128 {
129     if (!widget) {
130     	error("NULL widget passed to SetBounds_GLWidget!");
131     	return;
132     }
133     if (!b) {
134     	error("NULL bounds passed to SetBounds_GLWidget!");
135     	return;
136     }
137 
138     if (widget->SetBounds) widget->SetBounds(widget,b);
139     else {
140     	widget->bounds.x = b->x;
141     	widget->bounds.y = b->y;
142     	widget->bounds.w = b->w;
143     	widget->bounds.h = b->h;
144     }
145 }
146 
hover_optionWidget(int over,Uint16 x,Uint16 y,void * data)147 static void hover_optionWidget( int over, Uint16 x , Uint16 y , void *data )
148 {
149     static GLWidget *hoverWidget, *labelWidget;
150     xp_option_t *opt;
151     static SDL_Rect b;
152     const char *help;
153     static char line[256];
154     int start = 0, end = 0;
155     bool eternalLoop = true;
156     static Uint32 bgColor = 0x0000ff88;
157 
158     if (over) {
159     	if (!data) {
160     	    error("NULL option passed to hover_optionWidget\n");
161 	    return;
162     	}
163 
164     	opt = (xp_option_t *)data;
165 
166     	if ((help = Option_get_help(opt))) {
167     	    if (!(hoverWidget = Init_ListWidget( x, y, &nullRGBA, &nullRGBA, &nullRGBA, DOWN, LEFT, VERTICAL, false ))) {
168 	    	error("hover_optionWidget: Failed to create ListWidget\n");
169 		return;
170 	    }
171 
172     	    if (!(labelWidget = Init_LabelWidget( Option_get_name(opt), &yellowRGBA, &bgColor, CENTER, CENTER ))) {
173     	    	error("hover_optionWidget: Failed to create LabelWidget\n");
174     	    	Close_Widget(&hoverWidget);
175     	    	return;
176     	    }
177     	    ListWidget_Append( hoverWidget , labelWidget );
178 
179 	    for ( end=0 ; end < 1000000; ++end) {
180 	    	if ( help[end] != '\n' && help[end] != '\0') {
181 		    continue;
182 		}
183 
184     	    	if (start != end ) {
185 		    strncpy(&line[0],help+start,MIN(255,end-start));
186 		    line[MIN(255,end-start)]='\0';
187 
188     	    	    if (!(labelWidget = Init_LabelWidget( &line[0], &whiteRGBA, &bgColor, CENTER, CENTER ))) {
189     	    	    	error("hover_optionWidget: Failed to create LabelWidget\n");
190 		    	Close_Widget(&hoverWidget);
191     	    	    	return;
192     	    	    }
193     	    	    ListWidget_Append( hoverWidget , labelWidget );
194 		}
195 
196     	    	start = end+1;
197 		if (help[end] == '\0') {
198 		    eternalLoop = false;
199 		    break;
200 		}
201 	    }
202 
203 	    if (eternalLoop) error("hover_optionWidget: string parse never ends! (infinite loop prevented)\n");
204 
205 	    AppendGLWidgetList( &(MainWidget->children), hoverWidget );
206 
207    	    b.h = hoverWidget->bounds.h;
208     	    b.w = hoverWidget->bounds.w;
209     	    b.x = x - hoverWidget->bounds.w - 10;
210     	    b.y = y - hoverWidget->bounds.h/2;
211 
212     	    SetBounds_GLWidget(hoverWidget,&b);
213     	}
214     } else {
215     	if (!hoverWidget)
216 	    return;
217     	DelGLWidgetListItem( &(MainWidget->children), hoverWidget );
218     	Close_Widget(&hoverWidget);
219     }
220 }
221 
option_callback(void * tmp,const char * value)222 static void option_callback( void *tmp, const char *value )
223 {
224     xp_option_t *opt;
225 
226     if (!(opt = (xp_option_t *)tmp)) {
227     	error("Faulty parameter to option_callback: opt is a NULL pointer!");
228 	return;
229     }
230 
231     switch ( Option_get_type(opt) ) {
232     	case xp_bool_option:
233     	    Set_bool_option( opt, *(opt->bool_ptr), xp_option_origin_config);
234 	    return;
235     	case xp_int_option:
236     	    Set_int_option( opt, *(opt->int_ptr), xp_option_origin_config);
237 	    return;
238     	case xp_double_option:
239     	    Set_double_option( opt, *(opt->dbl_ptr), xp_option_origin_config);
240 	    return;
241     	case xp_string_option:
242 	    if (Option_get_flags(opt) & XP_OPTFLAG_CONFIG_COLORS) {
243 	    	Set_string_option( opt, value, xp_option_origin_config);
244 	    	return;
245 	    }
246     	default:
247 	    return;
248     }
249 }
250 
251 /* Eventually this will be the only visible initializer I guess */
Init_OptionWidget(xp_option_t * opt,Uint32 * fgcolor,Uint32 * bgcolor)252 GLWidget *Init_OptionWidget( xp_option_t *opt, Uint32 *fgcolor, Uint32 *bgcolor )
253 {
254     if (!opt) {
255     	error("Faulty parameter to Init_DoubleChooserWidget: opt is a NULL pointer!");
256 	return NULL;
257     }
258 
259     switch ( Option_get_type(opt) ) {
260     	case xp_bool_option:
261 	    if (Option_get_flags(opt) & XP_OPTFLAG_CONFIG_DEFAULT)
262 	    	return Init_BoolChooserWidget(opt->name,opt->bool_ptr,fgcolor,bgcolor,option_callback,opt);
263 	    break;
264     	case xp_int_option:
265 	    if (Option_get_flags(opt) & XP_OPTFLAG_CONFIG_DEFAULT)
266 	    	return Init_IntChooserWidget(opt->name,opt->int_ptr,opt->int_minval,opt->int_maxval,fgcolor,bgcolor,option_callback,opt);
267 	    break;
268     	case xp_double_option:
269 	    if (Option_get_flags(opt) & XP_OPTFLAG_CONFIG_DEFAULT)
270 	    	return Init_DoubleChooserWidget(opt->name,opt->dbl_ptr,opt->dbl_minval,opt->dbl_maxval,fgcolor,bgcolor,option_callback,opt);
271 	    break;
272     	case xp_string_option:
273 	    if (Option_get_flags(opt) & XP_OPTFLAG_CONFIG_COLORS)
274 	    	return Init_ColorChooserWidget(opt->name,(Uint32 *)opt->private_data,fgcolor,bgcolor,option_callback,opt);
275 	    break;
276     	default:
277 	    break;
278     }
279     return NULL;
280 }
281 
AppendGLWidgetList(GLWidget ** list,GLWidget * item)282 bool AppendGLWidgetList( GLWidget **list, GLWidget *item )
283 {
284     GLWidget **curr;
285 
286     if (!list) {
287     	error("No list holder for AppendGLWidgetList %i");
288     	return false;
289     }
290     if (!item) {
291     	error("Null item sent to AppendGLWidgetList");
292     }
293 
294     item->list = list;
295 
296     curr = list;
297     while (*curr) {
298     	/* Just a trivial check if item already is in the list
299 	 * doesn't check for item's trailers however!
300 	 * Make sure items aren't added twice!
301 	 */
302 	if (*curr == item) {
303 	    error("AppendGLWidgetList: item is already in the list!");
304 	    return false;
305 	}
306     	curr = &((*curr)->next);
307     }
308     *curr = item;
309 
310     return true;
311 }
312 
PrependGLWidgetList(GLWidget ** list,GLWidget * item)313 void PrependGLWidgetList( GLWidget **list, GLWidget *item )
314 {
315     GLWidget **curr;
316 
317     if (!list) {
318     	error("No list holder for PrependGLWidgetList");
319     	return;
320     }
321     if (!item) {
322     	error("Null item sent to PrependGLWidgetList");
323     }
324 
325     item->list = list;
326 
327     curr = &item;
328     while (*curr) {
329     	curr = &((*curr)->next);
330     }
331 
332     *curr = *list;
333     *list = item;
334 }
335 
DelGLWidgetListItem(GLWidget ** list,GLWidget * widget)336 bool DelGLWidgetListItem( GLWidget **list, GLWidget *widget )
337 {
338     GLWidget **curr;
339 
340     if (!list) {
341     	error("No list holder for DelGLWidgetListItem");
342     	return false;
343     }
344     if (!widget) {
345     	error("Null widget sent to DelGLWidgetListItem");
346 	return false;
347     }
348 
349     /* We don't clear widget->list here, because it still 'belongs'
350      * to list until we link it somewhere else
351      */
352 
353     curr = list;
354     while (*curr) {
355     	if (*curr == widget) {
356 	    *curr = (*curr)->next;
357 	    widget->next = NULL;
358 	    return true;
359 	}
360     	curr = &((*curr)->next);
361     }
362 
363     return false;
364 }
365 
366 /*
367  * Traverses a widget tree and calls Draw for each widget
368  * the order is widget then its children (first to last)
369  * then it moves onto the next widget in the list
370  */
DrawGLWidgetsi(GLWidget * list,int x,int y,int w,int h)371 void DrawGLWidgetsi( GLWidget *list, int x, int y, int w, int h)
372 {
373     int x2,y2,w2,h2;
374     GLWidget *curr;
375 
376     curr = list;
377 
378     while (curr) {
379     	x2 = MAX(x,curr->bounds.x);
380     	y2 = MAX(y,curr->bounds.y);
381     	w2 = MIN(x+w,curr->bounds.x+curr->bounds.w) - x2;
382     	h2 = MIN(y+h,curr->bounds.y+curr->bounds.h) - y2;
383 	if ( (w2 > 0) && (h2 > 0) ) {
384     	    glEnable(GL_BLEND);
385     	    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
386 	    glScissor(x2, draw_height - y2 - h2, w2+1, h2+1);
387 	    if (curr->Draw) curr->Draw(curr);
388 	    glDisable(GL_BLEND);
389 
390 	    DrawGLWidgetsi(curr->children,x2, y2, w2, h2);
391 	    glScissor(x, draw_height - y - h, w, h);
392 	}
393 
394 	curr = curr->next;
395     }
396 }
DrawGLWidgets(GLWidget * list)397 void DrawGLWidgets( GLWidget *list )
398 {
399     glScissor(0, 0, draw_width, draw_height);
400     glEnable(GL_SCISSOR_TEST);
401     DrawGLWidgetsi( list , 0, 0, draw_width, draw_height );
402     glDisable(GL_SCISSOR_TEST);
403 }
404 
405 /*
406  * Similar to DrawGLWidgets, but this one needs to traverse the
407  * tree in reverse order! (since the things painted last will
408  * be seen ontop, thus should get first pick of events
409  * So it will descend to the last child in the list's last widget
410  * then traverse back trying to find the target.
411  */
412 /*
413  * Possibly this function will be hidden, and
414  * GLWidget *FindGLWidget( Uint16 x, Uint16 y );
415  * visible only. (so that nobody passes a non-visible
416  * widget list)
417  */
FindGLWidgeti(GLWidget * widget,Uint16 x,Uint16 y)418 GLWidget *FindGLWidgeti( GLWidget *widget, Uint16 x, Uint16 y )
419 {
420     GLWidget *tmp;
421 
422     if ( !widget ) return NULL;
423 
424     if ( (tmp = FindGLWidgeti( widget->next, x, y )) ) {
425     	return tmp;
426     }
427 
428     if(     (x >= widget->bounds.x) && (x <= (widget->bounds.x + widget->bounds.w))
429     	&&  (y >= widget->bounds.y) && (y <= (widget->bounds.y + widget->bounds.h)) ) {
430     	if ( (tmp = FindGLWidgeti( widget->children, x, y )) ) {
431     	    return tmp;
432     	} else return widget;
433     } else {
434     	return NULL;
435     }
436 }
FindGLWidget(GLWidget * list,Uint16 x,Uint16 y)437 GLWidget *FindGLWidget( GLWidget *list, Uint16 x, Uint16 y )
438 {
439     return FindGLWidgeti( list, x, y );
440 }
441 
load_textscrap(char * text)442 void load_textscrap(char *text)
443 {
444     char *cp;
445     int   i;
446 
447     if (!text) return;
448 
449     scraptarget = NULL;
450     scrap = realloc(scrap, strlen(text)+1);
451     strcpy(scrap, text);
452     for ( cp=scrap, i=0; i<(int)strlen(scrap); ++cp, ++i ) {
453     	if ( *cp == '\n' )
454     	    *cp = '\r';
455     }
456     put_scrap(TextScrap('T','E','X','T'), strlen(scrap), scrap);
457 }
458 /****************************************************/
459 /* END: Main GLWidget stuff 	    	    	    */
460 /****************************************************/
461 
462 /**********************/
463 /* Begin:  ArrowWidget*/
464 /**********************/
465 static void button_ArrowWidget( Uint8 button, Uint8 state, Uint16 x, Uint16 y, void *data );
466 static void Paint_ArrowWidget( GLWidget *widget );
467 
button_ArrowWidget(Uint8 button,Uint8 state,Uint16 x,Uint16 y,void * data)468 static void button_ArrowWidget( Uint8 button, Uint8 state, Uint16 x, Uint16 y, void *data )
469 {
470     ArrowWidget *tmp;
471 
472     if (!data) return;
473     tmp = (ArrowWidget *)(((GLWidget *)data)->wid_info);
474     if (state == SDL_PRESSED && !(tmp->locked)) {
475 	if (button == 1) {
476     	    tmp->press = true;
477 	}
478 	if (button == 2) {
479 	    tmp->tap = true;
480 	    if (tmp->action) tmp->action(tmp->actiondata);
481 	}
482     }
483     if (state == SDL_RELEASED) {
484 	if (button == 1) {
485     	    tmp->press = false;
486 	}
487     }
488 }
489 
Paint_ArrowWidget(GLWidget * widget)490 static void Paint_ArrowWidget( GLWidget *widget )
491 {
492     GLWidget *tmp;
493     SDL_Rect *b;
494     ArrowWidget *wid_info;
495     ArrowWidget_dir_t dir;
496     static Uint32 normalcolor  = 0xff0000ff;
497     static Uint32 presscolor   = 0x00ff00ff;
498     static Uint32 tapcolor     = 0xffffffff;
499     static Uint32 lockcolor    = 0x88000088;
500 
501     if (!widget) return;
502 
503     tmp = widget;
504     b = &(tmp->bounds);
505     wid_info = (ArrowWidget *)(tmp->wid_info);
506 
507     if (wid_info->locked) {
508     	set_alphacolor( lockcolor );
509     } else if (wid_info->press) {
510     	if (wid_info->action) {
511 	    wid_info->action(wid_info->actiondata);
512 	}
513 	set_alphacolor( presscolor );
514     } else if (wid_info->tap) {
515     	set_alphacolor( tapcolor );
516     	wid_info->tap = false;
517     } else {
518     	set_alphacolor( normalcolor );
519     }
520 
521     dir = wid_info->direction;
522     glBegin(GL_POLYGON);
523     switch ( dir ) {
524     	case RIGHTARROW:
525 	    glVertex2i(b->x 	    ,b->y   	);
526 	    glVertex2i(b->x 	    ,b->y+b->h	);
527 	    glVertex2i(b->x + b->w  ,b->y+b->h/2);
528 	    break;
529     	case UPARROW:
530 	    glVertex2i(b->x + b->w/2,b->y   	);
531 	    glVertex2i(b->x 	    ,b->y+b->h	);
532 	    glVertex2i(b->x + b->w  ,b->y+b->h	);
533 	    break;
534     	case LEFTARROW:
535 	    glVertex2i(b->x + b->w  ,b->y   	);
536 	    glVertex2i(b->x 	    ,b->y+b->h/2);
537 	    glVertex2i(b->x + b->w  ,b->y+b->h	);
538 	    break;
539     	case DOWNARROW:
540 	    glVertex2i(b->x 	    ,b->y   	);
541 	    glVertex2i(b->x + b->w/2,b->y+b->h	);
542 	    glVertex2i(b->x + b->w  ,b->y   	);
543 	    break;
544 	default:
545 	    error("Weird direction for ArrowWidget! (direction:%i)\n",dir);
546     }
547     glEnd();
548 }
549 
Init_ArrowWidget(ArrowWidget_dir_t direction,int width,int height,void (* action)(void * data),void * actiondata)550 GLWidget *Init_ArrowWidget( ArrowWidget_dir_t direction,int width, int height,
551     	     void (*action)( void *data), void *actiondata )
552 {
553     ArrowWidget *wid_info;
554     GLWidget	*tmp	= Init_EmptyBaseGLWidget();
555 
556     if ( !tmp ) {
557         error("Failed to malloc in Init_ArrowWidget");
558 	return NULL;
559     }
560     tmp->wid_info   	= malloc(sizeof(ArrowWidget));
561     if ( !(tmp->wid_info) ) {
562     	free(tmp);
563         error("Failed to malloc in Init_ArrowWidget");
564 	return NULL;
565     }
566     wid_info = (ArrowWidget *)tmp->wid_info;
567 
568     tmp->WIDGET     	= ARROWWIDGET;
569     wid_info->direction  = direction;
570     tmp->bounds.w   	= width;
571     tmp->bounds.h   	= height;
572     wid_info->press 	= false;
573     wid_info->tap   	= false;
574     wid_info->locked	= false;
575     wid_info->action	= action;
576     wid_info->actiondata= actiondata;
577     tmp->Draw	    	= Paint_ArrowWidget;
578     tmp->button     	= button_ArrowWidget;
579     tmp->buttondata 	= tmp;
580 
581     return tmp;
582 }
583 
584 /********************/
585 /* End:  ArrowWidget*/
586 /********************/
587 
588 /**********************/
589 /* Begin:  ButtonWidget*/
590 /**********************/
591 static void button_ButtonWidget( Uint8 button, Uint8 state, Uint16 x, Uint16 y, void *data );
592 static void Paint_ButtonWidget( GLWidget *widget );
593 
button_ButtonWidget(Uint8 button,Uint8 state,Uint16 x,Uint16 y,void * data)594 static void button_ButtonWidget( Uint8 button, Uint8 state, Uint16 x, Uint16 y, void *data )
595 {
596     ButtonWidget *tmp;
597 
598     if (!data) return;
599     tmp = (ButtonWidget *)(((GLWidget *)data)->wid_info);
600     if (state == SDL_PRESSED) {
601     	if (tmp->pressed) return;
602 	if (button == 1) {
603     	    tmp->pressed = true;
604 	    tmp->press_time = loopsSlow;
605 	    if (tmp->action) tmp->action(tmp->actiondata);
606 	}
607     }
608 }
609 
Paint_ButtonWidget(GLWidget * widget)610 static void Paint_ButtonWidget( GLWidget *widget )
611 {
612     ButtonWidget *wid_info;
613     int color;
614 
615     if (!widget) return;
616     if (!(wid_info = (ButtonWidget *)(widget->wid_info))) return;
617 
618     if (wid_info->pressed) {
619     	if (wid_info->pressed_color)
620 	    color = *(wid_info->pressed_color);
621 	else color = redRGBA;
622 	if (loopsSlow >= (int)(wid_info->press_time + wid_info->depress_time))
623 	    wid_info->pressed = false;
624     } else {
625     	if (wid_info->normal_color)
626 	    color = *(wid_info->normal_color);
627 	else color = greenRGBA;
628     }
629 
630     set_alphacolor(color);
631     glBegin(GL_QUADS);
632     	glVertex2i( widget->bounds.x 	    	    	, widget->bounds.y	    	    	);
633     	glVertex2i( widget->bounds.x	    	    	, widget->bounds.y+widget->bounds.h	);
634     	glVertex2i( widget->bounds.x+widget->bounds.w	, widget->bounds.y+widget->bounds.h	);
635     	glVertex2i( widget->bounds.x+widget->bounds.w	, widget->bounds.y	    	    	);
636     glEnd();
637 }
638 
Init_ButtonWidget(Uint32 * normal_color,Uint32 * pressed_color,Uint8 depress_time,void (* action)(void * data),void * actiondata)639 GLWidget *Init_ButtonWidget( Uint32 *normal_color, Uint32 *pressed_color, Uint8 depress_time, void (*action)(void *data), void *actiondata)
640 {
641     ButtonWidget    *wid_info;
642     GLWidget	    *tmp    = Init_EmptyBaseGLWidget();
643 
644     if ( !tmp ) {
645         error("Failed to malloc in Init_ButtonWidget");
646 	return NULL;
647     }
648     tmp->wid_info   	= malloc(sizeof(ButtonWidget));
649     if ( !(tmp->wid_info) ) {
650     	free(tmp);
651         error("Failed to malloc in Init_ButtonWidget");
652 	return NULL;
653     }
654     wid_info = (ButtonWidget *)tmp->wid_info;
655 
656     tmp->WIDGET     	= BUTTONWIDGET;
657     wid_info->pressed	    = false;
658     wid_info->normal_color  = normal_color;
659     wid_info->pressed_color = pressed_color;
660     wid_info->depress_time  = depress_time;
661     wid_info->action	    = action;
662     wid_info->actiondata    = actiondata;
663     tmp->Draw	    	= Paint_ButtonWidget;
664     tmp->button     	= button_ButtonWidget;
665     tmp->buttondata 	= tmp;
666 
667     return tmp;
668 }
669 
670 /********************/
671 /* End:  ButtonWidget*/
672 /********************/
673 
674 /**********************/
675 /* Begin: SlideWidget*/
676 /**********************/
677 static void button_SlideWidget( Uint8 button, Uint8 state, Uint16 x, Uint16 y, void *data );
678 static void Paint_SlideWidget( GLWidget *widget );
679 
button_SlideWidget(Uint8 button,Uint8 state,Uint16 x,Uint16 y,void * data)680 static void button_SlideWidget( Uint8 button, Uint8 state, Uint16 x, Uint16 y, void *data )
681 {
682     SlideWidget *tmp;
683 
684     if (!data) return;
685 
686     tmp = (SlideWidget *)(((GLWidget *)data)->wid_info);
687     if (state == SDL_PRESSED && !(tmp->sliding)) {
688 	if (button == 1) {
689     	    tmp->sliding = true;
690 	}
691     }
692     if (state == SDL_RELEASED) {
693 	if (button == 1) {
694     	    tmp->sliding = false;
695 	    if (tmp->release) tmp->release(tmp->releasedata);
696 	}
697     }
698 }
699 
Paint_SlideWidget(GLWidget * widget)700 static void Paint_SlideWidget( GLWidget *widget )
701 {
702     GLWidget *tmp;
703     SDL_Rect *b;
704     SlideWidget *wid_info;
705 
706 
707     static Uint32 normalcolor	= 0xff0000ff;
708     static Uint32 presscolor	= 0x00ff00ff;
709     static Uint32 lockcolor 	= 0x333333ff;
710     Uint32 color;
711 
712     if (!widget) return;
713     tmp = widget;
714     b = &(tmp->bounds);
715     wid_info = (SlideWidget *)(tmp->wid_info);
716 
717     if (wid_info->locked) {
718     	color = lockcolor;
719     } else if (wid_info->sliding) {
720     	color = presscolor;
721     } else {
722     	color = normalcolor;
723     }
724 
725     glBegin(GL_QUADS);
726     	set_alphacolor(color	    	    	);
727 	glVertex2i(b->x     	, b->y	    	);
728     	set_alphacolor(color	    	    	);
729     	glVertex2i(b->x + b->w	, b->y	    	);
730     	set_alphacolor(color & 0xffffff77   	);
731     	glVertex2i(b->x + b->w	, b->y + b->h	);
732     	set_alphacolor(color & 0xffffff77   	);
733     	glVertex2i(b->x     	, b->y + b->h	);
734     glEnd();
735 }
736 
Init_SlideWidget(bool locked,void (* motion)(Sint16 xrel,Sint16 yrel,Uint16 x,Uint16 y,void * data),void * motiondata,void (* release)(void * releasedata),void * releasedata)737 GLWidget *Init_SlideWidget( bool locked,
738     	     void (*motion)( Sint16 xrel, Sint16 yrel, Uint16 x, Uint16 y, void *data ), void *motiondata,
739 	     void (*release)(void *releasedata),void *releasedata )
740 {
741     SlideWidget *wid_info;
742     GLWidget *tmp	= Init_EmptyBaseGLWidget();
743 
744     if ( !tmp ) {
745         error("Failed to malloc in Init_SlideWidget");
746 	return NULL;
747     }
748     tmp->wid_info   	= malloc(sizeof(SlideWidget));
749     if ( !(tmp->wid_info) ) {
750     	free(tmp);
751         error("Failed to malloc in Init_SlideWidget");
752 	return NULL;
753     }
754     wid_info = (SlideWidget *)tmp->wid_info;
755 
756     tmp->WIDGET     	= SLIDEWIDGET;
757     tmp->bounds.x   	= 0;
758     tmp->bounds.y   	= 0;
759     tmp->bounds.w   	= 10;
760     tmp->bounds.h   	= 10;
761     wid_info->sliding	    = false;
762     wid_info->locked	    = locked;
763     wid_info->release	    = release;
764     wid_info->releasedata   = releasedata;
765     tmp->Draw	    	= Paint_SlideWidget;
766     tmp->button     	= button_SlideWidget;
767     tmp->buttondata 	= tmp;
768     tmp->motion     	= motion;
769     tmp->motiondata 	= motiondata;
770 
771     return tmp;
772 }
773 
774 /********************/
775 /* End: SlideWidget*/
776 /********************/
777 
778 /*************************/
779 /* Begin: ScrollbarWidget*/
780 /*************************/
781 static void motion_ScrollbarWidget( Sint16 xrel, Sint16 yrel, Uint16 x, Uint16 y, void *data );
782 static void release_ScrollbarWidget( void *releasedata );
783 static void Paint_ScrollbarWidget( GLWidget *widget );
784 static void SetBounds_ScrollbarWidget( GLWidget *widget, SDL_Rect *b );
785 static void Close_ScrollbarWidget ( GLWidget *widget );
786 
Close_ScrollbarWidget(GLWidget * widget)787 static void Close_ScrollbarWidget ( GLWidget *widget )
788 {
789     if (!widget) return;
790     if (widget->WIDGET !=SCROLLBARWIDGET) {
791     	error("Wrong widget type for Close_ScrollbarWidget [%i]",widget->WIDGET);
792 	return;
793     }
794 }
795 
SetBounds_ScrollbarWidget(GLWidget * widget,SDL_Rect * b)796 static void SetBounds_ScrollbarWidget( GLWidget *widget, SDL_Rect *b )
797 {
798     ScrollbarWidget *tmp;
799     SDL_Rect sb;
800 
801     if (!widget) return;
802     if (!b) return;
803     if (widget->WIDGET !=SCROLLBARWIDGET) {
804     	error("Wrong widget type for SetBounds_ScrollbarWidget [%i]",widget->WIDGET);
805 	return;
806     }
807 
808     widget->bounds.x = b->x;
809     widget->bounds.y = b->y;
810     widget->bounds.w = b->w;
811     widget->bounds.h = b->h;
812 
813     tmp = (ScrollbarWidget *)(widget->wid_info);
814 
815     switch (tmp->dir) {
816     	case SB_VERTICAL:
817     	    sb.x = b->x;
818     	    sb.w = b->w;
819 	    sb.y = b->y + (int)(b->h*tmp->pos);
820 	    sb.h = (int)(b->h*tmp->size);
821 	    break;
822 	case SB_HORISONTAL:
823     	    sb.y = b->y;
824     	    sb.h = b->h;
825 	    sb.x = b->x + (int)(b->w*tmp->pos);
826 	    sb.w = (int)(b->w*tmp->size);
827 	    break;
828     	default :
829 	    error("bad direction for Scrollbar in SetBounds_ScrollbarWidget!");
830 	    return;
831     }
832 
833     SetBounds_GLWidget(tmp->slide,&sb);
834 }
835 
Paint_ScrollbarWidget(GLWidget * widget)836 static void Paint_ScrollbarWidget( GLWidget *widget )
837 {
838     static Uint32 bgcolor  = 0x00000044;
839     SDL_Rect *b = &(widget->bounds);
840 
841     set_alphacolor( bgcolor );
842 
843     glBegin(GL_QUADS);
844     	glVertex2i(b->x     	, b->y);
845     	glVertex2i(b->x + b->w	, b->y);
846     	glVertex2i(b->x + b->w	, b->y + b->h);
847     	glVertex2i(b->x     	, b->y + b->h);
848     glEnd();
849 }
850 
motion_ScrollbarWidget(Sint16 xrel,Sint16 yrel,Uint16 x,Uint16 y,void * data)851 static void motion_ScrollbarWidget( Sint16 xrel, Sint16 yrel, Uint16 x, Uint16 y, void *data )
852 {
853     GLWidget *tmp;
854     ScrollbarWidget *wid_info;
855     GLWidget *slide;
856     Sint16 *coord1, coord2 = 0, min, max, size, move;
857     GLfloat oldpos;
858 
859     if (!data) return;
860 
861     tmp = (GLWidget *)data;
862     wid_info = (ScrollbarWidget *)tmp->wid_info;
863     slide = wid_info->slide;
864 
865 
866     switch (wid_info->dir) {
867     	case SB_VERTICAL:
868 	    coord1 = &(slide->bounds.y);
869 	    min = tmp->bounds.y;
870 	    size = slide->bounds.h;
871 	    max = min + tmp->bounds.h;
872 	    move = yrel;
873 	    break;
874 	case SB_HORISONTAL:
875 	    coord1 = &(slide->bounds.x);
876 	    min = tmp->bounds.x;
877 	    size = slide->bounds.w;
878 	    max = min + tmp->bounds.w;
879 	    move = xrel;
880 	    break;
881     	default :
882 	    error("bad direction for Scrollbar in motion_ScrollbarWidget!");
883 	    return;
884     }
885 
886     wid_info->oldmoves += move;
887 
888     if (!(wid_info->oldmoves)) return;
889 
890     if (wid_info->oldmoves > 0) {
891     	coord2 = MIN(max-size,*coord1+wid_info->oldmoves);
892     } else if (wid_info->oldmoves < 0) {
893     	coord2 = MAX(min,*coord1+wid_info->oldmoves);
894     }
895     wid_info->oldmoves -= coord2 - *coord1;
896     *coord1 = coord2;
897 
898     oldpos = wid_info->pos;
899     wid_info->pos = ((GLfloat)(*coord1 - min))/((GLfloat)(max - min));
900 
901     if ( (oldpos != wid_info->pos) && wid_info->poschange )
902     	wid_info->poschange(wid_info->pos,wid_info->poschangedata);
903 }
904 
release_ScrollbarWidget(void * releasedata)905 static void release_ScrollbarWidget( void *releasedata )
906 {
907     GLWidget *tmp;
908     ScrollbarWidget *wid_info;
909     if (!releasedata) return;
910 
911     tmp = (GLWidget *)releasedata;
912     wid_info = (ScrollbarWidget *)tmp->wid_info;
913 
914     wid_info->oldmoves = 0;
915 }
916 
ScrollbarWidget_SetSlideSize(GLWidget * widget,GLfloat size)917 void ScrollbarWidget_SetSlideSize( GLWidget *widget, GLfloat size )
918 {
919     ScrollbarWidget *sb;
920 
921     if (!widget) return;
922     if (widget->WIDGET !=SCROLLBARWIDGET) {
923     	error("Wrong widget type for SetBounds_ScrollbarWidget [%i]",widget->WIDGET);
924 	return;
925     }
926     if (!(sb = (ScrollbarWidget *)(widget->wid_info))) {
927     	error("ScrollbarWidget_SetSlideSize: wid_info missing!");
928 	return;
929     }
930 
931     sb->size = MIN(1.0f,MAX(0.0f,size));
932 
933     SetBounds_ScrollbarWidget(widget,&(widget->bounds));
934 }
935 
Init_ScrollbarWidget(bool locked,GLfloat pos,GLfloat size,ScrollWidget_dir_t dir,void (* poschange)(GLfloat pos,void * poschangedata),void * poschangedata)936 GLWidget *Init_ScrollbarWidget( bool locked, GLfloat pos, GLfloat size, ScrollWidget_dir_t dir,
937     	    	    	    	void (*poschange)( GLfloat pos , void *poschangedata),
938 				void *poschangedata )
939 {
940     ScrollbarWidget *wid_info;
941     GLWidget *tmp	= Init_EmptyBaseGLWidget();
942 
943     if ( !tmp ) {
944         error("Failed to malloc in Init_ScrollbarWidget");
945 	return NULL;
946     }
947     tmp->wid_info   	= malloc(sizeof(ScrollbarWidget));
948     if ( !(tmp->wid_info) ) {
949     	free(tmp);
950         error("Failed to malloc in Init_ScrollbarWidget");
951 	return NULL;
952     }
953     wid_info = (ScrollbarWidget *)tmp->wid_info;
954 
955     tmp->WIDGET     	= SCROLLBARWIDGET;
956     tmp->bounds.w   	= 10;
957     tmp->bounds.h   	= 10;
958     tmp->Draw	    	= Paint_ScrollbarWidget;
959     tmp->Close	    	= Close_ScrollbarWidget;
960     tmp->SetBounds  	= SetBounds_ScrollbarWidget;
961     /*add pgUp, pgDown here later with button*/
962     wid_info->pos   	= MAX(0.0f,MIN(1.0f,pos));
963     wid_info->size  	= MAX(0.0f,MIN(1.0f,size));
964     wid_info->dir   	= dir;
965     wid_info->oldmoves	= 0;
966     wid_info->poschange = poschange;
967     wid_info->poschangedata = poschangedata;
968     wid_info->slide 	= Init_SlideWidget(locked,motion_ScrollbarWidget, tmp, release_ScrollbarWidget, tmp);
969 
970     if ( !(((ScrollbarWidget *)tmp->wid_info)->slide) ) {
971     	error("Failed to make a SlideWidget for Init_ScrollbarWidget");
972 	free(tmp->wid_info);
973 	free(tmp);
974 	return NULL;
975     }
976 
977     AppendGLWidgetList(&(tmp->children), ((ScrollbarWidget *)tmp->wid_info)->slide);
978     return tmp;
979 }
980 /*************************/
981 /*   End: ScrollbarWidget*/
982 /*************************/
983 
984 /***********************/
985 /* Begin:  LabelWidget*/
986 /***********************/
987 static void Paint_LabelWidget( GLWidget *widget );
988 static void Close_LabelWidget ( GLWidget *widget );
989 
button_LabelWidget(Uint8 button,Uint8 state,Uint16 x,Uint16 y,void * data)990 static void button_LabelWidget( Uint8 button, Uint8 state, Uint16 x, Uint16 y, void *data )
991 {
992     LabelWidget *tmp;
993 
994     if (!data) return;
995     tmp = (LabelWidget *)(((GLWidget *)data)->wid_info);
996     if (state == SDL_PRESSED) {
997 	if (button == 1) {
998 	    if ((tmp->tex).text) {
999 	    	load_textscrap((tmp->tex).text);
1000 		scraptarget = (GLWidget *)data;
1001 	    }
1002 	}
1003     }
1004 }
1005 
Close_LabelWidget(GLWidget * widget)1006 static void Close_LabelWidget( GLWidget *widget )
1007 {
1008     if (!widget) return;
1009     if (widget->WIDGET !=LABELWIDGET) {
1010     	error("Wrong widget type for Close_LabelWidget [%i]",widget->WIDGET);
1011 	return;
1012     }
1013     free_string_texture(&(((LabelWidget *)widget->wid_info)->tex));
1014 }
1015 
LabelWidget_SetColor(GLWidget * widget,Uint32 * fgcolor,Uint32 * bgcolor)1016 bool LabelWidget_SetColor( GLWidget *widget , Uint32 *fgcolor, Uint32 *bgcolor )
1017 {
1018     LabelWidget *wi;
1019 
1020     if (!widget) return false;
1021     if (widget->WIDGET !=LABELWIDGET) {
1022     	error("Wrong widget type for LabelWidget_SetColor [%i]",widget->WIDGET);
1023 	return false;
1024     }
1025 
1026     if ( !(wi = (LabelWidget *)widget->wid_info) ) {
1027     	error("LabelWidget_SetColor: widget->wid_info missing!");
1028 	return false;
1029     }
1030     wi->bgcolor = bgcolor;
1031     wi->fgcolor = fgcolor;
1032 
1033     return true;
1034 }
Paint_LabelWidget(GLWidget * widget)1035 static void Paint_LabelWidget( GLWidget *widget )
1036 {
1037     GLWidget *tmp;
1038     SDL_Rect *b;
1039     LabelWidget *wid_info;
1040     int x, y, alpha;
1041     Uint32 color;
1042     static int flasher = 0;
1043 
1044     if (!widget) return;
1045 
1046     tmp = widget;
1047     b = &(tmp->bounds);
1048     wid_info = (LabelWidget *)(tmp->wid_info);
1049 
1050     if ( (wid_info->bgcolor) && *(wid_info->bgcolor) ) {
1051     	set_alphacolor(*(wid_info->bgcolor));
1052 
1053     	glBegin(GL_QUADS);
1054     	    glVertex2i(b->x     	,b->y);
1055    	    glVertex2i(b->x + b->w  ,b->y);
1056     	    glVertex2i(b->x + b->w  ,b->y+b->h);
1057     	    glVertex2i(b->x     	,b->y+b->h);
1058      	glEnd();
1059     }
1060 
1061     x = wid_info->align == LEFT   ? tmp->bounds.x :
1062 	wid_info->align == CENTER ? tmp->bounds.x + tmp->bounds.w / 2 :
1063 	tmp->bounds.x + tmp->bounds.w;
1064     y = wid_info->valign == DOWN   ? tmp->bounds.y :
1065 	wid_info->valign == CENTER ? tmp->bounds.y + tmp->bounds.h / 2 :
1066 	tmp->bounds.y + tmp->bounds.h;
1067 
1068 
1069     if ( wid_info->fgcolor )
1070     	color = *(wid_info->fgcolor);
1071     else
1072     	color = whiteRGBA;
1073 
1074     if (scraptarget == tmp) {
1075 	alpha = MAX(0,MIN(255,(color & 255) + tsin(flasher)*64));
1076 	flasher += TABLE_SIZE/clientFPS;
1077     	if (flasher >= TABLE_SIZE) flasher -= TABLE_SIZE;
1078 
1079 	color = (color&0xFFFFFF00) + alpha;
1080     }
1081 
1082     disp_text(&(wid_info->tex),
1083     	    	color,
1084     	    	wid_info->align,
1085     	    	wid_info->valign,
1086     	    	x,
1087     	    	draw_height - y,
1088     	    	true);
1089 }
1090 
Init_LabelWidget(const char * text,Uint32 * fgcolor,Uint32 * bgcolor,int align,int valign)1091 GLWidget *Init_LabelWidget( const char *text , Uint32 *fgcolor, Uint32 *bgcolor, int align, int valign  )
1092 {
1093     GLWidget *tmp;
1094     LabelWidget *wid_info;
1095 
1096     if (!text) {
1097     	error("text missing for Init_LabelWidget.");
1098 	return NULL;
1099     }
1100     tmp	= Init_EmptyBaseGLWidget();
1101     if ( !tmp ) {
1102         error("Failed to malloc in Init_LabelWidget");
1103 	return NULL;
1104     }
1105     tmp->wid_info   	= malloc(sizeof(LabelWidget));
1106     if ( !(tmp->wid_info) ) {
1107     	free(tmp);
1108         error("Failed to malloc in Init_LabelWidget");
1109 	return NULL;
1110     }
1111     wid_info = (LabelWidget *)tmp->wid_info;
1112 
1113     if ( !render_text(&gamefont, text, &(((LabelWidget *)tmp->wid_info)->tex)) ) {
1114     	free(tmp->wid_info);
1115     	free(tmp);
1116         error("Failed to render text in Init_LabelWidget");
1117 	return NULL;
1118     }
1119 
1120     tmp->WIDGET     	= LABELWIDGET;
1121     tmp->bounds.w   	= (((LabelWidget *)tmp->wid_info)->tex).width;
1122     tmp->bounds.h   	= (((LabelWidget *)tmp->wid_info)->tex).height;
1123     wid_info->fgcolor	= fgcolor;
1124     wid_info->bgcolor	= bgcolor;
1125     wid_info->align 	= align;
1126     wid_info->valign	= valign;
1127     tmp->Draw	    	= Paint_LabelWidget;
1128     tmp->Close     	= Close_LabelWidget;
1129     tmp->button     	= button_LabelWidget;
1130     tmp->buttondata 	= tmp;
1131 
1132     return tmp;
1133 }
1134 /********************/
1135 /* End:  LabelWidget*/
1136 /********************/
1137 
1138 /***********************************/
1139 /* Begin:  LabeledRadiobuttonWidget*/
1140 /***********************************/
1141 static void button_LabeledRadiobuttonWidget( Uint8 button, Uint8 state, Uint16 x, Uint16 y, void *data );
1142 static void Paint_LabeledRadiobuttonWidget( GLWidget *widget );
1143 
button_LabeledRadiobuttonWidget(Uint8 button,Uint8 state,Uint16 x,Uint16 y,void * data)1144 static void button_LabeledRadiobuttonWidget( Uint8 button, Uint8 state, Uint16 x, Uint16 y, void *data )
1145 {
1146     LabeledRadiobuttonWidget *tmp;
1147     if (!data) return;
1148     tmp = (LabeledRadiobuttonWidget *)(((GLWidget *)data)->wid_info);
1149     if (state == SDL_PRESSED) {
1150 	if (button == 1) {
1151 	    /* Toggle state, and call (*action)*/
1152 	    tmp->state = !(tmp->state);
1153 	    if (tmp->action)  {
1154 		tmp->action(tmp->state,tmp->actiondata);
1155 	    }
1156 	}
1157     }
1158 }
1159 
Paint_LabeledRadiobuttonWidget(GLWidget * widget)1160 static void Paint_LabeledRadiobuttonWidget( GLWidget *widget )
1161 {
1162     GLWidget *tmp;
1163     SDL_Rect *b;
1164     LabeledRadiobuttonWidget *wid_info;
1165     static Uint32 false_bg_color	= 0x00000044;
1166     static Uint32 true_bg_color	    	= 0x00000044;
1167     static Uint32 false_text_color	= 0xff0000ff;
1168     static Uint32 true_text_color	= 0x00ff00ff;
1169 
1170     if (!widget) return;
1171 
1172     tmp = widget;
1173     b = &(tmp->bounds);
1174     wid_info = (LabeledRadiobuttonWidget *)(tmp->wid_info);
1175 
1176     if (wid_info->state)
1177     	set_alphacolor(true_bg_color);
1178     else
1179     	set_alphacolor(false_bg_color);
1180 
1181     glBegin(GL_QUADS);
1182     	glVertex2i(b->x     	,b->y);
1183    	glVertex2i(b->x + b->w  ,b->y);
1184     	glVertex2i(b->x + b->w  ,b->y+b->h);
1185     	glVertex2i(b->x     	,b->y+b->h);
1186      glEnd();
1187 
1188     if (wid_info->state) {
1189     	disp_text(wid_info->ontex, true_text_color, CENTER, CENTER,tmp->bounds.x+tmp->bounds.w/2, draw_height - tmp->bounds.y-tmp->bounds.h/2, true);
1190     } else {
1191     	disp_text(wid_info->offtex, false_text_color, CENTER, CENTER, tmp->bounds.x+tmp->bounds.w/2, draw_height - tmp->bounds.y-tmp->bounds.h/2, true);
1192     }
1193 }
1194 
Init_LabeledRadiobuttonWidget(string_tex_t * ontex,string_tex_t * offtex,void (* action)(bool state,void * actiondata),void * actiondata,bool start_state)1195 GLWidget *Init_LabeledRadiobuttonWidget( string_tex_t *ontex, string_tex_t *offtex,
1196     	    	    	    	    	void (*action)(bool state, void *actiondata),
1197 					void *actiondata, bool start_state )
1198 {
1199     GLWidget	    	    	*tmp;
1200     LabeledRadiobuttonWidget	*wid_info;
1201 
1202     if (!ontex || !(ontex->tex_list) || !offtex || !(offtex->tex_list) ) {
1203     	error("texure(s) missing for Init_LabeledRadiobuttonWidget.");
1204 	return NULL;
1205     }
1206     tmp	= Init_EmptyBaseGLWidget();
1207     if ( !tmp ) {
1208         error("Failed to malloc in Init_LabeledRadiobuttonWidget");
1209 	return NULL;
1210     }
1211     tmp->wid_info   	= malloc(sizeof(LabeledRadiobuttonWidget));
1212     if ( !(tmp->wid_info) ) {
1213     	free(tmp);
1214         error("Failed to malloc in Init_LabeledRadiobuttonWidget");
1215 	return NULL;
1216     }
1217     wid_info = (LabeledRadiobuttonWidget *)tmp->wid_info;
1218 
1219     tmp->WIDGET     	= LABELEDRADIOBUTTONWIDGET;
1220     tmp->bounds.w   	= MAX(ontex->width,offtex->width)+5;
1221     tmp->bounds.h   	= MAX(ontex->height,offtex->height);
1222     wid_info->state 	= start_state;
1223     wid_info->ontex 	= ontex;
1224     wid_info->offtex	= offtex;
1225     wid_info->action	= action;
1226     wid_info->actiondata= actiondata;
1227     tmp->Draw	    	= Paint_LabeledRadiobuttonWidget;
1228     tmp->button     	= button_LabeledRadiobuttonWidget;
1229     tmp->buttondata 	= tmp;
1230 
1231     return tmp;
1232 }
1233 /*********************************/
1234 /* End:  LabeledRadiobuttonWidget*/
1235 /*********************************/
1236 
1237 /*****************************/
1238 /* Begin:  BoolChooserWidget */
1239 /*****************************/
1240 static void Paint_BoolChooserWidget( GLWidget *widget );
1241 static void BoolChooserWidget_SetValue( bool state, void *data );
1242 static void Close_BoolChooserWidget ( GLWidget *widget );
1243 static void SetBounds_BoolChooserWidget( GLWidget *widget, SDL_Rect *b );
1244 
1245 static int num_BoolChooserWidget = 0;
1246 static string_tex_t *BoolChooserWidget_ontex = NULL;
1247 static string_tex_t *BoolChooserWidget_offtex = NULL;
1248 
Close_BoolChooserWidget(GLWidget * widget)1249 static void Close_BoolChooserWidget( GLWidget *widget )
1250 {
1251     if (!widget) return;
1252     if (widget->WIDGET !=BOOLCHOOSERWIDGET) {
1253     	error("Wrong widget type for Close_BoolChooserWidget [%i]",widget->WIDGET);
1254 	return;
1255     }
1256 
1257     --num_BoolChooserWidget;
1258     if (!num_BoolChooserWidget) {
1259     	free_string_texture(BoolChooserWidget_ontex);
1260 	free(BoolChooserWidget_ontex);
1261 	BoolChooserWidget_ontex = NULL;
1262     	free_string_texture(BoolChooserWidget_offtex);
1263 	free(BoolChooserWidget_offtex);
1264 	BoolChooserWidget_offtex = NULL;
1265     }
1266 }
1267 
SetBounds_BoolChooserWidget(GLWidget * widget,SDL_Rect * b)1268 static void SetBounds_BoolChooserWidget( GLWidget *widget, SDL_Rect *b )
1269 {
1270     GLWidget *tmp;
1271     SDL_Rect b2;
1272 
1273     if (!widget) return;
1274     if (!b) return;
1275     if (widget->WIDGET !=BOOLCHOOSERWIDGET) {
1276     	error("Wrong widget type for SetBounds_BoolChooserWidget [%i]",widget->WIDGET);
1277 	return;
1278     }
1279 
1280     widget->bounds.x = b->x;
1281     widget->bounds.y = b->y;
1282     widget->bounds.w = b->w;
1283     widget->bounds.h = b->h;
1284 
1285     tmp = ((BoolChooserWidget *)(widget->wid_info))->buttonwidget;
1286 
1287     b2.h = tmp->bounds.h;
1288     b2.w = tmp->bounds.w;
1289     b2.x = widget->bounds.x + widget->bounds.w - 2 - tmp->bounds.w;
1290     b2.y = widget->bounds.y + 1;
1291 
1292     SetBounds_GLWidget(tmp,&b2);
1293 
1294     tmp = ((BoolChooserWidget *)(widget->wid_info))->name;
1295 
1296     b2.h = widget->bounds.h;
1297     b2.w = tmp->bounds.w;
1298     b2.x = widget->bounds.x + 2;
1299     b2.y = widget->bounds.y;
1300 
1301     SetBounds_GLWidget(tmp,&b2);
1302 }
1303 
BoolChooserWidget_SetValue(bool state,void * data)1304 static void BoolChooserWidget_SetValue( bool state, void *data )
1305 {
1306     GLWidget *wid;
1307     BoolChooserWidget *wi;
1308 
1309     if ( !(wid = (GLWidget *)data) ) {
1310     	error("BoolChooserWidget_SetValue: data missing!");
1311 	return;
1312     }
1313 
1314     if ( wid->WIDGET != BOOLCHOOSERWIDGET ) {
1315     	error("BoolChooserWidget_SetValue: wrong type of widget!");
1316 	return;
1317     }
1318 
1319     if ( !(wi = (BoolChooserWidget *)(wid->wid_info)) ) {
1320     	error("BoolChooserWidget_SetValue: wid_info missing!");
1321 	return;
1322     }
1323 
1324     *(wi->value) = state;
1325 
1326     if (wi->callback)
1327     	wi->callback( wi->data, NULL );
1328 }
1329 
Paint_BoolChooserWidget(GLWidget * widget)1330 static void Paint_BoolChooserWidget( GLWidget *widget )
1331 {
1332     /*static int name_color   = 0xffff66ff;*/
1333     BoolChooserWidget *wid_info;
1334 
1335     if (!widget) {
1336     	error("Paint_BoolChooserWidget: widget missing!");
1337 	return;
1338     }
1339 
1340     if ( widget->WIDGET != BOOLCHOOSERWIDGET ) {
1341     	error("Paint_BoolChooserWidget: wrong type of widget!");
1342 	return;
1343     }
1344 
1345     if ( !(wid_info = (BoolChooserWidget *)(widget->wid_info)) ) {
1346     	error("Paint_BoolChooserWidget: wid_info missing!");
1347 	return;
1348     }
1349 
1350     if ( (wid_info->bgcolor) && *(wid_info->bgcolor) ) {
1351     	set_alphacolor( *(wid_info->bgcolor) );
1352     	glBegin(GL_QUADS);
1353     	    glVertex2i(widget->bounds.x 	    	    ,widget->bounds.y	    	    	);
1354     	    glVertex2i(widget->bounds.x+widget->bounds.w,widget->bounds.y	    	    	);
1355     	    glVertex2i(widget->bounds.x+widget->bounds.w,widget->bounds.y+widget->bounds.h	);
1356     	    glVertex2i(widget->bounds.x 	    	    ,widget->bounds.y+widget->bounds.h	);
1357     	glEnd();
1358     }
1359 }
1360 
Init_BoolChooserWidget(const char * name,bool * value,Uint32 * fgcolor,Uint32 * bgcolor,void (* callback)(void * tmp,const char * value),void * data)1361 GLWidget *Init_BoolChooserWidget( const char *name, bool *value, Uint32 *fgcolor, Uint32 *bgcolor,
1362     	    	    	    	 void (*callback)(void *tmp, const char *value), void *data )
1363 {
1364     GLWidget *tmp;
1365     BoolChooserWidget *wid_info;
1366 
1367     if (!value) {
1368     	error("Faulty parameter to Init_BoolChooserWidget: value is a NULL pointer!");
1369 	return NULL;
1370     }
1371     if (!name || !strlen(name) ) {
1372     	error("name misssing for Init_BoolChooserWidget.");
1373 	return NULL;
1374     }
1375 
1376 
1377     if (!BoolChooserWidget_ontex) {
1378     	if ((BoolChooserWidget_ontex = XMALLOC(string_tex_t, 1))) {
1379 	    if (!(BoolChooserWidget_offtex = XMALLOC(string_tex_t, 1))) {
1380 	    	XFREE(BoolChooserWidget_ontex);
1381 	    	error("Failed to malloc BoolChooserWidget_offtex in Init_BoolChooserWidget");
1382 	    	return NULL;
1383 	    }
1384 	} else {
1385 	    error("Failed to malloc BoolChooserWidget_ontex in Init_BoolChooserWidget");
1386 	    return NULL;
1387 	}
1388 	if (render_text(&gamefont,"True",BoolChooserWidget_ontex)) {
1389     	    if (!render_text(&gamefont,"False",BoolChooserWidget_offtex)) {
1390 	    	error("Failed to render 'False' in Init_BoolChooserWidget");
1391 		free_string_texture(BoolChooserWidget_ontex);
1392 		XFREE(BoolChooserWidget_ontex);
1393 		XFREE(BoolChooserWidget_offtex);
1394 		return NULL;
1395 	    }
1396     	} else {
1397 	    error("Failed to render 'True' in Init_BoolChooserWidget");
1398     	    XFREE(BoolChooserWidget_ontex);
1399     	    XFREE(BoolChooserWidget_offtex);
1400     	    return NULL;
1401 	}
1402     }
1403 
1404     tmp	= Init_EmptyBaseGLWidget();
1405     if ( !tmp ) {
1406         error("Failed to malloc tmp in Init_BoolChooserWidget");
1407 	return NULL;
1408     }
1409     tmp->wid_info   	= malloc(sizeof(BoolChooserWidget));
1410     if ( !(tmp->wid_info) ) {
1411     	free(tmp);
1412         error("Failed to malloc tmp->wid_info in Init_BoolChooserWidget");
1413 	return NULL;
1414     }
1415 
1416     wid_info = (BoolChooserWidget *)(tmp->wid_info);
1417 
1418     if ( !(wid_info->name = Init_LabelWidget(name,fgcolor,&nullRGBA,LEFT,CENTER)) ) {
1419     	error("Failed to make a LabelWidget for Init_BoolChooserWidget");
1420 	Close_Widget(&tmp);
1421 	return NULL;
1422     }
1423     AppendGLWidgetList(&(tmp->children),wid_info->name);
1424 
1425     wid_info->name->hover   	= hover_optionWidget;
1426     wid_info->name->hoverdata	= data;
1427 
1428     if ( !(wid_info->buttonwidget = Init_LabeledRadiobuttonWidget(BoolChooserWidget_ontex,
1429     	    	    	    	    	BoolChooserWidget_offtex, BoolChooserWidget_SetValue,
1430 					tmp, *(value))) ) {
1431     	error("Failed to make a LabeledRadiobuttonWidget for Init_BoolChooserWidget");
1432 	Close_Widget(&tmp);
1433     	return NULL;
1434     }
1435     AppendGLWidgetList(&(tmp->children),wid_info->buttonwidget);
1436 
1437     tmp->WIDGET     	= BOOLCHOOSERWIDGET;
1438     tmp->bounds.w   	= 2 + wid_info->name->bounds.w+5+wid_info->buttonwidget->bounds.w + 2;
1439     tmp->bounds.h   	= 1 + MAX( wid_info->name->bounds.h,wid_info->buttonwidget->bounds.h) + 1 ;
1440 
1441     wid_info->value 	= value;
1442     wid_info->fgcolor 	= fgcolor;
1443     wid_info->bgcolor 	= bgcolor;
1444     wid_info->callback 	= callback;
1445     wid_info->data 	= data;
1446 
1447     tmp->Draw	    	= Paint_BoolChooserWidget;
1448     tmp->Close  	= Close_BoolChooserWidget;
1449     tmp->SetBounds  	= SetBounds_BoolChooserWidget;
1450 
1451     ++num_BoolChooserWidget;
1452     return tmp;
1453 }
1454 /***************************/
1455 /* End:  BoolChooserWidget */
1456 /***************************/
1457 
1458 /***************************/
1459 /* Begin: IntChooserWidget */
1460 /***************************/
1461 static void IntChooserWidget_Add( void *data );
1462 static void IntChooserWidget_Subtract( void *data );
1463 static void Paint_IntChooserWidget( GLWidget *widget );
1464 static void Close_IntChooserWidget ( GLWidget *widget );
1465 static void SetBounds_IntChooserWidget( GLWidget *widget, SDL_Rect *b );
1466 
Close_IntChooserWidget(GLWidget * widget)1467 static void Close_IntChooserWidget ( GLWidget *widget )
1468 {
1469     if (!widget) return;
1470     if (widget->WIDGET !=INTCHOOSERWIDGET) {
1471     	error("Wrong widget type for Close_IntChooserWidget [%i]",widget->WIDGET);
1472 	return;
1473     }
1474 
1475     free_string_texture( &(((IntChooserWidget *)widget->wid_info)->valuetex) );
1476 }
1477 
SetBounds_IntChooserWidget(GLWidget * widget,SDL_Rect * b)1478 static void SetBounds_IntChooserWidget( GLWidget *widget, SDL_Rect *b )
1479 {
1480     IntChooserWidget *tmp;
1481     GLWidget *tmp2;
1482     SDL_Rect rab,lab,b2;
1483 
1484     if (!widget) return;
1485     if (!b) return;
1486     if (widget->WIDGET !=INTCHOOSERWIDGET) {
1487     	error("Wrong widget type for SetBounds_IntChooserWidget [%i]",widget->WIDGET);
1488 	return;
1489     }
1490 
1491     widget->bounds.x = b->x;
1492     widget->bounds.y = b->y;
1493     widget->bounds.w = b->w;
1494     widget->bounds.h = b->h;
1495 
1496     tmp = (IntChooserWidget *)(widget->wid_info);
1497 
1498     lab.h = rab.h = tmp->valuetex.height-4;
1499     lab.w = rab.w = rab.h;
1500     lab.y = rab.y = widget->bounds.y + (widget->bounds.h-rab.h)/2;
1501     rab.x = widget->bounds.x + widget->bounds.w - rab.w -2/*>_|*/;
1502     lab.x = rab.x - tmp->valuespace/*_value*/ -2/*<_value_>*/ - lab.w;
1503 
1504     SetBounds_GLWidget(tmp->leftarrow,&lab);
1505     SetBounds_GLWidget(tmp->rightarrow,&rab);
1506 
1507     tmp2 = ((IntChooserWidget *)(widget->wid_info))->name;
1508 
1509     b2.h = widget->bounds.h;
1510     b2.w = tmp2->bounds.w;
1511     b2.x = widget->bounds.x + 2;
1512     b2.y = widget->bounds.y;
1513 
1514     SetBounds_GLWidget(tmp2,&b2);
1515 }
1516 
IntChooserWidget_Add(void * data)1517 static void IntChooserWidget_Add( void *data )
1518 {
1519     IntChooserWidget *tmp;
1520     char valuetext[16];
1521     int step;
1522 
1523     if (!data) return;
1524     tmp = ((IntChooserWidget *)((GLWidget *)data)->wid_info);
1525 
1526     if (tmp->direction > 0) {
1527      	step = (++tmp->duration)*(tmp->maxval-tmp->minval)/(MAX(1,MIN(maxFPS,FPS))*3);
1528     } else {
1529     	step = 1;
1530     }
1531 
1532     if (*(tmp->value) > tmp->maxval) {
1533     	((ArrowWidget *)tmp->rightarrow->wid_info)->locked = true;
1534     } else if (step) {
1535     	tmp->duration = 0;
1536     	*(tmp->value) = MIN( *(tmp->value) + step, tmp->maxval);
1537 
1538 	if (tmp->callback) tmp->callback( tmp->data, NULL );
1539 
1540     	if ( (*(tmp->value)) > tmp->minval)
1541 	    ((ArrowWidget *)tmp->leftarrow->wid_info)->locked = false;
1542     	if ( (*(tmp->value)) == tmp->maxval)
1543 	    ((ArrowWidget *)tmp->rightarrow->wid_info)->locked = true;
1544 	tmp->direction = 2;
1545 	snprintf(valuetext,15,"%i",*(tmp->value));
1546 	free_string_texture(&(tmp->valuetex));
1547 	if(!render_text(&gamefont,valuetext,&(tmp->valuetex)))
1548 	    error("Failed to make value (%s=%i) texture for IntChooserWidget!\n",
1549 	    	((LabelWidget *)(tmp->name->wid_info))->tex.text,*(tmp->value));
1550     } else {
1551     	++tmp->direction;
1552     }
1553 }
1554 
IntChooserWidget_Subtract(void * data)1555 static void IntChooserWidget_Subtract( void *data )
1556 {
1557     IntChooserWidget *tmp;
1558     char valuetext[16];
1559     int step;
1560 
1561     if (!data) return;
1562     tmp = ((IntChooserWidget *)((GLWidget *)data)->wid_info);
1563 
1564     if (tmp->direction < 0) {
1565     	step = (++tmp->duration)*(tmp->maxval-tmp->minval)/(MAX(1,MIN(maxFPS,FPS))*3);
1566     } else {
1567     	step = 1;
1568     }
1569 
1570     if (*(tmp->value) < tmp->minval) {
1571     	((ArrowWidget *)tmp->leftarrow->wid_info)->locked = true;
1572     } else if (step) {
1573     	tmp->duration = 0;
1574     	*(tmp->value) = MAX( (*(tmp->value)) - step, tmp->minval);
1575 
1576 	if (tmp->callback) tmp->callback( tmp->data, NULL );
1577 
1578     	if ( (*(tmp->value)) < tmp->maxval)
1579 	    ((ArrowWidget *)tmp->rightarrow->wid_info)->locked = false;
1580     	if ( (*(tmp->value)) == tmp->minval)
1581 	    ((ArrowWidget *)tmp->leftarrow->wid_info)->locked = true;
1582 	tmp->direction = -2;
1583 	snprintf(valuetext,15,"%i",*(tmp->value));
1584 	free_string_texture(&(tmp->valuetex));
1585 	if(!render_text(&gamefont,valuetext,&(tmp->valuetex)))
1586 	    error("Failed to make value (%s=%i) texture for IntChooserWidget!\n",
1587 	    ((LabelWidget *)(tmp->name->wid_info))->tex.text,*(tmp->value));
1588     } else {
1589     	--tmp->direction;
1590     }
1591 }
1592 
Paint_IntChooserWidget(GLWidget * widget)1593 static void Paint_IntChooserWidget( GLWidget *widget )
1594 {
1595     IntChooserWidget *wid_info;
1596 
1597     if (!widget) {
1598     	error("Paint_IntChooserWidget: argument is NULL!");
1599 	return;
1600     }
1601 
1602     wid_info = (IntChooserWidget *)(widget->wid_info);
1603 
1604     if (!wid_info) {
1605     	error("Paint_IntChooserWidget: wid_info missing");
1606 	return;
1607     }
1608 
1609     if (wid_info->direction > 0) --(wid_info->direction);
1610     else if (wid_info->direction < 0) ++(wid_info->direction);
1611 
1612     if ( (wid_info->bgcolor) && *(wid_info->bgcolor) ) {
1613     	set_alphacolor(*(wid_info->bgcolor));
1614     	glBegin(GL_QUADS);
1615     	    glVertex2i(widget->bounds.x 	    	    ,widget->bounds.y	    	    	);
1616     	    glVertex2i(widget->bounds.x+widget->bounds.w,widget->bounds.y	    	    	);
1617     	    glVertex2i(widget->bounds.x+widget->bounds.w,widget->bounds.y+widget->bounds.h	);
1618     	    glVertex2i(widget->bounds.x 	    	    ,widget->bounds.y+widget->bounds.h	);
1619     	glEnd();
1620     }
1621     if ( wid_info->fgcolor )
1622     	disp_text(&(wid_info->valuetex), *(wid_info->fgcolor), RIGHT, CENTER, wid_info->rightarrow->bounds.x-1/*value_>*/-2/*>_|*/, draw_height - widget->bounds.y - widget->bounds.h/2, true );
1623     else
1624     	disp_text(&(wid_info->valuetex), whiteRGBA, RIGHT, CENTER, wid_info->rightarrow->bounds.x-1/*value_>*/-2/*>_|*/, draw_height - widget->bounds.y - widget->bounds.h/2, true );
1625 }
1626 
Init_IntChooserWidget(const char * name,int * value,int minval,int maxval,Uint32 * fgcolor,Uint32 * bgcolor,void (* callback)(void * tmp,const char * value),void * data)1627 GLWidget *Init_IntChooserWidget( const char *name, int *value, int minval, int maxval, Uint32 *fgcolor,
1628     	    	    	    	Uint32 *bgcolor, void (*callback)(void *tmp, const char *value), void *data )
1629 {
1630     int valuespace;
1631     GLWidget *tmp;
1632     IntChooserWidget *wid_info;
1633     char valuetext[16];
1634     string_tex_t tmp_tex;
1635     int buttonsize;
1636 
1637     if (!value) {
1638     	error("Faulty parameter to Init_IntChooserWidget: value is a NULL pointer!");
1639 	return NULL;
1640     }
1641     if (!(name) || !strlen(name) ) {
1642     	error("name misssing for Init_IntChooserWidget.");
1643 	return NULL;
1644     }
1645 
1646     tmp = Init_EmptyBaseGLWidget();
1647     if ( !tmp ) {
1648         error("Failed to malloc in Init_IntChooserWidget");
1649 	return NULL;
1650     }
1651     tmp->wid_info   = malloc(sizeof(IntChooserWidget));
1652     if ( !(tmp->wid_info) ) {
1653     	free(tmp);
1654         error("Failed to malloc in Init_IntChooserWidget");
1655 	return NULL;
1656     }
1657 
1658     /* hehe ugly hack to guess max size of value strings
1659      * monospace font is preferred
1660      */
1661     if (render_text(&gamefont,"555.55",&tmp_tex)) {
1662     	free_string_texture(&tmp_tex);
1663 	valuespace = tmp_tex.width+4;
1664     } else {
1665     	valuespace = 50;
1666     }
1667 
1668     wid_info = (IntChooserWidget *)tmp->wid_info;
1669 
1670     snprintf(valuetext,15,"%i",*(value));
1671     if(!render_text(&gamefont,valuetext,&(wid_info->valuetex))) {
1672     	Close_Widget(&tmp);
1673 	error("Init_IntChooserWidget: Failed to render value string");
1674 	return NULL;
1675     }
1676     buttonsize = wid_info->valuetex.height-4;
1677 
1678     tmp->WIDGET     = INTCHOOSERWIDGET;
1679     tmp->Draw	    	= Paint_IntChooserWidget;
1680     tmp->Close  	= Close_IntChooserWidget;
1681     tmp->SetBounds  	= SetBounds_IntChooserWidget;
1682     wid_info->value   	= value;
1683     wid_info->minval   	= minval;
1684     wid_info->maxval   	= maxval;
1685     wid_info->valuespace= valuespace;
1686     wid_info->direction = 0;
1687     wid_info->fgcolor 	= fgcolor;
1688     wid_info->bgcolor 	= bgcolor;
1689     wid_info->callback 	= callback;
1690     wid_info->data 	= data;
1691 
1692 
1693     if ( !AppendGLWidgetList(&(tmp->children),(wid_info->name = Init_LabelWidget(name,fgcolor,&nullRGBA,LEFT,CENTER))) ) {
1694     	Close_Widget(&tmp);
1695     	error("Init_IntChooserWidget: Failed to initialize label [%s]",name);
1696 	return NULL;
1697     }
1698 
1699     wid_info->name->hover   	= hover_optionWidget;
1700     wid_info->name->hoverdata	= data;
1701 
1702     if ( !AppendGLWidgetList(&(tmp->children),(wid_info->leftarrow  = Init_ArrowWidget(LEFTARROW,buttonsize,buttonsize,IntChooserWidget_Subtract,tmp))) ) {
1703     	Close_Widget(&tmp);
1704     	error("Init_IntChooserWidget couldn't init leftarrow!");
1705     	return NULL;
1706     }
1707 
1708     if (*(wid_info->value) <= wid_info->minval) ((ArrowWidget *)(wid_info->leftarrow->wid_info))->locked = true;
1709 
1710     if ( !AppendGLWidgetList(&(tmp->children),(wid_info->rightarrow = Init_ArrowWidget(RIGHTARROW,buttonsize,buttonsize,IntChooserWidget_Add,tmp))) ) {
1711     	Close_Widget(&tmp);
1712     	error("Init_IntChooserWidget couldn't init rightarrow!");
1713     	return NULL;
1714     }
1715 
1716     if (*(wid_info->value) >= wid_info->maxval) ((ArrowWidget *)(wid_info->rightarrow->wid_info))->locked = true;
1717 
1718     tmp->bounds.w   = 2/*|_text*/+ wid_info->name->bounds.w +5/*text___<*/ + valuespace/*__value*/ + 2/*<_value_>*/
1719     	    	    + wid_info->leftarrow->bounds.w + wid_info->rightarrow->bounds.w +2/*>_|*/;
1720     tmp->bounds.h   = wid_info->name->bounds.h;
1721 
1722     return tmp;
1723 }
1724 /*************************/
1725 /* End: IntChooserWidget */
1726 /*************************/
1727 
1728 /******************************/
1729 /* Begin: DoubleChooserWidget */
1730 /******************************/
1731 static void DoubleChooserWidget_Add( void *data );
1732 static void DoubleChooserWidget_Subtract( void *data );
1733 static void Paint_DoubleChooserWidget( GLWidget *widget );
1734 static void Close_DoubleChooserWidget ( GLWidget *widget );
1735 static void SetBounds_DoubleChooserWidget( GLWidget *widget, SDL_Rect *b );
1736 
Close_DoubleChooserWidget(GLWidget * widget)1737 static void Close_DoubleChooserWidget ( GLWidget *widget )
1738 {
1739     if (!widget) return;
1740     if (widget->WIDGET !=DOUBLECHOOSERWIDGET) {
1741     	error("Wrong widget type for Close_DoubleChooserWidget [%i]",widget->WIDGET);
1742 	return;
1743     }
1744 
1745     free_string_texture( &(((DoubleChooserWidget *)widget->wid_info)->valuetex) );
1746 }
1747 
SetBounds_DoubleChooserWidget(GLWidget * widget,SDL_Rect * b)1748 static void SetBounds_DoubleChooserWidget( GLWidget *widget, SDL_Rect *b )
1749 {
1750     DoubleChooserWidget *tmp;
1751     GLWidget *tmp2;
1752     SDL_Rect rab,lab,b2;
1753 
1754     if (!widget) return;
1755     if (!b) return;
1756     if (widget->WIDGET !=DOUBLECHOOSERWIDGET) {
1757     	error("Wrong widget type for SetBounds_DoubleChooserWidget [%i]",widget->WIDGET);
1758 	return;
1759     }
1760 
1761     widget->bounds.x = b->x;
1762     widget->bounds.y = b->y;
1763     widget->bounds.w = b->w;
1764     widget->bounds.h = b->h;
1765 
1766     tmp = (DoubleChooserWidget *)(widget->wid_info);
1767 
1768     lab.h = rab.h = tmp->valuetex.height-4;
1769     lab.w = rab.w = rab.h;
1770     lab.y = rab.y = widget->bounds.y + (widget->bounds.h-rab.h)/2;
1771     rab.x = widget->bounds.x + widget->bounds.w - rab.w -2/*>_|*/;
1772     lab.x = rab.x - tmp->valuespace/*_value*/ -2/*<_value_>*/ - lab.w;
1773 
1774     SetBounds_GLWidget(tmp->leftarrow,&lab);
1775     SetBounds_GLWidget(tmp->rightarrow,&rab);
1776 
1777     tmp2 = ((DoubleChooserWidget *)(widget->wid_info))->name;
1778 
1779     b2.h = widget->bounds.h;
1780     b2.w = tmp2->bounds.w;
1781     b2.x = widget->bounds.x + 2;
1782     b2.y = widget->bounds.y;
1783 
1784     SetBounds_GLWidget(tmp2,&b2);
1785 }
1786 
DoubleChooserWidget_Add(void * data)1787 static void DoubleChooserWidget_Add( void *data )
1788 {
1789     DoubleChooserWidget *tmp;
1790     double step;
1791     char valuetext[16];
1792 
1793     if (!data) return;
1794     tmp = ((DoubleChooserWidget *)((GLWidget *)data)->wid_info);
1795 
1796     if (tmp->direction > 0)
1797     	step = (tmp->maxval-tmp->minval)/(clientFPS*10.0);
1798     else
1799     	step = 0.01;
1800 
1801     if ( *(tmp->value) < tmp->maxval ) {
1802     	*(tmp->value) = MIN( (*(tmp->value))+step,tmp->maxval );
1803 
1804 	if ( tmp->callback ) tmp->callback( tmp->data, NULL );
1805 
1806     	if ( (*(tmp->value)) > tmp->minval )
1807 	    ((ArrowWidget *)tmp->leftarrow->wid_info)->locked = false;
1808     	if ( (*(tmp->value)) >= tmp->maxval )
1809 	    ((ArrowWidget *)tmp->rightarrow->wid_info)->locked = true;
1810 	tmp->direction = 2;
1811 	snprintf(valuetext,15,"%1.2f",*(tmp->value));
1812 	free_string_texture(&(tmp->valuetex));
1813 	if(!render_text(&gamefont,valuetext,&(tmp->valuetex)))
1814 	    error("Failed to make value (%s=%1.2f) texture for doubleChooserWidget!\n",
1815 	    	    ((LabelWidget *)(tmp->name->wid_info))->tex.text,*(tmp->value));
1816     } else {
1817     	((ArrowWidget *)tmp->rightarrow->wid_info)->locked = true;
1818     }
1819 }
1820 
DoubleChooserWidget_Subtract(void * data)1821 static void DoubleChooserWidget_Subtract( void *data )
1822 {
1823     DoubleChooserWidget *tmp;
1824     double step;
1825     char valuetext[16];
1826 
1827     if (!data) return;
1828     tmp = ((DoubleChooserWidget *)((GLWidget *)data)->wid_info);
1829 
1830     if (tmp->direction < 0)
1831     	step = (tmp->maxval-tmp->minval)/(clientFPS*10.0);
1832     else
1833     	step = 0.01;
1834 
1835     if ( *(tmp->value) > tmp->minval ) {
1836     	*(tmp->value) = MAX( (*(tmp->value))-step,tmp->minval );
1837 
1838     	if ( tmp->callback ) tmp->callback( tmp->data, NULL );
1839 
1840     	if ( (*(tmp->value)) < tmp->maxval )
1841 	    ((ArrowWidget *)tmp->rightarrow->wid_info)->locked = false;
1842     	if ( (*(tmp->value)) <= tmp->minval )
1843 	    ((ArrowWidget *)tmp->leftarrow->wid_info)->locked = true;
1844 	tmp->direction = -2;
1845 	snprintf(valuetext,15,"%1.2f",*(tmp->value));
1846 	free_string_texture(&(tmp->valuetex));
1847 	if(!render_text(&gamefont,valuetext,&(tmp->valuetex)))
1848 	    error("Failed to make value (%s=%1.2f) texture for doubleChooserWidget!\n",
1849 	    	    ((LabelWidget *)(tmp->name->wid_info))->tex.text,*(tmp->value));
1850     } else {
1851     	((ArrowWidget *)tmp->leftarrow->wid_info)->locked = true;
1852     }
1853 }
1854 
Paint_DoubleChooserWidget(GLWidget * widget)1855 static void Paint_DoubleChooserWidget( GLWidget *widget )
1856 {
1857     DoubleChooserWidget *wid_info;
1858 
1859     if (!widget) {
1860     	error("Paint_DoubleChooserWidget: argument is NULL!");
1861 	return;
1862     }
1863 
1864     wid_info = (DoubleChooserWidget *)(widget->wid_info);
1865 
1866     if (!wid_info) {
1867     	error("Paint_DoubleChooserWidget: wid_info missing");
1868 	return;
1869     }
1870 
1871     if (wid_info->direction > 0) --(wid_info->direction);
1872     else if (wid_info->direction < 0) ++(wid_info->direction);
1873 
1874     if ( (wid_info->bgcolor) && *(wid_info->bgcolor) ) {
1875     	set_alphacolor(*(wid_info->bgcolor));
1876     	glBegin(GL_QUADS);
1877     	    glVertex2i(widget->bounds.x 	    	    ,widget->bounds.y	    	    	);
1878     	    glVertex2i(widget->bounds.x+widget->bounds.w,widget->bounds.y	    	    	);
1879     	    glVertex2i(widget->bounds.x+widget->bounds.w,widget->bounds.y+widget->bounds.h	);
1880     	    glVertex2i(widget->bounds.x 	    	    ,widget->bounds.y+widget->bounds.h	);
1881     	glEnd();
1882     }
1883 
1884     if ( wid_info->fgcolor )
1885     	disp_text(&(wid_info->valuetex), *(wid_info->fgcolor), RIGHT, CENTER, wid_info->rightarrow->bounds.x-1/*value_>*/-2/*>_|*/, draw_height - widget->bounds.y - widget->bounds.h/2, true );
1886     else
1887     	disp_text(&(wid_info->valuetex), whiteRGBA, RIGHT, CENTER, wid_info->rightarrow->bounds.x-1/*value_>*/-2/*>_|*/, draw_height - widget->bounds.y - widget->bounds.h/2, true );
1888 }
1889 
Init_DoubleChooserWidget(const char * name,double * value,double minval,double maxval,Uint32 * fgcolor,Uint32 * bgcolor,void (* callback)(void * tmp,const char * value),void * data)1890 GLWidget *Init_DoubleChooserWidget( const char *name, double *value, double minval, double maxval,
1891     	    	    	    	    Uint32 *fgcolor, Uint32 *bgcolor,
1892     	    	    	    	    void (*callback)(void *tmp, const char *value), void *data )
1893 {
1894     int valuespace;
1895     GLWidget *tmp;
1896     string_tex_t tmp_tex;
1897     DoubleChooserWidget *wid_info;
1898     char valuetext[16];
1899     int buttonsize;
1900 
1901     if (!value) {
1902     	error("Faulty parameter to Init_DoubleChooserWidget: value is a NULL pointer!");
1903 	return NULL;
1904     }
1905     if (!(name) || !strlen(name) ) {
1906     	error("name misssing for Init_DoubleChooserWidget.");
1907 	return NULL;
1908     }
1909 
1910     tmp = Init_EmptyBaseGLWidget();
1911     if ( !tmp ) {
1912         error("Failed to malloc in Init_DoubleChooserWidget");
1913 	return NULL;
1914     }
1915     tmp->wid_info   = XMALLOC(DoubleChooserWidget, 1);
1916     if ( !(tmp->wid_info) ) {
1917     	free(tmp);
1918         error("Failed to malloc in Init_DoubleChooserWidget");
1919 	return NULL;
1920     }
1921 
1922     /* hehe ugly hack to guess max size of value strings
1923      * monospace font is preferred
1924      */
1925     if (render_text(&gamefont,"555.55",&tmp_tex)) {
1926     	free_string_texture(&tmp_tex);
1927 	valuespace = tmp_tex.width+4;
1928     } else {
1929     	valuespace = 50;
1930     }
1931 
1932     wid_info = (DoubleChooserWidget *)tmp->wid_info;
1933 
1934     snprintf(valuetext,15,"%1.2f",*(value));
1935     if(!render_text(&gamefont,valuetext,&(wid_info->valuetex))) {
1936     	Close_Widget(&tmp);
1937 	error("Init_DoubleChooserWidget: Failed to render value string");
1938 	return NULL;
1939     }
1940     buttonsize = wid_info->valuetex.height-4;
1941 
1942     tmp->WIDGET     = DOUBLECHOOSERWIDGET;
1943     tmp->Draw	    	= Paint_DoubleChooserWidget;
1944     tmp->Close  	= Close_DoubleChooserWidget;
1945     tmp->SetBounds  	= SetBounds_DoubleChooserWidget;
1946     wid_info->value   	= value;
1947     wid_info->minval   	= minval;
1948     wid_info->maxval   	= maxval;
1949     wid_info->valuespace = valuespace;
1950     wid_info->direction = 0;
1951     wid_info->fgcolor 	= fgcolor;
1952     wid_info->bgcolor 	= bgcolor;
1953     wid_info->callback 	= callback;
1954     wid_info->data 	= data;
1955 
1956     if ( !AppendGLWidgetList(&(tmp->children),(wid_info->name = Init_LabelWidget(name,fgcolor,&nullRGBA,LEFT,CENTER))) ) {
1957     	Close_Widget(&tmp);
1958     	error("Init_DoubleChooserWidget: Failed to initialize label [%s]",name);
1959 	return NULL;
1960     }
1961 
1962     wid_info->name->hover   	= hover_optionWidget;
1963     wid_info->name->hoverdata	= data;
1964 
1965     if ( !AppendGLWidgetList(&(tmp->children),(wid_info->leftarrow  = Init_ArrowWidget(LEFTARROW,buttonsize,buttonsize,DoubleChooserWidget_Subtract,tmp))) ) {
1966     	Close_Widget(&tmp);
1967     	error("Init_DoubleChooserWidget: couldn't init leftarrow!");
1968     	return NULL;
1969     }
1970 
1971     if (*(wid_info->value) <= wid_info->minval) ((ArrowWidget *)(wid_info->leftarrow->wid_info))->locked = true;
1972 
1973     if ( !AppendGLWidgetList(&(tmp->children),(wid_info->rightarrow = Init_ArrowWidget(RIGHTARROW,buttonsize,buttonsize,DoubleChooserWidget_Add,tmp))) ) {
1974     	Close_Widget(&tmp);
1975     	error("Init_DoubleChooserWidget: couldn't init rightarrow!");
1976     	return NULL;
1977     }
1978 
1979     if (*(wid_info->value) >= wid_info->maxval) ((ArrowWidget *)(wid_info->rightarrow->wid_info))->locked = true;
1980 
1981     tmp->bounds.w   = 2/*|_text*/+ wid_info->name->bounds.w +5/*text___<*/ + valuespace/*__value*/ + 2/*<_value_>*/
1982     	    	    + wid_info->leftarrow->bounds.w + wid_info->rightarrow->bounds.w +2/*>_|*/;
1983     tmp->bounds.h   = wid_info->name->bounds.h;
1984 
1985     return tmp;
1986 }
1987 /****************************/
1988 /* End: DoubleChooserWidget */
1989 /****************************/
1990 
1991 /*****************************/
1992 /* Begin: ColorChooserWidget */
1993 /*****************************/
1994 static void Paint_ColorChooserWidget( GLWidget *widget );
1995 static void SetBounds_ColorChooserWidget( GLWidget *widget, SDL_Rect *b );
1996 static void action_ColorChooserWidget(void *data);
1997 
SetBounds_ColorChooserWidget(GLWidget * widget,SDL_Rect * b)1998 static void SetBounds_ColorChooserWidget( GLWidget *widget, SDL_Rect *b )
1999 {
2000     ColorChooserWidget *wid_info;
2001     GLWidget *name,*button,*m;
2002     SDL_Rect b2;
2003 
2004     if (!widget) return;
2005     if (!b) return;
2006     if (widget->WIDGET !=COLORCHOOSERWIDGET) {
2007     	error("Wrong widget type for SetBounds_ColorChooserWidget [%i]",widget->WIDGET);
2008 	return;
2009     }
2010     if (!(wid_info = (ColorChooserWidget *)(widget->wid_info) )) {
2011     	error("SetBounds_ColorChooserWidget: wid_info missing");
2012 	return;
2013     }
2014 
2015     name = ((ColorChooserWidget *)(widget->wid_info))->name;
2016     button = ((ColorChooserWidget *)(widget->wid_info))->button;
2017     m = ((ColorChooserWidget *)(widget->wid_info))->mod;
2018 
2019     widget->bounds.x = b->x;
2020     widget->bounds.y = b->y;
2021     widget->bounds.w = b->w;
2022     widget->bounds.h = b->h;
2023 
2024     b2.h = name->bounds.h;
2025     b2.w = name->bounds.w;
2026     b2.x = widget->bounds.x + 2;
2027     b2.y = widget->bounds.y;
2028 
2029     SetBounds_GLWidget(name,&b2);
2030 
2031     b2.h = name->bounds.h - 4;
2032     b2.w = b2.h;
2033     b2.x = widget->bounds.x + widget->bounds.w - 2 - b2.w;
2034     b2.y = widget->bounds.y + 2;
2035 
2036     SetBounds_GLWidget(button,&b2);
2037 
2038     if (wid_info->expanded && m) {
2039 
2040     	b2.h = m->bounds.h;
2041     	b2.w = widget->bounds.w;
2042     	b2.x = widget->bounds.x;
2043     	b2.y = widget->bounds.y + name->bounds.h;
2044 
2045     	SetBounds_GLWidget(m,&b2);
2046    }
2047 }
2048 
Paint_ColorChooserWidget(GLWidget * widget)2049 static void Paint_ColorChooserWidget( GLWidget *widget )
2050 {
2051     ColorChooserWidget *wid_info;
2052 
2053     if (!widget) {
2054     	error("Paint_ColorChooserWidget: argument is NULL!");
2055 	return;
2056     }
2057 
2058     wid_info = (ColorChooserWidget *)(widget->wid_info);
2059 
2060     if (!wid_info) {
2061     	error("Paint_ColorChooserWidget: wid_info missing");
2062 	return;
2063     }
2064 
2065     if ( (wid_info->bgcolor) && *(wid_info->bgcolor) ) {
2066     	set_alphacolor(*(wid_info->bgcolor));
2067     	glBegin(GL_QUADS);
2068     	    glVertex2i(widget->bounds.x 	    	    ,widget->bounds.y	    	    	);
2069     	    glVertex2i(widget->bounds.x+widget->bounds.w    ,widget->bounds.y	    	    	);
2070     	    glVertex2i(widget->bounds.x+widget->bounds.w    ,widget->bounds.y+widget->bounds.h	);
2071     	    glVertex2i(widget->bounds.x 	    	    ,widget->bounds.y+widget->bounds.h	);
2072     	glEnd();
2073     }
2074     set_alphacolor(blackRGBA);
2075     glBegin(GL_TRIANGLES);
2076     	glVertex2i(wid_info->button->bounds.x ,wid_info->button->bounds.y);
2077     	glVertex2i(wid_info->button->bounds.x ,wid_info->button->bounds.y + wid_info->button->bounds.h);
2078     	glVertex2i(wid_info->button->bounds.x +wid_info->button->bounds.w ,wid_info->button->bounds.y + wid_info->button->bounds.h);
2079     glEnd();
2080 }
2081 
action_ColorChooserWidget(void * data)2082 static void action_ColorChooserWidget(void *data)
2083 {
2084     ColorChooserWidget *wid_info;
2085     GLWidget *widget;
2086 
2087     if (!(widget = (GLWidget *)data)) {
2088     	error("action_ColorChooserWidget: argument is NULL!");
2089 	return;
2090     }
2091 
2092     if (widget->WIDGET != COLORCHOOSERWIDGET) {
2093     	error("action_ColorChooserWidget: wrong type widget!");
2094 	return;
2095     }
2096 
2097     wid_info = (ColorChooserWidget *)(widget->wid_info);
2098 
2099     if (!wid_info) {
2100     	error("action_ColorChooserWidget: wid_info missing");
2101 	return;
2102     }
2103 
2104     if (wid_info->expanded) {
2105     	if (wid_info->mod) {
2106     	    DelGLWidgetListItem(&(widget->children),wid_info->mod);
2107 	    widget->bounds.h -= wid_info->mod->bounds.h;
2108     	    Close_Widget(&(wid_info->mod));
2109     	} else error("action_ColorChooserWidget: Color mod widget mysteriously missing!");
2110 	wid_info->expanded = false;
2111     } else {
2112     	if (!(wid_info->mod)) {
2113 	    wid_info->mod = Init_ColorModWidget(wid_info->value,wid_info->fgcolor,&nullRGBA,wid_info->callback,wid_info->data);
2114     	    if (!(wid_info->mod)) {
2115 	    	error("action_ColorChooserWidget: Failed to Init_ColorModWidget!");
2116 	    }
2117 	    widget->bounds.h += wid_info->mod->bounds.h;
2118 	    AppendGLWidgetList(&(widget->children),wid_info->mod);
2119     	} else error("action_ColorChooserWidget: Color mod widget mysteriously present!");
2120 	wid_info->expanded = true;
2121     }
2122 
2123     confmenu_callback();
2124 }
2125 
Init_ColorChooserWidget(const char * name,Uint32 * value,Uint32 * fgcolor,Uint32 * bgcolor,void (* callback)(void * tmp,const char * value),void * data)2126 GLWidget *Init_ColorChooserWidget( const char *name, Uint32 *value, Uint32 *fgcolor, Uint32 *bgcolor,
2127     	    	    	    	    void (*callback)(void *tmp, const char *value), void *data )
2128 {
2129     GLWidget *tmp;
2130     ColorChooserWidget *wid_info;
2131 
2132     if (!value) {
2133     	error("Faulty parameter to Init_ColorChooserWidget: value is a NULL pointer!");
2134 	return NULL;
2135     }
2136     if (!(name) || !strlen(name) ) {
2137     	error("name misssing for Init_ColorChooserWidget.");
2138 	return NULL;
2139     }
2140 
2141     tmp = Init_EmptyBaseGLWidget();
2142     if ( !tmp ) {
2143         error("Failed to malloc in Init_ColorChooserWidget.");
2144 	return NULL;
2145     }
2146     tmp->wid_info = XMALLOC(ColorChooserWidget, 1);
2147     if ( !(tmp->wid_info) ) {
2148     	free(tmp);
2149         error("Failed to malloc in Init_ColorChooserWidget.");
2150 	return NULL;
2151     }
2152 
2153     wid_info = (ColorChooserWidget *)tmp->wid_info;
2154 
2155     tmp->WIDGET     	= COLORCHOOSERWIDGET;
2156     tmp->Draw	    	= Paint_ColorChooserWidget;
2157     tmp->SetBounds  	= SetBounds_ColorChooserWidget;
2158     wid_info->value   	= value;
2159     wid_info->fgcolor 	= fgcolor;
2160     wid_info->bgcolor 	= bgcolor;
2161     wid_info->callback 	= callback;
2162     wid_info->data 	= data;
2163     wid_info->expanded 	= false;
2164     wid_info->mod 	= NULL;
2165 
2166     if ( !AppendGLWidgetList(&(tmp->children),(wid_info->name = Init_LabelWidget(name,fgcolor,&nullRGBA,LEFT,CENTER))) ) {
2167     	Close_Widget(&tmp);
2168     	error("Init_ColorChooserWidget: Failed to initialize label [%s]",name);
2169 	return NULL;
2170     }
2171 
2172     wid_info->name->hover   	= hover_optionWidget;
2173     wid_info->name->hoverdata	= data;
2174 
2175     if ( !AppendGLWidgetList(&(tmp->children),(wid_info->button = Init_ButtonWidget( wid_info->value, &whiteRGBA, 1, action_ColorChooserWidget, tmp ))) ) {
2176     	Close_Widget(&tmp);
2177     	error("Init_ColorChooserWidget: Failed to initialize button");
2178 	return NULL;
2179     }
2180 
2181     tmp->bounds.w   = 2 + wid_info->name->bounds.w + 5 + wid_info->button->bounds.w + 2;
2182     tmp->bounds.h   = wid_info->name->bounds.h;
2183 
2184     return tmp;
2185 }
2186 /***************************/
2187 /* End: ColorChooserWidget */
2188 /***************************/
2189 
2190 /*****************************/
2191 /* Begin: ColorModWidget */
2192 /*****************************/
2193 static void Paint_ColorModWidget( GLWidget *widget );
2194 static void SetBounds_ColorModWidget( GLWidget *widget, SDL_Rect *b );
2195 static void Callback_ColorModWidget(void *tmp, const char *value);
2196 
SetBounds_ColorModWidget(GLWidget * widget,SDL_Rect * b)2197 static void SetBounds_ColorModWidget( GLWidget *widget, SDL_Rect *b )
2198 {
2199     ColorModWidget *wi;
2200     GLWidget *tmp2;
2201     SDL_Rect b2;
2202 
2203     if (!widget) return;
2204     if (!b) return;
2205     if (widget->WIDGET !=COLORMODWIDGET) {
2206     	error("Wrong widget type for SetBounds_ColorModWidget [%i]",widget->WIDGET);
2207 	return;
2208     }
2209 
2210     if ( !(wi=((ColorModWidget *)(widget->wid_info))) ) {
2211     	error("SetBounds_ColorModWidget: wid_info missing!");
2212 	return;
2213     }
2214 
2215     widget->bounds.x = b->x;
2216     widget->bounds.y = b->y;
2217     widget->bounds.w = b->w;
2218     widget->bounds.h = b->h;
2219 
2220     tmp2 = wi->redpick;
2221 
2222     b2.x = widget->bounds.x + 2;
2223     b2.y = widget->bounds.y;
2224     b2.h = tmp2->bounds.h;
2225     b2.w = tmp2->bounds.w;
2226 
2227     SetBounds_GLWidget(tmp2,&b2);
2228 
2229     tmp2 = wi->greenpick;
2230 
2231     b2.x = widget->bounds.x + 2;
2232     b2.y += b2.h;
2233     b2.h = tmp2->bounds.h;
2234     b2.w = tmp2->bounds.w;
2235 
2236     SetBounds_GLWidget(tmp2,&b2);
2237 
2238     tmp2 = wi->bluepick;
2239 
2240     b2.x = widget->bounds.x + 2;
2241     b2.y += b2.h;
2242     b2.h = tmp2->bounds.h;
2243     b2.w = tmp2->bounds.w;
2244 
2245     SetBounds_GLWidget(tmp2,&b2);
2246 
2247     tmp2 = wi->alphapick;
2248 
2249     b2.x = widget->bounds.x + 2;
2250     b2.y += b2.h;
2251     b2.h = tmp2->bounds.h;
2252     b2.w = tmp2->bounds.w;
2253 
2254     SetBounds_GLWidget(tmp2,&b2);
2255 }
2256 
Paint_ColorModWidget(GLWidget * widget)2257 static void Paint_ColorModWidget( GLWidget *widget )
2258 {
2259     ColorModWidget *wid_info;
2260     SDL_Rect b;
2261 
2262     if (!widget) {
2263     	error("Paint_ColorModWidget: argument is NULL!");
2264 	return;
2265     }
2266 
2267     if ( widget->WIDGET != COLORMODWIDGET ) {
2268     	error("Paint_ColorModWidget: widget is not a ColorModWidget!");
2269 	return;
2270     }
2271 
2272     wid_info = (ColorModWidget *)(widget->wid_info);
2273 
2274     if (!wid_info) {
2275     	error("Paint_ColorModWidget: wid_info missing");
2276 	return;
2277     }
2278 
2279     if ( (wid_info->bgcolor) && *(wid_info->bgcolor) ) {
2280     	b.x = widget->bounds.x;
2281     	b.y = widget->bounds.y;
2282     	b.w = widget->bounds.w;
2283     	b.h = widget->bounds.h;
2284     	set_alphacolor(*(wid_info->bgcolor));
2285     	glBegin(GL_QUADS);
2286     	    glVertex2i(b.x  	,b.y	    );
2287     	    glVertex2i(b.x+b.w	,b.y	    );
2288     	    glVertex2i(b.x+b.w	,b.y+b.h    );
2289     	    glVertex2i(b.x  	,b.y+b.h    );
2290     	glEnd();
2291     }
2292 
2293     b.x = wid_info->redpick->bounds.x + wid_info->redpick->bounds.w + 16;
2294     b.y = widget->bounds.y + 2;
2295     b.w = widget->bounds.x + widget->bounds.w - 2 - b.x;
2296     b.h = widget->bounds.y + widget->bounds.h - 2 - b.y;
2297 
2298     glBegin(GL_TRIANGLES);
2299     	set_alphacolor(blackRGBA);
2300     	glVertex2i(b.x	    ,b.y    	);
2301     	glVertex2i(b.x	    ,b.y+b.h    );
2302     	glVertex2i(b.x+b.w  ,b.y+b.h    );
2303     	set_alphacolor(whiteRGBA);
2304     	glVertex2i(b.x	    ,b.y    	);
2305     	glVertex2i(b.x+b.w  ,b.y+b.h    );
2306     	glVertex2i(b.x+b.w  ,b.y    	);
2307     glEnd();
2308 
2309     glBegin(GL_POLYGON);
2310     	set_alphacolor(whiteRGBA);
2311     	glVertex2i(b.x + (GLint)(0.9*b.w)   ,b.y + b.h	    	    );
2312     	glVertex2i(b.x + b.w	    	    ,b.y + b.h	    	    );
2313     	glVertex2i(b.x + b.w	    	    ,b.y + (GLint)(0.9*b.h) );
2314     	set_alphacolor(blackRGBA);
2315     	glVertex2i(b.x + (GLint)(0.1*b.w)   ,b.y    	    	    );
2316     	glVertex2i(b.x	    	    	    ,b.y    	    	    );
2317     	glVertex2i(b.x	    	    	    ,b.y + (GLint)(0.1*b.h) );
2318     glEnd();
2319 
2320     glBegin(GL_QUADS);
2321     	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2322     	set_alphacolor(*(wid_info->value));
2323     	glVertex2i(b.x + (GLint)(0.1*b.w)   ,b.y + (GLint)(0.1*b.h) );
2324     	glVertex2i(b.x + (GLint)(0.1*b.w)   ,b.y + (GLint)(0.9*b.h) );
2325     	glVertex2i(b.x + (GLint)(0.9*b.w)   ,b.y + (GLint)(0.9*b.h) );
2326     	glVertex2i(b.x + (GLint)(0.9*b.w)   ,b.y + (GLint)(0.1*b.h) );
2327     glEnd();
2328 }
2329 
Callback_ColorModWidget(void * tmp,const char * value)2330 static void Callback_ColorModWidget(void *tmp, const char *value)
2331 {
2332     GLWidget *widget;
2333     ColorModWidget *wid_info;
2334     char str[10];
2335 
2336     if (!(widget = (GLWidget *)tmp)) {
2337     	error("Callback_ColorModWidget: argument is NULL!");
2338 	return;
2339     }
2340 
2341     if ( widget->WIDGET != COLORMODWIDGET ) {
2342     	error("Callback_ColorModWidget: widget is not a ColorModWidget!");
2343 	return;
2344     }
2345 
2346     wid_info = (ColorModWidget *)(widget->wid_info);
2347 
2348     if (!wid_info) {
2349     	error("Callback_ColorModWidget: wid_info missing");
2350 	return;
2351     }
2352 
2353     *(wid_info->value) = ((wid_info->red)<<24) | ((wid_info->green)<<16)
2354     	    	    	 | ((wid_info->blue)<<8) | (wid_info->alpha);
2355 
2356     snprintf(str,10,"#%02X%02X%02X%02X",wid_info->red,wid_info->green,wid_info->blue,wid_info->alpha);
2357     str[9] = '\0';
2358 
2359     if (wid_info->callback) wid_info->callback(wid_info->data,str);
2360 }
2361 
Init_ColorModWidget(Uint32 * value,Uint32 * fgcolor,Uint32 * bgcolor,void (* callback)(void * tmp,const char * value),void * data)2362 GLWidget *Init_ColorModWidget( Uint32 *value, Uint32 *fgcolor, Uint32 *bgcolor,
2363     	    	    	    	    void (*callback)(void *tmp, const char *value), void *data )
2364 {
2365     GLWidget *tmp;
2366     ColorModWidget *wid_info;
2367     int maxwidth = 0;
2368 
2369     if (!value) {
2370     	error("Faulty parameter to Init_ColorModWidget: value is a NULL pointer!");
2371 	return NULL;
2372     }
2373     tmp = Init_EmptyBaseGLWidget();
2374     if ( !tmp ) {
2375         error("Failed to malloc in Init_ColorModWidget.");
2376 	return NULL;
2377     }
2378     tmp->wid_info   = XMALLOC(ColorModWidget, 1);
2379     if ( !(tmp->wid_info) ) {
2380     	free(tmp);
2381         error("Failed to malloc in Init_ColorModWidget.");
2382 	return NULL;
2383     }
2384 
2385     wid_info = (ColorModWidget *)tmp->wid_info;
2386 
2387     tmp->WIDGET     	= COLORMODWIDGET;
2388     tmp->Draw	    	= Paint_ColorModWidget;
2389     tmp->SetBounds  	= SetBounds_ColorModWidget;
2390     wid_info->value   	= value;
2391     wid_info->red   	= ((*value) >> 24) & 255;
2392     wid_info->green   	= ((*value) >> 16) & 255;
2393     wid_info->blue   	= ((*value) >> 8) & 255;
2394     wid_info->alpha   	= (*value) & 255;
2395     wid_info->fgcolor 	= fgcolor;
2396     wid_info->bgcolor 	= bgcolor;
2397     wid_info->callback 	= callback;
2398     wid_info->data 	= data;
2399 
2400     if ( !AppendGLWidgetList(&(tmp->children),(wid_info->redpick = Init_IntChooserWidget("Red",&(wid_info->red),0,255,fgcolor,&nullRGBA,Callback_ColorModWidget,tmp))) ) {
2401     	Close_Widget(&tmp);
2402     	error("Init_ColorModWidget: Failed to initialize label [%s]","Red");
2403 	return NULL;
2404     }
2405     if ( !AppendGLWidgetList(&(tmp->children),(wid_info->greenpick = Init_IntChooserWidget("Green",&(wid_info->green),0,255,fgcolor,&nullRGBA,Callback_ColorModWidget,tmp))) ) {
2406     	Close_Widget(&tmp);
2407     	error("Init_ColorModWidget: Failed to initialize label [%s]","Green");
2408 	return NULL;
2409     }
2410     if ( !AppendGLWidgetList(&(tmp->children),(wid_info->bluepick = Init_IntChooserWidget("Blue",&(wid_info->blue),0,255,fgcolor,&nullRGBA,Callback_ColorModWidget,tmp))) ) {
2411     	Close_Widget(&tmp);
2412     	error("Init_ColorModWidget: Failed to initialize label [%s]","Blue");
2413 	return NULL;
2414     }
2415     if ( !AppendGLWidgetList(&(tmp->children),(wid_info->alphapick = Init_IntChooserWidget("Alpha",&(wid_info->alpha),0,255,fgcolor,&nullRGBA,Callback_ColorModWidget,tmp))) ) {
2416     	Close_Widget(&tmp);
2417     	error("Init_ColorModWidget: Failed to initialize label [%s]","Alpha");
2418 	return NULL;
2419     }
2420 
2421     maxwidth = MAX(maxwidth,wid_info->redpick->bounds.w);
2422     maxwidth = MAX(maxwidth,wid_info->greenpick->bounds.w);
2423     maxwidth = MAX(maxwidth,wid_info->bluepick->bounds.w);
2424     maxwidth = MAX(maxwidth,wid_info->alphapick->bounds.w);
2425 
2426     wid_info->redpick->bounds.w = maxwidth;
2427     wid_info->greenpick->bounds.w = maxwidth;
2428     wid_info->bluepick->bounds.w = maxwidth;
2429     wid_info->alphapick->bounds.w = maxwidth;
2430 
2431     tmp->bounds.h   = wid_info->redpick->bounds.h
2432     	    	    + wid_info->greenpick->bounds.h
2433     	    	    + wid_info->bluepick->bounds.h
2434 		    + wid_info->alphapick->bounds.h;
2435     tmp->bounds.w   = 2 + maxwidth + 16 + tmp->bounds.h + 2;
2436 
2437     return tmp;
2438 }
2439 /***********************/
2440 /* End: ColorModWidget */
2441 /***********************/
2442 
2443 /**********************/
2444 /* Begin: ListWidget  */
2445 /**********************/
2446 static void SetBounds_ListWidget( GLWidget *widget, SDL_Rect *b );
2447 static void Paint_ListWidget( GLWidget *widget );
2448 
ListWidget_Append(GLWidget * list,GLWidget * item)2449 bool ListWidget_Append( GLWidget *list, GLWidget *item )
2450 {
2451     GLWidget *curr1, **curr2;
2452     ListWidget *wid_info;
2453 
2454     if (!list) {
2455     	error("ListWidget_Append: *list is NULL!");
2456 	return false;
2457     }
2458     if (list->WIDGET != LISTWIDGET) {
2459     	error("ListWidget_Append: list is not a LISTWIDGET! [%i]",list->WIDGET);
2460 	return false;
2461     }
2462     if (!(wid_info = (ListWidget *)list->wid_info)) {
2463     	error("ListWidget_Append: list->wid_info missing!");
2464 	return false;
2465     }
2466     if (!item) {
2467     	error("ListWidget_Append: *item is NULL");
2468 	return false;
2469     }
2470 
2471     curr1 = item;
2472     while (curr1) {
2473 	curr2 = &(list->children);
2474     	while (*curr2) {
2475 	    if (*curr2 == curr1) break;
2476 	    curr2 = &((*curr2)->next);
2477     	}
2478 
2479     	if (*curr2) {
2480 	    error("ListWidget_Append: Attempt to append an existing item!");
2481 	    break;
2482 	}
2483 
2484 	*curr2 = curr1;
2485 	curr1 = curr1->next;
2486 	/* disengage added item from the item list t be added */
2487 	(*curr2)->next = NULL;
2488 
2489      	++wid_info->num_elements;
2490     }
2491 
2492     /* This works since SetBounds_ListWidget copies the content
2493      * if the SDL_Rect *
2494      */
2495     SetBounds_ListWidget( list, &(list->bounds));
2496 
2497     return true;
2498 }
2499 
ListWidget_Prepend(GLWidget * list,GLWidget * item)2500 bool ListWidget_Prepend( GLWidget *list, GLWidget *item )
2501 {
2502     GLWidget *curr1, *curr2, **entry_pt, *first;
2503     ListWidget *wid_info;
2504     /*int y_rel;*/
2505 
2506     if (!list) {
2507     	error("ListWidget_Prepend: *list is NULL!");
2508 	return false;
2509     }
2510     if (list->WIDGET != LISTWIDGET) {
2511     	error("ListWidget_Prepend: list is not a LISTWIDGET! [%i]",list->WIDGET);
2512 	return false;
2513     }
2514     if (!(wid_info = (ListWidget *)list->wid_info)) {
2515     	error("ListWidget_Prepend: list->wid_info missing!");
2516 	return false;
2517     }
2518     if (!item) {
2519     	error("ListWidget_Prepend: *item is NULL");
2520 	return false;
2521     }
2522 
2523     entry_pt = &(list->children);
2524     first = *entry_pt;
2525 
2526     curr1 = item;
2527     while (curr1) {
2528     	curr2 = list->children;
2529     	while (curr2) {
2530 	    if (curr2 == item) break;
2531 	    curr2 = curr2->next;
2532     	}
2533 
2534 	if (curr2) {
2535 	    error("ListWidget_Append: Attempt to append an existing item!");
2536 	    break;
2537 	}
2538 
2539 	*entry_pt = curr1;
2540 	curr1 = curr1->next;
2541 	(*entry_pt)->next = first;
2542 	entry_pt = &((*entry_pt)->next);
2543 
2544     	++wid_info->num_elements;
2545     }
2546 
2547     /* This works since SetBounds_ListWidget copies the content
2548      * if the SDL_Rect *
2549      */
2550     SetBounds_ListWidget( list, &(list->bounds));
2551 
2552     return true;
2553 }
2554 
ListWidget_Insert(GLWidget * list,GLWidget * target,GLWidget * item)2555 bool ListWidget_Insert( GLWidget *list, GLWidget *target, GLWidget *item )
2556 {
2557     GLWidget **curr, *curr1, *curr2;
2558     ListWidget *wid_info;
2559 
2560     if (!list) {
2561     	error("ListWidget_Insert: *list is NULL!");
2562 	return false;
2563     }
2564     if (list->WIDGET != LISTWIDGET) {
2565     	error("ListWidget_Insert: list is not a LISTWIDGET! [%i]",list->WIDGET);
2566 	return false;
2567     }
2568     if (!(wid_info = (ListWidget *)list->wid_info)) {
2569     	error("ListWidget_Insert: list->wid_info missing!");
2570 	return false;
2571     }
2572     if (!item) {
2573     	error("ListWidget_Insert: *item is NULL");
2574 	return false;
2575     }
2576 
2577     curr = &(list->children);
2578     while (*curr) {
2579 	if (*curr == target) break;
2580 	curr = &((*curr)->next);
2581     }
2582 
2583     if (!(*curr)) {
2584 	    error("ListWidget_Insert: target is not in the list!");
2585 	    return false;
2586     }
2587 
2588     curr1 = item;
2589     while (curr1) {
2590     	curr2 = list->children;
2591     	while (curr2) {
2592 	    if (curr2 == item) break;
2593 	    curr2 = curr2->next;
2594     	}
2595 
2596 	if (curr2) {
2597 	    error("ListWidget_Append: Attempt to append an existing item!");
2598 	    break;
2599 	}
2600 
2601 	*curr = curr1;
2602 	curr1 = curr1->next;
2603 	(*curr)->next = target;
2604 	curr = &((*curr)->next);
2605 
2606     	++wid_info->num_elements;
2607     }
2608 
2609     /* This works since SetBounds_ListWidget copies the content
2610      * if the SDL_Rect *
2611      */
2612     SetBounds_ListWidget( list, &(list->bounds));
2613 
2614     return true;
2615 }
2616 
ListWidget_Remove(GLWidget * list,GLWidget * item)2617 bool ListWidget_Remove( GLWidget *list, GLWidget *item )
2618 {
2619     GLWidget **curr;
2620     ListWidget *wid_info;
2621 
2622     if (!list) {
2623     	error("ListWidget_Remove: *list is NULL!");
2624 	return false;
2625     }
2626     if (list->WIDGET != LISTWIDGET) {
2627     	error("ListWidget_Remove: list is not a LISTWIDGET! [%i]",list->WIDGET);
2628 	return false;
2629     }
2630     if (!(wid_info = (ListWidget *)list->wid_info)) {
2631     	error("ListWidget_Remove: list->wid_info missing!");
2632 	return false;
2633     }
2634     if (!item) {
2635     	error("ListWidget_Remove: *item is NULL");
2636 	return false;
2637     }
2638 
2639     curr = &(list->children);
2640     while (*curr) {
2641 	if (*curr == item) {
2642 	    break;
2643 	}
2644 	curr = &((*curr)->next);
2645     }
2646 
2647     if (!(*curr)) {
2648 	    error("ListWidget_Remove: item is not in the list!");
2649 	    return false;
2650     }
2651 
2652     *curr = (*curr)->next;
2653     item->next = NULL;
2654 
2655     --wid_info->num_elements;
2656 
2657     /* This works since SetBounds_ListWidget copies the content
2658      * if the SDL_Rect *
2659      */
2660     SetBounds_ListWidget( list, &(list->bounds));
2661 
2662     return true;
2663 }
2664 
ListWidget_SetScrollorder(GLWidget * list,bool order)2665 bool ListWidget_SetScrollorder( GLWidget *list, bool order )
2666 {
2667     /*GLWidget **curr;*/
2668     ListWidget *wid_info;
2669 
2670     if (!list) {
2671     	error("ListWidget_SetScrollorder: *list is NULL!");
2672 	return false;
2673     }
2674     if (list->WIDGET != LISTWIDGET) {
2675     	error("ListWidget_SetScrollorder: list is not a LISTWIDGET! [%i]",list->WIDGET);
2676 	return false;
2677     }
2678     if (!(wid_info = (ListWidget *)list->wid_info)) {
2679     	error("ListWidget_SetScrollorder: list->wid_info missing!");
2680 	return false;
2681     }
2682 
2683     wid_info->reverse_scroll = order;
2684 
2685     /* This works since SetBounds_ListWidget copies the content
2686      * if the SDL_Rect *
2687      */
2688     SetBounds_ListWidget( list, &(list->bounds));
2689 
2690     return true;
2691 }
2692 
ListWidget_NELEM(GLWidget * list)2693 int ListWidget_NELEM( GLWidget *list )
2694 {
2695     ListWidget *wid_info;
2696 
2697     if (!list) {
2698     	error("ListWidget_NELEM: *list is NULL!");
2699 	return -1;
2700     }
2701     if (list->WIDGET != LISTWIDGET) {
2702     	error("ListWidget_NELEM: list is not a LISTWIDGET! [%i]",list->WIDGET);
2703 	return -1;
2704     }
2705     if (!(wid_info = (ListWidget *)list->wid_info)) {
2706     	error("ListWidget_Remove: list->wid_info missing!");
2707 	return -1;
2708     }
2709 
2710     return wid_info->num_elements;
2711 }
2712 
ListWidget_GetItemByIndex(GLWidget * list,int i)2713 GLWidget *ListWidget_GetItemByIndex( GLWidget *list, int i )
2714 {
2715     GLWidget *curr;
2716     ListWidget *wid_info;
2717     int j;
2718 
2719     if (!list) {
2720     	error("ListWidget_NELEM: *list is NULL!");
2721 	return NULL;
2722     }
2723     if (list->WIDGET != LISTWIDGET) {
2724     	error("ListWidget_NELEM: list is not a LISTWIDGET! [%i]",list->WIDGET);
2725 	return NULL;
2726     }
2727     if (!(wid_info = (ListWidget *)list->wid_info)) {
2728     	error("ListWidget_Remove: list->wid_info missing!");
2729 	return NULL;
2730     }
2731 
2732     if ( i > ( wid_info->num_elements - 1) ) return NULL;
2733 
2734     curr = list->children;
2735     j = 0;
2736     while (curr && (j<i)) {
2737 	curr = curr->next;
2738     	++j;
2739     }
2740 
2741     if ( j != i ) return NULL;
2742 
2743     return curr;
2744 }
2745 
2746 
Paint_ListWidget(GLWidget * widget)2747 static void Paint_ListWidget( GLWidget *widget )
2748 {
2749     ListWidget *wid_info;
2750     GLWidget *curr;
2751     int count = 0;
2752     Uint32  *col;
2753 
2754     if (!widget) return;
2755 
2756     wid_info = (ListWidget *)(widget->wid_info);
2757 
2758     glBegin(GL_QUADS);
2759 
2760     curr = widget->children;
2761     while (curr) {
2762     	if (count % 2) col = wid_info->bg2;
2763     	else col = wid_info->bg1;
2764 
2765 	++count;
2766 
2767     	if (*col) {
2768     	    set_alphacolor(*col);
2769 
2770     	    glVertex2i(curr->bounds.x	    	    	,curr->bounds.y	    	    	);
2771     	    glVertex2i(curr->bounds.x+widget->bounds.w	,curr->bounds.y	    	    	);
2772     	    glVertex2i(curr->bounds.x+widget->bounds.w	,curr->bounds.y+curr->bounds.h	);
2773     	    glVertex2i(curr->bounds.x 	    	    	,curr->bounds.y+curr->bounds.h	);
2774     	}
2775     	curr = curr->next;
2776     }
2777 
2778     glEnd();
2779 }
2780 
2781 /* This setbounds method has very special behaviour; basically
2782  * only one corner of the bounding box is regarded, this is
2783  * because the list is an expanding/contracting entity, and
2784  * thus the others might soon get overridden anyway.
2785  * The only way to properly bound a ListWidget is to make a
2786  * bounding widget adopt it. (i.e. a scrollpane)
2787  */
SetBounds_ListWidget(GLWidget * widget,SDL_Rect * b)2788 static void SetBounds_ListWidget( GLWidget *widget, SDL_Rect *b )
2789 {
2790     ListWidget *tmp;
2791     SDL_Rect bounds,b2;
2792     GLWidget *curr;
2793 
2794     if (!widget) return;
2795     if (!b) return;
2796     if (widget->WIDGET !=LISTWIDGET) {
2797     	error("Wrong widget type for SetBounds_ListWidget [%i]",widget->WIDGET);
2798 	return;
2799     }
2800 
2801     if (!(tmp = (ListWidget *)(widget->wid_info))) {
2802     	error("SetBounds_ListWidget: wid_info missing!");
2803 	return;
2804     }
2805 
2806     bounds.y = b->y;
2807     bounds.x = b->x;
2808     bounds.w = 0;
2809     bounds.h = 0;
2810     curr = widget->children;
2811     while(curr) {
2812     	if (tmp->direction == VERTICAL) {
2813     	    bounds.w = MAX(bounds.w,curr->bounds.w);
2814 	    bounds.h += curr->bounds.h;
2815 	} else {
2816     	    bounds.w += curr->bounds.w;
2817 	    bounds.h = MAX(bounds.h,curr->bounds.h);
2818 	}
2819 	curr = curr->next;
2820     }
2821 
2822     if (tmp->v_dir == LW_UP) {
2823     	bounds.y += b->h - bounds.h;
2824     }
2825     if (tmp->v_dir == LW_VCENTER) {
2826     	bounds.y += (b->h - bounds.h)/2;
2827     }
2828     if (tmp->h_dir == LW_LEFT) {
2829     	bounds.x += b->w - bounds.w;
2830     }
2831     if (tmp->h_dir == LW_HCENTER) {
2832     	bounds.x += (b->w - bounds.w)/2;
2833     }
2834 
2835     widget->bounds.y = bounds.y;
2836     widget->bounds.h = bounds.h;
2837     widget->bounds.x = bounds.x;
2838     widget->bounds.w = bounds.w;
2839 
2840     curr = widget->children;
2841     while(curr) {
2842     	if (tmp->direction == VERTICAL) {
2843     	    bounds.h -= curr->bounds.h;
2844 
2845 	    b2.y = bounds.y;
2846 	    if (tmp->reverse_scroll) {
2847     	    	b2.y += bounds.h;
2848     	    } else {
2849 	    	bounds.y += curr->bounds.h;
2850 	    }
2851 
2852     	    b2.x = bounds.x;
2853 	    if (tmp->h_dir == LW_LEFT) {
2854 	    	b2.x += bounds.w - curr->bounds.w;
2855 	    }
2856 
2857 	    b2.h = curr->bounds.h;
2858 	    b2.w = widget->bounds.w;
2859 	    /*b2.w = curr->bounds.w;*/ /*TODO: make this optional*/
2860 	} else {
2861     	    bounds.w -= curr->bounds.w;
2862 
2863 	    b2.x = bounds.x;
2864 	    if (tmp->reverse_scroll) {
2865     	    	b2.x += bounds.w;
2866     	    } else {
2867 	    	bounds.x += curr->bounds.w;
2868 	    }
2869 
2870     	    b2.y = bounds.y;
2871 	    if (tmp->v_dir == LW_UP) {
2872 	    	b2.y += bounds.h - curr->bounds.h;
2873 	    }
2874 
2875 	    b2.w = curr->bounds.w;
2876 	    b2.h = widget->bounds.h;
2877 	    /*b2.w = curr->bounds.w;*/ /*TODO: make this optional*/
2878 	}
2879 
2880 	SetBounds_GLWidget( curr, &b2 );
2881 
2882     	curr = curr->next;
2883     }
2884 }
2885 
Init_ListWidget(Uint16 x,Uint16 y,Uint32 * bg1,Uint32 * bg2,Uint32 * highlight_color,ListWidget_ver_dir_t v_dir,ListWidget_hor_dir_t h_dir,ListWidget_direction direction,bool reverse_scroll)2886 GLWidget *Init_ListWidget( Uint16 x, Uint16 y, Uint32 *bg1, Uint32 *bg2, Uint32 *highlight_color
2887     	    	    	    ,ListWidget_ver_dir_t v_dir, ListWidget_hor_dir_t h_dir
2888 			    ,ListWidget_direction direction, bool reverse_scroll )
2889 {
2890     GLWidget *tmp;
2891     ListWidget *wid_info;
2892 
2893     tmp	= Init_EmptyBaseGLWidget();
2894     if ( !tmp ) {
2895         error("Failed to malloc GLWidget in Init_ListWidget");
2896 	return NULL;
2897     }
2898     tmp->wid_info   	= malloc(sizeof(ListWidget));
2899     if ( !(tmp->wid_info) ) {
2900     	free(tmp);
2901         error("Failed to malloc MainWidget in Init_ListWidget");
2902 	return NULL;
2903     }
2904     wid_info = ((ListWidget *)tmp->wid_info);
2905     wid_info->num_elements = 0;
2906     wid_info->bg1	= bg1;
2907     wid_info->bg2	= bg2;
2908     wid_info->highlight_color	= highlight_color;
2909     wid_info->reverse_scroll	= reverse_scroll;
2910     wid_info->direction	= direction;
2911     wid_info->v_dir	= v_dir;
2912     wid_info->h_dir	= h_dir;
2913 
2914     tmp->WIDGET     	= LISTWIDGET;
2915     tmp->bounds.x   	= x;
2916     tmp->bounds.y   	= y;
2917     tmp->bounds.w   	= 0;
2918     tmp->bounds.h   	= 0;
2919     tmp->SetBounds  	= SetBounds_ListWidget;
2920     tmp->Draw	    	= Paint_ListWidget;
2921 
2922     return tmp;
2923 }
2924 
2925 /*******************/
2926 /* End: ListWidget */
2927 /*******************/
2928 
2929 /****************************/
2930 /* Begin: ScrollPaneWidget  */
2931 /****************************/
2932 static void ScrollPaneWidget_poschange( GLfloat pos , void *data );
2933 static void SetBounds_ScrollPaneWidget( GLWidget *widget, SDL_Rect *b );
2934 
ScrollPaneWidget_poschange(GLfloat pos,void * data)2935 static void ScrollPaneWidget_poschange( GLfloat pos , void *data )
2936 {
2937     GLWidget *widget;
2938     GLWidget *masque;
2939     ScrollPaneWidget *wid_info;
2940     SDL_Rect bounds;
2941     GLWidget *vert_scroller;
2942     GLWidget *hori_scroller;
2943     /*GLWidget *curr;*/
2944 
2945     if ( !data ) {
2946         error("NULL data to ScrollPaneWidget_poschange!");
2947 	return;
2948     }
2949     widget = (GLWidget *)data;
2950     wid_info = ((ScrollPaneWidget *)(widget->wid_info));
2951     masque = wid_info->masque;
2952     if (!masque) {
2953     	error("ScrollPaneWidget_poschange: masque missing!");
2954 	return;
2955     }
2956     vert_scroller = wid_info->vert_scroller;
2957     hori_scroller = wid_info->hori_scroller;
2958 
2959     if (wid_info->content) {
2960     	bounds.x = masque->bounds.x;
2961     	if (hori_scroller) {
2962 	    if (!hori_scroller->wid_info) {
2963     	    	error("ScrollPaneWidget_poschange: hori_scroller wid_info missing!");
2964 	    	return;
2965 	    }
2966     	    bounds.x -= (Sint16)((((ScrollbarWidget *)(hori_scroller->wid_info))->pos)*(wid_info->content->bounds.w));
2967 	}
2968     	bounds.w = wid_info->content->bounds.w;
2969     	bounds.y = masque->bounds.y;
2970     	if (vert_scroller) {
2971 	    if (!vert_scroller->wid_info) {
2972     	    	error("ScrollPaneWidget_poschange: vert_scroller wid_info missing!");
2973 	    	return;
2974 	    }
2975     	    bounds.y -= (Sint16)((((ScrollbarWidget *)(vert_scroller->wid_info))->pos)*(wid_info->content->bounds.h));
2976 	}
2977     	bounds.h = wid_info->content->bounds.h;
2978     	SetBounds_GLWidget(wid_info->content,&bounds);
2979     }
2980 }
2981 
SetBounds_ScrollPaneWidget(GLWidget * widget,SDL_Rect * b)2982 static void SetBounds_ScrollPaneWidget(GLWidget *widget, SDL_Rect *b )
2983 {
2984     ScrollPaneWidget *wid_info;
2985     SDL_Rect bounds;
2986     GLfloat pos;
2987     int i;
2988 
2989     if (!widget) return;
2990     if (!b) return;
2991     if (widget->WIDGET != SCROLLPANEWIDGET) {
2992     	error("Wrong widget type for SetBounds_ScrollPaneWidget [%i]",widget->WIDGET);
2993 	return;
2994     }
2995 
2996     if (!(wid_info = (ScrollPaneWidget *)(widget->wid_info))) {
2997     	error("SetBounds_ScrollPaneWidget: wid_info missing!");
2998 	return;
2999     }
3000 
3001     widget->bounds.x = b->x;
3002     widget->bounds.w = b->w;
3003     widget->bounds.y = b->y;
3004     widget->bounds.h = b->h;
3005 
3006     if (!wid_info->masque) {
3007     	error("SetBounds_ScrollPaneWidget: masque missing!");
3008 	return;
3009     }
3010 
3011     if (!wid_info->content) {
3012     	if (wid_info->vert_scroller) {
3013     	    Close_Widget(&(wid_info->vert_scroller));
3014     	}
3015     	if (wid_info->hori_scroller) {
3016     	    Close_Widget(&(wid_info->hori_scroller));
3017     	}
3018     	return;
3019     }
3020 
3021     for ( i = 0 ; i < 2 ; ++i ) {
3022     	if  (
3023 	    (	(wid_info->vert_scroller) &&
3024 	    	(widget->bounds.w - wid_info->vert_scroller->bounds.w < wid_info->content->bounds.w))
3025 	    || (widget->bounds.w < wid_info->content->bounds.w)
3026 	    ) {
3027     	    if (!wid_info->hori_scroller) {
3028     	    	if  ( !AppendGLWidgetList(&(widget->children),
3029     	    	    	(wid_info->hori_scroller = Init_ScrollbarWidget(false,0.0f,1.0f,SB_HORISONTAL
3030 	    	    	    	    	    	    ,ScrollPaneWidget_poschange,widget)))
3031 		    ) {
3032 	    	    error("SetBounds_ScrollPaneWidget: Failed to init horisontal scroller!");
3033     	    	    return;
3034     	    	}
3035 	    }
3036     	} else {
3037     	    if (wid_info->hori_scroller) {
3038 	    	Close_Widget(&(wid_info->hori_scroller));
3039 	    }
3040     	}
3041 
3042     	if  (
3043 	    (	(wid_info->hori_scroller) &&
3044 	    	(widget->bounds.h - wid_info->hori_scroller->bounds.h < wid_info->content->bounds.h))
3045 	    || (widget->bounds.h < wid_info->content->bounds.h)
3046 	    ) {
3047     	    if (!wid_info->vert_scroller) {
3048     	    	if  ( !AppendGLWidgetList(&(widget->children),
3049     	    	    	(wid_info->vert_scroller = Init_ScrollbarWidget(false,0.0f,1.0f,SB_VERTICAL
3050 	    	    	    	    	    	    ,ScrollPaneWidget_poschange,widget)))
3051 		    ) {
3052 	    	    error("SetBounds_ScrollPaneWidget: Failed to init vertical scroller!");
3053     	    	    return;
3054     	    	}
3055 	    }
3056     	} else {
3057     	    if (wid_info->vert_scroller) {
3058 	    	Close_Widget(&(wid_info->vert_scroller));
3059 	    }
3060     	}
3061     }
3062 
3063     if (wid_info->vert_scroller) {
3064     	bounds.x = widget->bounds.x + widget->bounds.w - wid_info->vert_scroller->bounds.w;
3065     	bounds.w = wid_info->vert_scroller->bounds.w;
3066     	bounds.y = widget->bounds.y;
3067     	bounds.h = widget->bounds.h;
3068     	if (wid_info->hori_scroller)
3069     	    bounds.h -= wid_info->hori_scroller->bounds.h;
3070 
3071     	SetBounds_GLWidget(wid_info->vert_scroller,&bounds);
3072     }
3073 
3074     if (wid_info->hori_scroller) {
3075      	bounds.x = widget->bounds.x;
3076     	bounds.w = widget->bounds.w;
3077     	if (wid_info->vert_scroller)
3078     	    bounds.w -= wid_info->vert_scroller->bounds.w;
3079     	bounds.y = widget->bounds.y + widget->bounds.h - wid_info->hori_scroller->bounds.h;
3080     	bounds.h = wid_info->hori_scroller->bounds.h;
3081 
3082     	SetBounds_GLWidget(wid_info->hori_scroller,&bounds);
3083     }
3084 
3085     /* we already made sure masque exists! */
3086     bounds.x = widget->bounds.x;
3087     bounds.w = widget->bounds.w;
3088     if (wid_info->vert_scroller)
3089     	bounds.w -= wid_info->vert_scroller->bounds.w;
3090     bounds.y = widget->bounds.y;
3091     bounds.h = widget->bounds.h;
3092     if (wid_info->hori_scroller)
3093     	bounds.h -= wid_info->hori_scroller->bounds.h;
3094 
3095     SetBounds_GLWidget(wid_info->masque,&bounds);
3096 
3097     if (wid_info->content) {
3098     	if (wid_info->hori_scroller) {
3099 	    bounds.w = wid_info->content->bounds.w;
3100 	} else {
3101 	    bounds.w = wid_info->masque->bounds.w;
3102 	}
3103     	if (wid_info->vert_scroller) {
3104 	    bounds.h = wid_info->content->bounds.h;
3105 	} else {
3106 	    bounds.h = wid_info->masque->bounds.h;
3107 	}
3108 
3109 	if (wid_info->hori_scroller) {
3110 	    ScrollbarWidget_SetSlideSize(wid_info->hori_scroller,MIN(((GLfloat)wid_info->masque->bounds.w)/((GLfloat)bounds.w),1.0f));
3111     	    pos = MIN( ((ScrollbarWidget *)(wid_info->hori_scroller->wid_info))->pos, 1.0f - ((ScrollbarWidget *)(wid_info->hori_scroller->wid_info))->size);
3112     	    bounds.x = (Sint16)(wid_info->masque->bounds.x - pos*(wid_info->content->bounds.x));
3113 	} else {
3114 	    bounds.x = wid_info->masque->bounds.x;
3115 	}
3116 
3117 	if (wid_info->vert_scroller) {
3118 	    ScrollbarWidget_SetSlideSize(wid_info->vert_scroller,MIN(((GLfloat)wid_info->masque->bounds.h)/((GLfloat)bounds.h),1.0f));
3119     	    pos = MIN( ((ScrollbarWidget *)(wid_info->vert_scroller->wid_info))->pos, 1.0f - ((ScrollbarWidget *)(wid_info->vert_scroller->wid_info))->size);
3120     	    bounds.y = (Sint16)(wid_info->masque->bounds.y - pos*(wid_info->content->bounds.h));
3121 	} else {
3122 	    bounds.y = wid_info->masque->bounds.y;
3123 	}
3124 
3125     	SetBounds_GLWidget(wid_info->content,&bounds);
3126     }
3127 }
3128 
Init_ScrollPaneWidget(GLWidget * content)3129 GLWidget *Init_ScrollPaneWidget( GLWidget *content )
3130 {
3131     GLWidget *tmp;
3132     ScrollPaneWidget *wid_info;
3133     /*SDL_Rect b;*/
3134 
3135     tmp	= Init_EmptyBaseGLWidget();
3136     if ( !tmp ) {
3137         error("Failed to malloc GLWidget in Init_ScrollPaneWidget");
3138 	return NULL;
3139     }
3140     tmp->wid_info   	= malloc(sizeof(ScrollPaneWidget));
3141     if ( !(tmp->wid_info) ) {
3142     	free(tmp);
3143         error("Failed to malloc MainWidget in Init_ScrollPaneWidget");
3144 	return NULL;
3145     }
3146     wid_info = ((ScrollPaneWidget *)tmp->wid_info);
3147     wid_info->content	= content;
3148     wid_info->hori_scroller = NULL;
3149     wid_info->vert_scroller = NULL;
3150 
3151     tmp->WIDGET     	= SCROLLPANEWIDGET;
3152     tmp->bounds.x   	= 0;
3153     tmp->bounds.y   	= 0;
3154     tmp->bounds.w   	= 0;
3155     tmp->bounds.h   	= 0;
3156     tmp->SetBounds  	= SetBounds_ScrollPaneWidget;
3157 
3158     if ( !AppendGLWidgetList(&(tmp->children),(wid_info->masque = Init_EmptyBaseGLWidget()))
3159     	) {
3160 	error("Init_ScrollPaneWidget: Failed to init masque!");
3161 	Close_Widget(&tmp);
3162     	return NULL;
3163     }
3164 
3165     if (wid_info->content) {
3166     	if ( !AppendGLWidgetList(&(wid_info->masque->children),wid_info->content) ) {
3167 	    error("Init_ScrollPaneWidget: Failed to adopt the content to the masque!");
3168     	    /*Close_Widget(&(wid_info->scroller));*/
3169 	    Close_Widget(&tmp);
3170     	    return NULL;
3171     	}
3172 
3173         tmp->bounds.w = wid_info->content->bounds.w;
3174         tmp->bounds.h = wid_info->content->bounds.h;
3175     }
3176 
3177     /*tmp->bounds.w += wid_info->scroller->bounds.w;*/
3178 
3179     return tmp;
3180 }
3181 
3182 /**************************/
3183 /* End: ScrollPaneWidget  */
3184 /**************************/
3185 
3186 /**********************/
3187 /* Begin: MainWidget  */
3188 /**********************/
3189 static void SetBounds_MainWidget( GLWidget *widget, SDL_Rect *b );
3190 static void button_MainWidget( Uint8 button, Uint8 state , Uint16 x , Uint16 y, void *data );
3191 static void Close_MainWidget( GLWidget *widget );
3192 
MainWidget_ShowMenu(GLWidget * widget,bool show)3193 void MainWidget_ShowMenu( GLWidget *widget, bool show )
3194 {
3195     WrapperWidget *wid_info;
3196 
3197     if (!widget) {
3198     	error("MainWidget_ShowMenu: widget missing!");
3199 	return;
3200     }
3201     if (widget->WIDGET != MAINWIDGET) {
3202     	error("Wrong widget type for MainWidget_ShowMenu [%i]",widget->WIDGET);
3203 	return;
3204     }
3205     if (!(wid_info = (WrapperWidget *)(widget->wid_info)) ) {
3206     	error("MainWidget_ShowMenu: wid_info missing!");
3207 	return;
3208     }
3209 
3210     if (wid_info->showconf == show) return;
3211 
3212     wid_info->showconf = show;
3213     if (show) {
3214     	AppendGLWidgetList(&(widget->children), wid_info->confmenu);
3215     } else {
3216     	DelGLWidgetListItem(&(widget->children), wid_info->confmenu);
3217 	if (hovertarget)
3218 	    hover_optionWidget( 0, 0 , 0 , NULL );
3219     }
3220 }
3221 
SetBounds_MainWidget(GLWidget * widget,SDL_Rect * b)3222 static void SetBounds_MainWidget( GLWidget *widget, SDL_Rect *b )
3223 {
3224     WrapperWidget *wid_info;
3225     SDL_Rect bs = {0,0,0,0},*bw;
3226     GLWidget *subs[5];
3227     int i,diff;
3228     bool change;
3229 
3230     if (!widget) return;
3231     if (!b) return;
3232     if (widget->WIDGET != MAINWIDGET) {
3233     	error("Wrong widget type for SetBounds_MainWidget [%i]",widget->WIDGET);
3234 	return;
3235     }
3236 
3237     if (!(wid_info = (WrapperWidget *)(widget->wid_info))) {
3238     	error("SetBounds_MainWidget: wid_info missing!");
3239 	return;
3240     }
3241 
3242     subs[0] = wid_info->radar;
3243     subs[1] = wid_info->scorelist;
3244     subs[2] = wid_info->chat_msgs;
3245     subs[3] = wid_info->game_msgs;
3246     subs[4] = wid_info->confmenu;
3247 
3248     bw = &(widget->bounds);
3249 
3250     for ( i=0; i < 5 ; ++i) {
3251     	if (subs[i]) {
3252 	    change = false;
3253 
3254     	    bs.x = subs[i]->bounds.x;
3255     	    bs.w = subs[i]->bounds.w;
3256     	    bs.y = subs[i]->bounds.y;
3257     	    bs.h = subs[i]->bounds.h;
3258 
3259 	    if ( ABS(bs.x - bw->x) > ABS( diff = (bw->x+bw->w) - (bs.x+bs.w) ) ) {
3260 	    	bs.x = b->x + b->w - diff - bs.w;
3261 		change = true;
3262 	    }
3263 
3264 	    if ( ABS(bs.y - bw->y) > ABS( diff = (bw->y+bw->h) - (bs.y+bs.h) ) ) {
3265 	    	bs.y = b->y + b->h - diff - bs.h;
3266 		change = true;
3267 	    }
3268 
3269 	    if ( change )
3270     	    	SetBounds_GLWidget(subs[i],&bs);
3271     	}
3272     }
3273 
3274     bs.w = wid_info->alert_msgs->bounds.w;
3275     bs.x = (b->w - bs.w)/2;
3276     bs.h = wid_info->alert_msgs->bounds.h;
3277     bs.y = b->h/2 - bs.h - 50;
3278 
3279     SetBounds_GLWidget(wid_info->alert_msgs,&bs);
3280 
3281 
3282     widget->bounds.x = b->x;
3283     widget->bounds.w = b->w;
3284     widget->bounds.y = b->y;
3285     widget->bounds.h = b->h;
3286 
3287 }
3288 
3289 extern int Console_isVisible(void);
3290 extern void Paste_String_to_Console(char *text);
button_MainWidget(Uint8 button,Uint8 state,Uint16 x,Uint16 y,void * data)3291 static void button_MainWidget( Uint8 button, Uint8 state , Uint16 x , Uint16 y, void *data )
3292 {
3293     int scraplen;
3294 
3295     if (!data) return;
3296 
3297     if (state == SDL_PRESSED) {
3298 	if (button == 1) {
3299 	    Key_press(KEY_POINTER_CONTROL);
3300 	}
3301 	if (button == 2) {
3302     	    if (Console_isVisible()) {
3303 	    	scraptarget = NULL;
3304 	    	get_scrap(TextScrap('T','E','X','T'), &scraplen, &scrap);
3305 		if ( scraplen == 0 ) return;
3306 		Paste_String_to_Console(scrap);
3307 	    }
3308 	}
3309     }
3310 }
3311 
Close_MainWidget(GLWidget * widget)3312 static void Close_MainWidget ( GLWidget *widget )
3313 {
3314     if (!widget) return;
3315     if (widget->WIDGET !=MAINWIDGET) {
3316     	error("Wrong widget type for Close_MainWidget [%i]",widget->WIDGET);
3317 	return;
3318     }
3319 
3320     if ( scrap ) free(scrap);
3321 }
3322 
Init_MainWidget(font_data * font)3323 GLWidget *Init_MainWidget( font_data *font )
3324 {
3325     GLWidget *tmp;
3326     WrapperWidget *wid_info;
3327     SDL_Rect b;
3328 
3329     tmp	= Init_EmptyBaseGLWidget();
3330     if ( !tmp ) {
3331         error("Failed to malloc GLWidget in Init_MainWidget");
3332 	return NULL;
3333     }
3334     tmp->wid_info   	= malloc(sizeof(WrapperWidget));
3335     if ( !(tmp->wid_info) ) {
3336     	free(tmp);
3337         error("Failed to malloc MainWidget in Init_MainWidget");
3338 	return NULL;
3339     }
3340     wid_info = ((WrapperWidget *)tmp->wid_info);
3341     wid_info->font	= font;
3342     wid_info->BORDER	= 10;
3343     wid_info->showconf	= true;
3344 
3345     tmp->WIDGET     	= MAINWIDGET;
3346     tmp->bounds.w   	= draw_width;
3347     tmp->bounds.h   	= draw_height;
3348     tmp->SetBounds 	= SetBounds_MainWidget;
3349     tmp->button     	= button_MainWidget;
3350     tmp->buttondata 	= tmp;
3351     tmp->Close	    	= Close_MainWidget;
3352 
3353     if ( !AppendGLWidgetList(&(tmp->children),
3354     	    (wid_info->game_msgs = Init_ListWidget(wid_info->BORDER,tmp->bounds.h-wid_info->BORDER,
3355 	    &nullRGBA,&nullRGBA,&greenRGBA,LW_UP,LW_RIGHT,VERTICAL,true)))
3356 	) {
3357 	error("Failed to initialize game msg list");
3358 	Close_Widget(&tmp);
3359 	return NULL;
3360     }
3361 
3362     if ( !AppendGLWidgetList(&(tmp->children),
3363     	    (wid_info->alert_msgs = Init_ListWidget(tmp->bounds.w/2,tmp->bounds.h/2-50,
3364 	    &nullRGBA,&nullRGBA,&greenRGBA,LW_UP,LW_HCENTER,VERTICAL,false)))
3365 	) {
3366 	error("Failed to initialize alert msg list");
3367 	Close_Widget(&tmp);
3368 	return NULL;
3369     }
3370 
3371     if ( !AppendGLWidgetList(&(tmp->children),(wid_info->radar = Init_RadarWidget())) ) {
3372 	error("radar initialization failed");
3373 	Close_Widget(&tmp);
3374 	return NULL;
3375     }
3376 
3377     if ( !AppendGLWidgetList(&(tmp->children),(wid_info->scorelist = Init_ScorelistWidget())) ) {
3378 	error("scorelist initialization failed");
3379 	Close_Widget(&tmp);
3380 	return NULL;
3381     }
3382 
3383     if ( !AppendGLWidgetList(&(tmp->children),(wid_info->confmenu = Init_ConfMenuWidget(0,0))) ) {
3384 	error("confmenu initialization failed");
3385 	Close_Widget(&tmp);
3386 	return NULL;
3387     }
3388 
3389     if ( !AppendGLWidgetList(&(tmp->children),
3390     	    	(wid_info->chat_msgs = Init_ListWidget(wid_info->radar->bounds.w + 2*wid_info->BORDER,wid_info->BORDER,
3391 		&nullRGBA,&nullRGBA,&greenRGBA,LW_DOWN,LW_RIGHT,VERTICAL,false)))
3392     	) {
3393 	error("Failed to initialize chat msg list");
3394 	Close_Widget(&tmp);
3395 	return NULL;
3396     }
3397 
3398     b.w = wid_info->confmenu->bounds.w;
3399     b.h = wid_info->confmenu->bounds.h;
3400     b.x = tmp->bounds.w - b.w - 16;
3401     b.y = tmp->bounds.h - b.h - 16;
3402     SetBounds_GLWidget(wid_info->confmenu,&b);
3403 
3404     return tmp;
3405 }
3406 /*******************/
3407 /* End: MainWidget */
3408 /*******************/
3409 
3410 /**************************/
3411 /* Begin: ConfMenuWidget  */
3412 /**************************/
3413 static Uint32 cm_name_color    = 0xffff66ff;
3414 static Uint32 cm_bg1_color     = 0x00000022;
3415 static Uint32 cm_bg2_color     = 0xffffff22;
3416 static Uint32 cm_but1_color    = 0xff000088;
3417 
3418 static void Paint_ConfMenuWidget( GLWidget *widget );
3419 static void ConfMenuWidget_Quit( void *data );
3420 static void ConfMenuWidget_Save( void *data );
3421 static void ConfMenuWidget_Join( void *data );
3422 static void ConfMenuWidget_Pause( void *data );
3423 static void ConfMenuWidget_Join_Team( void *data );
3424 static void ConfMenuWidget_Config( void *data );
3425 
confmenu_callback(void)3426 static void confmenu_callback( void )
3427 {
3428     GLWidget *list;
3429     WrapperWidget *mw;
3430     ConfMenuWidget *cm;
3431     ScrollPaneWidget *sp;
3432 
3433     if ( !(mw = (WrapperWidget *)(MainWidget->wid_info)) ) {
3434     	error("confmenu_callback: MainWidget missing!");
3435 	return;
3436     }
3437     if ( !(cm = (ConfMenuWidget*)(mw->confmenu->wid_info)) ) {
3438     	error("confmenu_callback: confmenu missing!");
3439 	return;
3440     }
3441     if ( !(sp = (ScrollPaneWidget *)(cm->scrollpane->wid_info)) ) {
3442     	error("confmenu_callback: scrollpane missing!");
3443 	return;
3444     }
3445     list = sp->content;
3446     if ( !list ) {
3447     	error("confmenu_callback: list missing!");
3448 	return;
3449     }
3450 
3451     SetBounds_GLWidget(list,&(list->bounds));
3452     SetBounds_GLWidget(mw->confmenu,&(mw->confmenu->bounds));
3453 }
3454 
ConfMenuWidget_Quit(void * data)3455 static void ConfMenuWidget_Quit( void *data )
3456 {
3457     SDL_Event quit;
3458     quit.type = SDL_QUIT;
3459     SDL_PushEvent(&quit);
3460 }
3461 
ConfMenuWidget_Save(void * data)3462 static void ConfMenuWidget_Save( void *data )
3463 {
3464     char path[PATH_MAX + 1];
3465 
3466     Xpilotrc_get_filename(path, sizeof(path));
3467     Xpilotrc_write(path);
3468 }
3469 
3470 typedef struct {
3471     GLWidget	*widget;
3472     int	    	team;
3473 } Join_Team_Data;
3474 
ConfMenuWidget_Join_Team(void * data)3475 static void ConfMenuWidget_Join_Team( void *data )
3476 {
3477     char msg[16];
3478     GLWidget *widget;
3479     ConfMenuWidget *wid_info;
3480 
3481     if (!(widget = ((Join_Team_Data *)data)->widget)) {
3482 	error("ConfMenuWidget_Join_Team: widget missing!");
3483 	return;
3484     }
3485     if ( widget->WIDGET != CONFMENUWIDGET ) {
3486 	error("ConfMenuWidget_Join_Team: Wrong widget type! [%i]",widget->WIDGET);
3487 	return;
3488     }
3489     if ( !(wid_info = (ConfMenuWidget *)(widget->wid_info)) ) {
3490 	error("ConfMenuWidget_Join_Team: wid_info missing!");
3491 	return;
3492     }
3493 
3494     if (wid_info->join_list) {
3495     	ListWidget_Remove(wid_info->main_list,wid_info->join_list);
3496     	Close_Widget(&(wid_info->join_list));
3497     	SetBounds_GLWidget(wid_info->main_list,&(wid_info->main_list->bounds));
3498     	widget->bounds.x = wid_info->main_list->bounds.x - 1;
3499     	widget->bounds.y = wid_info->main_list->bounds.y - 1;
3500     	widget->bounds.w = wid_info->main_list->bounds.w + 2;
3501     	widget->bounds.h = wid_info->main_list->bounds.h + 2;
3502     	SetBounds_GLWidget(widget,&(widget->bounds));
3503     }
3504 
3505     snprintf(msg, sizeof(msg), "/team %d", ((Join_Team_Data *)data)->team);
3506     Net_talk(msg);
3507 
3508     Pointer_control_set_state(true);
3509 }
3510 
ConfMenuWidget_Pause(void * data)3511 static void ConfMenuWidget_Pause( void *data )
3512 {
3513     GLWidget *widget;
3514     ConfMenuWidget *wid_info;
3515     bool change;
3516 
3517     if (!(widget = (GLWidget *)data)) {
3518 	error("ConfMenuWidget_Pause: widget missing!");
3519 	return;
3520     }
3521     if ( widget->WIDGET != CONFMENUWIDGET ) {
3522 	error("ConfMenuWidget_Pause: Wrong widget type! [%i]",widget->WIDGET);
3523 	return;
3524     }
3525     if ( !(wid_info = (ConfMenuWidget *)(widget->wid_info)) ) {
3526 	error("ConfMenuWidget_Pause: wid_info missing!");
3527 	return;
3528     }
3529 
3530     if (wid_info->join_list) {
3531     	ListWidget_Remove(wid_info->main_list,wid_info->join_list);
3532     	Close_Widget(&(wid_info->join_list));
3533     	SetBounds_GLWidget(wid_info->main_list,&(wid_info->main_list->bounds));
3534     	widget->bounds.x = wid_info->main_list->bounds.x - 1;
3535     	widget->bounds.y = wid_info->main_list->bounds.y - 1;
3536     	widget->bounds.w = wid_info->main_list->bounds.w + 2;
3537     	widget->bounds.h = wid_info->main_list->bounds.h + 2;
3538     	SetBounds_GLWidget(widget,&(widget->bounds));
3539     }
3540 
3541     change = false;
3542     change |= Key_press(KEY_PAUSE);
3543     if (change) Net_key_change();
3544     change = false;
3545     change |= Key_release(KEY_PAUSE);
3546     if (change) Net_key_change();
3547 }
ConfMenuWidget_Join(void * data)3548 static void ConfMenuWidget_Join( void *data )
3549 {
3550     GLWidget *widget;
3551     ConfMenuWidget *wid_info;
3552     static Join_Team_Data jtd[MAX_TEAMS];
3553 
3554     if (!(widget = (GLWidget *)data)) {
3555 	error("ConfMenuWidget_Join: widget missing!");
3556 	return;
3557     }
3558     if ( widget->WIDGET != CONFMENUWIDGET ) {
3559 	error("ConfMenuWidget_Join: Wrong widget type! [%i]",widget->WIDGET);
3560 	return;
3561     }
3562     if ( !(wid_info = (ConfMenuWidget *)(widget->wid_info)) ) {
3563 	error("ConfMenuWidget_Join: wid_info missing!");
3564 	return;
3565     }
3566 
3567     if ((Setup->mode & TEAM_PLAY) == 0) {
3568     	bool change = false;
3569 	change |= Key_press(KEY_PAUSE);
3570 	if (change) Net_key_change();
3571 	change = false;
3572 	change |= Key_release(KEY_PAUSE);
3573 	if (change) Net_key_change();
3574     } else {
3575     	int i, t;
3576     	char tstr[12];
3577     	bool has_base[MAX_TEAMS];
3578 	GLWidget *tmp;
3579 
3580 	if (wid_info->join_list) {
3581 	    ListWidget_Remove(wid_info->main_list,wid_info->join_list);
3582 	    Close_Widget(&(wid_info->join_list));
3583 
3584     	    widget->bounds.x = wid_info->main_list->bounds.x - 1;
3585     	    widget->bounds.y = wid_info->main_list->bounds.y - 1;
3586     	    widget->bounds.w = wid_info->main_list->bounds.w + 2;
3587     	    widget->bounds.h = wid_info->main_list->bounds.h + 2;
3588     	    SetBounds_GLWidget(widget,&(widget->bounds));
3589 
3590 	    return;
3591 	}
3592 
3593     	memset(has_base, 0, sizeof(has_base));
3594     	if ((Setup->mode & TEAM_PLAY) != 0) {
3595     	    for (i = 0; i < num_bases; i++) {
3596     	    	t = bases[i].team;
3597 	    	    if (t >= 0 && t < MAX_TEAMS)
3598 	            	has_base[t] = true;
3599             }
3600     	}
3601 
3602     	if (!(wid_info->join_list = Init_ListWidget(0,0,&cm_bg1_color,&cm_bg2_color,&nullRGBA,LW_DOWN,LW_RIGHT,VERTICAL,false))) {
3603     	    error("ConfMenuWidget_Join: Couldn't make the join teams list widget!");
3604     	    return;
3605     	}
3606 
3607 	for (i = 0; i < MAX_TEAMS; i++) {
3608     	    if (has_base[i]) {
3609 	    	snprintf(tstr, sizeof(tstr), "Join Team %i", i);
3610 		jtd[i].widget = widget;
3611 		jtd[i].team = i;
3612     	    	if ( !(tmp = Init_LabelButtonWidget(tstr,&greenRGBA,&cm_bg2_color,&cm_but1_color,1,ConfMenuWidget_Join_Team,&(jtd[i]))) ) {
3613     	    	    error("ConfMenuWidget_Join: Couldn't make the join team labelButton!");
3614 	    	    return;
3615     	    	}
3616 
3617 		tmp->bounds.w = widget->bounds.w - 2;
3618 
3619 		SetBounds_GLWidget(tmp,&(tmp->bounds));
3620 
3621 		ListWidget_Append(wid_info->join_list,tmp);
3622 	    }
3623     	}
3624 
3625     	if (self && strchr("P", self->mychar)) {
3626 	    snprintf(tstr, sizeof(tstr), "Unpause");
3627 	} else {
3628 	    snprintf(tstr, sizeof(tstr), "Pause");
3629 	}
3630 
3631     	if ( !(tmp = Init_LabelButtonWidget(tstr,&redRGBA,&cm_bg2_color,&cm_but1_color,1,ConfMenuWidget_Pause,widget)) ) {
3632     	    error("ConfMenuWidget_Join: Couldn't make the Pause labelButton!");
3633     	    return;
3634     	}
3635 
3636     	tmp->bounds.w = widget->bounds.w - 2;
3637 
3638     	SetBounds_GLWidget(tmp,&(tmp->bounds));
3639 
3640     	ListWidget_Append(wid_info->join_list,tmp);
3641 
3642 
3643 	ListWidget_Append(wid_info->main_list,wid_info->join_list);
3644 
3645     	widget->bounds.x = wid_info->main_list->bounds.x - 1;
3646     	widget->bounds.y = wid_info->main_list->bounds.y - 1;
3647     	widget->bounds.w = wid_info->main_list->bounds.w + 2;
3648     	widget->bounds.h = wid_info->main_list->bounds.h + 2;
3649     	SetBounds_GLWidget(widget,&(widget->bounds));
3650     }
3651 }
3652 
ConfMenuWidget_Config(void * data)3653 static void ConfMenuWidget_Config( void *data )
3654 {
3655     GLWidget *widget;
3656     ConfMenuWidget *wid_info;
3657 
3658     if (!(widget = (GLWidget *)data)) {
3659 	error("ConfMenuWidget_Close: widget missing!");
3660 	return;
3661     }
3662     if ( widget->WIDGET != CONFMENUWIDGET ) {
3663 	error("ConfMenuWidget_Close: Wrong widget type! [%i]",widget->WIDGET);
3664 	return;
3665     }
3666     if ( !(wid_info = (ConfMenuWidget *)(widget->wid_info)) ) {
3667 	error("ConfMenuWidget_Close: wid_info missing!");
3668 	return;
3669     }
3670 
3671     if ((wid_info->showconf = !wid_info->showconf)) {
3672     	if (wid_info->join_list) {
3673 	    ListWidget_Remove(wid_info->main_list,wid_info->join_list);
3674 	    Close_Widget(&(wid_info->join_list));
3675 	}
3676     	ListWidget_Remove(wid_info->button_list,wid_info->jlb);
3677     	ListWidget_Append(wid_info->button_list,wid_info->slb);
3678     	ListWidget_Append(wid_info->main_list,wid_info->scrollpane);
3679     } else {
3680      	ListWidget_Append(wid_info->button_list,wid_info->jlb);
3681     	ListWidget_Remove(wid_info->button_list,wid_info->slb);
3682    	ListWidget_Remove(wid_info->main_list,wid_info->scrollpane);
3683     }
3684 
3685     SetBounds_GLWidget(wid_info->main_list,&(wid_info->main_list->bounds));
3686 
3687     widget->bounds.x = wid_info->main_list->bounds.x - 1;
3688     widget->bounds.y = wid_info->main_list->bounds.y - 1;
3689     widget->bounds.w = wid_info->main_list->bounds.w + 2;
3690     widget->bounds.h = wid_info->main_list->bounds.h + 2;
3691     SetBounds_GLWidget(widget,&(widget->bounds));
3692 }
3693 
SetBounds_ConfMenuWidget(GLWidget * widget,SDL_Rect * b)3694 static void SetBounds_ConfMenuWidget( GLWidget *widget, SDL_Rect *b )
3695 {
3696     ConfMenuWidget *wid_info;
3697     SDL_Rect bounds = {0,0,0,0};
3698 
3699     if (!widget ) {
3700 	error("SetBounds_ConfMenuWidget: tried to change bounds on NULL ConfMenuWidget!");
3701 	return;
3702     }
3703     if ( widget->WIDGET != CONFMENUWIDGET ) {
3704 	error("SetBounds_ConfMenuWidget: Wrong widget type! [%i]",widget->WIDGET);
3705 	return;
3706     }
3707     if (!(wid_info = (ConfMenuWidget *)(widget->wid_info))) {
3708 	error("SetBounds_ConfMenuWidget: wid_info missing!");
3709 	return;
3710     }
3711     if (!b ) {
3712 	error("SetBounds_ConfMenuWidget: tried to set NULL bounds on ConfMenuWidget!");
3713 	return;
3714     }
3715 
3716     widget->bounds.x = b->x;
3717     widget->bounds.y = b->y;
3718     widget->bounds.w = b->w;
3719     widget->bounds.h = b->h;
3720 
3721     bounds.x += b->x + 1;
3722     bounds.y += b->y + 1;
3723 
3724     if (!wid_info->main_list) {
3725 	error("SetBounds_ConfMenuWidget: main_list missing!");
3726 	return;
3727     }
3728     bounds.w = wid_info->main_list->bounds.w;
3729     bounds.h = wid_info->main_list->bounds.h;
3730 
3731     SetBounds_GLWidget(wid_info->main_list,&bounds);
3732 }
3733 
Paint_ConfMenuWidget(GLWidget * widget)3734 static void Paint_ConfMenuWidget( GLWidget *widget )
3735 {
3736     Uint32 edgeColor = 0xff0000ff;
3737     Uint32 bgColor = 0x0000ff88;
3738     ConfMenuWidget *wid_info;
3739 
3740     if (!widget ) {
3741     	error("Paint_ConfMenuWidget: tried to paint NULL ConfMenuWidget!");
3742 	return;
3743     }
3744 
3745     if (!(wid_info = (ConfMenuWidget *)(widget->wid_info))) {
3746 	error("Paint_ConfMenuWidget: wid_info missing!");
3747 	return;
3748     }
3749 
3750     if ((Setup->mode & TEAM_PLAY) == 0) {
3751     	if (self && strchr("P", self->mychar)) {
3752     	    if ( !wid_info->paused ) {
3753     	    	ListWidget_Remove(wid_info->button_list,wid_info->jlb);
3754 	    	Close_Widget(&(wid_info->jlb));
3755     	    	if ( !(wid_info->jlb = Init_LabelButtonWidget("Join",&greenRGBA,&nullRGBA,&cm_but1_color,1,ConfMenuWidget_Join,widget)) ) {
3756     	    	    error("Paint_ConfMenuWidget: Couldn't make the join labelButton!");
3757 	    	    return;
3758 	    	}
3759     	    	SetBounds_GLWidget(wid_info->jlb, &(wid_info->clb->bounds));
3760     	    	ListWidget_Append(wid_info->button_list,wid_info->jlb);
3761 	    	wid_info->paused = true;
3762     	    }
3763     	} else {
3764     	    if ( wid_info->paused ) {
3765     	    	ListWidget_Remove(wid_info->button_list,wid_info->jlb);
3766 	    	Close_Widget(&(wid_info->jlb));
3767     	    	if ( !(wid_info->jlb = Init_LabelButtonWidget("Pause",&greenRGBA,&nullRGBA,&cm_but1_color,50,ConfMenuWidget_Pause,widget)) ) {
3768     	    	    error("Paint_ConfMenuWidget: Couldn't make the Pause labelButton!");
3769 	    	    return;
3770     	    	}
3771     	    	SetBounds_GLWidget(wid_info->jlb, &(wid_info->clb->bounds));
3772     	    	ListWidget_Append(wid_info->button_list,wid_info->jlb);
3773 	    	wid_info->paused = false;
3774 	    }
3775     	}
3776     }
3777 
3778     set_alphacolor(bgColor);
3779     glBegin(GL_QUADS);
3780     	glVertex2i(widget->bounds.x 	    	    ,widget->bounds.y	    	    	);
3781     	glVertex2i(widget->bounds.x+widget->bounds.w,widget->bounds.y	    	    	);
3782     	glVertex2i(widget->bounds.x+widget->bounds.w,widget->bounds.y+widget->bounds.h	);
3783     	glVertex2i(widget->bounds.x 	    	    ,widget->bounds.y+widget->bounds.h	);
3784     glEnd();
3785     glBegin(GL_LINE_LOOP);
3786     	set_alphacolor(edgeColor);
3787     	glVertex2i(widget->bounds.x 	    	    ,widget->bounds.y	    	    	);
3788     	set_alphacolor(bgColor | 0x000000ff);
3789     	glVertex2i(widget->bounds.x+widget->bounds.w,widget->bounds.y	    	    	);
3790     	set_alphacolor(edgeColor);
3791     	glVertex2i(widget->bounds.x+widget->bounds.w,widget->bounds.y+widget->bounds.h	);
3792     	set_alphacolor(bgColor | 0x000000ff);
3793     	glVertex2i(widget->bounds.x 	    	    ,widget->bounds.y+widget->bounds.h	);
3794     glEnd();
3795 }
3796 
Init_ConfMenuWidget(Uint16 x,Uint16 y)3797 GLWidget *Init_ConfMenuWidget( Uint16 x, Uint16 y )
3798 {
3799     GLWidget *tmp, *item, *dummy, *list;
3800     ConfMenuWidget *wid_info;
3801     int i;
3802     xp_option_t *opt;
3803 
3804     tmp	= Init_EmptyBaseGLWidget();
3805     if ( !tmp ) {
3806         error("Failed to malloc in Init_ConfMenu");
3807 	return NULL;
3808     }
3809     tmp->wid_info   	= malloc(sizeof(ConfMenuWidget));
3810     if ( !(tmp->wid_info) ) {
3811     	free(tmp);
3812         error("Failed to malloc in Init_ConfMenu");
3813 	return NULL;
3814     }
3815     wid_info = ((ConfMenuWidget *)(tmp->wid_info));
3816 
3817     tmp->WIDGET     	= CONFMENUWIDGET;
3818     tmp->Draw	    	= Paint_ConfMenuWidget;
3819     tmp->SetBounds  	= SetBounds_ConfMenuWidget;
3820     wid_info->showconf	= false;
3821     wid_info->join_list	= NULL;
3822 
3823     dummy = Init_EmptyBaseGLWidget();
3824     if ( !dummy ) {
3825         error("Failed to malloc in Init_ConfMenu");
3826 	return NULL;
3827     }
3828 
3829     for ( i=0 ; i < num_options; ++i ) {
3830     	opt = Option_by_index(i);
3831 	item = Init_OptionWidget(opt,&cm_name_color, &nullRGBA);
3832 	if (item) {
3833 	    AppendGLWidgetList( &(dummy->next), item );
3834 	}
3835     }
3836 
3837     if (!(list = Init_ListWidget(0,0,&cm_bg1_color,&cm_bg2_color,&nullRGBA,LW_DOWN,LW_RIGHT,VERTICAL,false))) {
3838     	error("Init_ConfMenuWidget: Couldn't make the list widget!");
3839 	Close_WidgetTree(&dummy);
3840 	Close_Widget(&tmp);
3841 	return NULL;
3842     }
3843 
3844     ListWidget_Append(list,dummy->next);
3845     Close_Widget(&dummy);
3846 
3847     if ( !(wid_info->scrollpane = Init_ScrollPaneWidget(list)) ) {
3848     	error("Init_ConfMenuWidget: Couldn't make the scrollpane!");
3849 	Close_Widget(&list);
3850 	Close_Widget(&tmp);
3851 	return NULL;
3852     }
3853 
3854     wid_info->scrollpane->bounds.h = 512;
3855 
3856     if ( !(wid_info->slb = Init_LabelButtonWidget("Save",&greenRGBA,&nullRGBA,&cm_but1_color,1,ConfMenuWidget_Save,tmp)) ) {
3857     	error("Init_ConfMenuWidget: Couldn't make the save labelButton!");
3858 	Close_Widget(&tmp);
3859 	return NULL;
3860     }
3861 
3862     if (self && strchr("P", self->mychar))
3863     	wid_info->paused = true;
3864     else
3865     	wid_info->paused = false;
3866 
3867     if ((Setup->mode & TEAM_PLAY) || wid_info->paused) {
3868     	if ( !(wid_info->jlb = Init_LabelButtonWidget("Join",&greenRGBA,&nullRGBA,&cm_but1_color,1,ConfMenuWidget_Join,tmp)) ) {
3869     	    error("Init_ConfMenuWidget: Couldn't make the join labelButton!");
3870 	    Close_Widget(&tmp);
3871 	    return NULL;
3872     	}
3873     } else {
3874     	if ( !(wid_info->jlb = Init_LabelButtonWidget("Pause",&greenRGBA,&nullRGBA,&cm_but1_color,50,ConfMenuWidget_Pause,tmp)) ) {
3875     	    error("Init_ConfMenuWidget: Couldn't make the Pause labelButton!");
3876 	    Close_Widget(&tmp);
3877 	    return NULL;
3878     	}
3879     }
3880 
3881     if ( !(wid_info->clb = Init_LabelButtonWidget("Config",&yellowRGBA,&nullRGBA,&cm_but1_color,1,ConfMenuWidget_Config,tmp)) ) {
3882     	error("Init_ConfMenuWidget: Couldn't make the config labelButton!");
3883 	Close_Widget(&tmp);
3884 	return NULL;
3885     }
3886 
3887     if ( !(wid_info->qlb = Init_LabelButtonWidget("Quit",&redRGBA,&nullRGBA,&cm_but1_color,1,ConfMenuWidget_Quit,tmp)) ) {
3888     	error("Init_ConfMenuWidget: Couldn't make the quit label!");
3889 	Close_Widget(&tmp);
3890 	return NULL;
3891     }
3892 
3893     if (!(wid_info->button_list = Init_ListWidget(0,0,&nullRGBA,&nullRGBA,&nullRGBA,LW_DOWN,LW_RIGHT,HORISONTAL,true))) {
3894     	error("Init_ConfMenuWidget: Couldn't make the button_list widget!");
3895 	Close_Widget(&tmp);
3896 	return NULL;
3897     }
3898 
3899     wid_info->clb->bounds.w = ( wid_info->scrollpane->bounds.w + 10 )/3 + 1;
3900     SetBounds_GLWidget(wid_info->clb, &(wid_info->clb->bounds));
3901     SetBounds_GLWidget(wid_info->slb, &(wid_info->clb->bounds));
3902     SetBounds_GLWidget(wid_info->jlb, &(wid_info->clb->bounds));
3903     SetBounds_GLWidget(wid_info->qlb, &(wid_info->clb->bounds));
3904 
3905 
3906     ListWidget_Append(wid_info->button_list,wid_info->qlb);
3907     ListWidget_Append(wid_info->button_list,wid_info->clb);
3908     ListWidget_Append(wid_info->button_list,wid_info->jlb);
3909 
3910     if (!(wid_info->main_list = Init_ListWidget(0,0,&nullRGBA,&nullRGBA,&nullRGBA,LW_UP,LW_LEFT,VERTICAL,true))) {
3911     	error("Init_ConfMenuWidget: Couldn't make the main_list widget!");
3912 	Close_Widget(&tmp);
3913 	return NULL;
3914     }
3915 
3916     ListWidget_Append(wid_info->main_list,wid_info->button_list);
3917 
3918     if (!AppendGLWidgetList( &(tmp->children), wid_info->main_list )) {
3919     	error("Init_ConfMenuWidget: failed to append main_list to children");
3920 	Close_Widget(&tmp);
3921 	return NULL;
3922     }
3923 
3924     tmp->bounds.x = x;
3925     tmp->bounds.y = y;
3926     tmp->bounds.w = wid_info->main_list->bounds.w + 2;
3927     tmp->bounds.h = wid_info->main_list->bounds.h + 2;
3928 
3929     SetBounds_GLWidget(tmp,&(tmp->bounds));
3930 
3931     return tmp;
3932 }
3933 /***********************/
3934 /* End: ConfMenuWidget */
3935 /***********************/
3936 
3937 /****************************/
3938 /* Begin: ImageButtonWidget */
3939 /****************************/
3940 
Button_ImageButtonWidget(Uint8 button,Uint8 state,Uint16 x,Uint16 y,void * data)3941 static void Button_ImageButtonWidget(Uint8 button, Uint8 state, Uint16 x,
3942 			      Uint16 y, void *data)
3943 {
3944     GLWidget *widget;
3945     ImageButtonWidget *info;
3946 
3947     widget = (GLWidget*)data;
3948     if (widget->WIDGET != IMAGEBUTTONWIDGET) {
3949 	error("expected IMAGEBUTTONWIDGET got [%d]", widget->WIDGET);
3950 	return;
3951     }
3952     info = (ImageButtonWidget*)widget->wid_info;
3953     if (info->state == state) return;
3954     info->state = state;
3955 
3956     if (state != SDL_PRESSED && info->onClick) {
3957 	if (x >= widget->bounds.x
3958 	    && x <= widget->bounds.x + widget->bounds.w
3959 	    && y >= widget->bounds.y
3960 	    && y <= widget->bounds.y + widget->bounds.h)
3961 	    info->onClick(widget);
3962     }
3963 }
3964 
Close_ImageButtonWidget(GLWidget * widget)3965 static void Close_ImageButtonWidget(GLWidget *widget)
3966 {
3967     ImageButtonWidget *info;
3968     if (!widget) return;
3969     if (widget->WIDGET != IMAGEBUTTONWIDGET) {
3970     	error("Wrong widget type for Close_ImageButtonWidget [%i]",
3971 	      widget->WIDGET);
3972 	return;
3973     }
3974     info = (ImageButtonWidget*)widget->wid_info;
3975     free_string_texture(&(info->tex));
3976     if (info->imageUp) glDeleteTextures(1, &(info->imageUp));
3977     if (info->imageDown) glDeleteTextures(1, &(info->imageDown));
3978 }
3979 
Paint_ImageButtonWidget(GLWidget * widget)3980 static void Paint_ImageButtonWidget(GLWidget *widget)
3981 {
3982     SDL_Rect *b;
3983     ImageButtonWidget *info;
3984     int x, y, c;
3985 
3986     if (!widget) return;
3987 
3988     b = &(widget->bounds);
3989     info = (ImageButtonWidget*)(widget->wid_info);
3990 
3991     if (info->state != SDL_PRESSED) {
3992 	if (info->imageUp) {
3993 	    set_alphacolor(info->bg);
3994 	    glBindTexture(GL_TEXTURE_2D, info->imageUp);
3995 	    glEnable(GL_TEXTURE_2D);
3996 	    glBegin(GL_QUADS);
3997 	    glTexCoord2f(info->txcUp.MinX, info->txcUp.MinY);
3998 	    glVertex2i(b->x, b->y);
3999 	    glTexCoord2f(info->txcUp.MaxX, info->txcUp.MinY);
4000 	    glVertex2i(b->x + b->w , b->y);
4001 	    glTexCoord2f(info->txcUp.MaxX, info->txcUp.MaxY);
4002 	    glVertex2i(b->x + b->w , b->y + b->h);
4003 	    glTexCoord2f(info->txcUp.MinY, info->txcUp.MaxY);
4004 	    glVertex2i(b->x, b->y + b->h);
4005 	    glEnd();
4006 	}
4007     } else {
4008 	if (info->imageDown) {
4009 	    set_alphacolor(info->bg);
4010 	    glBindTexture(GL_TEXTURE_2D, info->imageDown);
4011 	    glEnable(GL_TEXTURE_2D);
4012 	    glBegin(GL_QUADS);
4013 	    glTexCoord2f(info->txcDown.MinX, info->txcDown.MinY);
4014 	    glVertex2i(b->x, b->y);
4015 	    glTexCoord2f(info->txcDown.MaxX, info->txcDown.MinY);
4016 	    glVertex2i(b->x + b->w , b->y);
4017 	    glTexCoord2f(info->txcDown.MaxX, info->txcDown.MaxY);
4018 	    glVertex2i(b->x + b->w , b->y + b->h);
4019 	    glTexCoord2f(info->txcDown.MinY, info->txcDown.MaxY);
4020 	    glVertex2i(b->x, b->y + b->h);
4021 	    glEnd();
4022 	}
4023     }
4024 
4025     x = widget->bounds.x + widget->bounds.w / 2;
4026     y = widget->bounds.y + widget->bounds.h / 2;
4027     c = (int)(info->fg ? info->fg : whiteRGBA);
4028     if (info->state == SDL_PRESSED) {
4029 	x += 1;
4030 	y += 1;
4031     }
4032     disp_text(&(info->tex), c,
4033 	      CENTER, CENTER,
4034 	      x, draw_height - y,
4035 	      true);
4036 }
4037 
Init_ImageButtonWidget(const char * text,const char * upImage,const char * downImage,Uint32 bg,Uint32 fg,void (* onClick)(GLWidget * widget))4038 GLWidget *Init_ImageButtonWidget(const char *text,
4039 				 const char *upImage,
4040 				 const char *downImage,
4041 				 Uint32 bg,
4042 				 Uint32 fg,
4043 				 void (*onClick)(GLWidget *widget))
4044 {
4045     GLWidget *tmp;
4046     ImageButtonWidget *info;
4047     SDL_Surface *surface;
4048     char imagePath[256];
4049     int width, height;
4050 
4051     if (!text) {
4052     	error("text missing for Init_ImageButtonWidget.");
4053 	return NULL;
4054     }
4055     tmp	= Init_EmptyBaseGLWidget();
4056     if ( !tmp ) {
4057         error("Failed to malloc in Init_ImageButtonWidget");
4058 	return NULL;
4059     }
4060     info = XMALLOC(ImageButtonWidget, 1);
4061     if (!info) {
4062     	free(tmp);
4063         error("Failed to malloc in Init_ImageButtonWidget");
4064 	return NULL;
4065     }
4066 
4067     info->onClick = onClick;
4068     info->fg = fg;
4069     info->bg = bg;
4070     info->state = SDL_RELEASED;
4071     info->imageUp = 0;
4072     info->imageDown = 0;
4073 
4074     if (!render_text(&gamefont, text, &(info->tex))) {
4075     	free(info);
4076     	free(tmp);
4077         error("Failed to render text in Init_ImageButtonWidget");
4078 	return NULL;
4079     }
4080     width = info->tex.width + 1;
4081     height = info->tex.height + 1;
4082 
4083 #ifdef HAVE_SDL_IMAGE
4084     sprintf(imagePath, "%s%s", CONF_TEXTUREDIR, upImage);
4085     surface = IMG_Load(imagePath);
4086     if (surface) {
4087 	info->imageUp = SDL_GL_LoadTexture(surface, &(info->txcUp));
4088 	if (width < surface->w) width = surface->w;
4089 	if (height < surface->h) height = surface->h;
4090 	SDL_FreeSurface(surface);
4091     } else {
4092 	error("Failed to load button image %s", imagePath);
4093     }
4094     sprintf(imagePath, "%s%s", CONF_TEXTUREDIR, downImage);
4095     surface = IMG_Load(imagePath);
4096     if (surface) {
4097 	info->imageDown = SDL_GL_LoadTexture(surface, &(info->txcDown));
4098 	if (width < surface->w) width = surface->w;
4099 	if (height < surface->h) height = surface->h;
4100 	SDL_FreeSurface(surface);
4101     } else {
4102 	error("Failed to load button image %s", imagePath);
4103     }
4104 #endif
4105 
4106     tmp->WIDGET     	= IMAGEBUTTONWIDGET;
4107     tmp->wid_info       = info;
4108     tmp->bounds.w   	= width;
4109     tmp->bounds.h   	= height;
4110     tmp->Draw	    	= Paint_ImageButtonWidget;
4111     tmp->Close     	= Close_ImageButtonWidget;
4112     tmp->button         = Button_ImageButtonWidget;
4113     tmp->buttondata     = tmp;
4114     return tmp;
4115 }
4116 /**************************/
4117 /* End: ImageButtonWidget */
4118 /**************************/
4119 
4120 /*****************************/
4121 /* Begin: LabelButtonWidget  */
4122 /*****************************/
4123 static void SetBounds_LabelButtonWidget( GLWidget *widget, SDL_Rect *b );
4124 
SetBounds_LabelButtonWidget(GLWidget * widget,SDL_Rect * b)4125 static void SetBounds_LabelButtonWidget( GLWidget *widget, SDL_Rect *b )
4126 {
4127     LabelButtonWidget *wid_info;
4128 
4129     if (!widget ) {
4130 	error("SetBounds_LabelButtonWidget: tried to change bounds on NULL ImageButtonWidget!");
4131 	return;
4132     }
4133     if ( widget->WIDGET != LABELBUTTONWIDGET ) {
4134 	error("SetBounds_LabelButtonWidget: Wrong widget type! [%i]",widget->WIDGET);
4135 	return;
4136     }
4137     if (!(wid_info = (LabelButtonWidget *)(widget->wid_info))) {
4138 	error("SetBounds_LabelButtonWidget: wid_info missing!");
4139 	return;
4140     }
4141     if (!b ) {
4142 	error("SetBounds_LabelButtonWidget: tried to set NULL bounds on LabelButtonWidget!");
4143 	return;
4144     }
4145 
4146     widget->bounds.x = b->x;
4147     widget->bounds.w = b->w;
4148     widget->bounds.y = b->y;
4149     widget->bounds.h = b->h;
4150 
4151     SetBounds_GLWidget(wid_info->label,&(widget->bounds));
4152     SetBounds_GLWidget(wid_info->button,&(widget->bounds));
4153 }
4154 
Init_LabelButtonWidget(const char * text,Uint32 * text_color,Uint32 * bg_color,Uint32 * active_color,Uint8 depress_time,void (* action)(void * data),void * actiondata)4155 GLWidget *Init_LabelButtonWidget(   const char *text,
4156 				    Uint32 *text_color,
4157     	    	    	    	    Uint32 *bg_color,
4158     	    	    	    	    Uint32 *active_color,
4159     	    	    	    	    Uint8 depress_time,
4160     	    	    	    	    void (*action)(void *data),
4161 				    void *actiondata)
4162 {
4163     GLWidget *widget;
4164     LabelButtonWidget *wid_info;
4165 
4166     widget	= Init_EmptyBaseGLWidget();
4167     if ( !widget ) {
4168         error("Failed to malloc in Init_LabelButtonWidget");
4169 	return NULL;
4170     }
4171     widget->wid_info   	= malloc(sizeof(LabelButtonWidget));
4172     if ( !(widget->wid_info) ) {
4173     	free(widget);
4174         error("Failed to malloc in Init_LabelButtonWidget");
4175 	return NULL;
4176     }
4177     wid_info = ((LabelButtonWidget *)(widget->wid_info));
4178 
4179     widget->WIDGET     	= LABELBUTTONWIDGET;
4180     widget->SetBounds  	= SetBounds_LabelButtonWidget;
4181 
4182     wid_info->label = Init_LabelWidget( text , text_color, &nullRGBA, CENTER, CENTER );
4183 
4184     if (!AppendGLWidgetList(&(widget->children),wid_info->label)) {
4185     	error("Init_LabelButtonWidget: Could not initialize label widget!");
4186 	Close_Widget(&widget);
4187 	return NULL;
4188     }
4189 
4190     wid_info->button = Init_ButtonWidget( bg_color, active_color, depress_time, action, actiondata);
4191 
4192     if (!AppendGLWidgetList(&(widget->children),wid_info->button)) {
4193     	error("Init_LabelButtonWidget: Could not initialize button widget!");
4194 	Close_Widget(&widget);
4195 	return NULL;
4196     }
4197 
4198     SetBounds_GLWidget(widget,&(wid_info->label->bounds));
4199 
4200     return widget;
4201 }
4202 /**************************/
4203 /* End: LabelButtonWidget */
4204 /**************************/
4205