Передмова
Треба "замути" за допомоги віджету Table в системі Blynk меню. Щоб було зручно додавати, видаляти та розширяти пункти меню при програмуванні. Подобається реалізація мікроменю і захотілось щось подібне реалізувати. Почав переробляти мікроменю на свій лад і стикнувся з такою проблемою:
мікроменю - це однорядкове меню де є попереднє, наступне, батьківське і дочірнє меню, та функції зворотнього виклику - коли обрав меню і коли натиснув ввід. На екрані виводиться один пункт меню а доступ до інших пунктів меню та зміни параметрів виконується за допомоги клавішної навігації. На екрані по суті бачимо один пункт меню і все. Все інше гортаємо кнопками.
що мені треба! Є таблиця, яка складається з полів (рядків), а поле (рядок) з: Id, Name, Value. Меню сторінкове. Наприклад перша сторінка це набір рядків для головного меню. Коли тицяти в якийсь рядок меню, то, або потрапляєш на іншу сторінку меню (підменю), або виконується якась функція чи міняється параметр. Ну і так далі. З навігації достатньо мати батьківську сторінку і дочірню (оперуємо вже сторінками, а не пунктами меню)
Що я не можу осягнути і зрозуміти! Це як згрупувати пункти меню посторінково і оперувати сторінками, а не окремими пунктами. Ще одне. Ідентифікація на який пункт меню натиснуто йде по Id рядку. Треба якось додати ще те Id до структур, щоб можна було виконувати навігацію та виклик функцій зворотнього виклику
Керування таблицею
Перелічу тільки що потрібно.
Формуються рядки в таблиці таким чином:
Blynk.virtualWrite(V1, "add", id, "Name", "Value");
Оновити рядок:
Blynk.virtualWrite(V1, "update", id, "UpdatedName", "UpdatedValue");
А обробник зміни стану рядка "marked/unmarked", наприклад, має такий вигляд. Це просто для розуміння як працює:
table.onSelectChange([](int index, bool selected) {
Serial.print("Item ");
Serial.print(index);
Serial.print(selected ? " marked" : " unmarked");
});
Де index це Id рядку, а selected це - "позначено" чи "знята позначка" з того рядку.
Думаю що треба сформувати якесь "сховище" - структуру/макрос, де будуть зберігатись Id для головного меню і всіх інших підменю. А вже якесь окреме "сховище" для кожного рядку меню де будуть зберігатись Id, Parent, Child, SelectCallBack, EnterCallBack, Text, Value.
Тоді я виконую якусь функцію/макрос, яка формує головну сторінку, і вже далі, в залежності який рядок я натисну, викликається чи функція по зміні параметру, чи функція/макрос формування нової сторінки підменю, в залежності від параметрів що зберігає "сховище" для цього рядку, який позначили.
Що вже зробив
файл TableMenu.h:
// tableMenu.h
#ifndef _TABLEMENU_h
#define _TABLEMENU_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "arduino.h"
#else
#include "WProgram.h"
#endif
typedef const struct TableMenu
{
const struct TableMenu *Parent;
const struct TableMenu *Child;
void(*SelectCallback)(void);
void(*EnterCallback) (void);
const char Text[16];
const char Value[16];
}TableMenuStruct;
#define MENU_ITEM(Name, Parent, Child, SelectFunc, EnterFunc, Text, Value) \
extern TableMenuStruct const Parent; \
extern TableMenuStruct const Child; \
TableMenuStruct const Name = {&Parent, &Child, SelectFunc, EnterFunc, Text, Value}
#define MENU_PARENT (Menu_GetCurrentMenu()->Parent)
#define MENU_CHILD (Menu_GetCurrentMenu()->Child)
extern TableMenuStruct NULL_MENU;
TableMenuStruct* Menu_GetCurrentMenu(void);
void Menu_Navigate(TableMenuStruct* const NewMenu);
void Menu_SetGenericWriteCallback(void(*WriteFunc)(const char* Text, const char* Value));
void Menu_EnterCurrentItem(void);
#endif
Файл TableMenu.cpp:
#include "tableMenu.h"
TableMenuStruct NULL_MENU = { 0 };
static void(*MenuWriteFunc)(const char* Text, const char* Value) = NULL;
static TableMenuStruct* CurrentMenuItem = &NULL_MENU;
TableMenuStruct* Menu_GetCurrentMenu(void)
{
return CurrentMenuItem;
}
void Menu_Navigate(TableMenuStruct* const NewMenu)
{
if ((NewMenu == &NULL_MENU) || (NewMenu == NULL))
return;
CurrentMenuItem = NewMenu;
if (MenuWriteFunc)
MenuWriteFunc(CurrentMenuItem->Text, CurrentMenuItem->Value);
void(*SelectCallback)(void) = CurrentMenuItem->SelectCallback;
if (SelectCallback)
SelectCallback();
}
void Menu_SetGenericWriteCallback(void(*WriteFunc)(const char* Text, const char* Value))
{
MenuWriteFunc = WriteFunc;
Menu_Navigate(CurrentMenuItem);
}
void Menu_EnterCurrentItem(void)
{
if ((CurrentMenuItem == &NULL_MENU) || (CurrentMenuItem == NULL))
return;
void(*EnterCallback)(void) = CurrentMenuItem->EnterCallback;
if (EnterCallback)
EnterCallback();
}
В main.cpp додаю таке, для прикладу, просто початкова сторінка меню з трьох пунктів і як натиснути потрапити у відповідне підменю з одного пункту, натиснувши який повернутись в попереднє меню:
static void Generic_Write(const char* Text, const char* Value);
// Menus Name | Parent | Child | SelectFunction | EnterFunction | Text | Value
MENU_ITEM(Menu_1, NULL_MENU, Menu_1_1, NULL, NULL, "Menu-1", "->");
MENU_ITEM(Menu_2, NULL_MENU, Menu_2_1, NULL, NULL, "Menu-2", "->");
MENU_ITEM(Menu_3, NULL_MENU, Menu_3_1, NULL, NULL, "Menu-3", "->");
MENU_ITEM(Menu_1_1, Menu_1, NULL_MENU, NULL, NULL, "Menu-1.1", "<-");
MENU_ITEM(Menu_2_1, Menu_2, NULL_MENU, NULL, NULL, "Menu-2.1", "<-");
MENU_ITEM(Menu_3_1, Menu_3, NULL_MENU, NULL, NULL, "Menu-3.1", "<-");
static void Generic_Write(const char* Text, const char* Value)
{
if (Text && Value)
{
//TODO: тут формування рядка таблиці
}
}
Встановлення функції зворотнього виклику і встановлення початкового меню:
Menu_SetGenericWriteCallback(Generic_Write);
Menu_Navigate(&Menu_1);
На цьому етапі я зрозумів, що:
в мене не вистачає ще параметру Id, який треба додати до MENU_ITEM і відповідно до структури TableMenuStruct і передавати Id в функцію Generic_Write. Так?
в мене не вистачає ще якогось коду де буде формуватись список з айдішніків для головного меню та всіх підменю. Бо виходить що я викликаю формування одного рядку Menu_1 головного меню, а не списку рядків меню. І якщо повернутись з підменю Menu_1_1 я потрапляю конкретно на Menu_1, а не список з трьох пунктів головного меню. Так?
ще що?
Так що, допоможіть будь ласка, якщо мої здогадки вірні, з кодом (макросом, структурою чи масивом, чи enum) який формує список айдішніків для сторінок меню і як це зв'язати з тим що вже є. Не можу докумекати хоч ти лусни. Хоч щось порадьте шановні.
p.s. особливі сподівання на моїх постійних наставників ReAl та koala