I was able to get it going, although I wonder about its efficiency. Thanks to all who responded. Here’s the code:
Menu.h
/*
Menu.h - Library for creating nested Menus with callback functions
Original Author: CWAL
License: Just leave this header, do anything else with it you want
*/
#ifndef Menu_h
#define Menu_h
//This is for arduino 0022,23 - 1.0 compatibility.
#if defined(ARDUINO) && ARDUINO >= 100
#include <Arduino.h>
#else
#include <WProgram.h>
#endif
class Menu
{
private:
Menu * parent;//Parent Menu, NULL if this is the top
Menu * child;//First Child Menu, NULL if no children
Menu * sibling;//Next Sibling Menu, NULL if this is the last sibling
void setParent(Menu &p);//Sets the Menu's Parent to p
void addSibling(Menu &s,Menu &p);//Adds a Sibling s with Parent p. If the Menu already has a sibling, ask that sibling to add it
public:
char * name;//Name of this Menu
Menu(const prog_char *n);//Constructs the Menu with a name and a NULL use function (be careful calling it)
Menu(const prog_char *n, boolean (*c)(Menu&));//Constructs the Menu with a specified use function
boolean (*canEnter)(Menu&);//Function to be called when this menu is 'used'
void addChild(Menu &c);//Adds the child c to the Menu. If the menu already has a child, ask the child to add it as a sibling
boolean ChildExists();//Returns state of a child menu in current item
Menu * getChild(int which);//Returns a pointer to the which'th child of this Menu
Menu * getSibling(int howfar);//Returns a pointer to the sibling howfar siblings away from this Menu
Menu * getParent();//Returns this Menu's parent Menu. If no parent, returns itself
};
#endif //Menu_h
Menu.cpp
/*
Menu.cpp - Library for creating nested Menus with callback functions
Original Author: CWAL
License: Just leave this header, do anything else with it you want
*/
#include "Menu.h"
#include <WString.h> // uses enhanced wstring that supports progmem 01.23.12
void Menu::setParent(Menu &p)
{
parent=&p;
}
void Menu::addSibling(Menu &s,Menu &p)
{
if (sibling)
{
sibling->addSibling(s,p);
} else {
sibling=&s;
sibling->setParent(p);
}
}
Menu::Menu(const prog_char *n)
{
name = (char *)realloc(name, strlen_P(n)+1);
strcpy_P(name, n);
canEnter=NULL;
}
Menu::Menu(const prog_char *n, boolean (*c)(Menu&))
{
name = (char *)realloc(name, strlen_P(n)+1);
strcpy_P(name, n);
canEnter=c;
}
void Menu::addChild(Menu &c)
{
if (child)
{
child->addSibling(c,*this);
} else {
child=&c;
child->setParent(*this);
}
}
boolean Menu::ChildExists()
{
if (child)
{
return true;
}
else
{
return false;
}
}
Menu * Menu::getChild(int which)
{
if (child)
{
return child->getSibling(which);
} else {
// this Menu item has no children
return NULL;
}
}
Menu * Menu::getSibling(int howfar)
{
if (howfar==0)
{
return this;
} else if (sibling)
{
return sibling->getSibling(howfar-1);
} else //Asking for a nonexistent sibling
{
return NULL;
}
}
Menu * Menu::getParent()
{
if (parent)
{
return parent;
} else // top Menu
{
return this;
}
}
LCDMenu2.h + LCDMenu2.cpp stay the same.
Here are helper functions for dealing with menu items:
boolean CompareStringToPROGMEMstring(char * str, const prog_char * pgm)
{
char * a;
// allocate the buffer to the same size as the progmem string
a = (char *)realloc(a, strlen_P(pgm)+1);
// copy from progmem
strcpy_P(a, pgm);
// compare the string against the copied progmem string
if (strcmp(str,a)==0)
return true;
else
return false;
}
uint8_t GetPROGMEMbyte(const prog_char * pgm, uint8_t pos)
{
char * a;
// allocate the buffer to the same size as the progmem string
a = (char *)realloc(a, strlen_P(pgm)+1);
// copy from progmem
strcpy_P(a, pgm);
// return the byte at position
return a[pos];
}