Functional menu

This commit is contained in:
Lewis Jackson 2023-05-29 20:00:46 +03:00
parent 5b7ef1c24f
commit 06839fa806
6 changed files with 160 additions and 30 deletions

View file

@ -5,7 +5,10 @@
RTC_DATA_ATTR WatchyDisplay * Menu::m_display = nullptr;
RTC_DATA_ATTR std::function<void()> Menu::m_exitCallback = nullptr;
RTC_DATA_ATTR uint8_t Menu::m_numPages = 0, Menu::m_currentPage = 0, Menu::m_numMenuItemsinCurrentPage = 0, Menu::m_currentMenuItem = 0;
RTC_DATA_ATTR uint8_t Menu::m_numPages = 0;
RTC_DATA_ATTR uint8_t Menu::m_currentPage = 0;
RTC_DATA_ATTR uint8_t Menu::m_numMenuItemsinCurrentPage = 0;
RTC_DATA_ATTR uint8_t Menu::m_currentMenuItem = 0;
Menu::Menu()
{
@ -29,6 +32,7 @@ void Menu::HandleButtonPress(uint64_t buttonMask)
if (buttonMask & BACK_BTN_MASK) {
if (m_exitCallback) {
m_exitCallback();
return;
}
}
}
@ -45,23 +49,45 @@ void Menu::HandleButtonPress(uint64_t buttonMask)
if (m_currentMenuItem > 0) {
m_currentMenuItem--;
}
Redraw(true);
return;
}
if (buttonMask & DOWN_BTN_MASK) {
if (m_currentMenuItem < m_pages[m_currentPage].menuItems.size() - 1) {
if (m_currentMenuItem < m_numMenuItemsinCurrentPage - 1) {
m_currentMenuItem++;
}
Redraw(true);
return;
}
if (buttonMask & MENU_BTN_MASK) {
if (m_pages[m_currentPage].menuItems[m_currentMenuItem].callback) {
if (m_pages[m_currentPage].menuItems[m_currentMenuItem].callback != nullptr) {
m_pages[m_currentPage].menuItems[m_currentMenuItem].callback();
return;
}
if (m_pages[m_currentPage].menuItems[m_currentMenuItem].pageNum > 0) {
m_currentPage = m_pages[m_currentPage].menuItems[m_currentMenuItem].pageNum;
m_currentMenuItem = 0;
if (m_pages[m_currentPage].menuItems[m_currentMenuItem].pageNum == 0 && m_currentPage == 0 && m_exitCallback) {
m_exitCallback();
return;
}
m_currentPage = m_pages[m_currentPage].menuItems[m_currentMenuItem].pageNum;
m_currentMenuItem = 0;
Redraw(false);
return;
}
if (buttonMask & BACK_BTN_MASK) {
m_currentPage = m_pages[m_currentPage].backPageNum;
m_currentMenuItem = 0;
Redraw(false);
return;
}
}
@ -69,16 +95,20 @@ void Menu::SetPages(const std::vector<MenuPage> & pages)
{
// If the number of pages has changed, reset the current page and menu item.
if (pages.size() != m_numPages) {
Serial.println("Resetting current page");
m_currentPage = 0;
m_currentMenuItem = 0;
}
// If the number of menu items has changed, reset the current menu item.
if (pages.size() > 0 && pages[m_currentMenuItem].menuItems.size() != m_numMenuItemsinCurrentPage) {
Serial.println("Resetting current menu item");
m_currentMenuItem = 0;
m_numMenuItemsinCurrentPage = pages[m_currentPage].menuItems.size();
}
m_pages = pages;
m_numPages = pages.size();
}
void Menu::SetExitCallback(std::function<void()> callback)
@ -101,6 +131,10 @@ void Menu::Redraw(bool partialRefresh)
if (m_pages.size() > 0) {
bool hasTitle = false;
bool hasBody = false;
uint16_t top = 5;
if (m_pages[m_currentPage].title.length() > 0) {
hasTitle = true;
@ -109,6 +143,7 @@ void Menu::Redraw(bool partialRefresh)
int16_t x, y;
uint16_t w, h;
m_display->setTextWrap(false);
m_display->getTextBounds(m_pages[m_currentPage].title.c_str(), 0, 0, &x, &y, &w, &h);
if (m_pages[m_currentPage].titleAlignment == ALIGNMENT_LEFT) { // Left
@ -121,9 +156,56 @@ void Menu::Redraw(bool partialRefresh)
m_display->setCursor(x, 15);
m_display->print(m_pages[m_currentPage].title.c_str());
m_display->drawLine(5, 25, m_display->width() - 10, 25, GxEPD_BLACK);
m_display->drawLine(5, 20, m_display->width() - 10, 20, GxEPD_BLACK);
top += 35;
}
if (m_pages[m_currentPage].body.length() > 0) {
m_display->setFont(&FreeSans9pt7b);
m_display->setTextColor(GxEPD_BLACK);
int16_t x, y;
uint16_t w, h;
m_display->setTextWrap(false);
m_display->getTextBounds(m_pages[m_currentPage].body.c_str(), 0, 0, &x, &y, &w, &h);
m_display->setCursor(5, top);
m_display->print(m_pages[m_currentPage].body.c_str());
top += h - 5;
m_display->drawLine(5, top, m_display->width() - 10, top, GxEPD_BLACK);
top += 5;
}
for (uint8_t i = 0; i < m_numMenuItemsinCurrentPage; i++) {
int16_t x, y;
uint16_t w, h;
m_display->getTextBounds(m_pages[m_currentPage].menuItems[m_currentMenuItem].title.c_str(), 5, top, &x, &y, &w, &h);
if (i == m_currentMenuItem) {
m_display->fillRect(5, top, m_display->width() - 15, h + 6, GxEPD_BLACK);
m_display->setTextColor(GxEPD_WHITE);
} else {
m_display->setTextColor(GxEPD_BLACK);
}
m_display->setFont(&FreeSans9pt7b);
m_display->setCursor(x, top + 15);
m_display->print(m_pages[m_currentPage].menuItems[i].title.c_str());
top += h + 5;
}
}
m_display->display(partialRefresh);
}
void Menu::Reset()
{
m_currentPage = 0;
m_currentMenuItem = 0;
m_numPages = m_pages.size();
if (m_numPages) {
m_numMenuItemsinCurrentPage = m_pages[m_currentPage].menuItems.size();
}
}

View file

@ -22,10 +22,10 @@ enum MenuTextAlignment {
struct MenuPage
{
uint8_t backPageNum;
std::string title;
MenuTextAlignment titleAlignment;
std::string body;
MenuTextAlignment bodyAlignment;
std::vector<MenuItem> menuItems;
};
@ -39,6 +39,7 @@ public:
void SetPages(const std::vector<MenuPage> & pages);
void SetExitCallback(std::function<void()> callback);
void Redraw(bool partialRefresh = false);
void Reset();
private:

View file

@ -6,22 +6,6 @@ RTC_DATA_ATTR bool WatchFace::m_menuSetup = false;
RTC_DATA_ATTR bool WatchFace::m_inMenu = false;
Menu WatchFace::m_menu;
static const std::vector<MenuPage> menuPages = {
{
"Watchy",
ALIGNMENT_CENTER,
"",
ALIGNMENT_CENTER,
{
{
"Sync NTP",
nullptr,
0
}
}
}
};
void WatchFace::Setup() // Called after hardware is set up
{
if (!m_menuSetup) {
@ -29,8 +13,7 @@ void WatchFace::Setup() // Called after hardware is set up
m_menu.Init(m_display);
}
m_menu.SetPages(menuPages);
m_menu.SetExitCallback(std::bind(&WatchFace::MenuExited, this));
SetupVolatileMenuStuff();
}
void WatchFace::HandleButtonPress(uint64_t buttonMask)
@ -102,6 +85,51 @@ void WatchFace::DrawBatteryIcon()
m_display.fillRect(200 - 44, 9, (int)std::round(35.0f * level), 15, GxEPD_BLACK);
}
void WatchFace::SetupVolatileMenuStuff()
{
static const std::vector<MenuPage> menuPages = {
{
0, // backPageNum
"WATCHY", // title
ALIGNMENT_CENTER, // titleAlignment
"", // body
{ // Menu items
{
"Sync NTP", // title
nullptr, // callback
1 // pageNum
},
{
"Back", // title
nullptr, // callback
0 // pageNum
}
},
},
{
0, // backPageNum
"SYNC NTP", // title
ALIGNMENT_CENTER, // titleAlignment
"Sync with:\n" NTP_SERVER, // body
{ // Menu items
{
"Sync", // title
std::bind(&WatchFace::MenuNTPSyncSelected, this), // callback
1 // pageNum
},
{
"Back", // title
nullptr, // callback
0 // pageNum
}
},
},
};
m_menu.SetPages(menuPages);
m_menu.SetExitCallback(std::bind(&WatchFace::MenuExited, this));
}
void WatchFace::MenuExited()
{
if (m_inMenu) {
@ -109,3 +137,16 @@ void WatchFace::MenuExited()
DrawWatchFace(false);
}
}
void WatchFace::MenuNTPSyncSelected()
{
ConnectWiFi();
SyncNTPTime();
DisconnectWiFi();
if (m_inMenu) {
m_inMenu = false;
m_menu.Reset();
DrawWatchFace(false);
}
}

View file

@ -15,6 +15,8 @@ private:
RTC_DATA_ATTR static bool m_inMenu;
RTC_DATA_ATTR static Menu m_menu;
void SetupVolatileMenuStuff();
void DrawBatteryIcon();
void MenuExited();
void MenuNTPSyncSelected();
};

View file

@ -119,7 +119,7 @@ void Watchy::SyncNTPTime()
{
WiFiUDP ntpUDP;
// GMT offset should be, RTC class will adjust to local time
NTPClient timeClient(ntpUDP, "pool.ntp.org", 0);
NTPClient timeClient(ntpUDP, NTP_SERVER, 0);
timeClient.begin();
bool success = timeClient.forceUpdate();
if (!success) {

View file

@ -1,3 +1,5 @@
#include <Wire.h>
#define MENU_BTN_PIN 26
#define BACK_BTN_PIN 25
#define DOWN_BTN_PIN 4
@ -22,6 +24,8 @@
#define DISPLAY_WIDTH 200
#define DISPLAY_HEIGHT 200
#define WIFI_SSID "<my ssid>>"
#define WIFI_PASS "<my pass>"
#define WIFI_SSID "<ssid>"
#define WIFI_PASS "<pass>"
#define TZ_OFFSET 3600 * 3
#define NTP_SERVER "pool.ntp.org"