X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fgui%2Fmenu.cpp;h=3db37460e177ca97a67f19e007453085068af7ef;hb=20b1c27dacf592c4f82fa8772d135ca9b7375d45;hp=37d74c6684c90944fd789c08ac0457d85de1cc71;hpb=5b7f9214cb929399f1a855ef5807018a9447d510;p=supertux.git diff --git a/src/gui/menu.cpp b/src/gui/menu.cpp index 37d74c668..3db37460e 100644 --- a/src/gui/menu.cpp +++ b/src/gui/menu.cpp @@ -1,7 +1,7 @@ // $Id$ // // SuperTux -// Copyright (C) 2004 Tobias Glaesser +// Copyright (C) 2006 Matthias Braun // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -16,6 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + #include #include @@ -23,6 +24,7 @@ #include #include +#include #include #include #include @@ -30,28 +32,24 @@ #include #include "menu.hpp" -#include "video/screen.hpp" +#include "mainloop.hpp" #include "video/drawing_context.hpp" #include "gettext.hpp" #include "math/vector.hpp" #include "main.hpp" #include "resources.hpp" +#include "timer.hpp" #include "control/joystickkeyboardcontroller.hpp" -static const int MENU_REPEAT_INITIAL = 400; -static const int MENU_REPEAT_RATE = 200; -static const int FLICK_CURSOR_TIME = 500; +static const float MENU_REPEAT_INITIAL = 0.4f; +static const float MENU_REPEAT_RATE = 0.1f; +static const float FLICK_CURSOR_TIME = 0.5f; extern SDL_Surface* screen; -Surface* checkbox; -Surface* checkbox_checked; -Surface* back; -Surface* arrow_left; -Surface* arrow_right; - 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; @@ -68,23 +66,25 @@ bool confirm_dialog(Surface *background, std::string text) dialog->add_entry(true, _("Yes")); dialog->add_entry(false, _("No")); dialog->add_hl(); - + Menu::set_current(dialog); DrawingContext context; + // TODO make this a screen and not another mainloop... while(true) { SDL_Event event; while (SDL_PollEvent(&event)) { if(event.type == SDL_QUIT) - throw std::runtime_error("received window close event"); + main_loop->quit(); main_controller->process_event(event); dialog->event(event); } if(background == NULL) - context.draw_gradient(Color(200,240,220), Color(200,200,220), LAYER_BACKGROUND0); + 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); @@ -116,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_ticks = SDL_GetTicks(); + 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_ticks = SDL_GetTicks(); + current_->effect_start_time = real_time; + current_->effect_progress = 0.0f; last_menus.pop_back(); } else { current_ = 0; @@ -142,16 +148,33 @@ Menu::pop_current() void Menu::set_current(Menu* menu) { + previous = current_; + last_menus.clear(); if (menu) - menu->effect_ticks = SDL_GetTicks(); - + { + 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::vector::iterator i = last_menus.begin(); i != last_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) { @@ -172,30 +195,48 @@ MenuItem::change_input(const std::string& text_) input = text_; } +void +MenuItem::set_help(const std::string& help_text) +{ + std::string overflow; + help = Menu::default_font->wrap_to_width(help_text, 600, &overflow); + while (!overflow.empty()) + { + help += "\n"; + help += Menu::default_font->wrap_to_width(overflow, 600, &overflow); + } +} + std::string MenuItem::get_input_with_symbol(bool active_item) { if(!active_item) { input_flickering = true; } else { - input_flickering = (SDL_GetTicks() / FLICK_CURSOR_TIME) % 2; + input_flickering = ((int) (real_time / FLICK_CURSOR_TIME)) % 2; } char str[1024]; if(input_flickering) - sprintf(str,"%s ",input.c_str()); + snprintf(str, sizeof(str), "%s ",input.c_str()); else - sprintf(str,"%s_",input.c_str()); + snprintf(str, sizeof(str), "%s_",input.c_str()); std::string string = str; 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() @@ -209,12 +250,22 @@ Menu::Menu() pos_y = SCREEN_HEIGHT/2; 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")); + arrow_left.reset(new Surface("images/engine/menu/arrow-left.png")); + arrow_right.reset(new Surface("images/engine/menu/arrow-right.png")); } -void Menu::set_pos(int x, int y, float rw, float rh) +void +Menu::set_pos(float x, float y, float rw, float rh) { - pos_x = x + (int)((float)get_width() * rw); - pos_y = y + (int)((float)get_height() * rh); + pos_x = x + get_width() * rw; + pos_y = y + get_height() * rh; } /* Add an item to a menu */ @@ -228,28 +279,31 @@ Menu::additem(MenuItem* item) * selectable item added */ if (active_item == -1 - && item->kind != MN_HL + && item->kind != MN_HL && item->kind != MN_LABEL && item->kind != MN_DEACTIVE) { 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) { @@ -257,48 +311,63 @@ 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_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 @@ -316,28 +385,63 @@ 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) { + effect_progress = 0.0f; + } + /** check main input controller... */ - Uint32 ticks = SDL_GetTicks(); if(main_controller->pressed(Controller::UP)) { menuaction = MENU_ACTION_UP; - menu_repeat_ticks = ticks + MENU_REPEAT_INITIAL; + menu_repeat_time = real_time + MENU_REPEAT_INITIAL; } - if(main_controller->hold(Controller::UP) && - menu_repeat_ticks != 0 && ticks > menu_repeat_ticks) { + if(main_controller->hold(Controller::UP) && + menu_repeat_time != 0 && real_time > menu_repeat_time) { menuaction = MENU_ACTION_UP; - menu_repeat_ticks = ticks + MENU_REPEAT_RATE; - } + menu_repeat_time = real_time + MENU_REPEAT_RATE; + } + if(main_controller->pressed(Controller::DOWN)) { menuaction = MENU_ACTION_DOWN; - menu_repeat_ticks = ticks + MENU_REPEAT_INITIAL; + menu_repeat_time = real_time + MENU_REPEAT_INITIAL; } - if(main_controller->hold(Controller::DOWN) && - menu_repeat_ticks != 0 && ticks > menu_repeat_ticks) { + if(main_controller->hold(Controller::DOWN) && + menu_repeat_time != 0 && real_time > menu_repeat_time) { menuaction = MENU_ACTION_DOWN; - menu_repeat_ticks = ticks + MENU_REPEAT_RATE; + 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::JUMP) - || main_controller->pressed(Controller::ACTION) + + if(main_controller->pressed(Controller::ACTION) || main_controller->pressed(Controller::MENU_SELECT)) { menuaction = MENU_ACTION_HIT; } @@ -348,7 +452,7 @@ Menu::update() hit_item = -1; if(items.size() == 0) return; - + int last_active_item = active_item; switch(menuaction) { case MENU_ACTION_UP: @@ -357,13 +461,13 @@ Menu::update() --active_item; else active_item = int(items.size())-1; - } while ((items[active_item]->kind == MN_HL + } while ((items[active_item]->kind == MN_HL || items[active_item]->kind == MN_LABEL || items[active_item]->kind == MN_DEACTIVE) && (active_item != last_active_item)); - + break; - + case MENU_ACTION_DOWN: do { if(active_item < int(items.size())-1 ) @@ -374,27 +478,31 @@ Menu::update() || items[active_item]->kind == MN_LABEL || items[active_item]->kind == MN_DEACTIVE) && (active_item != last_active_item)); - + break; - + case MENU_ACTION_LEFT: if(items[active_item]->kind == MN_STRINGSELECT) { if(items[active_item]->selected > 0) items[active_item]->selected--; else items[active_item]->selected = items[active_item]->list.size()-1; + + menu_action(items[active_item]); } break; - + case MENU_ACTION_RIGHT: if(items[active_item]->kind == 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 MENU_ACTION_HIT: { hit_item = active_item; switch (items[active_item]->kind) { @@ -402,26 +510,35 @@ Menu::update() assert(items[active_item]->target_menu != 0); Menu::push_current(items[active_item]->target_menu); break; - + case MN_TOGGLE: items[active_item]->toggled = !items[active_item]->toggled; menu_action(items[active_item]); break; - + case MN_CONTROLFIELD: menu_action(items[active_item]); break; - + case MN_ACTION: 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; update(); break; - + case MN_BACK: Menu::pop_current(); break; @@ -430,7 +547,7 @@ Menu::update() } break; } - + case MENU_ACTION_REMOVE: if(items[active_item]->kind == MN_TEXTFIELD || items[active_item]->kind == MN_NUMFIELD) @@ -438,7 +555,7 @@ Menu::update() if(!items[active_item]->input.empty()) { int i = items[active_item]->input.size(); - + while(delete_character > 0) /* remove charactes */ { items[active_item]->input.resize(i-1); @@ -447,16 +564,16 @@ Menu::update() } } break; - + case MENU_ACTION_INPUT: if(items[active_item]->kind == MN_TEXTFIELD - || (items[active_item]->kind == MN_NUMFIELD + || (items[active_item]->kind == MN_NUMFIELD && mn_input_char >= '0' && mn_input_char <= '9')) { items[active_item]->input.push_back(mn_input_char); } break; - + case MENU_ACTION_BACK: Menu::pop_current(); break; @@ -485,32 +602,26 @@ Menu::menu_action(MenuItem* ) void Menu::draw_item(DrawingContext& context, int index) { - int menu_height = get_height(); - int menu_width = get_width(); + float menu_height = get_height(); + float menu_width = get_width(); MenuItem& pitem = *(items[index]); - int effect_offset = 0; - if(effect_ticks != 0) { - if(SDL_GetTicks() - effect_ticks > 500) { - effect_ticks = 0; - } else { - Uint32 effect_time = (500 - (SDL_GetTicks() - effect_ticks)) / 4; - effect_offset = (index % 2) ? effect_time : -effect_time; - } - } - Font* text_font = default_font; - int x_pos = pos_x; - int y_pos = pos_y + 24*index - menu_height/2 + 12 + effect_offset; + 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 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]); } - + if (arrange_left) x_pos += 24 - menu_width/2 + (text_width + input_width + list_width)/2; @@ -520,113 +631,105 @@ 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; } case MN_HL: { // TODO - int x = pos_x - menu_width/2; - int y = y_pos - 12 - effect_offset; + float x = pos_x - menu_width/2; + 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), Color(150,200,255,225), LAYER_GUI); + Vector(menu_width, 4), + Color(0.6f, 0.7f, 1.0f, 1.0f), LAYER_GUI); context.draw_filled_rect(Vector(x, y + 6), - Vector(menu_width, 2), Color(255,255,255,255), LAYER_GUI); + Vector(menu_width, 2), + Color(1.0f, 1.0f, 1.0f, 1.0f), LAYER_GUI); break; } 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: { - int width = text_width + input_width + 5; - int text_pos = SCREEN_WIDTH/2 - width/2; - int input_pos = text_pos + text_width + 10; - - context.draw_filled_rect( - Vector(input_pos - 5, y_pos - 10), - Vector(input_width + 10, 20), - Color(255,255,255,255), LAYER_GUI-5); - context.draw_filled_rect( - Vector(input_pos - 4, y_pos - 9), - Vector(input_width + 8, 18), - Color(0,0,0,128), LAYER_GUI-4); - 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: { - 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(text_font, pitem.text, + Vector(left, y_pos - int(text_font->get_height()/2)), + ALIGN_LEFT, LAYER_GUI); - /* Draw arrows */ - context.draw_surface(arrow_left, - Vector(x_pos - list_pos + text_pos - 17, y_pos - 8), + // Draw right side + context.draw_surface(arrow_left.get(), + Vector(right - list_width - roff - roff, y_pos - 8), LAYER_GUI); - context.draw_surface(arrow_right, - Vector(x_pos - list_pos + text_pos - 1 + list_pos_2, y_pos - 8), + context.draw_surface(arrow_right.get(), + 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(255,255,255,255), 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,128), 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); - 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); + context.draw_text(field_font, pitem.list[pitem.selected], + Vector(right - roff, y_pos - int(text_font->get_height()/2)), + ALIGN_RIGHT, 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); - context.draw_surface(back, + 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); break; @@ -635,57 +738,63 @@ 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, - Vector(x_pos + (text_width+16)/2, y_pos - 8), + context.draw_surface(checkbox_checked.get(), + Vector(x_pos + (menu_width/2-16) - checkbox->get_width(), y_pos - 8), LAYER_GUI + 1); else - context.draw_surface(checkbox, - Vector(x_pos + (text_width+16)/2, y_pos - 8), + context.draw_surface(checkbox.get(), + 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; } } -int 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 */ + float menu_width = 0; + for(unsigned int i = 0; i < items.size(); ++i) { - /* The width of the menu has to be more than the width of the text - with the most characters */ - int menu_width = 0; - for(unsigned int i = 0; i < items.size(); ++i) - { - int w = items[i]->text.size() + items[i]->input.size() + 1; - if(w > menu_width) - { - menu_width = w; - if( items[i]->kind == MN_TOGGLE) - menu_width += 2; - } - } + Font* font = default_font; + if(items[i]->kind == MN_LABEL) + font = label_font; - return (menu_width * 16 + 24); - } + float w = font->get_text_width(items[i]->text) + + label_font->get_text_width(items[i]->input) + 16; + if(items[i]->kind == MN_TOGGLE) + w += 32; -int Menu::get_height() const - { - return items.size() * 24; + if(w > menu_width) + menu_width = w; } + return menu_width + 24; +} + +float +Menu::get_height() const +{ + return items.size() * 24; +} + /* Draw the current menu. */ void Menu::draw(DrawingContext& context) @@ -693,20 +802,69 @@ Menu::draw(DrawingContext& context) if(MouseCursor::current()) { MouseCursor::current()->draw(context); } - - int menu_height = get_height(); - int 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(150,180,200,125), LAYER_GUI-10); + float menu_width = get_width(); + float menu_height = get_height(); - for(unsigned int i = 0; i < items.size(); ++i) + 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; + } + } + + /* 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 (!items[active_item]->help.empty()) { - draw_item(context, i); + int text_width = (int) default_font->get_text_width(items[active_item]->help); + int text_height = (int) default_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(default_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) + { + draw_item(context, i); + } } MenuItem& @@ -715,7 +873,7 @@ Menu::get_item_by_id(int id) for(std::vector::iterator i = items.begin(); i != items.end(); ++i) { MenuItem& item = **i; - + if(item.id == id) return item; } @@ -729,7 +887,7 @@ Menu::get_item_by_id(int id) const for(std::vector::const_iterator i = items.begin(); i != items.end(); ++i) { const MenuItem& item = **i; - + if(item.id == id) return item; } @@ -748,11 +906,26 @@ 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) { - if(effect_ticks != 0) + if(effect_progress != 1.0f) return; switch(event.type) { @@ -773,22 +946,23 @@ Menu::event(const SDL_Event& event) case SDL_MOUSEMOTION: { - int x = int(event.motion.x * float(SCREEN_WIDTH)/screen->w); - int y = int(event.motion.y * float(SCREEN_HEIGHT)/screen->h); + float x = event.motion.x * SCREEN_WIDTH/screen->w; + float y = event.motion.y * SCREEN_HEIGHT/screen->h; if(x > pos_x - get_width()/2 && x < pos_x + get_width()/2 && y > pos_y - get_height()/2 && y < pos_y + get_height()/2) { - int new_active_item = (y - (pos_y - get_height()/2)) / 24; - + int new_active_item + = static_cast ((y - (pos_y - get_height()/2)) / 24); + /* 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)) active_item = new_active_item; - + if(MouseCursor::current()) MouseCursor::current()->set_state(MC_LINK); }