From 7bf0743188380c77ca69b2f58dee72adf5b1a925 Mon Sep 17 00:00:00 2001 From: mbz4 <30321314+mbz4@users.noreply.github.com> Date: Sun, 10 May 2026 12:50:31 +0300 Subject: [PATCH 01/25] stop tracking chat_note.md --- docs/chat_note.md | 127 ---------------------------------------------- 1 file changed, 127 deletions(-) delete mode 100644 docs/chat_note.md diff --git a/docs/chat_note.md b/docs/chat_note.md deleted file mode 100644 index bb32148..0000000 --- a/docs/chat_note.md +++ /dev/null @@ -1,127 +0,0 @@ -=== CYD firmware — context for new chat === - -Repo: https://github.com/RobotStudyCompanion/CYD -Branches: - main branch-protected, integration target - dev/mbz my branch (current work) - dev/gio student's parallel Grobot test -Licence: Apache 2.0 - -=== Hardware === -ESP32-2432S028R (CYD original variant) -- ESP32 WROOM, no PSRAM, ~302 KB heap free at boot, 107 KB largest block -- ILI9341 320x240, SPI on (DC=2, CS=15, SCK=14, MOSI=13, MISO=12), BL=21 -- XPT2046 resistive touch (independent bus, bitbang) -- RGB LED on GPIO 4/16/17 (active low) -- LDR: investigated, none of GPIO 32/33/34/35/36/39 show light-responsive - behaviour. Floating-input signatures on most pins suggest this variant - doesn't have an LDR connected to any standard ADC1 pin. Either a clone - without LDR, or wired non-standardly. Hardware investigation needed - (visual / multimeter) before further software trial. External LDR on a - free GPIO is a fallback if light sensing genuinely needed. - -=== Software stack === -- platform = espressif32 6.4.0 (Arduino-ESP32 2.0.11) -- bodmer/TFT_eSPI 2.5.43 (ILI9341_2_DRIVER, 55 MHz SPI) -- tanmaywankar/Grobot_Animations 0.1.3, 320x140 sprite (~90 KB at RGB565) -- hexeguitar/CYD28_Touchscreen (bitbang fork, avoids HSPI collision) -- bitbank2/JPEGDEC (kept for future serial-JPEG, currently unused) -- Built-in Preferences for NVS persistence -- Git-describe versioning via PlatformIO extra_script - -=== Source layout === -include/ - Config.h shared config struct + initConfig/serviceConfig - DebugOverlay.h touch dots + memory/uptime/ldr/version helpers - DisplayInit.h TFT_eSPI init + setBacklight (PWM on GPIO 21) - FaceRenderer.h Grobot wrapper, setEyeColour/setBackgroundColour/setMood - LED_Solution.h setLedColor(r,g,b) for RGB LED - MjpegClass.h JPEG decoder wrapper (unused, kept for future) - TouchHandler.h initTouch + getTouchPoint (raw) - version.h AUTO-GENERATED, gitignored -src/ - Config.cpp dispatch-table command parser, NVS load/save - DebugOverlay.cpp dot rendering + edge detection + diag prints - DisplayInit.cpp display init + backlight PWM (LEDC channel 0) - FaceRenderer.cpp Grobot wrapper, splash, mood/colour application - LED_Solution.cpp - TouchHandler.cpp - main.cpp pure orchestration (~30 lines) -scripts/ - version.py git describe -> include/version.h pre-build hook - -=== Architecture === -- Config struct is single source of truth for stateful settings - (touchDebug, moodAutoCycle, showTouchDots, eyeColour, bgColour, mood, brightness) -- Config command parser uses dispatch table (Command struct with set/get - function pointers); auto-generates help and status output from the table -- FaceRenderer reads from config; setters update config and rebuild eyes/sprite -- DebugOverlay owns all visual debug + serial diagnostic helpers -- DisplayInit owns BL pin via LEDC (channel 0, 5 kHz, 8-bit PWM) -- All persistent settings stored in NVS namespace "rsc", saved on every change -- main.cpp = pure orchestration: printVersion, printMemoryReport, init*, service* - -=== UART command grammar === -- Setter form: key:value e.g. mood:HAPPY, eye_colour:00FF00, bright:128 -- Getter form: key? e.g. mood?, bright? -- Plain form: key acts as getter for settable, action for plain -- 22 commands total. Type 'help' on serial monitor for the list. -- All settable values persisted to NVS automatically on change. - -=== Key build flags (platformio.ini) === -USER_SETUP_LOADED=1, ILI9341_2_DRIVER=1 -TFT_MISO=12 TFT_MOSI=13 TFT_SCLK=14 TFT_CS=15 TFT_DC=2 TFT_RST=-1 TFT_BL=21 -TFT_BACKLIGHT_ON=HIGH, SPI_FREQUENCY=55000000 -LOAD_GLCD=1 LOAD_FONT2=1 LOAD_FONT4=1 LOAD_GFXFF=1 SMOOTH_FONT=1 -extra_scripts = pre:scripts/version.py -monitor_echo = yes - -=== Done across the whole journey === -- Track 1 quick fixes (HSPI swap, halt removal, debounce, debug gating) -- Migration Arduino_GFX -> TFT_eSPI + Grobot_Animations -- Sprite resize 120 -> 140 px tall (crisper eyes within memory budget) -- Renames: AnimationPlayer -> DisplayInit, TouchOverlay -> DebugOverlay -- DebugOverlay extracted: dots, edge detection, mem/uptime/ldr/version helpers -- Config layer: NVS-persisted struct + non-blocking serial parser -- Dispatch-table refactor: 22 commands, auto-generated help/status -- Backlight PWM, LED control, tap injection, splash/clear actions -- Version system: git-describe -> version.h, monitor echo enabled - -=== Open / next === -- LDR: probably absent on this variant; the 'ldr' command currently always - returns 0 (or noise). Either remove the command or hook to an external - sensor on a free GPIO. Defer until light-sensing actually needed.- PR dev/mbz to main; tag v0.1.0 (version string auto-upgrades from hash to semver) -- Coordinate with Gio on Grobot before merging anything that touches FaceRenderer -- Track 3: UIManager (modes FACE/MENU/TEXT), long-press menu trigger, - UART 'text:...' command for MODE_TEXT, PNG via bitbank2/PNGdec, - larger fonts via Adafruit GFX free fonts, mode-aware loop() -- Future: light-driven auto-brightness once LDR pin is sorted -- Future: status/loading screens (sprite + static background pattern from whiteboard) -- Future: serial-JPEG path (re-activate MjpegClass for 'image:' command) -- Minor: showSplash() blocks 800ms; non-blocking version wanted for Track 3 -- Minor: 'clear' command is partial in eye band (sprite repaints over) -- Expose Grobot's fine-grained controls over UART: - face:topH,botH,tilt,pR,r custom mood (symmetric) - face_l:... / face_r:... asymmetric per-eye - look:x,y canvas offset (lookAt) - blink manual blink trigger - hud:on|off FPS overlay toggle - All map to existing Grobot public API; ~50-60 lines via dispatch table. - Unblocks host-side tooling (e.g. live-control extension). - -=== Tooling / host-side === -- VS Code / Codium extension idea: live remote control of CYD over serial, - panel UI sends UART commands, reads back via getters. Lives in separate repo. - Bottleneck is firmware API surface, addressed by face-control commands above. -- Tanmay's GrobotAnimator (pre-alpha) at tanmaywankar.github.io/GrobotAnimator - — could contribute back to it as a richer offline simulator, separate effort -- Future fork of Grobot to expose eyeGap/blinkTime/spring constants as overridable - via #ifndef guards; submit as PR upstream rather than maintaining a private fork -- Future RPi/laptop counterpart controller: speaks the UART grammar, drives the - CYD in production. Existing 22 commands + face controls cover the surface. - -=== User preferences (carry forward) === -British English, active voice. Brief diff points (file + location + change), -not full file rewrites where avoidable. Ask before heavy refactor / token- -burny work. Working within hardware limitations — no PSRAM expansion unless -forced. Like the rhythm of one fix at a time with checkpoints. \ No newline at end of file From 8eced337ad638fa19ee7f1f71029f06d3c25d148 Mon Sep 17 00:00:00 2001 From: mbz4 <30321314+mbz4@users.noreply.github.com> Date: Sun, 10 May 2026 17:51:51 +0300 Subject: [PATCH 02/25] dynamic labels experiment --- include/Config.h | 3 ++ include/MenuSchema.h | 5 ++-- src/Config.cpp | 32 ++++++++++++++++---- src/MenuSchema.cpp | 26 +++++++++++++--- src/UIManager.cpp | 70 +++++++++++++++++++++++++++++++++++--------- 5 files changed, 110 insertions(+), 26 deletions(-) diff --git a/include/Config.h b/include/Config.h index c079dfc..9ab365d 100644 --- a/include/Config.h +++ b/include/Config.h @@ -14,6 +14,7 @@ struct Config { uint8_t brightLight = 50; // target % in bright rooms uint8_t brightDark = 1; // target % in dark rooms bool idleAnim = false; + String (*format)(); // optional: short live-value string for menus, e.g. "75%" }; extern Config config; @@ -26,7 +27,9 @@ struct Command { void (*set)(const String& val); void (*get)(); const char* help; + String (*format)(); }; + const Command* findCommand(const String& name); void serviceNvs(); void markDirty(); // for setters diff --git a/include/MenuSchema.h b/include/MenuSchema.h index 217ebf2..e6a0d41 100644 --- a/include/MenuSchema.h +++ b/include/MenuSchema.h @@ -1,13 +1,14 @@ #pragma once #include -enum ActionKind : uint8_t { ACT_PUSH, ACT_INVOKE, ACT_BACK }; +enum ActionKind : uint8_t { ACT_PUSH, ACT_INVOKE, ACT_BACK, ACT_NONE }; struct MenuScreen; struct MenuItem { const char* label; ActionKind kind; const void* payload; // MenuScreen* or const char* + const char* formatCmd; // optional: command name whose format() supplies the live suffix }; struct MenuScreen { const char* title; @@ -23,5 +24,5 @@ const MenuScreen* getActiveRoot(); void resetRuntimeSchema(); bool runtimeBegin(); bool runtimeAddScreen(const char* title); -bool runtimeAddItem(ActionKind kind, const char* label, const char* payload); +bool runtimeAddItem(ActionKind kind, const char* label, const char* payload, const char* formatCmd = nullptr); bool runtimeEnd(); \ No newline at end of file diff --git a/src/Config.cpp b/src/Config.cpp index 9495141..c1e68d6 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -283,17 +283,24 @@ static void cmdMenuScreen(const String& val) { } static void cmdMenuItem(const String& val) { int c1 = val.indexOf(','); - if (c1 < 0) { Serial.println("ERR: need kind,label[,payload]"); return; } + if (c1 < 0) { Serial.println("ERR: need kind,label[,payload[,formatCmd]]"); return; } int c2 = val.indexOf(',', c1 + 1); + int c3 = (c2 < 0) ? -1 : val.indexOf(',', c2 + 1); String kindStr = val.substring(0, c1); kindStr.toLowerCase(); - String label = (c2 < 0) ? val.substring(c1 + 1) : val.substring(c1 + 1, c2); - String payload = (c2 < 0) ? String() : val.substring(c2 + 1); + String label = (c2 < 0) ? val.substring(c1 + 1) + : val.substring(c1 + 1, c2); + String payload = (c2 < 0) ? String() + : (c3 < 0) ? val.substring(c2 + 1) + : val.substring(c2 + 1, c3); + String fmt = (c3 < 0) ? String() : val.substring(c3 + 1); ActionKind k; if (kindStr == "push") k = ACT_PUSH; else if (kindStr == "invoke") k = ACT_INVOKE; else if (kindStr == "back") k = ACT_BACK; - else { Serial.println("ERR: kind must be push|invoke|back"); return; } - if (runtimeAddItem(k, label.c_str(), payload.c_str())) Serial.println("OK"); + else if (kindStr == "none") k = ACT_NONE; + else { Serial.println("ERR: kind must be push|invoke|back|none"); return; } + const char* fmtPtr = fmt.length() ? fmt.c_str() : nullptr; + if (runtimeAddItem(k, label.c_str(), payload.c_str(), fmtPtr)) Serial.println("OK"); else Serial.println("ERR: addItem failed"); } static void cmdMenuEnd() { @@ -313,6 +320,15 @@ static void cmdGetAutoBright() { Serial.printf("auto_bright: %s\n", config.au static void cmdGetBrightLight(){ Serial.printf("bright_light: %u%%\n", config.brightLight); } static void cmdGetBrightDark() { Serial.printf("bright_dark: %u%%\n", config.brightDark); } static void cmdGetVersion() { Serial.printf("version: %s\n", FW_VERSION); } +static String fmtBright() { return String(config.brightness) + "%"; } +static String fmtMood() { return String(config.mood); } +static String fmtUptime() { + uint32_t s = millis() / 1000; + char buf[16]; + snprintf(buf, sizeof(buf), "%um %us", s / 60, s % 60); + return String(buf); +} +static String fmtMem() { return String(ESP.getFreeHeap() / 1024) + "K"; } // ============ Action handlers (no value, no get/set distinction) ============ static void cmdReset() { @@ -370,7 +386,7 @@ static const Command commands[] = { {"mode", cmdSetMode, cmdGetMode, "FACE|MENU"}, {"menu_begin", nullptr, cmdMenuBegin, "start runtime schema load"}, {"menu_screen", cmdMenuScreen, nullptr, "title add screen"}, - {"menu_item", cmdMenuItem, nullptr, "kind,label,payload add item"}, + {"menu_item", cmdMenuItem, nullptr, "kind,label,payload[,formatCmd] kind=push|invoke|back|none"}, {"menu_end", nullptr, cmdMenuEnd, "finalise + activate runtime schema"}, // Set-only commands @@ -397,6 +413,10 @@ static const Command commands[] = { {"resume", nullptr, cmdResume, "resume face renderer"}, {"reboot", nullptr, cmdReboot, "soft reboot (config preserved)"}, {"reset", nullptr, cmdReset, "clear NVS, reboot to defaults"}, + {"mood", cmdSetMood, cmdGetMood, "NEUTRAL|HAPPY|ANGRY|SAD|EXCITED|ANNOYED|QUESTIONING|IDLE1-3", fmtMood}, + {"bright", cmdSetBright, cmdGetBright, "0-100 backlight %", fmtBright}, + {"uptime", nullptr, cmdUptime, "time since boot", fmtUptime}, + {"mem", nullptr, cmdMem, "memory snapshot", fmtMem}, }; static const size_t COMMAND_COUNT = sizeof(commands) / sizeof(commands[0]); diff --git a/src/MenuSchema.cpp b/src/MenuSchema.cpp index a4db91a..e34ea93 100644 --- a/src/MenuSchema.cpp +++ b/src/MenuSchema.cpp @@ -31,6 +31,7 @@ static MenuItem* rtItemsFor(int screenIdx) { extern const MenuScreen ROOT_MENU; extern const MenuScreen MOOD_MENU; extern const MenuScreen BRIGHTNESS_MENU; +extern const MenuScreen STATUS_MENU; static const MenuItem BRIGHTNESS_ITEMS[] = { {"25%", ACT_INVOKE, "bright:25"}, @@ -50,13 +51,23 @@ static const MenuItem MOOD_ITEMS[] = { }; const MenuScreen MOOD_MENU = {"Mood", MOOD_ITEMS, 5}; +static const MenuItem STATUS_ITEMS[] = { + {"Bright", ACT_NONE, nullptr, "bright"}, + {"Mood", ACT_NONE, nullptr, "mood"}, + {"Up", ACT_NONE, nullptr, "uptime"}, + {"Mem", ACT_NONE, nullptr, "mem"}, + {"Back", ACT_BACK, nullptr}, +}; +const MenuScreen STATUS_MENU = {"Status", STATUS_ITEMS, 5}; + static const MenuItem ROOT_ITEMS[] = { - {"Brightness", ACT_PUSH, &BRIGHTNESS_MENU}, - {"Mood", ACT_PUSH, &MOOD_MENU}, + {"Brightness", ACT_PUSH, &BRIGHTNESS_MENU, "bright"}, + {"Mood", ACT_PUSH, &MOOD_MENU, "mood"}, + {"Status", ACT_PUSH, &STATUS_MENU, nullptr}, {"Blink", ACT_INVOKE, "blink"}, {"Resume", ACT_BACK, nullptr}, }; -const MenuScreen ROOT_MENU = {"Menu", ROOT_ITEMS, 4}; +const MenuScreen ROOT_MENU = {"Menu", ROOT_ITEMS, 5}; void resetRuntimeSchema() { @@ -75,7 +86,7 @@ bool runtimeAddScreen(const char* title) { return true; } -bool runtimeAddItem(ActionKind kind, const char* label, const char* payload) { +bool runtimeAddItem(ActionKind kind, const char* label, const char* payload, const char* formatCmd) { if (!_rtLoading || _rtCurScreen < 0) return false; MenuScreen& s = _rtScreens[_rtCurScreen]; if (s.count >= MAX_RT_ITEMS) return false; @@ -93,6 +104,13 @@ bool runtimeAddItem(ActionKind kind, const char* label, const char* payload) { } else { it.payload = nullptr; } + if (formatCmd && *formatCmd) { + const char* f = poolString(formatCmd); + if (!f) return false; + it.formatCmd = f; + } else { + it.formatCmd = nullptr; + } return true; } diff --git a/src/UIManager.cpp b/src/UIManager.cpp index ef60595..d58d286 100644 --- a/src/UIManager.cpp +++ b/src/UIManager.cpp @@ -9,12 +9,17 @@ extern TFT_eSPI tft; static bool _dirty = false; +static unsigned long _lastMenuRender = 0; + static UIMode _mode = MODE_FACE; static const MenuScreen* _stack[8]; static uint8_t _depth = 0; +static String _lastRowText[8]; // matches MAX_RT_ITEMS in MenuSchema.cpp + static int hitTest(uint16_t x, uint16_t y); static void renderMenu(); +static void renderRows(); static void enterMenu() { _mode = MODE_MENU; @@ -55,8 +60,9 @@ void serviceUI() { if (idx >= 0) { const MenuScreen* s = _stack[_depth - 1]; const MenuItem& it = s->items[idx]; - const char* k = it.kind == ACT_PUSH ? "PUSH" - : it.kind == ACT_INVOKE ? "INVOKE" : "BACK"; + const char* k = it.kind == ACT_PUSH ? "PUSH" + : it.kind == ACT_INVOKE ? "INVOKE" + : it.kind == ACT_BACK ? "BACK" : "NONE"; Serial.printf("MENU: tap row %d (%s, %s)\n", idx, it.label, k); menuSelect((uint8_t)idx); } else { @@ -64,11 +70,22 @@ void serviceUI() { } } } + auto screenHasFormatters = []() -> bool { + if (_depth == 0) return false; + const MenuScreen* s = _stack[_depth - 1]; + for (uint8_t i = 0; i < s->count; i++) if (s->items[i].formatCmd) return true; + return false; + }; if (_mode == MODE_MENU && _dirty) { renderMenu(); + _lastMenuRender = millis(); _dirty = false; } + else if (_mode == MODE_MENU && screenHasFormatters() && (millis() - _lastMenuRender) > 250) { + renderRows(); + _lastMenuRender = millis(); + } } UIMode getUIMode() { return _mode; } @@ -111,6 +128,8 @@ bool menuSelect(uint8_t idx) { else if (c->get) c->get(); return true; } + case ACT_NONE: + return true; // acknowledged, no action } return false; } @@ -128,8 +147,9 @@ void printMenuState() { Serial.printf("menu: %s (depth %u)\n", s->title, _depth); for (uint8_t i = 0; i < s->count; i++) { const MenuItem& it = s->items[i]; - const char* k = it.kind == ACT_PUSH ? "PUSH" - : it.kind == ACT_INVOKE ? "INVOKE" : "BACK"; + const char* k = it.kind == ACT_PUSH ? "PUSH" + : it.kind == ACT_INVOKE ? "INVOKE" + : it.kind == ACT_BACK ? "BACK" : "NONE"; Serial.printf(" [%u] %-16s %s\n", i, it.label, k); } } @@ -143,24 +163,46 @@ static int hitTest(uint16_t x, uint16_t y) { return (idx < 0 || idx >= s->count) ? -1 : idx; } -static void renderMenu() { +static void renderRows() { if (_mode != MODE_MENU || _depth == 0) return; const MenuScreen* s = _stack[_depth - 1]; - tft.fillScreen(TFT_BLACK); tft.setTextSize(1); - tft.setFreeFont(&FreeSansBold12pt7b); + tft.setFreeFont(&FreeSans12pt7b); tft.setTextColor(TFT_WHITE, TFT_BLACK); tft.setTextDatum(TL_DATUM); - tft.drawString(s->title, 12, 8); - - tft.drawFastHLine(0, 36, 320, TFT_DARKGREY); - - tft.setFreeFont(&FreeSans12pt7b); char buf[64]; int y = 48; for (uint8_t i = 0; i < s->count; i++) { - snprintf(buf, sizeof(buf), "%u %s", i, s->items[i].label); - tft.drawString(buf, 12, y); + const MenuItem& it = s->items[i]; + if (it.formatCmd) { + const Command* c = findCommand(it.formatCmd); + if (c && c->format) { + snprintf(buf, sizeof(buf), "%u %s: %s", i, it.label, c->format().c_str()); + } else { + snprintf(buf, sizeof(buf), "%u %s", i, it.label); + } + } else { + snprintf(buf, sizeof(buf), "%u %s", i, it.label); + } + if (_lastRowText[i] != buf) { + tft.fillRect(0, y - 4, 320, 32, TFT_BLACK); + tft.drawString(buf, 12, y); + _lastRowText[i] = buf; + } y += 36; } +} + +static void renderMenu() { + if (_mode != MODE_MENU || _depth == 0) return; + const MenuScreen* s = _stack[_depth - 1]; + tft.fillScreen(TFT_BLACK); + for (int i = 0; i < 8; i++) _lastRowText[i] = ""; + tft.setTextSize(1); + tft.setFreeFont(&FreeSansBold12pt7b); + tft.setTextColor(TFT_WHITE, TFT_BLACK); + tft.setTextDatum(TL_DATUM); + tft.drawString(s->title, 12, 8); + tft.drawFastHLine(0, 36, 320, TFT_DARKGREY); + renderRows(); } \ No newline at end of file From 4da9b227b5abf1413f0b1c2e18f663d84895b12d Mon Sep 17 00:00:00 2001 From: mbz4 <30321314+mbz4@users.noreply.github.com> Date: Mon, 11 May 2026 11:20:45 +0300 Subject: [PATCH 03/25] add guislice, start refactor to guislice menus --- .gitignore | 3 +- include/MenuApp.h | 12 ++ include/TouchHandler.h | 31 +++++ include/UIManager.h | 6 +- include/test_GSLC.h | 294 +++++++++++++++++++++++++++++++++++++++++ platformio.ini | 29 +++- src/MenuCallbacks.cpp | 0 src/UIManager.cpp | 173 +++--------------------- src/main.cpp | 27 +++- 9 files changed, 410 insertions(+), 165 deletions(-) create mode 100644 include/MenuApp.h create mode 100644 include/test_GSLC.h create mode 100644 src/MenuCallbacks.cpp diff --git a/.gitignore b/.gitignore index eb17851..9e0918c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ include/version.h /net-commander docs -data \ No newline at end of file +data +test \ No newline at end of file diff --git a/include/MenuApp.h b/include/MenuApp.h new file mode 100644 index 0000000..80515c2 --- /dev/null +++ b/include/MenuApp.h @@ -0,0 +1,12 @@ +#pragma once +#include "GUIslice.h" + +// GUIslice gui state lives in MenuCallbacks.cpp (single TU defining test_GSLC.h's globals) +extern gslc_tsGui m_gui; + +// Generated by Builder; defined in test_GSLC.h +extern void InitGUIslice_gen(); + +// Page IDs — must match enum order in test_GSLC.h. +// Update when redesigning menus in Builder. +static const int16_t MENU_PG_ROOT = 0; // E_PG_MAIN \ No newline at end of file diff --git a/include/TouchHandler.h b/include/TouchHandler.h index 4a41369..741bec7 100644 --- a/include/TouchHandler.h +++ b/include/TouchHandler.h @@ -2,6 +2,7 @@ #define TOUCHHANDLER_H #include +#include void initTouch(); bool getTouchPoint(uint16_t &x, uint16_t &y, uint16_t &z); @@ -14,4 +15,34 @@ struct TouchEvent { bool pollTouchEvent(TouchEvent& out); bool peekLastTouch(uint16_t& x, uint16_t& y, uint16_t& z); + +// GUIslice adapter — bridges this touch layer to GUIslice's plugin interface. +// Instantiate in main.cpp, register via gslc_InitTouchHandler(). +class CydTouchHandler : public TouchHandler { +public: + void begin() override {} // no-op; hardware init done in initTouch() + + THPoint getPoint() override { + uint16_t x, y, z; + bool touched = peekLastTouch(x, y, z); + if (touched) { + if (!inTouch_) { inTouch_ = true; x_ = x; y_ = y; } + else { x_ = (x_ * 7 + x) / 8; y_ = (y_ * 7 + y) / 8; } + releaseHoldoff_ = 3; + return THPoint(x_, y_, z ? z : 100); + } + if (releaseHoldoff_ > 0) { + releaseHoldoff_--; + return THPoint(x_, y_, 100); + } + inTouch_ = false; + return THPoint(0, 0, 0); + } + +private: + int16_t x_ = 0, y_ = 0; + bool inTouch_ = false; + uint8_t releaseHoldoff_ = 0; +}; + #endif \ No newline at end of file diff --git a/include/UIManager.h b/include/UIManager.h index 623894f..235a603 100644 --- a/include/UIManager.h +++ b/include/UIManager.h @@ -1,6 +1,5 @@ #pragma once #include -#include "MenuSchema.h" enum UIMode : uint8_t { MODE_FACE, MODE_MENU }; @@ -10,7 +9,8 @@ void serviceUI(); UIMode getUIMode(); void setUIMode(UIMode m); -void menuBack(); -bool menuSelect(uint8_t idx); +// Kept for dispatch-table compatibility (Config.cpp's cmdMenu*) +void menuBack(); // exits to FACE mode +bool menuSelect(uint8_t idx); // deprecated, no-op void printMode(); void printMenuState(); \ No newline at end of file diff --git a/include/test_GSLC.h b/include/test_GSLC.h new file mode 100644 index 0000000..2196bc3 --- /dev/null +++ b/include/test_GSLC.h @@ -0,0 +1,294 @@ +// +// FILE: [test_GSLC.h] +// Created by GUIslice Builder version: [0.17.b41] +// +// GUIslice Builder Generated GUI Framework File +// +// For the latest guides, updates and support view: +// https://github.com/ImpulseAdventure/GUIslice +// +// + +#ifndef _GUISLICE_GEN_H +#define _GUISLICE_GEN_H +// keep root page first +// ------------------------------------------------ +// Headers to include +// ------------------------------------------------ +#include "GUIslice.h" +#include "GUIslice_drv.h" + +// Include any extended elements +// +// Include extended elements +#include "elem/XCheckbox.h" +#include "elem/XKeyPad_Alpha.h" +#include "elem/XKeyPad_Num.h" +#include "elem/XProgress.h" +#include "elem/XRamp.h" +#include "elem/XRingGauge.h" +#include "elem/XSlider.h" +#include "elem/XSpinner.h" +#include "elem/XTogglebtn.h" + +// Ensure optional features are enabled in the configuration +#if !(GSLC_FEATURE_COMPOUND) + #error "Config: GSLC_FEATURE_COMPOUND required for this program but not enabled. Please see: https://github.com/ImpulseAdventure/GUIslice/wiki/Configuring-GUIslice" +#endif +// + +// ------------------------------------------------ +// Headers and Defines for fonts +// Note that font files are located within the Adafruit-GFX library folder: +// ------------------------------------------------ +// +#if !defined(DRV_DISP_TFT_ESPI) + #error E_PROJECT_OPTIONS tab->Graphics Library should be Adafruit_GFX +#endif +#include +// + +// ------------------------------------------------ +// Defines for resources +// ------------------------------------------------ +// +// + +// ------------------------------------------------ +// Enumerations for pages, elements, fonts, images +// ------------------------------------------------ +// +enum {E_PG_MAIN,E_POP_KEYPAD_NUM,E_POP_KEYPAD_ALPHA}; +enum {E_ELEM_BOX1,E_ELEM_BTN1,E_ELEM_BTN2,E_ELEM_CHECK1 + ,E_ELEM_NUMINPUT1,E_ELEM_PROGRESS1,E_ELEM_RADIO1 + ,E_ELEM_RAMPGAUGE1,E_ELEM_RINGGAUGE1,E_ELEM_SLIDER1 + ,E_ELEM_SPINNER1,E_ELEM_TEXT1,E_ELEM_TEXTINPUT1,E_ELEM_TOGGLE1 + ,E_ELEM_KEYPAD_NUM,E_ELEM_KEYPAD_ALPHA}; +// Must use separate enum for fonts with MAX_FONT at end to use gslc_FontSet. +enum {E_BUILTIN5X8,MAX_FONT}; +// + +// ------------------------------------------------ +// Instantiate the GUI +// ------------------------------------------------ + +// ------------------------------------------------ +// Define the maximum number of elements and pages +// ------------------------------------------------ +// +#define MAX_PAGE 3 + +#define MAX_ELEM_PG_MAIN 14 // # Elems total on page +#define MAX_ELEM_PG_MAIN_RAM MAX_ELEM_PG_MAIN // # Elems in RAM +// + +// ------------------------------------------------ +// Create element storage +// ------------------------------------------------ +gslc_tsGui m_gui; +gslc_tsDriver m_drv; +gslc_tsFont m_asFont[MAX_FONT]; +gslc_tsPage m_asPage[MAX_PAGE]; + +// +gslc_tsElem m_asPage1Elem[MAX_ELEM_PG_MAIN_RAM]; +gslc_tsElemRef m_asPage1ElemRef[MAX_ELEM_PG_MAIN]; +gslc_tsElem m_asKeypadNumElem[1]; +gslc_tsElemRef m_asKeypadNumElemRef[1]; +gslc_tsElem m_asKeypadAlphaElem[1]; +gslc_tsElemRef m_asKeypadAlphaElemRef[1]; +gslc_tsXKeyPad m_sKeyPadNum; +gslc_tsXKeyPad m_sKeyPadAlpha; +gslc_tsXSpinner m_sXSpinner1; +gslc_tsXRingGauge m_sXRingGauge1; +gslc_tsXProgress m_sXBarGauge1; +gslc_tsXSlider m_sXSlider1; +gslc_tsXTogglebtn m_asXToggle1; +gslc_tsXCheckbox m_asXCheck1; +gslc_tsXCheckbox m_asXRadio1; +gslc_tsXRamp m_sXRampGauge1; + +#define MAX_STR 100 + +// + +// ------------------------------------------------ +// Program Globals +// ------------------------------------------------ + +// Element References for direct access +// +extern gslc_tsElemRef* m_pElemCBCheckBox; +extern gslc_tsElemRef* m_pElemInTxt1; +extern gslc_tsElemRef* m_pElemProgress1; +extern gslc_tsElemRef* m_pElemRBRadioButton; +extern gslc_tsElemRef* m_pElemRamp1; +extern gslc_tsElemRef* m_pElemSlider1; +extern gslc_tsElemRef* m_pElemSpinner1; +extern gslc_tsElemRef* m_pElemToggle1; +extern gslc_tsElemRef* m_pElemVal1; +extern gslc_tsElemRef* m_pElemXRingGauge1; +extern gslc_tsElemRef* m_pElemKeyPadNum; +extern gslc_tsElemRef* m_pElemKeyPadAlpha; +// + +// Define debug message function +static int16_t DebugOut(char ch); + +// ------------------------------------------------ +// Callback Methods +// ------------------------------------------------ +bool CbBtnCommon(void* pvGui,void *pvElemRef,gslc_teTouch eTouch,int16_t nX,int16_t nY); +bool CbCheckbox(void* pvGui, void* pvElemRef, int16_t nSelId, bool bState); +bool CbDrawScanner(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw); +bool CbKeypad(void* pvGui, void *pvElemRef, int16_t nState, void* pvData); +bool CbListbox(void* pvGui, void* pvElemRef, int16_t nSelId); +bool CbSlidePos(void* pvGui,void* pvElemRef,int16_t nPos); +bool CbSpinner(void* pvGui, void *pvElemRef, int16_t nState, void* pvData); +bool CbTickScanner(void* pvGui,void* pvScope); + +// ------------------------------------------------ +// Create page elements +// ------------------------------------------------ +void InitGUIslice_gen() +{ + gslc_tsElemRef* pElemRef = NULL; + + if (!gslc_Init(&m_gui,&m_drv,m_asPage,MAX_PAGE,m_asFont,MAX_FONT)) { return; } + + // ------------------------------------------------ + // Load Fonts + // ------------------------------------------------ +// + if (!gslc_FontSet(&m_gui,E_BUILTIN5X8,GSLC_FONTREF_PTR,NULL,1)) { return; } +// + +// + gslc_PageAdd(&m_gui,E_PG_MAIN,m_asPage1Elem,MAX_ELEM_PG_MAIN_RAM,m_asPage1ElemRef,MAX_ELEM_PG_MAIN); + gslc_PageAdd(&m_gui,E_POP_KEYPAD_NUM,m_asKeypadNumElem,1,m_asKeypadNumElemRef,1); // KeyPad + gslc_PageAdd(&m_gui,E_POP_KEYPAD_ALPHA,m_asKeypadAlphaElem,1,m_asKeypadAlphaElemRef,1); // KeyPad + + // NOTE: The current page defaults to the first page added. Here we explicitly + // ensure that the main page is the correct page no matter the add order. + gslc_SetPageCur(&m_gui,E_PG_MAIN); + + // Set Background to a flat color + gslc_SetBkgndColor(&m_gui,GSLC_COL_BLACK); + + // ----------------------------------- + // PAGE: E_PG_MAIN + + + // create E_ELEM_BTN1 button with text label + pElemRef = gslc_ElemCreateBtnTxt(&m_gui,E_ELEM_BTN1,E_PG_MAIN, + (gslc_tsRect){14,12,80,40},(char*)"",0,E_BUILTIN5X8,&CbBtnCommon); + + // Create E_ELEM_BOX1 box + pElemRef = gslc_ElemCreateBox(&m_gui,E_ELEM_BOX1,E_PG_MAIN,(gslc_tsRect){187,4,126,119}); + + // Add Spinner element + pElemRef = gslc_ElemXSpinnerCreate(&m_gui,E_ELEM_SPINNER1,E_PG_MAIN,&m_sXSpinner1, + (gslc_tsRect){176,205,136,32},0,99,0,1,E_BUILTIN5X8,20,&CbSpinner); + m_pElemSpinner1 = pElemRef; + + // Create ring gauge E_ELEM_RINGGAUGE1 + static char m_sRingText1[11] = ""; + pElemRef = gslc_ElemXRingGaugeCreate(&m_gui,E_ELEM_RINGGAUGE1,E_PG_MAIN,&m_sXRingGauge1, + (gslc_tsRect){201,17,100,100}, + (char*)m_sRingText1,11,E_BUILTIN5X8); + gslc_ElemXRingGaugeSetValRange(&m_gui, pElemRef, 0, 100); + gslc_ElemXRingGaugeSetVal(&m_gui, pElemRef, 0); // Set initial value + m_pElemXRingGauge1 = pElemRef; + + // Create E_ELEM_TEXT1 text label + pElemRef = gslc_ElemCreateTxt(&m_gui,E_ELEM_TEXT1,E_PG_MAIN,(gslc_tsRect){111,14,60,10}, + (char*)"",0,E_BUILTIN5X8); + + // Create progress bar E_ELEM_PROGRESS1 + pElemRef = gslc_ElemXProgressCreate(&m_gui,E_ELEM_PROGRESS1,E_PG_MAIN,&m_sXBarGauge1, + (gslc_tsRect){200,178,111,18},0,100,0,GSLC_COL_GREEN,false); + m_pElemProgress1 = pElemRef; + + // Create slider E_ELEM_SLIDER1 + pElemRef = gslc_ElemXSliderCreate(&m_gui,E_ELEM_SLIDER1,E_PG_MAIN,&m_sXSlider1, + (gslc_tsRect){205,136,110,37},0,100,0,5,false); + gslc_ElemXSliderSetStyle(&m_gui,pElemRef,false,GSLC_COL_BLUE,10,5,GSLC_COL_BLUE); + gslc_ElemXSliderSetPosFunc(&m_gui,pElemRef,&CbSlidePos); + m_pElemSlider1 = pElemRef; + + // Create toggle button E_ELEM_TOGGLE1 + pElemRef = gslc_ElemXTogglebtnCreate(&m_gui,E_ELEM_TOGGLE1,E_PG_MAIN,&m_asXToggle1, + (gslc_tsRect){123,162,64,24},GSLC_COL_GRAY,GSLC_COL_BLUE_DK2,GSLC_COL_GRAY_LT3, + true,false,&CbBtnCommon); + m_pElemToggle1 = pElemRef; + + // create checkbox E_ELEM_CHECK1 + pElemRef = gslc_ElemXCheckboxCreate(&m_gui,E_ELEM_CHECK1,E_PG_MAIN,&m_asXCheck1, + (gslc_tsRect){120,201,31,31},false,GSLCX_CHECKBOX_STYLE_X,GSLC_COL_ORANGE,false); + gslc_ElemXCheckboxSetStateFunc(&m_gui, pElemRef, &CbCheckbox); + m_pElemCBCheckBox = pElemRef; + + // Create radio button E_ELEM_RADIO1 + pElemRef = gslc_ElemXCheckboxCreate(&m_gui,E_ELEM_RADIO1,E_PG_MAIN,&m_asXRadio1, + (gslc_tsRect){234,49,34,34},true,GSLCX_CHECKBOX_STYLE_ROUND,GSLC_COL_ORANGE,false); + gslc_ElemXCheckboxSetStateFunc(&m_gui, pElemRef, &CbCheckbox); + m_pElemRBRadioButton = pElemRef; + + // create E_ELEM_BTN2 button with text label + pElemRef = gslc_ElemCreateBtnTxt(&m_gui,E_ELEM_BTN2,E_PG_MAIN, + (gslc_tsRect){108,30,51,29},(char*)"",0,E_BUILTIN5X8,&CbBtnCommon); + + // Create progress bar E_ELEM_RAMPGAUGE1 + pElemRef = gslc_ElemXRampCreate(&m_gui,E_ELEM_RAMPGAUGE1,E_PG_MAIN,&m_sXRampGauge1, + (gslc_tsRect){9,156,100,80},0,100, + 0,GSLC_COL_YELLOW,false); + m_pElemRamp1 = pElemRef; + + // Create E_ELEM_TEXTINPUT1 text input field + static char m_sInputText1[11] = ""; + pElemRef = gslc_ElemCreateTxt(&m_gui,E_ELEM_TEXTINPUT1,E_PG_MAIN,(gslc_tsRect){12,70,86,72}, + (char*)m_sInputText1,11,E_BUILTIN5X8); + gslc_ElemSetTxtMargin(&m_gui,pElemRef,5); + gslc_ElemSetFrameEn(&m_gui,pElemRef,true); + gslc_ElemSetClickEn(&m_gui, pElemRef, true); + gslc_ElemSetTouchFunc(&m_gui, pElemRef, &CbBtnCommon); + m_pElemInTxt1 = pElemRef; + + // Create E_ELEM_NUMINPUT1 numeric input field + static char m_sInputNumber1[6] = ""; + pElemRef = gslc_ElemCreateTxt(&m_gui,E_ELEM_NUMINPUT1,E_PG_MAIN,(gslc_tsRect){116,70,61,76}, + (char*)m_sInputNumber1,6,E_BUILTIN5X8); + gslc_ElemSetTxtMargin(&m_gui,pElemRef,5); + gslc_ElemSetFrameEn(&m_gui,pElemRef,true); + gslc_ElemSetClickEn(&m_gui, pElemRef, true); + gslc_ElemSetTouchFunc(&m_gui, pElemRef, &CbBtnCommon); + m_pElemVal1 = pElemRef; + + // ----------------------------------- + // PAGE: E_POP_KEYPAD_NUM + + static gslc_tsXKeyPadCfg_Num sCfg; + sCfg = gslc_ElemXKeyPadCfgInit_Num(); + gslc_ElemXKeyPadCfgSetFloatEn_Num(&sCfg, true); + gslc_ElemXKeyPadCfgSetSignEn_Num(&sCfg, true); + m_pElemKeyPadNum = gslc_ElemXKeyPadCreate_Num(&m_gui, E_ELEM_KEYPAD_NUM, E_POP_KEYPAD_NUM, + &m_sKeyPadNum, 65, 80, E_BUILTIN5X8, &sCfg); + gslc_ElemXKeyPadValSetCb(&m_gui, m_pElemKeyPadNum, &CbKeypad); + + // ----------------------------------- + // PAGE: E_POP_KEYPAD_ALPHA + + static gslc_tsXKeyPadCfg_Alpha sCfgTx; + sCfgTx = gslc_ElemXKeyPadCfgInit_Alpha(); + m_pElemKeyPadAlpha = gslc_ElemXKeyPadCreate_Alpha(&m_gui, E_ELEM_KEYPAD_ALPHA, E_POP_KEYPAD_ALPHA, + &m_sKeyPadAlpha, 65, 80, E_BUILTIN5X8, &sCfgTx); + gslc_ElemXKeyPadValSetCb(&m_gui, m_pElemKeyPadAlpha, &CbKeypad); +// + +// + gslc_GuiRotate(&m_gui, 1); +// + +} + +#endif // end _GUISLICE_GEN_H diff --git a/platformio.ini b/platformio.ini index de1cbd1..9d9140c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -1,11 +1,13 @@ [env:Esp32dev] platform = espressif32 +; build_src_filter = + board = esp32dev framework = arduino extra_scripts = pre:scripts/version.py monitor_speed = 115200 monitor_echo = yes monitor_filters = esp32_exception_decoder +lib_ldf_mode = deep build_flags = -DUSER_SETUP_LOADED=1 -DILI9341_2_DRIVER=1 @@ -29,9 +31,28 @@ build_flags = -DSPI_TOUCH_FREQUENCY=2500000 ; -DLDR_DEBUG ; -DTOUCH_DEBUG + ; --- GUIslice demo --- + -DUSER_CONFIG_LOADED=1 + -DDRV_DISP_TFT_ESPI + -DDRV_TOUCH_HANDLER + -DDEBUG_ERR=1 + -DGSLC_USE_PROGMEM=0 + -DGSLC_USE_FLOAT=0 + -DGSLC_LOCAL_STR=0 + -DGSLC_LOCAL_STR_LEN=30 + -DGSLC_TOUCH_MAX_EVT=1 + -DGSLC_CLIP_EN=1 + -DGSLC_BMP_TRANS_EN=1 + -DGSLC_BMP_TRANS_RGB=0xFF,0x00,0xFF + -DGSLC_FEATURE_COMPOUND=1 + -DGSLC_FEATURE_XTEXTBOX_EMBED=0 + -DGSLC_FEATURE_INPUT=0 + -DGSLC_SD_EN=0 + -DGSLC_DEV_TOUCH=\"\" + -DGSLC_ROTATE=1 lib_deps = - ; moononournation/GFX Library for Arduino@1.4.7 bodmer/TFT_eSPI - https://github.com/tanmaywankar/Grobot_Animations.git - bitbank2/JPEGDEC - https://github.com/hexeguitar/CYD28_Touchscreen.git \ No newline at end of file + ; https://github.com/tanmaywankar/Grobot_Animations.git + ; bitbank2/JPEGDEC + https://github.com/hexeguitar/CYD28_Touchscreen.git + https://github.com/ImpulseAdventure/GUIslice.git \ No newline at end of file diff --git a/src/MenuCallbacks.cpp b/src/MenuCallbacks.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/UIManager.cpp b/src/UIManager.cpp index d58d286..26728e3 100644 --- a/src/UIManager.cpp +++ b/src/UIManager.cpp @@ -1,90 +1,52 @@ #include #include "UIManager.h" -#include "MenuSchema.h" #include "TouchHandler.h" #include "Config.h" -#include #include "FaceRenderer.h" +#include "MenuApp.h" +#include extern TFT_eSPI tft; -static bool _dirty = false; -static unsigned long _lastMenuRender = 0; - static UIMode _mode = MODE_FACE; -static const MenuScreen* _stack[8]; -static uint8_t _depth = 0; - -static String _lastRowText[8]; // matches MAX_RT_ITEMS in MenuSchema.cpp - -static int hitTest(uint16_t x, uint16_t y); -static void renderMenu(); -static void renderRows(); static void enterMenu() { _mode = MODE_MENU; - _stack[0] = getActiveRoot(); - _depth = 1; pauseFace(); tft.fillScreen(TFT_BLACK); - _dirty = true; + gslc_SetPageCur(&m_gui, MENU_PG_ROOT); + gslc_PageRedrawSet(&m_gui, true); // force full redraw on entry } + static void exitMenu() { _mode = MODE_FACE; - _depth = 0; tft.fillScreen(config.bgColour); resetFaceState(); resumeFace(); } -void initUI() { _mode = MODE_FACE; _depth = 0; } +void initUI() { + _mode = MODE_FACE; +} void serviceUI() { TouchEvent ev; - if (pollTouchEvent(ev)) { - #ifdef TOUCH_DEBUG - Serial.printf("touch: %s at (%u, %u)\n", - ev.kind == TOUCH_TAP ? "TAP" : "LONG_PRESS", ev.x, ev.y); - #endif + bool gotEvent = pollTouchEvent(ev); // also refreshes peekLastTouch cache - if (ev.kind == TOUCH_LONG_PRESS && _mode == MODE_FACE) { + // Long-press toggles mode in either direction. + // TAP events fall through — GUIslice handles taps via peekLastTouch. + if (gotEvent && ev.kind == TOUCH_LONG_PRESS) { + if (_mode == MODE_FACE) { enterMenu(); Serial.println("OK: entered MENU"); - } - else if (ev.kind == TOUCH_LONG_PRESS && _mode == MODE_MENU) { + } else { exitMenu(); Serial.println("OK: returned to FACE"); } - else if (ev.kind == TOUCH_TAP && _mode == MODE_MENU) { - int idx = hitTest(ev.x, ev.y); - if (idx >= 0) { - const MenuScreen* s = _stack[_depth - 1]; - const MenuItem& it = s->items[idx]; - const char* k = it.kind == ACT_PUSH ? "PUSH" - : it.kind == ACT_INVOKE ? "INVOKE" - : it.kind == ACT_BACK ? "BACK" : "NONE"; - Serial.printf("MENU: tap row %d (%s, %s)\n", idx, it.label, k); - menuSelect((uint8_t)idx); - } else { - Serial.printf("MENU: tap miss at (%u, %u)\n", ev.x, ev.y); - } -} } - auto screenHasFormatters = []() -> bool { - if (_depth == 0) return false; - const MenuScreen* s = _stack[_depth - 1]; - for (uint8_t i = 0; i < s->count; i++) if (s->items[i].formatCmd) return true; - return false; - }; - if (_mode == MODE_MENU && _dirty) { - renderMenu(); - _lastMenuRender = millis(); - _dirty = false; - } - else if (_mode == MODE_MENU && screenHasFormatters() && (millis() - _lastMenuRender) > 250) { - renderRows(); - _lastMenuRender = millis(); + if (_mode == MODE_MENU) { + gslc_Update(&m_gui); } } @@ -96,41 +58,12 @@ void setUIMode(UIMode m) { } void menuBack() { - if (_mode != MODE_MENU || _depth == 0) return; - _depth--; - if (_depth == 0) exitMenu(); - else _dirty = true; + if (_mode == MODE_MENU) exitMenu(); } bool menuSelect(uint8_t idx) { - if (_mode != MODE_MENU || _depth == 0) return false; - const MenuScreen* s = _stack[_depth - 1]; - if (idx >= s->count) return false; - const MenuItem& it = s->items[idx]; - - switch (it.kind) { - case ACT_PUSH: - if (_depth >= 8) return false; - _stack[_depth++] = (const MenuScreen*)it.payload; - _dirty = true; - return true; - case ACT_BACK: - menuBack(); - return true; - case ACT_INVOKE: { - String line = (const char*)it.payload; - int colon = line.indexOf(':'); - String key = colon >= 0 ? line.substring(0, colon) : line; - String val = colon >= 0 ? line.substring(colon + 1) : String(); - const Command* c = findCommand(key); - if (!c) { Serial.printf("ERR: invoke '%s'\n", line.c_str()); return false; } - if (colon >= 0 && c->set) c->set(val); - else if (c->get) c->get(); - return true; - } - case ACT_NONE: - return true; // acknowledged, no action - } + (void)idx; + Serial.println("ERR: menu_select deprecated — use touch UI"); return false; } @@ -139,70 +72,6 @@ void printMode() { } void printMenuState() { - if (_mode != MODE_MENU || _depth == 0) { - Serial.println("menu: (FACE mode)"); - return; - } - const MenuScreen* s = _stack[_depth - 1]; - Serial.printf("menu: %s (depth %u)\n", s->title, _depth); - for (uint8_t i = 0; i < s->count; i++) { - const MenuItem& it = s->items[i]; - const char* k = it.kind == ACT_PUSH ? "PUSH" - : it.kind == ACT_INVOKE ? "INVOKE" - : it.kind == ACT_BACK ? "BACK" : "NONE"; - Serial.printf(" [%u] %-16s %s\n", i, it.label, k); - } -} - -static int hitTest(uint16_t x, uint16_t y) { - if (_mode != MODE_MENU || _depth == 0) return -1; - const MenuScreen* s = _stack[_depth - 1]; - const int top = 48, row_h = 36; - if (y < top) return -1; - int idx = (y - top) / row_h; - return (idx < 0 || idx >= s->count) ? -1 : idx; -} - -static void renderRows() { - if (_mode != MODE_MENU || _depth == 0) return; - const MenuScreen* s = _stack[_depth - 1]; - tft.setTextSize(1); - tft.setFreeFont(&FreeSans12pt7b); - tft.setTextColor(TFT_WHITE, TFT_BLACK); - tft.setTextDatum(TL_DATUM); - char buf[64]; - int y = 48; - for (uint8_t i = 0; i < s->count; i++) { - const MenuItem& it = s->items[i]; - if (it.formatCmd) { - const Command* c = findCommand(it.formatCmd); - if (c && c->format) { - snprintf(buf, sizeof(buf), "%u %s: %s", i, it.label, c->format().c_str()); - } else { - snprintf(buf, sizeof(buf), "%u %s", i, it.label); - } - } else { - snprintf(buf, sizeof(buf), "%u %s", i, it.label); - } - if (_lastRowText[i] != buf) { - tft.fillRect(0, y - 4, 320, 32, TFT_BLACK); - tft.drawString(buf, 12, y); - _lastRowText[i] = buf; - } - y += 36; - } -} - -static void renderMenu() { - if (_mode != MODE_MENU || _depth == 0) return; - const MenuScreen* s = _stack[_depth - 1]; - tft.fillScreen(TFT_BLACK); - for (int i = 0; i < 8; i++) _lastRowText[i] = ""; - tft.setTextSize(1); - tft.setFreeFont(&FreeSansBold12pt7b); - tft.setTextColor(TFT_WHITE, TFT_BLACK); - tft.setTextDatum(TL_DATUM); - tft.drawString(s->title, 12, 8); - tft.drawFastHLine(0, 36, 320, TFT_DARKGREY); - renderRows(); + Serial.printf("menu: %s (GUIslice-driven)\n", + _mode == MODE_MENU ? "MENU" : "FACE"); } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 199b076..5a3dd4d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,16 +7,33 @@ #include "LdrSensor.h" #include "Config.h" #include "UIManager.h" +#include "MenuApp.h" +#include "version.h" + +static CydTouchHandler m_touch; + +static int16_t DebugOut(char ch) { + if (ch == '\n') Serial.println(""); + else Serial.write(ch); + return 0; +} void setup() { Serial.begin(115200); Serial.setTimeout(50); printVersion(); printMemoryReport(); - initConfig(); //must come before initDisplay so persisted config applies - initDisplay(); - initTouch(); - initUI(); + + initConfig(); // NVS — must precede initDisplay (persisted brightness etc.) + initDisplay(); // TFT_eSPI + splash + initTouch(); // CYD28_TouchR — sole hardware owner + + // GUIslice — re-inits TFT_eSPI internally; brief flicker is expected + gslc_InitDebug(&DebugOut); + gslc_InitTouchHandler(&m_touch); + InitGUIslice_gen(); + + initUI(); // _mode = FACE setupLed(); Serial.println("RSC ready"); } @@ -25,7 +42,7 @@ void loop() { serviceConfig(); serviceNvs(); if (getUIMode() == MODE_FACE) serviceFaceRenderer(); - serviceUI(); + serviceUI(); // mode-orchestrates GUIslice + long-press serviceDebugOverlay(); serviceLdr(); } \ No newline at end of file From ad5bd6a7d2844213c4d2ce6d3d3ec095944a4cf8 Mon Sep 17 00:00:00 2001 From: mbz4 <30321314+mbz4@users.noreply.github.com> Date: Tue, 12 May 2026 16:45:14 +0300 Subject: [PATCH 04/25] add back grobot faces; add host timestamps to serial console --- platformio.ini | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index 9d9140c..a3c67d0 100644 --- a/platformio.ini +++ b/platformio.ini @@ -6,7 +6,9 @@ framework = arduino extra_scripts = pre:scripts/version.py monitor_speed = 115200 monitor_echo = yes -monitor_filters = esp32_exception_decoder +monitor_filters = + -esp32_exception_decoder + -time lib_ldf_mode = deep build_flags = -DUSER_SETUP_LOADED=1 @@ -52,7 +54,7 @@ build_flags = -DGSLC_ROTATE=1 lib_deps = bodmer/TFT_eSPI - ; https://github.com/tanmaywankar/Grobot_Animations.git + https://github.com/tanmaywankar/Grobot_Animations.git ; bitbank2/JPEGDEC https://github.com/hexeguitar/CYD28_Touchscreen.git https://github.com/ImpulseAdventure/GUIslice.git \ No newline at end of file From 9a40450b60aca593a5a299fa6f61495536078521 Mon Sep 17 00:00:00 2001 From: mbz4 <30321314+mbz4@users.noreply.github.com> Date: Tue, 12 May 2026 16:45:39 +0300 Subject: [PATCH 05/25] add timeout --- include/Config.h | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/include/Config.h b/include/Config.h index 9ab365d..93dd454 100644 --- a/include/Config.h +++ b/include/Config.h @@ -2,18 +2,19 @@ #include struct Config { - bool touchDebug = false; - bool moodAutoCycle = true; - bool showTouchDots = true; - uint16_t eyeColour = 0xFFFF; // RGB565 (TFT_WHITE) - uint16_t bgColour = 0x0000; // RGB565 (TFT_BLACK) - char mood[16] = "NEUTRAL"; // null-terminated, max 15 chars - uint8_t brightness = 100; // 0-100 backlight % (converts to PWM 0=off, 255=full) - bool hudOn = false; - bool autoBright = false; - uint8_t brightLight = 50; // target % in bright rooms - uint8_t brightDark = 1; // target % in dark rooms - bool idleAnim = false; + bool touchDebug = false; + bool moodAutoCycle = true; + bool showTouchDots = false; + uint16_t eyeColour = 0xFFFF; // RGB565 (TFT_WHITE) + uint16_t bgColour = 0x0000; // RGB565 (TFT_BLACK) + char mood[16] = "NEUTRAL"; // null-terminated, max 15 chars + uint8_t brightness = 100; // 0-100 backlight % (converts to PWM 0=off, 255=full) + bool hudOn = false; + bool autoBright = false; + uint8_t brightLight = 50; // target % in bright rooms + uint8_t brightDark = 1; // target % in dark rooms + bool idleAnim = false; + uint16_t menuTimeoutSec = 10; // auto-return to face; 0 = disabled String (*format)(); // optional: short live-value string for menus, e.g. "75%" }; From 2136541c60e15c9c9a2bc8bdafb6b33b189e81f2 Mon Sep 17 00:00:00 2001 From: mbz4 <30321314+mbz4@users.noreply.github.com> Date: Tue, 12 May 2026 16:45:52 +0300 Subject: [PATCH 06/25] prune vestigial --- include/MenuSchema.h | 28 --------- src/MenuSchema.cpp | 137 ------------------------------------------- 2 files changed, 165 deletions(-) delete mode 100644 include/MenuSchema.h delete mode 100644 src/MenuSchema.cpp diff --git a/include/MenuSchema.h b/include/MenuSchema.h deleted file mode 100644 index e6a0d41..0000000 --- a/include/MenuSchema.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -#include - -enum ActionKind : uint8_t { ACT_PUSH, ACT_INVOKE, ACT_BACK, ACT_NONE }; - -struct MenuScreen; -struct MenuItem { - const char* label; - ActionKind kind; - const void* payload; // MenuScreen* or const char* - const char* formatCmd; // optional: command name whose format() supplies the live suffix -}; -struct MenuScreen { - const char* title; - const MenuItem* items; - uint8_t count; -}; - -extern const MenuScreen ROOT_MENU; -extern const MenuScreen MOOD_MENU; -extern const MenuScreen BRIGHTNESS_MENU; - -const MenuScreen* getActiveRoot(); -void resetRuntimeSchema(); -bool runtimeBegin(); -bool runtimeAddScreen(const char* title); -bool runtimeAddItem(ActionKind kind, const char* label, const char* payload, const char* formatCmd = nullptr); -bool runtimeEnd(); \ No newline at end of file diff --git a/src/MenuSchema.cpp b/src/MenuSchema.cpp deleted file mode 100644 index e34ea93..0000000 --- a/src/MenuSchema.cpp +++ /dev/null @@ -1,137 +0,0 @@ -#include "MenuSchema.h" -#include -#include - -#define MAX_RT_SCREENS 8 -#define MAX_RT_ITEMS 8 -#define RT_POOL_SIZE 1024 - -static MenuScreen _rtScreens[MAX_RT_SCREENS]; -static MenuItem _rtItems[MAX_RT_SCREENS * MAX_RT_ITEMS]; -static char _rtPool[RT_POOL_SIZE]; -static int _rtScreenCount = 0; -static size_t _rtPoolUsed = 0; -static int _rtCurScreen = -1; -static bool _rtLoading = false; -static bool _rtActive = false; - -static const char* poolString(const char* s) { - size_t n = strlen(s) + 1; - if (_rtPoolUsed + n > RT_POOL_SIZE) return nullptr; - char* d = &_rtPool[_rtPoolUsed]; - memcpy(d, s, n); - _rtPoolUsed += n; - return d; -} - -static MenuItem* rtItemsFor(int screenIdx) { - return &_rtItems[screenIdx * MAX_RT_ITEMS]; -} - -extern const MenuScreen ROOT_MENU; -extern const MenuScreen MOOD_MENU; -extern const MenuScreen BRIGHTNESS_MENU; -extern const MenuScreen STATUS_MENU; - -static const MenuItem BRIGHTNESS_ITEMS[] = { - {"25%", ACT_INVOKE, "bright:25"}, - {"50%", ACT_INVOKE, "bright:50"}, - {"75%", ACT_INVOKE, "bright:75"}, - {"100%", ACT_INVOKE, "bright:100"}, - {"Back", ACT_BACK, nullptr}, -}; -const MenuScreen BRIGHTNESS_MENU = {"Brightness", BRIGHTNESS_ITEMS, 5}; - -static const MenuItem MOOD_ITEMS[] = { - {"Neutral", ACT_INVOKE, "mood:NEUTRAL"}, - {"Happy", ACT_INVOKE, "mood:HAPPY"}, - {"Sad", ACT_INVOKE, "mood:SAD"}, - {"Angry", ACT_INVOKE, "mood:ANGRY"}, - {"Back", ACT_BACK, nullptr}, -}; -const MenuScreen MOOD_MENU = {"Mood", MOOD_ITEMS, 5}; - -static const MenuItem STATUS_ITEMS[] = { - {"Bright", ACT_NONE, nullptr, "bright"}, - {"Mood", ACT_NONE, nullptr, "mood"}, - {"Up", ACT_NONE, nullptr, "uptime"}, - {"Mem", ACT_NONE, nullptr, "mem"}, - {"Back", ACT_BACK, nullptr}, -}; -const MenuScreen STATUS_MENU = {"Status", STATUS_ITEMS, 5}; - -static const MenuItem ROOT_ITEMS[] = { - {"Brightness", ACT_PUSH, &BRIGHTNESS_MENU, "bright"}, - {"Mood", ACT_PUSH, &MOOD_MENU, "mood"}, - {"Status", ACT_PUSH, &STATUS_MENU, nullptr}, - {"Blink", ACT_INVOKE, "blink"}, - {"Resume", ACT_BACK, nullptr}, -}; -const MenuScreen ROOT_MENU = {"Menu", ROOT_ITEMS, 5}; - - -void resetRuntimeSchema() { - _rtScreenCount = 0; _rtPoolUsed = 0; - _rtCurScreen = -1; _rtLoading = false; _rtActive = false; -} - -bool runtimeBegin() { resetRuntimeSchema(); _rtLoading = true; return true; } - -bool runtimeAddScreen(const char* title) { - if (!_rtLoading || _rtScreenCount >= MAX_RT_SCREENS) return false; - const char* t = poolString(title); - if (!t) return false; - _rtCurScreen = _rtScreenCount++; - _rtScreens[_rtCurScreen] = {t, rtItemsFor(_rtCurScreen), 0}; - return true; -} - -bool runtimeAddItem(ActionKind kind, const char* label, const char* payload, const char* formatCmd) { - if (!_rtLoading || _rtCurScreen < 0) return false; - MenuScreen& s = _rtScreens[_rtCurScreen]; - if (s.count >= MAX_RT_ITEMS) return false; - const char* lbl = poolString(label); - if (!lbl) return false; - MenuItem& it = rtItemsFor(_rtCurScreen)[s.count++]; - it.label = lbl; - it.kind = kind; - if (kind == ACT_PUSH) { - it.payload = (const void*)(uintptr_t)atoi(payload); // resolved in runtimeEnd - } else if (kind == ACT_INVOKE) { - const char* p = poolString(payload); - if (!p) return false; - it.payload = p; - } else { - it.payload = nullptr; - } - if (formatCmd && *formatCmd) { - const char* f = poolString(formatCmd); - if (!f) return false; - it.formatCmd = f; - } else { - it.formatCmd = nullptr; - } - return true; -} - -bool runtimeEnd() { - if (!_rtLoading) return false; - // Fix up PUSH payloads from indices to pointers - for (int s = 0; s < _rtScreenCount; s++) { - MenuItem* items = rtItemsFor(s); - for (int i = 0; i < _rtScreens[s].count; i++) { - if (items[i].kind == ACT_PUSH) { - int idx = (int)(uintptr_t)items[i].payload; - if (idx < 0 || idx >= _rtScreenCount) return false; - items[i].payload = &_rtScreens[idx]; - } - } - } - _rtLoading = false; - _rtActive = true; - return true; -} - -const MenuScreen* getActiveRoot() { - return _rtActive ? &_rtScreens[0] : &ROOT_MENU; -} \ No newline at end of file From 01d7691b74e1d1c8abcdf71f3ad4e5c2108bc788 Mon Sep 17 00:00:00 2001 From: mbz4 <30321314+mbz4@users.noreply.github.com> Date: Tue, 12 May 2026 16:46:19 +0300 Subject: [PATCH 07/25] patch in new ui --- include/test_GSLC.h | 389 +++++++++++++++++++++++++++--------------- src/MenuCallbacks.cpp | 167 ++++++++++++++++++ 2 files changed, 417 insertions(+), 139 deletions(-) diff --git a/include/test_GSLC.h b/include/test_GSLC.h index 2196bc3..d6e8bb3 100644 --- a/include/test_GSLC.h +++ b/include/test_GSLC.h @@ -11,7 +11,7 @@ #ifndef _GUISLICE_GEN_H #define _GUISLICE_GEN_H -// keep root page first + // ------------------------------------------------ // Headers to include // ------------------------------------------------ @@ -21,20 +21,9 @@ // Include any extended elements // // Include extended elements -#include "elem/XCheckbox.h" -#include "elem/XKeyPad_Alpha.h" -#include "elem/XKeyPad_Num.h" -#include "elem/XProgress.h" -#include "elem/XRamp.h" -#include "elem/XRingGauge.h" #include "elem/XSlider.h" -#include "elem/XSpinner.h" +#include "elem/XToggleImgbtn.h" #include "elem/XTogglebtn.h" - -// Ensure optional features are enabled in the configuration -#if !(GSLC_FEATURE_COMPOUND) - #error "Config: GSLC_FEATURE_COMPOUND required for this program but not enabled. Please see: https://github.com/ImpulseAdventure/GUIslice/wiki/Configuring-GUIslice" -#endif // // ------------------------------------------------ @@ -52,20 +41,33 @@ // Defines for resources // ------------------------------------------------ // +extern "C" const unsigned short auto_bright_40x40px[] PROGMEM; +extern "C" const unsigned short back_40x40px[] PROGMEM; +extern "C" const unsigned short burger_icon_40x40px[] PROGMEM; +extern "C" const unsigned short mic_on_icon_40x40px[] PROGMEM; +extern "C" const unsigned short power_icon_40x40px[] PROGMEM; +extern "C" const unsigned short rsc_130x130[] PROGMEM; +extern "C" const unsigned short volume_loud_icon2_40x40px[] PROGMEM; // // ------------------------------------------------ // Enumerations for pages, elements, fonts, images // ------------------------------------------------ // -enum {E_PG_MAIN,E_POP_KEYPAD_NUM,E_POP_KEYPAD_ALPHA}; -enum {E_ELEM_BOX1,E_ELEM_BTN1,E_ELEM_BTN2,E_ELEM_CHECK1 - ,E_ELEM_NUMINPUT1,E_ELEM_PROGRESS1,E_ELEM_RADIO1 - ,E_ELEM_RAMPGAUGE1,E_ELEM_RINGGAUGE1,E_ELEM_SLIDER1 - ,E_ELEM_SPINNER1,E_ELEM_TEXT1,E_ELEM_TEXTINPUT1,E_ELEM_TOGGLE1 - ,E_ELEM_KEYPAD_NUM,E_ELEM_KEYPAD_ALPHA}; +enum {E_PG_MAIN,E_PG_BURGER_MENU,E_PG_PWR,E_PG_POPUP_CONFIRM}; +enum {E_DRAW_LINE1,E_DRAW_LINE2,E_DRAW_LINE3,E_ELEM_BOX1 + ,E_ELEM_BOX_CONFIRM,E_ELEM_BTN10,E_ELEM_BTN11,E_ELEM_BTN5 + ,E_ELEM_BTN6,E_ELEM_BTN_CANCEL,E_ELEM_BTN_MENU_CLOSE + ,E_ELEM_BTN_YES,E_ELEM_IMAGEBTN5,E_ELEM_IMAGEBTN_BACK + ,E_ELEM_IMAGEBTN_BRIGHTNESS,E_ELEM_IMAGEBTN_BURGER + ,E_ELEM_IMAGEBTN_CONFIRM_BACK,E_ELEM_IMAGEBTN_MIC + ,E_ELEM_IMAGEBTN_PWR,E_ELEM_IMAGEBTN_PWR_CLOSE + ,E_ELEM_IMAGEBTN_VOLUME,E_ELEM_MENU_BOX,E_ELEM_PWR_BOX + ,E_ELEM_SLIDER2,E_ELEM_SLIDER3,E_ELEM_TEXT10,E_ELEM_TEXT9 + ,E_ELEM_TEXT_CONFIRM,E_ELEM_TEXT_DEBUG_TOGGLE,E_ELEM_TEXT_STATS + ,E_ELEM_TEXT_THEME,E_ELEM_TOGGLE_DEBUG,E_ELEM_TOGGLE_THEME}; // Must use separate enum for fonts with MAX_FONT at end to use gslc_FontSet. -enum {E_BUILTIN5X8,MAX_FONT}; +enum {E_BUILTIN10X16,E_BUILTIN15X24,MAX_FONT}; // // ------------------------------------------------ @@ -76,10 +78,19 @@ enum {E_BUILTIN5X8,MAX_FONT}; // Define the maximum number of elements and pages // ------------------------------------------------ // -#define MAX_PAGE 3 +#define MAX_PAGE 4 -#define MAX_ELEM_PG_MAIN 14 // # Elems total on page +#define MAX_ELEM_PG_MAIN 10 // # Elems total on page #define MAX_ELEM_PG_MAIN_RAM MAX_ELEM_PG_MAIN // # Elems in RAM + +#define MAX_ELEM_PG_BURGER_MENU 9 // # Elems total on page +#define MAX_ELEM_PG_BURGER_MENU_RAM MAX_ELEM_PG_BURGER_MENU // # Elems in RAM + +#define MAX_ELEM_PG_PWR 9 // # Elems total on page +#define MAX_ELEM_PG_PWR_RAM MAX_ELEM_PG_PWR // # Elems in RAM + +#define MAX_ELEM_PG_POPUP_CONFIRM 5 // # Elems total on page +#define MAX_ELEM_PG_POPUP_CONFIRM_RAM MAX_ELEM_PG_POPUP_CONFIRM // # Elems in RAM // // ------------------------------------------------ @@ -93,20 +104,18 @@ gslc_tsPage m_asPage[MAX_PAGE]; // gslc_tsElem m_asPage1Elem[MAX_ELEM_PG_MAIN_RAM]; gslc_tsElemRef m_asPage1ElemRef[MAX_ELEM_PG_MAIN]; -gslc_tsElem m_asKeypadNumElem[1]; -gslc_tsElemRef m_asKeypadNumElemRef[1]; -gslc_tsElem m_asKeypadAlphaElem[1]; -gslc_tsElemRef m_asKeypadAlphaElemRef[1]; -gslc_tsXKeyPad m_sKeyPadNum; -gslc_tsXKeyPad m_sKeyPadAlpha; -gslc_tsXSpinner m_sXSpinner1; -gslc_tsXRingGauge m_sXRingGauge1; -gslc_tsXProgress m_sXBarGauge1; -gslc_tsXSlider m_sXSlider1; -gslc_tsXTogglebtn m_asXToggle1; -gslc_tsXCheckbox m_asXCheck1; -gslc_tsXCheckbox m_asXRadio1; -gslc_tsXRamp m_sXRampGauge1; +gslc_tsElem m_asPopup5Elem[MAX_ELEM_PG_BURGER_MENU_RAM]; +gslc_tsElemRef m_asPopup5ElemRef[MAX_ELEM_PG_BURGER_MENU]; +gslc_tsElem m_asPopup6Elem[MAX_ELEM_PG_PWR_RAM]; +gslc_tsElemRef m_asPopup6ElemRef[MAX_ELEM_PG_PWR]; +gslc_tsElem m_asPopup7Elem[MAX_ELEM_PG_POPUP_CONFIRM_RAM]; +gslc_tsElemRef m_asPopup7ElemRef[MAX_ELEM_PG_POPUP_CONFIRM]; +gslc_tsXSlider m_sXSlider2; +gslc_tsXToggleImgbtn m_sToggleImg32; +gslc_tsXToggleImgbtn m_sToggleImg29; +gslc_tsXSlider m_sXSlider3; +gslc_tsXTogglebtn m_asXToggle10; +gslc_tsXTogglebtn m_asXToggle7; #define MAX_STR 100 @@ -118,18 +127,14 @@ gslc_tsXRamp m_sXRampGauge1; // Element References for direct access // -extern gslc_tsElemRef* m_pElemCBCheckBox; -extern gslc_tsElemRef* m_pElemInTxt1; -extern gslc_tsElemRef* m_pElemProgress1; -extern gslc_tsElemRef* m_pElemRBRadioButton; -extern gslc_tsElemRef* m_pElemRamp1; -extern gslc_tsElemRef* m_pElemSlider1; -extern gslc_tsElemRef* m_pElemSpinner1; -extern gslc_tsElemRef* m_pElemToggle1; -extern gslc_tsElemRef* m_pElemVal1; -extern gslc_tsElemRef* m_pElemXRingGauge1; -extern gslc_tsElemRef* m_pElemKeyPadNum; -extern gslc_tsElemRef* m_pElemKeyPadAlpha; +extern gslc_tsElemRef* m_pElemOutTxt11; +extern gslc_tsElemRef* m_pElemOutTxt8; +extern gslc_tsElemRef* m_pElemSlider2; +extern gslc_tsElemRef* m_pElemSlider2_3; +extern gslc_tsElemRef* m_pElemToggle2_7; +extern gslc_tsElemRef* m_pElemToggle2_7_10; +extern gslc_tsElemRef* m_pElemToggleImg29; +extern gslc_tsElemRef* m_pElemToggleImg32; // // Define debug message function @@ -160,13 +165,15 @@ void InitGUIslice_gen() // Load Fonts // ------------------------------------------------ // - if (!gslc_FontSet(&m_gui,E_BUILTIN5X8,GSLC_FONTREF_PTR,NULL,1)) { return; } + if (!gslc_FontSet(&m_gui,E_BUILTIN10X16,GSLC_FONTREF_PTR,NULL,2)) { return; } + if (!gslc_FontSet(&m_gui,E_BUILTIN15X24,GSLC_FONTREF_PTR,NULL,3)) { return; } // // gslc_PageAdd(&m_gui,E_PG_MAIN,m_asPage1Elem,MAX_ELEM_PG_MAIN_RAM,m_asPage1ElemRef,MAX_ELEM_PG_MAIN); - gslc_PageAdd(&m_gui,E_POP_KEYPAD_NUM,m_asKeypadNumElem,1,m_asKeypadNumElemRef,1); // KeyPad - gslc_PageAdd(&m_gui,E_POP_KEYPAD_ALPHA,m_asKeypadAlphaElem,1,m_asKeypadAlphaElemRef,1); // KeyPad + gslc_PageAdd(&m_gui,E_PG_BURGER_MENU,m_asPopup5Elem,MAX_ELEM_PG_BURGER_MENU_RAM,m_asPopup5ElemRef,MAX_ELEM_PG_BURGER_MENU); + gslc_PageAdd(&m_gui,E_PG_PWR,m_asPopup6Elem,MAX_ELEM_PG_PWR_RAM,m_asPopup6ElemRef,MAX_ELEM_PG_PWR); + gslc_PageAdd(&m_gui,E_PG_POPUP_CONFIRM,m_asPopup7Elem,MAX_ELEM_PG_POPUP_CONFIRM_RAM,m_asPopup7ElemRef,MAX_ELEM_PG_POPUP_CONFIRM); // NOTE: The current page defaults to the first page added. Here we explicitly // ensure that the main page is the correct page no matter the add order. @@ -178,111 +185,215 @@ void InitGUIslice_gen() // ----------------------------------- // PAGE: E_PG_MAIN + + // Create E_ELEM_MENU_BOX box + pElemRef = gslc_ElemCreateBox(&m_gui,E_ELEM_MENU_BOX,E_PG_MAIN,(gslc_tsRect){0,0,320,240}); + gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_BLACK,GSLC_COL_BLACK,GSLC_COL_BLACK); + + // Create E_ELEM_IMAGEBTN_BACK button with image label + pElemRef = gslc_ElemCreateBtnImg(&m_gui,E_ELEM_IMAGEBTN_BACK,E_PG_MAIN,(gslc_tsRect){270,100,40,40}, + gslc_GetImageFromProg((const unsigned char*)back_40x40px,GSLC_IMGREF_FMT_RAW1), + gslc_GetImageFromProg((const unsigned char*)back_40x40px,GSLC_IMGREF_FMT_RAW1), + &CbBtnCommon); + + // Create slider E_ELEM_SLIDER2 + pElemRef = gslc_ElemXSliderCreate(&m_gui,E_ELEM_SLIDER2,E_PG_MAIN,&m_sXSlider2, + (gslc_tsRect){210,10,40,180},0,100,0,10,true); + gslc_ElemXSliderSetStyle(&m_gui,pElemRef,true,GSLC_COL_WHITE,5,10,GSLC_COL_WHITE); + gslc_ElemXSliderSetPosFunc(&m_gui,pElemRef,&CbSlidePos); + gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_WHITE,GSLC_COL_BLACK,GSLC_COL_BLACK); + m_pElemSlider2 = pElemRef; + + // Create E_ELEM_IMAGEBTN_VOLUME button with image label + pElemRef = gslc_ElemXToggleImgbtnCreate(&m_gui,E_ELEM_IMAGEBTN_VOLUME,E_PG_MAIN,&m_sToggleImg32,(gslc_tsRect){210,190,40,40}, + gslc_GetImageFromProg((const unsigned char*)volume_loud_icon2_40x40px,GSLC_IMGREF_FMT_RAW1), + gslc_GetImageFromProg((const unsigned char*)volume_loud_icon2_40x40px,GSLC_IMGREF_FMT_RAW1), + false,&CbBtnCommon); + m_pElemToggleImg32 = pElemRef; + + // Create E_ELEM_IMAGEBTN_MIC button with image label + pElemRef = gslc_ElemXToggleImgbtnCreate(&m_gui,E_ELEM_IMAGEBTN_MIC,E_PG_MAIN,&m_sToggleImg29,(gslc_tsRect){270,190,40,40}, + gslc_GetImageFromProg((const unsigned char*)mic_on_icon_40x40px,GSLC_IMGREF_FMT_RAW1), + gslc_GetImageFromProg((const unsigned char*)mic_on_icon_40x40px,GSLC_IMGREF_FMT_RAW1), + false,&CbBtnCommon); + m_pElemToggleImg29 = pElemRef; + + // Create slider E_ELEM_SLIDER3 + pElemRef = gslc_ElemXSliderCreate(&m_gui,E_ELEM_SLIDER3,E_PG_MAIN,&m_sXSlider3, + (gslc_tsRect){150,10,40,180},0,100,0,10,true); + gslc_ElemXSliderSetStyle(&m_gui,pElemRef,true,GSLC_COL_WHITE,5,10,GSLC_COL_WHITE); + gslc_ElemXSliderSetPosFunc(&m_gui,pElemRef,&CbSlidePos); + gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_WHITE,GSLC_COL_BLACK,GSLC_COL_BLACK); + m_pElemSlider2_3 = pElemRef; + + // Create E_ELEM_IMAGEBTN_BRIGHTNESS button with image label + pElemRef = gslc_ElemCreateBtnImg(&m_gui,E_ELEM_IMAGEBTN_BRIGHTNESS,E_PG_MAIN,(gslc_tsRect){150,190,40,40}, + gslc_GetImageFromProg((const unsigned char*)auto_bright_40x40px,GSLC_IMGREF_FMT_RAW1), + gslc_GetImageFromProg((const unsigned char*)auto_bright_40x40px,GSLC_IMGREF_FMT_RAW1), + &CbBtnCommon); + + // Create E_ELEM_IMAGEBTN5 button with image label + pElemRef = gslc_ElemCreateBtnImg(&m_gui,E_ELEM_IMAGEBTN5,E_PG_MAIN,(gslc_tsRect){10,70,130,130}, + gslc_GetImageFromProg((const unsigned char*)rsc_130x130,GSLC_IMGREF_FMT_RAW1), + gslc_GetImageFromProg((const unsigned char*)rsc_130x130,GSLC_IMGREF_FMT_RAW1), + &CbBtnCommon); + gslc_ElemSetFillEn(&m_gui,pElemRef,false); + + // Create E_ELEM_IMAGEBTN_BURGER button with image label + pElemRef = gslc_ElemCreateBtnImg(&m_gui,E_ELEM_IMAGEBTN_BURGER,E_PG_MAIN,(gslc_tsRect){270,10,40,40}, + gslc_GetImageFromProg((const unsigned char*)burger_icon_40x40px,GSLC_IMGREF_FMT_RAW1), + gslc_GetImageFromProg((const unsigned char*)burger_icon_40x40px,GSLC_IMGREF_FMT_RAW1), + &CbBtnCommon); + + // Create E_ELEM_IMAGEBTN_PWR button with image label + pElemRef = gslc_ElemCreateBtnImg(&m_gui,E_ELEM_IMAGEBTN_PWR,E_PG_MAIN,(gslc_tsRect){10,10,40,40}, + gslc_GetImageFromProg((const unsigned char*)power_icon_40x40px,GSLC_IMGREF_FMT_RAW1), + gslc_GetImageFromProg((const unsigned char*)power_icon_40x40px,GSLC_IMGREF_FMT_RAW1), + &CbBtnCommon); + + // ----------------------------------- + // PAGE: E_PG_BURGER_MENU - // create E_ELEM_BTN1 button with text label - pElemRef = gslc_ElemCreateBtnTxt(&m_gui,E_ELEM_BTN1,E_PG_MAIN, - (gslc_tsRect){14,12,80,40},(char*)"",0,E_BUILTIN5X8,&CbBtnCommon); // Create E_ELEM_BOX1 box - pElemRef = gslc_ElemCreateBox(&m_gui,E_ELEM_BOX1,E_PG_MAIN,(gslc_tsRect){187,4,126,119}); - - // Add Spinner element - pElemRef = gslc_ElemXSpinnerCreate(&m_gui,E_ELEM_SPINNER1,E_PG_MAIN,&m_sXSpinner1, - (gslc_tsRect){176,205,136,32},0,99,0,1,E_BUILTIN5X8,20,&CbSpinner); - m_pElemSpinner1 = pElemRef; - - // Create ring gauge E_ELEM_RINGGAUGE1 - static char m_sRingText1[11] = ""; - pElemRef = gslc_ElemXRingGaugeCreate(&m_gui,E_ELEM_RINGGAUGE1,E_PG_MAIN,&m_sXRingGauge1, - (gslc_tsRect){201,17,100,100}, - (char*)m_sRingText1,11,E_BUILTIN5X8); - gslc_ElemXRingGaugeSetValRange(&m_gui, pElemRef, 0, 100); - gslc_ElemXRingGaugeSetVal(&m_gui, pElemRef, 0); // Set initial value - m_pElemXRingGauge1 = pElemRef; + pElemRef = gslc_ElemCreateBox(&m_gui,E_ELEM_BOX1,E_PG_BURGER_MENU,(gslc_tsRect){10,10,300,220}); + gslc_ElemSetRoundEn(&m_gui, pElemRef, true); - // Create E_ELEM_TEXT1 text label - pElemRef = gslc_ElemCreateTxt(&m_gui,E_ELEM_TEXT1,E_PG_MAIN,(gslc_tsRect){111,14,60,10}, - (char*)"",0,E_BUILTIN5X8); - - // Create progress bar E_ELEM_PROGRESS1 - pElemRef = gslc_ElemXProgressCreate(&m_gui,E_ELEM_PROGRESS1,E_PG_MAIN,&m_sXBarGauge1, - (gslc_tsRect){200,178,111,18},0,100,0,GSLC_COL_GREEN,false); - m_pElemProgress1 = pElemRef; - - // Create slider E_ELEM_SLIDER1 - pElemRef = gslc_ElemXSliderCreate(&m_gui,E_ELEM_SLIDER1,E_PG_MAIN,&m_sXSlider1, - (gslc_tsRect){205,136,110,37},0,100,0,5,false); - gslc_ElemXSliderSetStyle(&m_gui,pElemRef,false,GSLC_COL_BLUE,10,5,GSLC_COL_BLUE); - gslc_ElemXSliderSetPosFunc(&m_gui,pElemRef,&CbSlidePos); - m_pElemSlider1 = pElemRef; + // Create E_ELEM_BTN_MENU_CLOSE button with image label + pElemRef = gslc_ElemCreateBtnImg(&m_gui,E_ELEM_BTN_MENU_CLOSE,E_PG_BURGER_MENU,(gslc_tsRect){270,100,40,40}, + gslc_GetImageFromProg((const unsigned char*)back_40x40px,GSLC_IMGREF_FMT_RAW1), + gslc_GetImageFromProg((const unsigned char*)back_40x40px,GSLC_IMGREF_FMT_RAW1), + &CbBtnCommon); - // Create toggle button E_ELEM_TOGGLE1 - pElemRef = gslc_ElemXTogglebtnCreate(&m_gui,E_ELEM_TOGGLE1,E_PG_MAIN,&m_asXToggle1, - (gslc_tsRect){123,162,64,24},GSLC_COL_GRAY,GSLC_COL_BLUE_DK2,GSLC_COL_GRAY_LT3, + // Create toggle button E_ELEM_TOGGLE_THEME + pElemRef = gslc_ElemXTogglebtnCreate(&m_gui,E_ELEM_TOGGLE_THEME,E_PG_BURGER_MENU,&m_asXToggle10, + (gslc_tsRect){180,20,60,30},GSLC_COL_WHITE,GSLC_COL_WHITE,GSLC_COL_BLACK, true,false,&CbBtnCommon); - m_pElemToggle1 = pElemRef; - - // create checkbox E_ELEM_CHECK1 - pElemRef = gslc_ElemXCheckboxCreate(&m_gui,E_ELEM_CHECK1,E_PG_MAIN,&m_asXCheck1, - (gslc_tsRect){120,201,31,31},false,GSLCX_CHECKBOX_STYLE_X,GSLC_COL_ORANGE,false); - gslc_ElemXCheckboxSetStateFunc(&m_gui, pElemRef, &CbCheckbox); - m_pElemCBCheckBox = pElemRef; + m_pElemToggle2_7_10 = pElemRef; - // Create radio button E_ELEM_RADIO1 - pElemRef = gslc_ElemXCheckboxCreate(&m_gui,E_ELEM_RADIO1,E_PG_MAIN,&m_asXRadio1, - (gslc_tsRect){234,49,34,34},true,GSLCX_CHECKBOX_STYLE_ROUND,GSLC_COL_ORANGE,false); - gslc_ElemXCheckboxSetStateFunc(&m_gui, pElemRef, &CbCheckbox); - m_pElemRBRadioButton = pElemRef; + // Create E_ELEM_TEXT_THEME text label + pElemRef = gslc_ElemCreateTxt(&m_gui,E_ELEM_TEXT_THEME,E_PG_BURGER_MENU,(gslc_tsRect){240,20,60,30}, + (char*)"Theme",0,E_BUILTIN10X16); + gslc_ElemSetTxtCol(&m_gui,pElemRef,GSLC_COL_WHITE); - // create E_ELEM_BTN2 button with text label - pElemRef = gslc_ElemCreateBtnTxt(&m_gui,E_ELEM_BTN2,E_PG_MAIN, - (gslc_tsRect){108,30,51,29},(char*)"",0,E_BUILTIN5X8,&CbBtnCommon); - - // Create progress bar E_ELEM_RAMPGAUGE1 - pElemRef = gslc_ElemXRampCreate(&m_gui,E_ELEM_RAMPGAUGE1,E_PG_MAIN,&m_sXRampGauge1, - (gslc_tsRect){9,156,100,80},0,100, - 0,GSLC_COL_YELLOW,false); - m_pElemRamp1 = pElemRef; + // Create toggle button E_ELEM_TOGGLE_DEBUG + pElemRef = gslc_ElemXTogglebtnCreate(&m_gui,E_ELEM_TOGGLE_DEBUG,E_PG_BURGER_MENU,&m_asXToggle7, + (gslc_tsRect){20,20,60,30},GSLC_COL_WHITE,GSLC_COL_WHITE,GSLC_COL_BLACK, + true,false,&CbBtnCommon); + m_pElemToggle2_7 = pElemRef; - // Create E_ELEM_TEXTINPUT1 text input field - static char m_sInputText1[11] = ""; - pElemRef = gslc_ElemCreateTxt(&m_gui,E_ELEM_TEXTINPUT1,E_PG_MAIN,(gslc_tsRect){12,70,86,72}, - (char*)m_sInputText1,11,E_BUILTIN5X8); - gslc_ElemSetTxtMargin(&m_gui,pElemRef,5); - gslc_ElemSetFrameEn(&m_gui,pElemRef,true); - gslc_ElemSetClickEn(&m_gui, pElemRef, true); - gslc_ElemSetTouchFunc(&m_gui, pElemRef, &CbBtnCommon); - m_pElemInTxt1 = pElemRef; + // Create E_ELEM_TEXT_DEBUG_TOGGLE text label + pElemRef = gslc_ElemCreateTxt(&m_gui,E_ELEM_TEXT_DEBUG_TOGGLE,E_PG_BURGER_MENU,(gslc_tsRect){80,20,60,30}, + (char*)"Debug",0,E_BUILTIN10X16); + gslc_ElemSetTxtCol(&m_gui,pElemRef,GSLC_COL_WHITE); - // Create E_ELEM_NUMINPUT1 numeric input field - static char m_sInputNumber1[6] = ""; - pElemRef = gslc_ElemCreateTxt(&m_gui,E_ELEM_NUMINPUT1,E_PG_MAIN,(gslc_tsRect){116,70,61,76}, - (char*)m_sInputNumber1,6,E_BUILTIN5X8); - gslc_ElemSetTxtMargin(&m_gui,pElemRef,5); + // Create E_ELEM_TEXT_STATS runtime modifiable text + static char m_sDisplayText8[121] = "Stats"; + pElemRef = gslc_ElemCreateTxt(&m_gui,E_ELEM_TEXT_STATS,E_PG_BURGER_MENU,(gslc_tsRect){20,70,240,150}, + (char*)m_sDisplayText8,121,E_BUILTIN10X16); gslc_ElemSetFrameEn(&m_gui,pElemRef,true); - gslc_ElemSetClickEn(&m_gui, pElemRef, true); - gslc_ElemSetTouchFunc(&m_gui, pElemRef, &CbBtnCommon); - m_pElemVal1 = pElemRef; + gslc_ElemSetTxtCol(&m_gui,pElemRef,GSLC_COL_WHITE); + gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_WHITE,GSLC_COL_BLACK,GSLC_COL_BLACK); + m_pElemOutTxt8 = pElemRef; + + // Create E_DRAW_LINE1 line + pElemRef = gslc_ElemCreateLine(&m_gui,E_DRAW_LINE1,E_PG_BURGER_MENU,10,60,310,60); + gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_BLACK,GSLC_COL_WHITE,GSLC_COL_WHITE); + + // Create E_DRAW_LINE2 line + pElemRef = gslc_ElemCreateLine(&m_gui,E_DRAW_LINE2,E_PG_BURGER_MENU,160,10,160,60); + gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_BLACK,GSLC_COL_WHITE,GSLC_COL_WHITE); // ----------------------------------- - // PAGE: E_POP_KEYPAD_NUM + // PAGE: E_PG_PWR + + + // Create E_ELEM_PWR_BOX box + pElemRef = gslc_ElemCreateBox(&m_gui,E_ELEM_PWR_BOX,E_PG_PWR,(gslc_tsRect){10,10,300,220}); + gslc_ElemSetRoundEn(&m_gui, pElemRef, true); + gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_WHITE,GSLC_COL_BLACK,GSLC_COL_BLACK); + + // Create E_ELEM_IMAGEBTN_PWR_CLOSE button with image label + pElemRef = gslc_ElemCreateBtnImg(&m_gui,E_ELEM_IMAGEBTN_PWR_CLOSE,E_PG_PWR,(gslc_tsRect){270,100,40,40}, + gslc_GetImageFromProg((const unsigned char*)back_40x40px,GSLC_IMGREF_FMT_RAW1), + gslc_GetImageFromProg((const unsigned char*)back_40x40px,GSLC_IMGREF_FMT_RAW1), + &CbBtnCommon); + + // create E_ELEM_BTN5 button with text label + pElemRef = gslc_ElemCreateBtnTxt(&m_gui,E_ELEM_BTN5,E_PG_PWR, + (gslc_tsRect){20,20,110,40},(char*)"Poweroff",0,E_BUILTIN10X16,&CbBtnCommon); + gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_WHITE,GSLC_COL_BLACK,GSLC_COL_BLACK); + gslc_ElemSetRoundEn(&m_gui, pElemRef, true); - static gslc_tsXKeyPadCfg_Num sCfg; - sCfg = gslc_ElemXKeyPadCfgInit_Num(); - gslc_ElemXKeyPadCfgSetFloatEn_Num(&sCfg, true); - gslc_ElemXKeyPadCfgSetSignEn_Num(&sCfg, true); - m_pElemKeyPadNum = gslc_ElemXKeyPadCreate_Num(&m_gui, E_ELEM_KEYPAD_NUM, E_POP_KEYPAD_NUM, - &m_sKeyPadNum, 65, 80, E_BUILTIN5X8, &sCfg); - gslc_ElemXKeyPadValSetCb(&m_gui, m_pElemKeyPadNum, &CbKeypad); + // create E_ELEM_BTN6 button with text label + pElemRef = gslc_ElemCreateBtnTxt(&m_gui,E_ELEM_BTN6,E_PG_PWR, + (gslc_tsRect){190,20,110,40},(char*)"Reboot",0,E_BUILTIN10X16,&CbBtnCommon); + gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_WHITE,GSLC_COL_BLACK,GSLC_COL_BLACK); + gslc_ElemSetRoundEn(&m_gui, pElemRef, true); + + // Create E_DRAW_LINE3 line + pElemRef = gslc_ElemCreateLine(&m_gui,E_DRAW_LINE3,E_PG_PWR,10,120,270,120); + gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_BLACK,GSLC_COL_GRAY_LT2,GSLC_COL_GRAY_LT2); + + // create E_ELEM_BTN10 button with text label + pElemRef = gslc_ElemCreateBtnTxt(&m_gui,E_ELEM_BTN10,E_PG_PWR, + (gslc_tsRect){20,180,110,40},(char*)"Reset",0,E_BUILTIN10X16,&CbBtnCommon); + gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_WHITE,GSLC_COL_BLACK,GSLC_COL_BLACK); + gslc_ElemSetRoundEn(&m_gui, pElemRef, true); + + // create E_ELEM_BTN11 button with text label + pElemRef = gslc_ElemCreateBtnTxt(&m_gui,E_ELEM_BTN11,E_PG_PWR, + (gslc_tsRect){190,180,110,40},(char*)"Reboot",0,E_BUILTIN10X16,&CbBtnCommon); + gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_WHITE,GSLC_COL_BLACK,GSLC_COL_BLACK); + gslc_ElemSetRoundEn(&m_gui, pElemRef, true); + + // Create E_ELEM_TEXT9 text label + pElemRef = gslc_ElemCreateTxt(&m_gui,E_ELEM_TEXT9,E_PG_PWR,(gslc_tsRect){50,70,216,24}, + (char*)"Raspberry Pi",0,E_BUILTIN15X24); + gslc_ElemSetTxtCol(&m_gui,pElemRef,GSLC_COL_WHITE); + gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_WHITE,GSLC_COL_BLACK,GSLC_COL_BLACK); + + // Create E_ELEM_TEXT10 text label + pElemRef = gslc_ElemCreateTxt(&m_gui,E_ELEM_TEXT10,E_PG_PWR,(gslc_tsRect){50,150,198,24}, + (char*)"Front panel",0,E_BUILTIN15X24); + gslc_ElemSetTxtCol(&m_gui,pElemRef,GSLC_COL_WHITE); + gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_WHITE,GSLC_COL_BLACK,GSLC_COL_BLACK); // ----------------------------------- - // PAGE: E_POP_KEYPAD_ALPHA + // PAGE: E_PG_POPUP_CONFIRM + + + // Create E_ELEM_BOX_CONFIRM box + pElemRef = gslc_ElemCreateBox(&m_gui,E_ELEM_BOX_CONFIRM,E_PG_POPUP_CONFIRM,(gslc_tsRect){10,50,300,130}); + gslc_ElemSetRoundEn(&m_gui, pElemRef, true); + + // Create E_ELEM_IMAGEBTN_CONFIRM_BACK button with image label + pElemRef = gslc_ElemCreateBtnImg(&m_gui,E_ELEM_IMAGEBTN_CONFIRM_BACK,E_PG_POPUP_CONFIRM,(gslc_tsRect){270,100,40,40}, + gslc_GetImageFromProg((const unsigned char*)back_40x40px,GSLC_IMGREF_FMT_RAW1), + gslc_GetImageFromProg((const unsigned char*)back_40x40px,GSLC_IMGREF_FMT_RAW1), + &CbBtnCommon); + + // Create E_ELEM_TEXT_CONFIRM runtime modifiable text + static char m_sDisplayText11[51] = "Message"; + pElemRef = gslc_ElemCreateTxt(&m_gui,E_ELEM_TEXT_CONFIRM,E_PG_POPUP_CONFIRM,(gslc_tsRect){20,60,240,60}, + (char*)m_sDisplayText11,51,E_BUILTIN10X16); + gslc_ElemSetTxtAlign(&m_gui,pElemRef,GSLC_ALIGN_MID_MID); + gslc_ElemSetTxtCol(&m_gui,pElemRef,GSLC_COL_WHITE); + m_pElemOutTxt11 = pElemRef; + + // create E_ELEM_BTN_YES button with text label + pElemRef = gslc_ElemCreateBtnTxt(&m_gui,E_ELEM_BTN_YES,E_PG_POPUP_CONFIRM, + (gslc_tsRect){30,130,90,30},(char*)"Yes",0,E_BUILTIN10X16,&CbBtnCommon); + gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_WHITE,GSLC_COL_BLACK,GSLC_COL_BLACK); + gslc_ElemSetRoundEn(&m_gui, pElemRef, true); + gslc_ElemSetFillEn(&m_gui,pElemRef,false); - static gslc_tsXKeyPadCfg_Alpha sCfgTx; - sCfgTx = gslc_ElemXKeyPadCfgInit_Alpha(); - m_pElemKeyPadAlpha = gslc_ElemXKeyPadCreate_Alpha(&m_gui, E_ELEM_KEYPAD_ALPHA, E_POP_KEYPAD_ALPHA, - &m_sKeyPadAlpha, 65, 80, E_BUILTIN5X8, &sCfgTx); - gslc_ElemXKeyPadValSetCb(&m_gui, m_pElemKeyPadAlpha, &CbKeypad); + // create E_ELEM_BTN_CANCEL button with text label + pElemRef = gslc_ElemCreateBtnTxt(&m_gui,E_ELEM_BTN_CANCEL,E_PG_POPUP_CONFIRM, + (gslc_tsRect){160,130,90,30},(char*)"Cancel",0,E_BUILTIN10X16,&CbBtnCommon); + gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_WHITE,GSLC_COL_BLACK,GSLC_COL_BLACK); + gslc_ElemSetRoundEn(&m_gui, pElemRef, true); + gslc_ElemSetFillEn(&m_gui,pElemRef,false); // // diff --git a/src/MenuCallbacks.cpp b/src/MenuCallbacks.cpp index e69de29..4c32842 100644 --- a/src/MenuCallbacks.cpp +++ b/src/MenuCallbacks.cpp @@ -0,0 +1,167 @@ +#include "test_GSLC.h" +#include "Config.h" + + +// ------------------------------------------------ +// Program Globals +// ------------------------------------------------ + +// Save some element references for direct access +// +gslc_tsElemRef* m_pElemOutTxt11 = NULL; +gslc_tsElemRef* m_pElemOutTxt8 = NULL; +gslc_tsElemRef* m_pElemSlider2 = NULL; +gslc_tsElemRef* m_pElemSlider2_3 = NULL; +gslc_tsElemRef* m_pElemToggle2_7 = NULL; +gslc_tsElemRef* m_pElemToggle2_7_10= NULL; +gslc_tsElemRef* m_pElemToggleImg29= NULL; +gslc_tsElemRef* m_pElemToggleImg32= NULL; +// + +// Confirm popup: pending command stashed by destructive buttons, executed by YES +#define PENDING_CMD_MAX 24 +static char m_acPendingCmd[PENDING_CMD_MAX] = {0}; + +// Routes host_* commands to Serial; everything else to the local dispatch table +static void executePending() { + if (strncmp(m_acPendingCmd, "host_", 5) == 0) { + Serial.println(m_acPendingCmd); // host service consumes via its serial listener + } else { + const Command* cmd = findCommand(String(m_acPendingCmd)); + if (cmd && cmd->get) cmd->get(); + else Serial.printf("ERR: no handler for '%s'\n", m_acPendingCmd); + } +} + + +// ------------------------------------------------ +// Callback Methods +// ------------------------------------------------ +// Common Button callback +bool CbBtnCommon(void* pvGui,void *pvElemRef,gslc_teTouch eTouch,int16_t nX,int16_t nY) +{ + // Typecast the parameters to match the GUI and element types + gslc_tsGui* pGui = (gslc_tsGui*)(pvGui); + gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef); + gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef); + + if ( eTouch == GSLC_TOUCH_UP_IN ) { + // From the element's ID we can determine which button was pressed. + switch (pElem->nId) { +//