1 #include <stdio.h>
2 #include <string.h>
3 #include <ctype.h>
4 #include <stdlib.h>
5 #include <sys/types.h>
6 
7 #ifdef __MSW__
8 # include <windows.h>
9 #endif
10 
11 #include <GL/gl.h>
12 
13 #include "../include/string.h"
14 #include "v3dgl.h"
15 #include "v3dtex.h"
16 
17 #include "gw.h"
18 #include "stategl.h"
19 #include "image.h"
20 #include "menu.h"
21 
22 
23 /* Utilities */
24 void SARMenuGLStateReset(gw_display_struct *display);
25 void *SARMenuGetObject(sar_menu_struct *m, int n);
26 void *SARMenuGetObjectByID(
27 	sar_menu_struct *m, int id, int *n
28 );
29 Boolean SARMenuObjectIsSensitive(sar_menu_struct *m, int n);
30 
31 /* Menu */
32 sar_menu_struct *SARMenuNew(
33 	sar_menu_type type, const char *name, const char *bg_image
34 );
35 void SARMenuLoadBackgroundImage(sar_menu_struct *m);
36 void SARMenuUnloadBackgroundImage(sar_menu_struct *m);
37 void SARMenuDelete(sar_menu_struct *m);
38 
39 /* Label */
40 int SARMenuLabelNew(
41 	sar_menu_struct *m,
42 	float x, float y,
43 	int width, int height,
44 	const char *label,
45 	sar_menu_color_struct *fg_color, GWFont *font,
46 	const sar_image_struct *image
47 );
48 
49 /* Button */
50 int SARMenuButtonNew(
51 	sar_menu_struct *m,
52 	float x, float y,
53 	int width, int height,
54 	const char *label,
55 	sar_menu_color_struct *fg_color, GWFont *font,
56 	const sar_image_struct *unarmed_image,
57 	const sar_image_struct *armed_image,
58 	const sar_image_struct *highlighted_image,
59 	void *client_data, int id,
60 	void (*func_cb)(void *, int, void *)
61 );
62 
63 /* Progress Bar */
64 int SARMenuProgressNew(
65 	sar_menu_struct *m,
66 	float x, float y,
67 	int width, int height,
68 	const char *label,
69 	sar_menu_color_struct *fg_color,
70 	GWFont *font,
71 	const sar_image_struct *bg_image,
72 	const sar_image_struct *fg_image,
73 	float progress
74 );
75 void SARMenuProgressSet(
76 	gw_display_struct *display, sar_menu_struct *m, int n,
77 	float progress, Boolean redraw
78 );
79 
80 /* Message Box */
81 int SARMenuMessageBoxNew(
82 	sar_menu_struct *m,
83 	float x, float y,
84 	float width, float height,
85 	sar_menu_color_struct *fg_color, GWFont *font,
86 	const sar_image_struct **bg_image,	/* Pointer to 9 images */
87 	void *client_data, int id,
88 	const char *message
89 );
90 void SARMenuMessageBoxSet(
91 	gw_display_struct *display, sar_menu_struct *m, int n,
92 	const char *message, Boolean redraw
93 );
94 
95 /* List */
96 int SARMenuListNew(
97 	sar_menu_struct *m,
98 	float x, float y,
99 	float width, float height,
100 	sar_menu_color_struct *fg_color, GWFont *font,
101 	const char *label,
102 	const sar_image_struct **bg_image,
103 	void *client_data, int id,
104 	void (*select_cb)(void *, int, void *, int, void *, void *),
105 	void (*activate_cb)(void *, int, void *, int, void *, void *)
106 );
107 int SARMenuListAppendItem(
108 	sar_menu_struct *m, int n,
109 	const char *name,
110 	void *client_data,
111 	sar_menu_flags_t flags
112 );
113 sar_menu_list_item_struct *SARMenuListGetItemByNumber(
114 	sar_menu_list_struct *list, int i
115 );
116 void SARMenuListSelect(
117 	gw_display_struct *display, sar_menu_struct *m, int n,
118 	int i,
119 	Boolean scroll, Boolean redraw
120 );
121 void SARMenuListDeleteAllItems(sar_menu_struct *m, int n);
122 
123 /* Multi-purpose Display */
124 int SARMenuMDisplayNew(
125 	sar_menu_struct *m,
126 	float x, float y,
127 	float width, float height,
128 	const sar_image_struct **bg_image,	/* Pointer to 9 images */
129 	void *client_data, int id,
130 	void (*draw_cb)(
131 		void *,         /* Display */
132 		void *,         /* Menu */
133 		void *,         /* This Object */
134 		int,            /* ID Code */
135 		void *,         /* Data */
136 		int, int, int, int      /* x_min, y_min, x_max, y_max */
137 	)
138 );
139 void SARMenuMDisplayDraw(
140 	gw_display_struct *display, sar_menu_struct *m, int n
141 );
142 
143 /* Switch */
144 int SARMenuSwitchNew(
145 	sar_menu_struct *m,
146 	float x, float y,
147 	int width, int height,
148 	sar_menu_color_struct *fg_color, GWFont *font,
149 	const char *label,
150 	const sar_image_struct *bg_image,
151 	const sar_image_struct *switch_off_image,
152 	const sar_image_struct *switch_on_image,
153 	Boolean state,
154 	void *client_data, int id,
155 	void (*switch_cb)(void *, int, void *, Boolean)
156 );
157 Boolean SARMenuSwitchGetValue(sar_menu_struct *m, int n);
158 void SARMenuSwitchSetValue(
159 	gw_display_struct *display, sar_menu_struct *m, int n,
160 	Boolean state, Boolean redraw
161 );
162 
163 /* Spin */
164 int SARMenuSpinNew(
165 	sar_menu_struct *m,
166 	float x, float y,
167 	float width, float height,
168 	sar_menu_color_struct *label_color,
169 	sar_menu_color_struct *value_color,
170 	GWFont *font,
171 	GWFont *value_font,
172 	const char *label,
173 	const sar_image_struct *label_image,
174 	const sar_image_struct *value_image,
175 	const sar_image_struct *dec_armed_image,
176 	const sar_image_struct *dec_unarmed_image,
177 	const sar_image_struct *inc_armed_image,
178 	const sar_image_struct *inc_unarmed_image,
179 	void *client_data, int id,
180 	void (*change_cb)(void *, int, void *, char *)
181 );
182 void SARMenuSpinSetValueType(
183 	sar_menu_struct *m, int n, int type
184 );
185 int SARMenuSpinAddValue(
186 	sar_menu_struct *m, int n, const char *value
187 );
188 char *SARMenuSpinGetCurrentValue(
189 	sar_menu_struct *m, int n, int *sel_num
190 );
191 void SARMenuSpinSelectValueIndex(
192 	gw_display_struct *display, sar_menu_struct *m, int n,
193 	int value_num,
194 	Boolean redraw
195 );
196 void SARMenuSpinSetValueIndex(
197 	gw_display_struct *display, sar_menu_struct *m, int n,
198 	int value_num, const char *value,
199 	Boolean redraw
200 );
201 void SARMenuSpinDeleteAllValues(sar_menu_struct *m, int n);
202 void SARMenuSpinDoInc(
203 	gw_display_struct *display, sar_menu_struct *m,	int n,
204 	Boolean redraw
205 );
206 void SARMenuSpinDoDec(
207 	gw_display_struct *display, sar_menu_struct *m, int n,
208 	Boolean redraw
209 );
210 
211 /* Slider */
212 int SARMenuSliderNew(
213 	sar_menu_struct *m,
214 	float x, float y,
215 	float width, float height,
216 	sar_menu_color_struct *label_color,
217 	GWFont *font,
218 	const char *label,
219 	const sar_image_struct *label_image,
220 	const sar_image_struct *trough_image,
221 	const sar_image_struct *handle_image,
222 	void *client_data, int id,
223 	void (*change_cb)(void *, int, void *, float)
224 );
225 void SARMenuSliderSetValueBounds(
226 	gw_display_struct *display, sar_menu_struct *m, int n,
227 	float lower, float upper,
228 	Boolean redraw
229 );
230 void SARMenuSliderSetValue(
231 	gw_display_struct *display, sar_menu_struct *m, int n,
232 	float value,
233 	Boolean redraw
234 );
235 float SARMenuSliderGetValue(sar_menu_struct *m, int n);
236 
237 /* Object Common */
238 void SARMenuObjectSetSensitive(
239 	gw_display_struct *display, sar_menu_struct *m, int n,
240 	Boolean sensitive, Boolean redraw
241 );
242 void SARMenuObjectDelete(sar_menu_struct *m, int n);
243 
244 /* Drawing */
245 static const char *SARMenuMessageBoxDrawString(
246 	gw_display_struct *display,
247 	int x, int y,
248 	const char *buf_ptr,
249 	int visible_columns, int font_width,
250 	Boolean sensitive,
251 	Boolean draw_line,
252 	const sar_menu_color_struct *c_def,
253 	const sar_menu_color_struct *c_bold,
254 	const sar_menu_color_struct *c_ul
255 );
256 static int SARMenuMessageBoxTotalLines(
257 	const char *buf_ptr, int visible_columns
258 );
259 void SARMenuDrawWindowBG(
260 	gw_display_struct *display,
261 	const sar_image_struct **bg_image,	/* Total 9 images */
262 	const sar_menu_color_struct *base_color,	/* Set NULL to use image as base */
263 	int x, int y,
264 	int width, int height,
265 	Boolean draw_base,
266 	Boolean draw_shadow,
267 	Boolean is_selected
268 );
269 static void SARMenuDoDrawObject(
270 	gw_display_struct *display, sar_menu_struct *m,
271 	int n,			/* Object number on m */
272 	Boolean draw_shadows
273 );
274 void SARMenuDrawObject(
275 	gw_display_struct *display, sar_menu_struct *m,
276 	int n			/* Object number on m */
277 );
278 void SARMenuDrawAll(
279 	gw_display_struct *display, sar_menu_struct *m
280 );
281 
282 /* Manage Pointer */
283 int SARMenuManagePointer(
284 	gw_display_struct *display, sar_menu_struct *m,
285 	int x, int y, gw_event_type type, int btn_num
286 );
287 
288 /* Manage Key */
289 int SARMenuManageKey(
290 	gw_display_struct *display,
291 	sar_menu_struct *m,
292 	int key, Boolean state
293 );
294 
295 
296 #define ATOI(s)         (((s) != NULL) ? atoi(s) : 0)
297 #define ATOL(s)         (((s) != NULL) ? atol(s) : 0)
298 #define ATOF(s)         (((s) != NULL) ? atof(s) : 0.0f)
299 #define STRDUP(s)       (((s) != NULL) ? strdup(s) : NULL)
300 
301 #define MAX(a,b)        (((a) > (b)) ? (a) : (b))
302 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
303 #define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))
304 #define STRLEN(s)	(((s) != NULL) ? ((int)strlen(s)) : 0)
305 
306 #define ISCR(c)		(((c) == '\n') || ((c) == '\r'))
307 
308 #define IS_CHAR_ESC_START(c)	((c) == '<')
309 #define IS_CHAR_ESC_END(c)	((c) == '>')
310 
311 
312 /* Default spacings (in pixels) */
313 #define DEF_XMARGIN			5
314 #define DEF_YMARGIN			5
315 
316 /* List object */
317 #define DEF_LIST_XMARGIN		25
318 #define DEF_LIST_YMARGIN		20
319 
320 /* Message box object */
321 #define DEF_MB_XMARGIN			25
322 #define DEF_MB_YMARGIN			20
323 
324 #define DEF_WIDTH			100
325 #define DEF_HEIGHT			100
326 
327 #define DEF_PROGRESS_HEIGHT		25
328 
329 #define DEF_SCROLL_CURSOR_WIDTH		16
330 #define DEF_SCROLL_CURSOR_HEIGHT	16
331 
332 #define DEF_SWITCH_WIDTH		48
333 #define DEF_SWITCH_HEIGHT		48
334 
335 
336 #define DO_REDRAW_MENU(d,m)	{	\
337  SARMenuDrawAll((d), (m));		\
338  GWSwapBuffer(d);			\
339 }
340 
341 #define DO_REDRAW_OBJECT(d,m,n)	{	\
342  if((m)->always_full_redraw)		\
343   SARMenuDrawAll((d), (m));		\
344  else					\
345   SARMenuDrawObject((d),(m),(n));	\
346  GWSwapBuffer(d);			\
347 }
348 
349 
350 /*
351  *	Resets gl states for 2d menu system drawing, this function
352  *	should be called at startup and whenever the menu system is
353  *	re-entered or needs the gl state to be reset to expected values.
354  */
SARMenuGLStateReset(gw_display_struct * display)355 void SARMenuGLStateReset(gw_display_struct *display)
356 {
357 	state_gl_struct *s;
358 
359 	if(display == NULL)
360 	    return;
361 
362 	s = &display->state_gl;
363 
364 	/* Set up GL states for 2d drawing */
365 	GWOrtho2D(display);
366 
367 	StateGLDisableF(s, GL_DEPTH_TEST, True);
368 	StateGLDepthMask(s, GL_TRUE);
369 	StateGLDepthFunc(s, GL_ALWAYS);
370 
371 	StateGLDisableF(s, GL_ALPHA_TEST, True);
372 	StateGLAlphaFunc(s, GL_GREATER, 0.5f);
373 
374 	StateGLDisableF(s, GL_CULL_FACE, True);
375 	StateGLShadeModel(s, GL_FLAT);
376 
377 	StateGLDisableF(s, GL_BLEND, True);
378 	StateGLDisableF(s, GL_FOG, True);
379 	StateGLDisableF(s, GL_TEXTURE_1D, True);
380 	StateGLDisableF(s, GL_TEXTURE_2D, True);
381 	StateGLDisableF(s, GL_COLOR_MATERIAL, True);
382 	StateGLDisableF(s, GL_LIGHTING, True);
383 	StateGLDisableF(s, GL_LIGHT0, True);
384 	StateGLDisableF(s, GL_LIGHT1, True);
385 	StateGLDisableF(s, GL_LIGHT2, True);
386 	StateGLDisableF(s, GL_LIGHT3, True);
387 	StateGLDisableF(s, GL_LIGHT4, True);
388 	StateGLDisableF(s, GL_LIGHT5, True);
389 	StateGLDisableF(s, GL_LIGHT6, True);
390 	StateGLDisableF(s, GL_LIGHT7, True);
391 	StateGLDisableF(s, GL_POINT_SMOOTH, True);
392 	StateGLDisableF(s, GL_LINE_SMOOTH, True);
393 	StateGLDisableF(s, GL_POLYGON_OFFSET_FILL, True);
394 	StateGLDisableF(s, GL_POLYGON_OFFSET_LINE, True);
395 	StateGLDisableF(s, GL_POLYGON_OFFSET_POINT, True);
396 	StateGLDisableF(s, GL_SCISSOR_TEST, True);
397 
398 	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
399 	glPixelStorei(GL_PACK_ALIGNMENT, 1);
400 }
401 
402 
403 /*
404  *	Returns the pointer to the object n on menu m.
405  *
406  *	Returns NULL on error.
407  */
SARMenuGetObject(sar_menu_struct * m,int n)408 void *SARMenuGetObject(sar_menu_struct *m, int n)
409 {
410 	if(m == NULL)
411 	    return(NULL);
412 	else if((n < 0) || (n >= m->total_objects))
413 	    return(NULL);
414 	else
415 	    return(m->object[n]);
416 }
417 
418 /*
419  *      Returns the object who's id matches the specified id.
420  */
SARMenuGetObjectByID(sar_menu_struct * m,int id,int * n)421 void *SARMenuGetObjectByID(sar_menu_struct *m, int id, int *n)
422 {
423 	int i;
424 	void *o;
425 
426 	if(n != NULL)
427 	    *n = -1;
428 
429 	if(m == NULL)
430 	    return(NULL);
431 
432 	for(i = 0; i < m->total_objects; i++)
433 	{
434 	    o = m->object[i];
435 	    if(o == NULL)
436 		continue;
437 
438 	    switch(SAR_MENU_OBJECT_TYPE(o))
439 	    {
440 	      case SAR_MENU_OBJECT_TYPE_BUTTON:
441 		if(SAR_MENU_BUTTON(o)->id == id)
442 		{
443 		    if(n != NULL)
444 			*n = i;
445 		    return(o);
446 		}
447 		break;
448 
449 	      case SAR_MENU_OBJECT_TYPE_LIST:
450 		if(SAR_MENU_LIST(o)->id == id)
451 		{
452 		    if(n != NULL)
453 			*n = i;
454 		    return(o);
455 		}
456 		break;
457 
458 	      case SAR_MENU_OBJECT_TYPE_MESSAGE_BOX:
459 		if(SAR_MENU_MESSAGE_BOX(o)->id == id)
460 		{
461 		    if(n != NULL)
462 			*n = i;
463 		    return(o);
464 		}
465 		break;
466 
467 	      case SAR_MENU_OBJECT_TYPE_MDISPLAY:
468 		if(SAR_MENU_MDISPLAY(o)->id == id)
469 		{
470 		    if(n != NULL)
471 			*n = i;
472 		    return(o);
473 		}
474 		break;
475 
476 	      case SAR_MENU_OBJECT_TYPE_SWITCH:
477 		if(SAR_MENU_SWITCH(o)->id == id)
478 		{
479 		    if(n != NULL)
480 			*n = i;
481 		    return(o);
482 		}
483 		break;
484 
485 	      case SAR_MENU_OBJECT_TYPE_SPIN:
486 		if(SAR_MENU_SPIN(o)->id == id)
487 		{
488 		    if(n != NULL)
489 			*n = i;
490 		    return(o);
491 		}
492 		break;
493 
494 	      case SAR_MENU_OBJECT_TYPE_SLIDER:
495 		if(SAR_MENU_SLIDER(o)->id == id)
496 		{
497 		    if(n != NULL)
498 			*n = i;
499 		    return(o);
500 		}
501 		break;
502 
503 	      case SAR_MENU_OBJECT_TYPE_MAP:
504 		if(SAR_MENU_MAP(o)->id == id)
505 		{
506 		    if(n != NULL)
507 			*n = i;
508 		    return(o);
509 		}
510 		break;
511 
512 	      case SAR_MENU_OBJECT_TYPE_OBJVIEW:
513 		if(SAR_MENU_OBJVIEW(o)->id == id)
514 		{
515 		    if(n != NULL)
516 			*n = i;
517 		    return(o);
518 		}
519 		break;
520 	    }
521 	}
522 
523 	return(NULL);
524 }
525 
526 /*
527  *	Returns True if the object n on menu m is sensitive.
528  */
SARMenuObjectIsSensitive(sar_menu_struct * m,int n)529 Boolean SARMenuObjectIsSensitive(sar_menu_struct *m, int n)
530 {
531 	void *o = SARMenuGetObject(m, n);
532 	if(o == NULL)
533 	    return(False);
534 
535 	switch(SAR_MENU_OBJECT_TYPE(o))
536 	{
537 	  case SAR_MENU_OBJECT_TYPE_LABEL:
538 	    return(SAR_MENU_LABEL(o)->sensitive);
539 	  case SAR_MENU_OBJECT_TYPE_BUTTON:
540 	    return(SAR_MENU_BUTTON(o)->sensitive);
541 	  case SAR_MENU_OBJECT_TYPE_PROGRESS:
542 	    return(SAR_MENU_PROGRESS(o)->sensitive);
543 	  case SAR_MENU_OBJECT_TYPE_MESSAGE_BOX:
544 	    return(SAR_MENU_MESSAGE_BOX(o)->sensitive);
545 	  case SAR_MENU_OBJECT_TYPE_LIST:
546 	    return(SAR_MENU_LIST(o)->sensitive);
547 	  case SAR_MENU_OBJECT_TYPE_MDISPLAY:
548 	    return(SAR_MENU_MDISPLAY(o)->sensitive);
549 	  case SAR_MENU_OBJECT_TYPE_SWITCH:
550 	    return(SAR_MENU_SWITCH(o)->sensitive);
551 	  case SAR_MENU_OBJECT_TYPE_SPIN:
552 	    return(SAR_MENU_SPIN(o)->sensitive);
553 	  case SAR_MENU_OBJECT_TYPE_SLIDER:
554 	    return(SAR_MENU_SLIDER(o)->sensitive);
555 	  case SAR_MENU_OBJECT_TYPE_MAP:
556 	    return(SAR_MENU_MAP(o)->sensitive);
557 	  case SAR_MENU_OBJECT_TYPE_OBJVIEW:
558 	    return(SAR_MENU_OBJVIEW(o)->sensitive);
559 	  default:
560 	    return(False);
561 	}
562 }
563 
564 
565 /*
566  *	Creates a new menu.
567  */
SARMenuNew(sar_menu_type type,const char * name,const char * bg_image)568 sar_menu_struct *SARMenuNew(
569 	sar_menu_type type, const char *name, const char *bg_image
570 )
571 {
572 	sar_menu_struct *m = SAR_MENU(calloc(
573 	    1, sizeof(sar_menu_struct)
574 	));
575 	if(m == NULL)
576 	    return(NULL);
577 
578 	m->type = type;
579 	m->name = STRDUP(name);
580 	m->always_full_redraw = False;
581 	m->bg_image_path = STRDUP(bg_image);
582 	m->bg_image = NULL;
583 
584 	m->object = NULL;
585 	m->total_objects = 0;
586 	m->selected_object = -1;
587 
588 	return(m);
589 }
590 
591 /*
592  *	Loads background image as needed on menu m.
593  */
SARMenuLoadBackgroundImage(sar_menu_struct * m)594 void SARMenuLoadBackgroundImage(sar_menu_struct *m)
595 {
596 	const char *path;
597 
598 	if(m == NULL)
599 	    return;
600 
601 	/* Get background image file path */
602 	path = m->bg_image_path;
603 	if(path == NULL)
604 	    return;
605 
606 	/* Load new background image only if the menu does not already
607 	 * have one
608 	 */
609 	if(m->bg_image == NULL)
610 	    m->bg_image = SARImageNewFromFile(path);
611 }
612 
613 /*
614  *      Unloads background image as needed on menu m.
615  */
SARMenuUnloadBackgroundImage(sar_menu_struct * m)616 void SARMenuUnloadBackgroundImage(sar_menu_struct *m)
617 {
618 	if(m == NULL)
619 	    return;
620 
621 	SARImageDelete(m->bg_image);
622 	m->bg_image = NULL;
623 }
624 
625 /*
626  *	Deletes the Menu.
627  */
SARMenuDelete(sar_menu_struct * m)628 void SARMenuDelete(sar_menu_struct *m)
629 {
630 	int i;
631 
632 	if(m == NULL)
633 	    return;
634 
635 	/* Delete all objects on this menu */
636 	for(i = 0; i < m->total_objects; i++)
637 	    SARMenuObjectDelete(m, i);
638 	free(m->object);
639 	m->object = NULL;
640 	m->total_objects = 0;
641 
642 	free(m->name);
643 	m->name = NULL;
644 
645 	free(m->bg_image_path);
646 	m->bg_image_path = NULL;
647 
648 	SARImageDelete(m->bg_image);
649 	m->bg_image = NULL;
650 
651 	free(m);
652 }
653 
654 /*
655  *	Allocates a new label on menu m.
656  *
657  *	Returns its index number or -1 on error.
658  */
SARMenuLabelNew(sar_menu_struct * m,float x,float y,int width,int height,const char * label,sar_menu_color_struct * fg_color,GWFont * font,const sar_image_struct * image)659 int SARMenuLabelNew(
660 	sar_menu_struct *m,
661 	float x, float y,
662 	int width, int height,
663 	const char *label,
664 	sar_menu_color_struct *fg_color,
665 	GWFont *font,
666 	const sar_image_struct *image
667 )
668 {
669 	int i, n;
670 	sar_menu_label_struct *label_ptr;
671 
672 
673 	if(m == NULL)
674 	    return(-1);
675 
676 	if(m->total_objects < 0)
677 	    m->total_objects = 0;
678 
679 	for(i = 0; i < m->total_objects; i++)
680 	{
681 	    if(m->object[i] == NULL)
682 		break;
683 	}
684 	if(i < m->total_objects)
685 	{
686 	    n = i;
687 	}
688 	else
689 	{
690 	    n = m->total_objects;
691 	    m->total_objects = n + 1;
692 	    m->object = (void **)realloc(
693 		m->object,
694 		m->total_objects * sizeof(void *)
695 	    );
696 	    if(m->object == NULL)
697 	    {
698 		m->total_objects = 0;
699 		return(-3);
700 	    }
701 	}
702 
703 	/* Allocate structure */
704 	m->object[n] = label_ptr = SAR_MENU_LABEL(calloc(
705 	    1, sizeof(sar_menu_label_struct)
706 	));
707 	if(label_ptr == NULL)
708 	    return(-3);
709 
710 	/* Load label values */
711 	label_ptr->type = SAR_MENU_OBJECT_TYPE_LABEL;
712 	label_ptr->x = x;
713 	label_ptr->y = y;
714 	label_ptr->width = width;
715 	label_ptr->height = height;
716 	label_ptr->sensitive = True;
717 	label_ptr->image = image;
718 	memcpy(&label_ptr->color, fg_color, sizeof(sar_menu_color_struct));
719 	label_ptr->font = font;
720 	label_ptr->label = STRDUP(label);
721 	label_ptr->align = SAR_MENU_LABEL_ALIGN_CENTER;
722 
723 	/* Select this object if it is the first one */
724 	if(m->total_objects == 1)
725 	    m->selected_object = 0;
726 
727 	return(n);
728 }
729 
730 /*
731  *	Allocates a new button on menu m.
732  *
733  *	Returns its index number or -1 on error.
734  */
SARMenuButtonNew(sar_menu_struct * m,float x,float y,int width,int height,const char * label,sar_menu_color_struct * fg_color,GWFont * font,const sar_image_struct * unarmed_image,const sar_image_struct * armed_image,const sar_image_struct * highlighted_image,void * client_data,int id,void (* func_cb)(void *,int,void *))735 int SARMenuButtonNew(
736 	sar_menu_struct *m,
737 	float x, float y,
738 	int width, int height,
739 	const char *label,
740 	sar_menu_color_struct *fg_color, GWFont *font,
741 	const sar_image_struct *unarmed_image,
742 	const sar_image_struct *armed_image,
743 	const sar_image_struct *highlighted_image,
744 	void *client_data, int id,
745 	void (*func_cb)(void *, int, void *)
746 )
747 {
748 	int i, n;
749 	sar_menu_button_struct *button;
750 
751 
752 	if(m == NULL)
753 	    return(-1);
754 
755 	if(m->total_objects < 0)
756 	    m->total_objects = 0;
757 
758 	for(i = 0; i < m->total_objects; i++)
759 	{
760 	    if(m->object[i] == NULL)
761 		break;
762 	}
763 	if(i < m->total_objects)
764 	{
765 	    n = i;
766 	}
767 	else
768 	{
769 	    n = m->total_objects;
770 	    m->total_objects = n + 1;
771 	    m->object = (void **)realloc(
772 		m->object,
773 		m->total_objects * sizeof(void *)
774 	    );
775 	    if(m->object == NULL)
776 	    {
777 		m->total_objects = 0;
778 		return(-3);
779 	    }
780 	}
781 
782 	/* Allocate structure */
783 	m->object[n] = button = SAR_MENU_BUTTON(calloc(
784 	    1, sizeof(sar_menu_button_struct)
785 	));
786 	if(button == NULL)
787 	    return(-3);
788 
789 	/* Load button values */
790 	button->type = SAR_MENU_OBJECT_TYPE_BUTTON;
791 	button->x = x;
792 	button->y = y;
793 	button->width = width;
794 	button->height = height;
795 	button->sensitive = True;
796 	button->unarmed_image = unarmed_image;
797 	button->armed_image = armed_image;
798 	button->highlighted_image = highlighted_image;
799 	memcpy(&button->color, fg_color, sizeof(sar_menu_color_struct));
800 	button->font = font;
801 	button->label = STRDUP(label);
802 	button->client_data = client_data;
803 	button->id = id;
804 	button->func_cb = func_cb;
805 
806 	/* Select this object if it is the first one */
807 	if(m->total_objects == 1)
808 	    m->selected_object = 0;
809 
810 	return(n);
811 }
812 
813 /*
814  *      Allocates a new progress bar on menu m.
815  *
816  *      Returns its index number or -1 on error.
817  */
SARMenuProgressNew(sar_menu_struct * m,float x,float y,int width,int height,const char * label,sar_menu_color_struct * fg_color,GWFont * font,const sar_image_struct * bg_image,const sar_image_struct * fg_image,float progress)818 int SARMenuProgressNew(
819 	sar_menu_struct *m,
820 	float x, float y,
821 	int width, int height,
822 	const char *label,
823 	sar_menu_color_struct *fg_color, GWFont *font,
824 	const sar_image_struct *bg_image,
825 	const sar_image_struct *fg_image,
826 	float progress
827 )
828 {
829 	int i, n;
830 	sar_menu_progress_struct *pb;
831 
832 
833 	if(m == NULL)
834 	    return(-1);
835 
836 	if(m->total_objects < 0)
837 	    m->total_objects = 0;
838 
839 	for(i = 0; i < m->total_objects; i++)
840 	{
841 	    if(m->object[i] == NULL)
842 		break;
843 	}
844 	if(i < m->total_objects)
845 	{
846 	    n = i;
847 	}
848 	else
849 	{
850 	    n = m->total_objects;
851 	    m->total_objects = n + 1;
852 	    m->object = (void **)realloc(
853 		m->object,
854 		m->total_objects * sizeof(void *)
855 	    );
856 	    if(m->object == NULL)
857 	    {
858 		m->total_objects = 0;
859 		return(-3);
860 	    }
861 	}
862 
863 	/* Allocate structure */
864 	m->object[n] = pb = SAR_MENU_PROGRESS(calloc(
865 	    1, sizeof(sar_menu_progress_struct)
866 	));
867 	if(pb == NULL)
868 	    return(-3);
869 
870 	/* Load progress bar values */
871 	pb->type = SAR_MENU_OBJECT_TYPE_PROGRESS;
872 	pb->x = x;
873 	pb->y = y;
874 	pb->width = width;
875 	pb->height = height;
876 	pb->sensitive = True;
877 	pb->bg_image = bg_image;
878 	pb->fg_image = fg_image;
879 	memcpy(&pb->color, fg_color, sizeof(sar_menu_color_struct));
880 	pb->font = font;
881 	pb->label = STRDUP(label);
882 	pb->progress = progress;
883 
884 	/* Select this object if it is the first one */
885 	if(m->total_objects == 1)
886 	    m->selected_object = 0;
887 
888 	return(n);
889 }
890 
891 /*
892  *	Sets the new value for the progress bar.
893  */
SARMenuProgressSet(gw_display_struct * display,sar_menu_struct * m,int n,float progress,Boolean redraw)894 void SARMenuProgressSet(
895 	gw_display_struct *display, sar_menu_struct *m, int n,
896 	float progress, Boolean redraw
897 )
898 {
899 	Boolean changed = False;
900 	sar_menu_progress_struct *pb = SAR_MENU_PROGRESS(
901 	    SARMenuGetObject(m, n)
902 	);
903 	if(!SAR_MENU_IS_PROGRESS(pb))
904 	    return;
905 
906 	if(pb->progress != progress)
907 	{
908 	    pb->progress = CLIP(progress, 0.0f, 1.0f);
909 	    changed = True;
910 	}
911 
912 	if(changed && redraw)
913 	    DO_REDRAW_OBJECT(display, m, n)
914 }
915 
916 
917 /*
918  *	Create message box on menu m.
919  */
SARMenuMessageBoxNew(sar_menu_struct * m,float x,float y,float width,float height,sar_menu_color_struct * fg_color,GWFont * font,const sar_image_struct ** bg_image,void * client_data,int id,const char * message)920 int SARMenuMessageBoxNew(
921 	sar_menu_struct *m,
922 	float x, float y,
923 	float width, float height,
924 	sar_menu_color_struct *fg_color,
925 	GWFont *font,
926 	const sar_image_struct **bg_image,	/* Pointer to 9 images */
927 	void *client_data, int id,
928 	const char *message
929 )
930 {
931 	int i, n;
932 	sar_menu_color_struct *c;
933 	sar_menu_message_box_struct *mesgbox;
934 
935 
936 	if(m == NULL)
937 	    return(-1);
938 
939 	if(m->total_objects < 0)
940 	    m->total_objects = 0;
941 
942 	for(i = 0; i < m->total_objects; i++)
943 	{
944 	    if(m->object[i] == NULL)
945 		break;
946 	}
947 	if(i < m->total_objects)
948 	{
949 	    n = i;
950 	}
951 	else
952 	{
953 	    n = m->total_objects;
954 	    m->total_objects = n + 1;
955 	    m->object = (void **)realloc(
956 		m->object,
957 		m->total_objects * sizeof(void *)
958 	    );
959 	    if(m->object == NULL)
960 	    {
961 		m->total_objects = 0;
962 		return(-3);
963 	    }
964 	}
965 
966 	/* Allocate structure */
967 	m->object[n] = mesgbox = SAR_MENU_MESSAGE_BOX(calloc(
968 	    1, sizeof(sar_menu_message_box_struct)
969 	));
970 	if(mesgbox == NULL)
971 	    return(-3);
972 
973 	/* Load message box values */
974 	mesgbox->type = SAR_MENU_OBJECT_TYPE_MESSAGE_BOX;
975 	mesgbox->id = id;
976 	mesgbox->client_data = client_data;
977 	mesgbox->x = x;
978 	mesgbox->y = y;
979 	mesgbox->width = width;
980 	mesgbox->height = height;
981 	mesgbox->sensitive = True;
982 	mesgbox->bg_image = bg_image;
983 	memcpy(&mesgbox->color, fg_color, sizeof(sar_menu_color_struct));
984 	c = &mesgbox->bold_color;
985 	c->a = 1.0f;
986 	c->r = 1.0f;
987 	c->g = 1.0f;
988 	c->b = 0.0f;
989 	c = &mesgbox->underline_color;
990 	c->a = 1.0f;
991 	c->r = 0.5f;
992 	c->g = 0.5f;
993 	c->b = 1.0f;
994 	mesgbox->font = font;
995 	mesgbox->message = STRDUP(message);
996 	mesgbox->scrolled_line = 0;
997 
998 	/* Select this object if it is the first one */
999 	if(m->total_objects == 1)
1000 	    m->selected_object = 0;
1001 
1002 	return(n);
1003 }
1004 
1005 /*
1006  *	Set the message for the message box.
1007  */
SARMenuMessageBoxSet(gw_display_struct * display,sar_menu_struct * m,int n,const char * message,Boolean redraw)1008 void SARMenuMessageBoxSet(
1009 	gw_display_struct *display, sar_menu_struct *m, int n,
1010 	const char *message, Boolean redraw
1011 )
1012 {
1013 	sar_menu_message_box_struct *mesgbox = SAR_MENU_MESSAGE_BOX(
1014 	    SARMenuGetObject(m, n)
1015 	);
1016 	if(!SAR_MENU_IS_MESSAGE_BOX(mesgbox))
1017 	    return;
1018 
1019 	free(mesgbox->message);
1020 	mesgbox->message = STRDUP(message);
1021 
1022 	mesgbox->scrolled_line = 0;
1023 
1024 	if(redraw)
1025 	    DO_REDRAW_OBJECT(display, m, n)
1026 }
1027 
1028 
1029 /*
1030  *	Create list on menu m.
1031  *
1032  *	Returns its index number or -1 on error.
1033  */
SARMenuListNew(sar_menu_struct * m,float x,float y,float width,float height,sar_menu_color_struct * fg_color,GWFont * font,const char * label,const sar_image_struct ** bg_image,void * client_data,int id,void (* select_cb)(void *,int,void *,int,void *,void *),void (* activate_cb)(void *,int,void *,int,void *,void *))1034 int SARMenuListNew(
1035 	sar_menu_struct *m,
1036 	float x, float y,
1037 	float width, float height,
1038 	sar_menu_color_struct *fg_color, GWFont *font,
1039 	const char *label,
1040 	const sar_image_struct **bg_image,	/* Pointer to 9 images */
1041 	void *client_data, int id,
1042 	void (*select_cb)(void *, int, void *, int, void *, void *),
1043 	void (*activate_cb)(void *, int, void *, int, void *, void *)
1044 )
1045 {
1046 	int i, n;
1047 	sar_menu_list_struct *list;
1048 
1049 
1050 	if(m == NULL)
1051 	    return(-1);
1052 
1053 	if(m->total_objects < 0)
1054 	    m->total_objects = 0;
1055 
1056 	for(i = 0; i < m->total_objects; i++)
1057 	{
1058 	    if(m->object[i] == NULL)
1059 		break;
1060 	}
1061 	if(i < m->total_objects)
1062 	{
1063 	    n = i;
1064 	}
1065 	else
1066 	{
1067 	    n = m->total_objects;
1068 	    m->total_objects = n + 1;
1069 	    m->object = (void **)realloc(
1070 		m->object,
1071 		m->total_objects * sizeof(void *)
1072 	    );
1073 	    if(m->object == NULL)
1074 	    {
1075 		m->total_objects = 0;
1076 		return(-3);
1077 	    }
1078 	}
1079 
1080 	/* Allocate structure */
1081 	m->object[n] = list = SAR_MENU_LIST(calloc(
1082 	    1, sizeof(sar_menu_list_struct)
1083 	));
1084 	if(list == NULL)
1085 	    return(-3);
1086 
1087 	/* Set values */
1088 	list->type = SAR_MENU_OBJECT_TYPE_LIST;
1089 	list->id = id;
1090 	list->client_data = client_data;
1091 	list->x = x;
1092 	list->y = y;
1093 	list->width = width;
1094 	list->height = height;
1095 	list->sensitive = True;
1096 	list->bg_image = bg_image;
1097 	memcpy(&list->color, fg_color, sizeof(sar_menu_color_struct));
1098 	list->font = font;
1099 	list->label = STRDUP(label);
1100 	list->item = NULL;
1101 	list->total_items = 0;
1102 	list->items_visable = 0;	/* Calculated when drawn or managed */
1103 	list->scrolled_item = 0;
1104 	list->selected_item = -1;
1105 	list->select_cb = select_cb;
1106 	list->activate_cb = activate_cb;
1107 
1108 	/* Select this object if it is the first one */
1109 	if(m->total_objects == 1)
1110 	    m->selected_object = 0;
1111 
1112 	return(n);
1113 }
1114 
1115 /*
1116  *	Appends item to the list object n on menu m.
1117  *
1118  *	Returns the item number or -1 on error.
1119  */
SARMenuListAppendItem(sar_menu_struct * m,int n,const char * name,void * client_data,sar_menu_flags_t flags)1120 int SARMenuListAppendItem(
1121 	sar_menu_struct *m, int n,
1122 	const char *name,
1123 	void *client_data,
1124 	sar_menu_flags_t flags
1125 )
1126 {
1127 	int item_num;
1128 	sar_menu_list_item_struct *item;
1129 	sar_menu_list_struct *list = SAR_MENU_LIST(SARMenuGetObject(m, n));
1130 	if(!SAR_MENU_IS_LIST(list))
1131 	    return(-2);
1132 
1133 	item_num = MAX(list->total_items, 0);
1134 	list->total_items = item_num + 1;
1135 	list->item = (sar_menu_list_item_struct **)realloc(
1136 	    list->item,
1137 	    list->total_items * sizeof(sar_menu_list_item_struct *)
1138 	);
1139 	if(list->item == NULL)
1140 	{
1141 	    list->total_items = 0;
1142 	    return(-3);
1143 	}
1144 
1145 	list->item[item_num] = item = SAR_MENU_LIST_ITEM(calloc(
1146 	    1, sizeof(sar_menu_list_item_struct)
1147 	));
1148 	if(item == NULL)
1149 	    return(-3);
1150 
1151 	/* Set item values */
1152 	item->flags = flags;
1153 	item->name = STRDUP(name);
1154 	item->client_data = client_data;
1155 
1156 	return(item_num);
1157 }
1158 
1159 /*
1160  *	Returns the pointer to the item number i or -1 on error.
1161  */
SARMenuListGetItemByNumber(sar_menu_list_struct * list,int i)1162 sar_menu_list_item_struct *SARMenuListGetItemByNumber(
1163 	sar_menu_list_struct *list, int i
1164 )
1165 {
1166 	if(list == NULL)
1167 	    return(NULL);
1168 	else if((i < 0) || (i >= list->total_items))
1169 	    return(NULL);
1170 	else
1171 	    return(list->item[i]);
1172 }
1173 
1174 /*
1175  *	Selects the list item specified by i.
1176  */
SARMenuListSelect(gw_display_struct * display,sar_menu_struct * m,int n,int i,Boolean scroll,Boolean redraw)1177 void SARMenuListSelect(
1178 	gw_display_struct *display, sar_menu_struct *m, int n,
1179 	int i,
1180 	Boolean scroll, Boolean redraw
1181 )
1182 {
1183 	Boolean selection_changed = False;
1184 	sar_menu_list_item_struct *item;
1185 	sar_menu_list_struct *list = SAR_MENU_LIST(SARMenuGetObject(m, n));
1186 	if(!SAR_MENU_IS_LIST(list))
1187 	    return;
1188 
1189 	if((i < 0) || (i >= list->total_items))
1190 	    return;
1191 
1192 	/* Change in selected item? */
1193 	if(i != list->selected_item)
1194 	{
1195 	    list->selected_item = i;
1196 	    selection_changed = True;
1197 	}
1198 
1199 	/* Scroll to selected item? */
1200 	if(scroll)
1201 	{
1202 	    list->scrolled_item = i;
1203 	    if((i + list->items_visable) > list->total_items)
1204 		list->scrolled_item = MAX(
1205 		    list->total_items - list->items_visable,
1206 		    0
1207 		);
1208 	    selection_changed = True;
1209 	}
1210 
1211 	/* Redraw as needed and requested */
1212 	if(selection_changed && redraw)
1213 	    DO_REDRAW_OBJECT(display, m, n)
1214 
1215 	/* Call select callback */
1216 	item = SARMenuListGetItemByNumber(list, i);
1217 	if((item != NULL) && selection_changed &&
1218 	   (list->select_cb != NULL)
1219 	)
1220 	    list->select_cb(
1221 		list,			/* This Object */
1222 		list->id,		/* ID Code */
1223 		list->client_data,	/* Data */
1224 		list->selected_item,	/* Selected Item */
1225 		item,			/* Item */
1226 		item->client_data	/* Item Data */
1227 	    );
1228 }
1229 
1230 /*
1231  *	Deletes all items allocated on list object n on menu m.
1232  *
1233  *	Client data on each item should have been taken care of
1234  *	by the calling function.
1235  */
SARMenuListDeleteAllItems(sar_menu_struct * m,int n)1236 void SARMenuListDeleteAllItems(sar_menu_struct *m, int n)
1237 {
1238 	int i;
1239 	sar_menu_list_item_struct *item;
1240 	sar_menu_list_struct *list = SAR_MENU_LIST(SARMenuGetObject(m, n));
1241 	if(!SAR_MENU_IS_LIST(list))
1242 	    return;
1243 
1244 	/* Iterate through each item on the list object */
1245 	for(i = 0; i < list->total_items; i++)
1246 	{
1247 	    item = list->item[i];
1248 	    if(item == NULL)
1249 		continue;
1250 
1251 	    free(item->name);
1252 	    item->name = NULL;
1253 
1254 	    /* Calling function needs to free client_data */
1255 	    if(item->client_data != NULL)
1256 		fprintf(
1257 		    stderr,
1258 "SARMenuListDeleteAllItems(): Client data on item %i on list object %i of menu \"%s\" is not NULL.\n",
1259 		    i, n, m->name
1260 		);
1261 
1262 	    free(item);
1263 	    list->item[i] = item = NULL;
1264 	}
1265 	free(list->item);
1266 	list->item = NULL;
1267 	list->total_items = 0;
1268 	list->scrolled_item = 0;
1269 	list->selected_item = -1;
1270 }
1271 
1272 
1273 /*
1274  *	Create multi-purpose display object on menu m.
1275  *
1276  *	Returns its index number or -1 on error.
1277  */
SARMenuMDisplayNew(sar_menu_struct * m,float x,float y,float width,float height,const sar_image_struct ** bg_image,void * client_data,int id,void (* draw_cb)(void *,void *,void *,int,void *,int,int,int,int))1278 int SARMenuMDisplayNew(
1279 	sar_menu_struct *m,
1280 	float x, float y,
1281 	float width, float height,
1282 	const sar_image_struct **bg_image,      /* Pointer to 9 images */
1283 	void *client_data, int id,
1284 	void (*draw_cb)(
1285 		void *,         /* Display */
1286 		void *,         /* Menu */
1287 		void *,         /* This Object */
1288 		int,            /* ID Code */
1289 		void *,         /* Data */
1290 		int, int, int, int      /* x_min, y_min, x_max, y_max */
1291 	)
1292 )
1293 {
1294 	int i, n;
1295 	sar_menu_mdisplay_struct *mdpy;
1296 
1297 
1298 	if(m == NULL)
1299 	    return(-1);
1300 
1301 	if(m->total_objects < 0)
1302 	    m->total_objects = 0;
1303 
1304 	for(i = 0; i < m->total_objects; i++)
1305 	{
1306 	    if(m->object[i] == NULL)
1307 		break;
1308 	}
1309 	if(i < m->total_objects)
1310 	{
1311 	    n = i;
1312 	}
1313 	else
1314 	{
1315 	    n = m->total_objects;
1316 	    m->total_objects = n + 1;
1317 	    m->object = (void **)realloc(
1318 		m->object,
1319 		m->total_objects * sizeof(void *)
1320 	    );
1321 	    if(m->object == NULL)
1322 	    {
1323 		m->total_objects = 0;
1324 		return(-3);
1325 	    }
1326 	}
1327 
1328 	/* Allocate structure */
1329 	m->object[n] = mdpy = SAR_MENU_MDISPLAY(calloc(
1330 	    1, sizeof(sar_menu_mdisplay_struct)
1331 	));
1332 	if(mdpy == NULL)
1333 	   return(-3);
1334 
1335 	/* Set mdisplay values */
1336 	mdpy->type = SAR_MENU_OBJECT_TYPE_MDISPLAY;
1337 	mdpy->x = x;
1338 	mdpy->y = y;
1339 	mdpy->width = width;
1340 	mdpy->height = height;
1341 	mdpy->sensitive = True;
1342 	mdpy->bg_image = bg_image;
1343 	mdpy->client_data = client_data;
1344 	mdpy->id = id;
1345 	mdpy->draw_cb = draw_cb;
1346 
1347 	/* Select this object if it is the first one */
1348 	if(m->total_objects == 1)
1349 	    m->selected_object = 0;
1350 
1351 	return(n);
1352 }
1353 
1354 /*
1355  *	Redraws the multi-purpose display.
1356  */
SARMenuMDisplayDraw(gw_display_struct * display,sar_menu_struct * m,int n)1357 void SARMenuMDisplayDraw(
1358 	gw_display_struct *display, sar_menu_struct *m, int n
1359 )
1360 {
1361 
1362 }
1363 
1364 
1365 /*
1366  *	Create switch object on menu m.
1367  *
1368  *	Returns its index number or -1 on error.
1369  */
SARMenuSwitchNew(sar_menu_struct * m,float x,float y,int width,int height,sar_menu_color_struct * fg_color,GWFont * font,const char * label,const sar_image_struct * bg_image,const sar_image_struct * switch_off_image,const sar_image_struct * switch_on_image,Boolean state,void * client_data,int id,void (* switch_cb)(void *,int,void *,Boolean))1370 int SARMenuSwitchNew(
1371 	sar_menu_struct *m,
1372 	float x, float y,
1373 	int width, int height,
1374 	sar_menu_color_struct *fg_color, GWFont *font,
1375 	const char *label,
1376 	const sar_image_struct *bg_image,
1377 	const sar_image_struct *switch_off_image,
1378 	const sar_image_struct *switch_on_image,
1379 	Boolean state,
1380 	void *client_data, int id,
1381 	void (*switch_cb)(void *, int, void *, Boolean)
1382 )
1383 {
1384 	int i, n;
1385 	sar_menu_switch_struct *sw;
1386 
1387 
1388 	if(m == NULL)
1389 	    return(-1);
1390 
1391 	if(m->total_objects < 0)
1392 	    m->total_objects = 0;
1393 
1394 	for(i = 0; i < m->total_objects; i++)
1395 	{
1396 	    if(m->object[i] == NULL)
1397 		break;
1398 	}
1399 	if(i < m->total_objects)
1400 	{
1401 	    n = i;
1402 	}
1403 	else
1404 	{
1405 	    n = m->total_objects;
1406 	    m->total_objects = n + 1;
1407 	    m->object = (void **)realloc(
1408 		m->object,
1409 		m->total_objects * sizeof(void *)
1410 	    );
1411 	    if(m->object == NULL)
1412 	    {
1413 		m->total_objects = 0;
1414 		return(-3);
1415 	    }
1416 	}
1417 
1418 	/* Allocate structure */
1419 	m->object[n] = sw = SAR_MENU_SWITCH(calloc(
1420 	    1, sizeof(sar_menu_switch_struct)
1421 	));
1422 	if(sw == NULL)
1423 	    return(-3);
1424 
1425 	/* Set switch values */
1426 	sw->type = SAR_MENU_OBJECT_TYPE_SWITCH;
1427 	sw->x = x;
1428 	sw->y = y;
1429 	sw->width = width;
1430 	sw->height = height;
1431 	sw->sensitive = True;
1432 	sw->bg_image = bg_image;
1433 	sw->switch_off_image = switch_off_image;
1434 	sw->switch_on_image = switch_on_image;
1435 	memcpy(&sw->color, fg_color, sizeof(sar_menu_color_struct));
1436 	sw->font = font;
1437 	sw->label = STRDUP(label);
1438 	sw->state = state;
1439 	sw->client_data = client_data;
1440 	sw->id = id;
1441 	sw->switch_cb = switch_cb;
1442 
1443 	/* Select this object if it is the first one */
1444 	if(m->total_objects == 1)
1445 	    m->selected_object = 0;
1446 
1447 	return(n);
1448 }
1449 
1450 /*
1451  *	Get state of the switch object n on menu m.
1452  */
SARMenuSwitchGetValue(sar_menu_struct * m,int n)1453 Boolean SARMenuSwitchGetValue(sar_menu_struct *m, int n)
1454 {
1455 	sar_menu_switch_struct *sw = SAR_MENU_SWITCH(
1456 	    SARMenuGetObject(m, n)
1457 	);
1458 	if(!SAR_MENU_IS_SWITCH(sw))
1459 	    return(False);
1460 
1461 	return(sw->state);
1462 }
1463 
1464 /*
1465  *	Set state of switch object n on menu m.
1466  */
SARMenuSwitchSetValue(gw_display_struct * display,sar_menu_struct * m,int n,Boolean state,Boolean redraw)1467 void SARMenuSwitchSetValue(
1468 	gw_display_struct *display, sar_menu_struct *m, int n,
1469 	Boolean state, Boolean redraw
1470 )
1471 {
1472 	Boolean change = False;
1473 	sar_menu_switch_struct *sw = SAR_MENU_SWITCH(
1474 	    SARMenuGetObject(m, n)
1475 	);
1476 	if(!SAR_MENU_IS_SWITCH(sw))
1477 	    return;
1478 
1479 	if(sw->state != state)
1480 	{
1481 	    sw->state = state;
1482 	    change = True;
1483 	}
1484 
1485 	if(change)
1486 	{
1487 	    if(redraw)
1488 		DO_REDRAW_OBJECT(display, m, n)
1489 
1490 	    if(sw->switch_cb != NULL)
1491 		sw->switch_cb(
1492 		    sw,			/* This Object */
1493 		    sw->id,		/* ID Code */
1494 		    sw->client_data,	/* Data */
1495 		    sw->state		/* Value */
1496 		);
1497 	}
1498 }
1499 
1500 
1501 /*
1502  *	Create spin object on menu m.
1503  *
1504  *	Returns the object's index or -1 on error.
1505  */
SARMenuSpinNew(sar_menu_struct * m,float x,float y,float width,float height,sar_menu_color_struct * label_color,sar_menu_color_struct * value_color,GWFont * font,GWFont * value_font,const char * label,const sar_image_struct * label_image,const sar_image_struct * value_image,const sar_image_struct * dec_armed_image,const sar_image_struct * dec_unarmed_image,const sar_image_struct * inc_armed_image,const sar_image_struct * inc_unarmed_image,void * client_data,int id,void (* change_cb)(void *,int,void *,char *))1506 int SARMenuSpinNew(
1507 	sar_menu_struct *m,
1508 	float x, float y,
1509 	float width, float height,
1510 	sar_menu_color_struct *label_color,
1511 	sar_menu_color_struct *value_color,
1512 	GWFont *font, GWFont *value_font,
1513 	const char *label,
1514 	const sar_image_struct *label_image,
1515 	const sar_image_struct *value_image,
1516 	const sar_image_struct *dec_armed_image,
1517 	const sar_image_struct *dec_unarmed_image,
1518 	const sar_image_struct *inc_armed_image,
1519 	const sar_image_struct *inc_unarmed_image,
1520 	void *client_data, int id,
1521 	void (*change_cb)(void *, int, void *, char *)
1522 )
1523 {
1524 	int i, n;
1525 	sar_menu_spin_struct *spin;
1526 
1527 
1528 	if(m == NULL)
1529 	    return(-1);
1530 
1531 	if(m->total_objects < 0)
1532 	    m->total_objects = 0;
1533 
1534 	for(i = 0; i < m->total_objects; i++)
1535 	{
1536 	    if(m->object[i] == NULL)
1537 		break;
1538 	}
1539 	if(i < m->total_objects)
1540 	{
1541 	    n = i;
1542 	}
1543 	else
1544 	{
1545 	    n = m->total_objects;
1546 	    m->total_objects = n + 1;
1547 	    m->object = (void **)realloc(
1548 		m->object,
1549 		m->total_objects * sizeof(void *)
1550 	    );
1551 	    if(m->object == NULL)
1552 	    {
1553 		m->total_objects = 0;
1554 		return(-3);
1555 	    }
1556 	}
1557 
1558 	/* Allocate structure */
1559 	m->object[n] = spin = SAR_MENU_SPIN(calloc(
1560 	    1, sizeof(sar_menu_spin_struct)
1561 	));
1562 	if(spin == NULL)
1563 	    return(-3);
1564 
1565 	/* Set spin values */
1566 	spin->type = SAR_MENU_OBJECT_TYPE_SPIN;
1567 	spin->x = x;
1568 	spin->y = y;
1569 	spin->width = width;
1570 	spin->height = height;
1571 	spin->sensitive = True;
1572 	spin->label_image = label_image;
1573 	spin->value_image = value_image;
1574 	spin->dec_armed_image = dec_armed_image;
1575 	spin->dec_unarmed_image = dec_unarmed_image;
1576 	spin->inc_armed_image = inc_armed_image;
1577 	spin->inc_unarmed_image = inc_unarmed_image;
1578 	memcpy(&spin->label_color, label_color, sizeof(sar_menu_color_struct));
1579 	memcpy(&spin->value_color, value_color, sizeof(sar_menu_color_struct));
1580 	spin->font = font;
1581 	spin->value_font = value_font;
1582 	spin->dec_state = SAR_MENU_BUTTON_STATE_UNARMED;
1583 	spin->inc_state = SAR_MENU_BUTTON_STATE_UNARMED;
1584 	spin->label = STRDUP(label);
1585 	spin->value_type = SAR_MENU_SPIN_TYPE_STRING;
1586 	spin->allow_warp = True;
1587 	spin->step = 1.0;
1588 	spin->value = NULL;
1589 	spin->total_values = 0;
1590 	spin->cur_value = -1;
1591 	spin->client_data = client_data;
1592 	spin->id = id;
1593 	spin->change_cb = change_cb;
1594 
1595 	/* Select this object if it is the first one */
1596 	if(m->total_objects == 1)
1597 	    m->selected_object = 0;
1598 
1599 	return(n);
1600 }
1601 
1602 /*
1603  *	Set value type for spin object n on menu m.
1604  */
SARMenuSpinSetValueType(sar_menu_struct * m,int n,int type)1605 void SARMenuSpinSetValueType(
1606 	sar_menu_struct *m, int n, int type
1607 )
1608 {
1609 	sar_menu_spin_struct *spin = SAR_MENU_SPIN(
1610 	    SARMenuGetObject(m, n)
1611 	);
1612 	if(!SAR_MENU_IS_SPIN(spin))
1613 	    return;
1614 
1615 	spin->value_type = type;
1616 }
1617 
1618 /*
1619  *	Adds value to spin object n on menu m.
1620  *
1621  *	If the spin object is set to SAR_MENU_SPIN_TYPE_NUMERIC then
1622  *	this will update its current value, otherwise a new value will
1623  *	be appended to the spin object's list of values.
1624  */
SARMenuSpinAddValue(sar_menu_struct * m,int n,const char * value)1625 int SARMenuSpinAddValue(
1626 	sar_menu_struct *m, int n, const char *value
1627 )
1628 {
1629 	int vn;
1630 	sar_menu_spin_struct *spin = SAR_MENU_SPIN(
1631 	    SARMenuGetObject(m, n)
1632 	);
1633 	if(!SAR_MENU_IS_SPIN(spin))
1634 	    return(-1);
1635 
1636 	/* Handle by value type */
1637 	switch(spin->value_type)
1638 	{
1639 	  case SAR_MENU_SPIN_TYPE_STRING:
1640 	    /* Allocate one more pointer */
1641 	    vn = MAX(spin->total_values, 0);
1642 	    spin->total_values = vn + 1;
1643 	    spin->value = (char **)realloc(
1644 		spin->value,
1645 		spin->total_values * sizeof(char *)
1646 	    );
1647 	    if(spin->value == NULL)
1648 	    {
1649 		spin->total_values = 0;
1650 		spin->cur_value = -1;
1651 		return(-3);
1652 	    }
1653 	    /* Now value_num should be a valid pointer, allocate a new
1654 	     * value for it
1655 	     */
1656 	    spin->value[vn] = STRDUP(value);
1657 	    break;
1658 
1659 	  case SAR_MENU_SPIN_TYPE_NUMERIC:
1660 	    /* Have at least one value? */
1661 	    if(spin->total_values < 1)
1662 	    {
1663 		/* Need to allocate just one value */
1664 		vn = 0;
1665 		spin->total_values = vn + 1;
1666 		spin->value = (char **)realloc(
1667 		    spin->value,
1668 		    spin->total_values * sizeof(char *)
1669 		);
1670 		if(spin->value == NULL)
1671 		{
1672 		    spin->total_values = 0;
1673 		    spin->cur_value = -1;
1674 		    return(-3);
1675 		}
1676 
1677 		spin->value[vn] = NULL;
1678 	    }
1679 	    else
1680 	    {
1681 		vn = 0;
1682 	    }
1683 	    /* Now value_num should be a valid pointer, allocate a new
1684 	     * value string for it.
1685 	     */
1686 	    free(spin->value[vn]);
1687 	    spin->value[vn] = STRDUP(value);
1688 	    break;
1689 	}
1690 
1691 	/* Update current value */
1692 	if(spin->total_values > 0)
1693 	{
1694 	    if(spin->cur_value < 0)
1695 		spin->cur_value = 0;
1696 	}
1697 
1698 	return(0);
1699 }
1700 
1701 /*
1702  *	Returns the Spin's current value.
1703  */
SARMenuSpinGetCurrentValue(sar_menu_struct * m,int n,int * sel_num)1704 char *SARMenuSpinGetCurrentValue(
1705 	sar_menu_struct *m, int n, int *sel_num
1706 )
1707 {
1708 	int vn;
1709 	sar_menu_spin_struct *spin = SAR_MENU_SPIN(
1710 	    SARMenuGetObject(m, n)
1711 	);
1712 
1713 	if(sel_num != NULL)
1714 	    *sel_num = -1;
1715 
1716 	if(!SAR_MENU_IS_SPIN(spin))
1717 	    return(NULL);
1718 
1719 	vn = spin->cur_value;
1720 	if((vn < 0) || (vn >= spin->total_values))
1721 	{
1722 	    return(NULL);
1723 	}
1724 	else
1725 	{
1726 	    if(sel_num != NULL)
1727 		*sel_num = vn;
1728 	    return(spin->value[vn]);
1729 	}
1730 }
1731 
1732 /*
1733  *	Spins the spin to the value specified by value_num.
1734  */
SARMenuSpinSelectValueIndex(gw_display_struct * display,sar_menu_struct * m,int n,int value_num,Boolean redraw)1735 void SARMenuSpinSelectValueIndex(
1736 	gw_display_struct *display, sar_menu_struct *m, int n,
1737 	int value_num,
1738 	Boolean redraw
1739 )
1740 {
1741 	sar_menu_spin_struct *spin = SAR_MENU_SPIN(
1742 	    SARMenuGetObject(m, n)
1743 	);
1744 	if(!SAR_MENU_IS_SPIN(spin))
1745 	    return;
1746 
1747 	if((value_num < 0) || (value_num >= spin->total_values))
1748 	    return;
1749 
1750 	if(value_num != spin->cur_value)
1751 	{
1752 	    spin->cur_value = value_num;
1753 
1754 	    if(redraw)
1755 		DO_REDRAW_OBJECT(display, m, n)
1756 
1757 	    if(spin->change_cb != NULL)
1758 		spin->change_cb(
1759 		    spin,			/* This Object */
1760 		    spin->id,			/* ID Code */
1761 		    spin->client_data,		/* Data */
1762 		    spin->value[value_num]	/* Value */
1763 		);
1764 	}
1765 }
1766 
1767 /*
1768  *	Sets the spin value specified by value_num to the new value
1769  *	specified by value.
1770  */
SARMenuSpinSetValueIndex(gw_display_struct * display,sar_menu_struct * m,int n,int value_num,const char * value,Boolean redraw)1771 void SARMenuSpinSetValueIndex(
1772 	gw_display_struct *display, sar_menu_struct *m, int n,
1773 	int value_num, const char *value,
1774 	Boolean redraw
1775 )
1776 {
1777 	Boolean need_change = False;
1778 	sar_menu_spin_struct *spin = SAR_MENU_SPIN(
1779 	    SARMenuGetObject(m, n)
1780 	);
1781 	if(!SAR_MENU_IS_SPIN(spin))
1782 	    return;
1783 
1784 	if((value_num < 0) || (value_num >= spin->total_values))
1785 	    return;
1786 
1787 	if(value == NULL)
1788 	    value = "";
1789 
1790 	if(spin->value[value_num] != NULL)
1791 	    need_change = (strcmp(spin->value[value_num], value)) ?
1792 		True : False;
1793 	else
1794 	    need_change = True;
1795 	if(need_change)
1796 	{
1797 	    free(spin->value[value_num]);
1798 	    spin->value[value_num] = STRDUP(value);
1799 
1800 	    if(redraw)
1801 		DO_REDRAW_OBJECT(display, m, n)
1802 
1803 	    if(spin->change_cb != NULL)
1804 		spin->change_cb(
1805 		    spin,			/* This Object */
1806 		    spin->id,			/* ID Code */
1807 		    spin->client_data,		/* Data */
1808 		    spin->value[value_num]	/* Value */
1809 		);
1810 	}
1811 }
1812 
1813 /*
1814  *	Deletes all values on spin n on menu m.
1815  */
SARMenuSpinDeleteAllValues(sar_menu_struct * m,int n)1816 void SARMenuSpinDeleteAllValues(sar_menu_struct *m, int n)
1817 {
1818 	sar_menu_spin_struct *spin = SAR_MENU_SPIN(
1819 	    SARMenuGetObject(m, n)
1820 	);
1821 	if(!SAR_MENU_IS_SPIN(spin))
1822 	    return;
1823 
1824 	strlistfree(spin->value, spin->total_values);
1825 	spin->value = NULL;
1826 	spin->total_values = 0;
1827 	spin->cur_value = -1;
1828 }
1829 
1830 /*
1831  *	Spin increment procedure.
1832  */
SARMenuSpinDoInc(gw_display_struct * display,sar_menu_struct * m,int n,Boolean redraw)1833 void SARMenuSpinDoInc(
1834 	gw_display_struct *display, sar_menu_struct *m, int n,
1835 	Boolean redraw
1836 )
1837 {
1838 	int prev_value_num;
1839 	char *value_ptr;
1840 	sar_menu_spin_struct *spin = SAR_MENU_SPIN(
1841 	    SARMenuGetObject(m, n)
1842 	);
1843 	if((display == NULL) || (spin == NULL))
1844 	    return;
1845 
1846 	if(!SAR_MENU_IS_SPIN(spin))
1847 	    return;
1848 
1849 	/* Record previous value number */
1850 	prev_value_num = spin->cur_value;
1851 
1852 	/* Increment by value type */
1853 	switch(spin->value_type)
1854 	{
1855 	  case SAR_MENU_SPIN_TYPE_STRING:
1856 	    if(spin->allow_warp ? True :
1857 		(spin->cur_value < (spin->total_values - 1))
1858 	    )
1859 	    {
1860 		spin->cur_value++;
1861 		if(spin->cur_value >= spin->total_values)
1862 		    spin->cur_value = 0;
1863 
1864 		if(redraw)
1865 		    DO_REDRAW_OBJECT(display, m, n)
1866 
1867 		if((spin->cur_value >= 0) &&
1868 		   (spin->cur_value < spin->total_values)
1869 		)
1870 		    value_ptr = spin->value[spin->cur_value];
1871 		else
1872 		    value_ptr = NULL;
1873 
1874 		/* Call change callback? */
1875 		if((spin->change_cb != NULL) &&
1876 		   (prev_value_num != spin->cur_value) &&
1877 		   (value_ptr != NULL)
1878 		)
1879 		    spin->change_cb(
1880 			spin,			/* This Object */
1881 			spin->id,		/* ID Code */
1882 			spin->client_data,	/* Data */
1883 			value_ptr		/* Value */
1884 		    );
1885 	    }
1886 	    break;
1887 
1888 	  case SAR_MENU_SPIN_TYPE_NUMERIC:
1889 /* TODO */
1890 	    break;
1891 	}
1892 }
1893 
1894 /*
1895  *	Spin increment procedure.
1896  */
SARMenuSpinDoDec(gw_display_struct * display,sar_menu_struct * m,int n,Boolean redraw)1897 void SARMenuSpinDoDec(
1898 	gw_display_struct *display, sar_menu_struct *m, int n,
1899 	Boolean redraw
1900 )
1901 {
1902 	int prev_value_num;
1903 	char *value_ptr;
1904 	sar_menu_spin_struct *spin = SAR_MENU_SPIN(
1905 	    SARMenuGetObject(m, n)
1906 	);
1907 	if((display == NULL) || (spin == NULL))
1908 	    return;
1909 
1910 	if(!SAR_MENU_IS_SPIN(spin))
1911 	    return;
1912 
1913 	/* Record previous value number */
1914 	prev_value_num = spin->cur_value;
1915 
1916 	/* Decrement by value type */
1917 	switch(spin->value_type)
1918 	{
1919 	  case SAR_MENU_SPIN_TYPE_STRING:
1920 	    if(spin->allow_warp ? True :
1921 		(spin->cur_value > 0)
1922 	    )
1923 	    {
1924 		spin->cur_value--;
1925 		if(spin->cur_value < 0)
1926 		    spin->cur_value = spin->total_values - 1;
1927 
1928 		if(redraw)
1929 		    DO_REDRAW_OBJECT(display, m, n)
1930 
1931 		if((spin->cur_value >= 0) &&
1932 		   (spin->cur_value < spin->total_values)
1933 		)
1934 		    value_ptr = spin->value[spin->cur_value];
1935 		else
1936 		    value_ptr = NULL;
1937 
1938 		/* Call change callback? */
1939 		if((spin->change_cb != NULL) &&
1940 		   (prev_value_num != spin->cur_value) &&
1941 		   (value_ptr != NULL)
1942 		)
1943 		    spin->change_cb(
1944 			spin,			/* This Object */
1945 			spin->id,		/* ID Code */
1946 			spin->client_data,	/* Data */
1947 			value_ptr		/* Value */
1948 		    );
1949 	    }
1950 	    break;
1951 
1952 	  case SAR_MENU_SPIN_TYPE_NUMERIC:
1953 /* TODO */
1954 	    break;
1955 	}
1956 }
1957 
1958 
1959 /*
1960  *      Create slider object on menu m.
1961  *
1962  *      Returns the object's index or -1 on error.
1963  */
SARMenuSliderNew(sar_menu_struct * m,float x,float y,float width,float height,sar_menu_color_struct * label_color,GWFont * font,const char * label,const sar_image_struct * label_image,const sar_image_struct * trough_image,const sar_image_struct * handle_image,void * client_data,int id,void (* change_cb)(void *,int,void *,float))1964 int SARMenuSliderNew(
1965 	sar_menu_struct *m,
1966 	float x, float y,
1967 	float width, float height,
1968 	sar_menu_color_struct *label_color,
1969 	GWFont *font,
1970 	const char *label,
1971 	const sar_image_struct *label_image,
1972 	const sar_image_struct *trough_image,
1973 	const sar_image_struct *handle_image,
1974 	void *client_data, int id,
1975 	void (*change_cb)(void *, int, void *, float)
1976 )
1977 {
1978 	int i, n;
1979 	sar_menu_slider_struct *slider;
1980 
1981 
1982 	if(m == NULL)
1983 	    return(-1);
1984 
1985 	if(m->total_objects < 0)
1986 	    m->total_objects = 0;
1987 
1988 	for(i = 0; i < m->total_objects; i++)
1989 	{
1990 	    if(m->object[i] == NULL)
1991 		break;
1992 	}
1993 	if(i < m->total_objects)
1994 	{
1995 	    n = i;
1996 	}
1997 	else
1998 	{
1999 	    n = m->total_objects;
2000 	    m->total_objects = n + 1;
2001 	    m->object = (void **)realloc(
2002 		m->object,
2003 		m->total_objects * sizeof(void *)
2004 	    );
2005 	    if(m->object == NULL)
2006 	    {
2007 		m->total_objects = 0;
2008 		return(-3);
2009 	    }
2010 	}
2011 
2012 	/* Allocate structure */
2013 	m->object[n] = slider = SAR_MENU_SLIDER(calloc(
2014 	    1, sizeof(sar_menu_slider_struct)
2015 	));
2016 	if(slider == NULL)
2017 	    return(-3);
2018 
2019 	/* Set slider values */
2020 	slider->type = SAR_MENU_OBJECT_TYPE_SLIDER;
2021 	slider->x = x;
2022 	slider->y = y;
2023 	slider->width = width;
2024 	slider->height = height;
2025 	slider->sensitive = True;
2026 	slider->label_image = label_image;
2027 	slider->trough_image = trough_image;
2028 	slider->handle_image = handle_image;
2029 	memcpy(&slider->label_color, label_color, sizeof(sar_menu_color_struct));
2030 	slider->font = font;
2031 	slider->label = STRDUP(label);
2032 	slider->value = 0.0f;
2033 	slider->lower = 0.0f;
2034 	slider->upper = 1.0f;
2035 	slider->drag_button = 0;
2036 	slider->client_data = client_data;
2037 	slider->id = id;
2038 	slider->change_cb = change_cb;
2039 
2040 	/* Select this object if it is the first one */
2041 	if(m->total_objects == 1)
2042 	    m->selected_object = 0;
2043 
2044 	return(n);
2045 }
2046 
2047 /*
2048  *	Sets the lower and upper value bounds for the slider.
2049  */
SARMenuSliderSetValueBounds(gw_display_struct * display,sar_menu_struct * m,int n,float lower,float upper,Boolean redraw)2050 void SARMenuSliderSetValueBounds(
2051 	gw_display_struct *display, sar_menu_struct *m, int n,
2052 	float lower, float upper,
2053 	Boolean redraw
2054 )
2055 {
2056 	Boolean change = False;
2057 	sar_menu_slider_struct *slider = SAR_MENU_SLIDER(
2058 	    SARMenuGetObject(m, n)
2059 	);
2060 	if((display == NULL) || (slider == NULL))
2061 	    return;
2062 
2063 	if(!SAR_MENU_IS_SLIDER(slider))
2064 	    return;
2065 
2066 	/* Set value only if the new value is different */
2067 	if((slider->lower != lower) || (slider->upper != upper))
2068 	{
2069 	    slider->upper = upper;
2070 	    slider->lower = lower;
2071 	    slider->value = CLIP(slider->value, slider->lower, slider->upper);
2072 	    change = True;
2073 	}
2074 
2075 	/* Check if there is a change in the value, if there is then
2076 	 * redraw and call change callback.
2077 	 */
2078 	if(change)
2079 	{
2080 	    if(redraw)
2081 		DO_REDRAW_OBJECT(display, m, n)
2082 
2083 	    if(slider->change_cb != NULL)
2084 		slider->change_cb(
2085 		    slider,			/* This Object */
2086 		    slider->id,			/* ID Code */
2087 		    slider->client_data,	/* Data */
2088 		    slider->value		/* Value */
2089 		);
2090 	}
2091 }
2092 
2093 /*
2094  *	Sets the value for the slider.
2095  */
SARMenuSliderSetValue(gw_display_struct * display,sar_menu_struct * m,int n,float value,Boolean redraw)2096 void SARMenuSliderSetValue(
2097 	gw_display_struct *display, sar_menu_struct *m, int n,
2098 	float value,
2099 	Boolean redraw
2100 )
2101 {
2102 	Boolean change = False;
2103 	sar_menu_slider_struct *slider = SAR_MENU_SLIDER(
2104 	    SARMenuGetObject(m, n)
2105 	);
2106 	if((display == NULL) || (slider == NULL))
2107 	    return;
2108 
2109 	if(!SAR_MENU_IS_SLIDER(slider))
2110 	    return;
2111 
2112 	/* Set value only if the new value is different */
2113 	if(slider->value != value)
2114 	{
2115 	    slider->value = CLIP(value, slider->lower, slider->upper);
2116 	    change = True;
2117 	}
2118 
2119 	/* Check if there is a change in the value, if there is then
2120 	 * redraw and call change callback
2121 	 */
2122 	if(change)
2123 	{
2124 	    if(redraw)
2125 		DO_REDRAW_OBJECT(display, m, n)
2126 
2127 	    if(slider->change_cb != NULL)
2128 		slider->change_cb(
2129 		    slider,			/* This Object */
2130 		    slider->id,			/* ID Code */
2131 		    slider->client_data,	/* Data */
2132 		    slider->value		/* Value */
2133 		);
2134 	}
2135 }
2136 
2137 /*
2138  *	Returns the current value of the slider.
2139  */
SARMenuSliderGetValue(sar_menu_struct * m,int n)2140 float SARMenuSliderGetValue(sar_menu_struct *m, int n)
2141 {
2142 	sar_menu_slider_struct *slider = SAR_MENU_SLIDER(
2143 	    SARMenuGetObject(m, n)
2144 	);
2145 	if(slider == NULL)
2146 	    return(0.0f);
2147 
2148 	if(!SAR_MENU_IS_SLIDER(slider))
2149 	    return(0.0f);
2150 
2151 	return(slider->value);
2152 }
2153 
2154 
2155 /*
2156  *	Sets object n sensitive or insensitive.
2157  */
SARMenuObjectSetSensitive(gw_display_struct * display,sar_menu_struct * m,int n,Boolean sensitive,Boolean redraw)2158 void SARMenuObjectSetSensitive(
2159 	gw_display_struct *display, sar_menu_struct *m, int n,
2160 	Boolean sensitive, Boolean redraw
2161 )
2162 {
2163 	sar_menu_label_struct *label_ptr;
2164 	sar_menu_button_struct *button;
2165 	sar_menu_progress_struct *progress;
2166 	sar_menu_message_box_struct *mesgbox;
2167 	sar_menu_list_struct *list;
2168 	sar_menu_mdisplay_struct *mdpy;
2169 	sar_menu_switch_struct *sw;
2170 	sar_menu_spin_struct *spin;
2171 	sar_menu_slider_struct *slider;
2172 	sar_menu_map_struct *map;
2173 	sar_menu_objview_struct *objview;
2174 	Boolean changed = False;
2175 	void *o = SARMenuGetObject(m, n);
2176 	if(o == NULL)
2177 	    return;
2178 
2179 	switch(SAR_MENU_OBJECT_TYPE(o))
2180 	{
2181 	  case SAR_MENU_OBJECT_TYPE_LABEL:
2182 	    label_ptr = SAR_MENU_LABEL(o);
2183 	    if(label_ptr->sensitive != sensitive)
2184 	    {
2185 		label_ptr->sensitive = sensitive;
2186 		changed = True;
2187 	    }
2188 	    break;
2189 	  case SAR_MENU_OBJECT_TYPE_BUTTON:
2190 	    button = SAR_MENU_BUTTON(o);
2191 	    if(button->sensitive != sensitive)
2192 	    {
2193 		button->sensitive = sensitive;
2194 		changed = True;
2195 	    }
2196 	    break;
2197 	  case SAR_MENU_OBJECT_TYPE_PROGRESS:
2198 	    progress = SAR_MENU_PROGRESS(o);
2199 	    if(progress->sensitive != sensitive)
2200 	    {
2201 		progress->sensitive = sensitive;
2202 		changed = True;
2203 	    }
2204 	    break;
2205 	  case SAR_MENU_OBJECT_TYPE_MESSAGE_BOX:
2206 	    mesgbox = SAR_MENU_MESSAGE_BOX(o);
2207 	    if(mesgbox->sensitive != sensitive)
2208 	    {
2209 		mesgbox->sensitive = sensitive;
2210 		changed = True;
2211 	    }
2212 	    break;
2213 	  case SAR_MENU_OBJECT_TYPE_LIST:
2214 	    list = SAR_MENU_LIST(o);
2215 	    if(list->sensitive != sensitive)
2216 	    {
2217 		list->sensitive = sensitive;
2218 		changed = True;
2219 	    }
2220 	    break;
2221 	 case SAR_MENU_OBJECT_TYPE_MDISPLAY:
2222 	    mdpy = SAR_MENU_MDISPLAY(o);
2223 	    if(mdpy->sensitive != sensitive)
2224 	    {
2225 		mdpy->sensitive = sensitive;
2226 		changed = True;
2227 	    }
2228 	    break;
2229 	  case SAR_MENU_OBJECT_TYPE_SWITCH:
2230 	    sw = SAR_MENU_SWITCH(o);
2231 	    if(sw->sensitive != sensitive)
2232 	    {
2233 		sw->sensitive = sensitive;
2234 		changed = True;
2235 	    }
2236 	    break;
2237 	  case SAR_MENU_OBJECT_TYPE_SPIN:
2238 	    spin = SAR_MENU_SPIN(o);
2239 	    if(spin->sensitive != sensitive)
2240 	    {
2241 		spin->sensitive = sensitive;
2242 		changed = True;
2243 	    }
2244 	    break;
2245 	  case SAR_MENU_OBJECT_TYPE_SLIDER:
2246 	    slider = SAR_MENU_SLIDER(o);
2247 	    if(slider->sensitive != sensitive)
2248 	    {
2249 		slider->sensitive = sensitive;
2250 		changed = True;
2251 	    }
2252 	    break;
2253 	  case SAR_MENU_OBJECT_TYPE_MAP:
2254 	    map = SAR_MENU_MAP(o);
2255 	    if(map->sensitive != sensitive)
2256 	    {
2257 		map->sensitive = sensitive;
2258 		changed = True;
2259 	    }
2260 	    break;
2261 	  case SAR_MENU_OBJECT_TYPE_OBJVIEW:
2262 	    objview = SAR_MENU_OBJVIEW(o);
2263 	    if(objview->sensitive != sensitive)
2264 	    {
2265 		objview->sensitive = sensitive;
2266 		changed = True;
2267 	    }
2268 	    break;
2269 	}
2270 
2271 	if(redraw && changed)
2272 	    DO_REDRAW_OBJECT(display, m, n)
2273 }
2274 
2275 /*
2276  *	Destroys object n on menu m.
2277  */
SARMenuObjectDelete(sar_menu_struct * m,int n)2278 void SARMenuObjectDelete(sar_menu_struct *m, int n)
2279 {
2280 	void *o = SARMenuGetObject(m, n);
2281 	if(o != NULL)
2282 	{
2283 	    sar_menu_object_type type;
2284 	    sar_menu_label_struct *label_ptr;
2285 	    sar_menu_button_struct *button;
2286 	    sar_menu_progress_struct *progress_ptr;
2287 	    sar_menu_message_box_struct *mesgbox;
2288 	    sar_menu_list_struct *list;
2289 	    sar_menu_mdisplay_struct *mdpy;
2290 	    sar_menu_switch_struct *sw;
2291 	    sar_menu_spin_struct *spin;
2292 	    sar_menu_slider_struct *slider;
2293 	    sar_menu_map_struct *map;
2294 	    sar_menu_objview_struct *objview;
2295 
2296 
2297 	    type = SAR_MENU_OBJECT_TYPE(o);
2298 	    switch(type)
2299 	    {
2300 	      case SAR_MENU_OBJECT_TYPE_LABEL:
2301 		label_ptr = SAR_MENU_LABEL(o);
2302 		label_ptr->image = NULL;	/* Shared */
2303 		free(label_ptr->label);
2304 		free(label_ptr);
2305 		break;
2306 
2307 	      case SAR_MENU_OBJECT_TYPE_BUTTON:
2308 		button = SAR_MENU_BUTTON(o);
2309 		button->unarmed_image = NULL;	/* Shared */
2310 		button->armed_image = NULL;		/* Shared */
2311 		button->highlighted_image = NULL;	/* Shared */
2312 		free(button->label);
2313 		free(button);
2314 		break;
2315 
2316 	      case SAR_MENU_OBJECT_TYPE_PROGRESS:
2317 		progress_ptr = SAR_MENU_PROGRESS(o);
2318 		progress_ptr->bg_image = NULL;	/* Shared */
2319 		progress_ptr->fg_image = NULL;	/* Shared */
2320 		free(progress_ptr->label);
2321 		free(progress_ptr);
2322 		break;
2323 
2324 	      case SAR_MENU_OBJECT_TYPE_MESSAGE_BOX:
2325 		mesgbox = SAR_MENU_MESSAGE_BOX(o);
2326 		mesgbox->bg_image = NULL;	/* Shared */
2327 		free(mesgbox->message);
2328 		free(mesgbox);
2329 		break;
2330 
2331 	      case SAR_MENU_OBJECT_TYPE_LIST:
2332 		list = SAR_MENU_LIST(o);
2333 		SARMenuListDeleteAllItems(m, n);
2334 		list->bg_image = NULL;	/* Shared */
2335 		free(list->item);
2336 		free(list->label);
2337 		free(list);
2338 		break;
2339 
2340 	      case SAR_MENU_OBJECT_TYPE_MDISPLAY:
2341 		mdpy = SAR_MENU_MDISPLAY(o);
2342 		mdpy->bg_image = NULL;	/* Shared */
2343 		free(mdpy);
2344 		break;
2345 
2346 	      case SAR_MENU_OBJECT_TYPE_SWITCH:
2347 		sw = SAR_MENU_SWITCH(o);
2348 		sw->bg_image = NULL;		/* Shared */
2349 		sw->switch_off_image = NULL;	/* Shared */
2350 		sw->switch_on_image = NULL;	/* Shared */
2351 		free(sw->label);
2352 		free(sw);
2353 		break;
2354 
2355 	      case SAR_MENU_OBJECT_TYPE_SPIN:
2356 		spin = SAR_MENU_SPIN(o);
2357 		SARMenuSpinDeleteAllValues(m, n);
2358 		spin->label_image = NULL;	/* Shared */
2359 		spin->value_image = NULL;	/* Shared */
2360 		spin->dec_armed_image = NULL;	/* Shared */
2361 		spin->dec_unarmed_image = NULL;	/* Shared */
2362 		spin->inc_armed_image = NULL;	/* Shared */
2363 		spin->inc_unarmed_image = NULL;	/* Shared */
2364 		free(spin->label);
2365 		free(spin);
2366 		break;
2367 
2368 	      case SAR_MENU_OBJECT_TYPE_SLIDER:
2369 		slider = SAR_MENU_SLIDER(o);
2370 		slider->label_image = NULL;	/* Shared */
2371 		slider->trough_image = NULL;	/* Shared */
2372 		slider->handle_image = NULL;	/* Shared */
2373 		free(slider->label);
2374 		free(slider);
2375 		break;
2376 
2377 	      case SAR_MENU_OBJECT_TYPE_MAP:
2378 		map = SAR_MENU_MAP(o);
2379 		SARMenuMapDeleteAllMarkings(map);
2380 		V3DTextureDestroy(map->bg_tex);
2381 		map->bg_tex = NULL;
2382 		free(map->title);
2383 		map->title = NULL;
2384 		free(map);
2385 		break;
2386 
2387 	      case SAR_MENU_OBJECT_TYPE_OBJVIEW:
2388 		objview = SAR_MENU_OBJVIEW(o);
2389 		free(objview->title);
2390 		objview->title = NULL;
2391 		free(objview->message);
2392 		objview->message = NULL;
2393 		if(objview->obj_list != NULL)
2394 		{
2395 		    GLuint list = (GLuint)objview->obj_list;
2396 		    glDeleteLists(list, 1);
2397 		    objview->obj_list = NULL;
2398 		}
2399 		V3DGLResourceDelete(
2400 		    (v3d_glresource_struct *)objview->obj_glres
2401 		);
2402 		objview->obj_glres = NULL;
2403 		free(objview->objimg);
2404 		objview->objimg = NULL;
2405 		free(objview);
2406 		break;
2407 
2408 
2409 	      default:
2410 		fprintf(
2411 		    stderr,
2412  "SARMenuObjectDelete(): Destroying unknown type `%i'\n",
2413 		    type
2414 		);
2415 		free(o);
2416 		break;
2417 	    }
2418 
2419 	    m->object[n] = NULL;
2420 	}
2421 }
2422 
2423 
2424 /*
2425  *	Draws one line of string starting at buf_ptr and does not
2426  *	draw more than the number of whole word characters specified by
2427  *	visible_columns.
2428  *
2429  *	Returns the pointer to the next word that lies within buf_ptr
2430  *	or NULL if a '\0' character was encountered while drawing the
2431  *	string.
2432  */
SARMenuMessageBoxDrawString(gw_display_struct * display,int x,int y,const char * buf_ptr,int visible_columns,int font_width,Boolean sensitive,Boolean draw_line,const sar_menu_color_struct * c_def,const sar_menu_color_struct * c_bold,const sar_menu_color_struct * c_ul)2433 static const char *SARMenuMessageBoxDrawString(
2434 	gw_display_struct *display,
2435 	int x, int y,
2436 	const char *buf_ptr,
2437 	int visible_columns, int font_width,
2438 	Boolean sensitive,
2439 	Boolean draw_line,
2440 	const sar_menu_color_struct *c_def,
2441 	const sar_menu_color_struct *c_bold,
2442 	const sar_menu_color_struct *c_ul
2443 )
2444 {
2445 	char c;
2446 	int characters_drawn;
2447 	const char *s, *buf_stop;
2448 
2449 
2450 	if((display == NULL) || (buf_ptr == NULL) || (visible_columns < 1))
2451 	    return(NULL);
2452 
2453 	/* If given buffer points to a end of buffer then return NULL */
2454 	if(*buf_ptr == '\0')
2455 	    return(NULL);
2456 
2457 	/* If given string points to a newline then just return the
2458 	 * pointer to the next character. This will effectivly draw one
2459 	 * empty line.
2460 	 */
2461 	if(ISCR(*buf_ptr))
2462 	    return(buf_ptr + 1);
2463 
2464 	/* Seek past initial spaces */
2465 	while(ISBLANK(*buf_ptr))
2466 	    buf_ptr++;
2467 
2468 	/* Probe to end of line and mark it by setting buf_stop to point
2469 	 * to that end.
2470 	 */
2471 	buf_stop = NULL;
2472 	s = buf_ptr;
2473 	for(characters_drawn = 0; characters_drawn < visible_columns;)
2474 	{
2475 	    c = *s;
2476 
2477 	    /* End of buffer? */
2478 	    if(c == '\0')
2479 	    {
2480 		buf_stop = s;
2481 		break;
2482 	    }
2483 	    /* Blank character? */
2484 	    else if(ISBLANK(c))
2485 	    {
2486 		/* Mark end of buffer at this blank character and count it
2487 		 * as one character drawn (regardless of how many blank
2488 		 * characters follow).
2489 		 */
2490 		buf_stop = s;
2491 		characters_drawn++;
2492 
2493 		/* Seek past this and any following blank characters */
2494 		while(ISBLANK(*s))
2495 		    s++;
2496 	    }
2497 	    /* New line? */
2498 	    else if(ISCR(c))
2499 	    {
2500 		buf_stop = s;
2501 		break;
2502 	    }
2503 	    /* Escape sequence? */
2504 	    else if(IS_CHAR_ESC_START(c))
2505 	    {
2506 		/* Skip this character */
2507 		s++;
2508 
2509 		/* Seek to end of escape sequence or end of buffer */
2510 		while((*s != '\0') &&
2511 		      !IS_CHAR_ESC_END(*s)
2512 		)
2513 		    s++;
2514 		if(*s != '\0')
2515 		    s++;
2516 	    }
2517 	    /* Regular character */
2518 	    else
2519 	    {
2520 		/* Mark this as a character to be drawn and increment to
2521 		 * next character.
2522 		 */
2523 		characters_drawn++;
2524 		s++;
2525 	    }
2526 	}
2527 
2528 	/* If end of buffer was not found then assume it is at s */
2529 	if(buf_stop == NULL)
2530 	    buf_stop = s;
2531 
2532 
2533 	/* Draw from buf_ptr to (but not including) buf_stop */
2534 	characters_drawn = 0;
2535 	s = buf_ptr;
2536 	while(s < buf_stop)
2537 	{
2538 	    c = *s;
2539 
2540 	    /* End of buffer? */
2541 	    if(c == '\0')
2542 	    {
2543 		break;
2544 	    }
2545 	    /* Blank character? */
2546 	    else if(ISBLANK(c))
2547 	    {
2548 		/* Draw one blank character and seek to next non-blank
2549 		 * character (regardless of how many blank characters
2550 		 * follow).
2551 		 */
2552 		if(draw_line)
2553 		    GWDrawCharacter(
2554 			display,
2555 			x + (characters_drawn * font_width),
2556 			y,
2557 			c
2558 		    );
2559 		characters_drawn++;
2560 
2561 		/* Seek past this and any following blank characters */
2562 		while(ISBLANK(*s))
2563 		    s++;
2564 	    }
2565 	    /* Escape sequence? */
2566 	    else if(IS_CHAR_ESC_START(c))
2567 	    {
2568 		int n;
2569 		char tag_name[256];
2570 
2571 
2572 		/* Skip this character */
2573 		s++;
2574 
2575 		/* Seek to end of escape sequence or end of buffer */
2576 		n = 0;
2577 		while((*s != '\0') &&
2578 		      !IS_CHAR_ESC_END(*s)
2579 		)
2580 		{
2581 		    if(n < 254)
2582 		    {
2583 			tag_name[n] = *s;
2584 			n++;
2585 		    }
2586 		    s++;
2587 		}
2588 		if(*s != '\0')
2589 		    s++;
2590 
2591 		/* Null terminate tag_name */
2592 		tag_name[n] = '\0';
2593 
2594 		/* Handle tag */
2595 		/* Default? */
2596 		if(!strcasecmp(tag_name, "default") ||
2597 		   !strcasecmp(tag_name, "plain") ||
2598 		   !strcasecmp(tag_name, "regular")
2599 		)
2600 		{
2601 		    if(c_def != NULL)
2602 		    {
2603 			if(sensitive)
2604 			    glColor4f(
2605 				c_def->r,
2606 				c_def->g,
2607 				c_def->b,
2608 				c_def->a
2609 			    );
2610 			else
2611 			    glColor4f(
2612 				c_def->r * 0.75f,
2613 				c_def->g * 0.75f,
2614 				c_def->b * 0.75f,
2615 				c_def->a
2616 			    );
2617 		    }
2618 		}
2619 		/* Bold? */
2620 		else if(!strcasecmp(tag_name, "bold"))
2621 		{
2622 		    if(c_bold != NULL)
2623 		    {
2624 			if(sensitive)
2625 			    glColor4f(
2626 				c_bold->r,
2627 				c_bold->g,
2628 				c_bold->b,
2629 				c_bold->a
2630 			    );
2631 			else
2632 			    glColor4f(
2633 				c_bold->r * 0.75f,
2634 				c_bold->g * 0.75f,
2635 				c_bold->b * 0.75f,
2636 				c_bold->a
2637 			    );
2638 		    }
2639 		}
2640 		/* Underline? */
2641 		else if(!strcasecmp(tag_name, "underline") ||
2642 		        !strcasecmp(tag_name, "underlined")
2643 		)
2644 		{
2645 		    if(c_ul != NULL)
2646 		    {
2647 			if(sensitive)
2648 			    glColor4f(
2649 				c_ul->r,
2650 				c_ul->g,
2651 				c_ul->b,
2652 				c_ul->a
2653 			    );
2654 			else
2655 			    glColor4f(
2656 				c_ul->r * 0.75f,
2657 				c_ul->g * 0.75f,
2658 				c_ul->b * 0.75f,
2659 				c_ul->a
2660 			    );
2661 		    }
2662 		}
2663 
2664 	    }
2665 	    else
2666 	    {
2667 		/* Actually draw this character? */
2668 		if(draw_line)
2669 		    GWDrawCharacter(
2670 			display,
2671 			x + (characters_drawn * font_width),
2672 			y,
2673 			c
2674 		    );
2675 		characters_drawn++;
2676 		s++;
2677 	    }
2678 	}
2679 
2680 	/* Return the pointer to the next character that was not
2681 	 * drawn.
2682 	 */
2683 	return(buf_stop);
2684 }
2685 
2686 /*
2687  *	Returns the total number of lines by seeking through the given
2688  *	buffer.
2689  */
SARMenuMessageBoxTotalLines(const char * buf_ptr,int visible_columns)2690 static int SARMenuMessageBoxTotalLines(
2691 	const char *buf_ptr, int visible_columns
2692 )
2693 {
2694 	char c;
2695 	int line_count = 0, characters_drawn;
2696 	const char *s, *buf_stop;
2697 
2698 
2699 	if((buf_ptr == NULL) || (visible_columns < 1))
2700 	    return(line_count);
2701 
2702 	/* Iterate until end of buffer */
2703 	while((buf_ptr != NULL) ? (*buf_ptr != '\0') : False)
2704 	{
2705 	    /* Set s to point to the start of current line */
2706 	    s = buf_ptr;
2707 
2708 	    /* If s is on a newline then seek to next character and
2709 	     * count this as one line.
2710 	     */
2711 	    if(ISCR(*s))
2712 	    {
2713 		buf_ptr = s + 1;
2714 		line_count++;
2715 		continue;
2716 	    }
2717 
2718 	    /* Seek past initial spaces */
2719 	    while(ISBLANK(*s))
2720 		s++;
2721 
2722 	    /* Reset stop buffer and seek to end of `line'. Remember that
2723 	     * characters_drawn represents the number of characters that
2724 	     * would be drawn to fit on one line with whole words. Not the
2725 	     * the actual characters drawn since nothing is being drawn in
2726 	     * this function.
2727 	     */
2728 	    buf_stop = NULL;
2729 	    for(characters_drawn = 0; characters_drawn < visible_columns;)
2730 	    {
2731 		c = *s;
2732 
2733 		/* End of buffer? */
2734 		if(c == '\0')
2735 		{
2736 		    buf_stop = s;
2737 		    break;
2738 		}
2739 		/* Blank character? */
2740 		else if(ISBLANK(c))
2741 		{
2742 		    /* Count blank character as one character drawn and
2743 		     * seek to next non-blank character.
2744 		     */
2745 		    buf_stop = s;
2746 		    characters_drawn++;
2747 
2748 		    /* Seek past this and any following blank characters */
2749 		    while(ISBLANK(*s))
2750 			s++;
2751 		}
2752 		/* New line? */
2753 		else if(ISCR(c))
2754 		{
2755 		    buf_stop = s;
2756 		    break;
2757 		}
2758 		/* Escape sequence? */
2759 		else if(IS_CHAR_ESC_START(c))
2760 		{
2761 		    /* Skip this character */
2762 		    s++;
2763 
2764 		    /* Seek to end of escape sequence or end of buffer */
2765 		    while((*s != '\0') &&
2766 			  !IS_CHAR_ESC_END(*s)
2767 		    )
2768 			s++;
2769 		    if(*s != '\0')
2770 			s++;
2771 		}
2772 		/* Regular character */
2773 		else
2774 		{
2775 		    /* Mark this as a character to be drawn and increment
2776 		     * to next character.
2777 		     */
2778 		    characters_drawn++;
2779 		    s++;
2780 		}
2781 	    }
2782 	    /* If not able to find end of line pointer then assume end of
2783 	     * line is at current position of s.
2784 	     */
2785 	    if(buf_stop == NULL)
2786 		buf_stop = s;
2787 
2788 	    /* End of line reached, count this as one line and set buffer
2789 	     * to start of next line.
2790 	     */
2791 	    line_count++;
2792 	    buf_ptr = buf_stop;
2793 	}
2794 
2795 	return(line_count);
2796 }
2797 
2798 /*
2799  *	Redraws a `window' comprised of 9 images where the first image
2800  *	(index 0) is the background and the second image (index 1) through
2801  *	the 9th image (index 8) are the 8 decoration edges starting from
2802  *	the upper left corner.
2803  */
SARMenuDrawWindowBG(gw_display_struct * display,const sar_image_struct ** bg_image,const sar_menu_color_struct * base_color,int x,int y,int width,int height,Boolean draw_base,Boolean draw_shadow,Boolean is_selected)2804 void SARMenuDrawWindowBG(
2805 	gw_display_struct *display,
2806 	const sar_image_struct **bg_image,      /* Total 9 images */
2807 	const sar_menu_color_struct *base_color,	/* Set NULL to use image as base */
2808 	int x, int y,
2809 	int width, int height,
2810 	Boolean draw_base,
2811 	Boolean draw_shadow,
2812 	Boolean is_selected
2813 )
2814 {
2815 	int corner_width = 0, corner_height = 0;
2816 	int vframe_width = 0, hframe_height = 0;
2817 	const sar_image_struct *img;
2818 	int win_width, win_height;
2819 
2820 
2821 	if((display == NULL) || (bg_image == NULL))
2822 	    return;
2823 
2824 	GWContextGet(
2825 	    display, GWContextCurrent(display),
2826 	    NULL, NULL,
2827 	    NULL, NULL,
2828 	    &win_width, &win_height
2829 	);
2830 
2831 	/* Get upper left corner image */
2832 	img = bg_image[1];
2833 	if(img != NULL)
2834 	{
2835 	    /* Get size of each corner by assuming they're all the same
2836 	     * and take the size of the upper left corner image.
2837 	     */
2838 	    corner_width = MAX(img->width, 0);
2839 	    corner_height = MAX(img->height, 0);
2840 	}
2841 
2842 	/* Get upper horizontal frame image */
2843 	img = bg_image[2];
2844 	if(img != NULL)
2845 	{
2846 	    /* Get height of both horizontal frames by taking the size of
2847 	     * the upper horizontal frame image.
2848 	     */
2849 	    hframe_height = MAX(img->height, 0);
2850 	}
2851 
2852 	/* Get right vertical frame image */
2853 	img = bg_image[4];
2854 	if(img != NULL)
2855 	{
2856 	    /* Get width of both vertical frames by taking the size of
2857 	     * the right vertical frame image.
2858 	     */
2859 	    vframe_width = MAX(img->width, 0);
2860 	}
2861 
2862 	/* Adjust given geometry to fit `with in' the decorations */
2863 	x += corner_width;
2864 	y += corner_height;
2865 	width = MAX(width - (2 * corner_width), 0);
2866 	height = MAX(height - (2 * corner_height), 0);
2867 
2868 	if((width < 1) || (height < 1))
2869 	    return;
2870 
2871 	/* Draw shadow */
2872 	if(draw_shadow)
2873 	{
2874 	    StateGLBoolean	alpha_test = display->state_gl.alpha_test,
2875 				blend = display->state_gl.blend;
2876 
2877 	    /* Set up GL states */
2878 	    StateGLDisable(&display->state_gl, GL_ALPHA_TEST);
2879 	    StateGLEnable(&display->state_gl, GL_BLEND);
2880 	    StateGLBlendFunc(
2881 		&display->state_gl, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
2882 	    );
2883 	    glColor4f(0.0f, 0.0f, 0.0f, 0.25f);
2884 
2885 	    glBegin(GL_QUADS);
2886 	    {
2887 		glVertex2i(
2888 		    (GLint)(x + width + (0.5 * corner_width)),
2889 		    (GLint)(win_height - (y + height + (1.5 * corner_height)))
2890 		);
2891 		glVertex2i(
2892 		    (GLint)(x + width + (1.5 * corner_width)),
2893 		    (GLint)(win_height - (y + height + (1.5 * corner_height)))
2894 		);
2895 		glVertex2i(
2896 		    (GLint)(x + width + (1.5 * corner_width)),
2897 		    (GLint)(win_height - (y - (0.5 * corner_height)))
2898 		);
2899 		glVertex2i(
2900 		    (GLint)(x + width + (0.5 * corner_width)),
2901 		    (GLint)(win_height - (y - (0.5 * corner_height)))
2902 		);
2903 
2904 		glVertex2i(
2905 		    (GLint)(x - (0.5 * corner_width)),
2906 		    (GLint)(win_height - (y + height + (1.5 * corner_height)))
2907 		);
2908 		glVertex2i(
2909 		    (GLint)(x + width + (0.5 * corner_width)),
2910 		    (GLint)(win_height - (y + height + (1.5 * corner_height)))
2911 		);
2912 		glVertex2i(
2913 		    (GLint)(x + width + (0.5 * corner_width)),
2914 		    (GLint)(win_height - (y + height + (0.5 * corner_height)))
2915 		);
2916 		glVertex2i(
2917 		    (GLint)(x - (0.5 * corner_width)),
2918 		    (GLint)(win_height - (y + height + (0.5 * corner_height)))
2919 		);
2920 	    }
2921 	    glEnd();
2922 
2923 	    /* Restore GL states */
2924 	    if(alpha_test)
2925 		StateGLEnable(&display->state_gl, GL_ALPHA_TEST);
2926 	    if(!blend)
2927 		StateGLDisable(&display->state_gl, GL_BLEND);
2928 	}
2929 
2930 	/* Draw base image at center, scaled to fit the width and height
2931 	 * regardless of the actual image size
2932 	 */
2933 	if(draw_base)
2934 	{
2935 	    if(base_color != NULL)
2936 	    {
2937 		glColor4f(
2938 		    base_color->r,
2939 		    base_color->g,
2940 		    base_color->b,
2941 		    base_color->a
2942 		);
2943 		glBegin(GL_QUADS);
2944 		{
2945 		    glVertex2i(x - 1, win_height - (y - 1));
2946 		    glVertex2i(x - 1, win_height - (y + height + 2));
2947 		    glVertex2i(x + width + 2, win_height - (y + height + 2));
2948 		    glVertex2i(x + width + 2, win_height - (y - 1));
2949 		}
2950 		glEnd();
2951 	    }
2952 	    else
2953 	    {
2954 		img = bg_image[0];
2955 		SARImageDraw(
2956 		    display, img,
2957 		    x - 1, y - 1, width + 2, height + 2
2958 		);
2959 	    }
2960 
2961 	    /* Draw selection rectangle? */
2962 	    if(is_selected)
2963 	    {
2964 		glColor4f(0.0f, 0.5f, 0.0f, 1.0f);
2965 		glBegin(GL_LINE_LOOP);
2966 		{
2967 		    int margin = 1;
2968 		    glVertex2i(x + margin, win_height - (y + margin));
2969 		    glVertex2i(x + margin, win_height - (y + height - margin));
2970 		    glVertex2i(x + width - margin, win_height - (y + height - margin));
2971 		    glVertex2i(x + width - margin, win_height - (y + margin));
2972  		}
2973 		glEnd();
2974 	    }
2975 	}
2976 
2977 	/* Draw frame decorations (not including corners) next */
2978 	img = bg_image[2];
2979 	SARImageDraw(
2980 	    display, img,
2981 	    x - 1, y - hframe_height,
2982 	    width + 2, hframe_height
2983 	);
2984 
2985 	img = bg_image[4];
2986 	SARImageDraw(
2987 	    display, img,
2988 	    x + width, y - 1,
2989 	    vframe_width, height + 2
2990 	);
2991 
2992 	img = bg_image[6];
2993 	SARImageDraw(
2994 	    display, img,
2995 	    x - 1, y + height,
2996 	    width + 2, hframe_height
2997 	);
2998 
2999 	img = bg_image[8];
3000 	SARImageDraw(
3001 	    display, img,
3002 	    x - vframe_width, y - 1,
3003 	    vframe_width, height + 2
3004 	);
3005 
3006 
3007 	/* Draw corners */
3008 	img = bg_image[1];
3009 	SARImageDraw(
3010 	    display, img,
3011 	    x - corner_width, y - corner_height,
3012 	    corner_width, corner_height
3013 	);
3014 
3015 	img = bg_image[3];
3016 	SARImageDraw(
3017 	    display, img,
3018 	    x + width, y - corner_height,
3019 	    corner_width, corner_height
3020 	);
3021 
3022 	img = bg_image[5];
3023 	SARImageDraw(
3024 	    display, img,
3025 	    x + width, y + height,
3026 	    corner_width, corner_height
3027 	);
3028 
3029 	img = bg_image[7];
3030 	SARImageDraw(
3031 	    display, img,
3032 	    x - corner_width, y + height,
3033 	    corner_width, corner_height
3034 	);
3035 }
3036 
3037 
3038 /*
3039  *	Draws the specified object n.
3040  */
SARMenuDoDrawObject(gw_display_struct * display,sar_menu_struct * m,int n,Boolean draw_shadows)3041 static void SARMenuDoDrawObject(
3042 	gw_display_struct *display, sar_menu_struct *m,
3043 	int n,                  /* Object number on m */
3044 	Boolean draw_shadows
3045 )
3046 {
3047 	Boolean draw_selected_rect = True, is_selected;
3048 	int i, x, y, xc, yc, w = 10, h = 10, width, height, len, type;
3049 	int fw, fh;
3050 	int items_visable, chars_per_row;
3051 	const char *cstrptr;
3052 	const sar_menu_color_struct *c;
3053 	void *o;
3054 	sar_menu_label_struct *label_ptr;
3055 	sar_menu_button_struct *button;
3056 	sar_menu_progress_struct *progress_ptr;
3057 	sar_menu_message_box_struct *mesgbox;
3058 	sar_menu_list_struct *list;
3059 	sar_menu_mdisplay_struct *mdpy;
3060 	sar_menu_switch_struct *sw;
3061 	sar_menu_spin_struct *spin;
3062 	sar_menu_slider_struct *slider;
3063 	sar_menu_map_struct *map;
3064 	sar_menu_objview_struct *objview;
3065 
3066 	static u_int8_t scroll_cursor_up_bm[] = {
3067 0xff, 0xff, 0x80, 0x01, 0xbf, 0xfd, 0xbf, 0xfd, 0x9f, 0xf9, 0x9f, 0xf9,
3068 0x8f, 0xf1, 0x8f, 0xf1, 0x87, 0xe1, 0x87, 0xe1, 0x83, 0xc1, 0x83, 0xc1,
3069 0x81, 0x81, 0x81, 0x81, 0x80, 0x01, 0xff, 0xff
3070 	};
3071 
3072 	static u_int8_t scroll_cursor_down_bm[] = {
3073 0xff, 0xff, 0x80, 0x01, 0x81, 0x81, 0x81, 0x81, 0x83, 0xc1, 0x83, 0xc1,
3074 0x87, 0xe1, 0x87, 0xe1, 0x8f, 0xf1, 0x8f, 0xf1, 0x9f, 0xf9, 0x9f, 0xf9,
3075 0xbf, 0xfd, 0xbf, 0xfd, 0x80, 0x01, 0xff, 0xff
3076 	};
3077 #if 0
3078 	static u_int8_t scroll_cursor_left_bm[] = {
3079 0xff, 0xff, 0x80, 0x01, 0x80, 0x0d, 0x80, 0x3d, 0x80, 0xfd, 0x83, 0xfd,
3080 0x8f, 0xfd, 0xbf, 0xfd, 0xbf, 0xfd, 0x8f, 0xfd, 0x83, 0xfd, 0x80, 0xfd,
3081 0x80, 0x3d, 0x80, 0x0d, 0x80, 0x01, 0xff, 0xff
3082 	};
3083 #endif
3084 #if 0
3085 	static u_int8_t scroll_cursor_right_bm[] = {
3086 0xff, 0xff, 0x80, 0x01, 0xb0, 0x01, 0xbc, 0x01, 0xbf, 0x01, 0xbf, 0xc1,
3087 0xbf, 0xf1, 0xbf, 0xfd, 0xbf, 0xfd, 0xbf, 0xf1, 0xbf, 0xc1, 0xbf, 0x01,
3088 0xbc, 0x01, 0xb0, 0x01, 0x80, 0x01, 0xff, 0xff
3089 	};
3090 #endif
3091 	const sar_image_struct *image;
3092 
3093 
3094 	if((display == NULL) || (m == NULL))
3095 	    return;
3096 
3097 	o = SARMenuGetObject(m, n);
3098 	if(o == NULL)
3099 	    return;
3100 
3101 	type = SAR_MENU_OBJECT_TYPE(o);
3102 
3103 	is_selected = (m->selected_object == n) ? True : False;
3104 
3105 	GWContextGet(
3106 	    display, GWContextCurrent(display),
3107 	    NULL, NULL,
3108 	    NULL, NULL,
3109 	    &width, &height
3110 	);
3111 
3112 #define DO_DRAW_IMAGE		\
3113 { if(image != NULL) {		\
3114  SARImageDraw(			\
3115   display, image,		\
3116   (int)(x - (w / 2)),		\
3117   (int)(y - (h / 2)),		\
3118   w, h				\
3119  );				\
3120 } }
3121 
3122 	switch(type)
3123 	{
3124 	  /* ******************************************************** */
3125 	  case SAR_MENU_OBJECT_TYPE_LABEL:
3126 	    label_ptr = SAR_MENU_LABEL(o);
3127 	    w = label_ptr->width;
3128 	    h = label_ptr->height;
3129 	    x = (int)(label_ptr->x * width) + label_ptr->offset_x;
3130 	    y = (int)(label_ptr->y * height) + label_ptr->offset_y;
3131 
3132 	    /* Draw label background image */
3133 	    image = label_ptr->image;
3134 	    DO_DRAW_IMAGE
3135 
3136 	    /* Draw label text */
3137 	    if(label_ptr->label != NULL)
3138 	    {
3139 		const char *s = label_ptr->label;
3140 		int	xp, yp,
3141 			lines = strlines(s),
3142 			longest_line = strlongestline(s);
3143 
3144 		GWGetFontSize(label_ptr->font, NULL, NULL, &fw, &fh);
3145 
3146 		/* Autocalculate width and height as needed */
3147 		if(w <= 0)
3148 		    w = fw * longest_line;
3149 		if(h <= 0)
3150 		    h = fh * lines;
3151 
3152 		/* Set label text font and color */
3153 	        GWSetFont(display, label_ptr->font);
3154 		c = &label_ptr->color;
3155 		if(label_ptr->sensitive)
3156 		    glColor4f(c->r, c->g, c->b, c->a);
3157 		else
3158 		    glColor4f(
3159 			c->r * 0.75f,
3160 			c->g * 0.75f,
3161 			c->b * 0.75f,
3162 			c->a
3163 		    );
3164 
3165 		/* Get starting position to draw label text */
3166 		xp = x - (fw * longest_line / 2);
3167 		yp = y - (fh * lines / 2);
3168 
3169 		/* Draw each line of the label text*/
3170 		while(*s != '\0')
3171 		{
3172 		    /* New line? */
3173 		    if(ISCR(*s))
3174 		    {
3175 			/* Restore x position and increment y position
3176 			 * to the next line
3177 			 */
3178 			switch(label_ptr->align)
3179 			{
3180 			  case SAR_MENU_LABEL_ALIGN_RIGHT:
3181 			    s++;
3182 			    xp = x + (fw * longest_line / 2) -
3183 				(fw * strlinelen(s));
3184 			    yp += fh;
3185 			    break;
3186 			  case SAR_MENU_LABEL_ALIGN_LEFT:
3187 			    s++;
3188 			    xp = x - (fw * longest_line / 2);
3189 			    yp += fh;
3190 			    break;
3191 			  default:	/* SAR_MENU_LABEL_ALIGN_CENTER */
3192 			    s++;
3193 			    xp = x - (fw * strlinelen(s) / 2);
3194 			    yp += fh;
3195 			    break;
3196 			}
3197 		    }
3198 		    else
3199 		    {
3200 			/* Draw current character */
3201 			GWDrawCharacter(display, xp, yp, *s);
3202 			s++;
3203 			xp += fw;
3204 		    }
3205 		}
3206 	    }
3207 	    break;
3208 
3209 	  /* ******************************************************** */
3210 	  case SAR_MENU_OBJECT_TYPE_BUTTON:
3211 	    button = SAR_MENU_BUTTON(o);
3212 	    w = button->width;
3213 	    h = button->height;
3214 	    x = (int)(button->x * width) + button->offset_x;
3215 	    y = (int)(button->y * height) + button->offset_y;
3216 	    /* Select image to use based on button state */
3217 	    switch(button->state)
3218 	    {
3219 	      case SAR_MENU_BUTTON_STATE_HIGHLIGHTED:
3220 		image = button->highlighted_image;
3221 		break;
3222 
3223 	      case SAR_MENU_BUTTON_STATE_ARMED:
3224 		image = button->armed_image;
3225 		break;
3226 
3227 	      default:
3228 		image = button->unarmed_image;
3229 		break;
3230 	    }
3231 	    /* If image is not available, then fall back to unarmed
3232 	     * image.
3233 	     */
3234 	    if(image == NULL)
3235 		image = button->unarmed_image;
3236 	    DO_DRAW_IMAGE
3237 
3238 	    /* Draw label */
3239 	    cstrptr = button->label;
3240 	    if(cstrptr != NULL)
3241 	    {
3242 		int x_min, x_max, y_min, y_max;
3243 
3244 		x_min = x - (w / 2);
3245 		x_max = x_min + w;
3246 		y_min = y - (h / 2);
3247 		y_max = y_min + h;
3248 
3249 		len = STRLEN(cstrptr);
3250 		GWGetFontSize(button->font, NULL, NULL, &fw, &fh);
3251 		GWSetFont(display, button->font);
3252 		c = &button->color;
3253 		if(button->sensitive)
3254 		    glColor4f(c->r, c->g, c->b, c->a);
3255 		else
3256 		    glColor4f(
3257 			c->r * 0.75f,
3258 			c->g * 0.75f,
3259 			c->b * 0.75f,
3260 			c->a
3261 		    );
3262 		GWDrawString(
3263 		    display,
3264 		    x - (len * fw / 2),
3265 		    y - (fh / 2),
3266 		    cstrptr
3267 		);
3268 
3269 		/* Do not draw outlines for buttons */
3270 	    }
3271 	    break;
3272 
3273 	  /* ******************************************************** */
3274 	  case SAR_MENU_OBJECT_TYPE_PROGRESS:
3275 	    progress_ptr = SAR_MENU_PROGRESS(o);
3276 
3277 	    x = (int)(progress_ptr->x * width);
3278 	    y = (int)(progress_ptr->y * height);
3279 
3280 	    if(progress_ptr->width > 0)
3281 		w = progress_ptr->width;
3282 	    else
3283 /*		w = width - (2 * DEF_XMARGIN); */
3284 		w = width;		/* Butt left to right end */
3285 
3286 	    if(progress_ptr->height > 0)
3287 		h = progress_ptr->height;
3288 	    else
3289 		h = DEF_PROGRESS_HEIGHT;
3290 
3291 	    xc = MAX(x - (w / 2), 0);
3292 	    yc = MAX(y - (h / 2), 0);
3293 	    if((yc + h) > height)
3294 		yc = height - h;
3295 
3296 	    /* Draw progress background */
3297 	    SARImageDraw(display, progress_ptr->bg_image, xc, yc, w, h);
3298 #if 0
3299 	    if(GL_TRUE)
3300 	    {
3301 		StateGLBoolean alpha_test = display->state_gl.alpha_test;
3302 		StateGLBoolean blend = display->state_gl.blend;
3303 
3304 		/* Set up GL states */
3305 		StateGLDisable(&display->state_gl, GL_ALPHA_TEST);
3306 		StateGLEnable(&display->state_gl, GL_BLEND);
3307 		StateGLBlendFunc(
3308 		    &display->state_gl, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
3309 		);
3310 
3311 		glColor4f(0.0f, 0.0f, 0.0f, 0.25f);
3312 		glBegin(GL_QUADS);
3313 		{
3314 		    glVertex2i(xc, height - yc);
3315 		    glVertex2i(xc, height - (yc + h));
3316 		    glVertex2i(xc + w, height - (yc + h));
3317 		    glVertex2i(xc + w, height - yc);
3318 		}
3319 		glEnd();
3320 
3321 		/* Restore GL states */
3322 		if(alpha_test)
3323 		    StateGLEnable(&display->state_gl, GL_ALPHA_TEST);
3324 		if(!blend)
3325 		    StateGLDisable(&display->state_gl, GL_BLEND);
3326 	    }
3327 #endif
3328 	    /* Draw progress foreground */
3329 	    SARImageDraw(
3330 		display, progress_ptr->fg_image,
3331 		xc, yc,
3332 		(int)(w * progress_ptr->progress), h
3333 	    );
3334 	    break;
3335 
3336 	  /* ******************************************************** */
3337 	  case SAR_MENU_OBJECT_TYPE_MESSAGE_BOX:
3338 	    mesgbox = SAR_MENU_MESSAGE_BOX(o);
3339 
3340 	    x = (int)(mesgbox->x * width);
3341 	    y = (int)(mesgbox->y * height);
3342 
3343 	    w = (int)(mesgbox->width * width);
3344 	    if(w <= 0)
3345 		w = width - (2 * DEF_MB_XMARGIN);
3346 	    if(w <= 0)
3347 		w = DEF_MB_XMARGIN;
3348 
3349 	    if(mesgbox->height > 0)
3350 		h = (int)(mesgbox->height * height);
3351 	    else
3352 		h = DEF_HEIGHT;
3353 	    if(h <= 0)
3354 		h = DEF_MB_YMARGIN;
3355 
3356 	    xc = MAX(x - (w / 2), 0);
3357 	    yc = MAX(y - (h / 2), 0);
3358 
3359 	    SARMenuDrawWindowBG(
3360 		display, mesgbox->bg_image, NULL,
3361 		xc, yc,
3362 		w, h,
3363 		True,		/* Draw base */
3364 		draw_shadows,	/* Draw shadow */
3365 		(Boolean)((draw_selected_rect && is_selected) ? True : False)
3366 	    );
3367 
3368 	    GWGetFontSize(
3369 		mesgbox->font,
3370 		NULL, NULL,
3371 		&fw, &fh
3372 	    );
3373 
3374 	    GWSetFont(display, mesgbox->font);
3375 	    c = &mesgbox->color;
3376 	    if(mesgbox->sensitive)
3377 		glColor4f(c->r, c->g, c->b, c->a);
3378 	    else
3379 		glColor4f(
3380 		    c->r * 0.75f,
3381 		    c->g * 0.75f,
3382 		    c->b * 0.75f,
3383 		    c->a
3384 		);
3385 
3386 	    /* Has message to be drawn? */
3387 	    if(mesgbox->message != NULL)
3388 	    {
3389 		Boolean actually_draw_line;
3390 		const char *buf_ptr;
3391 		int lines_processed = 0, lines_drawn = 0;
3392 		int lines_to_skip = mesgbox->scrolled_line;
3393 		int	mesg_x, mesg_y,
3394 			lines_visable, columns_visable, scroll_width;
3395 		const sar_menu_color_struct	*c_b = &mesgbox->bold_color,
3396 						*c_u = &mesgbox->underline_color;
3397 
3398 		/* Calculate width (height) of scroll indicator */
3399 		scroll_width = fh + (2 * DEF_MB_YMARGIN);
3400 
3401 		/* Calculate lines visable */
3402 		if(fh > 0)
3403 		    lines_visable = (h - (2 * DEF_MB_YMARGIN)) / fh;
3404 		else
3405 		    lines_visable = 0;
3406 		if(lines_visable < 0)
3407 		    lines_visable = 0;
3408 
3409 		/* Calculate columns visable (include margin for arrows) */
3410 		if(fw > 0)
3411 		    columns_visable = (w - DEF_SCROLL_CURSOR_WIDTH
3412 			- (2 * DEF_MB_XMARGIN)) / fw;
3413 		else
3414 		    columns_visable = 1;
3415 		/* Must have atleast one column visible */
3416 		if(columns_visable < 1)
3417 		    columns_visable = 1;
3418 
3419 		/* Draw scroll up and scroll down arrows */
3420 		glRasterPos2i(
3421 		    xc + w - DEF_SCROLL_CURSOR_WIDTH - DEF_MB_XMARGIN,
3422 		    height - (yc + DEF_SCROLL_CURSOR_HEIGHT + DEF_MB_YMARGIN)
3423 		);
3424 		glBitmap(
3425 		    DEF_SCROLL_CURSOR_WIDTH,
3426 		    DEF_SCROLL_CURSOR_HEIGHT,
3427 		    0.0, 0.0,
3428 		    DEF_SCROLL_CURSOR_WIDTH, 0.0,
3429 		    scroll_cursor_up_bm
3430 		);
3431 		glRasterPos2i(
3432 		    xc + w - DEF_SCROLL_CURSOR_WIDTH - DEF_MB_XMARGIN,
3433 		    height - (y + (h / 2) - DEF_MB_YMARGIN)
3434 		);
3435 		glBitmap(
3436 		    DEF_SCROLL_CURSOR_WIDTH,
3437 		    DEF_SCROLL_CURSOR_HEIGHT,
3438 		    0.0, 0.0,
3439 		    DEF_SCROLL_CURSOR_WIDTH, 0.0,
3440 		    scroll_cursor_down_bm
3441 		);
3442 
3443 		/* Get pointer to start of message buffer and begin
3444 		 * drawing lines.
3445 		 */
3446 		buf_ptr = mesgbox->message;
3447 		lines_processed = 0;
3448 		mesg_x = xc + DEF_MB_XMARGIN;
3449 		mesg_y = yc + DEF_MB_YMARGIN;
3450 		do
3451 		{
3452 		    actually_draw_line = (lines_processed >= lines_to_skip) ?
3453 			True : False;
3454 
3455 		    buf_ptr = SARMenuMessageBoxDrawString(
3456 			display,
3457 			mesg_x, mesg_y,
3458 			buf_ptr,
3459 			columns_visable, fw,
3460 			mesgbox->sensitive,
3461 			actually_draw_line,
3462 			c,		/* Foreground color */
3463 			c_b,		/* Bold color */
3464 			c_u		/* Underline color */
3465 		    );
3466 		    lines_processed++;
3467 
3468 		    if(actually_draw_line)
3469 		    {
3470 			lines_drawn++;
3471 			mesg_y += fh;
3472 		    }
3473 		}
3474 		while((buf_ptr != NULL) && (lines_drawn < lines_visable));
3475 	    }
3476 	    break;
3477 
3478 	  /* ******************************************************** */
3479 	  case SAR_MENU_OBJECT_TYPE_LIST:
3480 	    list = SAR_MENU_LIST(o);
3481 
3482 	    x = (int)(list->x * width);
3483 	    y = (int)(list->y * height);
3484 
3485 	    w = (int)(list->width * width);
3486 	    if(w <= 0)
3487 		w = width - (2 * DEF_LIST_XMARGIN);
3488 	    if(w <= 0)
3489 		w = DEF_LIST_XMARGIN;
3490 
3491 	    if(list->height > 0)
3492 		h = (int)(list->height * height);
3493 	    else
3494 		h = DEF_HEIGHT;
3495 	    if(h <= 0)
3496 		h = DEF_LIST_YMARGIN;
3497 
3498 	    xc = MAX(x - (w / 2), 0);
3499 	    yc = MAX(y - (h / 2), 0);
3500 
3501 	    SARMenuDrawWindowBG(
3502 		display, list->bg_image, NULL,
3503 		xc, yc,
3504 		w, h,
3505 		True,		/* Draw base */
3506 		draw_shadows,	/* Draw shadow */
3507 		(Boolean)((draw_selected_rect && is_selected) ? True : False)
3508 	    );
3509 
3510 	    GWGetFontSize(
3511 		list->font,
3512 		NULL, NULL,
3513 		&fw, &fh
3514 	    );
3515 	    /* Calculate items visible, remember to subtract three
3516 	     * items for borders and heading.
3517 	     */
3518 	    if(fh > 0)
3519 		items_visable = MAX(
3520 		    (h / fh) - 3,
3521 		    0
3522 		);
3523 	    else
3524 		items_visable = 0;
3525 	    /* Update items visable on list */
3526 	    list->items_visable = items_visable;
3527 
3528 	    /* Recalculate scroll position if too great */
3529 	    if((list->total_items - list->scrolled_item) <
3530 		items_visable
3531 	    )
3532 	        list->scrolled_item = MAX(
3533 		    list->total_items - items_visable,
3534 		    0
3535 		);
3536 
3537 	    /* Calculate len as lines visable + yc */
3538 	    len = yc + h;
3539 
3540 	    /* Calculate characters per row */
3541 	    if(fw > 0)
3542 		chars_per_row = MAX(
3543 		    (w - DEF_SCROLL_CURSOR_WIDTH -
3544 			(3 * DEF_LIST_XMARGIN)) / fw,
3545 		    1
3546 		);
3547 	    else
3548 		chars_per_row = 1;
3549 
3550 	    /* Draw heading label */
3551 	    yc += DEF_LIST_YMARGIN;
3552 	    GWSetFont(display, list->font);
3553 	    c = &list->color;
3554 	    if(list->sensitive)
3555 		glColor4f(c->r, c->g, c->b, c->a);
3556 	    else
3557 		glColor4f(
3558 		    c->r * 0.75f,
3559 		    c->g * 0.75f,
3560 		    c->b * 0.75f,
3561 		    c->a
3562 		);
3563 	    GWDrawString(
3564 		display,
3565 		xc + DEF_LIST_XMARGIN, yc,
3566 		list->label
3567 	    );
3568 	    yc += fh;
3569 
3570 	    /* Draw scroll up and down arrows */
3571 	    glRasterPos2i(
3572 		xc + w - DEF_SCROLL_CURSOR_WIDTH - DEF_LIST_XMARGIN,
3573 		height - (yc + DEF_SCROLL_CURSOR_HEIGHT)
3574 	    );
3575 	    glBitmap(
3576 		DEF_SCROLL_CURSOR_WIDTH,
3577 		DEF_SCROLL_CURSOR_HEIGHT,
3578 		0.0, 0.0,
3579 		DEF_SCROLL_CURSOR_WIDTH, 0.0,
3580 		scroll_cursor_up_bm
3581 	    );
3582 	    glRasterPos2i(
3583 		xc + w - DEF_SCROLL_CURSOR_WIDTH - DEF_LIST_XMARGIN,
3584 		height - (y + (h / 2) - DEF_LIST_YMARGIN)
3585 	    );
3586 	    glBitmap(
3587 		DEF_SCROLL_CURSOR_WIDTH,
3588 		DEF_SCROLL_CURSOR_HEIGHT,
3589 		0.0, 0.0,
3590 		DEF_SCROLL_CURSOR_WIDTH, 0.0,
3591 		scroll_cursor_down_bm
3592 	    );
3593 
3594 	    /* Sanitize scrolled item position */
3595 	    if(list->scrolled_item < 0)
3596 		list->scrolled_item = 0;
3597 
3598 	    /* Draw each item */
3599 	    for(i = list->scrolled_item; i < list->total_items; i++)
3600 	    {
3601 #define item_name_len	256
3602 		char item_name[item_name_len];
3603 		sar_menu_list_item_struct *item = list->item[i];
3604 		if((item != NULL) ? (item->name == NULL) : True)
3605 		    continue;
3606 
3607 		if((yc + fh) >= len)
3608 		    break;
3609 
3610 		/* Copy item name and shorten it as needed */
3611 		strncpy(item_name, item->name, item_name_len);
3612 		if(chars_per_row < item_name_len)
3613 		    item_name[chars_per_row] = '\0';
3614 		else
3615 		    item_name[item_name_len - 1] = '\0';
3616 
3617 		/* Draw item name */
3618 		GWDrawString(
3619 		    display,
3620 		    xc + (1 * fw) + DEF_LIST_XMARGIN,
3621 		    yc,
3622 		    item_name
3623 		);
3624 		/* If this item is selected then draw selection marker
3625 		 * in front of the item's name.
3626 		 */
3627 		if(i == list->selected_item)
3628 		    GWDrawString(
3629 		    display,
3630 		    xc + DEF_LIST_XMARGIN, yc,
3631 		    ">"
3632 		);
3633 
3634 		yc += fh;
3635 #undef item_name_len
3636 	    }
3637 	    break;
3638 
3639 	  /* ******************************************************** */
3640 	  case SAR_MENU_OBJECT_TYPE_MDISPLAY:
3641 	    mdpy = SAR_MENU_MDISPLAY(o);
3642 
3643 	    x = (int)(mdpy->x * width);
3644 	    y = (int)(mdpy->y * height);
3645 
3646 	    w = (int)(mdpy->width * width);
3647 	    if(w <= 0)
3648 		w = width - (2 * DEF_LIST_XMARGIN);
3649 	    if(w <= 0)
3650 		w = DEF_LIST_XMARGIN;
3651 
3652 	    if(mdpy->height > 0)
3653 		h = (int)(mdpy->height * height);
3654 	    else
3655 		h = DEF_HEIGHT;
3656 	    if(h <= 0)
3657 		h = DEF_LIST_YMARGIN;
3658 
3659 	    xc = MAX(x - (w / 2), 0);
3660 	    yc = MAX(y - (h / 2), 0);
3661 
3662 	    SARMenuDrawWindowBG(
3663 		display, mdpy->bg_image, NULL,
3664 		xc, yc,
3665 		w, h,
3666 		True,		/* Draw base */
3667 		draw_shadows,	/* Draw shadow */
3668 		(Boolean)((draw_selected_rect && is_selected) ? True : False)
3669 	    );
3670 
3671 	    if(mdpy->draw_cb != NULL)
3672 		mdpy->draw_cb(
3673 		    display,		/* Display */
3674 		    m,			/* Menu */
3675 		    o,			/* This Object */
3676 		    mdpy->id,		/* ID Code */
3677 		    mdpy->client_data,	/* Data */
3678 		    xc, yc, xc + w, yc + h
3679 		);
3680 #if 0
3681 	    /* Draw outline if selected */
3682 	    if(draw_selected_rect && is_selected)
3683 	    {
3684 		int     x_min = x - (w / 2),
3685 			x_max = x_min + w,
3686 			y_min = y - (h / 2),
3687 			y_max = y_min + h;
3688 		glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
3689 		glBegin(GL_LINE_LOOP);
3690 		{
3691 		    glVertex2i(x_min, height - y_min);
3692 		    glVertex2i(x_min, height - y_max);
3693 		    glVertex2i(x_max, height - y_max);
3694 		    glVertex2i(x_max, height - y_min);
3695 		}
3696 		glEnd();
3697 	    }
3698 #endif
3699 	    break;
3700 
3701 	  /* ******************************************************** */
3702 	  case SAR_MENU_OBJECT_TYPE_SWITCH:
3703 	    sw = SAR_MENU_SWITCH(o);
3704 	    w = sw->width;
3705 	    h = sw->height;
3706 
3707 	    GWGetFontSize(
3708 		sw->font,
3709 		NULL, NULL,
3710 		&fw, &fh
3711 	    );
3712 
3713 	    if(w <= 0)
3714 		w = MAX(
3715 		    (2 * DEF_XMARGIN) + DEF_SWITCH_WIDTH,
3716 		    (2 * DEF_XMARGIN) + (STRLEN(sw->label) * fw)
3717 		);
3718 	    if(h <= 0)
3719 		h = (1 * DEF_YMARGIN) + DEF_SWITCH_HEIGHT +
3720 		    ((sw->label != NULL) ? fh : 0);
3721 
3722 	    x = (int)(sw->x * width);
3723 	    y = (int)(sw->y * height);
3724 
3725 	    image = sw->bg_image;
3726 	    DO_DRAW_IMAGE
3727 
3728 	    if(sw->label != NULL)
3729 	    {
3730 		const char *label = sw->label;
3731 
3732 		GWSetFont(display, sw->font);
3733 		c = &sw->color;
3734 		if(sw->sensitive)
3735 		    glColor4f(c->r, c->g, c->b, c->a);
3736 		else
3737 		    glColor4f(
3738 			c->r * 0.75f,
3739 			c->g * 0.75f,
3740 			c->b * 0.75f,
3741 			c->a
3742 		    );
3743 		GWDrawString(
3744 		    display,
3745 		    x - (w / 2) + DEF_XMARGIN,
3746 		    y - (h / 2) + DEF_SWITCH_HEIGHT,
3747 		    label
3748 		);
3749 	    }
3750 
3751 	    /* Check state of switch and choose the appropriate switch
3752 	     * image to draw.
3753 	     */
3754 	    if(sw->state)
3755 		image = sw->switch_on_image;
3756 	    else
3757 		image = sw->switch_off_image;
3758 	    SARImageDraw(
3759 		display,
3760 		image,
3761 		x - (DEF_SWITCH_WIDTH / 2),
3762 		y - (h / 2) + 2,	/* Move down a little */
3763 		DEF_SWITCH_WIDTH, DEF_SWITCH_HEIGHT
3764 	    );
3765 
3766 	    /* Draw outline if selected */
3767 	    if(draw_selected_rect && is_selected)
3768 	    {
3769 		int     x_min = x - (w / 2) + 2,
3770 			x_max = x_min + w - 4,
3771 			y_min = y - (h / 2) + 2,
3772 			y_max = y_min + h - 4;
3773 		glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
3774 		glBegin(GL_LINE_LOOP);
3775 		{
3776 		    glVertex2i(x_min, height - y_min);
3777 		    glVertex2i(x_min, height - y_max);
3778 		    glVertex2i(x_max, height - y_max);
3779 		    glVertex2i(x_max, height - y_min);
3780 		}
3781 		glEnd();
3782 	    }
3783  	    break;
3784 
3785 	  /* ******************************************************** */
3786 	  case SAR_MENU_OBJECT_TYPE_SPIN:
3787 	    spin = SAR_MENU_SPIN(o);
3788 
3789 	    GWGetFontSize(
3790 		spin->font,
3791 		NULL, NULL,
3792 		&fw, &fh
3793 	    );
3794 
3795 	    w = (int)(width * spin->width);
3796 	    h = (int)MAX(
3797 		height * spin->height,
3798 		(4 * DEF_YMARGIN) + fh
3799 	    );
3800 
3801 	    x = (int)(width * spin->x);
3802 	    y = (int)(height * spin->y);
3803 
3804 	    if((w > 0) && (h > 0))
3805 	    {
3806 		int	x_start = x - (w / 2),
3807 			y_start = y - (h / 2),
3808 			label_len = STRLEN(spin->label),
3809 			label_width = (2 * DEF_XMARGIN) + (label_len * fw);
3810 
3811 		/* Draw label background */
3812 		SARImageDraw(
3813 		    display,
3814 		    spin->label_image,
3815 		    x_start,
3816 		    y_start,
3817 		    label_width,
3818 		    h
3819 		);
3820 		GWSetFont(display, spin->font);
3821 		c = &spin->label_color;
3822 		if(spin->sensitive)
3823 		    glColor4f(c->r, c->g, c->b, c->a);
3824 		else
3825 		    glColor4f(
3826 			c->r * 0.75f,
3827 			c->g * 0.75f,
3828 			c->b * 0.75f,
3829 			c->a
3830 		    );
3831 		GWDrawString(
3832 		    display,
3833 		    x_start + DEF_XMARGIN,
3834 		    y - (fh / 2),
3835 		    spin->label
3836 		);
3837 
3838 
3839 		/* Begin drawing value just to the right of the label */
3840 		GWSetFont(display, spin->value_font);
3841 		GWGetFontSize(
3842 		    spin->value_font,
3843 		    NULL, NULL,
3844 		    &fw, &fh
3845 		);
3846 		/* Draw value background */
3847 		SARImageDraw(
3848 		    display,
3849 		    spin->value_image,
3850 		    x_start + label_width - 1,	/* Overlap one pixel to the left */
3851 		    y_start,
3852 		    MAX(w - label_width, 0),
3853 		    h
3854 		);
3855 
3856 		/* Current spin value valid? */
3857 		if((spin->cur_value >= 0) &&
3858 		   (spin->cur_value < spin->total_values)
3859 		)
3860 		{
3861 		    const char *value_ptr = (const char *)spin->value[
3862 			spin->cur_value
3863 		    ];
3864 		    if(value_ptr != NULL)
3865 		    {
3866 			int	value_len = STRLEN(value_ptr),
3867 				value_width = value_len * fw,
3868 				value_twidth = w - label_width;
3869 
3870 			/* Draw outline around value if selected */
3871 			if(draw_selected_rect && is_selected)
3872 			{
3873 			    int	x_min = x_start + label_width +
3874 				(value_twidth / 2) - (value_width / 2) - 1,
3875 				x_max = x_min + value_width + 2,
3876 				y_min = y - (fh / 2) - 1,
3877 				y_max = y_min + fh + 2;
3878 			    c = &spin->value_color;
3879 			    glColor4f(
3880 				c->r * 0.5f,
3881 				c->g * 0.5f,
3882 				c->b * 0.5f,
3883 				c->a
3884 			    );
3885 			    glBegin(GL_LINE_LOOP);
3886 			    {
3887 				glVertex2i(x_min, height - y_min);
3888 				glVertex2i(x_min, height - y_max);
3889 				glVertex2i(x_max, height - y_max);
3890 				glVertex2i(x_max, height - y_min);
3891 			    }
3892 			    glEnd();
3893 			}
3894 
3895 			/* Draw value */
3896 			c = &spin->value_color;
3897 			if(spin->sensitive)
3898 			    glColor4f(c->r, c->g, c->b, c->a);
3899 			else
3900 			    glColor4f(
3901 				c->r * 0.75f,
3902 				c->g * 0.75f,
3903 				c->b * 0.75f,
3904 				c->a
3905 			    );
3906 			GWDrawString(
3907 			    display,
3908 			    x_start + label_width +
3909 				(value_twidth / 2) - (value_width / 2),
3910 			    y - (fh / 2),
3911 			    value_ptr
3912 			);
3913 		    }
3914 		}
3915 
3916 		/* Draw decrement button */
3917 		switch(spin->dec_state)
3918 		{
3919 		  case SAR_MENU_BUTTON_STATE_UNARMED:
3920 		  case SAR_MENU_BUTTON_STATE_HIGHLIGHTED:
3921 		    image = spin->dec_unarmed_image;
3922 		    break;
3923 		  default:
3924 		    image = spin->dec_armed_image;
3925 		    break;
3926 		}
3927 		if(image != NULL)
3928 		{
3929 		    int img_w = MIN(image->width, h),
3930 			img_h = MIN(image->height, h);
3931 		    SARImageDraw(
3932 			display, image,
3933 			x_start + label_width - 1,	/* Overlap one pixel to the left */
3934 			y_start + (h / 2) - (img_h / 2),
3935 			img_w, img_h
3936 		    );
3937 		}
3938 
3939 		/* Draw increment button */
3940 		switch(spin->inc_state)
3941 		{
3942 		  case SAR_MENU_BUTTON_STATE_UNARMED:
3943 		  case SAR_MENU_BUTTON_STATE_HIGHLIGHTED:
3944 		    image = spin->inc_unarmed_image;
3945 		    break;
3946 		  default:
3947 		    image = spin->inc_armed_image;
3948 		    break;
3949 		}
3950 		if(image != NULL)
3951 		{
3952 		    int	img_w = MIN(image->width, h),
3953 			img_h = MIN(image->height, h);
3954 		    SARImageDraw(
3955 			display, image,
3956 			x_start + w - h,
3957 			y_start + (h / 2) - (img_h / 2),
3958 			img_w, img_h
3959 		    );
3960 		}
3961 #if 0
3962 			/* Draw spin left arrow? */
3963 			if(spin->allow_warp ? True :
3964 			    (spin->cur_value > 0)
3965 			)
3966 			{
3967 			    glRasterPos2i(
3968 				x_start + label_width + (3 * DEF_XMARGIN),
3969 				height - (y_start + (h / 2) -
3970 				    (DEF_SCROLL_CURSOR_HEIGHT / 2) +
3971 				    DEF_SCROLL_CURSOR_HEIGHT
3972 			        )
3973 			    );
3974 			    glBitmap(
3975 				DEF_SCROLL_CURSOR_WIDTH,
3976 				DEF_SCROLL_CURSOR_HEIGHT,
3977 				0.0, 0.0,
3978 				DEF_SCROLL_CURSOR_WIDTH, 0.0,
3979 				scroll_cursor_left_bm
3980 			    );
3981 			}
3982 			/* Draw spin right arrow? */
3983 			if(spin->allow_warp ? True :
3984 			    (spin->cur_value < (spin->total_values - 1))
3985 			)
3986 			{
3987 			    glRasterPos2i(
3988 				x_start + w - (3 * DEF_XMARGIN) -
3989 				    DEF_SCROLL_CURSOR_WIDTH,
3990 				height - (y_start + (h / 2) -
3991 				    (DEF_SCROLL_CURSOR_HEIGHT / 2) +
3992 				    DEF_SCROLL_CURSOR_HEIGHT
3993 				)
3994 			    );
3995 			    glBitmap(
3996 				DEF_SCROLL_CURSOR_WIDTH,
3997 				DEF_SCROLL_CURSOR_HEIGHT,
3998 				0.0, 0.0,
3999 				DEF_SCROLL_CURSOR_WIDTH, 0.0,
4000 				scroll_cursor_right_bm
4001 			    );
4002 			}
4003 #endif
4004 #if 0
4005 		/* Draw outline if selected */
4006 		if(draw_selected_rect && is_selected)
4007 		{
4008 		    int	x_min = x - (w / 2),
4009 			x_max = x_min + w,
4010 			y_min = y - (h / 2),
4011 			y_max = y_min + h;
4012 		    glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
4013 		    glBegin(GL_LINE_LOOP);
4014 		    {
4015 			glVertex2i(x_min, height - y_min);
4016 			glVertex2i(x_min, height - y_max);
4017 			glVertex2i(x_max, height - y_max);
4018 			glVertex2i(x_max, height - y_min);
4019 		    }
4020 		    glEnd();
4021 		}
4022 #endif
4023 	    }
4024 	    break;
4025 
4026 	  /* ******************************************************** */
4027 	  case SAR_MENU_OBJECT_TYPE_SLIDER:
4028 	    slider = SAR_MENU_SLIDER(o);
4029 
4030 	    GWGetFontSize(
4031 		slider->font,
4032 		NULL, NULL,
4033 		&fw, &fh
4034 	    );
4035 
4036 	    w = (int)(width * slider->width);
4037 	    h = (int)MAX(
4038 		height * slider->height,
4039 		(4 * DEF_YMARGIN) + fh
4040 	    );
4041 
4042 	    x = (int)(width * slider->x);
4043 	    y = (int)(height * slider->y);
4044 
4045 	    if((w > 0) && (h > 0))
4046 	    {
4047 		int	x_start = x - (w / 2),
4048 			y_start = y - (h / 2),
4049 			label_len = STRLEN(slider->label),
4050 			label_width = (4 * DEF_XMARGIN) + (label_len * fw);
4051 
4052 		/* Draw label background */
4053 		SARImageDraw(
4054 		    display,
4055 		    slider->label_image,
4056 		    x_start,
4057 		    y_start,
4058 		    label_width,
4059 		    h
4060 		);
4061 		GWSetFont(display, slider->font);
4062 		c = &slider->label_color;
4063 		if(slider->sensitive)
4064 		    glColor4f(c->r, c->g, c->b, c->a);
4065 		else
4066 		    glColor4f(
4067 			c->r * 0.75f,
4068 			c->g * 0.75f,
4069 			c->b * 0.75f,
4070 			c->a
4071 		    );
4072 		GWDrawString(
4073 		    display,
4074 		    x_start + DEF_XMARGIN,
4075 		    y - (fh / 2),
4076 		    slider->label
4077 		);
4078 
4079 		/* Draw trough background */
4080 		SARImageDraw(
4081 		    display,
4082 		    slider->trough_image,
4083 		    x_start + label_width - 1,  /* Overlap one pixel to the left */
4084 		    y_start,
4085 		    MAX(w - label_width, 0),
4086 		    h
4087 		);
4088 
4089 		/* Draw handle */
4090 		image = slider->handle_image;
4091 		if(image != NULL)
4092 		{
4093 		    int trough_range = MAX(
4094 			w - label_width - (2 * DEF_XMARGIN),
4095 			0
4096 		    );
4097 		    int handle_x = x_start + label_width - 1 +
4098 			DEF_XMARGIN - (image->width / 2);
4099 		    int handle_y = y_start + (h / 2) -
4100 			(image->height / 2);
4101 		    float vrange = slider->upper - slider->lower;
4102 		    float vc = (vrange > 0.0f) ?
4103 			(slider->value / vrange) : 0.0f;
4104 
4105 		    handle_x += (int)(vc * trough_range);
4106 		    if((handle_x + image->width + 1) > (x_start - 1 + w))
4107 			handle_x = (x_start - 1 + w) - (image->width + 1);
4108 
4109 		    SARImageDraw(
4110 			display,
4111 			image,
4112 			handle_x, handle_y,
4113 			image->width, image->height
4114 		    );
4115 		}
4116 
4117 		/* Draw outline if selected */
4118 		if(draw_selected_rect && is_selected)
4119 		{
4120 		    int	x_min = x - (w / 2) + 2,
4121 			x_max = x_min + w - 4,
4122 			y_min = y - (h / 2) + 2,
4123 			y_max = y_min + h - 4;
4124 		    glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
4125 		    glBegin(GL_LINE_LOOP);
4126 		    {
4127 			glVertex2i(x_min, height - y_min);
4128 			glVertex2i(x_min, height - y_max);
4129 			glVertex2i(x_max, height - y_max);
4130 			glVertex2i(x_max, height - y_min);
4131 		    }
4132 		    glEnd();
4133 		}
4134 	    }
4135 	    break;
4136 
4137 	  /* ******************************************************** */
4138 	  case SAR_MENU_OBJECT_TYPE_MAP:
4139 	    map = SAR_MENU_MAP(o);
4140 
4141 	    /* Draw map object with its own drawing function first */
4142 	    SARMenuMapDraw(display, m, map, n);
4143 
4144 	    /* Calculate map object geometry for window frame drawing */
4145 	    x = (int)(map->x * width);
4146 	    y = (int)(map->y * height);
4147 
4148 	    /* Calculate size to be one pixel bigger (to ensure cover) */
4149 	    w = (int)(map->width * width) + 2;
4150 	    h = (int)(map->height * height) + 2;
4151 
4152 	    xc = MAX(x - (w / 2) - 1, 0);
4153 	    yc = MAX(y - (h / 2) - 1, 0);
4154 
4155 	    SARMenuDrawWindowBG(
4156 		display, map->bg_image, NULL,
4157 		xc, yc,
4158 		w, h,
4159 		False,		/* Do not draw base */
4160 		draw_shadows,	/* Draw shadow */
4161 		(Boolean)((draw_selected_rect && is_selected) ? True : False)
4162 	    );
4163 	    break;
4164 
4165 	  /* ******************************************************** */
4166 	  case SAR_MENU_OBJECT_TYPE_OBJVIEW:
4167 	    objview = SAR_MENU_OBJVIEW(o);
4168 
4169 	    /* Calculate 3d object viewer object geometry for window
4170 	     * frame drawing.
4171 	     */
4172 	    x = (int)(objview->x * width);
4173 	    y = (int)(objview->y * height);
4174 
4175 	    /* Calculate size to be one pixel bigger (to ensure cover) */
4176 	    w = (int)(objview->width * width) + 2;
4177 	    h = (int)(objview->height * height) + 2;
4178 
4179 	    xc = MAX(x - (w / 2) - 1, 0);
4180 	    yc = MAX(y - (h / 2) - 1, 0);
4181 
4182 	    SARMenuDrawWindowBG(
4183 		display, objview->bg_image, &objview->bg_color,
4184 		xc, yc,
4185 		w, h,
4186 		True,		/* Draw base */
4187 		draw_shadows,	/* Draw shadow */
4188 		(Boolean)((draw_selected_rect && is_selected) ? True : False)
4189 	    );
4190 
4191 	    /* Draw buffered 3d object image, this image has an alpha
4192 	     * channel so it should be drawn over the base of the
4193 	     * window background drawn above.
4194 	     */
4195 	    if(objview->objimg != NULL)
4196 	    {
4197 		sar_image_struct tmp_img;
4198 		float aspect = (float)((objview->objimg_width > 0) ?
4199 		    ((float)objview->objimg_height /
4200 			(float)objview->objimg_width) : 0.75
4201 		);
4202 		int	draw_width = w,
4203 			draw_height = (int)(w * aspect);
4204 
4205 		if((draw_height > h) && (aspect > 0.0f))
4206 		{
4207 		    draw_width = (int)(h / aspect);
4208 		    draw_height = h;
4209 		}
4210 
4211 		tmp_img.width = objview->objimg_width;
4212 		tmp_img.height = objview->objimg_height;
4213 		tmp_img.data = objview->objimg;
4214 
4215 		StateGLEnable(&display->state_gl, GL_SCISSOR_TEST);
4216 		StateGLScissor(
4217 		    &display->state_gl,
4218 		    xc + DEF_MB_XMARGIN,
4219 		    height - yc - h + DEF_MB_YMARGIN,
4220 		    MAX(w - (2 * DEF_MB_XMARGIN), DEF_MB_XMARGIN),
4221 		    MAX(h - (2 * DEF_MB_YMARGIN), DEF_MB_YMARGIN)
4222 		);
4223 		if(objview->show_message)
4224 		    SARImageDraw(
4225 			display, &tmp_img,
4226 			MAX(x + (w / 2) - draw_width, 0),
4227 			MAX(y - (draw_height / 2), 0),
4228 			draw_width, draw_height
4229 		    );
4230 		else
4231 		    SARImageDraw(
4232 			display, &tmp_img,
4233 			MAX(x - (draw_width / 2), 0),
4234 			MAX(y - (draw_height / 2), 0),
4235 			draw_width, draw_height
4236 		    );
4237 		StateGLDisable(&display->state_gl, GL_SCISSOR_TEST);
4238 	    }
4239 
4240 	    /* Begin drawing message */
4241 
4242 	    GWGetFontSize(
4243 		objview->font,
4244 		NULL, NULL,
4245 		&fw, &fh
4246 	    );
4247 	    GWSetFont(display, objview->font);
4248 
4249 	    /* Draw message? */
4250 	    if((objview->message != NULL) && objview->show_message)
4251 	    {
4252 		int	draw_x = xc + DEF_MB_XMARGIN,
4253 			draw_y = yc + DEF_MB_YMARGIN;
4254 		const char *buf_ptr = objview->message;
4255 		const sar_menu_color_struct *c_b = &objview->bold_color,
4256 					    *c_u = &objview->underline_color;
4257 
4258 		c = &objview->color;
4259 		if(objview->sensitive)
4260 		    glColor4f(c->r, c->g, c->b, c->a);
4261 		else
4262 		    glColor4f(
4263 			c->r * 0.75f,
4264 			c->g * 0.75f,
4265 			c->b * 0.75f,
4266 			c->a
4267 		    );
4268 
4269 #define DO_DRAW_LINE_COLORED			\
4270 {						\
4271  const char *s = buf_ptr;			\
4272  int sx = draw_x, sy = draw_y;			\
4273  while((*s != '\n') && (*s != '\0'))		\
4274  {						\
4275   if(IS_CHAR_ESC_START(*s))			\
4276   {						\
4277    s++;						\
4278    if(strcasepfx(s, "bold"))			\
4279     glColor4f(c_b->r, c_b->g, c_b->b, c_b->a);	\
4280    else if(strcasepfx(s, "underline"))		\
4281     glColor4f(c_u->r, c_u->g, c_u->b, c_u->a);  \
4282    else if(strcasepfx(s, "default"))		\
4283     glColor4f(c->r, c->g, c->b, c->a);		\
4284    while(!IS_CHAR_ESC_END(*s) && (*s != '\0'))	\
4285     s++;					\
4286    if(*s != '\0')				\
4287     s++;					\
4288   }						\
4289   else						\
4290   {						\
4291    GWDrawCharacter(display, sx, sy, *s);	\
4292    s++; sx += fw;				\
4293   }						\
4294  }						\
4295  if(*s == '\n')					\
4296   s++;						\
4297  buf_ptr = s;					\
4298 }
4299 
4300 		/* Begin drawing each line, draw in a style similar to
4301 		 * the message box.
4302 		 */
4303 		do
4304 		{
4305 		    if(draw_y >= (yc + h - (2 * DEF_MB_YMARGIN)))
4306 			break;
4307 
4308 		    DO_DRAW_LINE_COLORED
4309 		    draw_y += fh;
4310 
4311 		} while(buf_ptr != NULL);
4312 #undef DO_DRAW_LINE_COLORED
4313 	    }
4314 
4315 	    if(objview->objimg != NULL)
4316 	    {
4317 		const char *s =
4318 "(Button1 + DRAG = Heading & Pitch  Button3 + DRAG = Bank)";
4319 		int     draw_x = x - (STRLEN(s) * fw / 2),
4320 			draw_y = yc + h - DEF_MB_YMARGIN - fh;
4321 
4322 		c = &objview->color;
4323 		if(objview->sensitive)
4324 		    glColor4f(c->r, c->g, c->b, c->a);
4325 		else
4326 		    glColor4f(
4327 			c->r * 0.75f,
4328 			c->g * 0.75f,
4329 			c->b * 0.75f,
4330 			c->a
4331 		    );
4332 
4333 		GWDrawString(
4334 		    display, draw_x, draw_y, s
4335 		);
4336 	    }
4337 	    break;
4338 
4339 	}
4340 #undef DO_DRAW_IMAGE
4341 }
4342 
4343 
4344 /*
4345  *      Draws the specified object n (but not its shadow).
4346  */
SARMenuDrawObject(gw_display_struct * display,sar_menu_struct * m,int n)4347 void SARMenuDrawObject(
4348 	gw_display_struct *display, sar_menu_struct *m,
4349 	int n			/* Object number on m */
4350 )
4351 {
4352 	SARMenuDoDrawObject(display, m, n, False);
4353 }
4354 
4355 /*
4356  *	Draws the specified menu m.
4357  *
4358  *	Does not swap the GW buffers.
4359  */
SARMenuDrawAll(gw_display_struct * display,sar_menu_struct * m)4360 void SARMenuDrawAll(
4361 	gw_display_struct *display,
4362 	sar_menu_struct *m
4363 )
4364 {
4365 	int i, width, height;
4366 
4367 	if((display == NULL) || (m == NULL))
4368 	    return;
4369 
4370 	/* Set up gl state for 2d drawing */
4371 	GWOrtho2D(display);
4372 
4373 	GWContextGet(
4374 	    display, GWContextCurrent(display),
4375 	    NULL, NULL,
4376 	    NULL, NULL,
4377 	    &width, &height
4378 	);
4379 
4380 	/* Draw background image */
4381 	if(m->bg_image != NULL)
4382 	{
4383 	    /* Draw to the size of the frame buffer, thus clearing it */
4384 	    SARImageDraw(
4385 		display,
4386 		m->bg_image,
4387 	        0, 0,
4388 	        width, height
4389 	    );
4390 	}
4391 	else
4392 	{
4393 	    glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
4394 	    glClearDepth(1.0f);
4395 	    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
4396 	}
4397 
4398 	/* Draw each object (with shadows) */
4399 	for(i = 0; i < m->total_objects; i++)
4400 	    SARMenuDoDrawObject(display, m, i, True);
4401 }
4402 
4403 
4404 /*
4405  *	Manages a pointer event assumed for the given menu.
4406  */
SARMenuManagePointer(gw_display_struct * display,sar_menu_struct * m,int x,int y,gw_event_type type,int btn_num)4407 int SARMenuManagePointer(
4408 	gw_display_struct *display, sar_menu_struct *m,
4409 	int x, int y, gw_event_type type, int btn_num
4410 )
4411 {
4412 	int i, events_handled = 0;
4413 	int xp, yp, w, h;
4414 	int x_min, x_max, y_min, y_max, width, height;
4415 	void *o;
4416 	sar_menu_button_struct *button;
4417 	sar_menu_message_box_struct *mesgbox;
4418 	sar_menu_list_struct *list;
4419 	sar_menu_mdisplay_struct *mdpy;
4420 	sar_menu_switch_struct *sw;
4421 	sar_menu_spin_struct *spin;
4422 	sar_menu_slider_struct *slider;
4423 	sar_menu_map_struct *map;
4424 	sar_menu_objview_struct *objview;
4425 
4426 
4427 	if((display == NULL) || (m == NULL))
4428 	    return(events_handled);
4429 
4430 	GWContextGet(
4431 	    display, GWContextCurrent(display),
4432 	    NULL, NULL,
4433 	    NULL, NULL,
4434 	    &width, &height
4435 	);
4436 
4437 	/* Iterate through all menu object/widgets */
4438 	for(i = 0; i < m->total_objects; i++)
4439 	{
4440 	    o = m->object[i];
4441 	    if(o == NULL)
4442 		continue;
4443 
4444 	    switch(SAR_MENU_OBJECT_TYPE(o))
4445 	    {
4446 	      /* ***************************************************** */
4447 	      case SAR_MENU_OBJECT_TYPE_BUTTON:
4448 		button = SAR_MENU_BUTTON(o);
4449 		if(!button->sensitive)
4450 		    break;
4451 
4452 		xp = (int)(button->x * width) + button->offset_x;
4453 		yp = (int)(button->y * height) + button->offset_y;
4454 		w = button->width;
4455 		h = button->height;
4456 
4457 		/* Calculate coordinate bounds */
4458 		x_min = (int)MAX(xp - (w / 2), 0);
4459 		x_max = (int)MAX(x_min + w, w);
4460 		y_min = (int)MAX(yp - (h / 2), 0);
4461 		y_max = (int)MAX(y_min + h, h);
4462 
4463 		/* Event in bounds? */
4464 		if((events_handled <= 0) &&
4465 		   (x >= x_min) && (x < x_max) &&
4466 		   (y >= y_min) && (y < y_max)
4467 		)
4468 		{
4469 		    /* Handle by event type */
4470 		    switch(type)
4471 		    {
4472 		      case GWEventTypePointerMotion:
4473 			if(button->state == SAR_MENU_BUTTON_STATE_UNARMED)
4474 			{
4475 			    button->state = SAR_MENU_BUTTON_STATE_HIGHLIGHTED;
4476 			    events_handled++;
4477 			    DO_REDRAW_OBJECT(display, m, i)
4478 			}
4479 			break;
4480 
4481 		      case GWEventTypeButtonPress:
4482 			events_handled++;
4483 			/* Select new object as needed and redraw the
4484 			 * previously selected object
4485 			 */
4486 			if(m->selected_object != i)
4487 			{
4488 			    int po = m->selected_object;
4489 			    m->selected_object = i;
4490 			    if(m->always_full_redraw)
4491 				SARMenuDrawAll(display, m);
4492 			    else
4493 				SARMenuDrawObject(display, m, po);
4494 			}
4495 			/* Set button to armed state as appropriate */
4496 			if((button->state != SAR_MENU_BUTTON_STATE_ARMED) &&
4497 			   (btn_num == 1)
4498 			)
4499 			{
4500 			    button->state = SAR_MENU_BUTTON_STATE_ARMED;
4501 			    DO_REDRAW_OBJECT(display, m, i)
4502 			}
4503 			else
4504 			{
4505 			    GWSwapBuffer(display);
4506 			}
4507 			break;
4508 
4509 		      case GWEventTypeButtonRelease:
4510 			events_handled++;
4511 			/* Select new object as needed and redraw the
4512 			 * previously selected object
4513 			 */
4514 			if(m->selected_object != i)
4515 			{
4516 			    int po = m->selected_object;
4517 			    m->selected_object = i;
4518 			    if(m->always_full_redraw)
4519 				SARMenuDrawAll(display, m);
4520 			    else
4521 				SARMenuDrawObject(display, m, po);
4522 			}
4523 			/* Set button back to highlighted state if it
4524 			 * was armed and call the button's click
4525 			 * callback
4526 			 */
4527 			if(button->state == SAR_MENU_BUTTON_STATE_ARMED)
4528 			{
4529 			    button->state = SAR_MENU_BUTTON_STATE_HIGHLIGHTED;
4530 			    if(m->always_full_redraw)
4531 				SARMenuDrawAll(display, m);
4532 			    else
4533 				SARMenuDrawObject(display, m, i);
4534 
4535 			    if(button->func_cb != NULL)
4536 			    {
4537 				int n;
4538 				sar_menu_button_struct *button2;
4539 
4540 				/* Set all other buttons on this menu to
4541 				 * unarmed.
4542 				 */
4543 				for(n = 0; n < m->total_objects; n++)
4544 				{
4545 				    o = m->object[n];
4546 				    if(SAR_MENU_IS_BUTTON(o))
4547 					button2 = SAR_MENU_BUTTON(o);
4548 				    else
4549 					continue;
4550 				    if(button == button2)
4551 					continue;
4552 
4553 				    if(button2->state != SAR_MENU_BUTTON_STATE_UNARMED)
4554 				    {
4555 					button2->state = SAR_MENU_BUTTON_STATE_UNARMED;
4556 					if(m->always_full_redraw)
4557 					    SARMenuDrawAll(display, m);
4558 					else
4559 					    SARMenuDrawObject(display, m, n);
4560 				    }
4561 				}
4562 
4563 				GWSwapBuffer(display);
4564 
4565 				/* Call callback function */
4566 				button->func_cb(
4567 				    button,		/* Object */
4568 				    button->id,		/* ID Code */
4569 				    button->client_data	/* Data */
4570 				);
4571 			    }
4572 			    else
4573 			    {
4574 				GWSwapBuffer(display);
4575 			    }
4576 			}
4577 			break;
4578 
4579 		      case GWEventType2ButtonPress:
4580 		      case GWEventType3ButtonPress:
4581 			break;
4582 		    }
4583 		}
4584 		else
4585 		{
4586 		    /* Pointer event out of bounds */
4587 		    switch(type)
4588 		    {
4589 		      case GWEventTypeButtonPress:
4590 			break;
4591 		      case GWEventTypeButtonRelease:
4592 		      case GWEventTypePointerMotion:
4593 			if(button->state != SAR_MENU_BUTTON_STATE_UNARMED)
4594 			{
4595 			    button->state = SAR_MENU_BUTTON_STATE_UNARMED;
4596 			    DO_REDRAW_OBJECT(display, m, i)
4597 			}
4598 			break;
4599 		      case GWEventType2ButtonPress:
4600 		      case GWEventType3ButtonPress:
4601 			break;
4602 		    }
4603 		}
4604 		break;
4605 
4606 	      /* ***************************************************** */
4607 	      case SAR_MENU_OBJECT_TYPE_MESSAGE_BOX:
4608 		mesgbox = SAR_MENU_MESSAGE_BOX(o);
4609 		if(!mesgbox->sensitive)
4610 		    break;
4611 
4612 		w = (int)(mesgbox->width * width);
4613 		if(w <= 0)
4614 		    w = (int)(width - (2 * DEF_MB_XMARGIN));
4615 		if(w <= 0)
4616 		    w = DEF_MB_XMARGIN;
4617 
4618 		if(mesgbox->height > 0)
4619 		    h = (int)(mesgbox->height * height);
4620 		else
4621 		    h = DEF_HEIGHT;
4622 		if(h <= 0)
4623 		    h = DEF_MB_YMARGIN;
4624 
4625 		/* Get coordinate bounds */
4626 		x_min = (int)((mesgbox->x * width) - (w / 2));
4627 		x_max = (int)(x_min + w);
4628 		y_min = (int)((mesgbox->y * height) - (h / 2));
4629 		y_max = (int)(y_min + h);
4630 
4631 		/* Pointer event in bounds? */
4632 		if((events_handled <= 0) &&
4633 		   (x >= x_min) && (x < x_max) &&
4634 		   (y >= y_min) && (y < y_max) &&
4635 		   (mesgbox->message != NULL) &&
4636 		   (type == GWEventTypeButtonPress)
4637 		)
4638 		{
4639 		    int fh, fw;
4640 		    int lines_visable, columns_visable,
4641 			total_lines, scroll_width;
4642 
4643 		    events_handled++;
4644 
4645 		    /* Select new object as needed and redraw the
4646 		     * previously selected object.
4647 		     */
4648 		    if(m->selected_object != i)
4649 		    {
4650 			int po = m->selected_object;
4651 			m->selected_object = i;
4652 			if(m->always_full_redraw)
4653 			    SARMenuDrawAll(display, m);
4654 			else
4655 			    SARMenuDrawObject(display, m, po);
4656 		    }
4657 
4658 		    GWGetFontSize(
4659 			mesgbox->font,
4660 			NULL, NULL,
4661 			&fw, &fh
4662 		    );
4663 
4664 		    /* Calculate colums visable */
4665 		    if(fw > 0)
4666 			columns_visable = (w - DEF_SCROLL_CURSOR_WIDTH
4667 			    - (2 * DEF_MB_XMARGIN)) / fw;
4668 		    else
4669 			columns_visable = 1;
4670 		    if(columns_visable < 1)
4671 			columns_visable = 1;
4672 
4673 		    /* Calculate width (height) of scroll indicator */
4674 		    scroll_width = fh + (2 * DEF_MB_YMARGIN);
4675 
4676 		    /* Calculate lines visable */
4677 		    if(fh > 0)
4678 			lines_visable = (h - (2 * DEF_MB_YMARGIN)) / fh;
4679 		    else
4680 			lines_visable = 0;
4681 		    if(lines_visable < 0)
4682 			lines_visable = 0;
4683 
4684 		    /* Calculate total number of lines */
4685 		    total_lines = SARMenuMessageBoxTotalLines(
4686 			mesgbox->message, columns_visable
4687 		    );
4688 
4689 		    /* Let's make scrolling simple, check if y is above
4690 		     * or below the midpoint.
4691 		     */
4692 		    if(y < (mesgbox->y * height))
4693 		    {
4694 			/* Scroll up */
4695 			mesgbox->scrolled_line--;
4696 		    }
4697 		    else
4698 		    {
4699 			/* Scroll down */
4700 			mesgbox->scrolled_line++;
4701 		    }
4702 
4703 		    if(mesgbox->scrolled_line >
4704 			(total_lines - (lines_visable / 2))
4705 		    )
4706 			mesgbox->scrolled_line = total_lines -
4707 			    (lines_visable / 2);
4708 		    if(mesgbox->scrolled_line < 0)
4709 			mesgbox->scrolled_line = 0;
4710 
4711 		    DO_REDRAW_OBJECT(display, m, i)
4712 		}
4713 		break;
4714 
4715 	      /* ***************************************************** */
4716 	      case SAR_MENU_OBJECT_TYPE_LIST:
4717 		list = SAR_MENU_LIST(o);
4718 		if(!list->sensitive)
4719 		    break;
4720 
4721 		w = (int)(list->width * width);
4722 		if(w <= 0)
4723 		    w = width - (2 * DEF_LIST_XMARGIN);
4724 		if(w <= 0)
4725 		    w = DEF_LIST_XMARGIN;
4726 
4727 		if(list->height > 0)
4728 		    h = (int)(list->height * height);
4729 		else
4730 		    h = DEF_HEIGHT;
4731 		if(h <= 0)
4732 		    h = DEF_LIST_YMARGIN;
4733 
4734 		/* Calculate coordinate bounds */
4735 		x_min = (int)((list->x * width) - (w / 2));
4736 		x_max = (int)(x_min + w);
4737 		y_min = (int)((list->y * height) - (h / 2));
4738 		y_max = (int)(y_min + h);
4739 
4740 		/* Event in bounds? */
4741 		if((events_handled <= 0) &&
4742 		   (x >= x_min) && (x < x_max) &&
4743 		   (y >= y_min) && (y < y_max)
4744 		)
4745 		{
4746 		    int fh, fw, items_visible;
4747 		    int scroll = 0;
4748 
4749 		    GWGetFontSize(
4750 			list->font,
4751 			NULL, NULL,
4752 			&fw, &fh
4753 		    );
4754 		    /* Calculate items visible, remember to subtract
4755 		     * three items for borders and heading
4756 		     */
4757 		    if(fh > 0)
4758 			items_visible = MAX(
4759 			    (h / fh) - 3,
4760 			    0
4761 			);
4762 		    else
4763 			items_visible = 0;
4764 
4765 		    /* Update items visable on list */
4766 		    list->items_visable = items_visible;
4767 
4768 		    /* Determine if we need to scroll up or down
4769 		     * depending on the location of the event
4770 		     */
4771 		    if(x >= (x_max - DEF_SCROLL_CURSOR_WIDTH - DEF_LIST_XMARGIN))
4772 		    {
4773 			if(y < (y_min + DEF_SCROLL_CURSOR_HEIGHT + fh + DEF_LIST_YMARGIN))
4774 			    scroll = 1;
4775 			else if(y >= (y_max - DEF_SCROLL_CURSOR_HEIGHT - DEF_LIST_YMARGIN))
4776 			    scroll = 2;
4777 		    }
4778 
4779 		    /* Handle by event type */
4780 		    switch(type)
4781 		    {
4782 		      case GWEventTypeButtonPress:
4783 			events_handled++;
4784 
4785 			/* Select new object as needed and redraw the
4786 			 * previously selected object
4787 			 */
4788 			if(m->selected_object != i)
4789 			{
4790 			    int po = m->selected_object;
4791 			    m->selected_object = i;
4792 			    if(m->always_full_redraw)
4793 				SARMenuDrawAll(display, m);
4794 			    else
4795 				SARMenuDrawObject(display, m, po);
4796 			}
4797 
4798 			/* Scroll up? */
4799 			if(scroll == 1)
4800 			{
4801 			    list->scrolled_item -= MAX(
4802 				items_visible - 1,
4803 				1
4804 			    );
4805 			    if(list->scrolled_item < 0)
4806 				list->scrolled_item = 0;
4807 
4808 			    DO_REDRAW_OBJECT(display, m, i)
4809 			}
4810 			/* Scroll down? */
4811 			else if(scroll == 2)
4812 			{
4813 			    list->scrolled_item += MAX(
4814 				items_visible - 1,
4815 				1
4816 			    );
4817 			    if(list->scrolled_item >=
4818 				(list->total_items - (items_visible / 2))
4819 			    )
4820 				list->scrolled_item =
4821 				    list->total_items -
4822 				    (items_visible / 2);
4823 			    if(list->scrolled_item < 0)
4824 				list->scrolled_item = 0;
4825 
4826 			    DO_REDRAW_OBJECT(display, m, i)
4827 			}
4828 			else
4829 			{
4830 			    /* Match selection */
4831 			    int sel_num, prev_sel_num;
4832 
4833 			    /* Calculate selection position, remember
4834 			     * to - 1 to account for the heading
4835 			     * which should not be selected
4836 			     */
4837 			    if(fh > 0)
4838 				sel_num = list->scrolled_item +
4839 				    ((y - DEF_LIST_YMARGIN - fh - y_min) / fh);
4840 			    else
4841 				sel_num = -1;
4842 
4843 			    /* Sanitize selection */
4844 			    if(sel_num < -1)
4845 				sel_num = -1;
4846 			    if(sel_num >= list->total_items)
4847 				sel_num = list->total_items - 1;
4848 
4849 			    /* Record previously selected item and set
4850 			     * new selected item
4851 			     */
4852 			    prev_sel_num = list->selected_item;
4853 			    list->selected_item = sel_num;
4854 
4855 			    DO_REDRAW_OBJECT(display, m, i)
4856 
4857 			    /* Call select callback */
4858 			    if((list->select_cb != NULL) &&
4859 			       (prev_sel_num != sel_num) &&
4860 			       (sel_num >= 0) &&
4861 			       (sel_num < list->total_items)
4862 			    )
4863 			    {
4864 				sar_menu_list_item_struct *item = list->item[sel_num];
4865 				if(item != NULL)
4866 				    list->select_cb(
4867 				    list,		/* This Object */
4868 				    list->id,		/* ID Code */
4869 				    list->client_data,	/* Data */
4870 				    sel_num,		/* Item Number */
4871 				    item,		/* Item Pointer */
4872 				    item->client_data	/* Item Data */
4873 				);
4874 			    }
4875 		        }
4876 			break;
4877 
4878 		      case GWEventTypeButtonRelease:
4879 			break;
4880 
4881 		      case GWEventTypePointerMotion:
4882 			break;
4883 
4884 		      case GWEventType2ButtonPress:
4885 			events_handled++;
4886 
4887 			/* No scroll? */
4888 			if(scroll == 0)
4889 			{
4890 			    int sel_num = list->selected_item;
4891 
4892 			    /* Call activate callback */
4893 			    if((list->activate_cb != NULL) &&
4894 			       (sel_num >= 0) &&
4895 			       (sel_num < list->total_items)
4896 			    )
4897 			    {
4898 				sar_menu_list_item_struct *item = list->item[sel_num];
4899 				if(item != NULL)
4900 				    list->activate_cb(
4901 				    list,		/* This Object */
4902 				    list->id,		/* ID Code */
4903 				    list->client_data,	/* Data */
4904 				    sel_num,		/* Item Number */
4905 				    item,		/* Item Pointer */
4906 				    item->client_data	/* Item Data */
4907 				);
4908 			    }
4909 			}
4910 			break;
4911 
4912 		      case GWEventType3ButtonPress:
4913 			break;
4914 		    }
4915 		}
4916 		break;
4917 
4918 	      /* ***************************************************** */
4919 	      case SAR_MENU_OBJECT_TYPE_MDISPLAY:
4920 		mdpy = SAR_MENU_MDISPLAY(o);
4921 		if(!mdpy->sensitive)
4922 		    break;
4923 
4924 		w = (int)(mdpy->width * width);
4925 		if(w <= 0)
4926 		    w = width - (2 * DEF_LIST_XMARGIN);
4927 		if(w <= 0)
4928 		    w = DEF_LIST_XMARGIN;
4929 
4930 		if(mdpy->height > 0)
4931 		    h = (int)(mdpy->height * height);
4932 		else
4933 		    h = DEF_HEIGHT;
4934 		if(h <= 0)
4935 		    h = DEF_LIST_YMARGIN;
4936 
4937 		/* Get coordinate bounds */
4938 		x_min = (int)((mdpy->x * width) - (w / 2));
4939 		x_max = (int)(x_min + w);
4940 		y_min = (int)((mdpy->y * height) - (h / 2));
4941 		y_max = (int)(y_min + h);
4942 
4943 		/* Pointer event in bounds? */
4944 		if((events_handled <= 0) &&
4945 		   (x >= x_min) && (x < x_max) &&
4946 		   (y >= y_min) && (y < y_max)
4947 		)
4948 		{
4949 		    switch(type)
4950 		    {
4951 		      case GWEventTypeButtonPress:
4952 			events_handled++;
4953 
4954 			/* Select new object as needed and redraw the
4955 			 * previously selected object.
4956 			 */
4957 			if(m->selected_object != i)
4958 			{
4959 			    int po = m->selected_object;
4960 			    m->selected_object = i;
4961 			    if(m->always_full_redraw)
4962 				SARMenuDrawAll(display, m);
4963 			    else
4964 				SARMenuDrawObject(display, m, po);
4965 			}
4966 
4967 			DO_REDRAW_OBJECT(display, m, i)
4968 			break;
4969 
4970 		      case GWEventTypeButtonRelease:
4971 		      case GWEventTypePointerMotion:
4972 		      case GWEventType2ButtonPress:
4973 		      case GWEventType3ButtonPress:
4974 			break;
4975 		    }
4976 		}
4977 		break;
4978 
4979 	      /* ***************************************************** */
4980 	      case SAR_MENU_OBJECT_TYPE_SWITCH:
4981 		sw = SAR_MENU_SWITCH(o);
4982 		if(sw->sensitive)
4983 		{
4984 		    int fw, fh;
4985 		    const char *label = sw->label;
4986 
4987 		    w = sw->width;
4988 		    h = sw->height;
4989 
4990 		    GWGetFontSize(
4991 			sw->font,
4992 			NULL, NULL,
4993 			&fw, &fh
4994 		    );
4995 
4996 		    /* Calculate size of switch area */
4997 		    if(w <= 0)
4998 			w = DEF_SWITCH_WIDTH;
4999 		    if(h <= 0)
5000 			h = DEF_YMARGIN + DEF_SWITCH_HEIGHT +
5001 			    ((label != NULL) ? fh : 0);
5002 
5003 		    /* Get coordinate bounds for switch area */
5004 		    x_min = (int)((sw->x * width) - (w / 2));
5005 		    x_max = (int)(x_min + DEF_SWITCH_WIDTH);
5006 		    y_min = (int)((sw->y * height) - (h / 2) + 2);
5007 		    y_max = (int)(y_min + DEF_SWITCH_HEIGHT);
5008 
5009 		    /* Pointer event in bounds? */
5010 		    if((events_handled <= 0) &&
5011 		       (x >= x_min) && (x < x_max) &&
5012 		       (y >= y_min) && (y < y_max)
5013 		    )
5014 		    {
5015 			switch(type)
5016 			{
5017 			  case GWEventTypeButtonPress:
5018 			    break;
5019 
5020 			  case GWEventTypeButtonRelease:
5021 			    switch(btn_num)
5022 			    {
5023 			      case 1:
5024 				events_handled++;
5025 
5026 				/* Select new object as needed and
5027 				 * redraw the previously selected object.
5028 				 */
5029 				if(m->selected_object != i)
5030 				{
5031 				    int po = m->selected_object;
5032 				    m->selected_object = i;
5033 				    if(m->always_full_redraw)
5034 					SARMenuDrawAll(display, m);
5035 				    else
5036 					SARMenuDrawObject(display, m, po);
5037 				}
5038 
5039 				sw->state = !sw->state;
5040 				DO_REDRAW_OBJECT(display, m, i)
5041 
5042 				if(sw->switch_cb != NULL)
5043 				    sw->switch_cb(
5044 					sw,		/* This Object */
5045 					sw->id,		/* ID Code */
5046 					sw->client_data,/* Data */
5047 					sw->state	/* State */
5048 				);
5049 				break;
5050 			    }
5051 			    break;
5052 
5053 			  case GWEventTypePointerMotion:
5054 			  case GWEventType2ButtonPress:
5055 			  case GWEventType3ButtonPress:
5056 			    break;
5057 		        }
5058 		    }
5059 		    /* Event not handled? */
5060 		    if(events_handled <= 0)
5061 		    {
5062 			/* Calculate size of object area */
5063 			w = sw->width;
5064 			h = sw->height;
5065 			if(w <= 0)
5066 			    w = MAX(
5067 				(2 * DEF_XMARGIN) + DEF_SWITCH_WIDTH,
5068 				(2 * DEF_XMARGIN) + (STRLEN(label) * fw)
5069 			    );
5070 			if(h <= 0)
5071 			    h = (1 * DEF_YMARGIN) + DEF_SWITCH_HEIGHT +
5072 				((label != NULL) ? fh : 0);
5073 
5074 			/* Get coordinate bounds */
5075 			x_min = (int)((sw->x * width) - (w / 2));
5076 			x_max = (int)(x_min + w);
5077 			y_min = (int)((sw->y * height) - (h / 2));
5078 			y_max = (int)(y_min + h);
5079 
5080 			/* Pointer event in bounds? */
5081 			if((x >= x_min) && (x < x_max) &&
5082 			   (y >= y_min) && (y < y_max)
5083 			)
5084 			{
5085 			    switch(type)
5086 			    {
5087 			      case GWEventTypeButtonPress:
5088 				events_handled++;
5089 
5090 				/* Select new object as needed and
5091 				 * redraw the previously selected
5092 				 * object
5093 				 */
5094 				if(m->selected_object != i)
5095 				{
5096 				    int po = m->selected_object;
5097 				    m->selected_object = i;
5098 				    if(m->always_full_redraw)
5099 					SARMenuDrawAll(display, m);
5100 				    else
5101 					SARMenuDrawObject(display, m, po);
5102 				}
5103 
5104 				DO_REDRAW_OBJECT(display, m, i)
5105 				break;
5106 
5107 			      case GWEventTypeButtonRelease:
5108 			      case GWEventTypePointerMotion:
5109 			      case GWEventType2ButtonPress:
5110 			      case GWEventType3ButtonPress:
5111 				break;
5112 			    }
5113 			}
5114 		    }
5115 		}
5116 		break;
5117 
5118 	      /* ***************************************************** */
5119 	      case SAR_MENU_OBJECT_TYPE_SPIN:
5120 		spin = SAR_MENU_SPIN(o);
5121 		if(spin->sensitive)
5122 		{
5123 		    int fw, fh;
5124 		    int label_len = STRLEN(spin->label);
5125 		    int label_width;
5126 
5127 		    GWGetFontSize(
5128 			spin->font,
5129 			NULL, NULL,
5130 			&fw, &fh
5131 		    );
5132 
5133 		    label_width = (2 * DEF_XMARGIN) + (label_len * fw);
5134 
5135 		    w = (int)(width * spin->width);
5136 		    h = (int)MAX(
5137 			height * spin->height,
5138 			(4 * DEF_YMARGIN) + fh
5139 		    );
5140 
5141 		    /* Get coordinate bounds for decrement button */
5142 		    x_min = (int)((spin->x * width) - (w / 2) + label_width);
5143 		    x_max = (int)(x_min + h);
5144 		    y_min = (int)((spin->y * height) - (h / 2));
5145 		    y_max = (int)(y_min + h);
5146 		    /* Pointer event in bounds? */
5147 		    if((x >= x_min) && (x < x_max) &&
5148 		       (y >= y_min) && (y < y_max) &&
5149 		       (events_handled <= 0)
5150 		    )
5151 		    {
5152 			switch(type)
5153 			{
5154 			  case GWEventTypeButtonPress:
5155 			    events_handled++;
5156 			    /* Select new object as needed and redraw
5157 			     * the previously selected object
5158 			     */
5159 			    if(m->selected_object != i)
5160 			    {
5161 				int po = m->selected_object;
5162 				m->selected_object = i;
5163 				if(m->always_full_redraw)
5164 				    SARMenuDrawAll(display, m);
5165 				else
5166 				    SARMenuDrawObject(display, m, po);
5167 			    }
5168 			    spin->dec_state = SAR_MENU_BUTTON_STATE_ARMED;
5169 			    DO_REDRAW_OBJECT(display, m, i)
5170 			    break;
5171 			  case GWEventTypeButtonRelease:
5172 			    events_handled++;
5173 			    switch(spin->dec_state)
5174 			    {
5175 			      case SAR_MENU_BUTTON_STATE_ARMED:
5176 			      case SAR_MENU_BUTTON_STATE_HIGHLIGHTED:
5177 				spin->dec_state = SAR_MENU_BUTTON_STATE_HIGHLIGHTED;
5178 				if(btn_num == 3)
5179 				    SARMenuSpinSelectValueIndex(
5180 					display, m, i,
5181 					0,
5182 					False
5183 				    );
5184 				else
5185 				    SARMenuSpinDoDec(display, m, i, False);
5186 				DO_REDRAW_OBJECT(display, m, i)
5187 				break;
5188 			    }
5189 			    break;
5190 			  case GWEventTypePointerMotion:
5191 			    events_handled++;
5192 			    if(spin->dec_state == SAR_MENU_BUTTON_STATE_UNARMED)
5193 			    {
5194 				spin->dec_state = SAR_MENU_BUTTON_STATE_HIGHLIGHTED;
5195 				DO_REDRAW_OBJECT(display, m, i)
5196 			    }
5197 			    break;
5198 			  case GWEventType2ButtonPress:
5199 			  case GWEventType3ButtonPress:
5200 			    break;
5201 			}
5202 		    }
5203 
5204 		    /* Get coordinate bounds for increment button */
5205 		    x_max = (int)((spin->x * width) + (w / 2));
5206 		    x_min = (int)(x_max - h);
5207 		    y_min = (int)((spin->y * height) - (h / 2));
5208 		    y_max = (int)(y_min + h);
5209 		    /* Pointer event in bounds? */
5210 		    if((x >= x_min) && (x < x_max) &&
5211 		       (y >= y_min) && (y < y_max) &&
5212 		       (events_handled <= 0)
5213 		    )
5214 		    {
5215 			switch(type)
5216 			{
5217 			  case GWEventTypeButtonPress:
5218 			    events_handled++;
5219 			    /* Select new object as needed and redraw
5220 			     * the previously selected object
5221 			     */
5222 			    if(m->selected_object != i)
5223 			    {
5224 				int po = m->selected_object;
5225 				m->selected_object = i;
5226 				if(m->always_full_redraw)
5227 				    SARMenuDrawAll(display, m);
5228 				else
5229 				    SARMenuDrawObject(display, m, po);
5230 			    }
5231 			    spin->inc_state = SAR_MENU_BUTTON_STATE_ARMED;
5232 			    DO_REDRAW_OBJECT(display, m, i)
5233 			    break;
5234 			  case GWEventTypeButtonRelease:
5235 			    events_handled++;
5236 			    switch(spin->inc_state)
5237 			    {
5238 			      case SAR_MENU_BUTTON_STATE_ARMED:
5239 			      case SAR_MENU_BUTTON_STATE_HIGHLIGHTED:
5240 				spin->inc_state = SAR_MENU_BUTTON_STATE_HIGHLIGHTED;
5241 				if(btn_num == 3)
5242 				    SARMenuSpinSelectValueIndex(
5243 					display, m, i,
5244 					MAX(spin->total_values - 1, 0),
5245 					False
5246 				    );
5247 				else
5248 				    SARMenuSpinDoInc(display, m, i, False);
5249 				DO_REDRAW_OBJECT(display, m, i)
5250 				break;
5251 			    }
5252 			    break;
5253 			  case GWEventTypePointerMotion:
5254 			    events_handled++;
5255 			    if(spin->inc_state == SAR_MENU_BUTTON_STATE_UNARMED)
5256 			    {
5257 				spin->inc_state = SAR_MENU_BUTTON_STATE_HIGHLIGHTED;
5258 				DO_REDRAW_OBJECT(display, m, i)
5259 			    }
5260 			    break;
5261 			  case GWEventType2ButtonPress:
5262 			  case GWEventType3ButtonPress:
5263 			    break;
5264 			}
5265 		    }
5266 
5267 		    /* Event not handled above? */
5268 		    if(events_handled <= 0)
5269 		    {
5270 			/* Event not handled above, this implies the
5271 			 * event occured outside the event areas of
5272 			 * this object
5273 			 */
5274 			switch(type)
5275 			{
5276 			  case GWEventTypeButtonPress:
5277 			    /* Get coordinate bounds */
5278 			    x_min = (int)((spin->x * width) - (w / 2));
5279 			    x_max = (int)(x_min + w);
5280 			    y_min = (int)((spin->y * height) - (h / 2));
5281 			    y_max = (int)(y_min + h);
5282 
5283 			    /* Pointer event in bounds? */
5284 			    if((x >= x_min) && (x < x_max) &&
5285 			       (y >= y_min) && (y < y_max)
5286 			    )
5287 			    {
5288 				events_handled++;
5289 				/* Select new object as needed and
5290 				 * redraw the previously selected object.
5291 				 */
5292 				if(m->selected_object != i)
5293 				{
5294 				    int po = m->selected_object;
5295 				    m->selected_object = i;
5296 				    if(m->always_full_redraw)
5297 					SARMenuDrawAll(display, m);
5298 				    else
5299 					SARMenuDrawObject(display, m, po);
5300 				}
5301 				DO_REDRAW_OBJECT(display, m, i)
5302 			    }
5303 			    break;
5304 
5305 			  case GWEventTypeButtonRelease:
5306 			  case GWEventTypePointerMotion:
5307 			    if(spin->dec_state != SAR_MENU_BUTTON_STATE_UNARMED)
5308 			    {
5309 				spin->dec_state = SAR_MENU_BUTTON_STATE_UNARMED;
5310 				DO_REDRAW_OBJECT(display, m, i)
5311 			    }
5312 			    if(spin->inc_state != SAR_MENU_BUTTON_STATE_UNARMED)
5313 			    {
5314 				spin->inc_state = SAR_MENU_BUTTON_STATE_UNARMED;
5315 				DO_REDRAW_OBJECT(display, m, i)
5316 			    }
5317 			    break;
5318 
5319 			  case GWEventType2ButtonPress:
5320 			  case GWEventType3ButtonPress:
5321 			    break;
5322 			}
5323 		    }
5324 		}
5325 		break;
5326 
5327 	      /* ***************************************************** */
5328 	      case SAR_MENU_OBJECT_TYPE_SLIDER:
5329 		slider = SAR_MENU_SLIDER(o);
5330 		if(slider->sensitive)
5331 		{
5332 		    int fw, fh;
5333 		    int label_len = STRLEN(slider->label);
5334 		    int label_width;
5335 
5336 		    GWGetFontSize(
5337 		       slider->font,
5338 		       NULL, NULL,
5339 		       &fw, &fh
5340 		    );
5341 
5342 		    w = (int)(width * slider->width);
5343 		    h = (int)MAX(
5344 			height * slider->height,
5345 			(4 * DEF_YMARGIN) + fh
5346 		    );
5347 
5348 		    label_width = (4 * DEF_XMARGIN) + (label_len * fw);
5349 
5350 		    /* Get coordinate bounds of trough */
5351 		    x_min = (int)(
5352 			(slider->x * width) - (w / 2) + label_width
5353 		    ) + DEF_XMARGIN;
5354 		    x_max = (int)((slider->x * width) + (w / 2)) - DEF_XMARGIN;
5355 		    y_min = (int)((slider->y * height) - (h / 2));
5356 		    y_max = (int)(y_min + h);
5357 
5358 		    /* Pointer event in bounds? */
5359 		    if((events_handled <= 0) &&
5360 		       (x >= x_min) && (x < x_max) &&
5361 		       (y >= y_min) && (y < y_max)
5362 		    )
5363 		    {
5364 			float vc, value;
5365 #define DO_CALCULATE_VALUE	{			\
5366  vc = ((x_max - x_min) > 0) ?				\
5367   (float)(x - x_min) / (float)(x_max - x_min) : 0.0f;	\
5368  value = CLIP(slider->lower +				\
5369   (vc * (slider->upper - slider->lower)),		\
5370   slider->lower, slider->upper				\
5371  );							\
5372 }
5373 
5374 			switch(type)
5375 			{
5376 			  case GWEventTypeButtonPress:
5377 			    events_handled++;
5378 			    /* Select new object as needed and redraw the
5379 			     * previously selected object
5380 			     */
5381 			    if(m->selected_object != i)
5382 			    {
5383 				int po = m->selected_object;
5384 				m->selected_object = i;
5385 				if(m->always_full_redraw)
5386 				    SARMenuDrawAll(display, m);
5387 				else
5388 				    SARMenuDrawObject(display, m, po);
5389 			    }
5390 			    /* Record drag button number */
5391 			    slider->drag_button = btn_num;
5392 			    if(slider->drag_button == 1)
5393 			    {
5394 				DO_CALCULATE_VALUE
5395 				SARMenuSliderSetValue(
5396 				    display, m, i, value, True
5397 				);
5398 			    }
5399 			    else
5400 			    {
5401 				DO_REDRAW_OBJECT(display, m, i)
5402 			    }
5403 			    break;
5404 
5405 			  case GWEventTypeButtonRelease:
5406 			    events_handled++;
5407 			    slider->drag_button = 0;
5408 			    break;
5409 
5410 			  case GWEventTypePointerMotion:
5411 			    if(slider->drag_button == 1)
5412 			    {
5413 				DO_CALCULATE_VALUE
5414 				SARMenuSliderSetValue(
5415 				    display, m, i, value, True
5416 				);
5417 				events_handled++;
5418 			    }
5419 			    break;
5420 
5421 			  case GWEventType2ButtonPress:
5422 			  case GWEventType3ButtonPress:
5423 			    break;
5424 			}
5425 #undef DO_CALCULATE_VALUE
5426 		    }
5427 		}
5428 		break;
5429 
5430 	      /* ***************************************************** */
5431 	      case SAR_MENU_OBJECT_TYPE_MAP:
5432 		map = SAR_MENU_MAP(o);
5433 		if(!map->sensitive)
5434 		    break;
5435 		events_handled += SARMenuMapManagePointer(
5436 		    display, m, map, i,
5437 		    x, y, type, btn_num
5438 		);
5439 		break;
5440 
5441 	      /* ***************************************************** */
5442 	      case SAR_MENU_OBJECT_TYPE_OBJVIEW:
5443 		objview = SAR_MENU_OBJVIEW(o);
5444 		if(!objview->sensitive)
5445 		    break;
5446 		events_handled += SARMenuObjViewManagePointer(
5447 		    display, m, objview, i,
5448 		    x, y, type, btn_num
5449 		);
5450 		break;
5451 	    }
5452 	}
5453 
5454 	return(events_handled);
5455 }
5456 
5457 
5458 /*
5459  *	Manages a key event assumed for the menu.
5460  */
SARMenuManageKey(gw_display_struct * display,sar_menu_struct * m,int key,Boolean state)5461 int SARMenuManageKey(
5462 	gw_display_struct *display, sar_menu_struct *m,
5463 	int key, Boolean state
5464 )
5465 {
5466 	int i, prev_sel_num, events_handled = 0;
5467 	int items_visable = 0;
5468 	int fw, fh, w, h, width, height;
5469 	void *o;
5470 	sar_menu_button_struct *button;
5471 	sar_menu_message_box_struct *mesgbox;
5472 	sar_menu_list_struct *list;
5473 	sar_menu_switch_struct *sw;
5474 	sar_menu_spin_struct *spin;
5475 	sar_menu_slider_struct *slider;
5476 	sar_menu_objview_struct *ov;
5477 
5478 
5479 	if((display == NULL) || (m == NULL))
5480 	    return(events_handled);
5481 
5482 #if 0
5483 	/* Always ignore key releases */
5484 	if(!state)
5485 	    return(events_handled);
5486 #endif
5487 
5488 	GWContextGet(
5489 	    display, GWContextCurrent(display),
5490 	    NULL, NULL,
5491 	    NULL, NULL,
5492 	    &width, &height
5493 	);
5494 
5495 
5496 	/* Menu global key functions */
5497 	switch(key)
5498 	{
5499 	  /* Tab changes selected object */
5500 	  case '\t':
5501 	    if(!state)
5502 	    {
5503 		events_handled++;
5504 		break;
5505 	    }
5506 
5507 	    prev_sel_num = m->selected_object;
5508 
5509 #define TYPE_SELECTABLE(t)	(		\
5510  ((t) != SAR_MENU_OBJECT_TYPE_LABEL) &&		\
5511  ((t) != SAR_MENU_OBJECT_TYPE_PROGRESS)		\
5512 )
5513 
5514 	    if(display->shift_key_state)
5515 	    {
5516 		/* Seek backwards until we get a selectable object
5517 		 * type or the list has cycled
5518 		 */
5519 		sar_menu_object_type type;
5520 		int status = 0;
5521 		m->selected_object--;
5522 		while(m->selected_object >= 0)
5523 		{
5524 		    o = SARMenuGetObject(m, m->selected_object);
5525 		    if((o != NULL) &&
5526 		       SARMenuObjectIsSensitive(m, m->selected_object)
5527 		    )
5528 		    {
5529 			type = SAR_MENU_OBJECT_TYPE(o);
5530 			if(TYPE_SELECTABLE(type))
5531 			{
5532 			    status = 1;
5533 			    break;
5534 			}
5535 		    }
5536 		    m->selected_object--;
5537 		}
5538 		/* Did not get a match? */
5539 		if(!status)
5540 		{
5541 		    /* From the end */
5542 		    m->selected_object = m->total_objects - 1;
5543 		    while(m->selected_object > prev_sel_num)
5544 		    {
5545 			o = SARMenuGetObject(m, m->selected_object);
5546 			if((o != NULL) &&
5547 			   SARMenuObjectIsSensitive(m, m->selected_object)
5548 			)
5549 			{
5550 			    type = SAR_MENU_OBJECT_TYPE(o);
5551 			    if(TYPE_SELECTABLE(type))
5552 			    {
5553 				status = 1;
5554 				break;
5555 			    }
5556 			}
5557 			m->selected_object--;
5558 		    }
5559 		}
5560 		/* Still no match? */
5561 		if(!status)
5562 		    m->selected_object = prev_sel_num;
5563 	    }
5564 	    else
5565 	    {
5566 		/* Seek forwards until we get a selectable object
5567 		 * type or the list has cycled
5568 		 */
5569 		sar_menu_object_type type;
5570 		int status = 0;
5571 		m->selected_object++;
5572 		while(m->selected_object < m->total_objects)
5573 		{
5574 		    o = SARMenuGetObject(m, m->selected_object);
5575 		    if((o != NULL) &&
5576 		       SARMenuObjectIsSensitive(m, m->selected_object)
5577 		    )
5578 		    {
5579 			type = SAR_MENU_OBJECT_TYPE(o);
5580 			if(TYPE_SELECTABLE(type))
5581 			{
5582 			    status = 1;
5583 			    break;
5584 			}
5585 		    }
5586 		    m->selected_object++;
5587 		}
5588 		/* Didn't get a match? */
5589 		if(!status)
5590 		{
5591 		    /* From the beginning */
5592 		    m->selected_object = 0;
5593 		    while(m->selected_object < prev_sel_num)
5594 		    {
5595 			o = SARMenuGetObject(m, m->selected_object);
5596 			if((o != NULL) &&
5597 			   SARMenuObjectIsSensitive(m, m->selected_object)
5598 			)
5599 			{
5600 			    type = SAR_MENU_OBJECT_TYPE(o);
5601 			    if(TYPE_SELECTABLE(type))
5602 			    {
5603 				status = 1;
5604 				break;
5605 			    }
5606 			}
5607 			m->selected_object++;
5608 		    }
5609 		}
5610 		/* Still no match? */
5611 		if(!status)
5612 		    m->selected_object = prev_sel_num;
5613 	    }
5614 
5615 	    /* Sanitize */
5616 	    if(m->selected_object >= m->total_objects)
5617 		m->selected_object = 0;
5618 	    else if(m->selected_object < 0)
5619 		m->selected_object = m->total_objects - 1;
5620 
5621 	    if(m->selected_object < 0)
5622 		m->selected_object = 0;
5623 
5624 	    /* If a menu's selected object is this button and this
5625 	     * button is unarmed, it needs to be highlighted
5626 	     */
5627 	    o = SARMenuGetObject(m, prev_sel_num);
5628 	    if(o != NULL)
5629 	    {
5630 		if(SAR_MENU_IS_BUTTON(o))
5631 		{
5632 		    button = SAR_MENU_BUTTON(o);
5633 		    button->state = SAR_MENU_BUTTON_STATE_UNARMED;
5634 		}
5635 	    }
5636 	    o = SARMenuGetObject(m, m->selected_object);
5637 	    if(o != NULL)
5638 	    {
5639 		if(SAR_MENU_IS_BUTTON(o))
5640 		{
5641 		    button = SAR_MENU_BUTTON(o);
5642 		    button->state = SAR_MENU_BUTTON_STATE_HIGHLIGHTED;
5643 		}
5644 	    }
5645 
5646 	    DO_REDRAW_MENU(display,m)
5647 	    events_handled++;
5648 	    break;
5649 	}
5650 	if(events_handled > 0)
5651 	    return(events_handled);
5652 
5653 
5654 	/* Key on selected widget */
5655 	i = m->selected_object;
5656 	o = SARMenuGetObject(m, i);
5657 	if(o != NULL)
5658 	{
5659 	    /* Handle by widget type */
5660 	    switch(SAR_MENU_OBJECT_TYPE(o))
5661 	    {
5662 	      /* **************************************************** */
5663 	      case SAR_MENU_OBJECT_TYPE_BUTTON:
5664 		button = SAR_MENU_BUTTON(o);
5665 		if(!button->sensitive)
5666 		    break;
5667 
5668 		switch(key)
5669 		{
5670 		  case '\n': case ' ':
5671 		    if(state)
5672 		    {
5673 			button->state = SAR_MENU_BUTTON_STATE_ARMED;
5674 			DO_REDRAW_OBJECT(display, m, i)
5675 		    }
5676 		    else if(button->state == SAR_MENU_BUTTON_STATE_ARMED)
5677 		    {
5678 			button->state = SAR_MENU_BUTTON_STATE_HIGHLIGHTED;
5679 			DO_REDRAW_OBJECT(display, m, i)
5680 			if(button->func_cb != NULL)
5681 			    button->func_cb(
5682 				button,			/* Object */
5683 				button->id,		/* ID Code */
5684 				button->client_data	/* Data */
5685 			    );
5686 		    }
5687 		    events_handled++;
5688 		    break;
5689 		}
5690 		break;
5691 
5692 	      /* **************************************************** */
5693 	      case SAR_MENU_OBJECT_TYPE_MESSAGE_BOX:
5694 		mesgbox = SAR_MENU_MESSAGE_BOX(o);
5695 		if(!mesgbox->sensitive)
5696 		    break;
5697 
5698 		if(!state)
5699 		    break;
5700 
5701 		w = (int)(mesgbox->width * width);
5702 		if(w <= 0)
5703 		    w = (int)(width - (2 * DEF_MB_XMARGIN));
5704 		if(w <= 0)
5705 		    w = DEF_MB_XMARGIN;
5706 
5707 		if(mesgbox->height > 0)
5708 		    h = (int)(mesgbox->height * height);
5709 		else
5710 		    h = DEF_HEIGHT;
5711 		if(h <= 0)
5712 		    h = DEF_MB_YMARGIN;
5713 
5714 		if(mesgbox->message != NULL)
5715 		{
5716 		    int	total_lines, columns_visable,
5717 			lines_visable, scroll_width;
5718 
5719 
5720 		    GWGetFontSize(
5721 			mesgbox->font,
5722 			NULL, NULL,
5723 			&fw, &fh
5724 		    );
5725 
5726 		    /* Calculate colums visible */
5727 		    if(fw > 0)
5728 			columns_visable = (w - DEF_SCROLL_CURSOR_WIDTH
5729 			    - (2 * DEF_MB_XMARGIN)) / fw;
5730 		    else
5731 			columns_visable = 1;
5732 		    if(columns_visable < 1)
5733 			columns_visable = 1;
5734 
5735 		    /* Calculate width (height) of scroll indicator */
5736 		    scroll_width = fh + (2 * DEF_MB_YMARGIN);
5737 
5738 		    /* Calculate lines visable */
5739 		    if(fh > 0)
5740 			lines_visable = (h - (2 * DEF_MB_YMARGIN)) / fh;
5741 		    else
5742 			lines_visable = 0;
5743 		    if(lines_visable < 0)
5744 			lines_visable = 0;
5745 
5746 		    /* Calculate total number of lines */
5747 		    total_lines = SARMenuMessageBoxTotalLines(
5748 			mesgbox->message, columns_visable
5749 		    );
5750 
5751 		    switch(key)
5752 		    {
5753 		      case GWKeyHome:
5754 			events_handled++;
5755 			mesgbox->scrolled_line = 0;
5756 			DO_REDRAW_OBJECT(display, m, i)
5757 			break;
5758 
5759 		      case GWKeyEnd:
5760 			events_handled++;
5761 			mesgbox->scrolled_line =
5762 			    total_lines - (lines_visable / 2);
5763 			if(mesgbox->scrolled_line < 0)
5764 			    mesgbox->scrolled_line = 0;
5765 			DO_REDRAW_OBJECT(display, m, i)
5766 			break;
5767 
5768 		      case GWKeyUp:
5769 			events_handled++;
5770 			mesgbox->scrolled_line--;
5771 			if(mesgbox->scrolled_line < 0)
5772 			    mesgbox->scrolled_line = 0;
5773 			DO_REDRAW_OBJECT(display, m, i)
5774 			break;
5775 
5776 		      case GWKeyDown:
5777 			events_handled++;
5778 			mesgbox->scrolled_line++;
5779 			if(mesgbox->scrolled_line >=
5780 			    (total_lines - (lines_visable / 2))
5781 			)
5782 			    mesgbox->scrolled_line = total_lines - (lines_visable / 2);
5783 			if(mesgbox->scrolled_line < 0)
5784 			    mesgbox->scrolled_line = 0;
5785 			DO_REDRAW_OBJECT(display, m, i)
5786 			break;
5787 
5788 		      case GWKeyPageUp:
5789 		      case 'b': case '-': case 'p':
5790 			events_handled++;
5791 			mesgbox->scrolled_line -= lines_visable;
5792 			if(mesgbox->scrolled_line < 0)
5793 			    mesgbox->scrolled_line = 0;
5794 			DO_REDRAW_OBJECT(display, m, i)
5795 			break;
5796 
5797 		      case GWKeyPageDown:
5798 		      case ' ': case 'n':
5799 			events_handled++;
5800 			mesgbox->scrolled_line += lines_visable;
5801 			if(mesgbox->scrolled_line >=
5802 			    (total_lines - (lines_visable / 2))
5803 			)
5804 			    mesgbox->scrolled_line = total_lines - (lines_visable / 2);
5805 			if(mesgbox->scrolled_line < 0)
5806 			    mesgbox->scrolled_line = 0;
5807 			DO_REDRAW_OBJECT(display, m, i)
5808 			break;
5809 		    }
5810 		}
5811 		break;
5812 
5813 	      /* **************************************************** */
5814 	      case SAR_MENU_OBJECT_TYPE_LIST:
5815 		list = SAR_MENU_LIST(o);
5816 		if(!list->sensitive)
5817 		    break;
5818 
5819 		if(!state)
5820 		    break;
5821 
5822 		w = (int)(list->width * width);
5823 		if(w <= 0)
5824 		    w = width - (2 * DEF_LIST_XMARGIN);
5825 		if(w <= 0)
5826 		    w = DEF_LIST_XMARGIN;
5827 
5828 		if(list->height > 0)
5829 		    h = (int)(list->height * height);
5830 		else
5831 		    h = DEF_HEIGHT;
5832 		if(h <= 0)
5833 		    h = DEF_LIST_YMARGIN;
5834 
5835 		GWGetFontSize(
5836 		    list->font,
5837 		    NULL, NULL,
5838 		    &fw, &fh
5839 		);
5840 		/* Calculate items visible, remember to subtract 3
5841 		 * items for borders and heading
5842 		 */
5843 		if(fh > 0)
5844 		    items_visable = MAX(
5845 			(h / fh) - 3,
5846 			0
5847 		    );
5848 		else
5849 		    items_visable = 0;
5850 
5851 		/* Update items visable on list */
5852 		list->items_visable = items_visable;
5853 
5854 		/* Record previously selected item */
5855 		prev_sel_num = list->selected_item;
5856 
5857 		switch(key)
5858 		{
5859 		  case GWKeyHome:
5860 		    events_handled++;
5861 		    list->selected_item = 0;
5862 		    list->scrolled_item = 0;
5863 		    DO_REDRAW_OBJECT(display, m, i)
5864 		    break;
5865 
5866 		  case GWKeyEnd:
5867 		    events_handled++;
5868 		    list->selected_item = list->total_items - 1;
5869 		    if(list->selected_item < 0)
5870 			list->selected_item = 0;
5871 		    list->scrolled_item = list->total_items -
5872 			(items_visable / 2);
5873 		    if(list->scrolled_item < 0)
5874 			list->scrolled_item = 0;
5875 		    DO_REDRAW_OBJECT(display, m, i)
5876 		    break;
5877 
5878 		  case GWKeyUp:
5879 		    events_handled++;
5880 		    list->selected_item--;
5881 		    if(list->selected_item < 0)
5882 			list->selected_item = 0;
5883 		    if(list->selected_item < list->scrolled_item)
5884 		    {
5885 			list->scrolled_item -= (items_visable + 1);
5886 			if(list->scrolled_item < 0)
5887 			    list->scrolled_item = 0;
5888 		    }
5889 		    DO_REDRAW_OBJECT(display, m, i)
5890 		    break;
5891 
5892 		  case GWKeyDown:
5893 		    events_handled++;
5894 		    list->selected_item++;
5895 		    if(list->selected_item >= list->total_items)
5896 			list->selected_item = list->total_items - 1;
5897 		    if(list->selected_item < 0)
5898 		       list->selected_item = 0;
5899 		    if(list->selected_item > (list->scrolled_item +
5900 			items_visable)
5901 		    )
5902 		    {
5903 			list->scrolled_item = list->selected_item;
5904 		    }
5905 		    DO_REDRAW_OBJECT(display, m, i)
5906 		    break;
5907 
5908 		  case GWKeyPageUp:
5909 		  case 'b': case '-': case 'p':
5910 		    events_handled++;
5911 		    list->scrolled_item -= items_visable;
5912 		    if(list->scrolled_item < 0)
5913 			list->scrolled_item = 0;
5914 
5915 		    list->selected_item = list->scrolled_item;
5916 
5917 		    DO_REDRAW_OBJECT(display, m, i)
5918 		    break;
5919 
5920 		  case GWKeyPageDown:
5921 		  case ' ': case 'n':
5922 		    events_handled++;
5923 		    list->scrolled_item += items_visable;
5924 		    if(list->scrolled_item >=
5925 			(list->total_items - (items_visable / 2))
5926 		    )
5927 			list->scrolled_item = list->total_items -
5928 			    (items_visable / 2);
5929 		    if(list->scrolled_item < 0)
5930 			list->scrolled_item = 0;
5931 		    list->selected_item = list->scrolled_item;
5932 		    DO_REDRAW_OBJECT(display, m, i)
5933 		    break;
5934 		}
5935 
5936 		/* Call select notify function */
5937 		if((list->select_cb != NULL) &&
5938 		   (prev_sel_num != list->selected_item) &&
5939 		   (list->selected_item >= 0) &&
5940 		   (list->selected_item < list->total_items)
5941 		)
5942 		{
5943 		    sar_menu_list_item_struct *item = list->item[list->selected_item];
5944 		    if(item != NULL)
5945 			list->select_cb(
5946 			    list,			/* This Object */
5947 			    list->id,			/* ID Code */
5948 			    list->client_data,		/* Data */
5949 			    list->selected_item, 	/* Item Number */
5950 			    item,			/* Item Pointer */
5951 			    item->client_data		/* Item Data */
5952 			);
5953 		}
5954 		break;
5955 
5956 	      /* **************************************************** */
5957 	      case SAR_MENU_OBJECT_TYPE_SWITCH:
5958 		sw = SAR_MENU_SWITCH(o);
5959 		if(!sw->sensitive)
5960 		    break;
5961 
5962 		if(!state)
5963 		    break;
5964 
5965 		switch(key)
5966 		{
5967 		  case GWKeyUp:
5968 		  case GWKeyDown:
5969 		  case GWKeyLeft:
5970 		  case GWKeyRight:
5971 		  case ' ': case '\n':
5972 		    events_handled++;
5973 		    sw->state = !sw->state;
5974 		    DO_REDRAW_OBJECT(display, m, i)
5975 		    if(sw->switch_cb != NULL)
5976 			sw->switch_cb(
5977 			    sw,			/* This Object */
5978 			    sw->id,		/* ID Code */
5979 			    sw->client_data,	/* Data */
5980 			    sw->state		/* Value */
5981 			);
5982 		    break;
5983 		}
5984 		break;
5985 
5986 	      /* ***************************************************** */
5987 	      case SAR_MENU_OBJECT_TYPE_SPIN:
5988 		spin = SAR_MENU_SPIN(o);
5989 		if(!spin->sensitive)
5990 		    break;
5991 
5992 		switch(key)
5993 		{
5994 		  case GWKeyRight:
5995 		  case GWKeyDown:
5996 		  case GWKeyPageDown:
5997 		  case ' ': case '\n':
5998 		  case '+': case '=': case 'n':
5999 		    if(state)
6000 		    {
6001 			spin->inc_state = SAR_MENU_BUTTON_STATE_ARMED;
6002 		    }
6003 		    else if(spin->inc_state == SAR_MENU_BUTTON_STATE_ARMED)
6004 		    {
6005 			spin->inc_state = SAR_MENU_BUTTON_STATE_UNARMED;
6006 			SARMenuSpinDoInc(display, m, i, False);
6007 		    }
6008 		    DO_REDRAW_OBJECT(display, m, i)
6009 		    events_handled++;
6010 		    break;
6011 		  case GWKeyLeft:
6012 		  case GWKeyUp:
6013 		  case GWKeyPageUp:
6014 		  case GWKeyBackSpace:
6015 		  case '-': case '_': case 'b':
6016 		    if(state)
6017 		    {
6018 			spin->dec_state = SAR_MENU_BUTTON_STATE_ARMED;
6019 		    }
6020 		    else if(spin->dec_state == SAR_MENU_BUTTON_STATE_ARMED)
6021 		    {
6022 			spin->dec_state = SAR_MENU_BUTTON_STATE_UNARMED;
6023 			SARMenuSpinDoDec(display, m, i, False);
6024 		    }
6025 		    DO_REDRAW_OBJECT(display, m, i)
6026 		    events_handled++;
6027 		    break;
6028 		  case GWKeyHome:
6029 		    if(state)
6030 		    {
6031 			spin->dec_state = SAR_MENU_BUTTON_STATE_ARMED;
6032 		    }
6033 		    else if(spin->dec_state == SAR_MENU_BUTTON_STATE_ARMED)
6034 		    {
6035 			spin->dec_state = SAR_MENU_BUTTON_STATE_UNARMED;
6036 			SARMenuSpinSelectValueIndex(
6037 			    display, m, i,
6038 			    0,
6039 			    False
6040 			);
6041 		    }
6042 		    DO_REDRAW_OBJECT(display, m, i)
6043 		    events_handled++;
6044 		    break;
6045 		  case GWKeyEnd:
6046 		    if(state)
6047 		    {
6048 			spin->inc_state = SAR_MENU_BUTTON_STATE_ARMED;
6049 		    }
6050 		    else if(spin->inc_state == SAR_MENU_BUTTON_STATE_ARMED)
6051 		    {
6052 			spin->inc_state = SAR_MENU_BUTTON_STATE_UNARMED;
6053 			SARMenuSpinSelectValueIndex(
6054 			    display, m, i,
6055 			    MAX(spin->total_values - 1, 0),
6056 			    False
6057 			);
6058 		    }
6059 		    DO_REDRAW_OBJECT(display, m, i)
6060 		    events_handled++;
6061 		    break;
6062 		}
6063 		break;
6064 
6065 	      /* ***************************************************** */
6066 	      case SAR_MENU_OBJECT_TYPE_SLIDER:
6067 		slider = SAR_MENU_SLIDER(o);
6068 		if(!slider->sensitive)
6069 		    break;
6070 
6071 		if(!state)
6072 		    break;
6073 
6074 		if(slider->upper > slider->lower)
6075 		{
6076 		    float inc = (float)(slider->upper - slider->lower) * 0.1f;
6077 		    float page_inc = (float)(slider->upper - slider->lower) * 0.25f;
6078 		    float value;
6079 
6080 		    switch(key)
6081 		    {
6082 		      case GWKeyRight:
6083 		      case GWKeyUp:
6084 		      case '+': case '=': case ' ': case '\n':
6085 			value = CLIP(
6086 			    slider->value + inc,
6087 			    slider->lower, slider->upper
6088 			);
6089 			SARMenuSliderSetValue(
6090 			    display, m, i, value, True
6091 			);
6092 			events_handled++;
6093 			break;
6094 		      case GWKeyLeft:
6095 		      case GWKeyDown:
6096 		      case '_': case '-':
6097 			value = CLIP(
6098 			    slider->value - inc,
6099 			    slider->lower, slider->upper
6100 			);
6101 			SARMenuSliderSetValue(
6102 			    display, m, i, value, True
6103 			);
6104 			events_handled++;
6105 			break;
6106 		      case GWKeyPageUp:
6107 			value = CLIP(
6108 			    slider->value + page_inc,
6109 			    slider->lower, slider->upper
6110 			);
6111 			SARMenuSliderSetValue(
6112 			    display, m, i, value, True
6113 			);
6114 			events_handled++;
6115 			break;
6116 		      case GWKeyPageDown:
6117 			value = CLIP(
6118 			    slider->value - page_inc,
6119 			    slider->lower, slider->upper
6120 			);
6121 			SARMenuSliderSetValue(
6122 			    display, m, i, value, True
6123 			);
6124 			events_handled++;
6125 			break;
6126 		      case GWKeyHome:
6127 			value = slider->lower;
6128 			SARMenuSliderSetValue(
6129 			    display, m, i, value, True
6130 			);
6131 			events_handled++;
6132 			break;
6133 		      case GWKeyEnd:
6134 			value = slider->upper;
6135 			SARMenuSliderSetValue(
6136 			    display, m, i, value, True
6137 			);
6138 			events_handled++;
6139 			break;
6140 		    }
6141 		}
6142 		break;
6143 
6144 	      /* **************************************************** */
6145 	      case SAR_MENU_OBJECT_TYPE_OBJVIEW:
6146 		ov = SAR_MENU_OBJVIEW(o);
6147 		if(!ov->sensitive)
6148 		    break;
6149 		SARMenuObjViewManageKey(
6150 		    display, m, ov, i,
6151 		    key, state
6152 		);
6153 		break;
6154 	    }
6155 	}
6156 
6157 	return(events_handled);
6158 }
6159