X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Fmenu.cpp;h=9932ed669ac6ee428d780a37252255d637dae106;hb=3369ed08e4b7126af560dc5f9c3442fc76b43ab4;hp=a131c50d931fc6b185cd310ab710809a9e5b3ade;hpb=a7045d8eeb0e923852128a362c2ca8cf5c76e1ae;p=supertux.git diff --git a/src/menu.cpp b/src/menu.cpp index a131c50d9..9932ed669 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -1,568 +1,908 @@ -/* - menu.c - - Super Tux - Menu - - by Tobias Glaesser - tobi.web@gmx.de - http://www.newbreedsoftware.com/supertux/ - - December 20, 2003 - March 15, 2004 -*/ +// $Id$ +// +// SuperTux +// Copyright (C) 2004 Tobias Glaesser +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// 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. #ifndef WIN32 #include #include #endif +#include +#include #include #include -#include +#include +#include #include "defines.h" #include "globals.h" #include "menu.h" -#include "screen.h" +#include "screen/screen.h" +#include "screen/drawing_context.h" #include "setup.h" #include "sound.h" #include "scene.h" #include "leveleditor.h" #include "timer.h" #include "high_scores.h" +#include "gettext.h" + +#define FLICK_CURSOR_TIME 500 + +Surface* checkbox; +Surface* checkbox_checked; +Surface* back; +Surface* arrow_left; +Surface* arrow_right; + +Menu* main_menu = 0; +Menu* game_menu = 0; +Menu* worldmap_menu = 0; +Menu* options_menu = 0; +Menu* options_keys_menu = 0; +Menu* options_joystick_menu = 0; +Menu* highscore_menu = 0; +Menu* load_game_menu = 0; +Menu* save_game_menu = 0; +Menu* contrib_menu = 0; +Menu* contrib_subset_menu = 0; + +std::vector Menu::last_menus; +Menu* Menu::current_ = 0; + +/* 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->additem(MN_DEACTIVE, text,0,0); + dialog->additem(MN_HL,"",0,0); + dialog->additem(MN_ACTION,_("Yes"),0,0,true); + dialog->additem(MN_ACTION,_("No"),0,0,false); + dialog->additem(MN_HL,"",0,0); -/* (global) menu variables */ -MenuAction menuaction; -int show_menu; -int menu_change; -texture_type checkbox, checkbox_checked, back, arrow_left, arrow_right; + Menu::set_current(dialog); -menu_type main_menu, game_menu, options_menu, highscore_menu, load_game_menu, save_game_menu; -menu_type* current_menu, * last_menu; + DrawingContext context; -/* input implementation variables */ -int delete_character; -char mn_input_char; + while(true) + { + SDL_Event event; -/* Set the current menu */ -void menu_set_current(menu_type* pmenu) -{ - if(pmenu != current_menu) + while (SDL_PollEvent(&event)) { - menu_change = YES; - last_menu = current_menu; - current_menu = pmenu; - timer_start(&pmenu->effect, 500); + dialog->event(event); } + + if(background == NULL) + context.draw_gradient(Color(200, 100, 200), Color(100, 200, 100), LAYER_BACKGROUND0); + else + context.draw_surface(background, Vector(0,0), LAYER_BACKGROUND0); + + dialog->draw(context); + dialog->action(); + + switch (dialog->check()) + { + case true: + //delete cap_screen; + Menu::set_current(0); + delete dialog; + return true; + break; + case false: + //delete cap_screen; + Menu::set_current(0); + delete dialog; + return false; + break; + default: + break; + } + + mouse_cursor->draw(context); + context.do_drawing(); + SDL_Delay(25); + } + + return false; +} + +void +Menu::push_current(Menu* pmenu) +{ + if (current_) + last_menus.push_back(current_); + + current_ = pmenu; + current_->effect.start(500); +} + +void +Menu::pop_current() +{ + if (!last_menus.empty()) + { + current_ = last_menus.back(); + current_->effect.start(500); + + last_menus.pop_back(); + } + else + { + current_ = 0; + } +} + +void +Menu::set_current(Menu* menu) +{ + last_menus.clear(); + + if (menu) + menu->effect.start(500); + + current_ = menu; } /* Return a pointer to a new menu item */ -menu_item_type* menu_item_create(MenuItemKind kind, char *text, int init_toggle, void* target_menu) +MenuItem* +MenuItem::create(MenuItemKind kind_, const char *text_, int init_toggle_, Menu* target_menu_, int id, int* int_p_) { - menu_item_type *pnew_item = (menu_item_type*) malloc(sizeof(menu_item_type)); - pnew_item->kind = kind; - pnew_item->text = (char*) malloc(sizeof(char) * (strlen(text) + 1)); - strcpy(pnew_item->text,text); - if(kind == MN_TOGGLE) - pnew_item->toggled = init_toggle; + MenuItem *pnew_item = new MenuItem; + + pnew_item->kind = kind_; + pnew_item->text = (char*) malloc(sizeof(char) * (strlen(text_) + 1)); + strcpy(pnew_item->text, text_); + + if(kind_ == MN_TOGGLE) + pnew_item->toggled = init_toggle_; else - pnew_item->toggled = NO; - pnew_item->target_menu = target_menu; + pnew_item->toggled = false; + + pnew_item->target_menu = target_menu_; pnew_item->input = (char*) malloc(sizeof(char)); pnew_item->input[0] = '\0'; - if(kind == MN_STRINGSELECT) - { - pnew_item->list = (string_list_type*) malloc(sizeof(string_list_type)); - string_list_init(pnew_item->list); - } + + if(kind_ == MN_STRINGSELECT) + { + pnew_item->list = (string_list_type*) malloc(sizeof(string_list_type)); + string_list_init(pnew_item->list); + } else pnew_item->list = NULL; + + pnew_item->id = id; + pnew_item->int_p = int_p_; + + pnew_item->input_flickering = false; + pnew_item->input_flickering_timer.init(true); + pnew_item->input_flickering_timer.start(FLICK_CURSOR_TIME); + return pnew_item; } -void menu_item_change_text(menu_item_type* pmenu_item,const char *text) +void +MenuItem::change_text(const char *text_) +{ + if (text_) + { + free(text); + text = (char*) malloc(sizeof(char )*(strlen(text_)+1)); + strcpy(text, text_); + } +} + +void +MenuItem::change_input(const char *text_) { if(text) + { + free(input); + input = (char*) malloc(sizeof(char )*(strlen(text_)+1)); + strcpy(input, text_); + } +} + +std::string MenuItem::get_input_with_symbol(bool active_item) +{ + if(!active_item) + input_flickering = true; + else + { + if(input_flickering_timer.get_left() < 0) { - free(pmenu_item->text); - pmenu_item->text = (char*) malloc(sizeof(char )*(strlen(text)+1)); - strcpy(pmenu_item->text,text); + if(input_flickering) + input_flickering = false; + else + input_flickering = true; + input_flickering_timer.start(FLICK_CURSOR_TIME); } + } + + char str[1024]; + if(input_flickering) + sprintf(str,"%s_",input); + else + sprintf(str,"%s ",input); + + std::string string = str; + + return string; } -void menu_item_change_input(menu_item_type* pmenu_item,const char *text) + +/* Set ControlField for keyboard key */ +void Menu::get_controlfield_key_into_input(MenuItem *item) { - if(text) + switch(*item->int_p) + { + case SDLK_UP: + item->change_input(_("Up cursor")); + break; + case SDLK_DOWN: + item->change_input(_("Down cursor")); + break; + case SDLK_LEFT: + item->change_input(_("Left cursor")); + break; + case SDLK_RIGHT: + item->change_input(_("Right cursor")); + break; + case SDLK_RETURN: + item->change_input(_("Return")); + break; + case SDLK_SPACE: + item->change_input(_("Space")); + break; + case SDLK_RSHIFT: + item->change_input(_("Right Shift")); + break; + case SDLK_LSHIFT: + item->change_input(_("Left Shift")); + break; + case SDLK_RCTRL: + item->change_input(_("Right Control")); + break; + case SDLK_LCTRL: + item->change_input(_("Left Control")); + break; + case SDLK_RALT: + item->change_input(_("Right Alt")); + break; + case SDLK_LALT: + item->change_input(_("Left Alt")); + break; + default: { - free(pmenu_item->input); - pmenu_item->input = (char*) malloc(sizeof(char )*(strlen(text)+1)); - strcpy(pmenu_item->input,text); + char tmp[64]; + snprintf(tmp, 64, "%d", *item->int_p); + item->change_input(tmp); } + break; + } +} + +/* Set ControlField for joystick button */ +void Menu::get_controlfield_js_into_input(MenuItem *item) +{ + std::ostringstream oss; + oss << "Button " << *item->int_p; + item->change_input(oss.str().c_str()); } /* Free a menu and all its items */ -void menu_free(menu_type* pmenu) +Menu::~Menu() { - int i; - if(pmenu->num_items != 0 && pmenu->item != NULL) + if(item.size() != 0) + { + for(unsigned int i = 0; i < item.size(); ++i) { - for(i = 0; i < pmenu->num_items; ++i) - { - free(pmenu->item[i].text); - free(pmenu->item[i].input); - string_list_free(pmenu->item[i].list); - } - free(pmenu->item); + free(item[i].text); + free(item[i].input); + string_list_free(item[i].list); } + } +} + + +Menu::Menu() +{ + hit_item = -1; + menuaction = MENU_ACTION_NONE; + delete_character = 0; + mn_input_char = '\0'; + + pos_x = screen->w/2; + pos_y = screen->h/2; + arrange_left = 0; + active_item = 0; + effect.init(false); + + joystick_timer.init(true); } -/* Initialize a menu */ -void menu_init(menu_type* pmenu) +void Menu::set_pos(int x, int y, float rw, float rh) { - pmenu->arrange_left = 0; - pmenu->num_items = 0; - pmenu->active_item = 0; - pmenu->item = NULL; - timer_init(&pmenu->effect,NO); + pos_x = x + (int)((float)get_width() * rw); + pos_y = y + (int)((float)get_height() * rh); +} + +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)); } /* Add an item to a menu */ -void menu_additem(menu_type* pmenu, menu_item_type* pmenu_item) +void +Menu::additem(MenuItem* pmenu_item) { - ++pmenu->num_items; - pmenu->item = (menu_item_type*) realloc(pmenu->item, sizeof(menu_item_type) * pmenu->num_items); - memcpy(&pmenu->item[pmenu->num_items-1],pmenu_item,sizeof(menu_item_type)); - free(pmenu_item); + item.push_back(*pmenu_item); + delete pmenu_item; } -/* Process actions done on the menu */ -void menu_action(menu_type* pmenu) +void +Menu::clear() { - menu_item_type& item = pmenu->item[pmenu->active_item]; + item.clear(); +} - if(pmenu->num_items != 0 && pmenu->item != NULL) +/* Process actions done on the menu */ +void +Menu::action() +{ + hit_item = -1; + if(item.size() != 0) + { + switch(menuaction) { - switch(menuaction) + case MENU_ACTION_UP: + if (active_item > 0) + --active_item; + else + active_item = int(item.size())-1; + break; + + case MENU_ACTION_DOWN: + if(active_item < int(item.size())-1) + ++active_item; + else + active_item = 0; + break; + + case MENU_ACTION_LEFT: + if(item[active_item].kind == MN_STRINGSELECT + && item[active_item].list->num_items != 0) + { + if(item[active_item].list->active_item > 0) + --item[active_item].list->active_item; + else + item[active_item].list->active_item = item[active_item].list->num_items-1; + } + break; + + case MENU_ACTION_RIGHT: + if(item[active_item].kind == MN_STRINGSELECT + && item[active_item].list->num_items != 0) + { + if(item[active_item].list->active_item < item[active_item].list->num_items-1) + ++item[active_item].list->active_item; + else + item[active_item].list->active_item = 0; + } + break; + + case MENU_ACTION_HIT: + { + hit_item = active_item; + switch (item[active_item].kind) { - case MENU_ACTION_UP: - if(pmenu->active_item > 0) - --pmenu->active_item; + case MN_GOTO: + if (item[active_item].target_menu != NULL) + Menu::push_current(item[active_item].target_menu); else - pmenu->active_item = pmenu->num_items-1; + puts("NULLL"); break; - case MENU_ACTION_DOWN: - if(pmenu->active_item < pmenu->num_items-1) - ++pmenu->active_item; - else - pmenu->active_item = 0; - break; - case MENU_ACTION_LEFT: - if(item.kind == MN_STRINGSELECT - && item.list->num_items != 0) - { - if(item.list->active_item > 0) - --item.list->active_item; - else - item.list->active_item = item.list->num_items-1; - } - break; - case MENU_ACTION_RIGHT: - if(item.kind == MN_STRINGSELECT - && item.list->num_items != 0) - { - if(item.list->active_item < item.list->num_items-1) - ++item.list->active_item; - else - item.list->active_item = 0; - } + + case MN_TOGGLE: + item[active_item].toggled = !item[active_item].toggled; break; - case MENU_ACTION_HIT: - if(item.kind == MN_GOTO - && item.target_menu != NULL) - menu_set_current((menu_type*)item.target_menu); - - else if(item.kind == MN_TOGGLE) - { - item.toggled = !item.toggled; - menu_change = YES; - } - else if(item.kind == MN_ACTION || item.kind == MN_TEXTFIELD || item.kind == MN_NUMFIELD) - { - item.toggled = YES; - } - else if(item.kind == MN_BACK) - { - if(last_menu != NULL) - menu_set_current(last_menu); - } + + case MN_ACTION: + Menu::set_current(0); + item[active_item].toggled = true; break; - case MENU_ACTION_REMOVE: - if(item.kind == MN_TEXTFIELD - || item.kind == MN_NUMFIELD) - { - if(item.input != NULL) - { - int i = strlen(item.input); - - while(delete_character > 0) /* remove charactes */ - { - item.input[i-1] = '\0'; - delete_character--; - } - } - } + case MN_TEXTFIELD: + case MN_NUMFIELD: + menuaction = MENU_ACTION_DOWN; + action(); break; - case MENU_ACTION_INPUT: - if(item.kind == MN_TEXTFIELD - || (item.kind == MN_NUMFIELD && mn_input_char >= '0' && mn_input_char <= '9')) - { - if(item.input != NULL) - { - int i = strlen(item.input); - item.input = (char*) realloc(item.input,sizeof(char)*(i + 2)); - item.input[i] = mn_input_char; - item.input[i+1] = '\0'; - } - else - { - item.input = (char*) malloc(2*sizeof(char)); - item.input[0] = mn_input_char; - item.input[1] = '\0'; - } - } + + case MN_BACK: + Menu::pop_current(); break; - case MENU_ACTION_NONE: + default: break; } - } - - if(item.kind == MN_DEACTIVE || item.kind == MN_LABEL || item.kind == MN_HL) - { - if(menuaction != MENU_ACTION_UP && menuaction != MENU_ACTION_DOWN) - menuaction = MENU_ACTION_DOWN; - - if(pmenu->num_items > 1) - menu_action(pmenu); - } + } + break; -} + case MENU_ACTION_REMOVE: + if(item[active_item].kind == MN_TEXTFIELD + || item[active_item].kind == MN_NUMFIELD) + { + if(item[active_item].input != NULL) + { + int i = strlen(item[active_item].input); -/* Check, if the value of the active menu item has changed. */ -int menu_check(menu_type* pmenu) -{ - menu_item_type& item = pmenu->item[pmenu->active_item]; + while(delete_character > 0) /* remove charactes */ + { + item[active_item].input[i-1] = '\0'; + delete_character--; + } + } + } + break; - if(pmenu->num_items != 0 && pmenu->item != NULL) - { - if((item.kind == MN_ACTION || item.kind == MN_TEXTFIELD || item.kind == MN_NUMFIELD) && item.toggled == YES) + case MENU_ACTION_INPUT: + 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) { - item.toggled = NO; - show_menu = 0; - return pmenu->active_item; + 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 if(item.kind == MN_TOGGLE || item.kind == MN_GOTO) + else { - return pmenu->active_item; + item[active_item].input = (char*) malloc(2*sizeof(char)); + item[active_item].input[0] = mn_input_char; + item[active_item].input[1] = '\0'; } - else - return -1; + } + + case MENU_ACTION_NONE: + break; } + } + + 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; + + if (active_item >= int(item.size())) + active_item = int(item.size()) - 1; +} + +int +Menu::check() +{ + if (hit_item != -1) + return item[hit_item].id; else return -1; } -void menu_draw_item(menu_type* pmenu, - int index, // Position of the current item in the menu - int menu_width, - int menu_height) +void +Menu::draw_item(DrawingContext& context, + int index, // Position of the current item in the menu + int menu_width, int menu_height) { - int font_width = 16; - - const menu_item_type& pitem = pmenu->item[index]; + MenuItem& pitem = item[index]; int effect_offset = 0; { int effect_time = 0; - if(timer_check(&pmenu->effect)) - effect_time = timer_get_left(&pmenu->effect) / 4; + + if(effect.check()) + effect_time = effect.get_left() / 4; effect_offset = (index % 2) ? effect_time : -effect_time; } - int x_pos = screen->w/2; - int y_pos = screen->h/2 + 24*index - menu_height/2 + 12 + effect_offset; + Font* text_font = white_text; + int x_pos = pos_x; + int y_pos = pos_y + 24*index - menu_height/2 + 12 + effect_offset; int shadow_size = 2; - int text_width = strlen(pitem.text) * font_width; - int input_width = strlen(pitem.input) * font_width; - int list_width = strlen(string_list_active(pitem.list)) * font_width; - text_type* text_font = &white_text; + 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 = + int(text_font->get_text_width(string_list_active(pitem.list))); - if(pmenu->arrange_left == YES) + if (arrange_left) x_pos += 24 - menu_width/2 + (text_width + input_width + list_width)/2; - - if(index == pmenu->active_item) - { - shadow_size = 3; - text_font = &blue_text; - } + + if(index == active_item) + { + shadow_size = 3; + text_font = blue_text; + } switch (pitem.kind) + { + case MN_DEACTIVE: { - case MN_DEACTIVE: - { - text_draw_align(&black_text, pitem.text, - x_pos, y_pos, - A_HMIDDLE, A_VMIDDLE, 2); - break; - } - - case MN_HL: - { - int x = screen->w/2 - menu_width/2; - int y = y_pos - 12 - effect_offset; - /* Draw a horizontal line with a little 3d effect */ - fillrect(x, y + 6, - menu_width, 4, - 210,50,50,225); - fillrect(x, y + 10 + 6, - menu_width, 2, - 0,0,0,255); - break; - } - case MN_LABEL: - { - text_draw_align(&white_big_text, pitem.text, - x_pos, y_pos, - A_HMIDDLE, A_VMIDDLE, 2); - break; - } - case MN_TEXTFIELD: - case MN_NUMFIELD: - { - int input_pos = input_width/2; - int text_pos = (text_width + font_width)/2; - - fillrect(x_pos - input_pos + text_pos - 1, y_pos - 10, - input_width + font_width + 2, 20, - 255,255,255,255); - fillrect(x_pos - input_pos + text_pos, y_pos - 9, - input_width + font_width, 18, - 0,0,0,128); - - text_draw_align(&gold_text, pitem.input, - x_pos + text_pos, y_pos, - A_HMIDDLE, A_VMIDDLE, 2); - - text_draw_align(text_font, pitem.text, - x_pos - (input_width + font_width)/2, y_pos, - A_HMIDDLE, A_VMIDDLE, shadow_size); - break; - } - case MN_STRINGSELECT: - { - int list_pos_2 = list_width + font_width; - int list_pos = list_width/2; - int text_pos = (text_width + font_width)/2; - - /* Draw arrows */ - texture_draw(&arrow_left, x_pos - list_pos + text_pos - 17, y_pos - 8); - texture_draw(&arrow_right, x_pos - list_pos + text_pos - 1 + list_pos_2, y_pos - 8); - - /* Draw input background */ - fillrect(x_pos - list_pos + text_pos - 1, y_pos - 10, - list_pos_2 + 2, 20, - 255,255,255,255); - fillrect(x_pos - list_pos + text_pos, y_pos - 9, - list_pos_2, 18, - 0,0,0,128); - - text_draw_align(&gold_text, string_list_active(pitem.list), - x_pos + text_pos, y_pos, - A_HMIDDLE, A_VMIDDLE,2); - - text_draw_align(text_font, pitem.text, - x_pos - list_pos_2/2, y_pos, - A_HMIDDLE, A_VMIDDLE, shadow_size); - break; - } - case MN_BACK: - { - text_draw_align(text_font, pitem.text, x_pos, y_pos, A_HMIDDLE, A_VMIDDLE, shadow_size); - texture_draw(&back, x_pos + text_width/2 + font_width, y_pos - 8); - break; - } + context.draw_text_center(blue_text, pitem.text, + Vector(0, y_pos - int(blue_text->get_height()/2)), + LAYER_FOREGROUND1); + break; + } - case MN_TOGGLE: + case MN_HL: + { + // TODO + int x = pos_x - menu_width/2; + int y = y_pos - 12 - effect_offset; + /* 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_FOREGROUND1); + context.draw_filled_rect(Vector(x, y + 6), + Vector(menu_width, 2), Color(255,255,255,255), LAYER_FOREGROUND1); + break; + } + case MN_LABEL: + { + context.draw_text_center(white_big_text, + pitem.text, Vector(0, y_pos - int(white_big_text->get_height()/2)), + LAYER_FOREGROUND1); + break; + } + case MN_TEXTFIELD: + case MN_NUMFIELD: + case MN_CONTROLFIELD_KB: + case MN_CONTROLFIELD_JS: + { + int width = text_width + input_width + 5; + int text_pos = screen->w/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_FOREGROUND1-5); + context.draw_filled_rect( + Vector(input_pos - 4, y_pos - 9), + Vector(input_width + 8, 18), + Color(0,0,0,128), LAYER_FOREGROUND1-4); + + if(pitem.kind == MN_CONTROLFIELD_KB) + get_controlfield_key_into_input(&pitem); + else if (pitem.kind == MN_CONTROLFIELD_JS) + get_controlfield_js_into_input(&pitem); + + if(pitem.kind == MN_TEXTFIELD || pitem.kind == MN_NUMFIELD) { - text_draw_align(text_font, pitem.text, x_pos, y_pos, A_HMIDDLE, A_VMIDDLE, shadow_size); - - if(pitem.toggled == YES) - texture_draw(&checkbox_checked, - x_pos + (text_width+font_width)/2, - y_pos - 8); + if(active_item == index) + context.draw_text(gold_text, + pitem.get_input_with_symbol(true), + Vector(input_pos, y_pos - int(gold_text->get_height()/2)), + LAYER_FOREGROUND1); else - texture_draw(&checkbox, - x_pos + (text_width+font_width)/2, - y_pos - 8); - break; + context.draw_text(gold_text, + pitem.get_input_with_symbol(false), + Vector(input_pos, y_pos - int(gold_text->get_height()/2)), + LAYER_FOREGROUND1); } - case MN_ACTION: - text_draw_align(text_font, pitem.text, x_pos, y_pos, A_HMIDDLE, A_VMIDDLE, shadow_size); + else + context.draw_text(gold_text, pitem.input, + Vector(input_pos, y_pos - int(gold_text->get_height()/2)), + LAYER_FOREGROUND1); + + context.draw_text(text_font, pitem.text, + Vector(text_pos, y_pos - int(text_font->get_height()/2)), + LAYER_FOREGROUND1); break; + } + case MN_STRINGSELECT: + { + int list_pos_2 = list_width + 16; + int list_pos = list_width/2; + int text_pos = (text_width + 16)/2; + + /* Draw arrows */ + context.draw_surface(arrow_left, + Vector(x_pos - list_pos + text_pos - 17, y_pos - 8), + LAYER_FOREGROUND1); + context.draw_surface(arrow_right, + Vector(x_pos - list_pos + text_pos - 1 + list_pos_2, y_pos - 8), + LAYER_FOREGROUND1); + + /* 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_FOREGROUND1 - 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_FOREGROUND1 - 5); + + context.draw_text_center(text_font, string_list_active(pitem.list), + Vector(text_pos, y_pos - int(text_font->get_height()/2)), + LAYER_FOREGROUND1); + context.draw_text_center(text_font, pitem.text, + Vector(list_pos_2/2, y_pos - int(text_font->get_height()/2)), + LAYER_FOREGROUND1); + break; + } + case MN_BACK: + { + context.draw_text_center(text_font, pitem.text, + Vector(0, y_pos - int(text_font->get_height()/2)), + LAYER_FOREGROUND1); + context.draw_surface(back, + Vector(x_pos + text_width/2 + 16, y_pos - 8), + LAYER_FOREGROUND1); + break; + } - case MN_GOTO: - text_draw_align(text_font, pitem.text, x_pos, y_pos, A_HMIDDLE, A_VMIDDLE, shadow_size); + case MN_TOGGLE: + { + context.draw_text_center(text_font, pitem.text, + Vector(0, y_pos - (text_font->get_height()/2)), + LAYER_FOREGROUND1); + + if(pitem.toggled) + context.draw_surface(checkbox_checked, + Vector(x_pos + (text_width+16)/2, y_pos - 8), + LAYER_FOREGROUND1 + 1); + else + context.draw_surface(checkbox, + Vector(x_pos + (text_width+16)/2, y_pos - 8), + LAYER_FOREGROUND1 + 1); break; } + case MN_ACTION: + context.draw_text_center(text_font, pitem.text, + Vector(0, y_pos - int(text_font->get_height()/2)), + LAYER_FOREGROUND1); + break; + + case MN_GOTO: + context.draw_text_center(text_font, pitem.text, + Vector(0, y_pos - int(text_font->get_height()/2)), + LAYER_FOREGROUND1); + break; + } } -/* Draw the current menu. */ -void menu_draw(menu_type* pmenu) +int Menu::get_width() const { - int y; - int menu_height; - int menu_width; - - /* The width of the menu has to be more than the width of the text with the most characters */ - menu_width = 0; - for(int i = 0; i < pmenu->num_items; ++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 < item.size(); ++i) + { + int w = strlen(item[i].text) + (item[i].input ? strlen(item[i].input) + 1 : 0) + strlen(string_list_active(item[i].list)); + if( w > menu_width ) { - y = strlen(pmenu->item[i].text) + (pmenu->item[i].input ? strlen(pmenu->item[i].input) + 1 : 0) + strlen(string_list_active(pmenu->item[i].list)); - if( y > menu_width ) - { - menu_width = y; - if( pmenu->item[i].kind == MN_TOGGLE) - menu_width += 2; - } + menu_width = w; + if( item[i].kind == MN_TOGGLE) + menu_width += 2; } + } - menu_width = menu_width * 16 + 48; - menu_height = (pmenu->num_items) * 24; + return (menu_width * 16 + 24); +} + +int Menu::get_height() const +{ + return item.size() * 24; +} + +/* Draw the current menu. */ +void +Menu::draw(DrawingContext& context) +{ + int menu_height = get_height(); + int menu_width = get_width(); - int center_x = screen->w/2; /* Draw a transparent background */ - fillrect(center_x - menu_width/2,screen->h/2-(((pmenu->num_items)*24)/2),menu_width,menu_height,150,150,150,100); + context.draw_filled_rect( + Vector(pos_x - menu_width/2, pos_y - 24*item.size()/2 - 10), + Vector(menu_width,menu_height + 20), + Color(150,180,200,125), LAYER_FOREGROUND1-10); - for(int i = 0; i < pmenu->num_items; ++i) - { - menu_draw_item(pmenu, i, menu_width, menu_height); - } + for(unsigned int i = 0; i < item.size(); ++i) + { + draw_item(context, i, menu_width, menu_height); + } } -/* Reset/Set global defaults */ -void menu_reset(void) +MenuItem& +Menu::get_item_by_id(int id) { - menu_change = NO; - show_menu = NO; - menuaction = MENU_ACTION_NONE; - current_menu = NULL; - last_menu = NULL; + for(std::vector::iterator i = item.begin(); i != item.end(); ++i) + { + if(i->id == id) + return *i; + } - delete_character = 0; - mn_input_char = '\0'; + assert(false); + static MenuItem dummyitem; + return dummyitem; } -/* --- MENU --- */ -/* Draw the current menu and execute the (menu)events */ -void menu_process_current(void) +int Menu::get_active_item_id() { - menu_change = NO; - - if(current_menu != NULL) - { - menu_action(current_menu); - menu_draw(current_menu); - } + return item[active_item].id; +} - menuaction = MENU_ACTION_NONE; +bool +Menu::isToggled(int id) +{ + return get_item_by_id(id).toggled; } /* Check for menu event */ -void menu_event(SDL_keysym* keysym) +void +Menu::event(SDL_Event& event) { - SDLKey key = keysym->sym; - SDLMod keymod; - char ch[2]; - keymod = SDL_GetModState(); - - /* If the current unicode character is an ASCII character, - assign it to ch. */ - if ( (keysym->unicode & 0xFF80) == 0 ) + SDLKey key; + switch(event.type) + { + case SDL_KEYDOWN: + key = event.key.keysym.sym; + SDLMod keymod; + char ch[2]; + keymod = SDL_GetModState(); + int x,y; + + /* If the current unicode character is an ASCII character, + assign it to ch. */ + if ( (event.key.keysym.unicode & 0xFF80) == 0 ) { - ch[0] = keysym->unicode & 0x7F; + ch[0] = event.key.keysym.unicode & 0x7F; ch[1] = '\0'; } - else + else { /* An International Character. */ } - switch(key) + if(item[active_item].kind == MN_CONTROLFIELD_KB) + { + if(key == SDLK_ESCAPE) + { + Menu::pop_current(); + return; + } + *item[active_item].int_p = key; + menuaction = MENU_ACTION_DOWN; + return; + } + + + switch(key) { case SDLK_UP: /* Menu Up */ menuaction = MENU_ACTION_UP; - menu_change = YES; break; case SDLK_DOWN: /* Menu Down */ menuaction = MENU_ACTION_DOWN; - menu_change = YES; break; case SDLK_LEFT: /* Menu Up */ menuaction = MENU_ACTION_LEFT; - menu_change = YES; break; case SDLK_RIGHT: /* Menu Down */ menuaction = MENU_ACTION_RIGHT; - menu_change = YES; break; case SDLK_SPACE: - if(current_menu->item[current_menu->active_item].kind == MN_TEXTFIELD) + if(item[active_item].kind == MN_TEXTFIELD) { - menuaction = MENU_ACTION_INPUT; - menu_change = YES; - mn_input_char = ' '; - break; + menuaction = MENU_ACTION_INPUT; + mn_input_char = ' '; + break; } case SDLK_RETURN: /* Menu Hit */ menuaction = MENU_ACTION_HIT; - menu_change = YES; break; case SDLK_DELETE: case SDLK_BACKSPACE: menuaction = MENU_ACTION_REMOVE; - menu_change = YES; delete_character++; break; + case SDLK_ESCAPE: + Menu::pop_current(); + break; default: if( (key >= SDLK_0 && key <= SDLK_9) || (key >= SDLK_a && key <= SDLK_z) || (key >= SDLK_SPACE && key <= SDLK_SLASH)) - { - menuaction = MENU_ACTION_INPUT; - menu_change = YES; - mn_input_char = *ch; - } + { + menuaction = MENU_ACTION_INPUT; + mn_input_char = *ch; + } else - { - mn_input_char = '\0'; - } + { + mn_input_char = '\0'; + } break; } - - - /* FIXME: NO JOYSTICK SUPPORT */ - /*#ifdef JOY_YES - else if (event.type == SDL_JOYBUTTONDOWN) - { - Joystick button: Continue: - - done = 1; - } - #endif*/ + break; + case SDL_JOYAXISMOTION: + if(event.jaxis.axis == joystick_keymap.y_axis) + { + if (event.jaxis.value > joystick_keymap.dead_zone && !joystick_timer.started()) + { + menuaction = MENU_ACTION_DOWN; + joystick_timer.start(JOYSTICK_MENU_DELAY); + } + else if (event.jaxis.value < -joystick_keymap.dead_zone && !joystick_timer.started()) + { + menuaction = MENU_ACTION_UP; + joystick_timer.start(JOYSTICK_MENU_DELAY); + } + else + joystick_timer.stop(); + } + break; + case SDL_JOYBUTTONDOWN: + if (item[active_item].kind == MN_CONTROLFIELD_JS) + { + *item[active_item].int_p = key; + menuaction = MENU_ACTION_DOWN; + } + menuaction = MENU_ACTION_HIT; + break; + case SDL_MOUSEBUTTONDOWN: + x = event.motion.x; + y = event.motion.y; + 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) + { + menuaction = MENU_ACTION_HIT; + } + break; + case SDL_MOUSEMOTION: + x = event.motion.x; + y = event.motion.y; + 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) + { + active_item = (y - (pos_y - get_height()/2)) / 24; + mouse_cursor->set_state(MC_LINK); + } + else + { + mouse_cursor->set_state(MC_NORMAL); + } + break; + default: + break; + } } -menu_item_type* -menu_additem(menu_type* pmenu, MenuItemKind kind, char *text, int init_toggle, void* target_menu) -{ - menu_item_type* item = menu_item_create(kind, text, init_toggle, target_menu); - menu_additem(pmenu, item); - return item; -} // EOF //