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