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/gettext.hpp"
30 #include "util/log.hpp"
31 #include "video/drawing_context.hpp"
33 MenuManager* MenuManager::s_instance = 0;
36 MenuManager::instance()
44 Rectf menu2rect(const Menu& menu)
46 return Rectf(menu.get_center_pos().x - menu.get_width() / 2,
47 menu.get_center_pos().y - menu.get_height() / 2,
48 menu.get_center_pos().x + menu.get_width() / 2,
49 menu.get_center_pos().y + menu.get_height() / 2);
60 float m_effect_progress;
61 float m_effect_start_time;
68 m_effect_progress(1.0f),
69 m_effect_start_time(),
74 void start(const Rectf& from_rect,
77 m_from_rect = from_rect;
80 m_effect_start_time = real_time;
81 m_effect_progress = 0.0f;
86 void set(const Rectf& rect)
88 m_to_rect = m_from_rect = rect;
95 m_effect_progress = (real_time - m_effect_start_time) * 6.0f;
97 if (m_effect_progress > 1.0f)
99 m_effect_progress = 1.0f;
105 void draw(DrawingContext& context)
107 float p = m_effect_progress;
109 Rectf rect = m_to_rect;
112 rect.p1.x = (m_to_rect.p1.x * p) + (m_from_rect.p1.x * (1.0f - p));
113 rect.p1.y = (m_to_rect.p1.y * p) + (m_from_rect.p1.y * (1.0f - p));
114 rect.p2.x = (m_to_rect.p2.x * p) + (m_from_rect.p2.x * (1.0f - p));
115 rect.p2.y = (m_to_rect.p2.y * p) + (m_from_rect.p2.y * (1.0f - p));
118 // draw menu background rectangles
119 context.draw_filled_rect(Rectf(rect.p1.x - 4, rect.p1.y - 10-4,
120 rect.p2.x + 4, rect.p2.y + 10 + 4),
121 Color(0.2f, 0.3f, 0.4f, 0.8f),
125 context.draw_filled_rect(Rectf(rect.p1.x, rect.p1.y - 10,
126 rect.p2.x, rect.p2.y + 10),
127 Color(0.6f, 0.7f, 0.8f, 0.5f),
138 MenuManager::MenuManager() :
140 m_has_next_dialog(false),
143 m_transition(new MenuTransition)
148 MenuManager::~MenuManager()
150 s_instance = nullptr;
154 MenuManager::refresh()
156 for(auto i = m_menu_stack.begin(); i != m_menu_stack.end(); ++i)
163 MenuManager::process_input()
167 m_dialog->process_input(*InputManager::current()->get_controller());
169 else if (current_menu())
171 current_menu()->process_input();
176 MenuManager::event(const SDL_Event& ev)
178 if (!m_transition->is_active())
184 else if (current_menu())
186 // only pass events when the menu is fully visible and not in a
187 // transition animation
188 current_menu()->event(ev);
194 MenuManager::draw(DrawingContext& context)
196 if (m_has_next_dialog)
198 m_dialog = std::move(m_next_dialog);
199 m_has_next_dialog = false;
202 if (m_transition->is_active())
204 m_transition->update();
205 m_transition->draw(context);
212 m_dialog->draw(context);
214 else if (current_menu())
216 // brute force the transition into the right shape in case the
217 // menu has changed sizes
218 m_transition->set(menu2rect(*current_menu()));
219 m_transition->draw(context);
221 current_menu()->draw(context);
225 if (current_menu() && MouseCursor::current())
227 MouseCursor::current()->draw(context);
232 MenuManager::set_dialog(std::unique_ptr<Dialog> dialog)
234 // delay reseting m_dialog to a later point, as otherwise the Dialog
235 // can't unset itself without ending up with "delete this" problems
236 m_next_dialog = std::move(dialog);
237 m_has_next_dialog = true;
241 MenuManager::push_menu(int id)
243 push_menu(MenuStorage::instance().create(static_cast<MenuStorage::MenuId>(id)));
247 MenuManager::set_menu(int id)
249 set_menu(MenuStorage::instance().create(static_cast<MenuStorage::MenuId>(id)));
253 MenuManager::push_menu(std::unique_ptr<Menu> menu)
256 transition(m_menu_stack.empty() ? nullptr : m_menu_stack.back().get(),
258 m_menu_stack.push_back(std::move(menu));
262 MenuManager::pop_menu()
264 if (m_menu_stack.empty())
266 log_warning << "trying to pop on an empty menu_stack" << std::endl;
270 transition(m_menu_stack.back().get(),
271 (m_menu_stack.size() >= 2)
272 ? m_menu_stack[m_menu_stack.size() - 2].get()
275 m_menu_stack.pop_back();
280 MenuManager::set_menu(std::unique_ptr<Menu> menu)
284 transition(m_menu_stack.empty() ? nullptr : m_menu_stack.back().get(),
286 m_menu_stack.clear();
287 m_menu_stack.push_back(std::move(menu));
291 transition(m_menu_stack.empty() ? nullptr : m_menu_stack.back().get(),
293 m_menu_stack.clear();
296 // just to be sure...
297 InputManager::current()->reset();
301 MenuManager::clear_menu_stack()
303 transition(m_menu_stack.empty() ? nullptr : m_menu_stack.back().get(),
305 m_menu_stack.clear();
309 MenuManager::on_window_resize()
311 for(auto i = m_menu_stack.begin(); i != m_menu_stack.end(); ++i)
313 (*i)->on_window_resize();
318 MenuManager::current_menu() const
320 if (m_menu_stack.empty())
326 return m_menu_stack.back().get();
331 MenuManager::transition(Menu* from, Menu* to)
342 from_rect = menu2rect(*from);
346 from_rect = Rectf(to->get_center_pos(), Sizef(0, 0));
352 to_rect = menu2rect(*to);
356 to_rect = Rectf(from->get_center_pos(), Sizef(0, 0));
359 m_transition->start(from_rect, to_rect);