- data/levels/default/ moved to data/levels/worldmap/
[supertux.git] / src / menu.cpp
1 //  $Id$
2 //
3 //  SuperTux
4 //  Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 2
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 //
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19
20 #ifndef WIN32
21 #include <sys/types.h>
22 #include <ctype.h>
23 #endif
24
25 #include <iostream>
26 #include <sstream>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string>
30 #include <assert.h>
31
32 #include "defines.h"
33 #include "globals.h"
34 #include "menu.h"
35 #include "screen/screen.h"
36 #include "screen/drawing_context.h"
37 #include "setup.h"
38 #include "sound.h"
39 #include "scene.h"
40 #include "leveleditor.h"
41 #include "timer.h"
42 #include "high_scores.h"
43 #include "gettext.h"
44
45 #define FLICK_CURSOR_TIME 500
46
47 Surface* checkbox;
48 Surface* checkbox_checked;
49 Surface* back;
50 Surface* arrow_left;
51 Surface* arrow_right;
52
53 Menu* main_menu      = 0;
54 Menu* game_menu      = 0;
55 Menu* worldmap_menu  = 0;
56 Menu* options_menu   = 0;
57 Menu* options_keys_menu     = 0;
58 Menu* options_joystick_menu = 0;
59 Menu* highscore_menu = 0;
60 Menu* load_game_menu = 0;
61 Menu* save_game_menu = 0;
62 Menu* contrib_menu   = 0;
63 Menu* contrib_subset_menu   = 0;
64
65 std::vector<Menu*> Menu::last_menus;
66 Menu* Menu::current_ = 0;
67
68 /* just displays a Yes/No text that can be used to confirm stuff */
69 bool confirm_dialog(Surface *background, std::string text)
70 {
71   //Surface* cap_screen = Surface::CaptureScreen();
72   
73   Menu* dialog = new Menu;
74   dialog->additem(MN_DEACTIVE, text,0,0);
75   dialog->additem(MN_HL,"",0,0);
76   dialog->additem(MN_ACTION,_("Yes"),0,0,true);
77   dialog->additem(MN_ACTION,_("No"),0,0,false);
78   dialog->additem(MN_HL,"",0,0);
79
80   Menu::set_current(dialog);
81
82   DrawingContext context;
83
84   while(true)
85   {
86     SDL_Event event;
87
88     while (SDL_PollEvent(&event))
89     {
90       dialog->event(event);
91     }
92
93     if(background == NULL)
94       context.draw_gradient(Color(200, 100, 200), Color(100, 200, 100), LAYER_BACKGROUND0);
95     else
96       context.draw_surface(background, Vector(0,0), LAYER_BACKGROUND0);
97
98     dialog->draw(context);
99     dialog->action();
100
101     switch (dialog->check())
102     {
103     case true:
104       //delete cap_screen;
105       Menu::set_current(0);
106       delete dialog;
107       return true;
108       break;
109     case false:
110       //delete cap_screen;
111       Menu::set_current(0);
112       delete dialog;
113       return false;
114       break;
115     default:
116       break;
117     }
118
119     mouse_cursor->draw(context);
120     context.do_drawing();
121     SDL_Delay(25);
122   }
123
124   return false;
125 }
126
127 void
128 Menu::push_current(Menu* pmenu)
129 {
130   if (current_)
131     last_menus.push_back(current_);
132
133   current_ = pmenu;
134   current_->effect.start(500);
135 }
136
137 void
138 Menu::pop_current()
139 {
140   if (!last_menus.empty())
141   {
142     current_ = last_menus.back();
143     current_->effect.start(500);
144
145     last_menus.pop_back();
146   }
147   else
148   {
149     current_ = 0;
150   }
151 }
152
153 void
154 Menu::set_current(Menu* menu)
155 {
156   last_menus.clear();
157
158   if (menu)
159     menu->effect.start(500);
160
161   current_ = menu;
162 }
163
164 /* Return a pointer to a new menu item */
165 MenuItem*
166 MenuItem::create(MenuItemKind kind_, const char *text_, int init_toggle_, Menu* target_menu_, int id, int* int_p_)
167 {
168   MenuItem *pnew_item = new MenuItem;
169
170   pnew_item->kind = kind_;
171   pnew_item->text = (char*) malloc(sizeof(char) * (strlen(text_) + 1));
172   strcpy(pnew_item->text, text_);
173
174   if(kind_ == MN_TOGGLE)
175     pnew_item->toggled = init_toggle_;
176   else
177     pnew_item->toggled = false;
178
179   pnew_item->target_menu = target_menu_;
180   pnew_item->input = (char*) malloc(sizeof(char));
181   pnew_item->input[0] = '\0';
182
183   if(kind_ == MN_STRINGSELECT)
184   {
185     pnew_item->list = (string_list_type*) malloc(sizeof(string_list_type));
186     string_list_init(pnew_item->list);
187   }
188   else
189     pnew_item->list = NULL;
190
191   pnew_item->id = id;
192   pnew_item->int_p = int_p_;
193
194   pnew_item->input_flickering = false;
195   pnew_item->input_flickering_timer.init(true);
196   pnew_item->input_flickering_timer.start(FLICK_CURSOR_TIME);
197
198   return pnew_item;
199 }
200
201 void
202 MenuItem::change_text(const  char *text_)
203 {
204   if (text_)
205   {
206     free(text);
207     text = (char*) malloc(sizeof(char )*(strlen(text_)+1));
208     strcpy(text, text_);
209   }
210 }
211
212 void
213 MenuItem::change_input(const  char *text_)
214 {
215   if(text)
216   {
217     free(input);
218     input = (char*) malloc(sizeof(char )*(strlen(text_)+1));
219     strcpy(input, text_);
220   }
221 }
222
223 std::string MenuItem::get_input_with_symbol(bool active_item)
224 {
225   if(!active_item)
226     input_flickering = true;
227   else
228   {
229     if(input_flickering_timer.get_left() < 0)
230     {
231       if(input_flickering)
232         input_flickering = false;
233       else
234         input_flickering = true;
235       input_flickering_timer.start(FLICK_CURSOR_TIME);
236     }
237   }
238
239   char str[1024];
240   if(input_flickering)
241     sprintf(str,"%s_",input);
242   else
243     sprintf(str,"%s ",input);
244
245   std::string string = str;
246
247   return string;
248 }
249
250 /* Set ControlField for keyboard key */
251 void Menu::get_controlfield_key_into_input(MenuItem *item)
252 {
253   switch(*item->int_p)
254   {
255   case SDLK_UP:
256     item->change_input(_("Up cursor"));
257     break;
258   case SDLK_DOWN:
259     item->change_input(_("Down cursor"));
260     break;
261   case SDLK_LEFT:
262     item->change_input(_("Left cursor"));
263     break;
264   case SDLK_RIGHT:
265     item->change_input(_("Right cursor"));
266     break;
267   case SDLK_RETURN:
268     item->change_input(_("Return"));
269     break;
270   case SDLK_SPACE:
271     item->change_input(_("Space"));
272     break;
273   case SDLK_RSHIFT:
274     item->change_input(_("Right Shift"));
275     break;
276   case SDLK_LSHIFT:
277     item->change_input(_("Left Shift"));
278     break;
279   case SDLK_RCTRL:
280     item->change_input(_("Right Control"));
281     break;
282   case SDLK_LCTRL:
283     item->change_input(_("Left Control"));
284     break;
285   case SDLK_RALT:
286     item->change_input(_("Right Alt"));
287     break;
288   case SDLK_LALT:
289     item->change_input(_("Left Alt"));
290     break;
291   default:
292     {
293       char tmp[64];
294       snprintf(tmp, 64, "%d", *item->int_p);
295       item->change_input(tmp);
296     }
297     break;
298   }
299 }
300
301 /* Set ControlField for joystick button */
302 void Menu::get_controlfield_js_into_input(MenuItem *item)
303 {
304   std::ostringstream oss;
305   oss << "Button " << *item->int_p;
306   item->change_input(oss.str().c_str());
307 }
308
309 /* Free a menu and all its items */
310 Menu::~Menu()
311 {
312   if(item.size() != 0)
313   {
314     for(unsigned int i = 0; i < item.size(); ++i)
315     {
316       free(item[i].text);
317       free(item[i].input);
318       string_list_free(item[i].list);
319     }
320   }
321 }
322
323
324 Menu::Menu()
325 {
326   hit_item = -1;
327   menuaction = MENU_ACTION_NONE;
328   delete_character = 0;
329   mn_input_char = '\0';
330
331   pos_x        = screen->w/2;
332   pos_y        = screen->h/2;
333   arrange_left = 0;
334   active_item  = 0;
335   effect.init(false);
336
337   joystick_timer.init(true);
338 }
339
340 void Menu::set_pos(int x, int y, float rw, float rh)
341 {
342   pos_x = x + (int)((float)get_width() * rw);
343   pos_y = y + (int)((float)get_height() * rh);
344 }
345
346 void
347 Menu::additem(MenuItemKind kind_, const std::string& text_, int toggle_, Menu* menu_, int id, int* int_p)
348 {
349   additem(MenuItem::create(kind_, text_.c_str(), toggle_, menu_, id, int_p));
350 }
351
352 /* Add an item to a menu */
353 void
354 Menu::additem(MenuItem* pmenu_item)
355 {
356   item.push_back(*pmenu_item);
357   delete pmenu_item;
358 }
359
360 void
361 Menu::clear()
362 {
363   item.clear();
364 }
365
366 /* Process actions done on the menu */
367 void
368 Menu::action()
369 {
370   hit_item = -1;
371   if(item.size() != 0)
372   {
373     switch(menuaction)
374     {
375     case MENU_ACTION_UP:
376       if (active_item > 0)
377         --active_item;
378       else
379         active_item = int(item.size())-1;
380       break;
381
382     case MENU_ACTION_DOWN:
383       if(active_item < int(item.size())-1)
384         ++active_item;
385       else
386         active_item = 0;
387       break;
388
389     case MENU_ACTION_LEFT:
390       if(item[active_item].kind == MN_STRINGSELECT
391           && item[active_item].list->num_items != 0)
392       {
393         if(item[active_item].list->active_item > 0)
394           --item[active_item].list->active_item;
395         else
396           item[active_item].list->active_item = item[active_item].list->num_items-1;
397       }
398       break;
399
400     case MENU_ACTION_RIGHT:
401       if(item[active_item].kind == MN_STRINGSELECT
402           && item[active_item].list->num_items != 0)
403       {
404         if(item[active_item].list->active_item < item[active_item].list->num_items-1)
405           ++item[active_item].list->active_item;
406         else
407           item[active_item].list->active_item = 0;
408       }
409       break;
410
411     case MENU_ACTION_HIT:
412       {
413         hit_item = active_item;
414         switch (item[active_item].kind)
415         {
416         case MN_GOTO:
417           if (item[active_item].target_menu != NULL)
418             Menu::push_current(item[active_item].target_menu);
419           else
420             puts("NULLL");
421           break;
422
423         case MN_TOGGLE:
424           item[active_item].toggled = !item[active_item].toggled;
425           break;
426
427         case MN_ACTION:
428           Menu::set_current(0);
429           item[active_item].toggled = true;
430           break;
431         case MN_TEXTFIELD:
432         case MN_NUMFIELD:
433           menuaction = MENU_ACTION_DOWN;
434           action();
435           break;
436
437         case MN_BACK:
438           Menu::pop_current();
439           break;
440         default:
441           break;
442         }
443       }
444       break;
445
446     case MENU_ACTION_REMOVE:
447       if(item[active_item].kind == MN_TEXTFIELD
448           || item[active_item].kind == MN_NUMFIELD)
449       {
450         if(item[active_item].input != NULL)
451         {
452           int i = strlen(item[active_item].input);
453
454           while(delete_character > 0)   /* remove charactes */
455           {
456             item[active_item].input[i-1] = '\0';
457             delete_character--;
458           }
459         }
460       }
461       break;
462
463     case MENU_ACTION_INPUT:
464       if(item[active_item].kind == MN_TEXTFIELD
465           || (item[active_item].kind == MN_NUMFIELD && mn_input_char >= '0' && mn_input_char <= '9'))
466       {
467         if(item[active_item].input != NULL)
468         {
469           int i = strlen(item[active_item].input);
470           item[active_item].input = (char*) realloc(item[active_item].input,sizeof(char)*(i + 2));
471           item[active_item].input[i] = mn_input_char;
472           item[active_item].input[i+1] = '\0';
473         }
474         else
475         {
476           item[active_item].input = (char*) malloc(2*sizeof(char));
477           item[active_item].input[0] = mn_input_char;
478           item[active_item].input[1] = '\0';
479         }
480       }
481
482     case MENU_ACTION_NONE:
483       break;
484     }
485   }
486
487   MenuItem& new_item = item[active_item];
488   if(new_item.kind == MN_DEACTIVE
489       || new_item.kind == MN_LABEL
490       || new_item.kind == MN_HL)
491   {
492     // Skip the horzontal line item
493     if (menuaction != MENU_ACTION_UP && menuaction != MENU_ACTION_DOWN)
494       menuaction = MENU_ACTION_DOWN;
495
496     if (item.size() > 1)
497       action();
498   }
499
500   menuaction = MENU_ACTION_NONE;
501
502   if (active_item >= int(item.size()))
503     active_item = int(item.size()) - 1;
504 }
505
506 int
507 Menu::check()
508 {
509   if (hit_item != -1)
510     return item[hit_item].id;
511   else
512     return -1;
513 }
514
515 void
516 Menu::draw_item(DrawingContext& context,
517     int index, // Position of the current item in the menu
518     int menu_width, int menu_height)
519 {
520   MenuItem& pitem = item[index];
521
522   int effect_offset = 0;
523   {
524     int effect_time = 0;
525
526     if(effect.check())
527       effect_time = effect.get_left() / 4;
528
529     effect_offset = (index % 2) ? effect_time : -effect_time;
530   }
531
532   Font* text_font = white_text;
533   int x_pos       = pos_x;
534   int y_pos       = pos_y + 24*index - menu_height/2 + 12 + effect_offset;
535   int shadow_size = 2;
536   int text_width  = int(text_font->get_text_width(pitem.text));
537   int input_width = int(text_font->get_text_width(pitem.input) + 10);
538   int list_width  =
539     int(text_font->get_text_width(string_list_active(pitem.list)));
540
541   if (arrange_left)
542     x_pos += 24 - menu_width/2 + (text_width + input_width + list_width)/2;
543
544   if(index == active_item)
545   {
546     shadow_size = 3;
547     text_font = blue_text;
548   }
549
550   switch (pitem.kind)
551   {
552   case MN_DEACTIVE:
553     {
554       context.draw_text_center(blue_text, pitem.text,
555           Vector(0, y_pos - int(blue_text->get_height()/2)),
556           LAYER_FOREGROUND1);
557       break;
558     }
559
560   case MN_HL:
561     {
562       // TODO
563       int x = pos_x - menu_width/2;
564       int y = y_pos - 12 - effect_offset;
565       /* Draw a horizontal line with a little 3d effect */
566       context.draw_filled_rect(Vector(x, y + 6),
567           Vector(menu_width, 4), Color(150,200,255,225), LAYER_FOREGROUND1);
568       context.draw_filled_rect(Vector(x, y + 6),
569           Vector(menu_width, 2), Color(255,255,255,255), LAYER_FOREGROUND1);
570       break;
571     }
572   case MN_LABEL:
573     {
574       context.draw_text_center(white_big_text,
575           pitem.text, Vector(0, y_pos - int(white_big_text->get_height()/2)),
576           LAYER_FOREGROUND1);
577       break;
578     }
579   case MN_TEXTFIELD:
580   case MN_NUMFIELD:
581   case MN_CONTROLFIELD_KB:
582   case MN_CONTROLFIELD_JS:
583     {
584       int width = text_width + input_width + 5;
585       int text_pos = screen->w/2 - width/2;
586       int input_pos = text_pos + text_width + 10;
587
588       context.draw_filled_rect(
589           Vector(input_pos - 5, y_pos - 10),
590           Vector(input_width + 10, 20),
591           Color(255,255,255,255), LAYER_FOREGROUND1-5);
592       context.draw_filled_rect(
593           Vector(input_pos - 4, y_pos - 9),
594           Vector(input_width + 8, 18),
595           Color(0,0,0,128), LAYER_FOREGROUND1-4);
596
597       if(pitem.kind == MN_CONTROLFIELD_KB)
598         get_controlfield_key_into_input(&pitem);
599       else if (pitem.kind == MN_CONTROLFIELD_JS)
600         get_controlfield_js_into_input(&pitem);
601
602       if(pitem.kind == MN_TEXTFIELD || pitem.kind == MN_NUMFIELD)
603       {
604         if(active_item == index)
605           context.draw_text(gold_text,
606               pitem.get_input_with_symbol(true),
607               Vector(input_pos, y_pos - int(gold_text->get_height()/2)),
608               LAYER_FOREGROUND1);
609         else
610           context.draw_text(gold_text,
611               pitem.get_input_with_symbol(false),
612               Vector(input_pos, y_pos - int(gold_text->get_height()/2)),
613               LAYER_FOREGROUND1);
614       }
615       else
616         context.draw_text(gold_text, pitem.input,
617             Vector(input_pos, y_pos - int(gold_text->get_height()/2)),
618             LAYER_FOREGROUND1);
619
620       context.draw_text(text_font, pitem.text,
621           Vector(text_pos, y_pos - int(text_font->get_height()/2)),
622           LAYER_FOREGROUND1);
623       break;
624     }
625   case MN_STRINGSELECT:
626     {
627       int list_pos_2 = list_width + 16;
628       int list_pos   = list_width/2;
629       int text_pos   = (text_width + 16)/2;
630
631       /* Draw arrows */
632       context.draw_surface(arrow_left,
633           Vector(x_pos - list_pos + text_pos - 17, y_pos - 8),
634           LAYER_FOREGROUND1);
635       context.draw_surface(arrow_right,
636           Vector(x_pos - list_pos + text_pos - 1 + list_pos_2, y_pos - 8),
637           LAYER_FOREGROUND1);
638
639       /* Draw input background */
640       context.draw_filled_rect(
641           Vector(x_pos - list_pos + text_pos - 1, y_pos - 10),
642           Vector(list_pos_2 + 2, 20),
643           Color(255,255,255,255), LAYER_FOREGROUND1 - 4);
644       context.draw_filled_rect(
645           Vector(x_pos - list_pos + text_pos, y_pos - 9),
646           Vector(list_pos_2, 18),
647           Color(0,0,0,128), LAYER_FOREGROUND1 - 5);
648
649       context.draw_text_center(text_font, string_list_active(pitem.list),
650           Vector(text_pos, y_pos - int(text_font->get_height()/2)),
651           LAYER_FOREGROUND1);
652       context.draw_text_center(text_font, pitem.text,
653           Vector(list_pos_2/2, y_pos - int(text_font->get_height()/2)),
654           LAYER_FOREGROUND1);
655       break;
656     }
657   case MN_BACK:
658     {
659       context.draw_text_center(text_font, pitem.text,
660           Vector(0, y_pos - int(text_font->get_height()/2)),
661           LAYER_FOREGROUND1);
662       context.draw_surface(back,
663           Vector(x_pos + text_width/2  + 16, y_pos - 8),
664           LAYER_FOREGROUND1);
665       break;
666     }
667
668   case MN_TOGGLE:
669     {
670       context.draw_text_center(text_font, pitem.text,
671           Vector(0, y_pos - (text_font->get_height()/2)),
672           LAYER_FOREGROUND1);
673
674       if(pitem.toggled)
675         context.draw_surface(checkbox_checked,
676             Vector(x_pos + (text_width+16)/2, y_pos - 8),
677             LAYER_FOREGROUND1 + 1);
678       else
679         context.draw_surface(checkbox,
680             Vector(x_pos + (text_width+16)/2, y_pos - 8),
681             LAYER_FOREGROUND1 + 1);                                      
682       break;
683     }
684   case MN_ACTION:
685     context.draw_text_center(text_font, pitem.text,
686         Vector(0, y_pos - int(text_font->get_height()/2)),
687         LAYER_FOREGROUND1);
688     break;
689
690   case MN_GOTO:
691     context.draw_text_center(text_font, pitem.text,
692         Vector(0, y_pos - int(text_font->get_height()/2)),
693         LAYER_FOREGROUND1);
694     break;
695   }
696 }
697
698 int Menu::get_width() const
699 {
700   /* The width of the menu has to be more than the width of the text
701      with the most characters */
702   int menu_width = 0;
703   for(unsigned int i = 0; i < item.size(); ++i)
704   {
705     int w = strlen(item[i].text) + (item[i].input ? strlen(item[i].input) + 1 : 0) + strlen(string_list_active(item[i].list));
706     if( w > menu_width )
707     {
708       menu_width = w;
709       if( item[i].kind == MN_TOGGLE)
710         menu_width += 2;
711     }
712   }
713
714   return (menu_width * 16 + 24);
715 }
716
717 int Menu::get_height() const
718 {
719   return item.size() * 24;
720 }
721
722 /* Draw the current menu. */
723 void
724 Menu::draw(DrawingContext& context)
725 {
726   int menu_height = get_height();
727   int menu_width  = get_width();
728
729   /* Draw a transparent background */
730   context.draw_filled_rect(
731       Vector(pos_x - menu_width/2, pos_y - 24*item.size()/2 - 10),
732       Vector(menu_width,menu_height + 20),
733       Color(150,180,200,125), LAYER_FOREGROUND1-10);
734
735   for(unsigned int i = 0; i < item.size(); ++i)
736   {
737     draw_item(context, i, menu_width, menu_height);
738   }
739 }
740
741 MenuItem&
742 Menu::get_item_by_id(int id)
743 {
744   for(std::vector<MenuItem>::iterator i = item.begin(); i != item.end(); ++i)
745   {
746     if(i->id == id)
747       return *i;
748   }
749
750   assert(false);
751   static MenuItem dummyitem;
752   return dummyitem;
753 }
754
755 int Menu::get_active_item_id()
756 {
757   return item[active_item].id;
758 }
759
760 bool
761 Menu::isToggled(int id)
762 {
763   return get_item_by_id(id).toggled;
764 }
765
766 /* Check for menu event */
767 void
768 Menu::event(SDL_Event& event)
769 {
770   SDLKey key;
771   switch(event.type)
772   {
773   case SDL_KEYDOWN:
774     key = event.key.keysym.sym;
775     SDLMod keymod;
776     char ch[2];
777     keymod = SDL_GetModState();
778     int x,y;
779
780     /* If the current unicode character is an ASCII character,
781        assign it to ch. */
782     if ( (event.key.keysym.unicode & 0xFF80) == 0 )
783     {
784       ch[0] = event.key.keysym.unicode & 0x7F;
785       ch[1] = '\0';
786     }
787     else
788     {
789       /* An International Character. */
790     }
791
792     if(item[active_item].kind == MN_CONTROLFIELD_KB)
793     {
794       if(key == SDLK_ESCAPE)
795       {
796         Menu::pop_current();
797         return;
798       }
799       *item[active_item].int_p = key;
800       menuaction = MENU_ACTION_DOWN;
801       return;
802     }
803
804
805     switch(key)
806     {
807     case SDLK_UP:               /* Menu Up */
808       menuaction = MENU_ACTION_UP;
809       break;
810     case SDLK_DOWN:             /* Menu Down */
811       menuaction = MENU_ACTION_DOWN;
812       break;
813     case SDLK_LEFT:             /* Menu Up */
814       menuaction = MENU_ACTION_LEFT;
815       break;
816     case SDLK_RIGHT:            /* Menu Down */
817       menuaction = MENU_ACTION_RIGHT;
818       break;
819     case SDLK_SPACE:
820       if(item[active_item].kind == MN_TEXTFIELD)
821       {
822         menuaction = MENU_ACTION_INPUT;
823         mn_input_char = ' ';
824         break;
825       }
826     case SDLK_RETURN: /* Menu Hit */
827       menuaction = MENU_ACTION_HIT;
828       break;
829     case SDLK_DELETE:
830     case SDLK_BACKSPACE:
831       menuaction = MENU_ACTION_REMOVE;
832       delete_character++;
833       break;
834     case SDLK_ESCAPE:
835       Menu::pop_current();
836       break;
837     default:
838       if( (key >= SDLK_0 && key <= SDLK_9) || (key >= SDLK_a && key <= SDLK_z) || (key >= SDLK_SPACE && key <= SDLK_SLASH))
839       {
840         menuaction = MENU_ACTION_INPUT;
841         mn_input_char = *ch;
842       }
843       else
844       {
845         mn_input_char = '\0';
846       }
847       break;
848     }
849     break;
850   case  SDL_JOYAXISMOTION:
851     if(event.jaxis.axis == joystick_keymap.y_axis)
852     {
853       if (event.jaxis.value > joystick_keymap.dead_zone && !joystick_timer.started())
854       {
855         menuaction = MENU_ACTION_DOWN;
856         joystick_timer.start(JOYSTICK_MENU_DELAY);
857       }
858       else if (event.jaxis.value < -joystick_keymap.dead_zone && !joystick_timer.started())
859       {
860         menuaction = MENU_ACTION_UP;
861         joystick_timer.start(JOYSTICK_MENU_DELAY);
862       }
863       else
864         joystick_timer.stop();
865     }
866     break;
867   case  SDL_JOYBUTTONDOWN:
868     if (item[active_item].kind == MN_CONTROLFIELD_JS)
869     {
870       *item[active_item].int_p = key;
871       menuaction = MENU_ACTION_DOWN;
872     }
873     menuaction = MENU_ACTION_HIT;
874     break;
875   case SDL_MOUSEBUTTONDOWN:
876     x = event.motion.x;
877     y = event.motion.y;
878     if(x > pos_x - get_width()/2 &&
879         x < pos_x + get_width()/2 &&
880         y > pos_y - get_height()/2 &&
881         y < pos_y + get_height()/2)
882     {
883       menuaction = MENU_ACTION_HIT;
884     }
885     break;
886   case SDL_MOUSEMOTION:
887     x = event.motion.x;
888     y = event.motion.y;
889     if(x > pos_x - get_width()/2 &&
890         x < pos_x + get_width()/2 &&
891         y > pos_y - get_height()/2 &&
892         y < pos_y + get_height()/2)
893     {
894       active_item = (y - (pos_y - get_height()/2)) / 24;
895       mouse_cursor->set_state(MC_LINK);
896     }
897     else
898     {
899       mouse_cursor->set_state(MC_NORMAL);
900     }
901     break;
902   default:
903     break;
904   }
905 }
906
907
908 // EOF //