#ifndef MENU_H #define MENU_H #include "display.h" #include #include #include class Menu { public: static constexpr int HOLD_MS_THRESHOLD = 250; explicit Menu(lib::Display& display); virtual ~Menu() = default; virtual void onTick(float dt) = 0; virtual void onResume() = 0; virtual void onLeftPressed() = 0; virtual void onLeftHeld() = 0; virtual void onMenuPressed() = 0; virtual void onMenuHeld() = 0; virtual void onRightPressed() = 0; virtual void onRightHeld() = 0; protected: lib::Display* const display; }; namespace ease { // adapted from easings.net inline float inOutElastic(float x) { constexpr float c5 = (2 * 3.1415926f) / 4.5f; if (x == 0) { return 0; } if (x == 1) { return 1; } if (x < 0.5) { return -powf(2, 20 * x - 10) * sinf((20 * x - 11.125f) * c5) / 2.0f; } else { return powf(2, -20 * x + 10) * sinf((20 * x - 11.25f) * c5) / 2.0f + 1; } } // adapted from easings.net inline float outElastic(float x) { constexpr float c4 = (2 * 3.1415926f) / 3; if (x == 0) { return 0; } if (x == 1) { return 1; } return powf(2, -10 * x) * sinf((x * 10 - 0.75f) * c4) + 1; } // adapted from easings.net inline float inElastic(float x) { constexpr float c4 = (2 * 3.1415926f) / 3; if (x == 0) { return 0; } if (x == 1) { return 1; } return -powf(2, 10 * x - 10) * sinf((x * 10 - 10.75f) * c4); } } namespace menus { class ManaMenu : public Menu { public: explicit ManaMenu(lib::Display& display); ~ManaMenu() override = default; void onTick(float dt) override; void onResume() override; void onLeftPressed() override; void onLeftHeld() override; void onMenuPressed() override; void onMenuHeld() override; void onRightPressed() override; void onRightHeld() override; private: uint8_t current; uint8_t previous; bool going_right; float progress; }; class CMCMenu : public Menu { public: explicit CMCMenu(lib::Display& display, uint8_t color); ~CMCMenu() override = default; void onTick(float dt) override; void onResume() override; void onLeftPressed() override; void onLeftHeld() override; void onMenuPressed() override; void onMenuHeld() override; void onRightPressed() override; void onRightHeld() override; private: uint8_t color; uint8_t current; uint8_t previous; float progress; }; namespace detail { union Menus { ManaMenu mana; CMCMenu cmc; }; } constexpr size_t MAX_MENU_COUNT = 5; extern uint8_t MENU_MEMORY[sizeof(detail::Menus) * MAX_MENU_COUNT]; extern int8_t current_menu; inline Menu* get_current_menu() { return reinterpret_cast(MENU_MEMORY + current_menu * sizeof(detail::Menus)); } template inline void push_menu(lib::Display& display, Args&&... args) { current_menu += 1; new (get_current_menu()) T(display, args...); } inline void pop_menu() { get_current_menu()->~Menu(); current_menu -= 1; get_current_menu()->onResume(); } } #endif // MENU_H