Need some feedback

by patrikk on Sat May 04, 2013 3:00 pm

Hi everyone,
I've been working on a menu lib to be able to to traverse through a menu on the LCD.
the structure is similar to the tree structure you have in explorer etc.

My problem is that I cant get it to work perfectly. in the code I've posted here I can step through the menu up and down( submenu) and into menu "item2" but I can't do that with the first item (item1) instead it jumps to item3 and not to the "item1 submenu" what am I missing?

the second thing is that when I enter a submenu( submenu for item 2) I end up at the last submenuitem and not the first one. I can't figure out why it does that I would like it to go to the first subitem ( firstChild).

components:
Arduino Uno
adafruit 16x2 LCD negative with the I2C chip and buttons.

I appreciate all the help

library for the menu:

Code: Select all
/*LcdMenu library*/
#ifndef   LcdMenu_h
#define LcdMenu_h


class MenuItem {
public:
   MenuItem(const char* itemName, char shortKey='\0' ) : name(itemName), shortkey(shortKey) {
      parent = prevSibling = nextSibling = firstChild = 0;
   }

   inline const char* getName() const { return name; }
   inline const char getShortkey() const { return shortkey; }
   inline const bool hasShortkey() const { return (shortkey!='\0'); }
   inline void setBack(MenuItem *b) { parent = b; }

   inline MenuItem* getParent() const { return parent; }
   inline MenuItem* getPrevSibling() const { return prevSibling; }
   inline MenuItem* getNextSibling() const { return nextSibling; }
   inline MenuItem* getFirstChild() const { return firstChild; }
   
   
   MenuItem *moveBack() { return parent; }

   MenuItem *moveUp() {
      return prevSibling;
   }

   MenuItem *moveDown() {
       return nextSibling;
   }

   MenuItem *moveLeft() {
      return parent;
   }

   MenuItem *moveRight() {
      return firstChild;
   }

   //default menu

   MenuItem &setParent(MenuItem &mi) {
      mi.firstChild = this;
      parent = &mi;
      return mi;
   }
   
   MenuItem &setPrevSibling(MenuItem &mi) {
      mi.nextSibling = this;
      prevSibling = &mi;
      return mi;
   }
   
   MenuItem &setNextSibling(MenuItem &mi) {
      mi.prevSibling = this;
      nextSibling = &mi;
      return mi;
   }
   
   MenuItem &setFirstChild(MenuItem &mi) {
      mi.parent = this;
      firstChild = &mi;
      return mi;
   }
   
   
protected:

   const char* name;
   const char shortkey;

   MenuItem *parent;
   MenuItem *prevSibling;
   MenuItem *nextSibling;
   MenuItem *firstChild;
   
};

//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==(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   LcdMenu {
public:

       LcdMenu(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() {
      setCurrent(current->getParent());
   }

   void moveUp() {
      setCurrent(current->moveUp());
   }

   void moveDown() {
      setCurrent(current->moveDown());
   }

   void moveLeft() {
      setCurrent(current->moveLeft());
   }

   void moveRight() {
      setCurrent(current->moveRight());
   }

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

private:
   void setCurrent( MenuItem *next ) {
      if (next) {
         if (cb_menuChange) {
            MenuChangeEvent mce = { *current, *next };
            (*cb_menuChange)(mce);
         }
         current = next;
      }
   }
   MenuItem root;
   MenuItem *current;

   cb_change cb_menuChange;
   cb_use cb_menuUse;
};

#endif


and then the project code:

Code: Select all
#include <LcdMenu.h>    //LcdMenu library
#include <Wire.h>
#include <Adafruit_MCP23017.h>
#include <Adafruit_RGBLCDShield.h>

Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();

// These #defines make it easy to set the backlight color
#define RED 0x1
#define GREEN 0x2
#define YELLOW 0x3
#define BLUE 0x4
#define VIOLET 0x5
#define TEAL 0x6
#define WHITE 0x7


//Menu variables
LcdMenu menu = LcdMenu(menuUsed,menuChanged);
//initialize menuitems
    MenuItem menu1Item1 = MenuItem("Item1");
      MenuItem menuItem1SubItem1 = MenuItem("Item1SubItem1");
      MenuItem menuItem1SubItem2 = MenuItem("Item1SubItem2");
    MenuItem menu1Item2 = MenuItem("Item2");
      MenuItem menuItem2SubItem1 = MenuItem("Item2SubItem1");
      MenuItem menuItem2SubItem2 = MenuItem("Item2SubItem2");
      MenuItem menuItem2SubItem3 = MenuItem("Item2SubItem3");
    MenuItem menu1Item3 = MenuItem("Item3");


