X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=lib%2Fgui%2Fmenu.cpp;h=ba7b749a69809c474612068673dc5bcd1ba1f032;hb=133d94d5b145f325c38c8c15c9ea561bfffb092d;hp=7e273d6656201ea47617c322a71606fb23c7c80b;hpb=6ed1900da4edf7d7922f7a4626f95a83e34dff82;p=supertux.git diff --git a/lib/gui/menu.cpp b/lib/gui/menu.cpp index 7e273d665..ba7b749a6 100644 --- a/lib/gui/menu.cpp +++ b/lib/gui/menu.cpp @@ -18,6 +18,8 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifndef WIN32 +#include + #include #include #endif @@ -29,14 +31,13 @@ #include #include -#include "../app/globals.h" -#include "../gui/menu.h" -#include "../video/screen.h" -#include "../video/drawing_context.h" -#include "../app/setup.h" -#include "../special/timer.h" -#include "../app/gettext.h" -#include "../math/vector.h" +#include "app/globals.h" +#include "menu.h" +#include "video/screen.h" +#include "video/drawing_context.h" +#include "app/setup.h" +#include "app/gettext.h" +#include "math/vector.h" using namespace SuperTux; @@ -152,15 +153,23 @@ Menu::set_current(Menu* menu) current_ = menu; } +MenuItem::MenuItem(MenuItemKind _kind, int _id) + : kind(_kind) , id(_id) +{ +} + +MenuItem::MenuItem(MenuItemKind _kind, int _id, const std::string& _text) + : kind(_kind) , id(_id) , text(_text) +{ +} + /* Return a pointer to a new menu item */ MenuItem* -MenuItem::create(MenuItemKind kind_, const char *text_, int init_toggle_, Menu* target_menu_, int id, int* int_p_) +MenuItem::create(MenuItemKind kind_, const std::string& text_, int init_toggle_, Menu* target_menu_, int id_, int* int_p_) { - MenuItem *pnew_item = new MenuItem; + MenuItem *pnew_item = new MenuItem(kind_,id_); - pnew_item->kind = kind_; - pnew_item->text = (char*) malloc(sizeof(char) * (strlen(text_) + 1)); - strcpy(pnew_item->text, text_); + pnew_item->text = text_; if(kind_ == MN_TOGGLE) pnew_item->toggled = init_toggle_; @@ -168,13 +177,10 @@ MenuItem::create(MenuItemKind kind_, const char *text_, int init_toggle_, Menu* pnew_item->toggled = false; pnew_item->target_menu = target_menu_; - pnew_item->input = (char*) malloc(sizeof(char)); - pnew_item->input[0] = '\0'; - pnew_item->id = id; pnew_item->int_p = int_p_; - - pnew_item->list.second = 0; + + pnew_item->selected = 0; pnew_item->input_flickering = false; pnew_item->input_flickering_timer.init(true); @@ -184,25 +190,15 @@ MenuItem::create(MenuItemKind kind_, const char *text_, int init_toggle_, Menu* } void -MenuItem::change_text(const char *text_) +MenuItem::change_text(const std::string& text_) { - if (text_) - { - free(text); - text = (char*) malloc(sizeof(char )*(strlen(text_)+1)); - strcpy(text, text_); - } + text = text_; } void -MenuItem::change_input(const char *text_) +MenuItem::change_input(const std::string& text_) { - if(text) - { - free(input); - input = (char*) malloc(sizeof(char )*(strlen(text_)+1)); - strcpy(input, text_); - } + input = text_; } std::string MenuItem::get_input_with_symbol(bool active_item) @@ -223,9 +219,9 @@ std::string MenuItem::get_input_with_symbol(bool active_item) char str[1024]; if(input_flickering) - sprintf(str,"%s ",input); + sprintf(str,"%s ",input.c_str()); else - sprintf(str,"%s_",input); + sprintf(str,"%s_",input.c_str()); std::string string = str; @@ -291,21 +287,10 @@ void Menu::get_controlfield_js_into_input(MenuItem *item) item->change_input(oss.str().c_str()); } -/* Free a menu and all its items */ Menu::~Menu() { - if(item.size() != 0) - { - for(unsigned int i = 0; i < item.size(); ++i) - { - free(item[i].text); - free(item[i].input); - item[i].list.first.clear(); - } - } } - Menu::Menu() { hit_item = -1; @@ -332,6 +317,15 @@ void Menu::additem(MenuItemKind kind_, const std::string& text_, int toggle_, Menu* menu_, int id, int* int_p) { additem(MenuItem::create(kind_, text_.c_str(), toggle_, menu_, id, int_p)); + + /* If a new menu is being built, the active item shouldn't be set to something + that isnt selectable. Keep setting the active item to the most recently + added item until a selectable entry is found. + */ + if (item[active_item].kind == MN_HL + || item[active_item].kind == MN_LABEL + || item[active_item].kind == MN_DEACTIVE) + active_item = item.size() - 1; } /* Add an item to a menu */ @@ -342,10 +336,18 @@ Menu::additem(MenuItem* pmenu_item) delete pmenu_item; } +/* Add an item to a menu */ +void +Menu::additem(const MenuItem& pmenu_item) +{ + item.push_back(pmenu_item); +} + void Menu::clear() { item.clear(); + active_item = 0; } /* Process actions done on the menu */ @@ -355,42 +357,51 @@ Menu::action() hit_item = -1; if(item.size() != 0) { + int last_active_item = active_item; switch(menuaction) { case MENU_ACTION_UP: - if (active_item > 0) - --active_item; - else - active_item = int(item.size())-1; + do { + if (active_item > 0) + --active_item; + else + active_item = int(item.size())-1; + } while ((item[active_item].kind == MN_HL + || item[active_item].kind == MN_LABEL + || item[active_item].kind == MN_DEACTIVE) + && (active_item != last_active_item)); + break; case MENU_ACTION_DOWN: - if(active_item < int(item.size())-1) - ++active_item; - else - active_item = 0; + do { + if(active_item < int(item.size())-1 ) + ++active_item; + else + active_item = 0; + } while ((item[active_item].kind == MN_HL + || item[active_item].kind == MN_LABEL + || item[active_item].kind == MN_DEACTIVE) + && (active_item != last_active_item)); + break; case MENU_ACTION_LEFT: - if(item[active_item].kind == MN_STRINGSELECT - && item[active_item].list.first.size() != 0) - { - if(item[active_item].list.second != item[active_item].list.first.begin()) - --item[active_item].list.second; - else - item[active_item].list.second = item[active_item].list.first.end(); - } + if(item[active_item].kind == MN_STRINGSELECT) { + if(item[active_item].selected > 0) + item[active_item].selected--; + else + item[active_item].selected = item[active_item].list.size()-1; + } break; case MENU_ACTION_RIGHT: - if(item[active_item].kind == MN_STRINGSELECT - && item[active_item].list.first.size() != 0) - { - if(item[active_item].list.second != item[active_item].list.first.end()) - ++item[active_item].list.second; - else - item[active_item].list.second = item[active_item].list.first.begin(); - } + if(item[active_item].kind == MN_STRINGSELECT) { + if(item[active_item].selected+1 < item[active_item].list.size()) + item[active_item].selected++; + else + item[active_item].selected = 0; + } break; case MENU_ACTION_HIT: @@ -432,13 +443,13 @@ Menu::action() if(item[active_item].kind == MN_TEXTFIELD || item[active_item].kind == MN_NUMFIELD) { - if(item[active_item].input != NULL) + if(!item[active_item].input.empty()) { - int i = strlen(item[active_item].input); + int i = item[active_item].input.size(); while(delete_character > 0) /* remove charactes */ { - item[active_item].input[i-1] = '\0'; + item[active_item].input.resize(i-1); delete_character--; } } @@ -449,19 +460,7 @@ Menu::action() if(item[active_item].kind == MN_TEXTFIELD || (item[active_item].kind == MN_NUMFIELD && mn_input_char >= '0' && mn_input_char <= '9')) { - if(item[active_item].input != NULL) - { - int i = strlen(item[active_item].input); - item[active_item].input = (char*) realloc(item[active_item].input,sizeof(char)*(i + 2)); - item[active_item].input[i] = mn_input_char; - item[active_item].input[i+1] = '\0'; - } - else - { - item[active_item].input = (char*) malloc(2*sizeof(char)); - item[active_item].input[0] = mn_input_char; - item[active_item].input[1] = '\0'; - } + item[active_item].input.push_back(mn_input_char); } case MENU_ACTION_NONE: @@ -469,18 +468,6 @@ Menu::action() } } - MenuItem& new_item = item[active_item]; - if(new_item.kind == MN_DEACTIVE - || new_item.kind == MN_LABEL - || new_item.kind == MN_HL) - { - // Skip the horzontal line item - if (menuaction != MENU_ACTION_UP && menuaction != MENU_ACTION_DOWN) - menuaction = MENU_ACTION_DOWN; - - if (item.size() > 1) - action(); - } menuaction = MENU_ACTION_NONE; @@ -521,8 +508,9 @@ Menu::draw_item(DrawingContext& context, int text_width = int(text_font->get_text_width(pitem.text)); int input_width = int(text_font->get_text_width(pitem.input) + 10); int list_width = 0; - if(pitem.list.second != 0) - list_width = int(text_font->get_text_width((*pitem.list.second))); + if(pitem.list.size() > 0) { + list_width = (int) text_font->get_text_width(pitem.list[pitem.selected]); + } if (arrange_left) x_pos += 24 - menu_width/2 + (text_width + input_width + list_width)/2; @@ -537,9 +525,9 @@ Menu::draw_item(DrawingContext& context, { case MN_DEACTIVE: { - context.draw_text_center(deactive_font, pitem.text, - Vector(0, y_pos - int(deactive_font->get_height()/2)), - LAYER_GUI); + context.draw_text(deactive_font, pitem.text, + Vector(screen->w/2, y_pos - int(deactive_font->get_height()/2)), + CENTER_ALLIGN, LAYER_GUI); break; } @@ -557,9 +545,9 @@ Menu::draw_item(DrawingContext& context, } case MN_LABEL: { - context.draw_text_center(label_font, - pitem.text, Vector(0, y_pos - int(label_font->get_height()/2)), - LAYER_GUI); + context.draw_text(label_font, pitem.text, + Vector(screen->w/2, y_pos - int(label_font->get_height()/2)), + CENTER_ALLIGN, LAYER_GUI); break; } case MN_TEXTFIELD: @@ -591,21 +579,21 @@ Menu::draw_item(DrawingContext& context, context.draw_text(field_font, pitem.get_input_with_symbol(true), Vector(input_pos, y_pos - int(field_font->get_height()/2)), - LAYER_GUI); + LEFT_ALLIGN, LAYER_GUI); else context.draw_text(field_font, pitem.get_input_with_symbol(false), Vector(input_pos, y_pos - int(field_font->get_height()/2)), - LAYER_GUI); + LEFT_ALLIGN, LAYER_GUI); } else context.draw_text(field_font, pitem.input, Vector(input_pos, y_pos - int(field_font->get_height()/2)), - LAYER_GUI); + LEFT_ALLIGN, LAYER_GUI); context.draw_text(text_font, pitem.text, Vector(text_pos, y_pos - int(text_font->get_height()/2)), - LAYER_GUI); + LEFT_ALLIGN, LAYER_GUI); break; } case MN_STRINGSELECT: @@ -632,19 +620,19 @@ Menu::draw_item(DrawingContext& context, Vector(list_pos_2, 18), Color(0,0,0,128), LAYER_GUI - 5); - context.draw_text_center(text_font, (*pitem.list.second), - Vector(text_pos, y_pos - int(text_font->get_height()/2)), - LAYER_GUI); - context.draw_text_center(text_font, pitem.text, - Vector(list_pos_2/2, y_pos - int(text_font->get_height()/2)), - LAYER_GUI); + context.draw_text(text_font, pitem.list[pitem.selected], + Vector(screen->w/2 + text_pos, y_pos - int(text_font->get_height()/2)), + CENTER_ALLIGN, LAYER_GUI); + context.draw_text(text_font, pitem.text, + Vector(screen->w/2 + list_pos_2/2, y_pos - int(text_font->get_height()/2)), + CENTER_ALLIGN, LAYER_GUI); break; } case MN_BACK: { - context.draw_text_center(text_font, pitem.text, - Vector(0, y_pos - int(text_font->get_height()/2)), - LAYER_GUI); + context.draw_text(text_font, pitem.text, + Vector(screen->w/2, y_pos - int(text_font->get_height()/2)), + CENTER_ALLIGN, LAYER_GUI); context.draw_surface(back, Vector(x_pos + text_width/2 + 16, y_pos - 8), LAYER_GUI); @@ -653,9 +641,9 @@ Menu::draw_item(DrawingContext& context, case MN_TOGGLE: { - context.draw_text_center(text_font, pitem.text, - Vector(0, y_pos - (text_font->get_height()/2)), - LAYER_GUI); + context.draw_text(text_font, pitem.text, + Vector(screen->w/2, y_pos - (text_font->get_height()/2)), + CENTER_ALLIGN, LAYER_GUI); if(pitem.toggled) context.draw_surface(checkbox_checked, @@ -668,15 +656,15 @@ Menu::draw_item(DrawingContext& context, break; } case MN_ACTION: - context.draw_text_center(text_font, pitem.text, - Vector(0, y_pos - int(text_font->get_height()/2)), - LAYER_GUI); + context.draw_text(text_font, pitem.text, + Vector(screen->w/2, y_pos - int(text_font->get_height()/2)), + CENTER_ALLIGN, LAYER_GUI); break; case MN_GOTO: - context.draw_text_center(text_font, pitem.text, - Vector(0, y_pos - int(text_font->get_height()/2)), - LAYER_GUI); + context.draw_text(text_font, pitem.text, + Vector(screen->w/2, y_pos - int(text_font->get_height()/2)), + CENTER_ALLIGN, LAYER_GUI); break; } } @@ -688,7 +676,7 @@ int Menu::get_width() const int menu_width = 0; for(unsigned int i = 0; i < item.size(); ++i) { - int w = strlen(item[i].text) + (item[i].input ? strlen(item[i].input) + 1 : 0); //+ ((item[i].list.second != item[i].list.first.end()) ? (strlen((*(item[i].list.second)).c_str())) : 0); + int w = item[i].text.size() + item[i].input.size() + 1; if( w > menu_width ) { menu_width = w; @@ -775,7 +763,7 @@ Menu::event(SDL_Event& event) /* An International Character. */ } - if(item[active_item].kind == MN_CONTROLFIELD_KB) + if(item.size() > 0 && item[active_item].kind == MN_CONTROLFIELD_KB) { if(key == SDLK_ESCAPE) { @@ -803,7 +791,7 @@ Menu::event(SDL_Event& event) menuaction = MENU_ACTION_RIGHT; break; case SDLK_SPACE: - if(item[active_item].kind == MN_TEXTFIELD) + if(item.size() > 0 && item[active_item].kind == MN_TEXTFIELD) { menuaction = MENU_ACTION_INPUT; mn_input_char = ' '; @@ -852,8 +840,15 @@ Menu::event(SDL_Event& event) joystick_timer.stop(); } break; + case SDL_JOYHATMOTION: + if(event.jhat.value & SDL_HAT_UP) { + menuaction = MENU_ACTION_UP; + } else if(event.jhat.value & SDL_HAT_DOWN) { + menuaction = MENU_ACTION_DOWN; + } + break; case SDL_JOYBUTTONDOWN: - if (item[active_item].kind == MN_CONTROLFIELD_JS) + if (item.size() > 0 && item[active_item].kind == MN_CONTROLFIELD_JS) { // FIXME: This next line does nothing useable, right? // *item[active_item].int_p = key; @@ -887,14 +882,21 @@ Menu::event(SDL_Event& event) y > pos_y - get_height()/2 && y < pos_y + get_height()/2) { - active_item = (y - (pos_y - get_height()/2)) / 24; - if(MouseCursor::current()) - MouseCursor::current()->set_state(MC_LINK); + int new_active_item = (y - (pos_y - get_height()/2)) / 24; + + /* only change the mouse focus to a selectable item */ + if ((item[new_active_item].kind != MN_HL) + && (item[new_active_item].kind != MN_LABEL) + && (item[new_active_item].kind != MN_DEACTIVE)) + active_item = new_active_item; + + if(MouseCursor::current()) + MouseCursor::current()->set_state(MC_LINK); } else { - if(MouseCursor::current()) - MouseCursor::current()->set_state(MC_NORMAL); + if(MouseCursor::current()) + MouseCursor::current()->set_state(MC_NORMAL); } } break; @@ -904,5 +906,3 @@ Menu::event(SDL_Event& event) } } - -// EOF //