Functional menu
This commit is contained in:
parent
5b7ef1c24f
commit
06839fa806
6 changed files with 160 additions and 30 deletions
96
src/Menu.cpp
96
src/Menu.cpp
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
};
|
|
@ -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) {
|
||||
|
|
|
@ -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"
|
Loading…
Reference in a new issue