-// $Id$
-//
// SuperTux
// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
//
-// 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 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 3 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
// 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.
-
-#include <config.h>
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
-#include <sys/types.h>
-#include <ctype.h>
+#include "gui/menu.hpp"
-#include <iostream>
-#include <sstream>
-#include <cstdlib>
-#include <cstdio>
-#include <string>
-#include <cassert>
+#include <math.h>
#include <stdexcept>
-#include "menu.hpp"
-#include "mainloop.hpp"
+#include "control/input_manager.hpp"
+#include "gui/menu_item.hpp"
+#include "gui/menu_manager.hpp"
+#include "gui/mousecursor.hpp"
+#include "supertux/colorscheme.hpp"
+#include "supertux/globals.hpp"
+#include "supertux/resources.hpp"
+#include "supertux/screen_manager.hpp"
+#include "supertux/timer.hpp"
+#include "util/gettext.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 float MENU_REPEAT_INITIAL = 0.4;
-static const float MENU_REPEAT_RATE = 0.2;
-static const float FLICK_CURSOR_TIME = 0.5;
-
-extern SDL_Surface* screen;
-
-std::vector<Menu*> Menu::last_menus;
-Menu* Menu::current_ = 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_hl();
- 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)
- main_loop->quit();
- main_controller->process_event(event);
- dialog->event(event);
- }
-
- if(background == NULL)
- context.draw_gradient(Color(0.8, 0.95, 0.85), Color(0.8, 0.8, 0.8),
- LAYER_BACKGROUND0);
- else
- context.draw_surface(background, Vector(0,0), LAYER_BACKGROUND0);
-
- dialog->draw(context);
- dialog->update();
-
- 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_time = real_time;
-}
-
-void
-Menu::pop_current()
-{
- if (last_menus.size() >= 1) {
- current_ = last_menus.back();
- current_->effect_time = real_time;
- last_menus.pop_back();
- } else {
- current_ = 0;
- }
-}
-
-void
-Menu::set_current(Menu* menu)
+#include "video/font.hpp"
+#include "video/renderer.hpp"
+#include "video/video_system.hpp"
+
+static const float MENU_REPEAT_INITIAL = 0.4f;
+static const float MENU_REPEAT_RATE = 0.1f;
+
+Menu::Menu() :
+ pos(),
+ delete_character(),
+ mn_input_char(),
+ menu_repeat_time(),
+ items(),
+ arrange_left(),
+ active_item()
{
- last_menus.clear();
-
- if (menu)
- menu->effect_time = real_time;
-
- current_ = menu;
- // just to be sure...
- main_controller->reset();
-}
-
-MenuItem::MenuItem(MenuItemKind _kind, int _id)
- : kind(_kind) , id(_id)
-{
- toggled = false;
- selected = false;
- target_menu = 0;
-}
-
-void
-MenuItem::change_text(const std::string& text_)
-{
- text = text_;
-}
-
-void
-MenuItem::change_input(const std::string& text_)
-{
- input = text_;
-}
-
-std::string MenuItem::get_input_with_symbol(bool active_item)
-{
- if(!active_item) {
- input_flickering = true;
- } else {
- input_flickering = ((int) (real_time / FLICK_CURSOR_TIME)) % 2;
- }
-
- char str[1024];
- if(input_flickering)
- snprintf(str, sizeof(str), "%s ",input.c_str());
- else
- snprintf(str, sizeof(str), "%s_",input.c_str());
-
- std::string string = str;
-
- return string;
-}
-
-Menu::~Menu()
-{
- for(std::vector<MenuItem*>::iterator i = items.begin();
- i != items.end(); ++i)
- delete *i;
- if(current_ == this)
- current_ = NULL;
-}
-
-Menu::Menu()
-{
- hit_item = -1;
- menuaction = MENU_ACTION_NONE;
delete_character = 0;
mn_input_char = '\0';
- pos_x = SCREEN_WIDTH/2;
- pos_y = SCREEN_HEIGHT/2;
+ pos.x = SCREEN_WIDTH/2;
+ pos.y = SCREEN_HEIGHT/2;
arrange_left = 0;
active_item = -1;
+}
- 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"));
+Menu::~Menu()
+{
}
-void Menu::set_pos(float x, float y, float rw, float rh)
+void
+Menu::set_center_pos(float x, float y)
{
- pos_x = x + get_width() * rw;
- pos_y = y + get_height() * rh;
+ pos.x = x;
+ pos.y = y;
}
/* Add an item to a menu */
-void
-Menu::additem(MenuItem* item)
+MenuItem*
+Menu::add_item(std::unique_ptr<MenuItem> new_item)
{
- items.push_back(item);
+ items.push_back(std::move(new_item));
+ MenuItem* item = items.back().get();
/* 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;
}
+
+ return item;
}
-void
+MenuItem*
Menu::add_hl()
{
- additem(new MenuItem(MN_HL));
+ std::unique_ptr<MenuItem> item(new MenuItem(MN_HL));
+ return add_item(std::move(item));
}
-void
+MenuItem*
Menu::add_label(const std::string& text)
{
- MenuItem* item = new MenuItem(MN_LABEL);
+ std::unique_ptr<MenuItem> item(new MenuItem(MN_LABEL));
item->text = text;
- additem(item);
+ return add_item(std::move(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);
+ std::unique_ptr<MenuItem> item(new MenuItem(MN_CONTROLFIELD, id));
item->change_text(text);
- item->change_input(mapping);
- additem(item);
+ item->change_input(mapping);
+ return add_item(std::move(item));
}
-void
+MenuItem*
Menu::add_entry(int id, const std::string& text)
{
- MenuItem* item = new MenuItem(MN_ACTION, id);
+ std::unique_ptr<MenuItem> item(new MenuItem(MN_ACTION, id));
item->text = text;
- additem(item);
+ return add_item(std::move(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);
+ std::unique_ptr<MenuItem> item(new MenuItem(MN_INACTIVE, id));
item->text = text;
- additem(item);
+ return add_item(std::move(item));
}
-void
+MenuItem*
Menu::add_toggle(int id, const std::string& text, bool toogled)
{
- MenuItem* item = new MenuItem(MN_TOGGLE, id);
+ std::unique_ptr<MenuItem> item(new MenuItem(MN_TOGGLE, id));
item->text = text;
item->toggled = toogled;
- additem(item);
+ return add_item(std::move(item));
}
-void
+MenuItem*
+Menu::add_string_select(int id, const std::string& text)
+{
+ std::unique_ptr<MenuItem> item(new MenuItem(MN_STRINGSELECT, id));
+ item->text = text;
+ return add_item(std::move(item));
+}
+
+MenuItem*
Menu::add_back(const std::string& text)
{
- MenuItem* item = new MenuItem(MN_BACK);
+ std::unique_ptr<MenuItem> item(new MenuItem(MN_BACK));
item->text = text;
- additem(item);
+ return add_item(std::move(item));
}
-void
-Menu::add_submenu(const std::string& text, Menu* submenu, int id)
+MenuItem*
+Menu::add_submenu(const std::string& text, int submenu)
{
- MenuItem* item = new MenuItem(MN_GOTO, id);
+ std::unique_ptr<MenuItem> item(new MenuItem(MN_GOTO));
item->text = text;
item->target_menu = submenu;
- additem(item);
+ return add_item(std::move(item));
}
void
Menu::clear()
{
- for(std::vector<MenuItem*>::iterator i = items.begin();
- i != items.end(); ++i) {
- delete *i;
- }
items.clear();
active_item = -1;
}
-/* Process actions done on the menu */
void
-Menu::update()
+Menu::process_input()
{
+ 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;
+ }
+
+ MenuAction menuaction = MENU_ACTION_NONE;
+ Controller* controller = InputManager::current()->get_controller();
/** check main input controller... */
- if(main_controller->pressed(Controller::UP)) {
+ if(controller->pressed(Controller::UP)) {
menuaction = MENU_ACTION_UP;
menu_repeat_time = real_time + MENU_REPEAT_INITIAL;
}
- if(main_controller->hold(Controller::UP) &&
- menu_repeat_time != 0 && real_time > menu_repeat_time) {
+ if(controller->hold(Controller::UP) &&
+ menu_repeat_time != 0 && real_time > menu_repeat_time) {
menuaction = MENU_ACTION_UP;
menu_repeat_time = real_time + MENU_REPEAT_RATE;
}
- if(main_controller->pressed(Controller::DOWN)) {
+
+ if(controller->pressed(Controller::DOWN)) {
menuaction = MENU_ACTION_DOWN;
menu_repeat_time = real_time + MENU_REPEAT_INITIAL;
}
- if(main_controller->hold(Controller::DOWN) &&
- menu_repeat_time != 0 && real_time > menu_repeat_time) {
+ if(controller->hold(Controller::DOWN) &&
+ menu_repeat_time != 0 && real_time > menu_repeat_time) {
menuaction = MENU_ACTION_DOWN;
menu_repeat_time = real_time + MENU_REPEAT_RATE;
}
- if(main_controller->pressed(Controller::JUMP)
- || main_controller->pressed(Controller::ACTION)
- || main_controller->pressed(Controller::MENU_SELECT)) {
+
+ if(controller->pressed(Controller::LEFT)) {
+ menuaction = MENU_ACTION_LEFT;
+ menu_repeat_time = real_time + MENU_REPEAT_INITIAL;
+ }
+ if(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(controller->pressed(Controller::RIGHT)) {
+ menuaction = MENU_ACTION_RIGHT;
+ menu_repeat_time = real_time + MENU_REPEAT_INITIAL;
+ }
+ if(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(controller->pressed(Controller::ACTION)
+ || controller->pressed(Controller::MENU_SELECT)) {
menuaction = MENU_ACTION_HIT;
}
- if(main_controller->pressed(Controller::PAUSE_MENU)) {
+ if(controller->pressed(Controller::ESCAPE) ||
+ controller->pressed(Controller::START) ||
+ controller->pressed(Controller::MENU_BACK)) {
menuaction = MENU_ACTION_BACK;
}
- hit_item = -1;
if(items.size() == 0)
return;
+ // The menu_action() call can pop() the menu from the stack and thus
+ // delete it, so it's important that no further member variables are
+ // accessed after this call
+ process_action(menuaction);
+}
+
+void
+Menu::process_action(MenuAction menuaction)
+{
int last_active_item = active_item;
switch(menuaction) {
case MENU_ACTION_UP:
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;
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;
items[active_item]->selected--;
else
items[active_item]->selected = items[active_item]->list.size()-1;
+
+ menu_action(items[active_item].get());
}
break;
items[active_item]->selected++;
else
items[active_item]->selected = 0;
+
+ menu_action(items[active_item].get());
}
break;
case MENU_ACTION_HIT: {
- hit_item = active_item;
switch (items[active_item]->kind) {
case MN_GOTO:
assert(items[active_item]->target_menu != 0);
- Menu::push_current(items[active_item]->target_menu);
+ MenuManager::instance().push_menu(items[active_item]->target_menu);
break;
case MN_TOGGLE:
items[active_item]->toggled = !items[active_item]->toggled;
- menu_action(items[active_item]);
+ menu_action(items[active_item].get());
break;
case MN_CONTROLFIELD:
- menu_action(items[active_item]);
+ menu_action(items[active_item].get());
break;
case MN_ACTION:
- menu_action(items[active_item]);
+ menu_action(items[active_item].get());
+ 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].get());
break;
case MN_TEXTFIELD:
case MN_NUMFIELD:
menuaction = MENU_ACTION_DOWN;
- update();
+ process_input();
break;
case MN_BACK:
- Menu::pop_current();
- break;
+ MenuManager::instance().pop_menu();
+ return;
+
default:
break;
}
{
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--;
break;
case MENU_ACTION_BACK:
- Menu::pop_current();
- break;
+ MenuManager::instance().pop_menu();
+ return;
case MENU_ACTION_NONE:
break;
}
- menuaction = MENU_ACTION_NONE;
-
- assert(active_item < int(items.size()));
-}
-
-int
-Menu::check()
-{
- if (hit_item != -1)
- return items[hit_item]->id;
- else
- return -1;
}
void
-Menu::menu_action(MenuItem* )
-{}
-
-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;
- 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);
+ Color text_color = ColorScheme::Menu::default_color;
+ float x_pos = pos.x;
+ float y_pos = pos.y + 24*index - menu_height/2 + 12;
+ int text_width = int(Resources::normal_font->get_text_width(pitem.text));
+ int input_width = int(Resources::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) Resources::normal_font->get_text_width(pitem.list[pitem.selected]);
}
if (arrange_left)
x_pos += 24 - menu_width/2 + (text_width + input_width + list_width)/2;
if(index == active_item)
- {
- shadow_size = 3;
- text_font = active_font;
- }
+ {
+ text_color = ColorScheme::Menu::active_color;
+ }
+
+ 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(Rectf(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(Rectf(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_INACTIVE:
{
- 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);
- break;
- }
+ context.draw_text(Resources::normal_font, pitem.text,
+ Vector(pos.x, y_pos - int(Resources::normal_font->get_height()/2)),
+ ALIGN_CENTER, LAYER_GUI, ColorScheme::Menu::inactive_color);
+ break;
+ }
case MN_HL:
- {
- // TODO
- float x = pos_x - menu_width/2;
- float 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(0.6f, 0.7f, 1.0f, 1.0f), LAYER_GUI);
- context.draw_filled_rect(Vector(x, y + 6),
- Vector(menu_width, 2),
- Color(1.0f, 1.0f, 1.0f, 1.0f), LAYER_GUI);
- break;
- }
+ {
+ // TODO
+ 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(0.6f, 0.7f, 1.0f, 1.0f), LAYER_GUI);
+ context.draw_filled_rect(Vector(x, y + 6),
+ 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);
- break;
- }
+ {
+ context.draw_text(Resources::big_font, pitem.text,
+ Vector(pos.x, y_pos - int(Resources::big_font->get_height()/2)),
+ ALIGN_CENTER, LAYER_GUI, ColorScheme::Menu::label_color);
+ break;
+ }
case MN_TEXTFIELD:
case MN_NUMFIELD:
case MN_CONTROLFIELD:
+ {
+ if(pitem.kind == MN_TEXTFIELD || pitem.kind == MN_NUMFIELD)
{
- 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);
-
- 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);
- 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);
- }
+ if(active_item == index)
+ context.draw_text(Resources::normal_font,
+ pitem.get_input_with_symbol(true),
+ Vector(right, y_pos - int(Resources::normal_font->get_height()/2)),
+ ALIGN_RIGHT, LAYER_GUI, ColorScheme::Menu::field_color);
else
- context.draw_text(field_font, pitem.input,
- Vector(input_pos, y_pos - int(field_font->get_height()/2)),
- LEFT_ALLIGN, LAYER_GUI);
-
- context.draw_text(text_font, pitem.text,
- Vector(text_pos, y_pos - int(text_font->get_height()/2)),
- LEFT_ALLIGN, LAYER_GUI);
- break;
+ context.draw_text(Resources::normal_font,
+ pitem.get_input_with_symbol(false),
+ Vector(right, y_pos - int(Resources::normal_font->get_height()/2)),
+ ALIGN_RIGHT, LAYER_GUI, ColorScheme::Menu::field_color);
}
+ else
+ context.draw_text(Resources::normal_font, pitem.input,
+ Vector(right, y_pos - int(Resources::normal_font->get_height()/2)),
+ ALIGN_RIGHT, LAYER_GUI, ColorScheme::Menu::field_color);
+
+ context.draw_text(Resources::normal_font, pitem.text,
+ Vector(left, y_pos - int(Resources::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;
-
- /* Draw arrows */
- context.draw_surface(arrow_left.get(),
- Vector(x_pos - list_pos + text_pos - 17, 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),
- 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)),
- 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);
- break;
- }
+ {
+ float roff = Resources::arrow_left->get_width();
+ // Draw left side
+ context.draw_text(Resources::normal_font, pitem.text,
+ Vector(left, y_pos - int(Resources::normal_font->get_height()/2)),
+ ALIGN_LEFT, LAYER_GUI, text_color);
+
+ // Draw right side
+ context.draw_surface(Resources::arrow_left,
+ Vector(right - list_width - roff - roff, y_pos - 8),
+ LAYER_GUI);
+ context.draw_surface(Resources::arrow_right,
+ Vector(right - roff, y_pos - 8),
+ LAYER_GUI);
+ context.draw_text(Resources::normal_font, pitem.list[pitem.selected],
+ Vector(right - roff, y_pos - int(Resources::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)),
- CENTER_ALLIGN, LAYER_GUI);
- context.draw_surface(back.get(),
- Vector(x_pos + text_width/2 + 16, y_pos - 8),
- LAYER_GUI);
- break;
- }
+ {
+ context.draw_text(Resources::Resources::normal_font, pitem.text,
+ Vector(pos.x, y_pos - int(Resources::normal_font->get_height()/2)),
+ ALIGN_CENTER, LAYER_GUI, text_color);
+ context.draw_surface(Resources::back,
+ Vector(x_pos + text_width/2 + 16, y_pos - 8),
+ LAYER_GUI);
+ break;
+ }
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);
-
- if(pitem.toggled)
- context.draw_surface(checkbox_checked.get(),
- Vector(x_pos + (text_width+16)/2, y_pos - 8),
- LAYER_GUI + 1);
- else
- context.draw_surface(checkbox.get(),
- Vector(x_pos + (text_width+16)/2, y_pos - 8),
- LAYER_GUI + 1);
- break;
- }
+ {
+ context.draw_text(Resources::normal_font, pitem.text,
+ Vector(pos.x - menu_width/2 + 16, y_pos - (Resources::normal_font->get_height()/2)),
+ ALIGN_LEFT, LAYER_GUI, text_color);
+
+ if(pitem.toggled)
+ context.draw_surface(Resources::checkbox_checked,
+ Vector(x_pos + (menu_width/2-16) - Resources::checkbox->get_width(), y_pos - 8),
+ LAYER_GUI + 1);
+ else
+ context.draw_surface(Resources::checkbox,
+ Vector(x_pos + (menu_width/2-16) - Resources::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);
+ context.draw_text(Resources::normal_font, pitem.text,
+ Vector(pos.x, y_pos - int(Resources::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)),
- CENTER_ALLIGN, LAYER_GUI);
+ context.draw_text(Resources::normal_font, pitem.text,
+ Vector(pos.x, y_pos - int(Resources::normal_font->get_height()/2)),
+ ALIGN_CENTER, LAYER_GUI, text_color);
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 */
float menu_width = 0;
for(unsigned int i = 0; i < items.size(); ++i)
{
- Font* font = default_font;
+ FontPtr font = Resources::Resources::normal_font;
if(items[i]->kind == MN_LABEL)
- font = label_font;
+ font = Resources::big_font;
float w = font->get_text_width(items[i]->text) +
- label_font->get_text_width(items[i]->input) + 16;
+ Resources::big_font->get_text_width(items[i]->input) + 16;
if(items[i]->kind == MN_TOGGLE)
w += 32;
+ if (items[i]->kind == MN_STRINGSELECT)
+ w += font->get_text_width(items[i]->list[items[i]->selected]) + 32;
+
if(w > menu_width)
menu_width = w;
return menu_width + 24;
}
-float Menu::get_height() const
+float
+Menu::get_height() const
{
return items.size() * 24;
}
-/* Draw the current menu. */
+void
+Menu::on_window_resize()
+{
+ pos.x = SCREEN_WIDTH / 2;
+ pos.y = SCREEN_HEIGHT / 2;
+}
+
void
Menu::draw(DrawingContext& context)
{
- if(MouseCursor::current()) {
- MouseCursor::current()->draw(context);
+ if (!items[active_item]->help.empty())
+ {
+ int text_width = (int) Resources::normal_font->get_text_width(items[active_item]->help);
+ int text_height = (int) Resources::normal_font->get_text_height(items[active_item]->help);
+
+ Rectf 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(Rectf(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(Resources::normal_font, items[active_item]->help,
+ Vector(pos.x, SCREEN_HEIGHT - 48 - text_height/2),
+ ALIGN_CENTER, LAYER_GUI);
}
- 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)
- {
- draw_item(context, i);
- }
+ {
+ draw_item(context, i);
+ }
}
MenuItem&
Menu::get_item_by_id(int id)
{
- for(std::vector<MenuItem*>::iterator i = items.begin();
- i != items.end(); ++i) {
- MenuItem& item = **i;
-
- if(item.id == id)
- return item;
+ for (const auto& item : items)
+ {
+ if (item->id == id)
+ {
+ return *item;
+ }
}
- throw std::runtime_error("MenuItem not found");
+ throw std::runtime_error("MenuItem not found: " + std::to_string(id));
}
const MenuItem&
Menu::get_item_by_id(int id) const
{
- for(std::vector<MenuItem*>::const_iterator i = items.begin();
- i != items.end(); ++i) {
- const MenuItem& item = **i;
-
- if(item.id == id)
- return item;
+ for (const auto& item : items)
+ {
+ if (item->id == id)
+ {
+ return *item;
+ }
}
throw std::runtime_error("MenuItem not found");
return get_item_by_id(id).toggled;
}
-/* Check for menu event */
void
-Menu::event(const SDL_Event& event)
+Menu::set_toggled(int id, bool toggled)
{
- if(effect_time != 0)
- return;
+ get_item_by_id(id).toggled = toggled;
+}
- switch(event.type) {
+void
+Menu::event(const SDL_Event& ev)
+{
+ switch(ev.type) {
case SDL_MOUSEBUTTONDOWN:
+ if(ev.button.button == SDL_BUTTON_LEFT)
+ {
+ Vector mouse_pos = VideoSystem::current()->get_renderer().to_logical(ev.motion.x, ev.motion.y);
+ int x = int(mouse_pos.x);
+ int y = int(mouse_pos.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)
{
- int x = int(event.motion.x * float(SCREEN_WIDTH)/screen->w);
- int y = int(event.motion.y * float(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)
- {
- menuaction = MENU_ACTION_HIT;
- }
+ process_action(MENU_ACTION_HIT);
}
- break;
+ }
+ break;
case SDL_MOUSEMOTION:
+ {
+ Vector mouse_pos = VideoSystem::current()->get_renderer().to_logical(ev.motion.x, ev.motion.y);
+ float x = mouse_pos.x;
+ float y = mouse_pos.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)
{
- 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
- = static_cast<int> ((y - (pos_y - get_height()/2)) / 24);
+ int new_active_item
+ = static_cast<int> ((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;
+ /* 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_INACTIVE))
+ 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_LINK);
}
- break;
+ else
+ {
+ if(MouseCursor::current())
+ MouseCursor::current()->set_state(MC_NORMAL);
+ }
+ }
+ break;
default:
break;
- }
+ }
}
void
Menu::set_active_item(int id)
{
for(size_t i = 0; i < items.size(); ++i) {
- MenuItem* item = items[i];
- if(item->id == id) {
+ if(items[i]->id == id) {
active_item = i;
break;
}
}
}
+
+/* EOF */