Menu (lv_menu)
Overview
The Menu Widget can be used to create multi-level menus that automatically handle navigation among menu levels, and enable its user to capture page navigation and click events.
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.
This creates a Menu Widget with this object hierarchy:
- Menu:
lv_menu_t
Hidden Sub-Page Storage:
lv_obj_t
- Main container:
lv_menu_main_cont_class
- Main header:
lv_menu_main_header_cont_class
- Back button: Button (lv_button)
Back button icon: Image (lv_image)
Main header title: Label (lv_label) (default hidden)
Note that no sidebar is created. You can create one later if you wish.
Header mode
The following header modes exist:
LV_MENU_HEADER_TOP_FIXED
Header is positioned at the top. (default)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
(default)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