From: Ingo Ruhnke Date: Tue, 12 Aug 2014 08:12:57 +0000 (+0200) Subject: Rewrote ScreenManager push/pop handling again, should now be able to handle multiple... X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=9d6e6cb2637bbf4ac84a1d111fe6a0f4bd3ac6f5;p=supertux.git Rewrote ScreenManager push/pop handling again, should now be able to handle multiple push/pops in a row more gracefully --- diff --git a/src/supertux/screen_manager.cpp b/src/supertux/screen_manager.cpp index b8d26ef33..9e11eed7d 100644 --- a/src/supertux/screen_manager.cpp +++ b/src/supertux/screen_manager.cpp @@ -1,5 +1,6 @@ // SuperTux // Copyright (C) 2006 Matthias Braun +// 2014 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 @@ -47,9 +48,8 @@ ScreenManager::ScreenManager() : m_menu_storage(new MenuStorage), m_menu_manager(new MenuManager), m_speed(1.0), - m_action(NO_ACTION), + m_actions(), m_fps(0), - m_next_screen(), m_screen_fade(), m_screen_stack(), m_screenshot_requested(false) @@ -71,41 +71,17 @@ ScreenManager::push_screen(std::unique_ptr screen, std::unique_ptr screen_fade) { log_debug << "ScreenManager::pop_screen(): stack_size: " << m_screen_stack.size() << std::endl; - assert(m_action == NO_ACTION); - m_next_screen.reset(); m_screen_fade = std::move(screen_fade); - m_action = POP_ACTION; + m_actions.push_back(Action(Action::POP_ACTION)); } void @@ -118,7 +94,7 @@ void ScreenManager::quit(std::unique_ptr screen_fade) { m_screen_fade = std::move(screen_fade); - m_action = QUIT_ACTION; + m_actions.push_back(Action(Action::QUIT_ACTION)); } void @@ -276,56 +252,64 @@ ScreenManager::has_pending_fadeout() const void ScreenManager::handle_screen_switch() { - if (m_action != NO_ACTION && !has_pending_fadeout()) + if (has_pending_fadeout()) { - if (m_action == POP_ACTION) - { - assert(!m_screen_stack.empty()); - m_action = NO_ACTION; + // wait till the fadeout is completed before switching screens + } + else + { + m_screen_fade.reset(); - m_screen_stack.back()->leave(); - m_screen_stack.pop_back(); + // keep track of the current screen, as only that needs a call to Screen::leave() + Screen* current_screen = m_screen_stack.empty() ? nullptr : m_screen_stack.back().get(); - if (!m_screen_stack.empty()) - { - m_screen_stack.back()->setup(); - } - } - else if (m_action == PUSH_ACTION) + // Screen::setup() might push more screens, so loop till everything is done + while (!m_actions.empty()) { - assert(m_next_screen); - m_action = NO_ACTION; + // move actions to a new vector since setup() might modify it + auto actions = std::move(m_actions); - if (!m_screen_stack.empty()) + for(auto it = actions.begin(); it != actions.end(); ++it) { - m_screen_stack.back()->leave(); - } - - m_screen_stack.push_back(std::move(m_next_screen)); - m_screen_stack.back()->setup(); - } - else if (m_action == REPLACE_ACTION) - { - assert(!m_screen_stack.empty()); - assert(!m_next_screen); - m_action = NO_ACTION; - - m_screen_stack.back()->leave(); - m_screen_stack.pop_back(); + auto& action = *it; - m_screen_stack.push_back(std::move(m_next_screen)); - m_screen_stack.back()->setup(); - } - else if (m_action == QUIT_ACTION) - { - m_screen_stack.clear(); - } + switch (action.type) + { + case Action::POP_ACTION: + assert(!m_screen_stack.empty()); + if (current_screen == m_screen_stack.back().get()) + { + m_screen_stack.back()->leave(); + } + m_screen_stack.pop_back(); + break; - m_speed = 1.0; + case Action::PUSH_ACTION: + assert(action.screen); + + if (!m_screen_stack.empty()) + { + if (current_screen == m_screen_stack.back().get()) + { + m_screen_stack.back()->leave(); + } + } + m_screen_stack.push_back(std::move(action.screen)); + break; - m_screen_fade.reset(); + case Action::QUIT_ACTION: + m_screen_stack.clear(); + break; + } + } - m_waiting_threads.wakeup(); + if (!m_screen_stack.empty()) + { + m_screen_stack.back()->setup(); + m_speed = 1.0; + m_waiting_threads.wakeup(); + } + } } } @@ -335,9 +319,7 @@ ScreenManager::run(DrawingContext &context) Uint32 last_ticks = 0; Uint32 elapsed_ticks = 0; - assert(m_action == PUSH_ACTION); - m_screen_stack.push_back(std::move(m_next_screen)); - m_action = NO_ACTION; + handle_screen_switch(); while (!m_screen_stack.empty()) { diff --git a/src/supertux/screen_manager.hpp b/src/supertux/screen_manager.hpp index 0c0cd0fe5..53d02b1c2 100644 --- a/src/supertux/screen_manager.hpp +++ b/src/supertux/screen_manager.hpp @@ -1,5 +1,6 @@ // SuperTux // Copyright (C) 2006 Matthias Braun +// 2014 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 @@ -21,6 +22,7 @@ #include #include "scripting/thread_queue.hpp" +#include "supertux/screen.hpp" class Console; class DrawingContext; @@ -69,11 +71,23 @@ private: std::unique_ptr m_menu_manager; float m_speed; - enum Action { NO_ACTION, PUSH_ACTION, POP_ACTION, REPLACE_ACTION, QUIT_ACTION }; - Action m_action; + struct Action + { + enum Type { PUSH_ACTION, POP_ACTION, QUIT_ACTION }; + Type type; + std::unique_ptr screen; + + Action(Type type_, + std::unique_ptr screen_ = {}) : + type(type_), + screen(std::move(screen_)) + {} + }; + + std::vector m_actions; + /// measured fps float m_fps; - std::unique_ptr m_next_screen; std::unique_ptr m_screen_fade; std::vector > m_screen_stack; bool m_screenshot_requested; /**< true if a screenshot should be taken after the next frame has been rendered */