X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fgui%2Fmenu.cpp;h=cc062a08af63139d45f386a7beb6b6d89f2dbb5a;hb=ba5f95533903ed6190b0fddede258c86540afffa;hp=49ebd64bb8f59e259a3acdfccdcb5c76d3b4153e;hpb=45a538e3407dcfa7a9fd8beace9dbd06b8d993a3;p=supertux.git diff --git a/src/gui/menu.cpp b/src/gui/menu.cpp index 49ebd64bb..cc062a08a 100644 --- a/src/gui/menu.cpp +++ b/src/gui/menu.cpp @@ -42,26 +42,22 @@ #include "control/joystickkeyboardcontroller.hpp" static const float MENU_REPEAT_INITIAL = 0.4f; -static const float MENU_REPEAT_RATE = 0.2f; -static const float FLICK_CURSOR_TIME = 0.5f; +static const float MENU_REPEAT_RATE = 0.1f; +static const float FLICK_CURSOR_TIME = 0.5f; extern SDL_Surface* screen; std::vector Menu::last_menus; +std::list Menu::all_menus; Menu* Menu::current_ = 0; Menu* Menu::previous = 0; -Font* Menu::default_font; -Font* Menu::active_font; -Font* Menu::deactive_font; -Font* Menu::label_font; -Font* Menu::field_font; /* just displays a Yes/No text that can be used to confirm stuff */ bool confirm_dialog(Surface *background, std::string text) { //Surface* cap_screen = Surface::CaptureScreen(); Menu* dialog = new Menu; - dialog->add_deactive(-1, text); + dialog->add_inactive(-1, text); dialog->add_hl(); dialog->add_entry(true, _("Yes")); dialog->add_entry(false, _("No")); @@ -116,7 +112,7 @@ bool confirm_dialog(Surface *background, std::string text) return false; } - + void Menu::push_current(Menu* pmenu) { @@ -141,27 +137,47 @@ Menu::pop_current() current_->effect_progress = 0.0f; last_menus.pop_back(); } else { - current_ = 0; + set_current(NULL); } } void Menu::set_current(Menu* menu) { + if (current_ && current_->close == true) + return; + previous = current_; - last_menus.clear(); + if (menu) { + menu->effect_start_time = real_time; + menu->effect_progress = 0.0f; + current_ = menu; + } + else if (current_) { + last_menus.clear(); //NULL new menu pointer => close all menus + current_->effect_start_time = real_time; + current_->effect_progress = 0.0f; + current_->close = true; + } - if (menu) - { - menu->effect_start_time = real_time; - menu->effect_progress = 0.0f; - } - current_ = menu; // just to be sure... main_controller->reset(); } - + +void +Menu::recalc_pos() +{ + if (current_) + current_->set_pos(SCREEN_WIDTH/2, SCREEN_HEIGHT/2); + + for(std::list::iterator i = all_menus.begin(); i != all_menus.end(); ++i) + { + // FIXME: This is of course not quite right, since it ignores any previous set_pos() calls + (*i)->set_pos(SCREEN_WIDTH/2, SCREEN_HEIGHT/2); + } +} + MenuItem::MenuItem(MenuItemKind _kind, int _id) : kind(_kind) , id(_id) { @@ -182,6 +198,18 @@ MenuItem::change_input(const std::string& text_) input = text_; } +void +MenuItem::set_help(const std::string& help_text) +{ + std::string overflow; + help = normal_font->wrap_to_width(help_text, 600, &overflow); + while (!overflow.empty()) + { + help += "\n"; + help += normal_font->wrap_to_width(overflow, 600, &overflow); + } +} + std::string MenuItem::get_input_with_symbol(bool active_item) { if(!active_item) { @@ -200,18 +228,27 @@ std::string MenuItem::get_input_with_symbol(bool active_item) return string; } - + Menu::~Menu() { + all_menus.remove(this); + for(std::vector::iterator i = items.begin(); i != items.end(); ++i) delete *i; + if(current_ == this) current_ = NULL; + + if (previous == this) + previous = NULL; } Menu::Menu() + : close(false) { + all_menus.push_back(this); + hit_item = -1; menuaction = MENU_ACTION_NONE; delete_character = 0; @@ -235,7 +272,7 @@ Menu::Menu() void Menu::set_pos(float x, float y, float rw, float rh) { - pos_x = x + get_width() * rw; + pos_x = x + get_width() * rw; pos_y = y + get_height() * rh; } @@ -246,81 +283,99 @@ Menu::additem(MenuItem* item) items.push_back(item); /* If a new menu is being built, the active item shouldn't be set to - * something that isnt selectable. Set the active_item to the first - * selectable item added + * something that isn't selectable. Set the active_item to the first + * selectable item added. */ if (active_item == -1 && item->kind != MN_HL && item->kind != MN_LABEL - && item->kind != MN_DEACTIVE) { + && item->kind != MN_INACTIVE) { active_item = items.size() - 1; } } -void +MenuItem* Menu::add_hl() { - additem(new MenuItem(MN_HL)); + MenuItem* item = new MenuItem(MN_HL); + additem(item); + return item; } -void +MenuItem* Menu::add_label(const std::string& text) { MenuItem* item = new MenuItem(MN_LABEL); item->text = text; additem(item); + return item; } -void +MenuItem* Menu::add_controlfield(int id, const std::string& text, - const std::string& mapping) + const std::string& mapping) { MenuItem* item = new MenuItem(MN_CONTROLFIELD, id); item->change_text(text); - item->change_input(mapping); + item->change_input(mapping); additem(item); + return item; } -void +MenuItem* Menu::add_entry(int id, const std::string& text) { MenuItem* item = new MenuItem(MN_ACTION, id); item->text = text; additem(item); + return item; } -void -Menu::add_deactive(int id, const std::string& text) +MenuItem* +Menu::add_inactive(int id, const std::string& text) { - MenuItem* item = new MenuItem(MN_DEACTIVE, id); + MenuItem* item = new MenuItem(MN_INACTIVE, id); item->text = text; additem(item); + return item; } -void +MenuItem* Menu::add_toggle(int id, const std::string& text, bool toogled) { MenuItem* item = new MenuItem(MN_TOGGLE, id); item->text = text; item->toggled = toogled; additem(item); + return item; } -void +MenuItem* +Menu::add_string_select(int id, const std::string& text) +{ + MenuItem* item = new MenuItem(MN_STRINGSELECT, id); + item->text = text; + additem(item); + return item; +} + +MenuItem* Menu::add_back(const std::string& text) { MenuItem* item = new MenuItem(MN_BACK); item->text = text; additem(item); + return item; } -void +MenuItem* Menu::add_submenu(const std::string& text, Menu* submenu, int id) { MenuItem* item = new MenuItem(MN_GOTO, id); item->text = text; item->target_menu = submenu; additem(item); + return item; } void @@ -338,11 +393,24 @@ Menu::clear() void Menu::update() { + int menu_height = (int) get_height(); + if (menu_height > SCREEN_HEIGHT) + { // Scrolling + int scroll_offset = (menu_height - SCREEN_HEIGHT) / 2 + 32; + pos_y = SCREEN_HEIGHT/2 - scroll_offset * ((float(active_item) / (items.size()-1)) - 0.5f) * 2.0f; + } + effect_progress = (real_time - effect_start_time) * 6.0f; if(effect_progress >= 1.0f) { effect_progress = 1.0f; - } else if (effect_progress <= 0.0f) { + + if (close) { + current_ = 0; + close = false; + } + } + else if (effect_progress <= 0.0f) { effect_progress = 0.0f; } @@ -356,6 +424,7 @@ Menu::update() menuaction = MENU_ACTION_UP; menu_repeat_time = real_time + MENU_REPEAT_RATE; } + if(main_controller->pressed(Controller::DOWN)) { menuaction = MENU_ACTION_DOWN; menu_repeat_time = real_time + MENU_REPEAT_INITIAL; @@ -365,6 +434,27 @@ Menu::update() menuaction = MENU_ACTION_DOWN; menu_repeat_time = real_time + MENU_REPEAT_RATE; } + + if(main_controller->pressed(Controller::LEFT)) { + menuaction = MENU_ACTION_LEFT; + menu_repeat_time = real_time + MENU_REPEAT_INITIAL; + } + if(main_controller->hold(Controller::LEFT) && + menu_repeat_time != 0 && real_time > menu_repeat_time) { + menuaction = MENU_ACTION_LEFT; + menu_repeat_time = real_time + MENU_REPEAT_RATE; + } + + if(main_controller->pressed(Controller::RIGHT)) { + menuaction = MENU_ACTION_RIGHT; + menu_repeat_time = real_time + MENU_REPEAT_INITIAL; + } + if(main_controller->hold(Controller::RIGHT) && + menu_repeat_time != 0 && real_time > menu_repeat_time) { + menuaction = MENU_ACTION_RIGHT; + menu_repeat_time = real_time + MENU_REPEAT_RATE; + } + if(main_controller->pressed(Controller::ACTION) || main_controller->pressed(Controller::MENU_SELECT)) { menuaction = MENU_ACTION_HIT; @@ -387,7 +477,7 @@ Menu::update() active_item = int(items.size())-1; } while ((items[active_item]->kind == MN_HL || items[active_item]->kind == MN_LABEL - || items[active_item]->kind == MN_DEACTIVE) + || items[active_item]->kind == MN_INACTIVE) && (active_item != last_active_item)); break; @@ -400,7 +490,7 @@ Menu::update() active_item = 0; } while ((items[active_item]->kind == MN_HL || items[active_item]->kind == MN_LABEL - || items[active_item]->kind == MN_DEACTIVE) + || items[active_item]->kind == MN_INACTIVE) && (active_item != last_active_item)); break; @@ -411,6 +501,8 @@ Menu::update() items[active_item]->selected--; else items[active_item]->selected = items[active_item]->list.size()-1; + + menu_action(items[active_item]); } break; @@ -420,6 +512,8 @@ Menu::update() items[active_item]->selected++; else items[active_item]->selected = 0; + + menu_action(items[active_item]); } break; @@ -444,6 +538,15 @@ Menu::update() menu_action(items[active_item]); break; + case MN_STRINGSELECT: + if(items[active_item]->selected+1 < items[active_item]->list.size()) + items[active_item]->selected++; + else + items[active_item]->selected = 0; + + menu_action(items[active_item]); + break; + case MN_TEXTFIELD: case MN_NUMFIELD: menuaction = MENU_ACTION_DOWN; @@ -467,7 +570,7 @@ Menu::update() { int i = items[active_item]->input.size(); - while(delete_character > 0) /* remove charactes */ + while(delete_character > 0) /* remove characters */ { items[active_item]->input.resize(i-1); delete_character--; @@ -518,15 +621,19 @@ Menu::draw_item(DrawingContext& context, int index) MenuItem& pitem = *(items[index]); - Font* text_font = default_font; + Color text_color = default_color; float x_pos = pos_x; float y_pos = pos_y + 24*index - menu_height/2 + 12; int shadow_size = 2; - int text_width = int(text_font->get_text_width(pitem.text)); - int input_width = int(text_font->get_text_width(pitem.input) + 10); + int text_width = int(normal_font->get_text_width(pitem.text)); + int input_width = int(normal_font->get_text_width(pitem.input) + 10); int list_width = 0; + + float left = pos_x - menu_width/2 + 16; + float right = pos_x + menu_width/2 - 16; + if(pitem.list.size() > 0) { - list_width = (int) text_font->get_text_width(pitem.list[pitem.selected]); + list_width = (int) normal_font->get_text_width(pitem.list[pitem.selected]); } if (arrange_left) @@ -535,7 +642,7 @@ Menu::draw_item(DrawingContext& context, int index) if(index == active_item) { shadow_size = 3; - text_font = active_font; + text_color = active_color; } if(active_item == index) @@ -555,11 +662,11 @@ Menu::draw_item(DrawingContext& context, int index) switch (pitem.kind) { - case MN_DEACTIVE: + case MN_INACTIVE: { - context.draw_text(deactive_font, pitem.text, - Vector(SCREEN_WIDTH/2, y_pos - int(deactive_font->get_height()/2)), - ALIGN_CENTER, LAYER_GUI); + context.draw_text(normal_font, pitem.text, + Vector(pos_x, y_pos - int(normal_font->get_height()/2)), + ALIGN_CENTER, LAYER_GUI, inactive_color); break; } @@ -579,78 +686,63 @@ Menu::draw_item(DrawingContext& context, int index) } case MN_LABEL: { - context.draw_text(label_font, pitem.text, - Vector(SCREEN_WIDTH/2, y_pos - int(label_font->get_height()/2)), - ALIGN_CENTER, LAYER_GUI); + context.draw_text(big_font, pitem.text, + Vector(pos_x, y_pos - int(big_font->get_height()/2)), + ALIGN_CENTER, LAYER_GUI, label_color); break; } case MN_TEXTFIELD: case MN_NUMFIELD: case MN_CONTROLFIELD: { - float left = SCREEN_WIDTH/2 - menu_width/2 + 16; - float right = SCREEN_WIDTH/2 + menu_width/2 - 16; - if(pitem.kind == MN_TEXTFIELD || pitem.kind == MN_NUMFIELD) { if(active_item == index) - context.draw_text(field_font, + context.draw_text(normal_font, pitem.get_input_with_symbol(true), - Vector(right, y_pos - int(field_font->get_height()/2)), - ALIGN_RIGHT, LAYER_GUI); + Vector(right, y_pos - int(normal_font->get_height()/2)), + ALIGN_RIGHT, LAYER_GUI, field_color); else - context.draw_text(field_font, + context.draw_text(normal_font, pitem.get_input_with_symbol(false), - Vector(right, y_pos - int(field_font->get_height()/2)), - ALIGN_RIGHT, LAYER_GUI); + Vector(right, y_pos - int(normal_font->get_height()/2)), + ALIGN_RIGHT, LAYER_GUI, field_color); } else - context.draw_text(field_font, pitem.input, - Vector(right, y_pos - int(field_font->get_height()/2)), - ALIGN_RIGHT, LAYER_GUI); + context.draw_text(normal_font, pitem.input, + Vector(right, y_pos - int(normal_font->get_height()/2)), + ALIGN_RIGHT, LAYER_GUI, field_color); - context.draw_text(text_font, pitem.text, - Vector(left, y_pos - int(text_font->get_height()/2)), - ALIGN_LEFT, LAYER_GUI); + context.draw_text(normal_font, pitem.text, + Vector(left, y_pos - int(normal_font->get_height()/2)), + ALIGN_LEFT, LAYER_GUI, text_color); break; } case MN_STRINGSELECT: { - int list_pos_2 = list_width + 16; - int list_pos = list_width/2; - int text_pos = (text_width + 16)/2; + float roff = arrow_left->get_width(); + // Draw left side + context.draw_text(normal_font, pitem.text, + Vector(left, y_pos - int(normal_font->get_height()/2)), + ALIGN_LEFT, LAYER_GUI, text_color); - /* Draw arrows */ + // Draw right side context.draw_surface(arrow_left.get(), - Vector(x_pos - list_pos + text_pos - 17, y_pos - 8), + Vector(right - list_width - roff - roff, y_pos - 8), LAYER_GUI); context.draw_surface(arrow_right.get(), - Vector(x_pos - list_pos + text_pos - 1 + list_pos_2, y_pos - 8), + Vector(right - roff, y_pos - 8), LAYER_GUI); - - /* Draw input background */ - context.draw_filled_rect( - Vector(x_pos - list_pos + text_pos - 1, y_pos - 10), - Vector(list_pos_2 + 2, 20), - Color(1.0f, 1.0f, 1.0f, 1.0f), LAYER_GUI - 4); - context.draw_filled_rect( - Vector(x_pos - list_pos + text_pos, y_pos - 9), - Vector(list_pos_2, 18), - Color(0, 0, 0, 0.5f), LAYER_GUI - 5); - - context.draw_text(text_font, pitem.list[pitem.selected], - Vector(SCREEN_WIDTH/2 + text_pos, y_pos - int(text_font->get_height()/2)), - ALIGN_CENTER, LAYER_GUI); - context.draw_text(text_font, pitem.text, - Vector(SCREEN_WIDTH/2 + list_pos_2/2, y_pos - int(text_font->get_height()/2)), - ALIGN_CENTER, LAYER_GUI); + context.draw_text(normal_font, pitem.list[pitem.selected], + Vector(right - roff, y_pos - int(normal_font->get_height()/2)), + ALIGN_RIGHT, LAYER_GUI, text_color); break; } case MN_BACK: { - context.draw_text(text_font, pitem.text, - Vector(SCREEN_WIDTH/2, y_pos - int(text_font->get_height()/2)), - ALIGN_CENTER, LAYER_GUI); + context.draw_text(normal_font, pitem.text, + Vector(pos_x, y_pos - int(normal_font->get_height()/2)), + ALIGN_CENTER, LAYER_GUI, text_color); context.draw_surface(back.get(), Vector(x_pos + text_width/2 + 16, y_pos - 8), LAYER_GUI); @@ -659,9 +751,9 @@ Menu::draw_item(DrawingContext& context, int index) case MN_TOGGLE: { - context.draw_text(text_font, pitem.text, - Vector(SCREEN_WIDTH/2 - menu_width/2 + 16, y_pos - (text_font->get_height()/2)), - ALIGN_LEFT, LAYER_GUI); + context.draw_text(normal_font, pitem.text, + Vector(pos_x - menu_width/2 + 16, y_pos - (normal_font->get_height()/2)), + ALIGN_LEFT, LAYER_GUI, text_color); if(pitem.toggled) context.draw_surface(checkbox_checked.get(), @@ -674,15 +766,15 @@ Menu::draw_item(DrawingContext& context, int index) break; } case MN_ACTION: - context.draw_text(text_font, pitem.text, - Vector(SCREEN_WIDTH/2, y_pos - int(text_font->get_height()/2)), - ALIGN_CENTER, LAYER_GUI); + context.draw_text(normal_font, pitem.text, + Vector(pos_x, y_pos - int(normal_font->get_height()/2)), + ALIGN_CENTER, LAYER_GUI, text_color); break; case MN_GOTO: - context.draw_text(text_font, pitem.text, - Vector(SCREEN_WIDTH/2, y_pos - int(text_font->get_height()/2)), - ALIGN_CENTER, LAYER_GUI); + context.draw_text(normal_font, pitem.text, + Vector(pos_x, y_pos - int(normal_font->get_height()/2)), + ALIGN_CENTER, LAYER_GUI, text_color); break; } } @@ -695,12 +787,12 @@ Menu::get_width() const float menu_width = 0; for(unsigned int i = 0; i < items.size(); ++i) { - Font* font = default_font; + Font* font = normal_font; if(items[i]->kind == MN_LABEL) - font = label_font; + font = big_font; float w = font->get_text_width(items[i]->text) + - label_font->get_text_width(items[i]->input) + 16; + big_font->get_text_width(items[i]->input) + 16; if(items[i]->kind == MN_TOGGLE) w += 32; @@ -730,17 +822,22 @@ Menu::draw(DrawingContext& context) if (effect_progress != 1.0f) { - if (Menu::previous) - { - menu_width = (menu_width * effect_progress) + (Menu::previous->get_width() * (1.0f - effect_progress)); - menu_height = (menu_height * effect_progress) + (Menu::previous->get_height() * (1.0f - effect_progress)); - //std::cout << effect_progress << " " << this << " " << last_menus.back() << std::endl; - } - else - { - menu_width *= effect_progress; - menu_height *= effect_progress; - } + if (close) + { + menu_width = (current_->get_width() * (1.0f - effect_progress)); + menu_height = (current_->get_height() * (1.0f - effect_progress)); + } + else if (Menu::previous) + { + menu_width = (menu_width * effect_progress) + (Menu::previous->get_width() * (1.0f - effect_progress)); + menu_height = (menu_height * effect_progress) + (Menu::previous->get_height() * (1.0f - effect_progress)); + //std::cout << effect_progress << " " << this << " " << last_menus.back() << std::endl; + } + else + { + menu_width *= effect_progress; + menu_height *= effect_progress; + } } /* Draw a transparent background */ @@ -756,6 +853,32 @@ Menu::draw(DrawingContext& context) 16.0f, LAYER_GUI-10); + if (!items[active_item]->help.empty()) + { + int text_width = (int) normal_font->get_text_width(items[active_item]->help); + int text_height = (int) normal_font->get_text_height(items[active_item]->help); + + Rect text_rect(pos_x - text_width/2 - 8, + SCREEN_HEIGHT - 48 - text_height/2 - 4, + pos_x + text_width/2 + 8, + SCREEN_HEIGHT - 48 + text_height/2 + 4); + + context.draw_filled_rect(Rect(text_rect.p1 - Vector(4,4), + text_rect.p2 + Vector(4,4)), + Color(0.2f, 0.3f, 0.4f, 0.8f), + 16.0f, + LAYER_GUI-10); + + context.draw_filled_rect(text_rect, + Color(0.6f, 0.7f, 0.8f, 0.5f), + 16.0f, + LAYER_GUI-10); + + context.draw_text(normal_font, items[active_item]->help, + Vector(pos_x, SCREEN_HEIGHT - 48 - text_height/2), + ALIGN_CENTER, LAYER_GUI); + } + if (effect_progress == 1.0f) for(unsigned int i = 0; i < items.size(); ++i) { @@ -802,6 +925,21 @@ Menu::is_toggled(int id) const return get_item_by_id(id).toggled; } +void +Menu::set_toggled(int id, bool toggled) +{ + get_item_by_id(id).toggled = toggled; +} + +Menu* +Menu::get_parent() const +{ + if (last_menus.empty()) + return 0; + else + return last_menus.back(); +} + /* Check for menu event */ void Menu::event(const SDL_Event& event) @@ -841,7 +979,7 @@ Menu::event(const SDL_Event& event) /* only change the mouse focus to a selectable item */ if ((items[new_active_item]->kind != MN_HL) && (items[new_active_item]->kind != MN_LABEL) - && (items[new_active_item]->kind != MN_DEACTIVE)) + && (items[new_active_item]->kind != MN_INACTIVE)) active_item = new_active_item; if(MouseCursor::current())