J-M-L:
I think you are over engineering your Object Oriented approach there.
A menu is something that can hold an ordered list of either menu or leaves. leaves can have a call back function attached for example. (but so do intermediary menu items, you could want to trigger something as you dive in)
that would be something like
class Menu
{
public:
static const uint8_t maxName = 20;
Menu(const char* myname, void (*callBack)(void) = NULL) : action(callBack)
{
strncpy(label, myname, maxName);
label[maxName] = '\0'; // just in case we overflow
subMenu = NULL;
nbEntries = 0;
}
char label[maxName + 1];
uint8_t nbEntries;
Menu** subMenu;
void (*action)(void);
};
void f1(void) {
Serial.println("f1");
}
void f2(void) {
Serial.println("f2");
}
void f3(void) {
Serial.println("f3");
}
void f4(void) {
Serial.println("f4");
}
void f5(void) {
Serial.println("f5");
}
// we build up the Menu hierarchy starting from the leaves
Menu f1Menu("f1", f1);
Menu f2Menu("f2", f2);
Menu f3Menu("f3", f3);
Menu f4Menu("f4", f4);
Menu f5Menu("f5", f5);
Menu* M1[] = {&f1Menu, &f2Menu};
Menu* M2[] = {&f3Menu, &f4Menu, &f5Menu};
Menu subM1("M1");
Menu subM2("M2");
Menu* M0[] = {&subM1, &subM2};
Menu topMenu("Top Menu");
void displayMenuTree(Menu* m, uint8_t indent = 0)
{
Serial.println(m->label);
for (uint8_t i = 0; i < m->nbEntries; i++) {
for (uint8_t p = 0; p < indent+1; p++) Serial.print(" ");
if (m->subMenu[i] != NULL) displayMenuTree(m->subMenu[i], indent + 1);
}
}
void setup()
{
Serial.begin(115200);
// organize the Menu
topMenu.subMenu = M0;
topMenu.nbEntries = sizeof(M0) / sizeof(M0[0]);
subM1.subMenu = M1;
subM1.nbEntries = sizeof(M1) / sizeof(M1[0]);
subM2.subMenu = M2;
subM2.nbEntries = sizeof(M2) / sizeof(M2[0]);
displayMenuTree(&topMenu);
}
void loop() {}
Running this basically builds up the menu trees and calls displayMenuTree(). You should see this in the console
Top Menu
M1
f1
f2
M2
f3
f4
f5
Ah yes that does seem simpler. That's basically what I was going for except I wanted the list of members to be 2D so its easier to organise which members belong on which line/col on an LCD screen.
For example you might want:
Top Menu
M1
F1
F2
M2
F3 F4 F5
Could you replace
Menu* M2[] = {&f3Menu, &f4Menu, &f5Menu};
with
Menu** M2[] = Menu* M2[] = {{&f3Menu}, {&f4Menu}, {&f5Menu}};
And tweak displayMenuTree to get the desired effect above?
If you also wanted to add values of any type which also have names to your list how would you implement it without "over engineering" it?
How can I change my code so that I can use:
SET_TIME.menulist = {{&set_hour, &set_minute, &set_second},{&set_year, &set_month, &set_day}};
Instead of :
SET_TIME.menulist[0][1]=&set_hour; //menulist[0][0] reserved for previous Menu
SET_TIME.menulist[0][2]=&set_minute;
SET_TIME.menulist[0][3]=&set_second;
SET_TIME.menulist[1][0]=&set_day;
SET_TIME.menulist[1][1]=&set_month;
SET_TIME.menulist[1][2]=&set_year;