I've just roughed this out real quick.... But I've had relative success in the past a linked lists approach... (well, multi-linked lists anyway!).
Something approximating this:
#include "KTS_Button.h"
#include <LiquidCrystal_I2C.h>
KTS_Button buttons[] = { 22, 23, 24, 25, 9 };
const byte NUM_BTNS = sizeof(buttons) / sizeof(buttons[0]);
LiquidCrystal_I2C lcd(0x27, 16, 2);
class MenuItem {
public:
const char * title;
MenuItem *parent = nullptr;
MenuItem *prev = nullptr;
MenuItem *next = nullptr;
MenuItem *child = nullptr;
MenuItem(const char * title)
: title(title) {}
void display() {
lcd.clear();
if (parent) {
lcd.setCursor(0, 0);
lcd.print("# ");
lcd.print(parent->title);
lcd.print(" #");
}
lcd.setCursor(0, 1);
lcd.print(title);
}
};
MenuItem *currentMenu;
MenuItem mainMenu = { "Main Menu" };
MenuItem l1_MenuOne = { "1) Menu One L1" }; // Level One Menu Item
MenuItem l1_MenuTwo = { "2) Menu Two L1" };
MenuItem l2_MenuOne = { "1) Menu One L2" }; // Level Two Menu Item
MenuItem l2_MenuTwo = { "2) Menu Two L2" };
void setup() {
Serial.begin(115600);
lcd.init();
lcd.backlight();
mainMenu.child = &l1_MenuOne;
l1_MenuOne.parent = &mainMenu;
l1_MenuOne.next = &l1_MenuTwo;
l1_MenuTwo.prev = &l1_MenuOne;
l1_MenuTwo.parent = &mainMenu;
l1_MenuTwo.child = &l2_MenuOne;
l2_MenuOne.parent = &l1_MenuTwo;
l2_MenuOne.next = &l2_MenuTwo;
l2_MenuTwo.prev = &l2_MenuOne;
l2_MenuTwo.parent = &l1_MenuTwo;
currentMenu = &mainMenu;
currentMenu->display();
}
void handleMenuInput(byte buttonPressed) {
switch (buttonPressed) {
case 0:
if (currentMenu->child)
currentMenu = currentMenu->child;
break;
case 1:
if (currentMenu->parent)
currentMenu = currentMenu->parent;
break;
case 2:
if (currentMenu->prev)
currentMenu = currentMenu->prev;
break;
case 3:
if (currentMenu->next)
currentMenu = currentMenu->next;
break;
}
currentMenu->display();
}
void loop() {
for (byte i = 0; i < NUM_BTNS; i++) {
if (buttons[i].read() == SINGLE_PRESS)
handleMenuInput(i);
}
}
The issues I've had so far are:
One, it's a bit of a waste to hold empty pointers where they are not needed (especially if you have a very large menu!) and two, writing out how everything is connected is messy, and very prone to typos/mistakes.
Adding function pointers or values and things to the menu items is pretty easy though! And it's a tested and working example. (The button class is my own, but any will do).