1 /*
2 * IceBreaker
3 * Copyright (c) 2000-2002 Matthew Miller <mattdm@mattdm.org> and
4 *   Enrico Tassi <gareuselesinge@infinito.it>
5 *
6 * <http://www.mattdm.org/icebreaker/>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the Free
10 * Software Foundation; either version 2 of the License, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 * for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc., 59
20 * Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23 
24 #include <SDL.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include "icebreaker.h"
28 #include "globals.h"
29 #include "text.h"
30 #include "laundry.h"
31 #include "dialog.h"
32 #include "menu.h"
33 #include "sound.h"
34 #include "hiscore.h"
35 #include "options.h"
36 #include "fullscreen.h"
37 #include "themes.h"
38 #include "grid.h"
39 #include "status.h"
40 #include "level.h"
41 #include "event.h"
42 
43 // fix -- this file is too big; we should split the menu stuff out
44 // and put it in menu.c
45 
46 static PopupReturnType menuhandler(SDL_Rect menurect, int menulength, char ** menuitems, PopupReturnType (**menufunctions)(char *, int), int menuvaluetextwidth );
47 static void drawmenu(SDL_Rect menurect, int menulength, char ** menuitems, PopupReturnType (**menufunctions)(char *, int), int menuvaluetextwidth, int highlighted);
48 
49 static PopupReturnType menuitem_newgame(char * notused, int alsonotused);
50 static PopupReturnType menuitem_options(char * notused, int alsonotused);
51 static PopupReturnType menuitem_highscores(char * notused, int alsonotused);
52 static PopupReturnType menuitem_help(char * notused, int alsonotused);
53 static PopupReturnType menuitem_quit(char * notused, int alsonotused);
54 
55 static PopupReturnType menuitem_sound(char * val, int mbutton);
56 static PopupReturnType menuitem_autopause(char * val, int mbutton);
57 static PopupReturnType menuitem_fullscreen(char * val, int mbutton);
58 static PopupReturnType menuitem_difficulty(char * val, int mbutton);
59 static PopupReturnType menuitem_theme(char * val, int mbutton);
60 
61 
62 // puting this here is ugly, but it's less ugly than many of the
63 // alternatives -- it's very hard to switch themes on the fly
64 static SDL_Surface * optionsmenusave;
65 
66 #define MAXMENUITEMS 10
67 #define MAXMENUVALUELENGTH 10
68 
69 
70 #define MAINMENULENGTH 5
popuplevelmenu()71 PopupReturnType popuplevelmenu()
72 {
73 	SDL_Rect menurect, menubuttonrect;
74 	PopupReturnType rc;
75 	SDL_Surface * levelmenusave;
76 
77 	char * mainmenu[MAINMENULENGTH] = { "NEW GAME", "OPTIONS", "HIGH SCORES", "HELP","QUIT" };
78 	PopupReturnType (*mainmenufunctions[MAINMENULENGTH])(char *,int) = { &menuitem_newgame, &menuitem_options, &menuitem_highscores, &menuitem_help, &menuitem_quit };
79 
80 	menurect.w=128;
81 	menurect.h=7+(MAINMENULENGTH*(CHARHEIGHT*2+3));
82 	menurect.x=BORDERRIGHT-menurect.w+5;
83 	menurect.y=BORDERBOTTOM-menurect.h+9;
84 
85 	menubuttonrect.x=WIDTH-(CHARWIDTH*2*4)-MARGINRIGHT-4;
86 	menubuttonrect.y=BOTTOMSTATUSY;
87 	menubuttonrect.w=CHARWIDTH*2*4+3;
88 	menubuttonrect.h=CHARHEIGHT*2+3;
89 
90 	levelmenusave = SDL_CreateRGBSurface(SDL_SWSURFACE,menurect.w,menurect.h,screen->format->BitsPerPixel,0,0,0,0);
91 	SDL_BlitSurface(screen, &menurect, levelmenusave, NULL);
92 
93 	rc=menuhandler(menurect, MAINMENULENGTH, mainmenu, mainmenufunctions, 0);
94 
95 
96 	if (rc != POPUPQUITGAME)
97 	{
98 		if (gameflags.themechanged)
99 		{
100 			if (!strcmp(options.theme,"random") && rc != POPUPNEWGAME)
101 				settheme("random");
102 
103 			redrawwholelevel();
104 			drawmenubutton(&menubuttonrect,true);
105 			gameflags.themechanged=false;
106 			updateall();
107 		}
108 		else
109 		{
110 			SDL_BlitSurface(levelmenusave, NULL, screen, &menurect);
111 			soil(menurect);
112 		}
113 	}
114 
115 	SDL_FreeSurface(levelmenusave);
116 
117 	return rc;
118 }
119 
menuitem_newgame(char * notused,int alsonotused)120 PopupReturnType menuitem_newgame(char * notused, int alsonotused)
121 {
122 	return POPUPNEWGAME;
123 }
124 
125 
menuitem_options(char * notused,int alsonotused)126 PopupReturnType menuitem_options(char * notused, int alsonotused)
127 {
128 	SDL_Event event;
129 
130 	PopupReturnType rc=popupoptionsmenu();
131 
132 	if (rc!=POPUPEXITMENU)
133 	{
134 		return rc;
135 	}
136 	else
137 	{
138 		// add a fake event so "Options" gets un-highlighted if need be.
139 		SDL_GetMouseState((int *)&event.motion.x,(int *)&event.motion.y);
140 		event.type = SDL_MOUSEMOTION;
141 		SDL_PushEvent(&event);
142 		return POPUPDONOTHING;
143 	}
144 }
145 
146 
menuitem_highscores(char * notused,int alsonotused)147 PopupReturnType menuitem_highscores(char * notused, int alsonotused)
148 {
149 	PopupReturnType rc;
150 	SDL_Event event;
151 	rc=popuphighscores();
152 	// add a fake event so menuitem gets un-highlighted if need be.
153 	SDL_GetMouseState((int *)&event.motion.x,(int *)&event.motion.y);
154 	event.type = SDL_MOUSEMOTION;
155 	SDL_PushEvent(&event);
156 	return rc;
157 }
158 
159 
menuitem_help(char * notused,int alsonotused)160 PopupReturnType menuitem_help(char * notused, int alsonotused)
161 {
162 	PopupReturnType rc;
163 	SDL_Event event;
164 	rc=popuphelp();
165 	// add a fake event so menuitem gets un-highlighted if need be.
166 	SDL_GetMouseState((int *)&event.motion.x,(int *)&event.motion.y);
167 	event.type = SDL_MOUSEMOTION;
168 	SDL_PushEvent(&event);
169 
170 	return rc;
171 }
172 
173 
menuitem_quit(char * notused,int alsonotused)174 PopupReturnType menuitem_quit(char * notused, int alsonotused)
175 {
176 	return POPUPQUITGAME;
177 }
178 
179 #define OPTIONSMENULENGTH 5
180 
popupoptionsmenu()181 PopupReturnType popupoptionsmenu()
182 {
183 	SDL_Rect menurect;
184 	GameDifficultyType originaldifficulty=options.difficulty;
185 	char originaltheme[MAXTHEMENAMELENGTH+1];
186 	PopupReturnType rc;
187 	int originalthemecl=false;
188 	int recallme=false;
189 
190 
191 	char * optionsmenu[OPTIONSMENULENGTH] = { "SOUND", "AUTO PAUSE", "FULL SCREEN", "DIFFICULTY", "THEME" };
192 	PopupReturnType (*optionsmenufunctions[OPTIONSMENULENGTH])(char *,int) = { &menuitem_sound, &menuitem_autopause, &menuitem_fullscreen, &menuitem_difficulty, &menuitem_theme };
193 
194 	if (strlen(commandline.theme)>0)
195 	{
196 		snprintf(originaltheme,MAXTHEMENAMELENGTH+1,"%s",commandline.theme);
197 		originalthemecl=true;
198 	}
199 	else
200 	{
201 		snprintf(originaltheme,MAXTHEMENAMELENGTH+1,"%s",options.theme);
202 		originalthemecl=false;
203 	}
204 
205 	menurect.w=229;
206 	menurect.h=7+(OPTIONSMENULENGTH*(CHARHEIGHT*2+3));
207 	menurect.x=BORDERRIGHT-menurect.w+10;
208 	menurect.y=BORDERBOTTOM-menurect.h+9-((CHARHEIGHT*2+4)*4)-2;
209 
210 	optionsmenusave = SDL_CreateRGBSurface(SDL_SWSURFACE,menurect.w,menurect.h,screen->format->BitsPerPixel,0,0,0,0);
211 	SDL_BlitSurface(screen, &menurect, optionsmenusave, NULL);
212 
213 	rc=menuhandler(menurect, OPTIONSMENULENGTH, optionsmenu, optionsmenufunctions, 84);
214 
215 	if (rc==POPUPEXITMENU)
216 	{
217 		if ((originalthemecl && strcmp(commandline.theme, originaltheme)) ||
218 		    (!originalthemecl && strcmp(options.theme, originaltheme)) )
219 		{
220 			gameflags.themechanged=true;
221 		}
222 	}
223 
224 	if (rc==POPUPEXITMENU && options.difficulty != originaldifficulty)
225 	{
226 		if (checkiflevelatstart())
227 		{
228 			rc=POPUPNEWGAME;
229 		}
230 		else
231 		{
232 			switch (yesnodialog("Changing difficulty","requires restart.","End this game?"))
233 			{
234 				case POPUPQUITGAME:
235 					rc=POPUPQUITGAME;
236 				break;
237 				case POPUPYES:
238 					rc=POPUPNEWGAME;
239 				break;
240 				case POPUPNO:
241 					options.difficulty=originaldifficulty; // put things back. :)
242 					recallme=true;
243 				break;
244 				default:
245 					fprintf(stderr,"Internal weirdness: yes/no dialog box returned something other than yes or no.\n"
246 					               "That shouldn't ever happen.\n");
247 				break;
248 			}
249 		}
250 	}
251 
252 	//writeoptions(); // probably no need to do this until exit
253 
254 	// and restore the background
255 	if (rc != POPUPQUITGAME)
256 	{
257 		SDL_BlitSurface(optionsmenusave, NULL, screen, &menurect);
258 		soil(menurect);
259 	}
260 
261 	SDL_FreeSurface(optionsmenusave);
262 
263 
264 	if (recallme) rc=popupoptionsmenu(); // this is a bit sick.
265 	return rc;
266 }
267 
268 
menuitem_sound(char * val,int mbutton)269 PopupReturnType menuitem_sound(char * val, int mbutton)
270 {
271 	if (strlen(val)==0)
272 	{
273 		if (gameflags.soundsystemworks)
274 		{
275 			if (options.sound==SOUNDON)
276 				strncpy(val,"on",MAXMENUVALUELENGTH);
277 			else
278 				strncpy(val,"off",MAXMENUVALUELENGTH);
279 		}
280 		else
281 		{
282 			strncpy(val,"n/a",MAXMENUVALUELENGTH);
283 		}
284 		return POPUPDONOTHING;
285 	}
286 	else
287 	{
288 		if (!gameflags.soundsystemworks) return POPUPDONOTHING;
289 		if (options.sound==SOUNDON)
290 		{
291 			options.sound=SOUNDOFF;
292 			strncpy(val,"off",MAXMENUVALUELENGTH);
293 		}
294 		else
295 		{
296 			options.sound=SOUNDON;
297 			strncpy(val,"on",MAXMENUVALUELENGTH);
298 		}
299 		return POPUPREDRAWME;
300 	}
301 }
302 
menuitem_autopause(char * val,int mbutton)303 PopupReturnType menuitem_autopause(char * val, int mbutton)
304 {
305 	if (strlen(val)==0)
306 	{
307 		if (options.autopause==AUTOPAUSEON)
308 			strncpy(val,"on",MAXMENUVALUELENGTH);
309 		else
310 			strncpy(val,"off",MAXMENUVALUELENGTH);
311 		return POPUPDONOTHING;
312 	}
313 	else
314 	{
315 		if (options.autopause==AUTOPAUSEON)
316 		{
317 			options.autopause=AUTOPAUSEOFF;
318 			strncpy(val,"off",MAXMENUVALUELENGTH);
319 		}
320 		else
321 		{
322 			options.autopause=AUTOPAUSEON;
323 			strncpy(val,"on",MAXMENUVALUELENGTH);
324 		}
325 		return POPUPREDRAWME;
326 	}
327 }
328 
menuitem_fullscreen(char * val,int mbutton)329 PopupReturnType menuitem_fullscreen(char * val, int mbutton)
330 {
331 	// fix -- cope with failure to switch
332 	if (strlen(val)==0)
333 	{
334 		switch (options.fullscreen)
335 		{
336 			case FULLSCREENOFF:
337 				strncpy(val,"off",MAXMENUVALUELENGTH);
338 			break;
339 			case FULLSCREENON:
340 				strncpy(val,"on",MAXMENUVALUELENGTH);
341 			break;
342 			case FULLSCREENALWAYS:
343 				strncpy(val,"always",MAXMENUVALUELENGTH);
344 			break;
345 			case FULLSCREENUNKNOWN: // this should never happen!
346 				strncpy(val,"???",MAXMENUVALUELENGTH);
347 			break;
348 		}
349 		return POPUPDONOTHING;
350 	}
351 	else
352 	{
353 		if (mbutton==1 || mbutton==4) // left or scroll forwards
354 		{
355 			switch (options.fullscreen)
356 			{
357 				case FULLSCREENOFF:
358 					options.fullscreen=FULLSCREENON;
359 					strncpy(val,"on",MAXMENUVALUELENGTH);
360 					makefullscreen();
361 				break;
362 				case FULLSCREENON:
363 					options.fullscreen=FULLSCREENALWAYS;
364 					strncpy(val,"always",MAXMENUVALUELENGTH);
365 				break;
366 				case FULLSCREENALWAYS:
367 					options.fullscreen=FULLSCREENOFF;
368 					strncpy(val,"off",MAXMENUVALUELENGTH);
369 					makewindowed();
370 				break;
371 				case FULLSCREENUNKNOWN: // this should never happen!
372 					options.fullscreen=FULLSCREENOFF;
373 					strncpy(val,"off",MAXMENUVALUELENGTH);
374 					makewindowed();
375 				break;
376 			}
377 		}
378 		else // right or middle or scroll back
379 		{
380 			switch (options.fullscreen)
381 			{
382 				case FULLSCREENOFF:
383 					options.fullscreen=FULLSCREENALWAYS;
384 					strncpy(val,"always",MAXMENUVALUELENGTH);
385 					makefullscreen();
386 				break;
387 				case FULLSCREENON:
388 					options.fullscreen=FULLSCREENOFF;
389 					strncpy(val,"off",MAXMENUVALUELENGTH);
390 					makewindowed();
391 				break;
392 				case FULLSCREENALWAYS:
393 					options.fullscreen=FULLSCREENON;
394 					strncpy(val,"on",MAXMENUVALUELENGTH);
395 				break;
396 				case FULLSCREENUNKNOWN: // this should never happen!
397 					options.fullscreen=FULLSCREENOFF;
398 					strncpy(val,"off",MAXMENUVALUELENGTH);
399 					makewindowed();
400 				break;
401 			}
402 		}
403 		return POPUPREDRAWME;
404 	}
405 }
406 
407 
menuitem_difficulty(char * val,int mbutton)408 PopupReturnType menuitem_difficulty(char * val, int mbutton)
409 {
410 	if (strlen(val)==0)
411 	{
412 		switch (options.difficulty)
413 		{
414 			case NORMAL:
415 				strncpy(val,"normal",MAXMENUVALUELENGTH);
416 			break;
417 			case EASY:
418 				strncpy(val,"easy",MAXMENUVALUELENGTH);
419 			break;
420 			case HARD:
421 				strncpy(val,"hard",MAXMENUVALUELENGTH);
422 			break;
423 		}
424 		return POPUPDONOTHING;
425 	}
426 	else
427 	{
428 		if (mbutton==1 || mbutton==4) // left or scroll forwards
429 		{
430 			switch (options.difficulty)
431 			{
432 				case NORMAL:
433 					options.difficulty=EASY;
434 					strncpy(val,"easy",MAXMENUVALUELENGTH);
435 				break;
436 				case EASY:
437 					options.difficulty=HARD;
438 					strncpy(val,"hard",MAXMENUVALUELENGTH);
439 				break;
440 				case HARD:
441 					options.difficulty=NORMAL;
442 					strncpy(val,"normal",MAXMENUVALUELENGTH);
443 				break;
444 			}
445 		}
446 		else // right or middle or scroll back
447 		{
448 			switch (options.difficulty)
449 			{
450 				case NORMAL:
451 					options.difficulty=HARD;
452 					strncpy(val,"hard",MAXMENUVALUELENGTH);
453 				break;
454 				case EASY:
455 					options.difficulty=NORMAL;
456 					strncpy(val,"normal",MAXMENUVALUELENGTH);
457 				break;
458 				case HARD:
459 					options.difficulty=EASY;
460 					strncpy(val,"easy",MAXMENUVALUELENGTH);
461 				break;
462 			}
463 		}
464 		return POPUPREDRAWME;
465 	}
466 }
467 
menuitem_theme(char * val,int mbutton)468 PopupReturnType menuitem_theme(char * val, int mbutton)
469 {
470 	char** themelist;
471 	int t;
472 	int themecount;
473 	SDL_Rect tmprect;
474 
475 	// FIX -- this is kind of kludgy -- why define this twice?
476 	char * mainmenu[MAINMENULENGTH] = { "NEW GAME", "OPTIONS", "HIGH SCORES", "HELP","QUIT" };
477 
478 	// fix -- all of these are also stupidly duplicated
479 	SDL_Rect mainmenurect;
480 	SDL_Rect optionsmenurect;
481 	SDL_Rect menubuttonrect;
482 	mainmenurect.w=128;
483 	mainmenurect.h=7+(MAINMENULENGTH*(CHARHEIGHT*2+3));
484 	mainmenurect.x=BORDERRIGHT-mainmenurect.w+5;
485 	mainmenurect.y=BORDERBOTTOM-mainmenurect.h+9;
486 
487 	optionsmenurect.w=229;
488 	optionsmenurect.h=7+(OPTIONSMENULENGTH*(CHARHEIGHT*2+3));
489 	optionsmenurect.x=BORDERRIGHT-optionsmenurect.w+10;
490 	optionsmenurect.y=BORDERBOTTOM-optionsmenurect.h+9-((CHARHEIGHT*2+4)*4)-2;
491 
492 	menubuttonrect.x=WIDTH-(CHARWIDTH*2*4)-MARGINRIGHT-4;
493 	menubuttonrect.y=BOTTOMSTATUSY;
494 	menubuttonrect.w=CHARWIDTH*2*4+3;
495 	menubuttonrect.h=CHARHEIGHT*2+3;
496 
497 
498 	if (strlen(val)==0)
499 	{
500 		if (strlen(commandline.theme)>0)
501 			strncpy(val,commandline.theme,MAXMENUVALUELENGTH);
502 		else
503 			strncpy(val,options.theme,MAXMENUVALUELENGTH);
504 		return POPUPDONOTHING;
505 	}
506 	else
507 	{
508 		themecount=getthemenames(&themelist);
509 
510 		if (strlen(commandline.theme)>0)
511 		{
512 			t=getthemenumber(themelist,themecount,commandline.theme);
513 			// once we've changed the theme, there's no going back
514 			*(commandline.theme)='\0'; // makes this ""
515 		}
516 		else
517 		{
518 			t=getthemenumber(themelist,themecount,options.theme);
519 		}
520 
521 		if (((mbutton==1 || mbutton==4) && t==themecount-1) || ((mbutton!=1 && mbutton!=4) && t==0))
522 		{ // "random", at the end/beginning of the list
523 
524 			strncpy(val,"random",MAXMENUVALUELENGTH);
525 			snprintf(options.theme,MAXMENUVALUELENGTH,"random");
526 
527 			settheme("linux"); // just for pretty
528 
529 			redrawwholelevel();
530 			drawmenu(mainmenurect, MAINMENULENGTH, mainmenu, NULL, 0, 1);
531 			drawmenubutton(&menubuttonrect,true);
532 
533 			puttext((WIDTH-gettextwidth(10,"?"))/2,(HEIGHT-CHARHEIGHT*10)/2,10,color.gameovertext,"?");
534 			gameflags.themechanged=true;
535 		}
536 		else
537 		{
538 			if (mbutton==1 || mbutton==4) // left click or scroll forwards
539 			{
540 				strncpy(val,themelist[(t+1)%themecount],MAXMENUVALUELENGTH);
541 				snprintf(options.theme,MAXMENUVALUELENGTH,themelist[(t+1)%themecount]);
542 			}
543 			else // right or middle or scroll back
544 			{
545 				if (t<0) t=themecount;
546 				strncpy(val,themelist[(t-1)%themecount],MAXMENUVALUELENGTH);
547 				snprintf(options.theme,MAXMENUVALUELENGTH,themelist[(t-1)%themecount]);
548 			}
549 
550 			settheme(options.theme);
551 
552 			redrawwholelevel();
553 			drawmenu(mainmenurect, MAINMENULENGTH, mainmenu, NULL, 0, 1);
554 			drawmenubutton(&menubuttonrect,true);
555 		}
556 		SDL_BlitSurface(screen, &optionsmenurect, optionsmenusave, NULL);
557 
558 		freethemenames(&themelist,themecount);
559 
560 		tmprect.w=WIDTH; tmprect.h=HEIGHT;
561 		tmprect.x=0;tmprect.y=0;
562 		soil(tmprect);
563 
564 
565 		return POPUPDONOTHING;
566 	}
567 }
568 
569 
570 
571 /* displays a menu; takes a rect for position and size, the length of the
572  * menu, an array of menu items, an array of pointers to functions for
573  * each menu item (functions should return type MenuReturnType
574  * indicating what to do when the item is clicked) and a flag telling whether
575  * menu items are option/value pairs.
576  */
menuhandler(SDL_Rect menurect,int menulength,char ** menuitems,PopupReturnType (** menufunctions)(char *,int),int menuvaluetextwidth)577 PopupReturnType menuhandler(SDL_Rect menurect, int menulength, char ** menuitems, PopupReturnType (**menufunctions)(char *, int), int menuvaluetextwidth)
578 {
579 	SDL_Rect insiderect;
580 	SDL_Rect menuitemrect[MAXMENUITEMS];
581 	char menuvalues[MAXMENUITEMS][MAXMENUVALUELENGTH];
582 	int menuitemglow=-1;
583 
584 	int menuitempressed=false;
585 	SDL_Event event;
586 	PopupReturnType rc=POPUPDONOTHING;
587 	int redrawmenuflag=false;
588 	int domenuitemflag=false;
589 	Uint8 domenuitembutton=0;
590 
591 	int i;
592 
593 	SDL_EnableKeyRepeat(500,90);
594 
595 	insiderect.w=menurect.w-2;
596 	insiderect.h=menurect.h-2;
597 	insiderect.x=menurect.x+1;
598 	insiderect.y=menurect.y+1;
599 
600 	// fix -- use drawmenu() here?
601 	SDL_FillRect(screen,&menurect,color.gridline);
602 	SDL_FillRect(screen,&insiderect,color.background);
603 
604 	// find current option values
605 	for (i=0;i<menulength;i++)
606 	{
607 		menuitemrect[i].x=insiderect.x;
608 		menuitemrect[i].y=insiderect.y+2+(i*(CHARHEIGHT*2+3));
609 		menuitemrect[i].w=insiderect.w;
610 		menuitemrect[i].h=(CHARHEIGHT*2)+3;
611 		puttext(menuitemrect[i].x+5,menuitemrect[i].y+3,2,color.normaltext,menuitems[i]);
612 
613 		strncpy(menuvalues[i],"",MAXMENUVALUELENGTH);
614 		if (menuvaluetextwidth)
615 		{
616 			if (menufunctions!=NULL && menufunctions[i]!=NULL)
617 				(*menufunctions[i])(menuvalues[i],0);
618 			puttext(menuitemrect[i].x+menuitemrect[i].w-menuvaluetextwidth,menuitemrect[i].y+3,2,color.normaltext,menuvalues[i]);
619 		}
620 	}
621 	soil(menurect);
622 
623 	clean(); // fix -- any point in not doing this first thing in the
624 	        // loop and removing the clean at the bottom of the loop?
625 
626 	do
627 	{
628 		SDL_WaitEvent(NULL); // no new CPU cooler needed. :)
629 		while (pollevent(&event))
630 		{
631 			if (event.type == SDL_QUIT)
632 			{
633 				rc=POPUPQUITGAME;
634 			}
635 			else if (event.type == SDL_MOUSEBUTTONDOWN)
636 			{
637 				if (event.button.x>menurect.x &&
638 				    event.button.y>menurect.y &&
639 				    event.button.x<menurect.x + menurect.w &&
640 				    event.button.y<menurect.y + menurect.h)
641 				{
642 					if (event.button.button == 1 || menuvaluetextwidth) // we only care about right clicks on items with options
643 					{
644 						if (event.button.y-menurect.y>=3)
645 						if (menuitemglow!=(event.button.y-(menurect.y+3))/(CHARHEIGHT*2+3))
646 						{
647 							menuitemglow=(event.button.y-(menurect.y+3))/(CHARHEIGHT*2+3);
648 
649 							redrawmenuflag=true;
650 						}
651 						if (menuitemglow>=menulength)
652 							menuitemglow=-1;
653 						else
654 							menuitempressed=true;
655 					}
656 				}
657 				else
658 				{
659 					rc=POPUPEXITMENU;
660 				}
661 			}
662 			else if (event.type == SDL_MOUSEBUTTONUP)
663 			{
664 				if (menuitempressed && (event.button.button == 1 || menuvaluetextwidth)) // again, we only care about right clicks on items with options
665 				{
666 					// in area, button was down
667 					if (event.motion.x>menurect.x &&
668 					    event.motion.y>(menurect.y + 2) &&
669 					    event.motion.x<menurect.x + menurect.w &&
670 					    event.motion.y<menurect.y + menurect.h - 2)
671 					{
672 						if (menufunctions!=NULL && menufunctions[menuitemglow]!=NULL)
673 						{
674 							domenuitemflag=true;
675 							domenuitembutton=event.button.button;
676 						}
677 					}
678 					menuitempressed=false;
679 				}
680 			}
681 			else if (event.type == SDL_MOUSEMOTION)
682 			{
683 				// are we in the menu area?
684 				if (event.motion.x>menurect.x &&
685 				     event.motion.y>(menurect.y + 2) &&
686 				     event.motion.x<menurect.x + menurect.w &&
687 				     event.motion.y<menurect.y + menurect.h - 2)
688 				{
689 					menuitemglow=(event.motion.y-(menurect.y+3))/(CHARHEIGHT*2+3);
690 					if (menuitemglow>=menulength) menuitemglow=-1;
691 					redrawmenuflag=true;
692 				}
693 				else
694 				{
695 					if (menuitemglow != -1 && !menuitempressed)
696 					{
697 						menuitemglow=-1;
698 						redrawmenuflag=true;
699 					}
700 				}
701 
702 			}
703 			else if (event.type==SDL_KEYDOWN)
704 			{
705 				switch(translatekeyevent(&event))
706 				{
707 					case KEYMENU: // falls through
708 					case KEYCANCEL:
709 						rc=POPUPEXITMENU;
710 					case KEYMOVEUP:
711 						if (!menuitempressed)
712 						{
713 							menuitemglow--;
714 							if (menuitemglow<0) menuitemglow=menulength-1;
715 							redrawmenuflag=true;
716 						}
717 					break;
718 					case KEYMOVEDOWN:
719 						if (!menuitempressed)
720 						{
721 							menuitemglow++;
722 							if (menuitemglow>=menulength) menuitemglow=0;
723 							redrawmenuflag=true;
724 						}
725 					break;
726 					case KEYSTARTLINE:
727 						if (menuitemglow!=-1 && menufunctions!=NULL && menufunctions[menuitemglow]!=NULL)
728 						{
729 							domenuitemflag=true;
730 							domenuitembutton=1;
731 						}
732 					break;
733 					case KEYSWITCHLINE:
734 						if (menuvaluetextwidth && menuitemglow!=-1 && menufunctions!=NULL && menufunctions[menuitemglow]!=NULL)
735 						{
736 							domenuitemflag=true;
737 							domenuitembutton=2;
738 						}
739 					break;
740 					case KEYMOVERIGHT:
741 						if (menuvaluetextwidth && menuitemglow!=-1 && menufunctions!=NULL && menufunctions[menuitemglow]!=NULL)
742 						{
743 							domenuitemflag=true;
744 							domenuitembutton=1;
745 						}
746 					break;
747 					case KEYMOVELEFT:
748 						if (menuvaluetextwidth && menuitemglow!=-1 && menufunctions!=NULL && menufunctions[menuitemglow]!=NULL)
749 						{
750 							domenuitemflag=true;
751 							domenuitembutton=2;
752 						}
753 					break;
754 					default:
755 					break;
756 				}
757 
758 			}
759 		}
760 
761 		if (domenuitemflag)
762 		{
763 			// this calls the menu functions, in case that's not obvious
764 			rc=(*menufunctions[menuitemglow])(menuvalues[menuitemglow],domenuitembutton);
765 			domenuitemflag=false;
766 			redrawmenuflag=true;
767 		}
768 
769 
770 		if (rc==POPUPREDRAWME)
771 		{
772 			rc=POPUPDONOTHING;
773 			redrawmenuflag=true;
774 		}
775 
776 
777 		if (redrawmenuflag)
778 		{
779 			SDL_FillRect(screen,&menurect,color.gridline);
780 			SDL_FillRect(screen,&insiderect,color.background);
781 			for (i=0;i<menulength;i++)
782 			{
783 					if (i == menuitemglow)
784 				{
785 					SDL_FillRect(screen,&menuitemrect[i],color.menuhighlight);
786 					puttext(menuitemrect[i].x+5,menuitemrect[i].y+3,2,color.background,menuitems[i]);
787 					if (menuvaluetextwidth) puttext(menuitemrect[i].x+menuitemrect[i].w-menuvaluetextwidth,menuitemrect[i].y+3,2,color.background,menuvalues[i]);
788 				}
789 				else
790 				{
791 					puttext(menuitemrect[i].x+5,menuitemrect[i].y+3,2,color.normaltext,menuitems[i]);
792 					if (menuvaluetextwidth) puttext(menuitemrect[i].x+menuitemrect[i].w-menuvaluetextwidth,menuitemrect[i].y+3,2,color.normaltext,menuvalues[i]);
793 				}
794 			}
795 			soil(menurect);
796 			redrawmenuflag=false;
797 		}
798 
799 		clean();
800 	} while (rc==POPUPDONOTHING);
801 
802 	// a fake event to update things that depend on mouse position
803 	SDL_GetMouseState((int *)&event.motion.x,(int *)&event.motion.y);
804 	event.type = SDL_MOUSEMOTION;
805 	SDL_PushEvent(&event);
806 
807 	SDL_EnableKeyRepeat(0,0);
808 	return(rc);
809 }
810 
811 
drawmenu(SDL_Rect menurect,int menulength,char ** menuitems,PopupReturnType (** menufunctions)(char *,int),int menuvaluetextwidth,int highlighted)812 void drawmenu(SDL_Rect menurect, int menulength, char ** menuitems, PopupReturnType (**menufunctions)(char *, int), int menuvaluetextwidth, int highlighted)
813 {
814 	SDL_Rect insiderect;
815 	SDL_Rect menuitemrect[MAXMENUITEMS];
816 	char menuvalues[MAXMENUITEMS][MAXMENUVALUELENGTH];
817 
818 	int i;
819 
820 	insiderect.w=menurect.w-2;
821 	insiderect.h=menurect.h-2;
822 	insiderect.x=menurect.x+1;
823 	insiderect.y=menurect.y+1;
824 
825 	SDL_FillRect(screen,&menurect,color.gridline);
826 	SDL_FillRect(screen,&insiderect,color.background);
827 
828 	for (i=0;i<menulength;i++)
829 	{
830 		menuitemrect[i].x=insiderect.x;
831 		menuitemrect[i].y=insiderect.y+2+(i*(CHARHEIGHT*2+3));
832 		menuitemrect[i].w=insiderect.w;
833 		menuitemrect[i].h=(CHARHEIGHT*2)+3;
834 
835 		strncpy(menuvalues[i],"",MAXMENUVALUELENGTH);
836 		if (i == highlighted)
837 		{
838 			SDL_FillRect(screen,&menuitemrect[i],color.menuhighlight);
839 			puttext(menuitemrect[i].x+5,menuitemrect[i].y+3,2,color.background,menuitems[i]);
840 			if (menuvaluetextwidth) // get option value
841 			{
842 				if (menufunctions!=NULL && menufunctions[i]!=NULL)
843 					(*menufunctions[i])(menuvalues[i],0);
844 				puttext(menuitemrect[i].x+menuitemrect[i].w-menuvaluetextwidth,menuitemrect[i].y+3,2,color.background,menuvalues[i]);
845 			}
846 		}
847 		else
848 		{
849 			puttext(menuitemrect[i].x+5,menuitemrect[i].y+3,2,color.normaltext,menuitems[i]);
850 			if (menuvaluetextwidth)
851 			{
852 				if (menufunctions!=NULL && menufunctions[i]!=NULL)
853 					(*menufunctions[i])(menuvalues[i],0);
854 				puttext(menuitemrect[i].x+menuitemrect[i].w-menuvaluetextwidth,menuitemrect[i].y+3,2,color.normaltext,menuvalues[i]);
855 		 	}
856 		}
857 
858 	}
859 
860 	soil(menurect);
861 
862 	clean();
863 
864 }
865 
drawmenubutton(SDL_Rect * mbrect,int highlighted)866 void drawmenubutton(SDL_Rect* mbrect,int highlighted)
867 {
868 	if (highlighted)
869 	{
870 		SDL_FillRect(screen,mbrect,color.menuhighlight);
871 		puttext(mbrect->x+3,mbrect->y+3,2,color.background,"MENU");
872 	}
873 	else
874 	{
875 		SDL_FillRect(screen,mbrect,color.background);
876 		puttext(mbrect->x+3,mbrect->y+3,2,color.normaltext,"MENU");
877 	}
878 	soil(*mbrect);
879 }
880 
881