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