diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 61afb42..6d4b90c 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -596,6 +596,24 @@ void GMenu2X::main() { bool quit = false; while (!quit) { + // Check whether any layers are animating and remove dismissed layers + // from the stack. + bool animating = false; + for (auto it = layers.begin(); it != layers.end(); ) { + auto layer = *it; + switch (layer->getStatus()) { + case Layer::Status::DISMISSED: + it = layers.erase(it); + break; + case Layer::Status::ANIMATING: + animating = true; + // fall through + case Layer::Status::PASSIVE: + ++it; + break; + } + } + // Paint layers. for (auto layer : layers) { layer->paint(*s); @@ -613,20 +631,19 @@ void GMenu2X::main() { } // Handle other input events. - InputManager::Button button = input.waitForPressedButton(); - for (auto it = layers.rbegin(); it != layers.rend(); ++it) { - if ((*it)->handleButtonPress(button)) { - break; - } - } - - // Remove dismissed layers from the stack. - for (auto it = layers.begin(); it != layers.end(); ) { - auto layer = *it; - if (layer->wasDismissed()) { - it = layers.erase(it); - } else { - ++it; + InputManager::ButtonEvent event; + bool gotEvent; + const bool wait = !animating; + do { + do { + gotEvent = input.getEvent(&event, wait); + } while (gotEvent && event.state != InputManager::PRESSED); + } while (wait && !gotEvent); + if (gotEvent) { + for (auto it = layers.rbegin(); it != layers.rend(); ++it) { + if ((*it)->handleButtonPress(event.button)) { + break; + } } } } diff --git a/src/helppopup.cpp b/src/helppopup.cpp index 9bdb24b..1501b24 100644 --- a/src/helppopup.cpp +++ b/src/helppopup.cpp @@ -32,14 +32,14 @@ void HelpPopup::paint(Surface &s) { bool HelpPopup::handleButtonPress(InputManager::Button button) { if (button == InputManager::CANCEL) { - dismissed = true; + dismiss(); } return true; } bool HelpPopup::handleTouchscreen(Touchscreen &ts) { if (ts.pressed()) { - dismissed = true; + dismiss(); ts.setHandled(); } return true; diff --git a/src/inputmanager.h b/src/inputmanager.h index fca5eb6..b399345 100644 --- a/src/inputmanager.h +++ b/src/inputmanager.h @@ -58,6 +58,7 @@ public: bool waitForEvent(ButtonEvent *event); Button waitForPressedButton(); bool pollEvent(ButtonEvent *event); + bool getEvent(ButtonEvent *bevent, bool wait); private: enum ButtonSource { UNMAPPED, KEYBOARD, JOYSTICK }; @@ -69,7 +70,6 @@ private: Menu *menu; void readConfFile(const std::string &conffile); - bool getEvent(ButtonEvent *bevent, bool wait); ButtonMapEntry buttonMap[BUTTON_TYPE_SIZE]; #ifndef SDL_JOYSTICK_DISABLED diff --git a/src/layer.h b/src/layer.h index bac92cc..fb38160 100644 --- a/src/layer.h +++ b/src/layer.h @@ -16,6 +16,8 @@ class Touchscreen; */ class Layer { public: + enum class Status { PASSIVE, ANIMATING, DISMISSED }; + virtual ~Layer() {} /** @@ -36,13 +38,34 @@ public: */ virtual bool handleTouchscreen(Touchscreen &ts) = 0; - bool wasDismissed() { return dismissed; } + Status getStatus() { return status; } protected: /** - * Set this to true to request the layer to be removed from the stack. + * Request the Layer to be removed from the stack. + * There could be a few more calls to the Layer before it is actually + * removed, so be prepared to handle those. */ - bool dismissed = false; + void dismiss() { + status = Status::DISMISSED; + } + + /** + * Request that this layer be repainted every frame. + */ + void startAnimating() { + if (status == Status::PASSIVE) status = Status::ANIMATING; + } + + /** + * Request that this layer be repainted only after an event. + */ + void stopAnimating() { + if (status == Status::ANIMATING) status = Status::PASSIVE; + } + +private: + Status status = Status::PASSIVE; }; #endif // LAYER_H