Go Down

Topic: menubackend library submenus (Read 5103 times) previous topic - next topic

a.mlw.walker

Anyone worked out a neat way to have a second menu that is called from the first menu so that you dont have to repeat menuItems? but also be able to navigate back to the place you were in in the first menu?
i tried to adjust the library C++ file, but got in a right mess.
If anyone can help me with this I (and I think the community) would love this feature.

a.mlw.walker

Perhaps the only way is to write it out? every single one? sounds inefficient.
this must be useful for somebody?

olikraus

Hi

to my research, the author of MenuBackend has not been aktive since 4 months. Another problem is, that there are several menu libs out there. Several weeks ago, i collected some of them:

Library Name:             LCDMenu2
Download:             http://arduino.cc/forum/index.php/topic,73816.0.html

Library Name:             LCDMenu
Download:             http://arduino.cc/forum/index.php/topic,96104.0.html

Library Name:             MenuBackend
Download:             http://wiring.uniandes.edu.co/source/trunk/wiring/firmware/libraries/MenuBackend/

Library Name:             LCDMenu
Download:             http://www.metalgecko.com/arduino/LCDMenu.zip (does not exist any more)

Library Name:             Arduino_LCD_Menu
Download:             https://github.com/DavidAndrews/Arduino_LCD_Menu

Library Name:             MENWIZ
Download:             https://github.com/brunialti/MENWIZ

Library Name:             phi_prompt
Download:             http://liudr.wordpress.com/libraries/phi_prompt/

Library Name:             MenuSample
Download:             http://sourceforge.net/projects/arduinowifly/files/MenuSample/

Library Name:             M2tklib
Download:             http://code.google.com/p/m2tklib/

Not too many Arduino users add displays. And only some of them decide to use a menu lib.
Of course i would suggest to use "m2tklib" (as author of the lib ;) )
"m2tklib" can call sub menues.

Oliver

a.mlw.walker

#3
Jul 15, 2012, 08:22 pm Last Edit: Jul 15, 2012, 08:57 pm by a.mlw.walker Reason: 1
Oliver your always helpful!
Ok yeah I managed to contact him via email once a few weeks ago and he said he reckoned his library was capable of it and would write me an example, but never did, so as you have been helpful in the past, and are available :D. I am going to download your library and have a look.
Just to be clear on what Im after,
if you have one menu that has, girl, boy, man, woman and for each option you want to then choose hair colour, I dont want to have to make menu items of hair colours for each option, so i want to have a menu of hair colours that can be called from the higher level menu, but also pass the lower level menu the information, so that it knows who called it, and then be able to go back to that place in the higher menu:

girl -> brown/blonde/red -> "You chose girl with red hair"
|
boy -> brown/blonde/red -> "You chose boy with brown hair"
|
man -> brown/blonde/red -> "You chose man with blonde hair"
...

EDIT:
Any chance you might be able to give me a (pseudo) on how you would go about this using your library?

olikraus

Quote
Oliver your always helpful!

Hmm not so sure about my initial post to this thread.

Quote
Any chance you might be able to give me a (pseudo) on how you would go about this using your library?


There are several ways to implement your specification. The most flexible approach is described in tutorial 8:
http://code.google.com/p/m2tklib/wiki/t08.
Tutorial 8 is more technical, but i am sure your are able to match your specification:

"The user can select one of the PWM pins (six for the Arduino Uno)." --> "girl, boy, man, woman"
"The user can modify the output state of each pin" --> hair colours

The code itself is here:
http://code.google.com/p/m2tklib/source/browse/arduino/LiquidCrystal/PWMPinList/PWMPinList.pde

There might be other (simpler) approaches, when there is only a single option to choose. For example you can write a single callback procedure for a M2_COMBO element which can be placed several times (one for girl, boy, man, ...) on a dialog, but uses the same callback procedure for the hair colours.

Let me know if you need another example...

Oliver


a.mlw.walker

#5
Jul 16, 2012, 08:55 pm Last Edit: Jul 16, 2012, 10:40 pm by a.mlw.walker Reason: 1
Hi Oliver,
I wonder if you could pull a slightly more basic example together, Ive been studying the code from the example, but it seems like setting pwm pins is hard coded into the class?
Is there any chance you could make a simple example possibly using the girl/boy example where it calls a second menu for the hair colour. Also is there any chance you could do it using serial.println() to display the menu so it is very bare bone as it were?
i know im asking quite a lot but it would be extremely handy if you could find the time
Thanks
A

olikraus

