X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Fgui%2Fmenu.cpp;h=e46854305bfae5827dc6b04074f58538331e72b0;hb=a54195a086e58adbbe333c7a683df632289e997f;hp=1fb5ae67f8e3c4a3f65341a6161e2d0c2e37e01f;hpb=a113d3bd1feddd510e3b2852b0d42522735eee40;p=supertux.git diff --git a/src/gui/menu.cpp b/src/gui/menu.cpp index 1fb5ae67f..e46854305 100644 --- a/src/gui/menu.cpp +++ b/src/gui/menu.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -40,14 +41,15 @@ #include "timer.hpp" #include "control/joystickkeyboardcontroller.hpp" -static const float MENU_REPEAT_INITIAL = 0.4; -static const float MENU_REPEAT_RATE = 0.2; -static const float FLICK_CURSOR_TIME = 0.5; +static const float MENU_REPEAT_INITIAL = 0.4f; +static const float MENU_REPEAT_RATE = 0.2f; +static const float FLICK_CURSOR_TIME = 0.5f; extern SDL_Surface* screen; std::vector Menu::last_menus; Menu* Menu::current_ = 0; +Menu* Menu::previous = 0; Font* Menu::default_font; Font* Menu::active_font; Font* Menu::deactive_font; @@ -81,7 +83,7 @@ bool confirm_dialog(Surface *background, std::string text) } if(background == NULL) - context.draw_gradient(Color(0.8, 0.95, 0.85), Color(0.8, 0.8, 0.8), + context.draw_gradient(Color(0.8f, 0.95f, 0.85f), Color(0.8f, 0.8f, 0.8f), LAYER_BACKGROUND0); else context.draw_surface(background, Vector(0,0), LAYER_BACKGROUND0); @@ -114,23 +116,29 @@ bool confirm_dialog(Surface *background, std::string text) return false; } - + void Menu::push_current(Menu* pmenu) { + previous = current_; + if (current_) last_menus.push_back(current_); current_ = pmenu; - current_->effect_time = real_time; + current_->effect_start_time = real_time; + current_->effect_progress = 0.0f; } void Menu::pop_current() { + previous = current_; + if (last_menus.size() >= 1) { current_ = last_menus.back(); - current_->effect_time = real_time; + current_->effect_start_time = real_time; + current_->effect_progress = 0.0f; last_menus.pop_back(); } else { current_ = 0; @@ -140,16 +148,20 @@ Menu::pop_current() void Menu::set_current(Menu* menu) { + previous = current_; + last_menus.clear(); if (menu) - menu->effect_time = real_time; - + { + menu->effect_start_time = real_time; + menu->effect_progress = 0.0f; + } current_ = menu; // just to be sure... main_controller->reset(); } - + MenuItem::MenuItem(MenuItemKind _kind, int _id) : kind(_kind) , id(_id) { @@ -170,6 +182,12 @@ MenuItem::change_input(const std::string& text_) input = text_; } +void +MenuItem::set_help(const std::string& help_text) +{ + help = help_text; +} + std::string MenuItem::get_input_with_symbol(bool active_item) { if(!active_item) { @@ -188,14 +206,18 @@ std::string MenuItem::get_input_with_symbol(bool active_item) return string; } - + Menu::~Menu() { 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() @@ -210,6 +232,9 @@ Menu::Menu() arrange_left = 0; active_item = -1; + effect_progress = 0.0f; + effect_start_time = 0.0f; + checkbox.reset(new Surface("images/engine/menu/checkbox-unchecked.png")); checkbox_checked.reset(new Surface("images/engine/menu/checkbox-checked.png")); back.reset(new Surface("images/engine/menu/arrow-back.png")); @@ -217,7 +242,8 @@ Menu::Menu() arrow_right.reset(new Surface("images/engine/menu/arrow-right.png")); } -void Menu::set_pos(float x, float y, float rw, float rh) +void +Menu::set_pos(float x, float y, float rw, float rh) { pos_x = x + get_width() * rw; pos_y = y + get_height() * rh; @@ -241,21 +267,24 @@ Menu::additem(MenuItem* item) } } -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) { @@ -263,48 +292,54 @@ Menu::add_controlfield(int id, const std::string& text, item->change_text(text); 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 +MenuItem* Menu::add_deactive(int id, const std::string& text) { MenuItem* item = new MenuItem(MN_DEACTIVE, 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_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 @@ -322,6 +357,21 @@ Menu::clear() void Menu::update() { + int menu_height = 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) { + effect_progress = 0.0f; + } + /** check main input controller... */ if(main_controller->pressed(Controller::UP)) { menuaction = MENU_ACTION_UP; @@ -341,8 +391,7 @@ Menu::update() menuaction = MENU_ACTION_DOWN; menu_repeat_time = real_time + MENU_REPEAT_RATE; } - if(main_controller->pressed(Controller::JUMP) - || main_controller->pressed(Controller::ACTION) + if(main_controller->pressed(Controller::ACTION) || main_controller->pressed(Controller::MENU_SELECT)) { menuaction = MENU_ACTION_HIT; } @@ -491,23 +540,13 @@ void Menu::draw_item(DrawingContext& context, int index) { float menu_height = get_height(); - float menu_width = get_width(); + float menu_width = get_width(); MenuItem& pitem = *(items[index]); - int effect_offset = 0; - if(effect_time != 0) { - if(real_time - effect_time > 0.5) { - effect_time = 0; - } else { - float effect_delta = (0.5 - (real_time - effect_time)) * 250; - effect_offset = (int) ((index % 2) ? effect_delta : -effect_delta); - } - } - Font* text_font = default_font; float x_pos = pos_x; - float y_pos = pos_y + 24*index - menu_height/2 + 12 + effect_offset; + 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); @@ -525,13 +564,28 @@ Menu::draw_item(DrawingContext& context, int index) text_font = active_font; } + if(active_item == index) + { + float blink = (sinf(real_time * M_PI * 1.0f)/2.0f + 0.5f) * 0.5f + 0.25f; + context.draw_filled_rect(Rect(Vector(pos_x - menu_width/2 + 10 - 2, y_pos - 12 - 2), + Vector(pos_x + menu_width/2 - 10 + 2, y_pos + 12 + 2)), + Color(1.0f, 1.0f, 1.0f, blink), + 14.0f, + LAYER_GUI-10); + context.draw_filled_rect(Rect(Vector(pos_x - menu_width/2 + 10, y_pos - 12), + Vector(pos_x + menu_width/2 - 10, y_pos + 12)), + Color(1.0f, 1.0f, 1.0f, 0.5f), + 12.0f, + LAYER_GUI-10); + } + switch (pitem.kind) { case MN_DEACTIVE: { context.draw_text(deactive_font, pitem.text, - Vector(SCREEN_WIDTH/2, y_pos - int(deactive_font->get_height()/2)), - CENTER_ALLIGN, LAYER_GUI); + Vector(pos_x, y_pos - int(deactive_font->get_height()/2)), + ALIGN_CENTER, LAYER_GUI); break; } @@ -539,7 +593,7 @@ Menu::draw_item(DrawingContext& context, int index) { // TODO float x = pos_x - menu_width/2; - float y = y_pos - 12 - effect_offset; + float y = y_pos - 12; /* Draw a horizontal line with a little 3d effect */ context.draw_filled_rect(Vector(x, y + 6), Vector(menu_width, 4), @@ -552,48 +606,38 @@ 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)), - CENTER_ALLIGN, LAYER_GUI); + Vector(pos_x, y_pos - int(label_font->get_height()/2)), + ALIGN_CENTER, LAYER_GUI); break; } case MN_TEXTFIELD: case MN_NUMFIELD: case MN_CONTROLFIELD: { - float width = text_width + input_width + 5; - float text_pos = SCREEN_WIDTH/2 - width/2; - float input_pos = text_pos + text_width + 10; - - context.draw_filled_rect( - Vector(input_pos - 5, y_pos - 10), - Vector(input_width + 10, 20), - Color(1.0f, 1.0f, 1.0f, 1.0f), LAYER_GUI-5); - context.draw_filled_rect( - Vector(input_pos - 4, y_pos - 9), - Vector(input_width + 8, 18), - Color(0, 0, 0, 0.5f), LAYER_GUI-4); + float left = pos_x - menu_width/2 + 16; + float right = pos_x + menu_width/2 - 16; if(pitem.kind == MN_TEXTFIELD || pitem.kind == MN_NUMFIELD) { if(active_item == index) context.draw_text(field_font, pitem.get_input_with_symbol(true), - Vector(input_pos, y_pos - int(field_font->get_height()/2)), - LEFT_ALLIGN, LAYER_GUI); + Vector(right, y_pos - int(field_font->get_height()/2)), + ALIGN_RIGHT, 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)), - LEFT_ALLIGN, LAYER_GUI); + Vector(right, y_pos - int(field_font->get_height()/2)), + ALIGN_RIGHT, LAYER_GUI); } else context.draw_text(field_font, pitem.input, - Vector(input_pos, y_pos - int(field_font->get_height()/2)), - LEFT_ALLIGN, LAYER_GUI); + Vector(right, y_pos - int(field_font->get_height()/2)), + ALIGN_RIGHT, LAYER_GUI); context.draw_text(text_font, pitem.text, - Vector(text_pos, y_pos - int(text_font->get_height()/2)), - LEFT_ALLIGN, LAYER_GUI); + Vector(left, y_pos - int(text_font->get_height()/2)), + ALIGN_LEFT, LAYER_GUI); break; } case MN_STRINGSELECT: @@ -621,18 +665,18 @@ Menu::draw_item(DrawingContext& context, int index) 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)), - CENTER_ALLIGN, LAYER_GUI); + Vector(pos_x + 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)), - CENTER_ALLIGN, LAYER_GUI); + Vector(pos_x + list_pos_2/2, y_pos - int(text_font->get_height()/2)), + ALIGN_CENTER, LAYER_GUI); break; } case MN_BACK: { context.draw_text(text_font, pitem.text, - Vector(SCREEN_WIDTH/2, y_pos - int(text_font->get_height()/2)), - CENTER_ALLIGN, LAYER_GUI); + Vector(pos_x, y_pos - int(text_font->get_height()/2)), + ALIGN_CENTER, LAYER_GUI); context.draw_surface(back.get(), Vector(x_pos + text_width/2 + 16, y_pos - 8), LAYER_GUI); @@ -642,34 +686,35 @@ Menu::draw_item(DrawingContext& context, int index) case MN_TOGGLE: { context.draw_text(text_font, pitem.text, - Vector(SCREEN_WIDTH/2, y_pos - (text_font->get_height()/2)), - CENTER_ALLIGN, LAYER_GUI); + Vector(pos_x - menu_width/2 + 16, y_pos - (text_font->get_height()/2)), + ALIGN_LEFT, LAYER_GUI); if(pitem.toggled) context.draw_surface(checkbox_checked.get(), - Vector(x_pos + (text_width+16)/2, y_pos - 8), + Vector(x_pos + (menu_width/2-16) - checkbox->get_width(), y_pos - 8), LAYER_GUI + 1); else context.draw_surface(checkbox.get(), - Vector(x_pos + (text_width+16)/2, y_pos - 8), + Vector(x_pos + (menu_width/2-16) - checkbox->get_width(), y_pos - 8), LAYER_GUI + 1); break; } case MN_ACTION: context.draw_text(text_font, pitem.text, - Vector(SCREEN_WIDTH/2, y_pos - int(text_font->get_height()/2)), - CENTER_ALLIGN, LAYER_GUI); + Vector(pos_x, y_pos - int(text_font->get_height()/2)), + ALIGN_CENTER, LAYER_GUI); break; case MN_GOTO: context.draw_text(text_font, pitem.text, - Vector(SCREEN_WIDTH/2, y_pos - int(text_font->get_height()/2)), - CENTER_ALLIGN, LAYER_GUI); + Vector(pos_x, y_pos - int(text_font->get_height()/2)), + ALIGN_CENTER, LAYER_GUI); break; } } -float Menu::get_width() const +float +Menu::get_width() const { /* The width of the menu has to be more than the width of the text with the most characters */ @@ -692,7 +737,8 @@ float Menu::get_width() const return menu_width + 24; } -float Menu::get_height() const +float +Menu::get_height() const { return items.size() * 24; } @@ -705,19 +751,42 @@ Menu::draw(DrawingContext& context) MouseCursor::current()->draw(context); } + float menu_width = get_width(); float menu_height = get_height(); - float menu_width = get_width(); - - /* Draw a transparent background */ - context.draw_filled_rect( - Vector(pos_x - menu_width/2, pos_y - 24*items.size()/2 - 10), - Vector(menu_width,menu_height + 20), - Color(0.6f, 0.7f, 0.8f, 0.5f), LAYER_GUI-10); - for(unsigned int i = 0; i < items.size(); ++i) + if (effect_progress != 1.0f) { - draw_item(context, i); + 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 */ + context.draw_filled_rect(Rect(Vector(pos_x - menu_width/2-4, pos_y - menu_height/2 - 10-4), + Vector(pos_x + menu_width/2+4, pos_y - menu_height/2 + 10 + menu_height+4)), + Color(0.2f, 0.3f, 0.4f, 0.8f), + 20.0f, + LAYER_GUI-10); + + context.draw_filled_rect(Rect(Vector(pos_x - menu_width/2, pos_y - menu_height/2 - 10), + Vector(pos_x + menu_width/2, pos_y - menu_height/2 + 10 + menu_height)), + Color(0.6f, 0.7f, 0.8f, 0.5f), + 16.0f, + LAYER_GUI-10); + + if (effect_progress == 1.0f) + for(unsigned int i = 0; i < items.size(); ++i) + { + draw_item(context, i); + } } MenuItem& @@ -759,11 +828,20 @@ Menu::is_toggled(int id) const return get_item_by_id(id).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) { - if(effect_time != 0) + if(effect_progress != 1.0f) return; switch(event.type) {