#include "screen.h" // standard library includes #include #ifndef NDEBUG #include #endif // NDEBUG // local includes #include "screen_test.h" Screen::Screen(std::weak_ptr stack) : stack(stack) {} ScreenStack::PendingAction::PendingAction() : screen(), action(Action::NOP) {} ScreenStack::PendingAction::PendingAction(Action action) : screen(), action(action) { switch (action) { case Action::PUSH_SCREEN: case Action::CONSTRUCT_SCREEN: // Cannot push non-existant screen. this->action = Action::NOP; #ifndef NDEBUG std::clog << "WARNING: Cannot create PendingAction with PUSH_SCREEN or " "CONSTRUCT_SCREEN!\n"; #endif break; default: break; } } ScreenStack::PendingAction::PendingAction(Screen::Ptr &&screen) : screen(std::forward(screen)), action(Action::PUSH_SCREEN) {} ScreenStack::PendingAction::PendingAction( std::function &&fn) : screen(std::forward >(fn)), action(Action::CONSTRUCT_SCREEN) {} ScreenStack::Ptr ScreenStack::new_instance() { std::shared_ptr ptr = std::shared_ptr(new ScreenStack{}); ptr->self_weak = ptr; return ptr; } void ScreenStack::update(float dt) { handle_pending_actions(); auto idx = stack.size(); if (idx == 0) { #ifndef NDEBUG std::cerr << "WARNING: Stack is empty, pushing TestScreen...\n"; #endif // NDEBUG push_screen(Screen::new_screen(self_weak)); update(dt); return; } while (idx > 0 && stack.at(--idx)->update(dt)) { } } void ScreenStack::draw() { for (decltype(stack.size()) idx = 0; idx < stack.size() && stack.at(idx)->draw(); ++idx) { } } void ScreenStack::push_screen(Screen::Ptr &&screen) { actions.push_back(PendingAction(std::forward(screen))); } void ScreenStack::pop_screen() { actions.push_back(PendingAction(Action::POP_SCREEN)); } void ScreenStack::clear_screens() { actions.push_back(PendingAction(Action::CLEAR_SCREENS)); } ScreenStack::ScreenStack() : self_weak(), stack(), actions() {} void ScreenStack::handle_pending_actions() { while (!actions.empty()) { switch (actions.front().action) { case Action::PUSH_SCREEN: stack.emplace_back( std::move(std::get(actions.front().screen))); break; case Action::POP_SCREEN: if (!stack.empty()) { stack.pop_back(); } #ifndef NDEBUG else { std::cerr << "WARNING: Tried to pop screen when stack was empty!\n"; } #endif // NDEBUG break; case Action::CLEAR_SCREENS: #ifndef NDEBUG if (stack.empty()) { std::cerr << "WARNING: Clearing an empty screen stack!\n"; } #endif stack.clear(); break; case Action::CONSTRUCT_SCREEN: stack.emplace_back( std::get >( actions.front().screen)(self_weak)); break; case Action::NOP: // Intentionally left blank. break; default: assert(!"unreachable"); break; } actions.pop_front(); } }