Go Down

Topic: New Arduino library: MenuSystem (Read 10360 times) previous topic - next topic

jonblack

May 14, 2012, 09:41 pm Last Edit: Dec 20, 2013, 01:26 pm by jonblack Reason: 1
I've written an Arduino library for creating a nested menu system....and I called it MenuSystem (how original!). I wanted to share it with the World. Feedback and suggestions welcome (preferably on my blog, but that's up to you).

Tutorial: http://jonblack.org/2012/05/14/arduino-library-for-creating-a-menu-system/
Source Code: https://github.com/jonblack/arduino-menusystem

arcachofo

I was just starting to write a project that needs a menu when i saw your post... :-) , i'll give it a try.

Thanks for sharing.

jonblack

Good to hear :) If you have any questions, let me know. Good luck!

olikraus

Hi

How do i display the menu? Is it intended to show the menu tree somewhere?

Oliver

jonblack

Think of MenuSystem as a container for your menu system, holding the structure, current items, and callbacks. So, it won't display anything for you. What it does provide are three functions:


  • ms.get_current_menu_name(); // get the current menu name

  • ms.get_num_menu_items(); // get the number of menu items in the current menu

  • ms.get_cur_menu_item(); // get the current menu item number in the current menu



The first one is probably all you need. This returns the current menu name. Every time you call back(), next(), prev(), select() this will change. The other two functions return the current menu item number and total number of items in the current menu level. These are useful if you want to implement some kind of pagination.

Does that answer your question?


Hi

How do i display the menu? Is it intended to show the menu tree somewhere?

Oliver

olikraus

So this means, I need to write a procedure which renders the menu on an output device. This procedure also has to take care to highlight the "current" menu item, correct?

Thanks for clarification,
Oliver



jonblack


So this means, I need to write a procedure which renders the menu on an output device. This procedure also has to take care to highlight the "current" menu item, correct?

Thanks for clarification,
Oliver


Yes, you need to render the menu to a device. Bear in mind that this library manages which item is current for you, and that is the only item you should display. This means that you can only show one option on your output device at a time. If you want to display all menu items and highlight the current one, this library isn't for you. I've written some pseudo-code below to explain this, I hope it makes sense:


def process_input():
  if next_button_pressed:
    menusystem.next()
  else if prev_button_pressed:
    menusystem.prev()
  else if select_button_pressed:
    menusystem.select()
  else if back_button_pressed:
    menusystem.back()

def update_menu():
  current_item_text = menusystem.get_current_menu_name()
  output_device.write(current_item_text)

def loop():
  process_input()
  update_menu()

olikraus

ok, now I understand.

Thanks
Oliver

arcachofo

To manage the menu tree i added a function to Menu class:

Code: [Select]
MenuComponent* Menu::get_item( int num )
{
    return _menu_components[num];
}


And print items this way for example:

Code: [Select]

MenuComponent* selected = mm.get_selected();

for( int i=0; i<mm.get_num_menu_items(); i++ )
{
MenuComponent* item = mm.get_item( i );
gotoXY( 0, i );
if( item == selected ) LCDString( ">");
else                   LCDString( " ");
LCDString( item->get_name() );
}



By now i just have tested some basic things of the library and it is working very well.




avenue33

When I developed my menu class, I faced two difficulties: displaying the menu and defining the options.

Here's there result:


A menu is declared this way:
Code: [Select]
// menu declaration and size
item myMenuItems[] = {
  {     0x0000, "Menu 0"        }  ,   
  {     0x1000, "Item 1"        }  ,
  {     0x1100, "Item 11"       }  ,
  {     0x1200, "Item 12"       }  ,
  {     0x2000, "Item 2"        }  ,
  {     0x2100, "Item 21"       }  ,
  {     0x2110, "Item 211"      }  ,
  {     0x2120, "Item 212"      }  ,
  {     0x2121, "Item 2121"     }  ,
  {     0x2122, "Item 2122"     }  ,
  {     0x2200, "Item 22"       }  ,
  {     0x2300, "Item 23"       }  ,
  {     0x3000, "Item 3"        }
};


Learn more about the menu and the Serial_LCD library suite  :)

arcachofo

Not sure if this is possible without doing changes, but i needed another function in MesuSystem class:

Code: [Select]

Menu* MenuSystem::get_current_menu()
{
    return _p_curr_menu;
}


And i print the current menu at it's items this way:
Code: [Select]

void updateMenu()
{
LCDClear();

Menu* currentMenu = menu_system.get_current_menu();

MenuComponent* selected = currentMenu->get_selected();

LCDString( currentMenu->get_name() ); // Displays current menu

for( int i=0; i<currentMenu->get_num_menu_items(); i++ )
{
MenuComponent* item = currentMenu->get_item( i );

gotoXY(  5, i+1 );

if( item == selected ) LCDString( ">"); // Displays an arrow in current item
else                   LCDString( " ");

LCDString( item->get_name() ); // Displays items in current menu
}
}


I see more ineresting have getter: MenuSystem::get_current_menu() intead of MenuSystem::get_current_menu_name(), with the first i can access to anything i need in the current menu, not only name.

jonblack

Not entirely sure how this is relevant to the MenuSystem I've created. Looks to me like a shameless plug!


When I developed my menu class, I faced two difficulties: displaying the menu and defining the options.

A menu is declared this way:
Code: [Select]
// menu declaration and size
item myMenuItems[] = {
  {     0x0000, "Menu 0"        }  ,   
  {     0x1000, "Item 1"        }  ,
  {     0x1100, "Item 11"       }  ,
  {     0x1200, "Item 12"       }  ,
  {     0x2000, "Item 2"        }  ,
  {     0x2100, "Item 21"       }  ,
  {     0x2110, "Item 211"      }  ,
  {     0x2120, "Item 212"      }  ,
  {     0x2121, "Item 2121"     }  ,
  {     0x2122, "Item 2122"     }  ,
  {     0x2200, "Item 22"       }  ,
  {     0x2300, "Item 23"       }  ,
  {     0x3000, "Item 3"        }
};


Learn more about the menu and the Serial_LCD library suite  :)

jonblack

Looks interesting. I'll test it and see if it fits well with the original design. It's nice that you can display multiple items and show the highlighted one, what I don't like is having to iterate over the menu components outside of the library - those should stay internal.

Perhaps a function in the menu system like so would be better:

char** MenuSystem::get_current_menu_options();

This will return an array of the menu options for the current menu. What do you think?


Not sure if this is possible without doing changes, but i needed another function in MesuSystem class:

....

I see more ineresting have getter: MenuSystem::get_current_menu() intead of MenuSystem::get_current_menu_name(), with the first i can access to anything i need in the current menu, not only name.


arcachofo

Quote
Perhaps a function in the menu system like so would be better:

char** MenuSystem::get_current_menu_options();

This will return an array of the menu options for the current menu. What do you think?

Ok, this is a safer and easier (for the user) way to do it.

The only little disadvantage i see if i understand correctly is that MenuSystem has to iterate through items to create the array, and then the user has to iterate again through array to print names, what is little slower, but... all have a price.

Another cuestion: Why do you pass a pointer to MenuItem in the callback funtion?

Thinking about this library.. it could be used for anything that needs a tree structure, noy only a menu system.


avenue33


Not entirely sure how this is relevant to the MenuSystem I've created. Looks to me like a shameless plug!


When I developed my menu class, I faced two difficulties: displaying the menu and defining the options.



Sorry for my contribution on menu indexing being considered as a shameless plug.

Go Up