void setup()
{
  lcd.begin(16, 2);

  menu.getRoot().setNextSibling(menu1Item1);
  menu1Item1.setPrevSibling(menu1Item3);
  menu1Item1.setNextSibling(menu1Item2);
  menu1Item1.setFirstChild(menuItem1SubItem1);
    menuItem1SubItem1.setParent(menu1Item1);
    menuItem1SubItem1.setNextSibling(menuItem1SubItem2);
    menuItem1SubItem1.setPrevSibling(menuItem1SubItem2);
   
    menuItem1SubItem2.setPrevSibling(menuItem1SubItem1);
    menuItem1SubItem2.setNextSibling(menuItem1SubItem1);
    menuItem1SubItem2.setParent(menu1Item1);
   
 
 
  menu1Item2.setPrevSibling(menu1Item1);
  menu1Item2.setNextSibling(menu1Item3);
  menu1Item2.setFirstChild(menuItem2SubItem1);
    menuItem2SubItem1.setParent(menu1Item2);
    menuItem2SubItem1.setNextSibling(menuItem2SubItem2);
    menuItem2SubItem1.setPrevSibling(menuItem2SubItem3);
   
    menuItem2SubItem2.setPrevSibling(menuItem2SubItem1);
    menuItem2SubItem2.setNextSibling(menuItem2SubItem3);
    menuItem2SubItem2.setParent(menu1Item2);
   
    menuItem2SubItem3.setNextSibling(menuItem2SubItem1);
    menuItem2SubItem3.setParent(menu1Item2);
 
  menu1Item3.setParent(menu1Item1);
  menu1Item3.setPrevSibling(menu1Item2);
  menu1Item3.setNextSibling(menu1Item1);

    //menu1Item1.setPrevSibling(menu1Item3);

  //menu1Item3.setNextSibling(menu.getRoot());
  //menu1Item3.setNextSibling(menu.getRoot());
  //menu.toRoot();
  lcd.setCursor(0,0); 
  lcd.print("Main Menu");

}  // setup()...


void loop()
{

  readButtons();                 
} //loop()...


void menuChanged(MenuChangeEvent changed){
 
  MenuItem newMenuItem=changed.to; //get the destination menu
 
  lcd.setCursor(0,1); //set the start position for lcd printing to the second row
 
  if(newMenuItem.getName()==menu.getRoot()){
      lcd.print("Main Menu       ");
  }else if(newMenuItem.getName()=="Item1"){
      lcd.print("Item1           ");
  }else if(newMenuItem.getName()=="Item1SubItem1"){
      lcd.setCursor(0,0);
      lcd.print("--- Item1 ---");
      lcd.setCursor(0,1);
      lcd.print("Item1SubItem1");
  }else if(newMenuItem.getName()=="Item1SubItem2"){
      lcd.print("Item1SubItem2   ");
  }else if(newMenuItem.getName()=="Item2"){
    lcd.setCursor(0,0);
      lcd.print("   Main Menu    ");
      lcd.setCursor(0,1);
      lcd.print("Item2           ");
  }else if(newMenuItem.getName()=="Item2SubItem1"){
      lcd.setCursor(0,0);
      lcd.print("--- Item2 ---");
      lcd.setCursor(0,1);
      lcd.print("Item2SubItem1   ");
  }else if(newMenuItem.getName()=="Item2SubItem2"){
    lcd.setCursor(0,0);
      lcd.print("--- Item2 ---");
      lcd.setCursor(0,1);
      lcd.print("Item2SubItem2   ");
  }else if(newMenuItem.getName()=="Item2SubItem3"){
    lcd.setCursor(0,0);
      lcd.print("--- Item2 ---");
      lcd.setCursor(0,1);
      lcd.print("Item2SubItem3   ");
  }else if(newMenuItem.getName()=="Item3"){
      lcd.print("Item3           ");

  }
}

void menuUsed(MenuUseEvent used){
  lcd.setCursor(0,0); 
  lcd.print("You used        ");
  lcd.setCursor(0,1);
  lcd.print(used.item.getName());
  delay(1000);  //delay to allow message reading

  //menu.toRoot();  //back to Main
}


void  readButtons(){
  int reading;

uint8_t buttons = lcd.readButtons();
  if (buttons) {
    MenuItem currentMenu=menu.getCurrent();
    if (buttons & BUTTON_UP) {
      menu.moveUp();
      delay(500);
      lcd.setBacklight(RED);
    }
    if (buttons & BUTTON_DOWN) {
      menu.moveDown();
      delay(500);
      lcd.setBacklight(YELLOW);
    }
    if (buttons & BUTTON_LEFT) {
        menu.moveLeft();
        delay(500);
      lcd.setBacklight(GREEN);
    }
    if (buttons & BUTTON_RIGHT) {
       menu.moveRight();
       delay(500);
       lcd.setBacklight(TEAL);
    }
    if (buttons & BUTTON_SELECT) {
      if(!(currentMenu.moveRight())){  //if the current menu has a child and has been pressed enter then menu navigate to item below
        menu.use();
        delay(500);
      }else{  //otherwise, if menu has no child and has been pressed enter the current menu is used
        menu.moveRight();
        delay(500);
       }
      lcd.setBacklight(VIOLET);
    }
  }
}
patrikk
 
Posts: 31
Joined: Sun Feb 17, 2013 5:13 pm

Re: Need some feedback

by patrikk on Thu May 09, 2013 2:49 am

bump
patrikk
 
Posts: 31
Joined: Sun Feb 17, 2013 5:13 pm

Re: Need some feedback

by adafruit_support_mike on Thu May 09, 2013 7:49 pm

The library looks generally okay, but you haven't posted the code that actually creates and navigates the menu. It's possible that you have some confusion between "up/down mean siblings" and "left/right mean parent/child".
When you void a product warranty, you give up your right to sue the manufacturer if something goes wrong and accept full responsibility for whatever happens next. And then you truly own the product.
User avatar
adafruit_support_mike
 
Posts: 7201
Joined: Thu Feb 11, 2010 1:51 pm

Re: Need some feedback

by saltydog on Sun Aug 04, 2013 12:18 am

Hi Pat,

was wondering if you had this figured out yet with the menu system for the shield.
saltydog
 
Posts: 10
Joined: Mon Aug 22, 2011 9:38 am