184 lines
3.0 KiB
C++
184 lines
3.0 KiB
C++
#ifndef MENU_H
|
|
#define MENU_H
|
|
|
|
#include "display.h"
|
|
|
|
#include <cmath>
|
|
#include <new>
|
|
#include <pico/stdlib.h>
|
|
|
|
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*>(MENU_MEMORY
|
|
+ current_menu * sizeof(detail::Menus));
|
|
}
|
|
|
|
template <typename T, typename... Args>
|
|
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
|