Menu (lv_menu)
Overview
The Menu Widget can be used to easily create multi-level menus. It handles the traversal between Pages automatically.
Parts and Styles
The Menu Widget is built from the following Widgets:
Main container:
lv_menu_main_cont
Main header:
lv_menu_main_header_cont
Back button: Button (lv_button)
Back button icon: Image (lv_image)
Main Page:
lv_menu_page
Sidebar container:
lv_menu_sidebar_cont
Sidebar header:
lv_menu_sidebar_header_cont
Back button: Button (lv_button)
Back button icon: Image (lv_image)
Sidebar Page:
lv_menu_page
Usage
Create a Menu
lv_menu_create(parent) creates a new empty Menu.
Header mode
The following header modes exist:
LV_MENU_HEADER_TOP_FIXED
Header is positioned at the top.LV_MENU_HEADER_TOP_UNFIXED
Header is positioned at the top and can be scrolled out of view.LV_MENU_HEADER_BOTTOM_FIXED
Header is positioned at the bottom.
You can set header modes with lv_menu_set_mode_header(menu, LV_MENU_HEADER...).
Root back button mode
The following root back button modes exist:
LV_MENU_ROOT_BACK_BTN_DISABLED
LV_MENU_ROOT_BACK_BTN_ENABLED
You can set root back button modes with lv_menu_set_mode_root_back_button(menu, LV_MENU_ROOT_BACK_BTN...).
Create a Menu Page
lv_menu_page_create(menu, title) creates a new empty Menu Page. You can add any Widgets to the Page.
Set a Menu Page in the main area
Once a Menu Page has been created, you can set it to the main area with
lv_menu_set_page(menu, page). NULL
to clear main and clear Menu
history.
Set a Menu Page in the sidebar
Once a Menu Page has been created, you can set it to the sidebar with
lv_menu_set_sidebar_page(menu, page). NULL
to clear sidebar.
Linking between Menu Pages
If you have, for instance, created a button obj in the main Page. When you click the button Widget, you want it to open up a new Page, use lv_menu_set_load_page_event(menu, btn, new page).
Create a Menu container, section, separator
The following objects can be created so that it is easier to style the Menu:
lv_menu_cont_create(parent_page) creates a new empty container.
lv_menu_section_create(parent_page) creates a new empty section.
lv_menu_separator_create(parent_page) creates a separator.
Events
LV_EVENT_VALUE_CHANGED
Sent when a Page is shown.lv_menu_get_cur_main_page(menu) returns a pointer to Menu Page that is currently displayed in the main container.
lv_menu_get_cur_sidebar_page(menu) returns a pointer to Menu Page that is currently displayed in the sidebar container.
LV_EVENT_CLICKED
Sent when a back button in a header from either main or sidebar is clicked.LV_OBJ_FLAG_EVENT_BUBBLE
is enabled on the buttons so you can add events to the Menu itself.lv_menu_back_button_is_root(menu, button) to check if button is root back button.
Further Reading
Learn more about Base-Widget Events emitted by all Widgets.
Learn more about Events.
Keys
No Keys are processed by Menu Widgets.
Further Reading
Learn more about Keys.
Example
Simple Menu
C code
View on GitHub#include "../../lv_examples.h"
#if LV_USE_MENU && LV_BUILD_EXAMPLES
void lv_example_menu_1(void)
{
/*Create a menu object*/
lv_obj_t * menu = lv_menu_create(lv_screen_active());
lv_obj_set_size(menu, lv_display_get_horizontal_resolution(NULL), lv_display_get_vertical_resolution(NULL));
lv_obj_center(menu);
lv_obj_t * cont;
lv_obj_t * label;
/*Create a sub page*/
lv_obj_t * sub_page = lv_menu_page_create(menu, NULL);
cont = lv_menu_cont_create(sub_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Hello, I am hiding here");
/*Create a main page*/
lv_obj_t * main_page = lv_menu_page_create(menu, NULL);
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 1");
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 2");
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 3 (Click me!)");
lv_menu_set_load_page_event(menu, cont, sub_page);
lv_menu_set_page(menu, main_page);
}
#endif
Simple Menu with root btn
C code
View on GitHub#include "../../lv_examples.h"
#if LV_USE_MENU && LV_USE_MSGBOX && LV_BUILD_EXAMPLES
static void back_event_handler(lv_event_t * e)
{
lv_obj_t * obj = lv_event_get_target(e);
lv_obj_t * menu = lv_event_get_user_data(e);
if(lv_menu_back_button_is_root(menu, obj)) {
lv_obj_t * mbox1 = lv_msgbox_create(NULL);
lv_msgbox_add_title(mbox1, "Hello");
lv_msgbox_add_text(mbox1, "Root back btn click.");
lv_msgbox_add_close_button(mbox1);
}
}
void lv_example_menu_2(void)
{
lv_obj_t * menu = lv_menu_create(lv_screen_active());
lv_menu_set_mode_root_back_button(menu, LV_MENU_ROOT_BACK_BUTTON_ENABLED);
lv_obj_add_event_cb(menu, back_event_handler, LV_EVENT_CLICKED, menu);
lv_obj_set_size(menu, lv_display_get_horizontal_resolution(NULL), lv_display_get_vertical_resolution(NULL));
lv_obj_center(menu);
lv_obj_t * cont;
lv_obj_t * label;
/*Create a sub page*/
lv_obj_t * sub_page = lv_menu_page_create(menu, NULL);
cont = lv_menu_cont_create(sub_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Hello, I am hiding here");
/*Create a main page*/
lv_obj_t * main_page = lv_menu_page_create(menu, NULL);
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 1");
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 2");
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 3 (Click me!)");
lv_menu_set_load_page_event(menu, cont, sub_page);
lv_menu_set_page(menu, main_page);
}
#endif
Simple Menu with custom header
C code
View on GitHub#include "../../lv_examples.h"
#if LV_USE_MENU && LV_BUILD_EXAMPLES
void lv_example_menu_3(void)
{
/*Create a menu object*/
lv_obj_t * menu = lv_menu_create(lv_screen_active());
lv_obj_set_size(menu, lv_display_get_horizontal_resolution(NULL), lv_display_get_vertical_resolution(NULL));
lv_obj_center(menu);
/*Modify the header*/
lv_obj_t * back_btn = lv_menu_get_main_header_back_button(menu);
lv_obj_t * back_button_label = lv_label_create(back_btn);
lv_label_set_text(back_button_label, "Back");
lv_obj_t * cont;
lv_obj_t * label;
/*Create sub pages*/
lv_obj_t * sub_1_page = lv_menu_page_create(menu, "Page 1");
cont = lv_menu_cont_create(sub_1_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Hello, I am hiding here");
lv_obj_t * sub_2_page = lv_menu_page_create(menu, "Page 2");
cont = lv_menu_cont_create(sub_2_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Hello, I am hiding here");
lv_obj_t * sub_3_page = lv_menu_page_create(menu, "Page 3");
cont = lv_menu_cont_create(sub_3_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Hello, I am hiding here");
/*Create a main page*/
lv_obj_t * main_page = lv_menu_page_create(menu, NULL);
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 1 (Click me!)");
lv_menu_set_load_page_event(menu, cont, sub_1_page);
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 2 (Click me!)");
lv_menu_set_load_page_event(menu, cont, sub_2_page);
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 3 (Click me!)");
lv_menu_set_load_page_event(menu, cont, sub_3_page);
lv_menu_set_page(menu, main_page);
}
#endif
Simple Menu with floating btn to add new menu page
C code
View on GitHub#include "../../lv_examples.h"
#if LV_USE_MENU && LV_BUILD_EXAMPLES
static uint32_t btn_cnt = 1;
static lv_obj_t * main_page;
static lv_obj_t * menu;
static void float_button_event_cb(lv_event_t * e)
{
LV_UNUSED(e);
btn_cnt++;
lv_obj_t * cont;
lv_obj_t * label;
lv_obj_t * sub_page = lv_menu_page_create(menu, NULL);
cont = lv_menu_cont_create(sub_page);
label = lv_label_create(cont);
lv_label_set_text_fmt(label, "Hello, I am hiding inside %"LV_PRIu32"", btn_cnt);
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text_fmt(label, "Item %"LV_PRIu32"", btn_cnt);
lv_menu_set_load_page_event(menu, cont, sub_page);
lv_obj_scroll_to_view_recursive(cont, LV_ANIM_ON);
}
void lv_example_menu_4(void)
{
/*Create a menu object*/
menu = lv_menu_create(lv_screen_active());
lv_obj_set_size(menu, lv_display_get_horizontal_resolution(NULL), lv_display_get_vertical_resolution(NULL));
lv_obj_center(menu);
lv_obj_t * cont;
lv_obj_t * label;
/*Create a sub page*/
lv_obj_t * sub_page = lv_menu_page_create(menu, NULL);
cont = lv_menu_cont_create(sub_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Hello, I am hiding inside the first item");
/*Create a main page*/
main_page = lv_menu_page_create(menu, NULL);
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 1");
lv_menu_set_load_page_event(menu, cont, sub_page);
lv_menu_set_page(menu, main_page);
/*Create floating btn*/
lv_obj_t * float_btn = lv_button_create(lv_screen_active());
lv_obj_set_size(float_btn, 50, 50);
lv_obj_add_flag(float_btn, LV_OBJ_FLAG_FLOATING);
lv_obj_align(float_btn, LV_ALIGN_BOTTOM_RIGHT, -10, -10);
lv_obj_add_event_cb(float_btn, float_button_event_cb, LV_EVENT_CLICKED, menu);
lv_obj_set_style_radius(float_btn, LV_RADIUS_CIRCLE, 0);
lv_obj_set_style_bg_image_src(float_btn, LV_SYMBOL_PLUS, 0);
lv_obj_set_style_text_font(float_btn, lv_theme_get_font_large(float_btn), 0);
}
#endif
Complex Menu
C code
View on GitHub#include "../../lv_examples.h"
#if LV_USE_MENU && LV_USE_MSGBOX && LV_BUILD_EXAMPLES
typedef enum {
LV_MENU_ITEM_BUILDER_VARIANT_1,
LV_MENU_ITEM_BUILDER_VARIANT_2
} lv_menu_builder_variant_t;
static void back_event_handler(lv_event_t * e);
static void switch_handler(lv_event_t * e);
lv_obj_t * root_page;
static lv_obj_t * create_text(lv_obj_t * parent, const char * icon, const char * txt,
lv_menu_builder_variant_t builder_variant);
static lv_obj_t * create_slider(lv_obj_t * parent,
const char * icon, const char * txt, int32_t min, int32_t max, int32_t val);
static lv_obj_t * create_switch(lv_obj_t * parent,
const char * icon, const char * txt, bool chk);
void lv_example_menu_5(void)
{
lv_obj_t * menu = lv_menu_create(lv_screen_active());
lv_color_t bg_color = lv_obj_get_style_bg_color(menu, 0);
if(lv_color_brightness(bg_color) > 127) {
lv_obj_set_style_bg_color(menu, lv_color_darken(lv_obj_get_style_bg_color(menu, 0), 10), 0);
}
else {
lv_obj_set_style_bg_color(menu, lv_color_darken(lv_obj_get_style_bg_color(menu, 0), 50), 0);
}
lv_menu_set_mode_root_back_button(menu, LV_MENU_ROOT_BACK_BUTTON_ENABLED);
lv_obj_add_event_cb(menu, back_event_handler, LV_EVENT_CLICKED, menu);
lv_obj_set_size(menu, lv_display_get_horizontal_resolution(NULL), lv_display_get_vertical_resolution(NULL));
lv_obj_center(menu);
lv_obj_t * cont;
lv_obj_t * section;
/*Create sub pages*/
lv_obj_t * sub_mechanics_page = lv_menu_page_create(menu, NULL);
lv_obj_set_style_pad_hor(sub_mechanics_page, lv_obj_get_style_pad_left(lv_menu_get_main_header(menu), 0), 0);
lv_menu_separator_create(sub_mechanics_page);
section = lv_menu_section_create(sub_mechanics_page);
create_slider(section, LV_SYMBOL_SETTINGS, "Velocity", 0, 150, 120);
create_slider(section, LV_SYMBOL_SETTINGS, "Acceleration", 0, 150, 50);
create_slider(section, LV_SYMBOL_SETTINGS, "Weight limit", 0, 150, 80);
lv_obj_t * sub_sound_page = lv_menu_page_create(menu, NULL);
lv_obj_set_style_pad_hor(sub_sound_page, lv_obj_get_style_pad_left(lv_menu_get_main_header(menu), 0), 0);
lv_menu_separator_create(sub_sound_page);
section = lv_menu_section_create(sub_sound_page);
create_switch(section, LV_SYMBOL_AUDIO, "Sound", false);
lv_obj_t * sub_display_page = lv_menu_page_create(menu, NULL);
lv_obj_set_style_pad_hor(sub_display_page, lv_obj_get_style_pad_left(lv_menu_get_main_header(menu), 0), 0);
lv_menu_separator_create(sub_display_page);
section = lv_menu_section_create(sub_display_page);
create_slider(section, LV_SYMBOL_SETTINGS, "Brightness", 0, 150, 100);
lv_obj_t * sub_software_info_page = lv_menu_page_create(menu, NULL);
lv_obj_set_style_pad_hor(sub_software_info_page, lv_obj_get_style_pad_left(lv_menu_get_main_header(menu), 0), 0);
section = lv_menu_section_create(sub_software_info_page);
create_text(section, NULL, "Version 1.0", LV_MENU_ITEM_BUILDER_VARIANT_1);
lv_obj_t * sub_legal_info_page = lv_menu_page_create(menu, NULL);
lv_obj_set_style_pad_hor(sub_legal_info_page, lv_obj_get_style_pad_left(lv_menu_get_main_header(menu), 0), 0);
section = lv_menu_section_create(sub_legal_info_page);
for(uint32_t i = 0; i < 15; i++) {
create_text(section, NULL,
"This is a long long long long long long long long long text, if it is long enough it may scroll.",
LV_MENU_ITEM_BUILDER_VARIANT_1);
}
lv_obj_t * sub_about_page = lv_menu_page_create(menu, NULL);
lv_obj_set_style_pad_hor(sub_about_page, lv_obj_get_style_pad_left(lv_menu_get_main_header(menu), 0), 0);
lv_menu_separator_create(sub_about_page);
section = lv_menu_section_create(sub_about_page);
cont = create_text(section, NULL, "Software information", LV_MENU_ITEM_BUILDER_VARIANT_1);
lv_menu_set_load_page_event(menu, cont, sub_software_info_page);
cont = create_text(section, NULL, "Legal information", LV_MENU_ITEM_BUILDER_VARIANT_1);
lv_menu_set_load_page_event(menu, cont, sub_legal_info_page);
lv_obj_t * sub_menu_mode_page = lv_menu_page_create(menu, NULL);
lv_obj_set_style_pad_hor(sub_menu_mode_page, lv_obj_get_style_pad_left(lv_menu_get_main_header(menu), 0), 0);
lv_menu_separator_create(sub_menu_mode_page);
section = lv_menu_section_create(sub_menu_mode_page);
cont = create_switch(section, LV_SYMBOL_AUDIO, "Sidebar enable", true);
lv_obj_add_event_cb(lv_obj_get_child(cont, 2), switch_handler, LV_EVENT_VALUE_CHANGED, menu);
/*Create a root page*/
root_page = lv_menu_page_create(menu, "Settings");
lv_obj_set_style_pad_hor(root_page, lv_obj_get_style_pad_left(lv_menu_get_main_header(menu), 0), 0);
section = lv_menu_section_create(root_page);
cont = create_text(section, LV_SYMBOL_SETTINGS, "Mechanics", LV_MENU_ITEM_BUILDER_VARIANT_1);
lv_menu_set_load_page_event(menu, cont, sub_mechanics_page);
cont = create_text(section, LV_SYMBOL_AUDIO, "Sound", LV_MENU_ITEM_BUILDER_VARIANT_1);
lv_menu_set_load_page_event(menu, cont, sub_sound_page);
cont = create_text(section, LV_SYMBOL_SETTINGS, "Display", LV_MENU_ITEM_BUILDER_VARIANT_1);
lv_menu_set_load_page_event(menu, cont, sub_display_page);
create_text(root_page, NULL, "Others", LV_MENU_ITEM_BUILDER_VARIANT_1);
section = lv_menu_section_create(root_page);
cont = create_text(section, NULL, "About", LV_MENU_ITEM_BUILDER_VARIANT_1);
lv_menu_set_load_page_event(menu, cont, sub_about_page);
cont = create_text(section, LV_SYMBOL_SETTINGS, "Menu mode", LV_MENU_ITEM_BUILDER_VARIANT_1);
lv_menu_set_load_page_event(menu, cont, sub_menu_mode_page);
lv_menu_set_sidebar_page(menu, root_page);
lv_obj_send_event(lv_obj_get_child(lv_obj_get_child(lv_menu_get_cur_sidebar_page(menu), 0), 0), LV_EVENT_CLICKED,
NULL);
}
static void back_event_handler(lv_event_t * e)
{
lv_obj_t * obj = lv_event_get_target(e);
lv_obj_t * menu = lv_event_get_user_data(e);
if(lv_menu_back_button_is_root(menu, obj)) {
lv_obj_t * mbox1 = lv_msgbox_create(NULL);
lv_msgbox_add_title(mbox1, "Hello");
lv_msgbox_add_text(mbox1, "Root back btn click.");
lv_msgbox_add_close_button(mbox1);
}
}
static void switch_handler(lv_event_t * e)
{
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t * menu = lv_event_get_user_data(e);
lv_obj_t * obj = lv_event_get_target(e);
if(code == LV_EVENT_VALUE_CHANGED) {
if(lv_obj_has_state(obj, LV_STATE_CHECKED)) {
lv_menu_set_page(menu, NULL);
lv_menu_set_sidebar_page(menu, root_page);
lv_obj_send_event(lv_obj_get_child(lv_obj_get_child(lv_menu_get_cur_sidebar_page(menu), 0), 0), LV_EVENT_CLICKED,
NULL);
}
else {
lv_menu_set_sidebar_page(menu, NULL);
lv_menu_clear_history(menu); /* Clear history because we will be showing the root page later */
lv_menu_set_page(menu, root_page);
}
}
}
static lv_obj_t * create_text(lv_obj_t * parent, const char * icon, const char * txt,
lv_menu_builder_variant_t builder_variant)
{
lv_obj_t * obj = lv_menu_cont_create(parent);
lv_obj_t * img = NULL;
lv_obj_t * label = NULL;
if(icon) {
img = lv_image_create(obj);
lv_image_set_src(img, icon);
}
if(txt) {
label = lv_label_create(obj);
lv_label_set_text(label, txt);
lv_label_set_long_mode(label, LV_LABEL_LONG_MODE_SCROLL_CIRCULAR);
lv_obj_set_flex_grow(label, 1);
}
if(builder_variant == LV_MENU_ITEM_BUILDER_VARIANT_2 && icon && txt) {
lv_obj_add_flag(img, LV_OBJ_FLAG_FLEX_IN_NEW_TRACK);
lv_obj_swap(img, label);
}
return obj;
}
static lv_obj_t * create_slider(lv_obj_t * parent, const char * icon, const char * txt, int32_t min, int32_t max,
int32_t val)
{
lv_obj_t * obj = create_text(parent, icon, txt, LV_MENU_ITEM_BUILDER_VARIANT_2);
lv_obj_t * slider = lv_slider_create(obj);
lv_obj_set_flex_grow(slider, 1);
lv_slider_set_range(slider, min, max);
lv_slider_set_value(slider, val, LV_ANIM_OFF);
if(icon == NULL) {
lv_obj_add_flag(slider, LV_OBJ_FLAG_FLEX_IN_NEW_TRACK);
}
return obj;
}
static lv_obj_t * create_switch(lv_obj_t * parent, const char * icon, const char * txt, bool chk)
{
lv_obj_t * obj = create_text(parent, icon, txt, LV_MENU_ITEM_BUILDER_VARIANT_1);
lv_obj_t * sw = lv_switch_create(obj);
lv_obj_add_state(sw, chk ? LV_STATE_CHECKED : 0);
return obj;
}
#endif