ok, let me start with your last question:
Within the pwm example:
In line 67 replace
M2tk m2(&top_el_pin_list, m2_es_arduino, m2_eh_4bs, m2_gh_lc);
with
M2tk m2(&top_el_pin_list, m2_es_arduino_serial, m2_eh_4bs, m2_gh_arduino_serial);

This will use serial.print and you can see the menu on the serial monitor.
(hey, thats a really cool feature, isn't it...  8) )

I will answer the remaining questions in another post.

Oliver

olikraus

ok, then, here is my boy, girl,... example. Very simplified and reduced to one screen.

Code: [Select]

#include <LiquidCrystal.h>
#include "M2tk.h"
#include "m2ghlc.h"

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

uint8_t uiKeySelectPin = 10;
uint8_t uiKeyNextPin = 9;

uint8_t girl_color = 0;
uint8_t boy_color = 0;
uint8_t man_color = 0;

void fn_ok(m2_el_fnarg_p fnarg) {
  /* do something */
}

const char *fn_idx_to_color(uint8_t idx)
{
  switch(idx)
  {
    case 0: return "brown";
    case 1: return "blonde";
    case 2: return "red";
  }
  return "";
}


M2_LABEL(el_label1, NULL, "Boy:");
M2_COMBO(el_combo1, NULL, &boy_color, 3, fn_idx_to_color);

M2_LABEL(el_label2, NULL, "Girl: ");
M2_COMBO(el_combo2, NULL, &girl_color, 3, fn_idx_to_color);

M2_LABEL(el_label3, NULL, "Man: ");
M2_COMBO(el_combo3, NULL, &man_color, 3, fn_idx_to_color);

M2_BUTTON(el_ok, NULL, " ok ", fn_ok);

M2_LIST(list) = {
    &el_label1, &el_combo1,
    &el_label2, &el_combo2, 
    &el_label3, &el_combo3, 
    &el_ok
};

M2_GRIDLIST(list_element, "c2",list);
M2tk m2(&list_element, m2_es_arduino, m2_eh_4bs, m2_gh_lc);

void setup() {
  m2_SetLiquidCrystal(&lcd, 16, 4);
  m2.setPin(M2_KEY_SELECT, uiKeySelectPin);
  m2.setPin(M2_KEY_NEXT, uiKeyNextPin);
}

void loop() {
  m2.checkKey();
  if ( m2.handleKey() )
    m2.draw();
  m2.checkKey();
}


The result will be stored in the three variables:
Code: [Select]

uint8_t girl_color = 0;
uint8_t boy_color = 0;
uint8_t man_color = 0;


I am not sure if i should repeat what is written in the reference manual. Maybe you should have a look at M2_GRIDLIST, which arranges the element into a matrix and M2_COMBO which does most of the work here.
So please let me know if there is something i can explain into more detail.

Remember: You can still use the serial monitor by replacing the event handler (eh) and the graphics handler (eh) as described in my last post.

Oliver

olikraus

so, finally, here is the example with submenu:
Code: [Select]


#include <LiquidCrystal.h>
#include "M2tk.h"
#include "m2ghlc.h"

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

uint8_t uiKeySelectPin = 10;
uint8_t uiKeyNextPin = 9;

uint8_t girl_color = 0;
uint8_t boy_color = 0;
uint8_t man_color = 0;

M2_EXTERN_GRIDLIST(el_main_menu);
M2tk m2(&el_main_menu, m2_es_arduino, m2_eh_4bs, m2_gh_lc);

void fn_ok(m2_el_fnarg_p fnarg) {
  /* color changed, do something */
 
  /* then jump back to the main menu */
  m2.setRoot(&el_main_menu);
}

const char *fn_idx_to_color(uint8_t idx)
{
  switch(idx)
  {
    case 0: return "brown";
    case 1: return "blonde";
    case 2: return "red";
  }
  return "";
}

/* boy submenu */
M2_LABEL(el_label1, NULL, "Boy:");
M2_COMBO(el_combo1, NULL, &boy_color, 3, fn_idx_to_color);
M2_BUTTON(el_ok1, NULL, " ok ", fn_ok);
M2_LIST(list1) = {
    &el_label1, &el_combo1,
    &el_ok1
};
M2_GRIDLIST(el_grid1, "c2",list1);

/* girl submenu */
M2_LABEL(el_label2, NULL, "Girl:");
M2_COMBO(el_combo2, NULL, &girl_color, 3, fn_idx_to_color);
M2_BUTTON(el_ok2, NULL, " ok ", fn_ok);
M2_LIST(list2) = {
    &el_label2, &el_combo2,
    &el_ok2
};
M2_GRIDLIST(el_grid2, "c2",list2);

/* man submenu */
M2_LABEL(el_label3, NULL, "Man:");
M2_COMBO(el_combo3, NULL, &man_color, 3, fn_idx_to_color);
M2_BUTTON(el_ok3, NULL, " ok ", fn_ok);
M2_LIST(list3) = {
    &el_label3, &el_combo3,
    &el_ok3
};
M2_GRIDLIST(el_grid3, "c2",list3);

/* main menu */
M2_ROOT(el_boy_button, NULL, "Boy", &el_grid1);
M2_ROOT(el_girl_button, NULL, "Girl", &el_grid2);
M2_ROOT(el_man_button, NULL, "Man", &el_grid3);
M2_LIST(list_main_menu) = {
    &el_boy_button, 
    &el_girl_button,   
    &el_man_button, 
};
M2_GRIDLIST(el_main_menu, "c1",list_main_menu);

void setup() {
  m2_SetLiquidCrystal(&lcd, 16, 4);
  m2.setPin(M2_KEY_SELECT, uiKeySelectPin);
  m2.setPin(M2_KEY_NEXT, uiKeyNextPin);
}

void loop() {
  m2.checkKey();
  if ( m2.handleKey() )
    m2.draw();
  m2.checkKey();
}


This example defines four different menus (or dialog boxes). You can switch between these dialog boxes by using the M2_ROOT button or the m2.setRoot procedure. Calling a sub menu is nothing else than assigning a new dialog box with M2_ROOT. For the jump back to the main menu, the callback procedure of the ok button uses "m2.setRoot()".

hope this helps... again, let me know if you need more examples.

Oliver

a.mlw.walker

Great Oliver, thanks I'll give that a go.
So I can change easily to serial from you lcd, however what if I want to use a different lcd to the one in your library.
I declare my lcd here:

Code: [Select]

Adafruit_PCD8544 display = Adafruit_PCD8544(52, 51, 50, 48, 49);


So I need to replace:
Code: [Select]

m2_gh_lc

but Im not sure with what... it isnt declared anywhere else in your code, and I assume
Code: [Select]

m2_es_arduino

can stay the same if I change the lcd?
And lastly:
Code: [Select]

m2_SetLiquidCrystal(&lcd, 16, 4);
[code]
?
[/code]

olikraus

ooooohhhhhhh

To my knowledge menubackend only supports character lcds via LiquidCrystal, so i assumed, that your display is a character display. I mean, as far as i know, menubackend will also not work with the Adafruit PCD8455 lib for graphics lcd. So far M2tklib is the only menu lib which supports graphics lcds. However, m2tklib does not support the Adafruit PCD8455 library. The reason is simple: There are a large number of graphics libs out there and I can not write interfaces to all of them. Instead: M2tklib supports U8glib, which supports your PCD8455 display. So, to use m2tklib (again: which is probably the only Arduino menu lib for graphics displays) you probably need to download and use u8glib (http://code.google.com/p/u8glib/) instead of the Adafruit PCD8455 library.
Other option is to write the interface for the Adafruit lib, but this is a little bit complicated and poorly documented.

After this, you have to modify setup() and loop() procedures of the examples:
Code: [Select]


// Arduino setup procedure (called only once)
void setup() {
  // Connect u8glib with m2tklib
  m2_SetU8g(u8g.getU8g(), m2_u8g_box_icon);

  // Assign u8g font to index 0
  m2.setFont(0, u8g_font_7x13);

  // Setup keys
  m2.setPin(M2_KEY_SELECT, uiKeySelectPin);
  m2.setPin(M2_KEY_NEXT, uiKeyDownPin);
}

// Arduino loop procedure
void loop() {
  m2.checkKey();
  if ( m2.handleKey() ) {
    u8g.firstPage(); 
    do {
      draw();
    } while( u8g.nextPage() );
  }
}


See also the tutorial here:
http://code.google.com/p/m2tklib/wiki/t02u8g

And the reference page for the u8glib binding for m2tklib:
http://code.google.com/p/m2tklib/wiki/u8gref

And finally, you need to choose a font for your display from here:
http://code.google.com/p/u8glib/wiki/fontsize

well... let me conclude this:

- you own a graphics display
- m2tklib supports graphics libs
- m2tklib does not support the specific Adafruit GFX lib
- m2tklib supports PCD8455 based displays via u8glib

Oliver 

a.mlw.walker

#11
Jul 17, 2012, 12:01 am Last Edit: Jul 17, 2012, 12:04 am by a.mlw.walker Reason: 1
Haha! Oliver you are monopolizing the graphic lcd/menu industry with your libraries!
OK so I am using the nokia 5510 display from sparkfun, and you say that your u8_glib library supports that, then I have no issue using your library if it will work with your menu system. I have used menuBackend with that adafruit library, so it does seem to support it - I was doing it like this:
Code: [Select]

void menuChangeEvent(MenuChangeEvent changed)
{
 char string[30];
 string[0] = '\0';
 strcat(string, ">");
 strcat(string, changed.to.getLeft()->getName());
 strcat(string, ">");
 strcat(string, changed.to.getName());
 display.clearDisplay();   // clears the screen and buffer
 display.setCursor(0,0);
 display.println(string);
 display.display();

}

However thats just for info... I thought there may have been an equivelent for your menu library, but not bothered to use yours, because yours supports using a sub menu system.
i already have u8_glib downloaded and in my set of libraries, so I will set up my lcd to work with u8_glib then and then try out your boy/girl example.
In terms of that then, if I take your girl/boy example and adjust it to your newest setup()/loop() functions then it should work for my lcd...?

To initialize the lcd with u8_glib, the only line I can see that is close is:
Code: [Select]

U8GLIB_PCD8544 u8g(13, 11, 10, 9, 8);                    // SPI Com: SCK = 13, MOSI = 11, CS = 10, A0 = 9, Reset = 8

which seems like the right one, so i just change the pin numbers, use your setup/loop and bingo, I can see how your boy/girl example works... I'll get on with that then
Cheers
A

EDIT:
I notice you use .checkKey() to see if one of the two buttons has been pressed, can I use a potentiometer/rotary encoder to go up and down, rather than a button?

olikraus

#12
Jul 17, 2012, 12:20 am Last Edit: Jul 17, 2012, 12:26 am by olikraus Reason: 1
Quote

To initialize the lcd with u8_glib, the only line I can see that is close is:
Code:
Code: [Select]
U8GLIB_PCD8544 u8g(13, 11, 10, 9, 8);                    // SPI Com: SCK = 13, MOSI = 11, CS = 10, A0 = 9, Reset = 8

which seems like the right one, so i just change the pin numbers, use your setup/loop and bingo, I can see how your boy/girl example works...

Yes, ... hopefully

Quote
I notice you use .checkKey() to see if one of the two buttons has been pressed, can I use a potentiometer/rotary encoder to go up and down, rather than a button?

checkKey() calls an event source, which could analyse digital pins or a rotary encoder. However, I have not yet written the event source for a rotary encoder, but i added an enhancement request on the m2tklib project.

Oliver

Edit: Ensure to use m2tklib for u8glib. Also delete any other version before installing m2tklib for u8glib.


dannix


Hi

to my research, the author of MenuBackend has not been aktive since 4 months. Another problem is, that there are several menu libs out there. Several weeks ago, i collected some of them:

Library Name:             LCDMenu2
Download:             http://arduino.cc/forum/index.php/topic,73816.0.html

Library Name:             LCDMenu
Download:             http://arduino.cc/forum/index.php/topic,96104.0.html

Library Name:             MenuBackend
Download:             http://wiring.uniandes.edu.co/source/trunk/wiring/firmware/libraries/MenuBackend/

Library Name:             LCDMenu
Download:             http://www.metalgecko.com/arduino/LCDMenu.zip (does not exist any more)

Library Name:             Arduino_LCD_Menu
Download:             https://github.com/DavidAndrews/Arduino_LCD_Menu

Library Name:             MENWIZ
Download:             https://github.com/brunialti/MENWIZ

Library Name:             phi_prompt
Download:             http://liudr.wordpress.com/libraries/phi_prompt/

Library Name:             MenuSample
Download:             http://sourceforge.net/projects/arduinowifly/files/MenuSample/

Library Name:             M2tklib
Download:             http://code.google.com/p/m2tklib/

Not too many Arduino users add displays. And only some of them decide to use a menu lib.
Of course i would suggest to use "m2tklib" (as author of the lib ;) )
"m2tklib" can call sub menues.

Oliver



Wish I had this before I started out with menubackend!

Anyway in case it's of use I have created a menu using menubackend, not without problems using menubackend getBefore() in fact all getX() option won't compile but I did create a menu like so:

CONFIGURE (0)
        CONFIG HEATER (1)
                   HEATER ON (2)
                   HEATER OFF (2)
                   HEATER DISABLE (2)
                   EXIT (2)
        EXIT (1)
EXIT (0)

My problem was telling it to MoveToLevel(0) when I wanted to reset the position in the menu but it resets the board so I wrote a while loop to work it's wya back testing each element for an up or left option, if left that's leaving a submenu if up cycling through the current menus options. I link the 1st to the last menu element to create a loop.

Link is: http://arduino.cc/forum/index.php/topic,113673.msg858072.html#msg858072


a.mlw.walker

#14
Jul 17, 2012, 08:53 pm Last Edit: Jul 17, 2012, 08:59 pm by a.mlw.walker Reason: 1
Oliver, does this line need replacing for u8_glib?
Code: [Select]

M2tk m2(&el_main_menu, m2_es_arduino, m2_eh_4bs, m2_gh_lc);

I have my program like this, and I downloaded the latest library for m2 with u8_glib, but I get an error
Code: [Select]

#include "M2tk.h"
#include "m2ghu8g.h"
#include "U8glib.h"
U8GLIB_PCD8544 u8g(13, 11, 10, 9, 8);                    // SPI Com: SCK = 13, MOSI = 11, CS = 10, A0 = 9, Reset = 8
//Adafruit_PCD8544 display = Adafruit_PCD8544(52, 51, 50, 48, 49);

uint8_t uiKeySelectPin = 10;
uint8_t uiKeyNextPin = 9;

uint8_t girl_color = 0;
uint8_t boy_color = 0;
uint8_t man_color = 0;

M2_EXTERN_GRIDLIST(el_main_menu);
M2tk m2(&el_main_menu, m2_es_arduino, m2_eh_4bs, m2_gh_u8g_bf);

void fn_ok(m2_el_fnarg_p fnarg) {
  /* color changed, do something */
 
  /* then jump back to the main menu */
  m2.setRoot(&el_main_menu);
}

const char *fn_idx_to_color(uint8_t idx)
{
  switch(idx)
  {
    case 0: return "brown";
    case 1: return "blonde";
    case 2: return "red";
  }
  return "";
}

/* boy submenu */
M2_LABEL(el_label1, NULL, "Boy:");
M2_COMBO(el_combo1, NULL, &boy_color, 3, fn_idx_to_color);
M2_BUTTON(el_ok1, NULL, " ok ", fn_ok);
M2_LIST(list1) = {
    &el_label1, &el_combo1,
    &el_ok1
};
M2_GRIDLIST(el_grid1, "c2",list1);

/* girl submenu */
M2_LABEL(el_label2, NULL, "Girl:");
M2_COMBO(el_combo2, NULL, &girl_color, 3, fn_idx_to_color);
M2_BUTTON(el_ok2, NULL, " ok ", fn_ok);
M2_LIST(list2) = {
    &el_label2, &el_combo2,
    &el_ok2
};
M2_GRIDLIST(el_grid2, "c2",list2);

/* man submenu */
M2_LABEL(el_label3, NULL, "Man:");
M2_COMBO(el_combo3, NULL, &man_color, 3, fn_idx_to_color);
M2_BUTTON(el_ok3, NULL, " ok ", fn_ok);
M2_LIST(list3) = {
    &el_label3, &el_combo3,
    &el_ok3
};
M2_GRIDLIST(el_grid3, "c2",list3);

/* main menu */
M2_ROOT(el_boy_button, NULL, "Boy", &el_grid1);
M2_ROOT(el_girl_button, NULL, "Girl", &el_grid2);
M2_ROOT(el_man_button, NULL, "Man", &el_grid3);
M2_LIST(list_main_menu) = {
    &el_boy_button, 
    &el_girl_button,   
    &el_man_button, 
};
M2_GRIDLIST(el_main_menu, "c1",list_main_menu);

// Arduino setup procedure (called only once)
void setup() {
  // Connect u8glib with m2tklib
  m2_SetU8g(u8g.getU8g(), m2_u8g_box_icon);

  // Assign u8g font to index 0
  m2.setFont(0, u8g_font_7x13);

  // Setup keys
  m2.setPin(M2_KEY_SELECT, uiKeySelectPin);
  m2.setPin(M2_KEY_NEXT, uiKeyDownPin);
}

// Arduino loop procedure
void loop() {
  m2.checkKey();
  if ( m2.handleKey() ) {
    u8g.firstPage(); 
    do {
      draw();
    } while( u8g.nextPage() );
  }
}


sketch_jul17a.cpp:2:21: error: m2ghu8g.h: No such file or directory
sketch_jul17a:14: error: 'm2_gh_u8g_bf' was not declared in this scope
sketch_jul17a.cpp: In function 'void setup()':
sketch_jul17a:78: error: 'm2_u8g_box_icon' was not declared in this scope
sketch_jul17a:78: error: 'm2_SetU8g' was not declared in this scope
sketch_jul17a:85: error: 'uiKeyDownPin' was not declared in this scope
sketch_jul17a.cpp: In function 'void loop()':
sketch_jul17a:94: error: 'draw' was not declared in this scope

i.e i dont think it can find the libraries?

Go Up