From d5b0af3b19dadf39a74962280f268654928abf2b Mon Sep 17 00:00:00 2001 From: Thomas Hooge Date: Sun, 3 Aug 2025 21:18:08 +0200 Subject: [PATCH] Integrated config menu into system page --- lib/obp60task/ConfigMenu.cpp | 10 +++++ lib/obp60task/ConfigMenu.h | 3 ++ lib/obp60task/Graphics.cpp | 25 +++++++++++++ lib/obp60task/Graphics.h | 17 +++++++++ lib/obp60task/OBP60Extensions.cpp | 46 +++++++++++++---------- lib/obp60task/OBP60Extensions.h | 9 ++--- lib/obp60task/PageSystem.cpp | 61 +++++++++++++++++++++++++++++-- 7 files changed, 143 insertions(+), 28 deletions(-) create mode 100644 lib/obp60task/Graphics.cpp create mode 100644 lib/obp60task/Graphics.h diff --git a/lib/obp60task/ConfigMenu.cpp b/lib/obp60task/ConfigMenu.cpp index 1627531..65cff9f 100644 --- a/lib/obp60task/ConfigMenu.cpp +++ b/lib/obp60task/ConfigMenu.cpp @@ -192,3 +192,13 @@ Rect ConfigMenu::getItemRect(int8_t index) { return {static_cast(x), static_cast(y + index * h), static_cast(w), static_cast(h)}; } + +void ConfigMenu::setCallback(void (*callback)()) { + fptrCallback = callback; +} + +void ConfigMenu::storeValues() { + if (fptrCallback) { + fptrCallback(); + } +} diff --git a/lib/obp60task/ConfigMenu.h b/lib/obp60task/ConfigMenu.h index 439097d..e3e7993 100644 --- a/lib/obp60task/ConfigMenu.h +++ b/lib/obp60task/ConfigMenu.h @@ -44,6 +44,7 @@ private: uint16_t y; uint16_t w; uint16_t h; + void (*fptrCallback)(); public: ConfigMenu(String title, uint16_t menu_x, uint16_t menu_y); @@ -60,4 +61,6 @@ public: Point getXY(); Rect getRect(); Rect getItemRect(int8_t index); + void setCallback(void (*callback)()); + void storeValues(); }; diff --git a/lib/obp60task/Graphics.cpp b/lib/obp60task/Graphics.cpp new file mode 100644 index 0000000..ae0dcbd --- /dev/null +++ b/lib/obp60task/Graphics.cpp @@ -0,0 +1,25 @@ +/* +Generic graphics functions + +*/ +#include +#include "Graphics.h" + +Point rotatePoint(const Point& origin, const Point& p, double angle) { + // rotate poind around origin by degrees + Point rotated; + double phi = angle * M_PI / 180.0; + double dx = p.x - origin.x; + double dy = p.y - origin.y; + rotated.x = origin.x + cos(phi) * dx - sin(phi) * dy; + rotated.y = origin.y + sin(phi) * dx + cos(phi) * dy; + return rotated; +} + +std::vector rotatePoints(const Point& origin, const std::vector& pts, double angle) { + std::vector rotatedPoints; + for (const auto& p : pts) { + rotatedPoints.push_back(rotatePoint(origin, p, angle)); + } + return rotatedPoints; +} diff --git a/lib/obp60task/Graphics.h b/lib/obp60task/Graphics.h new file mode 100644 index 0000000..b55971b --- /dev/null +++ b/lib/obp60task/Graphics.h @@ -0,0 +1,17 @@ +#pragma once +#include + +struct Point { + double x; + double y; +}; + +struct Rect { + double x; + double y; + double w; + double h; +}; + +Point rotatePoint(const Point& origin, const Point& p, double angle); +std::vector rotatePoints(const Point& origin, const std::vector& pts, double angle); diff --git a/lib/obp60task/OBP60Extensions.cpp b/lib/obp60task/OBP60Extensions.cpp index 29d76a8..75821e9 100644 --- a/lib/obp60task/OBP60Extensions.cpp +++ b/lib/obp60task/OBP60Extensions.cpp @@ -297,30 +297,20 @@ String xdrDelete(String input){ return input; } -Point rotatePoint(const Point& origin, const Point& p, double angle) { - // rotate poind around origin by degrees - Point rotated; - double phi = angle * M_PI / 180.0; - double dx = p.x - origin.x; - double dy = p.y - origin.y; - rotated.x = origin.x + cos(phi) * dx - sin(phi) * dy; - rotated.y = origin.y + sin(phi) * dx + cos(phi) * dy; - return rotated; -} - -std::vector rotatePoints(const Point& origin, const std::vector& pts, double angle) { - std::vector rotatedPoints; - for (const auto& p : pts) { - rotatedPoints.push_back(rotatePoint(origin, p, angle)); - } - return rotatedPoints; -} - void fillPoly4(const std::vector& p4, uint16_t color) { getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[1].x, p4[1].y, p4[2].x, p4[2].y, color); getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[2].x, p4[2].y, p4[3].x, p4[3].y, color); } +void drawPoly(const std::vector& points, uint16_t color) { + size_t polysize = points.size(); + for (size_t i = 0; i < polysize - 1; i++) { + getdisplay().drawLine(points[i].x, points[i].y, points[i+1].x, points[i+1].y, color); + } + // close path + getdisplay().drawLine(points[polysize-1].x, points[polysize-1].y, points[0].x, points[0].y, color); +} + // Split string into words, whitespace separated std::vector split(const String &s) { std::vector words; @@ -382,6 +372,24 @@ void drawTextRalign(int16_t x, int16_t y, String text) { getdisplay().print(text); } +// Draw text inside box, normal or inverted +void drawTextBoxed(Rect box, String text, uint16_t fg, uint16_t bg, bool inverted, bool border) { + if (inverted) { + getdisplay().fillRect(box.x, box.y, box.w, box.h, fg); + getdisplay().setTextColor(bg); + } else { + if (border) { + getdisplay().fillRect(box.x + 1, box.y + 1, box.w - 2, box.h - 2, bg); + getdisplay().drawRect(box.x, box.y, box.w, box.h, fg); + } + getdisplay().setTextColor(fg); + } + uint16_t border_offset = box.h / 4; // 25% of box height + getdisplay().setCursor(box.x + border_offset, box.y + box.h - border_offset); + getdisplay().print(text); + getdisplay().setTextColor(fg); +} + // Show a triangle for trend direction high (x, y is the left edge) void displayTrendHigh(int16_t x, int16_t y, uint16_t size, uint16_t color){ getdisplay().fillTriangle(x, y, x+size*2, y, x+size, y-size*2, color); diff --git a/lib/obp60task/OBP60Extensions.h b/lib/obp60task/OBP60Extensions.h index 92e5486..bd15974 100644 --- a/lib/obp60task/OBP60Extensions.h +++ b/lib/obp60task/OBP60Extensions.h @@ -4,6 +4,7 @@ #include #include "OBP60Hardware.h" #include "LedSpiTask.h" +#include "Graphics.h" #include // E-paper lib V2 #include // I2C FRAM @@ -62,13 +63,8 @@ GxEPD2_BW & getdisplay(); #define PAGE_UPDATE 1 // page wants display to update #define PAGE_HIBERNATE 2 // page wants displey to hibernate -struct Point { - double x; - double y; -}; -Point rotatePoint(const Point& origin, const Point& p, double angle); -std::vector rotatePoints(const Point& origin, const std::vector& pts, double angle); void fillPoly4(const std::vector& p4, uint16_t color); +void drawPoly(const std::vector& points, uint16_t color); void deepSleep(CommonData &common); @@ -97,6 +93,7 @@ String xdrDelete(String input); // Delete xdr prefix from string void drawTextCenter(int16_t cx, int16_t cy, String text); void drawTextRalign(int16_t x, int16_t y, String text); +void drawTextBoxed(Rect box, String text, uint16_t fg, uint16_t bg, bool inverted, bool border); void displayTrendHigh(int16_t x, int16_t y, uint16_t size, uint16_t color); void displayTrendLow(int16_t x, int16_t y, uint16_t size, uint16_t color); diff --git a/lib/obp60task/PageSystem.cpp b/lib/obp60task/PageSystem.cpp index 700f9e9..2de30cc 100644 --- a/lib/obp60task/PageSystem.cpp +++ b/lib/obp60task/PageSystem.cpp @@ -2,6 +2,7 @@ #include "Pagedata.h" #include "OBP60Extensions.h" +#include "ConfigMenu.h" #include "images/logo64.xbm" #include #include "qrcode.h" @@ -44,6 +45,9 @@ class PageSystem : public Page { private: + GwConfigHandler *config; + GwLog *logger; + // NVRAM config options String flashLED; @@ -67,6 +71,9 @@ private: double homelon; char mode = 'N'; // (N)ormal, (S)ettings, (C)onfiguration, (D)evice list, c(A)rd + int8_t editmode = -1; // marker for menu/edit/set function + + ConfigMenu *menu; void incMode() { if (mode == 'N') { // Normal @@ -219,7 +226,7 @@ private: getdisplay().setFont(&Ubuntu_Bold8pt8b); - getdisplay().setCursor(x0, y0); + /*getdisplay().setCursor(x0, y0); getdisplay().print("CPU speed: 80 | 160 | 240"); getdisplay().setCursor(x0, y0 + 1 * dy); getdisplay().print("Power mode: Max | 5V | Min"); @@ -228,7 +235,30 @@ private: // TODO Change NVRAM-preferences settings here getdisplay().setCursor(x0, y0 + 4 * dy); - getdisplay().print("Simulation: On | Off"); + getdisplay().print("Simulation: On | Off"); */ + + getdisplay().setFont(&Ubuntu_Bold8pt8b); + for (int i = 0 ; i < menu->getItemCount(); i++) { + ConfigMenuItem *itm = menu->getItemByIndex(i); + if (!itm) { + LOG_DEBUG(GwLog::ERROR, "Menu item not found: %d", i); + } else { + Rect r = menu->getItemRect(i); + bool inverted = (i == menu->getActiveIndex()); + drawTextBoxed(r, itm->getLabel(), commonData->fgcolor, commonData->bgcolor, inverted, false); + if (inverted and editmode > 0) { + // triangle as edit marker + getdisplay().fillTriangle(r.x + r.w + 20, r.y, r.x + r.w + 30, r.y + r.h / 2, r.x + r.w + 20, r.y + r.h, commonData->fgcolor); + } + getdisplay().setCursor(r.x + r.w + 40, r.y + r.h - 4); + if (itm->getType() == "int") { + getdisplay().print(itm->getValue()); + getdisplay().print(itm->getUnit()); + } else { + getdisplay().print(itm->getValue() == 0 ? "No" : "Yes"); + } + } + } } void displayModeSettings() { @@ -351,10 +381,17 @@ private: getdisplay().print(String(commonData->status.n2kTx)); } + void storeConfig() { + menu->storeValues(); + } + public: PageSystem(CommonData &common){ commonData = &common; - common.logger->logDebug(GwLog::LOG,"Instantiate PageSystem"); + config = commonData->config; + logger = commonData->logger; + + logger->logDebug(GwLog::LOG,"Instantiate PageSystem"); if (hasFRAM) { mode = fram.read(FRAM_SYSTEM_MODE); } @@ -378,6 +415,24 @@ public: rot_sensor = common.config->getString(common.config->useRotSensor); homelat = common.config->getString(common.config->homeLAT).toDouble(); homelon = common.config->getString(common.config->homeLON).toDouble(); + + // CPU speed: 80 | 160 | 240 + // Power mode: Max | 5V | Min + // Accesspoint: On | Off + + // TODO Change NVRAM-preferences settings here + // getdisplay().setCursor(x0, y0 + 4 * dy); + // getdisplay().print("Simulation: On | Off"); + + // Initialize config menu + menu = new ConfigMenu("Options", 40, 80); + menu->setItemDimension(150, 20); + + ConfigMenuItem *newitem; + newitem = menu->addItem("accesspoint", "Accesspoint", "bool", 0, ""); + newitem = menu->addItem("simulation", "Simulation", "on/off", 0, ""); + menu->setItemActive("accesspoint"); + } virtual void setupKeys(){