Learning path for UI Menu design in arduino


I want to add a UI menu and shown on OLED for the IOT logger project.

I had reviewed a lot of menu sample coding (eg: menu using encoder , software creating menu) , but still feel different to merge the coding into my project...

Is that any path/ material to learning UI design for arduino? ( design logic, method etc).

(Seems related material is lacking, or wrong keyword was search....)

The complexity depends on your specific needs ... AND nesting levels.

Simple 1, 2, 3 menu
More complex 1a, 1b, 1c, 2a, 2b, 2c, 3a, 3b, 3c

and then if sub-levels return to main menu OR to previous (nested) menu.

Draw it on Paper ... Or put it in Excel as a start before beginning coding.

I suspect you have already investigated the obvious:

Not really, because every project menu is different. You will probably discover that most of the menu code you find does not do what you want, and is hard to modify.

Thanks for the advice

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 {
    const char * title;
    MenuItem *parent = nullptr;
    MenuItem *prev = nullptr;
    MenuItem *next = nullptr;
    MenuItem *child = nullptr;

    MenuItem(const char * title)
      : title(title) {}

    void display() {
      if (parent) {
        lcd.setCursor(0, 0);
        lcd.print("# ");
        lcd.print(" #");
      lcd.setCursor(0, 1);

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() {

  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;

void handleMenuInput(byte buttonPressed) {
  switch (buttonPressed) {
    case 0:
      if (currentMenu->child)
        currentMenu = currentMenu->child;

    case 1:
      if (currentMenu->parent)
        currentMenu = currentMenu->parent;

    case 2:
      if (currentMenu->prev)
        currentMenu = currentMenu->prev;

    case 3:
      if (currentMenu->next)
        currentMenu = currentMenu->next;

void loop() {
  for (byte i = 0; i < NUM_BTNS; i++) {
    if (buttons[i].read() == SINGLE_PRESS)

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).