Pages: 1 [2] 3   Go Down
Author Topic: New Arduino library: MenuSystem  (Read 7499 times)
0 Members and 2 Guests are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 26
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

I pass a pointer to the menu item to the callback so it knows what invoked it.

You're right about the double iteration. Still, optimising early is generally considered a bad idea. That said, I'm not totally against you're approach. I will try them both out smiley

Finally, you're right again, this could be used for any tree structure. That is the intent of the composite design pattern. I wouldn't use this library for anything other than a menu system though.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 26
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

arcachofo, I had a look at the two options: it was fun. smiley

I was leaning towards my option, because I really wanted to prevent the user from doing something stupid like:

Menu* current_menu = ms.get_current_menu();
current_menu->select();

My idea was too hard to implement in a clean and tidy way (because arduino doesn't support new and delete). So I went back to your idea and the answer came to me:

Menu const* get_current_menu() const;

Yup! The function returns a pointer to a const. I made a lot of functions do the same, so if users try silly things, it won't work without them being extra silly and const_casting.

So, you'll be pleased to know that I've applied a slightly modified version of your idea and uploaded it to github. I've also included some examples. Thanks for the idea! Enjoy!
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 24
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Menu const* get_current_menu() const;

Yup! The function returns a pointer to a const. I made a lot of functions do the same, so if users try silly things, it won't work without them being extra silly and const_casting.
Yes... looks the proper way, and if someones knows to do a cons_cast is suposed to know what is doing.

Quote
So, you'll be pleased to know that I've applied a slightly modified version of your idea and uploaded it to github. I've also included some examples. Thanks for the idea! Enjoy!
Nice!! i will have a look, thanks.

Regards.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello Jon

I'm bumping this old thread smiley

First, thanks for your menu class, this is exactly what I needed for my project.

I'm actually building an antenna tracker to track my drones using telemetry data.

Code is here: https://code.google.com/p/ghettostation/source/browse/#git%2FGhettoStation

On the ground device, there's an LCD ( i2c lcd03) proposing at startup a menu.

Here is the menu:

Menu Root:
    - START
    - SET_HOME
    - CONFIGURATION:
                  - SERVOS:
                        - PAN:
                               - MIN_PWM
                               - MIN_ANGLE
                               - MAX_PWM
                               - MAX_ANGLE
                        - TILT:
                               - MIN_PWM
                               - MIN_ANGLE
                               - MAX_PWM
                               - MAX_ANGLE
                        - TEST
                  - BAUDRATE


Here is my init menu function:

Code:
void init_menu() {
rootMenu.add_item(&m1i1Item, &screen_tracking); //start track
rootMenu.add_item(&m1i2Item, &screen_sethome); //set home position
rootMenu.add_menu(&m1m3Menu); //configure
m1m3Menu.add_menu(&m1m3m1Menu); //config servos
m1m3m1Menu.add_menu(&m1m3m1m1Menu); //config pan
m1m3m1m1Menu.add_item(&m1m3m1m1l1Item, &configure_pan_minpwm); // pan min pwm
m1m3m1m1Menu.add_item(&m1m3m1m1l2Item, &configure_pan_minangle); // pan min angle
m1m3m1m1Menu.add_item(&m1m3m1m1l3Item, &configure_pan_maxpwm); // pan max pwm
m1m3m1m1Menu.add_item(&m1m3m1m1l4Item, &configure_pan_maxangle); // pan max angle
m1m3m1Menu.add_menu(&m1m3m1m2Menu); //config tilt
m1m3m1m2Menu.add_item(&m1m3m1m2l1Item, &configure_tilt_minpwm); // tilt min pwm
m1m3m1m2Menu.add_item(&m1m3m1m2l2Item, &configure_tilt_minangle); // tilt min angle
m1m3m1m2Menu.add_item(&m1m3m1m2l3Item, &configure_tilt_maxpwm); // tilt max pwm
m1m3m1m2Menu.add_item(&m1m3m1m2l4Item, &configure_tilt_maxangle); // tilt max angle
                        m1m3m1Menu.add_item(&m1m3m1i3Item, &configure_test_servo);
m1m3Menu.add_item(&m1m3l2Item, &configure_baudrate); //config baudrate
displaymenu.set_root_menu(&rootMenu);
}


Then in the mainloop, when current_activity == "MENU" , it calls at 10hz:

Code:
void display_menu() {
        Menu const* displaymenu_current = displaymenu.get_current_menu();
//Serial.print("current menu = ");
//Serial.println(displaymenu_current->get_cur_menu_component_num());
MenuComponent const* displaymenu_sel = displaymenu_current->get_selected();
          
        for (int n = 1; n < 5; ++n) {
          char string_buffer[21];
//
            if ( (displaymenu_current->get_num_menu_components()) >= n ) {
                
        
      
        MenuComponent const* displaymenu_comp = displaymenu_current->get_menu_component(n-1);
        String getname = displaymenu_comp->get_name();
 for ( int l = getname.length()-1 ; l<20 ; l++ ) {
getname = getname + " ";
}  

        if (displaymenu_sel == displaymenu_comp) {
 
       getname.setCharAt(19,'<');
        } else {
         getname.setCharAt(19, ' ');
        }
      
        getname.toCharArray(string_buffer,21);
                
            }
            else {
               empty_line.toCharArray(string_buffer,21);
            }
store_lcdline(n, string_buffer);

};

}

Then LCD screen is refreshed at 10hz on another timed loop in the main loop.

This works almost well.
When I stay inside the menu, I can go next, prev, back and select...
I use click button to select, & long_press button to go back to the parent.

The problem is when I select an item in a submenu. Imagine I've selected CONFIGURATION/TILT/MIN_PWM. My current_activity change from #MENU" to "TILT_MINPWM". ( so the display_menu function is not called anymore. )
 It then call another function to display the configuration screen on the LCD & handle configuring parameters.
When I quit this screen, I change the current_status to "MENU", so it displays the menu again.
The problem is it doesn't go back to the previous menu state, it just start from the Root Menu, with the CONFIGURATION already selected.

I'd like to have it going back in menu_root/CONFIGURATION/SERVOS/TILT menu and not Root.

There's probably a mistake I've made somewhere, but I can't find it for now.

If you have a genius idea, I take it smiley

Cheers.
« Last Edit: March 27, 2013, 09:20:47 am by Kipkool » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Forget it I've found it.

It's un the library, cpp file:

Code:
// A menu item was selected, so reset the menu ready for when
// it's used again.
 _p_curr_menu = _p_root_menu;

So I've added mreset parameter at select() function:
Code:
void MenuSystem::select(boolean mreset)
{
    MenuComponent* pComponent = _p_curr_menu->activate();

    if (pComponent != NULL)
    {
        _p_curr_menu = (Menu*) pComponent;
    }
    else
    {
       
if (mreset) {
// A menu item was selected, so reset the menu ready for when
        // it's used again.
        _p_curr_menu = _p_root_menu;
}
    }
}
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 1
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Have anyone a complete code with this librarie so I can better understand and use to make my menu?

Thanks!
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi. im learning to trying your code here. however it stop on first line.

#include <MenuSystem.h>

 
MenuSystem ms;
Menu mm("");
MenuItem mi_time("TIME");
MenuItem mi_date("DATE");
MenuItem mi_alarm("ALARM");
Menu mu_disp("DISP");
MenuItem mi_disp_brightness("BRTNS");

my sketch stop n show error "menu system does not name a type"

what am i missing?
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 26
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Apologies for those who left messages addressed to me. I didn't have notifications turned on, so have missed them.

@vidsondak
I'm not sure because it's been a while since I've done any arduino development. My first thought is that the library isn't in the correct folder, but the error message is odd since "menu system" is written with a space in it. Did you make a typo by any chance?

@JoarleyRodrigues
There are examples included with the library, have you tried those out?

@kipkool
You posted way, way back in March. I'm very sorry. Hopefully you've found an answer by now. If not, please raise an issue on github and I'll take a look. Why do I need a github issue? I'm away for a few weeks, and I tend to be active on github a lot, so when I return I will be reminded.


Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi.
I've submited a pull request to your repo with my fix.

https://github.com/jonblack/menusystem/pull/3

Cheers.


Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 26
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks! I'm going away on holiday for a few weeks soon. I'll try and take a look before then, otherwise I'll handle it when I get back. It's nice that a solution is available in the meantime if people need it.
Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 47
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I had made a new example so that the user can navigate the menu over serial comands. The idea is to make easy to understand how to control the menu. I'll make a pull request of this example, but meanwhile you can found it here
https://github.com/jonblack/menusystem/pull/4
« Last Edit: December 01, 2013, 06:21:42 pm by niesteszeck » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 26
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Looks good. I'll merge this in sometime this week. Thanks again for the contribution smiley

I had made a new example so that the user can navigate the menu over serial comands. The idea is to make easy to understand how to control the menu. I'll make a pull request of this example, but meanwhile you can found it here
https://github.com/jonblack/menusystem/pull/4
Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 47
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi jonblack.

Thanks for considering my pull request. Actually I had make another example (LCDNav) that use a LCD 16x2 screen using LiquidCrystal library and controlled over serial in the same way. If you like it I can make a pull request of this example to.
https://github.com/niesteszeck/menusystem/commit/7c6d4755b1eba75e9edfe80c9e927ac346d5773a
 
Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 47
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi jonblack.

Is me again, I have a question:
Is there a way to identify a selection other that by name.
I want my serialHandler to react different if I'm in the menu, or if I'm in a selection. I want to make that, for example, when I select Level1 Item1 my serialHandler reacts accordingly  and set a variable value using the same comands (the plan if in the future swap serial handler with a button handler). Any tips how to approach?

One idea that I have is to modify the lib so add an id to the MenuComponent
Code:
class MenuComponent
{
public:
    MenuComponent(char* name, int id);

    void set_name(char* name);
    char* get_name() const;
    int get_Id() const;

    virtual MenuComponent* select() = 0;

protected:
    char* _name;
    byte _id;
};

But this way it will be responsibility of the user to put the unique id of the component

any other idea?
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 26
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

menusystem 1.0.0 has been released. See github for more information. This is the first release to have a version number, so it doesn't mean much at the moment. Also, I couldn't test this on an arduino because I've lost my usb cable....oops. It compiles fine, so hopefully all is well smiley

@kipkool
I've merged in your pull-request. What you wrote here in the forum was different to the pull request. I changed the pull request to match what you have here, but also making the default behaviour the same as always (return to the root menu).

@niesteszeck
I've merged in your examples as well. I renamed the files to match the format of the existing ones. A small thing, I know smiley.

As for your other question, I'm not sure I understand completely what you're trying to achieve. Your handler should be called directly when you select a menu item, so you shouldn't need to store what was selected. What is your use case for tracking the menu selection outside of the library (by returning the id)?
Logged

Pages: 1 [2] 3   Go Up
Jump to: