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