244 lines
4.3 KiB
C++

#ifndef MENU_H
#define MENU_H
#include "display.h"
#include "flash.h"
#include <cmath>
#include <new>
#include <pico/stdlib.h>
class Menu
{
public:
static constexpr int HOLD_MS_THRESHOLD = 250;
explicit Menu(lib::Display& display, lib::Flash& flash);
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;
lib::Flash* const flash;
};
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, lib::Flash& flash);
~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, lib::Flash& flash, 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;
};
class SelectMenu : public Menu
{
public:
explicit SelectMenu(lib::Display& display, lib::Flash& flash, uint8_t color,
uint8_t cmc);
~SelectMenu() 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 cmc;
uint8_t current;
uint16_t found;
uint16_t filtered[12];
void draw();
void draw_letter(uint8_t x, uint8_t y, uint8_t letter);
};
class CardMenu : public Menu
{
public:
explicit CardMenu(lib::Display& display, lib::Flash& flash, uint16_t card);
~CardMenu() 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 card;
void draw();
};
namespace detail
{
union Menus
{
ManaMenu mana;
CMCMenu cmc;
SelectMenu select;
CardMenu card;
};
}
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(Args&&... args)
{
current_menu += 1;
new (get_current_menu()) T(args...);
}
inline void pop_menu(uint8_t count = 1)
{
for (int i = 0; i < count; i++)
{
get_current_menu()->~Menu();
current_menu -= 1;
}
get_current_menu()->onResume();
}
}
#endif // MENU_H