Go Down

Topic: MenuBackend, new menu managment library (Read 92003 times) previous topic - next topic


maybe Exit is not a right name, moveleft maybe. And if it has no left connection move to most top one and then move left.



Hello I'm new to arduino and i would like to know is there a code for selecting menu with the thumb joystick like the one on sparkfun. Thank you!


Nice effort.... Bad that i only bumped into this thread accidentally after programming some complex menus the hard way :(


The latest source-post at pastebin for v 1.2 is not valid any more. Can someone post the code here at arduino forum please. Thx!


I've actually lost the sources myself, but I'll have a look in my backups and get back to you.



Is there someone who can post version 1.2?

I must agree with vysocan, the moveBack() for exiting from current level is useless. Also I would be very careful with recursive search within few kB of RAM.

Anyway this approach is very good and useful.


I'll try to remember to look when I get home, I don't recall what version I got last.  Its not on my usb stick here at work.


Sep 09, 2010, 11:42 am Last Edit: Sep 09, 2010, 05:08 pm by arian Reason: 1

Here is modified version 1.1.

I believe it contains more usable solution for exiting from menu levels. It was achieved just by setting back pointer during initialization of the MenuItem class and propagation of this pointer for items added later into the chain (only if they don't have back pointer specified). I also remove those chunks of code which was in my opinion useless or oversized.

For example, now if you want to have getBack method working in the proper way, the initialization should looks like this:

Code: [Select]

MenuItem miFile = MenuItem("File",&menu.getRoot());
           MenuItem miNew = MenuItem("New");
           MenuItem miOpen = MenuItem("Open");
           MenuItem miExamples = MenuItem("Examples");
                 MenuItem miArduinoISP = MenuItem("ArduinoISP",&miNew);

Where hitting back on item "ArduinoISP" will restore the current position to item "New", which is the first item for submenu "File". I think this kind of behavior is more suitable for LCD screens.

Code: [Select]

|| @file MenuBackend.h
|| @version 1.1-lite
|| @author Alexander Brevig
|| @contact alexanderbrevig@gmail.com
|| @note some minor changes Adrian Brzezinski adrb@wp.pl
|| @description
|| | Provide an easy way of making menus
|| #
|| @license
|| | This library is free software; you can redistribute it and/or
|| | modify it under the terms of the GNU Lesser General Public
|| | License as published by the Free Software Foundation; version
|| | 2.1 of the License.
|| |
|| | This library is distributed in the hope that it will be useful,
|| | but WITHOUT ANY WARRANTY; without even the implied warranty of
|| | Lesser General Public License for more details.
|| |
|| | You should have received a copy of the GNU Lesser General Public
|| | License along with this library; if not, write to the Free Software
|| | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
|| #

#ifndef MenuBackend_h
#define MenuBackend_h

class MenuItem {

     MenuItem(const char* itemName, MenuItem *backpoint=0 ) : name(itemName), back(backpoint) {
           before = 0;
           right = 0;
           after = 0;
           left = 0;

     const char* getName() const { return name; }
     MenuItem* getBack() { return back; }
     MenuItem* getBefore() { return before; }
     MenuItem* getRight() { return right; }
     MenuItem* getAfter() { return after; }
     MenuItem* getLeft() { return left; }

     MenuItem* moveUp() { return before; }
     MenuItem* moveDown() { return after; }
     MenuItem* moveLeft() { return left; }
     MenuItem* moveRight() { return right; }

     //default vertical menu
     MenuItem &add(MenuItem &mi) { return addAfter(mi); }

     MenuItem &addBefore(MenuItem &mi) {
           mi.after = this;
           before = &mi;
           if ( !mi.back ) mi.back = back;
           return mi;
     MenuItem &addRight(MenuItem &mi) {
           mi.left = this;
           right = &mi;
           if ( !mi.back ) mi.back = back;
           return mi;
     MenuItem &addAfter(MenuItem &mi) {
           mi.before = this;
           after = &mi;
           if ( !mi.back ) mi.back = back;
           return mi;
     MenuItem &addLeft(MenuItem &mi) {
           mi.right = this;
           left = &mi;
           if ( !mi.back ) mi.back = back;
           return mi;

     const char* name;

     MenuItem *before;
     MenuItem *right;
     MenuItem *after;
     MenuItem *left;
     MenuItem *back;

//no dependant inclusion of string or cstring
bool menuTestStrings(const char *a, const char *b) {
     while (*a) { if (*a != *b) { return false; } b++; a++; }
     return true;
bool operator==(MenuItem &lhs, char* test) {
     return menuTestStrings(lhs.getName(),test);
bool operator==(const MenuItem &lhs, char* test) {
     return menuTestStrings(lhs.getName(),test);
bool operator==(MenuItem &lhs, MenuItem &rhs) {
     return menuTestStrings(lhs.getName(),rhs.getName());
bool operator==(const MenuItem &lhs, MenuItem &rhs) {
     return menuTestStrings(lhs.getName(),rhs.getName());

struct MenuChangeEvent {
     const MenuItem &from;
     const MenuItem &to;

struct MenuUseEvent {
     const MenuItem &item;

typedef void (*cb_change)(MenuChangeEvent);
typedef void (*cb_use)(MenuUseEvent);

class MenuBackend {

     MenuBackend(cb_use menuUse, cb_change menuChange = 0) : root("MenuRoot") {
           current = &root;
           cb_menuChange = menuChange;
           cb_menuUse = menuUse;

     MenuItem &getRoot() {
           return root;
     MenuItem &getCurrent() {
           return *current;

     void moveBack() {

     void moveUp() {

     void moveDown() {

     void moveLeft() {

     void moveRight() {

     void use() {
           if (cb_menuUse) {
                 MenuUseEvent mue = { *current };

     void setCurrent( MenuItem *next ) {
           if (!next) return;

           if (cb_menuChange) {
                 MenuChangeEvent mce = { *current, *next };

           current = next;

     MenuItem root;
     MenuItem *current;

     cb_change cb_menuChange;
     cb_use cb_menuUse;


Actually there was some small bug, which i have just fixed.


Sep 09, 2010, 03:21 pm Last Edit: Sep 10, 2010, 03:25 am by AlphaBeta Reason: 1
Looks good :)


Sorry I failed, I only have a 1.0 maybe its 1.1.  But I see thats alreayd posted again.  So thats good.


I've started to do some work on this library again.

I will post a new version within a weeks time (I am in the middle of writing a paper for my masters and I am busy busy busy).


Nov 19, 2010, 03:35 am Last Edit: Nov 19, 2010, 08:45 pm by Kulty Reason: 1
Wow, I've been looking for something like this for a while now, looks quite impressive!

Question: Was the MenuBackend example code specifically written for serial LCD's? If yes, how could one go about making it work with 4bit/8bit controlled 44780's LCDisplays?



is 1.0 the latest version to use or is there a getter one I saw 1.1 and 1.2 but the links are dead

Go Up