X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fgui%2Fmenu_manager.cpp;h=32b61785de209086c9c6269dfb75b355dfe4a53c;hb=1f813f3b4ca1af669c7183f25af902de7205dd65;hp=c30471e31538986cb381dd33440aa2c16262886f;hpb=9ca6ad8086995cde21a4ae247dac53de336c15ec;p=supertux.git diff --git a/src/gui/menu_manager.cpp b/src/gui/menu_manager.cpp index c30471e31..32b61785d 100644 --- a/src/gui/menu_manager.cpp +++ b/src/gui/menu_manager.cpp @@ -1,5 +1,5 @@ // SuperTux -// Copyright (C) 2009 Ingo Ruhnke +// Copyright (C) 2009 Ingo Ruhnke // // 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 @@ -16,78 +16,347 @@ #include "gui/menu_manager.hpp" -#include "control/joystickkeyboardcontroller.hpp" +#include + +#include "control/input_manager.hpp" +#include "gui/dialog.hpp" #include "gui/menu.hpp" +#include "gui/mousecursor.hpp" +#include "math/sizef.hpp" #include "supertux/globals.hpp" +#include "supertux/menu/menu_storage.hpp" #include "supertux/timer.hpp" +#include "util/gettext.hpp" +#include "util/log.hpp" +#include "video/drawing_context.hpp" + +MenuManager* MenuManager::s_instance = 0; + +MenuManager& +MenuManager::instance() +{ + assert(s_instance); + return *s_instance; +} + +namespace { + +Rectf menu2rect(const Menu& menu) +{ + return Rectf(menu.get_center_pos().x - menu.get_width() / 2, + menu.get_center_pos().y - menu.get_height() / 2, + menu.get_center_pos().x + menu.get_width() / 2, + menu.get_center_pos().y + menu.get_height() / 2); +} + +} // namespace + +class MenuTransition +{ +private: + Rectf m_from_rect; + Rectf m_to_rect; + + float m_effect_progress; + float m_effect_start_time; + bool m_is_active; + +public: + MenuTransition() : + m_from_rect(), + m_to_rect(), + m_effect_progress(1.0f), + m_effect_start_time(), + m_is_active(false) + { + } + + void start(const Rectf& from_rect, + const Rectf& to_rect) + { + m_from_rect = from_rect; + m_to_rect = to_rect; + + m_effect_start_time = real_time; + m_effect_progress = 0.0f; + + m_is_active = true; + } + + void set(const Rectf& rect) + { + m_to_rect = m_from_rect = rect; + } + + void update() + { + if (m_is_active) + { + m_effect_progress = (real_time - m_effect_start_time) * 6.0f; + + if (m_effect_progress > 1.0f) + { + m_effect_progress = 1.0f; + m_is_active = false; + } + } + } -std::vector MenuManager::last_menus; -std::list MenuManager::all_menus; -Menu* MenuManager::current_ = 0; -Menu* MenuManager::previous = 0; + void draw(DrawingContext& context) + { + float p = m_effect_progress; + + Rectf rect = m_to_rect; + if (m_is_active) + { + rect.p1.x = (m_to_rect.p1.x * p) + (m_from_rect.p1.x * (1.0f - p)); + rect.p1.y = (m_to_rect.p1.y * p) + (m_from_rect.p1.y * (1.0f - p)); + rect.p2.x = (m_to_rect.p2.x * p) + (m_from_rect.p2.x * (1.0f - p)); + rect.p2.y = (m_to_rect.p2.y * p) + (m_from_rect.p2.y * (1.0f - p)); + } + + // draw menu background rectangles + context.draw_filled_rect(Rectf(rect.p1.x - 4, rect.p1.y - 10-4, + rect.p2.x + 4, rect.p2.y + 10 + 4), + Color(0.2f, 0.3f, 0.4f, 0.8f), + 20.0f, + LAYER_GUI-10); + + context.draw_filled_rect(Rectf(rect.p1.x, rect.p1.y - 10, + rect.p2.x, rect.p2.y + 10), + Color(0.6f, 0.7f, 0.8f, 0.5f), + 16.0f, + LAYER_GUI-10); + } + + bool is_active() + { + return m_is_active; + } +}; + +MenuManager::MenuManager() : + m_dialog(), + m_has_next_dialog(false), + m_next_dialog(), + m_menu_stack(), + m_transition(new MenuTransition) +{ + s_instance = this; +} + +MenuManager::~MenuManager() +{ + s_instance = nullptr; +} void -MenuManager::push_current(Menu* pmenu) +MenuManager::refresh() { - previous = current_; + for(auto i = m_menu_stack.begin(); i != m_menu_stack.end(); ++i) + { + (*i)->refresh(); + } +} - if (current_) - last_menus.push_back(current_); +void +MenuManager::process_input() +{ + if (m_dialog) + { + m_dialog->process_input(*InputManager::current()->get_controller()); + } + else if (current_menu()) + { + current_menu()->process_input(); + } +} - current_ = pmenu; - current_->effect_start_time = real_time; - current_->effect_progress = 0.0f; +void +MenuManager::event(const SDL_Event& ev) +{ + if (!m_transition->is_active()) + { + 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); + } + } } void -MenuManager::pop_current() +MenuManager::draw(DrawingContext& context) { - previous = current_; + if (m_has_next_dialog) + { + m_dialog = std::move(m_next_dialog); + m_has_next_dialog = false; + } + + if (m_transition->is_active()) + { + m_transition->update(); + m_transition->draw(context); + } + else + { + if (m_dialog) + { + m_dialog->update(); + 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_menu())); + m_transition->draw(context); + + current_menu()->draw(context); + } + } - if (last_menus.size() >= 1) { - current_ = last_menus.back(); - current_->effect_start_time = real_time; - current_->effect_progress = 0.0f; - last_menus.pop_back(); - } else { - set_current(NULL); + if (current_menu() && MouseCursor::current()) + { + MouseCursor::current()->draw(context); } } void -MenuManager::set_current(Menu* menu) +MenuManager::set_dialog(std::unique_ptr dialog) { - if (current_ && current_->close == true) - return; + // delay reseting m_dialog to a later point, as otherwise the Dialog + // can't unset itself without ending up with "delete this" problems + m_next_dialog = std::move(dialog); + m_has_next_dialog = true; +} + +void +MenuManager::push_menu(int id) +{ + push_menu(MenuStorage::instance().create(static_cast(id))); +} + +void +MenuManager::set_menu(int id) +{ + set_menu(MenuStorage::instance().create(static_cast(id))); +} + +void +MenuManager::push_menu(std::unique_ptr menu) +{ + assert(menu); + transition(m_menu_stack.empty() ? nullptr : m_menu_stack.back().get(), + menu.get()); + m_menu_stack.push_back(std::move(menu)); +} + +void +MenuManager::pop_menu() +{ + if (m_menu_stack.empty()) + { + log_warning << "trying to pop on an empty menu_stack" << std::endl; + } + else + { + transition(m_menu_stack.back().get(), + (m_menu_stack.size() >= 2) + ? m_menu_stack[m_menu_stack.size() - 2].get() + : nullptr); - previous = current_; + m_menu_stack.pop_back(); + } +} - if (menu) { - menu->effect_start_time = real_time; - menu->effect_progress = 0.0f; - current_ = menu; +void +MenuManager::set_menu(std::unique_ptr menu) +{ + if (menu) + { + transition(m_menu_stack.empty() ? nullptr : m_menu_stack.back().get(), + menu.get()); + m_menu_stack.clear(); + m_menu_stack.push_back(std::move(menu)); } - else if (current_) { - last_menus.clear(); //NULL new menu pointer => close all menus - current_->effect_start_time = real_time; - current_->effect_progress = 0.0f; - current_->close = true; + else + { + transition(m_menu_stack.empty() ? nullptr : m_menu_stack.back().get(), + nullptr); + m_menu_stack.clear(); } // just to be sure... - g_main_controller->reset(); + InputManager::current()->reset(); } void -MenuManager::recalc_pos() +MenuManager::clear_menu_stack() +{ + transition(m_menu_stack.empty() ? nullptr : m_menu_stack.back().get(), + nullptr); + m_menu_stack.clear(); +} + +void +MenuManager::on_window_resize() +{ + for(auto i = m_menu_stack.begin(); i != m_menu_stack.end(); ++i) + { + (*i)->on_window_resize(); + } +} + +Menu* +MenuManager::current_menu() const { - if (current_) - current_->set_pos(SCREEN_WIDTH/2, SCREEN_HEIGHT/2); + if (m_menu_stack.empty()) + { + return nullptr; + } + else + { + return m_menu_stack.back().get(); + } +} - for(std::list::iterator i = all_menus.begin(); i != all_menus.end(); ++i) +void +MenuManager::transition(Menu* from, Menu* to) +{ + if (!from && !to) { - // FIXME: This is of course not quite right, since it ignores any previous set_pos() calls - (*i)->set_pos(SCREEN_WIDTH/2, SCREEN_HEIGHT/2); + return; + } + else + { + Rectf from_rect; + if (from) + { + from_rect = menu2rect(*from); + } + else + { + from_rect = Rectf(to->get_center_pos(), Sizef(0, 0)); + } + + Rectf to_rect; + if (to) + { + to_rect = menu2rect(*to); + } + else + { + to_rect = Rectf(from->get_center_pos(), Sizef(0, 0)); + } + + m_transition->start(from_rect, to_rect); } }