Arduino LCD menu interface

I am trying to write an interface consisting of an LCD screen and 5 buttons to navigate a linked list menu system to view and change variables of the Arduino at run time. I want to be able to read values from sensors e.g. temperature, store them in variables, and access these variables through the interface.

So this means I want a menu object which can simultaneously store a collection of pointers to other menu objects (nodes) as well as pointers to any variable type (values).

Decided to go with a linked list tree instead of a singly or doubly linked list so that each node can contain pointers to more than 2 nodes, navigated by a 2D array of pointers. This should not make much difference to the implementation.

class  MenuItem
{
public:
char Name[15];


 MenuItem(char* MyName)
 {
  strcpy(Name, MyName);
 }
 virtual ~MenuItem() {}
};

class Menu: public MenuItem
{
  
  public:
  MenuItem*** MenuList;

  Menu(const char* MyName,const byte x, const byte y):MenuItem(Name)
{

    if (y>0) //2D array of MenuItem pointers with null termination
    {
      MenuList = new MenuItem**[y+1];
      MenuList[y]=0;
      for (byte i=0; i<=y; i++)
      { 
        MenuList[i] = new MenuItem*[x+1];
        for (byte p=0; p<=x; p++)
          MenuList[i][p]=0;
      }      
    }
   
  }
};

template  class ValueItem: public MenuItem
{  
    public:
    T Value;
    T incvalue;
    T* ValuePtr; //This is so that Value can be modified without modifying the value it points to, not //used in this example
    bool ReadOnly;
    
    const char* UnitStr;

    ValueItem(const char* MyName="",const char* Unit="", T* valptr=0,bool Read=1): MenuItem(MyName)
    {
      ValuePtr=valptr;
      Value=*ValuePtr;
      ReadOnly=Read;
      UnitStr=Unit;    
    }

    void ChangeValue(T incvalue)
    {
      if !(ReadOnly) Value+=incvalue;
    }

    

   T GetValue()
    {
      return *ValuePtr;
    }
};


  float Temp = 24.6; //Temperature read from sensor
  float Temp_SetMin = 10.0;
  float Temp_SetMax = 30.0;

  Menu Main("Main: ",2,2); //create a 2x2 menu
  ValueItem Temperature("Temp: ","\xDF\C",&Temp,true); 
  ValueItem Temperature_SetMin("Min: ","\xDF\C",&Temp_SetMin,false); //Set minimum 
  ValueItem Temperature_SetMax("Max: ","\xDF\C",&Temp_SetMax,false); //Set maximum 

void setup() 
{
  // Debugging output
  Serial.begin(9600);
  MenuItem* Current_Menu;
  Current_Menu=&Main;
  Main.MenuList[0][0]=&Temperature;
  Main.MenuList[0][1]=&Temperature_SetMin;
  Main.MenuList[1][1]=&Temperature_SetMax
  Serial.print(Temperature.Name);
  Serial.print(Temperature.GetValue());
  Serial.print(Temperature.UnitStr);


//ValueItem *d = dynamic_cast*>(Current_Menu->MenuList[0][0]); // use dynamic cast to convert Base pointer into Derived pointer 


}


void loop()
{
}

All of the data is stored as I want it, but I don't know how to access the value of Temperature through Current_Menu and the base class.

The way I see it there is no reason why a ValueItem should know anything about MenuLists, or a Menu should know anything about Values.

But there are a few problems. First of all the base class has no concept of MenuList, so I cant get the Current_Menu's MenuList. I could store MenuItem*** MenuList in the base class, effectively getting rid of the Menu class, but then ValueItem would inherit this which I said makes no sense, and then I am still left with the problem of accessing a ValueItem's Value.

I can't make a Virtual function for Value, because ValueItem is a template class so the base class would need to know the type. I can't pass in the T value to the base because then the Base would also need to be a template class which defeats the purpose of having a base class (Having a list of both Menus and ValueItems).

I could get rid of the derived classes entirely and just have a single Menu class which has a void Value pointer and a Menu*** Menulist, and then use TypeDefs to cast to the appropriate type. Which I have done and it works but it just feels wrong, there must be a way to separate out Templated Values and base class array of pointers.

I appreciate any help, advice, or questions which go towards solving this problem as I have been stuck on it for a long time.

If the way I am doing it is not right, then what is the correct method to implement this? All I want to do is be able to have a list of objects which can be other lists or any value type.

here’s menu code i created for an OLED screen with 4 buttons: up, down, select and menu.

menu.cpp is generic menu code, menus.cpp the menu tables for my application and menu.h defines structures and interfaces

there are menu items to select edit strings and integer values.

start with menu() at the bottom of menu.cpp.

if anything, it shows how tedious such code can be

menu.cpp (8.36 KB)

menu.h (2.28 KB)

menus.cpp (2.88 KB)