src/gui/menu.cpp

Go to the documentation of this file.
00001 //  SuperTux
00002 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
00003 //
00004 //  This program is free software: you can redistribute it and/or modify
00005 //  it under the terms of the GNU General Public License as published by
00006 //  the Free Software Foundation, either version 3 of the License, or
00007 //  (at your option) any later version.
00008 //
00009 //  This program is distributed in the hope that it will be useful,
00010 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 //  GNU General Public License for more details.
00013 //
00014 //  You should have received a copy of the GNU General Public License
00015 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016 
00017 #include "gui/menu.hpp"
00018 
00019 #include <math.h>
00020 #include <stdexcept>
00021 
00022 #include "control/joystickkeyboardcontroller.hpp"
00023 #include "gui/menu_item.hpp"
00024 #include "gui/menu_manager.hpp"
00025 #include "gui/mousecursor.hpp"
00026 #include "supertux/globals.hpp"
00027 #include "supertux/screen_manager.hpp"
00028 #include "supertux/resources.hpp"
00029 #include "supertux/timer.hpp"
00030 #include "util/gettext.hpp"
00031 #include "video/drawing_context.hpp"
00032 #include "video/font.hpp"
00033 
00034 static const float MENU_REPEAT_INITIAL = 0.4f;
00035 static const float MENU_REPEAT_RATE    = 0.1f;
00036 
00037 Menu::Menu() :
00038   hit_item(),
00039   pos(),
00040   menuaction(),
00041   delete_character(),
00042   mn_input_char(),
00043   menu_repeat_time(),
00044   close(false),
00045   items(),
00046   effect_progress(),
00047   effect_start_time(),
00048   arrange_left(),
00049   active_item(),
00050   checkbox(),
00051   checkbox_checked(),
00052   back(),
00053   arrow_left(),
00054   arrow_right()
00055 {
00056   MenuManager::all_menus.push_back(this);
00057 
00058   hit_item = -1;
00059   menuaction = MENU_ACTION_NONE;
00060   delete_character = 0;
00061   mn_input_char = '\0';
00062 
00063   pos.x        = SCREEN_WIDTH/2;
00064   pos.y        = SCREEN_HEIGHT/2;
00065   arrange_left = 0;
00066   active_item  = -1;
00067 
00068   effect_progress   = 0.0f;
00069   effect_start_time = 0.0f;
00070 
00071   checkbox         = Surface::create("images/engine/menu/checkbox-unchecked.png");
00072   checkbox_checked = Surface::create("images/engine/menu/checkbox-checked.png");
00073   back             = Surface::create("images/engine/menu/arrow-back.png");
00074   arrow_left       = Surface::create("images/engine/menu/arrow-left.png");
00075   arrow_right      = Surface::create("images/engine/menu/arrow-right.png");
00076 }
00077 
00078 Menu::~Menu()
00079 {
00080   MenuManager::all_menus.remove(this);
00081 
00082   for(std::vector<MenuItem*>::iterator i = items.begin();
00083       i != items.end(); ++i) 
00084   {
00085     delete *i;
00086   }
00087 
00088   if (MenuManager::current_ == this)
00089     MenuManager::current_ = NULL;
00090 
00091   if (MenuManager::previous == this)
00092     MenuManager::previous = NULL;
00093 }
00094 
00095 void
00096 Menu::set_pos(float x, float y, float rw, float rh)
00097 {
00098   pos.x = x + get_width()  * rw;
00099   pos.y = y + get_height() * rh;
00100 }
00101 
00102 /* Add an item to a menu */
00103 void
00104 Menu::additem(MenuItem* item)
00105 {
00106   items.push_back(item);
00107 
00108   /* If a new menu is being built, the active item shouldn't be set to
00109    * something that isn't selectable. Set the active_item to the first
00110    * selectable item added.
00111    */
00112   if (active_item == -1
00113       && item->kind != MN_HL
00114       && item->kind != MN_LABEL
00115       && item->kind != MN_INACTIVE) {
00116     active_item = items.size() - 1;
00117   }
00118 }
00119 
00120 MenuItem*
00121 Menu::add_hl()
00122 {
00123   MenuItem* item = new MenuItem(MN_HL);
00124   additem(item);
00125   return item;
00126 }
00127 
00128 MenuItem*
00129 Menu::add_label(const std::string& text)
00130 {
00131   MenuItem* item = new MenuItem(MN_LABEL);
00132   item->text = text;
00133   additem(item);
00134   return item;
00135 }
00136 
00137 MenuItem*
00138 Menu::add_controlfield(int id, const std::string& text,
00139                        const std::string& mapping)
00140 {
00141   MenuItem* item = new MenuItem(MN_CONTROLFIELD, id);
00142   item->change_text(text);
00143   item->change_input(mapping);
00144   additem(item);
00145   return item;
00146 }
00147 
00148 MenuItem*
00149 Menu::add_entry(int id, const std::string& text)
00150 {
00151   MenuItem* item = new MenuItem(MN_ACTION, id);
00152   item->text = text;
00153   additem(item);
00154   return item;
00155 }
00156 
00157 MenuItem*
00158 Menu::add_inactive(int id, const std::string& text)
00159 {
00160   MenuItem* item = new MenuItem(MN_INACTIVE, id);
00161   item->text = text;
00162   additem(item);
00163   return item;
00164 }
00165 
00166 MenuItem*
00167 Menu::add_toggle(int id, const std::string& text, bool toogled)
00168 {
00169   MenuItem* item = new MenuItem(MN_TOGGLE, id);
00170   item->text = text;
00171   item->toggled = toogled;
00172   additem(item);
00173   return item;
00174 }
00175 
00176 MenuItem*
00177 Menu::add_string_select(int id, const std::string& text)
00178 {
00179   MenuItem* item = new MenuItem(MN_STRINGSELECT, id);
00180   item->text = text;
00181   additem(item);
00182   return item;
00183 }
00184 
00185 MenuItem*
00186 Menu::add_back(const std::string& text)
00187 {
00188   MenuItem* item = new MenuItem(MN_BACK);
00189   item->text = text;
00190   additem(item);
00191   return item;
00192 }
00193 
00194 MenuItem*
00195 Menu::add_submenu(const std::string& text, Menu* submenu, int id)
00196 {
00197   MenuItem* item = new MenuItem(MN_GOTO, id);
00198   item->text = text;
00199   item->target_menu = submenu;
00200   additem(item);
00201   return item;
00202 }
00203 
00204 void
00205 Menu::clear()
00206 {
00207   for(std::vector<MenuItem*>::iterator i = items.begin();
00208       i != items.end(); ++i) {
00209     delete *i;
00210   }
00211   items.clear();
00212   active_item = -1;
00213 }
00214 
00215 /* Process actions done on the menu */
00216 void
00217 Menu::update()
00218 {
00219   int menu_height = (int) get_height();
00220   if (menu_height > SCREEN_HEIGHT)
00221   { // Scrolling
00222     int scroll_offset = (menu_height - SCREEN_HEIGHT) / 2 + 32;
00223     pos.y = SCREEN_HEIGHT/2 - scroll_offset * ((float(active_item) / (items.size()-1)) - 0.5f) * 2.0f;
00224   }
00225 
00226   effect_progress = (real_time - effect_start_time) * 6.0f;
00227 
00228   if(effect_progress >= 1.0f) {
00229     effect_progress = 1.0f;
00230 
00231     if (close) {
00232       MenuManager::current_ = 0;
00233       close = false;
00234     }
00235   }
00236   else if (effect_progress <= 0.0f) {
00237     effect_progress = 0.0f;
00238   }
00239 
00240   Controller *controller = g_jk_controller->get_main_controller();
00242   if(controller->pressed(Controller::UP)) {
00243     menuaction = MENU_ACTION_UP;
00244     menu_repeat_time = real_time + MENU_REPEAT_INITIAL;
00245   }
00246   if(controller->hold(Controller::UP) &&
00247      menu_repeat_time != 0 && real_time > menu_repeat_time) {
00248     menuaction = MENU_ACTION_UP;
00249     menu_repeat_time = real_time + MENU_REPEAT_RATE;
00250   }
00251 
00252   if(controller->pressed(Controller::DOWN)) {
00253     menuaction = MENU_ACTION_DOWN;
00254     menu_repeat_time = real_time + MENU_REPEAT_INITIAL;
00255   }
00256   if(controller->hold(Controller::DOWN) &&
00257      menu_repeat_time != 0 && real_time > menu_repeat_time) {
00258     menuaction = MENU_ACTION_DOWN;
00259     menu_repeat_time = real_time + MENU_REPEAT_RATE;
00260   }
00261 
00262   if(controller->pressed(Controller::LEFT)) {
00263     menuaction = MENU_ACTION_LEFT;
00264     menu_repeat_time = real_time + MENU_REPEAT_INITIAL;
00265   }
00266   if(controller->hold(Controller::LEFT) &&
00267      menu_repeat_time != 0 && real_time > menu_repeat_time) {
00268     menuaction = MENU_ACTION_LEFT;
00269     menu_repeat_time = real_time + MENU_REPEAT_RATE;
00270   }
00271 
00272   if(controller->pressed(Controller::RIGHT)) {
00273     menuaction = MENU_ACTION_RIGHT;
00274     menu_repeat_time = real_time + MENU_REPEAT_INITIAL;
00275   }
00276   if(controller->hold(Controller::RIGHT) &&
00277      menu_repeat_time != 0 && real_time > menu_repeat_time) {
00278     menuaction = MENU_ACTION_RIGHT;
00279     menu_repeat_time = real_time + MENU_REPEAT_RATE;
00280   }
00281 
00282   if(controller->pressed(Controller::ACTION)
00283      || controller->pressed(Controller::MENU_SELECT)) {
00284     menuaction = MENU_ACTION_HIT;
00285   }
00286   if(controller->pressed(Controller::PAUSE_MENU)) {
00287     menuaction = MENU_ACTION_BACK;
00288   }
00289 
00290   hit_item = -1;
00291   if(items.size() == 0)
00292     return;
00293 
00294   int last_active_item = active_item;
00295   switch(menuaction) {
00296     case MENU_ACTION_UP:
00297       do {
00298         if (active_item > 0)
00299           --active_item;
00300         else
00301           active_item = int(items.size())-1;
00302       } while ((items[active_item]->kind == MN_HL
00303                 || items[active_item]->kind == MN_LABEL
00304                 || items[active_item]->kind == MN_INACTIVE)
00305                && (active_item != last_active_item));
00306 
00307       break;
00308 
00309     case MENU_ACTION_DOWN:
00310       do {
00311         if(active_item < int(items.size())-1 )
00312           ++active_item;
00313         else
00314           active_item = 0;
00315       } while ((items[active_item]->kind == MN_HL
00316                 || items[active_item]->kind == MN_LABEL
00317                 || items[active_item]->kind == MN_INACTIVE)
00318                && (active_item != last_active_item));
00319 
00320       break;
00321 
00322     case MENU_ACTION_LEFT:
00323       if(items[active_item]->kind == MN_STRINGSELECT) {
00324         if(items[active_item]->selected > 0)
00325           items[active_item]->selected--;
00326         else
00327           items[active_item]->selected = items[active_item]->list.size()-1;
00328         
00329         menu_action(items[active_item]);
00330       }
00331       break;
00332 
00333     case MENU_ACTION_RIGHT:
00334       if(items[active_item]->kind == MN_STRINGSELECT) {
00335         if(items[active_item]->selected+1 < items[active_item]->list.size())
00336           items[active_item]->selected++;
00337         else
00338           items[active_item]->selected = 0;
00339         
00340         menu_action(items[active_item]);
00341       }
00342       break;
00343 
00344     case MENU_ACTION_HIT: {
00345       hit_item = active_item;
00346       switch (items[active_item]->kind) {
00347         case MN_GOTO:
00348           assert(items[active_item]->target_menu != 0);
00349           MenuManager::push_current(items[active_item]->target_menu);
00350           break;
00351 
00352         case MN_TOGGLE:
00353           items[active_item]->toggled = !items[active_item]->toggled;
00354           menu_action(items[active_item]);
00355           break;
00356 
00357         case MN_CONTROLFIELD:
00358           menu_action(items[active_item]);
00359           break;
00360 
00361         case MN_ACTION:
00362           menu_action(items[active_item]);
00363           break;
00364 
00365         case MN_STRINGSELECT:
00366           if(items[active_item]->selected+1 < items[active_item]->list.size())
00367             items[active_item]->selected++;
00368           else
00369             items[active_item]->selected = 0;
00370 
00371           menu_action(items[active_item]);
00372           break;
00373 
00374         case MN_TEXTFIELD:
00375         case MN_NUMFIELD:
00376           menuaction = MENU_ACTION_DOWN;
00377           update();
00378           break;
00379 
00380         case MN_BACK:
00381           MenuManager::pop_current();
00382           break;
00383         default:
00384           break;
00385       }
00386       break;
00387     }
00388 
00389     case MENU_ACTION_REMOVE:
00390       if(items[active_item]->kind == MN_TEXTFIELD
00391          || items[active_item]->kind == MN_NUMFIELD)
00392       {
00393         if(!items[active_item]->input.empty())
00394         {
00395           int i = items[active_item]->input.size();
00396 
00397           while(delete_character > 0)        /* remove characters */
00398           {
00399             items[active_item]->input.resize(i-1);
00400             delete_character--;
00401           }
00402         }
00403       }
00404       break;
00405 
00406     case MENU_ACTION_INPUT:
00407       if(items[active_item]->kind == MN_TEXTFIELD
00408          || (items[active_item]->kind == MN_NUMFIELD
00409              && mn_input_char >= '0' && mn_input_char <= '9'))
00410       {
00411         items[active_item]->input.push_back(mn_input_char);
00412       }
00413       break;
00414 
00415     case MENU_ACTION_BACK:
00416       MenuManager::pop_current();
00417       break;
00418 
00419     case MENU_ACTION_NONE:
00420       break;
00421   }
00422   menuaction = MENU_ACTION_NONE;
00423 
00424   assert(active_item < int(items.size()));
00425 }
00426 
00427 int
00428 Menu::check()
00429 {
00430   if (hit_item != -1) 
00431   {
00432     int id = items[hit_item]->id;
00433     // Clear event when checked out.. (we would end up in a loop when we try to leave "fake" submenu like Addons or Contrib)
00434     hit_item = -1;                      
00435     return id;
00436   }
00437   else
00438     return -1;
00439 }
00440 
00441 void
00442 Menu::menu_action(MenuItem* )
00443 {}
00444 
00445 void
00446 Menu::draw_item(DrawingContext& context, int index)
00447 {
00448   float menu_height = get_height();
00449   float menu_width  = get_width();
00450 
00451   MenuItem& pitem = *(items[index]);
00452 
00453   Color text_color = default_color;
00454   float x_pos       = pos.x;
00455   float y_pos       = pos.y + 24*index - menu_height/2 + 12;
00456   int text_width  = int(Resources::normal_font->get_text_width(pitem.text));
00457   int input_width = int(Resources::normal_font->get_text_width(pitem.input) + 10);
00458   int list_width = 0;
00459 
00460   float left  = pos.x - menu_width/2 + 16;
00461   float right = pos.x + menu_width/2 - 16;
00462 
00463   if(pitem.list.size() > 0) {
00464     list_width = (int) Resources::normal_font->get_text_width(pitem.list[pitem.selected]);
00465   }
00466 
00467   if (arrange_left)
00468     x_pos += 24 - menu_width/2 + (text_width + input_width + list_width)/2;
00469 
00470   if(index == active_item)
00471   {
00472     text_color = active_color;
00473   }
00474 
00475   if(active_item == index)
00476   {
00477     float blink = (sinf(real_time * M_PI * 1.0f)/2.0f + 0.5f) * 0.5f + 0.25f;
00478     context.draw_filled_rect(Rectf(Vector(pos.x - menu_width/2 + 10 - 2, y_pos - 12 - 2),
00479                                    Vector(pos.x + menu_width/2 - 10 + 2, y_pos + 12 + 2)),
00480                              Color(1.0f, 1.0f, 1.0f, blink),
00481                              14.0f,
00482                              LAYER_GUI-10);
00483     context.draw_filled_rect(Rectf(Vector(pos.x - menu_width/2 + 10, y_pos - 12),
00484                                    Vector(pos.x + menu_width/2 - 10, y_pos + 12)),
00485                              Color(1.0f, 1.0f, 1.0f, 0.5f),
00486                              12.0f,
00487                              LAYER_GUI-10);
00488   }
00489 
00490   switch (pitem.kind)
00491   {
00492     case MN_INACTIVE:
00493     {
00494       context.draw_text(Resources::normal_font, pitem.text,
00495                         Vector(pos.x, y_pos - int(Resources::normal_font->get_height()/2)),
00496                         ALIGN_CENTER, LAYER_GUI, inactive_color);
00497       break;
00498     }
00499 
00500     case MN_HL:
00501     {
00502       // TODO
00503       float x = pos.x - menu_width/2;
00504       float y = y_pos - 12;
00505       /* Draw a horizontal line with a little 3d effect */
00506       context.draw_filled_rect(Vector(x, y + 6),
00507                                Vector(menu_width, 4),
00508                                Color(0.6f, 0.7f, 1.0f, 1.0f), LAYER_GUI);
00509       context.draw_filled_rect(Vector(x, y + 6),
00510                                Vector(menu_width, 2),
00511                                Color(1.0f, 1.0f, 1.0f, 1.0f), LAYER_GUI);
00512       break;
00513     }
00514     case MN_LABEL:
00515     {
00516       context.draw_text(Resources::big_font, pitem.text,
00517                         Vector(pos.x, y_pos - int(Resources::big_font->get_height()/2)),
00518                         ALIGN_CENTER, LAYER_GUI, label_color);
00519       break;
00520     }
00521     case MN_TEXTFIELD:
00522     case MN_NUMFIELD:
00523     case MN_CONTROLFIELD:
00524     {
00525       if(pitem.kind == MN_TEXTFIELD || pitem.kind == MN_NUMFIELD)
00526       {
00527         if(active_item == index)
00528           context.draw_text(Resources::normal_font,
00529                             pitem.get_input_with_symbol(true),
00530                             Vector(right, y_pos - int(Resources::normal_font->get_height()/2)),
00531                             ALIGN_RIGHT, LAYER_GUI, field_color);
00532         else
00533           context.draw_text(Resources::normal_font,
00534                             pitem.get_input_with_symbol(false),
00535                             Vector(right, y_pos - int(Resources::normal_font->get_height()/2)),
00536                             ALIGN_RIGHT, LAYER_GUI, field_color);
00537       }
00538       else
00539         context.draw_text(Resources::normal_font, pitem.input,
00540                           Vector(right, y_pos - int(Resources::normal_font->get_height()/2)),
00541                           ALIGN_RIGHT, LAYER_GUI, field_color);
00542 
00543       context.draw_text(Resources::normal_font, pitem.text,
00544                         Vector(left, y_pos - int(Resources::normal_font->get_height()/2)),
00545                         ALIGN_LEFT, LAYER_GUI, text_color);
00546       break;
00547     }
00548     case MN_STRINGSELECT:
00549     {
00550       float roff = arrow_left->get_width();
00551       // Draw left side
00552       context.draw_text(Resources::normal_font, pitem.text,
00553                         Vector(left, y_pos - int(Resources::normal_font->get_height()/2)),
00554                         ALIGN_LEFT, LAYER_GUI, text_color);
00555 
00556       // Draw right side
00557       context.draw_surface(arrow_left,
00558                            Vector(right - list_width - roff - roff, y_pos - 8),
00559                            LAYER_GUI);
00560       context.draw_surface(arrow_right,
00561                            Vector(right - roff, y_pos - 8),
00562                            LAYER_GUI);
00563       context.draw_text(Resources::normal_font, pitem.list[pitem.selected],
00564                         Vector(right - roff, y_pos - int(Resources::normal_font->get_height()/2)),
00565                         ALIGN_RIGHT, LAYER_GUI, text_color);
00566       break;
00567     }
00568     case MN_BACK:
00569     {
00570       context.draw_text(Resources::Resources::normal_font, pitem.text,
00571                         Vector(pos.x, y_pos - int(Resources::normal_font->get_height()/2)),
00572                         ALIGN_CENTER, LAYER_GUI, text_color);
00573       context.draw_surface(back,
00574                            Vector(x_pos + text_width/2  + 16, y_pos - 8),
00575                            LAYER_GUI);
00576       break;
00577     }
00578 
00579     case MN_TOGGLE:
00580     {
00581       context.draw_text(Resources::normal_font, pitem.text,
00582                         Vector(pos.x - menu_width/2 + 16, y_pos - (Resources::normal_font->get_height()/2)),
00583                         ALIGN_LEFT, LAYER_GUI, text_color);
00584 
00585       if(pitem.toggled)
00586         context.draw_surface(checkbox_checked,
00587                              Vector(x_pos + (menu_width/2-16) - checkbox->get_width(), y_pos - 8),
00588                              LAYER_GUI + 1);
00589       else
00590         context.draw_surface(checkbox,
00591                              Vector(x_pos + (menu_width/2-16) - checkbox->get_width(), y_pos - 8),
00592                              LAYER_GUI + 1);
00593       break;
00594     }
00595     case MN_ACTION:
00596       context.draw_text(Resources::normal_font, pitem.text,
00597                         Vector(pos.x, y_pos - int(Resources::normal_font->get_height()/2)),
00598                         ALIGN_CENTER, LAYER_GUI, text_color);
00599       break;
00600 
00601     case MN_GOTO:
00602       context.draw_text(Resources::normal_font, pitem.text,
00603                         Vector(pos.x, y_pos - int(Resources::normal_font->get_height()/2)),
00604                         ALIGN_CENTER, LAYER_GUI, text_color);
00605       break;
00606   }
00607 }
00608 
00609 float
00610 Menu::get_width() const
00611 {
00612   /* The width of the menu has to be more than the width of the text
00613      with the most characters */
00614   float menu_width = 0;
00615   for(unsigned int i = 0; i < items.size(); ++i)
00616   {
00617     FontPtr font = Resources::Resources::normal_font;
00618     if(items[i]->kind == MN_LABEL)
00619       font = Resources::big_font;
00620 
00621     float w = font->get_text_width(items[i]->text) +
00622       Resources::big_font->get_text_width(items[i]->input) + 16;
00623     if(items[i]->kind == MN_TOGGLE)
00624       w += 32;
00625     if (items[i]->kind == MN_STRINGSELECT)
00626       w += font->get_text_width(items[i]->list[items[i]->selected]) + 32;
00627     
00628 
00629     if(w > menu_width)
00630       menu_width = w;
00631   }
00632 
00633   return menu_width + 24;
00634 }
00635 
00636 float
00637 Menu::get_height() const
00638 {
00639   return items.size() * 24;
00640 }
00641 
00642 /* Draw the current menu. */
00643 void
00644 Menu::draw(DrawingContext& context)
00645 {
00646   if(MouseCursor::current()) {
00647     MouseCursor::current()->draw(context);
00648   }
00649 
00650   float menu_width  = get_width();
00651   float menu_height = get_height();
00652 
00653   if (effect_progress != 1.0f)
00654   {
00655     if (close)
00656     {
00657       menu_width  = (MenuManager::current_->get_width()  * (1.0f - effect_progress));
00658       menu_height = (MenuManager::current_->get_height() * (1.0f - effect_progress));
00659     }
00660     else if (MenuManager::previous)
00661     {
00662       menu_width  = (menu_width  * effect_progress) + (MenuManager::previous->get_width()  * (1.0f - effect_progress));
00663       menu_height = (menu_height * effect_progress) + (MenuManager::previous->get_height() * (1.0f - effect_progress));
00664       //std::cout << effect_progress << " " << this << " " << last_menus.back() << std::endl;
00665     }
00666     else
00667     {
00668       menu_width  *= effect_progress;
00669       menu_height *= effect_progress;
00670     }
00671   }
00672 
00673   /* Draw a transparent background */
00674   context.draw_filled_rect(Rectf(Vector(pos.x - menu_width/2-4, pos.y - menu_height/2 - 10-4),
00675                                  Vector(pos.x + menu_width/2+4, pos.y - menu_height/2 + 10 + menu_height+4)),
00676                            Color(0.2f, 0.3f, 0.4f, 0.8f), 
00677                            20.0f,
00678                            LAYER_GUI-10);
00679 
00680   context.draw_filled_rect(Rectf(Vector(pos.x - menu_width/2, pos.y - menu_height/2 - 10),
00681                                  Vector(pos.x + menu_width/2, pos.y - menu_height/2 + 10 + menu_height)),
00682                            Color(0.6f, 0.7f, 0.8f, 0.5f), 
00683                            16.0f,
00684                            LAYER_GUI-10);
00685 
00686   if (!items[active_item]->help.empty())
00687   {
00688     int text_width  = (int) Resources::normal_font->get_text_width(items[active_item]->help);
00689     int text_height = (int) Resources::normal_font->get_text_height(items[active_item]->help);
00690       
00691     Rectf text_rect(pos.x - text_width/2 - 8, 
00692                    SCREEN_HEIGHT - 48 - text_height/2 - 4,
00693                    pos.x + text_width/2 + 8, 
00694                    SCREEN_HEIGHT - 48 + text_height/2 + 4);
00695         
00696     context.draw_filled_rect(Rectf(text_rect.p1 - Vector(4,4),
00697                                    text_rect.p2 + Vector(4,4)),
00698                              Color(0.2f, 0.3f, 0.4f, 0.8f), 
00699                              16.0f,
00700                              LAYER_GUI-10);
00701       
00702     context.draw_filled_rect(text_rect,
00703                              Color(0.6f, 0.7f, 0.8f, 0.5f), 
00704                              16.0f,
00705                              LAYER_GUI-10);
00706 
00707     context.draw_text(Resources::normal_font, items[active_item]->help,
00708                       Vector(pos.x, SCREEN_HEIGHT - 48 - text_height/2),
00709                       ALIGN_CENTER, LAYER_GUI);
00710   }
00711 
00712   if (effect_progress == 1.0f)
00713     for(unsigned int i = 0; i < items.size(); ++i)
00714     {
00715       draw_item(context, i);
00716     }
00717 }
00718 
00719 MenuItem&
00720 Menu::get_item_by_id(int id)
00721 {
00722   for(std::vector<MenuItem*>::iterator i = items.begin();
00723       i != items.end(); ++i) {
00724     MenuItem& item = **i;
00725 
00726     if(item.id == id)
00727       return item;
00728   }
00729 
00730   throw std::runtime_error("MenuItem not found");
00731 }
00732 
00733 const MenuItem&
00734 Menu::get_item_by_id(int id) const
00735 {
00736   for(std::vector<MenuItem*>::const_iterator i = items.begin();
00737       i != items.end(); ++i) {
00738     const MenuItem& item = **i;
00739 
00740     if(item.id == id)
00741       return item;
00742   }
00743 
00744   throw std::runtime_error("MenuItem not found");
00745 }
00746 
00747 int Menu::get_active_item_id()
00748 {
00749   return items[active_item]->id;
00750 }
00751 
00752 bool
00753 Menu::is_toggled(int id) const
00754 {
00755   return get_item_by_id(id).toggled;
00756 }
00757 
00758 void
00759 Menu::set_toggled(int id, bool toggled)
00760 {
00761   get_item_by_id(id).toggled = toggled;
00762 }
00763 
00764 Menu*
00765 Menu::get_parent() const
00766 {
00767   if (MenuManager::last_menus.empty())
00768     return 0;
00769   else
00770     return MenuManager::last_menus.back();
00771 }
00772 
00773 /* Check for menu event */
00774 void
00775 Menu::event(const SDL_Event& event)
00776 {
00777   if(effect_progress != 1.0f)
00778     return;
00779 
00780   switch(event.type) {
00781     case SDL_MOUSEBUTTONDOWN:
00782     {
00783       int x = int(event.motion.x * float(SCREEN_WIDTH)/g_screen->w);
00784       int y = int(event.motion.y * float(SCREEN_HEIGHT)/g_screen->h);
00785 
00786       if(x > pos.x - get_width()/2 &&
00787          x < pos.x + get_width()/2 &&
00788          y > pos.y - get_height()/2 &&
00789          y < pos.y + get_height()/2)
00790       {
00791         menuaction = MENU_ACTION_HIT;
00792       }
00793     }
00794     break;
00795 
00796     case SDL_MOUSEMOTION:
00797     {
00798       float x = event.motion.x * SCREEN_WIDTH/g_screen->w;
00799       float y = event.motion.y * SCREEN_HEIGHT/g_screen->h;
00800 
00801       if(x > pos.x - get_width()/2 &&
00802          x < pos.x + get_width()/2 &&
00803          y > pos.y - get_height()/2 &&
00804          y < pos.y + get_height()/2)
00805       {
00806         int new_active_item
00807           = static_cast<int> ((y - (pos.y - get_height()/2)) / 24);
00808 
00809         /* only change the mouse focus to a selectable item */
00810         if ((items[new_active_item]->kind != MN_HL)
00811             && (items[new_active_item]->kind != MN_LABEL)
00812             && (items[new_active_item]->kind != MN_INACTIVE))
00813           active_item = new_active_item;
00814 
00815         if(MouseCursor::current())
00816           MouseCursor::current()->set_state(MC_LINK);
00817       }
00818       else
00819       {
00820         if(MouseCursor::current())
00821           MouseCursor::current()->set_state(MC_NORMAL);
00822       }
00823     }
00824     break;
00825 
00826     default:
00827       break;
00828   }
00829 }
00830 
00831 void
00832 Menu::set_active_item(int id)
00833 {
00834   for(size_t i = 0; i < items.size(); ++i) {
00835     MenuItem* item = items[i];
00836     if(item->id == id) {
00837       active_item = i;
00838       break;
00839     }
00840   }
00841 }
00842 
00843 /* EOF */

Generated on Mon Jun 9 03:38:18 2014 for SuperTux by  doxygen 1.5.1