}
bool
-Controller::hold(Control control)
+Controller::hold(Control control) const
{
return controls[control];
}
bool
-Controller::pressed(Control control)
+Controller::pressed(Control control) const
{
return !oldControls[control] && controls[control];
}
bool
-Controller::released(Control control)
+Controller::released(Control control) const
{
return oldControls[control] && !controls[control];
}
void set_control(Control control, bool value);
/** returns true if the control is pressed down */
- bool hold(Control control);
+ bool hold(Control control) const;
/** returns true if the control has just been pressed down this frame */
- bool pressed(Control control);
+ bool pressed(Control control) const;
/** returns true if the control has just been released this frame */
- bool released(Control control);
+ bool released(Control control) const;
virtual void reset();
virtual void update();
--- /dev/null
+// SuperTux
+// Copyright (C) 2014 Ingo Ruhnke <grumbel@gmail.com>
+//
+// 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
+// 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, see <http://www.gnu.org/licenses/>.
+
+#include "gui/dialog.hpp"
+
+#include "control/controller.hpp"
+#include "gui/menu_manager.hpp"
+#include "gui/menu.hpp"
+#include "gui/mousecursor.hpp"
+#include "supertux/resources.hpp"
+#include "supertux/colorscheme.hpp"
+#include "video/drawing_context.hpp"
+#include "video/renderer.hpp"
+#include "video/video_system.hpp"
+
+Dialog::Dialog() :
+ m_text(),
+ m_buttons(),
+ m_selected_button(),
+ m_text_size()
+{
+}
+
+Dialog::~Dialog()
+{
+}
+
+void
+Dialog::set_text(const std::string& text)
+{
+ m_text = text;
+
+ m_text_size = Sizef(Resources::normal_font->get_text_width(m_text),
+ Resources::normal_font->get_text_height(m_text));
+
+}
+
+void
+Dialog::add_button(const std::string& text, const std::function<void ()>& callback, bool focus)
+{
+ m_buttons.push_back({text, callback});
+
+ if (focus)
+ {
+ m_selected_button = m_buttons.size() - 1;
+ }
+}
+
+int
+Dialog::get_button_at(const Vector& mouse_pos) const
+{
+ Rectf bg_rect(Vector(SCREEN_WIDTH/2 - m_text_size.width/2,
+ SCREEN_HEIGHT/2 - m_text_size.height/2),
+ Sizef(m_text_size.width,
+ m_text_size.height + 44));
+
+ for(int i = 0; i < static_cast<int>(m_buttons.size()); ++i)
+ {
+ float segment_width = bg_rect.get_width() / m_buttons.size();
+ float button_width = segment_width;
+ float button_height = 24.0f;
+ Vector pos(bg_rect.p1.x + segment_width/2.0f + i * segment_width,
+ bg_rect.p2.y - 12);
+ Rectf button_rect(Vector(pos.x - button_width/2, pos.y - button_height/2),
+ Vector(pos.x + button_width/2, pos.y + button_height/2));
+ if (button_rect.contains(mouse_pos))
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+void
+Dialog::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 new_button = get_button_at(mouse_pos);
+ if (new_button != -1)
+ {
+ m_selected_button = new_button;
+ on_button_click(m_selected_button);
+
+ // warning: this will "delete this"
+ MenuManager::instance().set_dialog({});
+ }
+ }
+ break;
+
+ case SDL_MOUSEMOTION:
+ {
+ Vector mouse_pos = VideoSystem::current()->get_renderer().to_logical(ev.motion.x, ev.motion.y);
+ int new_button = get_button_at(mouse_pos);
+ if (new_button != -1)
+ {
+ m_selected_button = new_button;
+ if(MouseCursor::current())
+ MouseCursor::current()->set_state(MC_LINK);
+ }
+ else
+ {
+ if(MouseCursor::current())
+ MouseCursor::current()->set_state(MC_NORMAL);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void
+Dialog::process_input(const Controller& controller)
+{
+ if (controller.pressed(Controller::LEFT))
+ {
+ m_selected_button -= 1;
+ m_selected_button = std::max(m_selected_button, 0);
+ }
+
+ if (controller.pressed(Controller::RIGHT))
+ {
+ m_selected_button += 1;
+ m_selected_button = std::min(m_selected_button, static_cast<int>(m_buttons.size()) - 1);
+ }
+
+ if (controller.pressed(Controller::ACTION) ||
+ controller.pressed(Controller::MENU_SELECT))
+ {
+ on_button_click(m_selected_button);
+
+ // warning: this will "delete this"
+ MenuManager::instance().set_dialog({});
+ }
+}
+
+void
+Dialog::draw(DrawingContext& ctx)
+{
+ Rectf bg_rect(Vector(SCREEN_WIDTH/2 - m_text_size.width/2,
+ SCREEN_HEIGHT/2 - m_text_size.height/2),
+ Sizef(m_text_size.width,
+ m_text_size.height + 44));
+
+ // draw background rect
+ ctx.draw_filled_rect(bg_rect.grown(12.0f),
+ Color(0.2f, 0.3f, 0.4f, 0.8f),
+ 16.0f,
+ LAYER_GUI-10);
+
+ ctx.draw_filled_rect(bg_rect.grown(8.0f),
+ Color(0.6f, 0.7f, 0.8f, 0.5f),
+ 16.0f,
+ LAYER_GUI-10);
+
+ // draw text
+ ctx.draw_text(Resources::normal_font, m_text,
+ Vector(bg_rect.p1.x + bg_rect.get_width()/2.0f,
+ bg_rect.p1.y),
+ ALIGN_CENTER, LAYER_GUI);
+
+ // draw HL line
+ ctx.draw_filled_rect(Vector(bg_rect.p1.x, bg_rect.p2.y - 35),
+ Vector(bg_rect.get_width(), 4),
+ Color(0.6f, 0.7f, 1.0f, 1.0f), LAYER_GUI);
+ ctx.draw_filled_rect(Vector(bg_rect.p1.x, bg_rect.p2.y - 35),
+ Vector(bg_rect.get_width(), 2),
+ Color(1.0f, 1.0f, 1.0f, 1.0f), LAYER_GUI);
+
+ // draw buttons
+ for(int i = 0; i < static_cast<int>(m_buttons.size()); ++i)
+ {
+ float segment_width = bg_rect.get_width() / m_buttons.size();
+ float button_width = segment_width;
+ float button_height = 24.0f;
+ Vector pos(bg_rect.p1.x + segment_width/2.0f + i * segment_width,
+ bg_rect.p2.y - 12);
+
+ if (i == m_selected_button)
+ {
+ float blink = (sinf(real_time * M_PI * 1.0f)/2.0f + 0.5f) * 0.5f + 0.25f;
+ ctx.draw_filled_rect(Rectf(Vector(pos.x - button_width/2, pos.y - button_height/2),
+ Vector(pos.x + button_width/2, pos.y + button_height/2)).grown(2.0f),
+ Color(1.0f, 1.0f, 1.0f, blink),
+ 14.0f,
+ LAYER_GUI-10);
+ ctx.draw_filled_rect(Rectf(Vector(pos.x - button_width/2, pos.y - button_height/2),
+ Vector(pos.x + button_width/2, pos.y + button_height/2)),
+ Color(1.0f, 1.0f, 1.0f, 0.5f),
+ 12.0f,
+ LAYER_GUI-10);
+ }
+
+ ctx.draw_text(Resources::normal_font, m_buttons[i].text,
+ Vector(pos.x, pos.y - int(Resources::normal_font->get_height()/2)),
+ ALIGN_CENTER, LAYER_GUI,
+ i == m_selected_button ? ColorScheme::Menu::active_color : ColorScheme::Menu::default_color);
+ }
+}
+
+void
+Dialog::on_button_click(int button) const
+{
+ if (m_buttons[button].callback)
+ {
+ m_buttons[button].callback();
+ }
+}
+
+/* EOF */
--- /dev/null
+// SuperTux
+// Copyright (C) 2014 Ingo Ruhnke <grumbel@gmail.com>
+//
+// 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
+// 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, see <http://www.gnu.org/licenses/>.
+
+#ifndef HEADER_SUPERTUX_GUI_DIALOG_HPP
+#define HEADER_SUPERTUX_GUI_DIALOG_HPP
+
+#include <SDL.h>
+#include <functional>
+#include <string>
+#include <vector>
+
+#include "math/sizef.hpp"
+
+class Controller;
+class DrawingContext;
+
+class Dialog
+{
+private:
+ struct Button
+ {
+ std::string text;
+ std::function<void ()> callback;
+ };
+
+ std::string m_text;
+ std::vector<Button> m_buttons;
+ int m_selected_button;
+
+ Sizef m_text_size;
+
+public:
+ Dialog();
+ virtual ~Dialog();
+
+ void set_text(const std::string& text);
+ void add_button(const std::string& text, const std::function<void ()>& callback = {},
+ bool focus = false);
+
+ void event(const SDL_Event& event);
+ void process_input(const Controller& controller);
+ void draw(DrawingContext& context);
+
+private:
+ void on_button_click(int button) const;
+ int get_button_at(const Vector& pos) const;
+
+private:
+ Dialog(const Dialog&) = delete;
+ Dialog& operator=(const Dialog&) = delete;
+};
+
+#endif
+
+/* EOF */
#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"
MenuItem& pitem = *(items[index]);
- Color text_color = default_color;
+ 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));
if(index == active_item)
{
- text_color = active_color;
+ text_color = ColorScheme::Menu::active_color;
}
if(active_item == index)
{
context.draw_text(Resources::normal_font, pitem.text,
Vector(pos.x, y_pos - int(Resources::normal_font->get_height()/2)),
- ALIGN_CENTER, LAYER_GUI, inactive_color);
+ ALIGN_CENTER, LAYER_GUI, ColorScheme::Menu::inactive_color);
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, label_color);
+ ALIGN_CENTER, LAYER_GUI, ColorScheme::Menu::label_color);
break;
}
case MN_TEXTFIELD:
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, field_color);
+ ALIGN_RIGHT, LAYER_GUI, ColorScheme::Menu::field_color);
else
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, field_color);
+ 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, field_color);
+ 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)),
class Menu
{
- static Color default_color;
- static Color active_color;
- static Color inactive_color;
- static Color label_color;
- static Color field_color;
-
private:
/* Action done on the menu */
enum MenuAction {
#include <assert.h>
#include "control/input_manager.hpp"
+#include "gui/dialog.hpp"
#include "gui/menu.hpp"
#include "gui/mousecursor.hpp"
#include "math/sizef.hpp"
};
MenuManager::MenuManager() :
+ m_dialog(),
m_menu_stack(),
m_transition(new MenuTransition)
{
void
MenuManager::process_input()
{
- if (current())
+ if (m_dialog)
{
- current()->process_input();
+ m_dialog->process_input(*InputManager::current()->get_controller());
+ }
+ else if (current_menu())
+ {
+ current_menu()->process_input();
}
}
void
-MenuManager::event(const SDL_Event& event_)
+MenuManager::event(const SDL_Event& ev)
{
- if (current() && !m_transition->is_active())
+ if (!m_transition->is_active())
{
- // only pass events when the menu is fully visible and not in a
- // transition animation
- current()->event(event_);
+ if (m_dialog)
+ {
+ m_dialog->event(ev);
+ }
+ else if (current_menu())
+ {
+ // only pass events when the menu is fully visible and not in a
+ // transition animation
+ current_menu()->event(ev);
+ }
}
}
}
else
{
- if (current())
+ if (m_dialog)
+ {
+ m_dialog->draw(context);
+ }
+ else if (current_menu())
{
// brute force the transition into the right shape in case the
// menu has changed sizes
- m_transition->set(menu2rect(*current()));
+ m_transition->set(menu2rect(*current_menu()));
m_transition->draw(context);
- current()->draw(context);
+ current_menu()->draw(context);
}
}
- if (current() && MouseCursor::current())
+ if (current_menu() && MouseCursor::current())
{
MouseCursor::current()->draw(context);
}
}
void
+MenuManager::set_dialog(std::unique_ptr<Dialog> dialog)
+{
+ m_dialog = std::move(dialog);
+}
+
+void
MenuManager::push_menu(int id)
{
push_menu(MenuStorage::instance().create(static_cast<MenuStorage::MenuId>(id)));
}
Menu*
-MenuManager::current() const
+MenuManager::current_menu() const
{
if (m_menu_stack.empty())
{
#include "SDL.h"
+class Dialog;
class DrawingContext;
class Menu;
class MenuTransition;
public:
static MenuManager& instance();
-public:
+private:
+ std::unique_ptr<Dialog> m_dialog;
std::vector<std::unique_ptr<Menu> > m_menu_stack;
std::unique_ptr<MenuTransition> m_transition;
- friend class Menu;
-
public:
MenuManager();
~MenuManager();
void draw(DrawingContext& context);
+ void set_dialog(std::unique_ptr<Dialog> dialog);
+
void set_menu(int id);
void set_menu(std::unique_ptr<Menu> menu);
void push_menu(int id);
}
private:
- Menu* current() const;
+ Menu* current_menu() const;
void transition(Menu* from, Menu* to);
private:
return ((v1 - v2).norm ());
}
+ Rectf grown(float border) const
+ {
+ return Rectf(p1.x - border, p1.y - border,
+ p2.x + border, p2.y + border);
+ }
+
// leave these two public to save the headaches of set/get functions for such
// simple things :)
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
+#include "supertux/colorscheme.hpp"
+
#include "gui/menu.hpp"
#include "object/floating_text.hpp"
#include "object/level_time.hpp"
Color Statistics::header_color(1.0,1.0,1.0);
Color Statistics::text_color(1.0,1.0,0.6);
-Color Menu::default_color(1.0,1.0,1.0);
-Color Menu::active_color(0.2,0.5,1.0);
-Color Menu::inactive_color(0.5,0.5,0.5);
-Color Menu::label_color(0.0,1.0,1.0);
-Color Menu::field_color(1.0,1.0,0.6);
+Color ColorScheme::Menu::default_color(1.0,1.0,1.0);
+Color ColorScheme::Menu::active_color(0.2,0.5,1.0);
+Color ColorScheme::Menu::inactive_color(0.5,0.5,0.5);
+Color ColorScheme::Menu::label_color(0.0,1.0,1.0);
+Color ColorScheme::Menu::field_color(1.0,1.0,0.6);
Color PlayerStatus::text_color(1.0,1.0,0.6);
--- /dev/null
+// SuperTux
+// Copyright (C) 2014 Ingo Ruhnke <grumbel@gmail.com>
+//
+// 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
+// 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, see <http://www.gnu.org/licenses/>.
+
+#ifndef HEADER_SUPERTUX_SUPERTUX_COLORSCHEME_HPP
+#define HEADER_SUPERTUX_SUPERTUX_COLORSCHEME_HPP
+
+#include "video/color.hpp"
+
+class ColorScheme
+{
+public:
+ class Menu
+ {
+ public:
+ static Color default_color;
+ static Color active_color;
+ static Color inactive_color;
+ static Color label_color;
+ static Color field_color;
+ };
+};
+
+#endif
+
+/* EOF */
#include "supertux/menu/main_menu.hpp"
#include "audio/sound_manager.hpp"
+#include "gui/dialog.hpp"
#include "gui/menu_item.hpp"
#include "gui/menu_manager.hpp"
#include "supertux/fadeout.hpp"
break;
case MNID_QUITMAINMENU:
- ScreenManager::current()->quit(std::unique_ptr<ScreenFade>(new FadeOut(0.25)));
- SoundManager::current()->stop_music(0.25);
+ std::unique_ptr<Dialog> dialog(new Dialog);
+ dialog->set_text(_("Do you really want to quit SuperTux?"));
+ dialog->add_button(_("Cancel"));
+ dialog->add_button(_("Quit SuperTux"), [] {
+ MenuManager::instance().clear_menu_stack();
+ ScreenManager::current()->quit(std::unique_ptr<ScreenFade>(new FadeOut(0.25)));
+ SoundManager::current()->stop_music(0.25);
+ }, true);
+ MenuManager::instance().set_dialog(std::move(dialog));
break;
}
}