2 // Copyright (C) 2009 Ingo Ruhnke <grumbel@gmail.com>
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "gui/menu_manager.hpp"
21 #include "control/input_manager.hpp"
22 #include "gui/dialog.hpp"
23 #include "gui/menu.hpp"
24 #include "gui/mousecursor.hpp"
25 #include "math/sizef.hpp"
26 #include "supertux/globals.hpp"
27 #include "supertux/menu/menu_storage.hpp"
28 #include "supertux/timer.hpp"
29 #include "util/log.hpp"
30 #include "video/drawing_context.hpp"
32 MenuManager* MenuManager::s_instance = 0;
35 MenuManager::instance()
43 Rectf menu2rect(const Menu& menu)
45 return Rectf(menu.get_center_pos().x - menu.get_width() / 2,
46 menu.get_center_pos().y - menu.get_height() / 2,
47 menu.get_center_pos().x + menu.get_width() / 2,
48 menu.get_center_pos().y + menu.get_height() / 2);
59 float m_effect_progress;
60 float m_effect_start_time;
67 m_effect_progress(1.0f),
68 m_effect_start_time(),
73 void start(const Rectf& from_rect,
76 m_from_rect = from_rect;
79 m_effect_start_time = real_time;
80 m_effect_progress = 0.0f;
85 void set(const Rectf& rect)
87 m_to_rect = m_from_rect = rect;
94 m_effect_progress = (real_time - m_effect_start_time) * 6.0f;
96 if (m_effect_progress > 1.0f)
98 m_effect_progress = 1.0f;
104 void draw(DrawingContext& context)
106 float p = m_effect_progress;
108 Rectf rect = m_to_rect;
111 rect.p1.x = (m_to_rect.p1.x * p) + (m_from_rect.p1.x * (1.0f - p));
112 rect.p1.y = (m_to_rect.p1.y * p) + (m_from_rect.p1.y * (1.0f - p));
113 rect.p2.x = (m_to_rect.p2.x * p) + (m_from_rect.p2.x * (1.0f - p));
114 rect.p2.y = (m_to_rect.p2.y * p) + (m_from_rect.p2.y * (1.0f - p));
117 // draw menu background rectangles
118 context.draw_filled_rect(Rectf(rect.p1.x - 4, rect.p1.y - 10-4,
119 rect.p2.x + 4, rect.p2.y + 10 + 4),
120 Color(0.2f, 0.3f, 0.4f, 0.8f),
124 context.draw_filled_rect(Rectf(rect.p1.x, rect.p1.y - 10,
125 rect.p2.x, rect.p2.y + 10),
126 Color(0.6f, 0.7f, 0.8f, 0.5f),
137 MenuManager::MenuManager() :
139 m_has_next_dialog(false),
142 m_transition(new MenuTransition)
147 MenuManager::~MenuManager()
149 s_instance = nullptr;
153 MenuManager::refresh()
155 for(auto i = m_menu_stack.begin(); i != m_menu_stack.end(); ++i)
162 MenuManager::process_input()
166 m_dialog->process_input(*InputManager::current()->get_controller());
168 else if (current_menu())
170 current_menu()->process_input();
175 MenuManager::event(const SDL_Event& ev)
177 if (!m_transition->is_active())
183 else if (current_menu())
185 // only pass events when the menu is fully visible and not in a
186 // transition animation
187 current_menu()->event(ev);
193 MenuManager::draw(DrawingContext& context)
195 if (m_has_next_dialog)
197 m_dialog = std::move(m_next_dialog);
198 m_has_next_dialog = false;
201 if (m_transition->is_active())
203 m_transition->update();
204 m_transition->draw(context);
211 m_dialog->draw(context);
213 else if (current_menu())
215 // brute force the transition into the right shape in case the
216 // menu has changed sizes
217 m_transition->set(menu2rect(*current_menu()));
218 m_transition->draw(context);
220 current_menu()->draw(context);
224 if (current_menu() && MouseCursor::current())
226 MouseCursor::current()->draw(context);
231 MenuManager::set_dialog(std::unique_ptr<Dialog> dialog)
233 // delay reseting m_dialog to a later point, as otherwise the Dialog
234 // can't unset itself without ending up with "delete this" problems
235 m_next_dialog = std::move(dialog);
236 m_has_next_dialog = true;
240 MenuManager::push_menu(int id)
242 push_menu(MenuStorage::instance().create(static_cast<MenuStorage::MenuId>(id)));
246 MenuManager::set_menu(int id)
248 set_menu(MenuStorage::instance().create(static_cast<MenuStorage::MenuId>(id)));
252 MenuManager::push_menu(std::unique_ptr<Menu> menu)
255 transition(m_menu_stack.empty() ? nullptr : m_menu_stack.back().get(),
257 m_menu_stack.push_back(std::move(menu));
261 MenuManager::pop_menu()
263 if (m_menu_stack.empty())
265 log_warning << "trying to pop on an empty menu_stack" << std::endl;
269 transition(m_menu_stack.back().get(),
270 (m_menu_stack.size() >= 2)
271 ? m_menu_stack[m_menu_stack.size() - 2].get()
274 m_menu_stack.pop_back();
279 MenuManager::set_menu(std::unique_ptr<Menu> menu)
283 transition(m_menu_stack.empty() ? nullptr : m_menu_stack.back().get(),
285 m_menu_stack.clear();
286 m_menu_stack.push_back(std::move(menu));
290 transition(m_menu_stack.empty() ? nullptr : m_menu_stack.back().get(),
292 m_menu_stack.clear();
295 // just to be sure...
296 InputManager::current()->reset();
300 MenuManager::clear_menu_stack()
302 transition(m_menu_stack.empty() ? nullptr : m_menu_stack.back().get(),
304 m_menu_stack.clear();
308 MenuManager::on_window_resize()
310 for(auto i = m_menu_stack.begin(); i != m_menu_stack.end(); ++i)
312 (*i)->on_window_resize();
317 MenuManager::current_menu() const
319 if (m_menu_stack.empty())
325 return m_menu_stack.back().get();
330 MenuManager::transition(Menu* from, Menu* to)
341 from_rect = menu2rect(*from);
345 from_rect = Rectf(to->get_center_pos(), Sizef(0, 0));
351 to_rect = menu2rect(*to);
355 to_rect = Rectf(from->get_center_pos(), Sizef(0, 0));
358 m_transition->start(from_rect, to_rect);