Files
esp-gui-lib/src/menudisplay.h
T

164 lines
5.0 KiB
C++

#pragma once
#include "sdkconfig.h"
// system includes
#include <array>
#include <algorithm>
#include <functional>
#include <cassert>
#include <memory>
#include <optional>
// 3rdparty lib includes
#include <espchrono.h>
// local includes
#include "displaywithtitle.h"
#include "textinterface.h"
#include "widgets/label.h"
#include "menuitem.h"
#include "backinterface.h"
namespace espgui {
class MenuDisplay :
public DisplayWithTitle,
public virtual BackInterface
{
using Base = DisplayWithTitle;
public:
void start() override;
void initScreen(TftInterface &tft) override;
void update() override;
void redraw(TftInterface &tft) override;
void stop() override;
void buttonPressed(Button button) override;
void buttonReleased(Button button) override;
MenuDisplay *asMenuDisplay() override { return this; }
const MenuDisplay *asMenuDisplay() const override { return this; }
int selectedIndex() const { return m_selectedIndex; }
std::size_t menuItemCount() const { return m_menuItems.size(); }
MenuItem& getMenuItem(std::size_t index)
{
assert(index < m_menuItems.size());
return *m_menuItems[index].get();
}
const MenuItem& getMenuItem(std::size_t index) const
{
assert(index < m_menuItems.size());
return *m_menuItems[index].get();
}
void runForEveryMenuItem(std::function<void(MenuItem&)> &&callback)
{
for (const auto &ptr : m_menuItems)
callback(*ptr);
}
void runForEveryMenuItem(std::function<void(const MenuItem&)> &&callback) const
{
for (const auto &ptr : m_menuItems)
callback(*ptr);
}
template<typename T, typename... Args>
T &constructMenuItem(Args&&... args)
{
auto ptr = std::make_unique<T>(std::forward<Args>(args)...);
T &ref = *ptr;
emplaceMenuItem(std::move(ptr));
return ref;
}
void emplaceMenuItem(std::unique_ptr<MenuItem> &&ptr)
{
m_menuItems.emplace_back(std::move(ptr));
}
void clearMenuItems()
{
m_menuItems.clear();
}
std::unique_ptr<MenuItem> takeLastMenuItem()
{
assert(!m_menuItems.empty());
std::unique_ptr<MenuItem> ptr = std::move(m_menuItems.back());
m_menuItems.pop_back();
return ptr;
}
protected:
void setSelectedIndex(int selectedIndex) { m_selectedIndex = selectedIndex; }
private:
static constexpr size_t rowCount = CONFIG_ESPGUI_MENUDISPLAY_ROWS;
static constexpr auto iconWidth = 25;
static constexpr auto horizontalSpacing = 10;
static constexpr auto topMargin = 39;
static constexpr auto lineHeight = 27;
static constexpr auto verticalSpacing = 2;
std::array<Label, rowCount> m_labels {{
#if CONFIG_ESPGUI_MENUDISPLAY_ROWS >= 1
Label{horizontalSpacing + iconWidth, topMargin+(0*(lineHeight+verticalSpacing))}, // 240-(horizontalSpacing*2)-iconWidth, lineHeight
#endif
#if CONFIG_ESPGUI_MENUDISPLAY_ROWS >= 2
Label{horizontalSpacing + iconWidth, topMargin+(1*(lineHeight+verticalSpacing))}, // 240-(horizontalSpacing*2)-iconWidth, lineHeight
#endif
#if CONFIG_ESPGUI_MENUDISPLAY_ROWS >= 3
Label{horizontalSpacing + iconWidth, topMargin+(2*(lineHeight+verticalSpacing))}, // 240-(horizontalSpacing*2)-iconWidth, lineHeight
#endif
#if CONFIG_ESPGUI_MENUDISPLAY_ROWS >= 4
Label{horizontalSpacing + iconWidth, topMargin+(3*(lineHeight+verticalSpacing))}, // 240-(horizontalSpacing*2)-iconWidth, lineHeight
#endif
#if CONFIG_ESPGUI_MENUDISPLAY_ROWS >= 5
Label{horizontalSpacing + iconWidth, topMargin+(4*(lineHeight+verticalSpacing))}, // 240-(horizontalSpacing*2)-iconWidth, lineHeight
#endif
#if CONFIG_ESPGUI_MENUDISPLAY_ROWS >= 6
Label{horizontalSpacing + iconWidth, topMargin+(5*(lineHeight+verticalSpacing))}, // 240-(horizontalSpacing*2)-iconWidth, lineHeight
#endif
#if CONFIG_ESPGUI_MENUDISPLAY_ROWS >= 7
Label{horizontalSpacing + iconWidth, topMargin+(6*(lineHeight+verticalSpacing))}, // 240-(horizontalSpacing*2)-iconWidth, lineHeight
#endif
#if CONFIG_ESPGUI_MENUDISPLAY_ROWS >= 8
Label{horizontalSpacing + iconWidth, topMargin+(7*(lineHeight+verticalSpacing))}, // 240-(horizontalSpacing*2)-iconWidth, lineHeight
#endif
#if CONFIG_ESPGUI_MENUDISPLAY_ROWS >= 9
Label{horizontalSpacing + iconWidth, topMargin+(8*(lineHeight+verticalSpacing))}, // 240-(horizontalSpacing*2)-iconWidth, lineHeight
#endif
#if CONFIG_ESPGUI_MENUDISPLAY_ROWS >= 10
Label{horizontalSpacing + iconWidth, topMargin+(9*(lineHeight+verticalSpacing))}, // 240-(horizontalSpacing*2)-iconWidth, lineHeight
#endif
}};
std::array<const Icon<24, 24> *, rowCount> m_icons;
int m_selectedIndex{};
int m_scrollOffset{};
int m_highlightedIndex;
int m_rotateOffset;
bool m_pressed;
std::vector<std::unique_ptr<MenuItem>> m_menuItems;
struct ButtonHeldInfo
{
espchrono::millis_clock::time_point nextTimestamp;
int counter{};
};
std::optional<ButtonHeldInfo> m_upHeld;
std::optional<ButtonHeldInfo> m_downHeld;
};
} // namespace espgui