Nested menus (with a rotary controller)

Description

I have a simple set of nested menus based on lists of buttons, in a hiearchy

E.g.
Level 1

Breakfast
Lunch
Dinner

Level 2(a)
Cereal
Juice

Level 2(b)
Sandwich

Level 2©
Chicken
Beef
Pasta

If I select breakfast, I should then be presented with the list 2(a) and be able to select one of the options presented. If I click lunch, list 2(b) is presented and so on.

I build the first menu based on:

    lv_obj_t * menu_scr = lv_obj_create(NULL, NULL);
    lv_scr_load(menu_scr);   

    /*Create a window*/
    lv_obj_t * win = lv_win_create(lv_scr_act(), NULL);

and assign buttons like this

   // button handler
     lv_group_t * g = lv_group_create();
     lv_obj_t * btn = lv_list_add_btn(list, LV_SYMBOL_EDIT, txts[0]);
     lv_obj_set_event_cb(btn, breakfast_event_handler);       /*Assign event function*/
     lv_group_add_obj(g,btn);

    // bind rotary handler to main menu
    lv_indev_set_group(my_indev, g);

And this works as expected - I can move up and down the list, and select an button by pressing my (physical) enter key. My sub-menu is built like this:

    lv_obj_t* lv_submenu_screen(lv_indev_t* my_indev) {
    
    lv_obj_t* menu_scr = lv_obj_create(NULL, NULL);
    lv_scr_load(menu_scr);   

    /*Create a window*/
    lv_obj_t * win = lv_win_create(lv_scr_act(), NULL);
    lv_win_set_title(win, "Food Log");                 
     
    /*Texts of the list elements*/
    const char * txts[] = {"Cereal", "Juice", NULL};
    lv_obj_t* list = lv_list_create(win, NULL);
    lv_obj_set_size(list, 220, 180+60);
    lv_obj_align(list, NULL, LV_ALIGN_CENTER, 0, 10);

    // button handler
    lv_group_t * g = lv_group_create();

    //... start of block repeated for each button

    lv_obj_t * btn = lv_list_add_btn(list, LV_SYMBOL_EDIT, txts[0]);
    lv_obj_set_event_cb(btn, med_sub_event);       /*Assign event function*/
    lv_group_add_obj(g,btn);

    //... end of block repeated for each button

    lv_indev_set_group(my_indev, g); // bind rotary handler to the submenu
    return menu_scr;
  }

But when the submenu is activated, whilst it displays correctly and the rotary event handler still receives key events, no button ever has visual focus.

I’ve been over and over the docs, but I can’t resolve this. I expect I am missing something trivially obvious, any ideas?

What MCU/Processor/Board and compiler are you using?

ESP32 with ILI1941 display and arduino environment v.1.8.10

Further investigation suggests that the request to register the new group

    lv_indev_set_group(my_indev, g); // bind rotary handler to the submenu

is simply being ignored, and the first handler registered is still receiving the events. This seems really basic; should I file a bug report or am I missing the obvious?

lv_indev_set_group(my_indev, g);

Has to be called when you call lv_load_scr() in the event handler, any binding registered during instantiation is not preserved.

LVGL has great promise, but I do keep feeling that I’m being dragged back to the 80’s. Call order of functions should either be explicit, or should not matter. Having to persist e.g. group variables as well as the screen itself in order to be able to handle input seems a really odd design choice. Good luck! Hopefully this post will save someone else a few hours.

I’d like to investigate it. Can you post a simple but full example which can be copy-pasted to the simulator?
Please add comments to shows which parts cause confusion.

This is not normal behavior. You shouldn’t need to keep variables like those around, unless you are trying to add more objects to them later.

1 Like