1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-28 07:03:00 +08:00

feat(widgets): add menu widget (#2603)

* add menu widget

* Update lv_example_widgets.h

* fix errors

* Update lv_menu.c

* try to fix errors

* micropython

* Fix colons

* Simplify and optimise

* Refactor

* Update lv_example_menu_3.c

* Update lv_example_menu_3.c

* Add simple micropython examples

* Improvements

* Automatically set clickable flags

* Custom header example

* Include example

* Refactor again

* Fix error

* Fix error

* Add back micropython example

* Hide back btn by default

* Add config

* Fix spacing

* Fix spacing

* Docs

* Update lv_theme_default.c

* Remove shaded text

* Improve clarity

* Create index.rst

* Update custom header example

* Change lv_menu_set_mode_sidebar to lv_menu_set_sidebar_page

* Fix unused variable

* Added ability to set title to page

* Flex

* Simplify sidebar check

* Rename mode and update header btn

* Run lv_conf_internal_gen.py

* Run code-format.sh

* Add contributors

* Micropython example 3

* Micropython example 4

* Improve docs
This commit is contained in:
HX2003 2021-11-29 18:33:34 +08:00 committed by GitHub
parent 1c64b78866
commit ad947d3085
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 1818 additions and 0 deletions

View File

@ -775,6 +775,9 @@ menu "LVGL configuration"
config LV_USE_LIST
bool "List."
default y if !LV_CONF_MINIMAL
config LV_USE_MENU
bool "Menu."
default y if !LV_CONF_MINIMAL
config LV_USE_METER
bool "Meter."
default y if !LV_CONF_MINIMAL

View File

@ -51,6 +51,7 @@ widgets = {
"led":"LED",
"line":"Line",
"list":"List",
"menu":"Menu",
"meter":"Meter",
"msgbox":"Message box",
"roller":"Roller",

View File

@ -17,6 +17,7 @@
keyboard
led
list
menu
meter
msgbox
span

View File

@ -0,0 +1,94 @@
```eval_rst
.. include:: /header.rst
:github_url: |github_link_base|/widgets/extra/menu.md
```
# 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 objects:
- Main container: lv_menu_main_cont
- Main header: lv_menu_main_header_cont
- Back btn: [lv_btn](/widgets/core/btn)
- Back btn icon: [lv_img](/widgets/core/img)
- Main page: lv_menu_page
- Sidebar container: lv_menu_sidebar_cont
- Sidebar header: lv_menu_sidebar_header_cont
- Back btn: [lv_btn](/widgets/core/btn)
- Back btn icon: [lv_img](/widgets/core/img)
- 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_btn(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
For instance, you have created a btn obj in the main page. When you click the btn obj, you want it to open up a new page, use `lv_menu_set_load_page_event(menu, obj, 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 main.
- `lv_menu_get_cur_sidebar_page(menu)` returns a pointer to menu page that is currently displayed in sidebar.
- `LV_EVENT_CLICKED` Sent when a back btn 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_btn_is_root(menu, btn)` to check if btn is root back btn
See the events of the [Base object](/widgets/obj) too.
Learn more about [Events](/overview/event).
## Keys
No keys are handled by the menu widget.
Learn more about [Keys](/overview/indev).
## Example
```eval_rst
.. include:: ../../../examples/widgets/menu/index.rst
```
## API
```eval_rst
.. doxygenfile:: lv_menu.h
:project: lvgl
```

View File

@ -90,6 +90,12 @@ void lv_example_line_1(void);
void lv_example_list_1(void);
void lv_example_list_2(void);
void lv_example_menu_1(void);
void lv_example_menu_2(void);
void lv_example_menu_3(void);
void lv_example_menu_4(void);
void lv_example_menu_5(void);
void lv_example_meter_1(void);
void lv_example_meter_2(void);
void lv_example_meter_3(void);

View File

@ -0,0 +1,31 @@
Simple Menu
""""""""""""""""
.. lv_example:: widgets/list/lv_example_menu_1
:language: c
Simple Menu with root btn
""""""""""""""""""""""""""""
.. lv_example:: widgets/list/lv_example_menu_2
:language: c
Simple Menu with custom header
""""""""""""""""""""""""""""
.. lv_example:: widgets/list/lv_example_menu_3
:language: c
Simple Menu with floating btn to add new menu
""""""""""""""""""""""""""""
.. lv_example:: widgets/list/lv_example_menu_4
:language: c
Complex Menu
""""""""""""""""""""""""""""
.. lv_example:: widgets/list/lv_example_menu_5
:language: c

View File

@ -0,0 +1,40 @@
#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_scr_act());
lv_obj_set_size(menu, lv_disp_get_hor_res(NULL), lv_disp_get_ver_res(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

View File

@ -0,0 +1,28 @@
# Create a menu object
menu = lv.menu(lv.scr_act())
menu.set_size(320, 240)
menu.center()
# Create a sub page
sub_page = lv.menu_page(menu, None)
cont = lv.menu_cont(sub_page)
label = lv.label(cont)
label.set_text("Hello, I am hiding here")
# Create a main page
main_page = lv.menu_page(menu, None)
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 1")
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 2")
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 3 (Click me!)")
menu.set_load_page_event(cont, sub_page)
menu.set_page(main_page)

View File

@ -0,0 +1,52 @@
#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_btn_is_root(menu, obj)) {
lv_obj_t * mbox1 = lv_msgbox_create(NULL, "Hello", "Root back btn click.", NULL, true);
lv_obj_center(mbox1);
}
}
void lv_example_menu_2(void)
{
lv_obj_t * menu = lv_menu_create(lv_scr_act());
lv_menu_set_mode_root_back_btn(menu, LV_MENU_ROOT_BACK_BTN_ENABLED);
lv_obj_add_event_cb(menu, back_event_handler, LV_EVENT_CLICKED, menu);
lv_obj_set_size(menu, lv_disp_get_hor_res(NULL), lv_disp_get_ver_res(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

View File

@ -0,0 +1,36 @@
def back_event_handler(e):
obj = e.get_target()
if menu.back_btn_is_root(obj):
mbox1 = lv.msgbox(lv.scr_act(), "Hello", "Root back btn click.", None, True)
mbox1.center()
# Create a menu object
menu = lv.menu(lv.scr_act())
menu.set_mode_root_back_btn(lv.menu.ROOT_BACK_BTN.ENABLED)
menu.add_event_cb(back_event_handler, lv.EVENT.CLICKED, None)
menu.set_size(320, 240)
menu.center()
# Create a sub page
sub_page = lv.menu_page(menu, None)
cont = lv.menu_cont(sub_page)
label = lv.label(cont)
label.set_text("Hello, I am hiding here")
# Create a main page
main_page = lv.menu_page(menu, None)
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 1")
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 2")
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 3 (Click me!)")
menu.set_load_page_event(cont, sub_page)
menu.set_page(main_page)

View File

@ -0,0 +1,59 @@
#include "../../lv_examples.h"
#if LV_USE_MENU && LV_USE_USER_DATA && LV_BUILD_EXAMPLES
void lv_example_menu_3(void)
{
/*Create a menu object*/
lv_obj_t * menu = lv_menu_create(lv_scr_act());
lv_obj_set_size(menu, lv_disp_get_hor_res(NULL), lv_disp_get_ver_res(NULL));
lv_obj_center(menu);
/*Modify the header*/
lv_obj_t * back_btn = lv_menu_get_main_header_back_btn(menu);
lv_obj_t * back_btn_label = lv_label_create(back_btn);
lv_label_set_text(back_btn_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

View File

@ -0,0 +1,43 @@
# Create a menu object
menu = lv.menu(lv.scr_act())
menu.set_size(320, 240)
menu.center()
# Create sub pages
sub_page_1 = lv.menu_page(menu, "Page 1")
cont = lv.menu_cont(sub_page_1)
label = lv.label(cont)
label.set_text("Hello, I am hiding here")
sub_page_2 = lv.menu_page(menu, "Page 2")
cont = lv.menu_cont(sub_page_2)
label = lv.label(cont)
label.set_text("Hello, I am hiding here")
sub_page_3 = lv.menu_page(menu, "Page 3")
cont = lv.menu_cont(sub_page_3)
label = lv.label(cont)
label.set_text("Hello, I am hiding here")
# Create a main page
main_page = lv.menu_page(menu, None)
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 1 (Click me!)")
menu.set_load_page_event(cont, sub_page_1)
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 2 (Click me!)")
menu.set_load_page_event(cont, sub_page_2)
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 3 (Click me!)")
menu.set_load_page_event(cont, sub_page_3)
menu.set_page(main_page)

View File

@ -0,0 +1,70 @@
#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_btn_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 %i", btn_cnt);
cont = lv_menu_cont_create(main_page);
label= lv_label_create(cont);
lv_label_set_text_fmt(label, "Item %i", 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_scr_act());
lv_obj_set_size(menu, lv_disp_get_hor_res(NULL), lv_disp_get_ver_res(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_btn_create(lv_scr_act());
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_btn_event_cb, LV_EVENT_CLICKED, menu);
lv_obj_set_style_radius(float_btn, LV_RADIUS_CIRCLE, 0);
lv_obj_set_style_bg_img_src(float_btn, LV_SYMBOL_PLUS, 0);
lv_obj_set_style_text_font(float_btn, lv_theme_get_font_large(float_btn), 0);
}
#endif

View File

@ -0,0 +1,47 @@
btn_cnt = 1
def float_btn_event_cb(e):
global btn_cnt
btn_cnt += 1
sub_page = lv.menu_page(menu, None)
cont = lv.menu_cont(sub_page)
label = lv.label(cont)
label.set_text("Hello, I am hiding inside {:d}".format(btn_cnt))
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item {:d}".format(btn_cnt))
menu.set_load_page_event(cont, sub_page);
# Create a menu object
menu = lv.menu(lv.scr_act())
menu.set_size(320, 240)
menu.center()
# Create a sub page
sub_page = lv.menu_page(menu, None)
cont = lv.menu_cont(sub_page)
label = lv.label(cont)
label.set_text("Hello, I am hiding inside the first item")
# Create a main page
main_page = lv.menu_page(menu, None)
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 1")
menu.set_load_page_event(cont, sub_page)
menu.set_page(main_page)
float_btn = lv.btn(lv.scr_act())
float_btn.set_size(50, 50)
float_btn.add_flag(lv.obj.FLAG.FLOATING)
float_btn.align(lv.ALIGN.BOTTOM_RIGHT, -10, -10)
float_btn.add_event_cb(float_btn_event_cb, lv.EVENT.CLICKED, None)
float_btn.set_style_radius(lv.RADIUS.CIRCLE, 0)
float_btn.set_style_bg_img_src(lv.SYMBOL.PLUS, 0)
float_btn.set_style_text_font(lv.theme_get_font_large(float_btn), 0)

View File

@ -0,0 +1,194 @@
#include "../../lv_examples.h"
#if LV_USE_MENU && LV_USE_MSGBOX && LV_BUILD_EXAMPLES
enum {
LV_MENU_ITEM_BUILDER_VARIANT_1,
LV_MENU_ITEM_BUILDER_VARIANT_2
};
typedef uint8_t 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_scr_act());
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_btn(menu, LV_MENU_ROOT_BACK_BTN_ENABLED);
lv_obj_add_event_cb(menu, back_event_handler, LV_EVENT_CLICKED, menu);
lv_obj_set_size(menu, lv_disp_get_hor_res(NULL), lv_disp_get_ver_res(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_event_send(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_btn_is_root(menu, obj)) {
lv_obj_t * mbox1 = lv_msgbox_create(NULL, "Hello", "Root back btn click.", NULL, true);
lv_obj_center(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_event_send(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_img_create(obj);
lv_img_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_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

View File

@ -484,6 +484,8 @@
#define LV_USE_LIST 1
#define LV_USE_MENU 1
#define LV_USE_METER 1
#define LV_USE_MSGBOX 1

View File

@ -28,3 +28,4 @@ Here some ideas as inspiration feel free to contribute with ideas too.
## Contributors
- lv_animimg: @ZhaoQiang-b45475
- lv_span: @guoweilkd
- lv_menu: @HX2003

View File

@ -125,6 +125,11 @@ typedef struct {
lv_style_t colorwheel_main;
#endif
#if LV_USE_MENU
lv_style_t menu_bg, menu_cont, menu_sidebar_cont, menu_main_cont, menu_page, menu_header_cont, menu_header_btn,
menu_section, menu_pressed, menu_separator;
#endif
#if LV_USE_MSGBOX
lv_style_t msgbox_bg, msgbox_btn_bg, msgbox_backdrop_bg;
#endif
@ -454,6 +459,67 @@ static void style_init(void)
lv_style_set_text_color(&styles->chart_ticks, lv_palette_main(LV_PALETTE_GREY));
#endif
#if LV_USE_MENU
style_init_reset(&styles->menu_bg);
lv_style_set_pad_all(&styles->menu_bg, 0);
lv_style_set_pad_gap(&styles->menu_bg, 0);
lv_style_set_radius(&styles->menu_bg, 0);
lv_style_set_clip_corner(&styles->menu_bg, true);
lv_style_set_border_side(&styles->menu_bg, LV_BORDER_SIDE_NONE);
style_init_reset(&styles->menu_section);
lv_style_set_radius(&styles->menu_section, RADIUS_DEFAULT);
lv_style_set_clip_corner(&styles->menu_section, true);
lv_style_set_bg_opa(&styles->menu_section, LV_OPA_COVER);
lv_style_set_bg_color(&styles->menu_section, color_card);
lv_style_set_text_color(&styles->menu_section, color_text);
style_init_reset(&styles->menu_cont);
lv_style_set_pad_hor(&styles->menu_cont, PAD_SMALL);
lv_style_set_pad_ver(&styles->menu_cont, PAD_SMALL);
lv_style_set_pad_gap(&styles->menu_cont, PAD_SMALL);
lv_style_set_border_width(&styles->menu_cont, lv_disp_dpx(theme.disp, 1));
lv_style_set_border_opa(&styles->menu_cont, LV_OPA_10);
lv_style_set_border_color(&styles->menu_cont, color_text);
lv_style_set_border_side(&styles->menu_cont, LV_BORDER_SIDE_NONE);
style_init_reset(&styles->menu_sidebar_cont);
lv_style_set_pad_all(&styles->menu_sidebar_cont, 0);
lv_style_set_pad_gap(&styles->menu_sidebar_cont, 0);
lv_style_set_border_width(&styles->menu_sidebar_cont, lv_disp_dpx(theme.disp, 1));
lv_style_set_border_opa(&styles->menu_sidebar_cont, LV_OPA_10);
lv_style_set_border_color(&styles->menu_sidebar_cont, color_text);
lv_style_set_border_side(&styles->menu_sidebar_cont, LV_BORDER_SIDE_RIGHT);
style_init_reset(&styles->menu_main_cont);
lv_style_set_pad_all(&styles->menu_main_cont, 0);
lv_style_set_pad_gap(&styles->menu_main_cont, 0);
style_init_reset(&styles->menu_header_cont);
lv_style_set_pad_hor(&styles->menu_header_cont, PAD_SMALL);
lv_style_set_pad_ver(&styles->menu_header_cont, PAD_TINY);
lv_style_set_pad_gap(&styles->menu_header_cont, PAD_SMALL);
style_init_reset(&styles->menu_header_btn);
lv_style_set_pad_hor(&styles->menu_header_btn, PAD_TINY);
lv_style_set_pad_ver(&styles->menu_header_btn, PAD_TINY);
lv_style_set_shadow_opa(&styles->menu_header_btn, LV_OPA_TRANSP);
lv_style_set_bg_opa(&styles->menu_header_btn, LV_OPA_TRANSP);
lv_style_set_text_color(&styles->menu_header_btn, color_text);
style_init_reset(&styles->menu_page);
lv_style_set_pad_hor(&styles->menu_page, 0);
lv_style_set_pad_gap(&styles->menu_page, 0);
style_init_reset(&styles->menu_pressed);
lv_style_set_bg_opa(&styles->menu_pressed, LV_OPA_20);
lv_style_set_bg_color(&styles->menu_pressed, lv_palette_main(LV_PALETTE_GREY));
style_init_reset(&styles->menu_separator);
lv_style_set_bg_opa(&styles->menu_separator, LV_OPA_TRANSP);
lv_style_set_pad_ver(&styles->menu_separator, PAD_TINY);
#endif
#if LV_USE_METER
style_init_reset(&styles->meter_marker);
lv_style_set_line_width(&styles->meter_marker, lv_disp_dpx(theme.disp, 5));
@ -690,6 +756,14 @@ static void theme_apply(lv_theme_t * th, lv_obj_t * obj)
#endif
lv_obj_add_style(obj, &styles->bg_color_secondary, LV_STATE_CHECKED);
lv_obj_add_style(obj, &styles->disabled, LV_STATE_DISABLED);
#if LV_USE_MENU
if(lv_obj_check_type(lv_obj_get_parent(obj), &lv_menu_sidebar_header_cont_class) ||
lv_obj_check_type(lv_obj_get_parent(obj), &lv_menu_main_header_cont_class)) {
lv_obj_add_style(obj, &styles->menu_header_btn, 0);
lv_obj_add_style(obj, &styles->menu_pressed, LV_STATE_PRESSED);
}
#endif
}
#endif
@ -983,6 +1057,44 @@ static void theme_apply(lv_theme_t * th, lv_obj_t * obj)
}
#endif
#if LV_USE_MENU
else if(lv_obj_check_type(obj, &lv_menu_class)) {
lv_obj_add_style(obj, &styles->card, 0);
lv_obj_add_style(obj, &styles->menu_bg, 0);
}
else if(lv_obj_check_type(obj, &lv_menu_sidebar_cont_class)) {
lv_obj_add_style(obj, &styles->menu_sidebar_cont, 0);
lv_obj_add_style(obj, &styles->scrollbar, LV_PART_SCROLLBAR);
lv_obj_add_style(obj, &styles->scrollbar_scrolled, LV_PART_SCROLLBAR | LV_STATE_SCROLLED);
}
else if(lv_obj_check_type(obj, &lv_menu_main_cont_class)) {
lv_obj_add_style(obj, &styles->menu_main_cont, 0);
lv_obj_add_style(obj, &styles->scrollbar, LV_PART_SCROLLBAR);
lv_obj_add_style(obj, &styles->scrollbar_scrolled, LV_PART_SCROLLBAR | LV_STATE_SCROLLED);
}
else if(lv_obj_check_type(obj, &lv_menu_cont_class)) {
lv_obj_add_style(obj, &styles->menu_cont, 0);
lv_obj_add_style(obj, &styles->menu_pressed, LV_STATE_PRESSED);
lv_obj_add_style(obj, &styles->bg_color_primary_muted, LV_STATE_PRESSED | LV_STATE_CHECKED);
lv_obj_add_style(obj, &styles->bg_color_primary_muted, LV_STATE_CHECKED);
}
else if(lv_obj_check_type(obj, &lv_menu_sidebar_header_cont_class) ||
lv_obj_check_type(obj, &lv_menu_main_header_cont_class)) {
lv_obj_add_style(obj, &styles->menu_header_cont, 0);
lv_obj_add_style(obj, &styles->menu_pressed, LV_STATE_PRESSED);
}
else if(lv_obj_check_type(obj, &lv_menu_page_class)) {
lv_obj_add_style(obj, &styles->menu_page, 0);
lv_obj_add_style(obj, &styles->scrollbar, LV_PART_SCROLLBAR);
lv_obj_add_style(obj, &styles->scrollbar_scrolled, LV_PART_SCROLLBAR | LV_STATE_SCROLLED);
}
else if(lv_obj_check_type(obj, &lv_menu_section_class)) {
lv_obj_add_style(obj, &styles->menu_section, 0);
}
else if(lv_obj_check_type(obj, &lv_menu_separator_class)) {
lv_obj_add_style(obj, &styles->menu_separator, 0);
}
#endif
#if LV_USE_MSGBOX
else if(lv_obj_check_type(obj, &lv_msgbox_class)) {
lv_obj_add_style(obj, &styles->card, 0);

View File

@ -20,6 +20,7 @@ extern "C" {
#include "chart/lv_chart.h"
#include "keyboard/lv_keyboard.h"
#include "list/lv_list.h"
#include "menu/lv_menu.h"
#include "msgbox/lv_msgbox.h"
#include "meter/lv_meter.h"
#include "spinbox/lv_spinbox.h"

View File

@ -0,0 +1,752 @@
/**
* @file lv_menu.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_menu.h"
#if LV_USE_MENU
/*********************
* DEFINES
*********************/
#define MY_CLASS &lv_menu_class
#include "../../../core/lv_obj.h"
#include "../../layouts/flex/lv_flex.h"
#include "../../../widgets/lv_label.h"
#include "../../../widgets/lv_btn.h"
#include "../../../widgets/lv_img.h"
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void lv_menu_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
static void lv_menu_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
static void lv_menu_page_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
static void lv_menu_page_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
static void lv_menu_cont_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
static void lv_menu_section_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
const lv_obj_class_t lv_menu_class = {
.constructor_cb = lv_menu_constructor,
.destructor_cb = lv_menu_destructor,
.base_class = &lv_obj_class,
.width_def = (LV_DPI_DEF * 3) / 2,
.height_def = LV_DPI_DEF * 2,
.instance_size = sizeof(lv_menu_t)
};
const lv_obj_class_t lv_menu_page_class = {
.constructor_cb = lv_menu_page_constructor,
.destructor_cb = lv_menu_page_destructor,
.base_class = &lv_obj_class,
.width_def = LV_PCT(100),
.height_def = LV_SIZE_CONTENT,
.instance_size = sizeof(lv_menu_page_t)
};
const lv_obj_class_t lv_menu_cont_class = {
.constructor_cb = lv_menu_cont_constructor,
.base_class = &lv_obj_class,
.width_def = LV_PCT(100),
.height_def = LV_SIZE_CONTENT
};
const lv_obj_class_t lv_menu_section_class = {
.constructor_cb = lv_menu_section_constructor,
.base_class = &lv_obj_class,
.width_def = LV_PCT(100),
.height_def = LV_SIZE_CONTENT
};
const lv_obj_class_t lv_menu_separator_class = {
.base_class = &lv_obj_class,
.width_def = LV_SIZE_CONTENT,
.height_def = LV_SIZE_CONTENT
};
const lv_obj_class_t lv_menu_sidebar_cont_class = {
.base_class = &lv_obj_class
};
const lv_obj_class_t lv_menu_main_cont_class = {
.base_class = &lv_obj_class
};
const lv_obj_class_t lv_menu_main_header_cont_class = {
.base_class = &lv_obj_class
};
const lv_obj_class_t lv_menu_sidebar_header_cont_class = {
.base_class = &lv_obj_class
};
static void lv_menu_refr(lv_obj_t * obj);
static void lv_menu_refr_sidebar_header_mode(lv_obj_t * obj);
static void lv_menu_refr_main_header_mode(lv_obj_t * obj);
static void lv_menu_load_page_event_cb(lv_event_t * e);
static void lv_menu_obj_del_event_cb(lv_event_t * e);
static void lv_menu_back_event_cb(lv_event_t * e);
static void lv_menu_value_changed_event_cb(lv_event_t * e);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
bool lv_menu_item_back_btn_is_root(lv_obj_t * menu, lv_obj_t * obj);
void lv_menu_clear_history(lv_obj_t * obj);
lv_obj_t * lv_menu_create(lv_obj_t * parent)
{
LV_LOG_INFO("begin");
lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
lv_obj_class_init_obj(obj);
return obj;
}
lv_obj_t * lv_menu_page_create(lv_obj_t * parent, char * title)
{
LV_LOG_INFO("begin");
lv_obj_t * obj = lv_obj_class_create_obj(&lv_menu_page_class, parent);
lv_obj_class_init_obj(obj);
lv_menu_page_t * page = (lv_menu_page_t *)obj;
page->title = title;
return obj;
}
lv_obj_t * lv_menu_cont_create(lv_obj_t * parent)
{
LV_LOG_INFO("begin");
lv_obj_t * obj = lv_obj_class_create_obj(&lv_menu_cont_class, parent);
lv_obj_class_init_obj(obj);
return obj;
}
lv_obj_t * lv_menu_section_create(lv_obj_t * parent)
{
LV_LOG_INFO("begin");
lv_obj_t * obj = lv_obj_class_create_obj(&lv_menu_section_class, parent);
lv_obj_class_init_obj(obj);
return obj;
}
lv_obj_t * lv_menu_separator_create(lv_obj_t * parent)
{
LV_LOG_INFO("begin");
lv_obj_t * obj = lv_obj_class_create_obj(&lv_menu_separator_class, parent);
lv_obj_class_init_obj(obj);
return obj;
}
void lv_menu_refr(lv_obj_t * obj)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_menu_t * menu = (lv_menu_t *)obj;
lv_ll_t * history_ll = &(menu->history_ll);
/* The current menu */
lv_menu_history_t * act_hist = _lv_ll_get_head(history_ll);
lv_obj_t * page = NULL;
if(act_hist != NULL) {
page = act_hist->page;
/* Delete the current item from the history */
_lv_ll_remove(history_ll, act_hist);
lv_mem_free(act_hist);
menu->cur_depth--;
}
/* Set it */
lv_menu_set_page(obj, page);
}
/*=====================
* Setter functions
*====================*/
void lv_menu_set_page(lv_obj_t * obj, lv_obj_t * page)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_menu_t * menu = (lv_menu_t *)obj;
/* Hide previous page */
if(menu->main_page != NULL) {
lv_obj_set_parent(menu->main_page, menu->storage);
}
if(page != NULL) {
/* Add a new node */
lv_ll_t * history_ll = &(menu->history_ll);
lv_menu_history_t * new_node = _lv_ll_ins_head(history_ll);
new_node->page = page;
menu->cur_depth++;
/* Place page in main */
lv_obj_set_parent(page, menu->main);
}
else {
/* Empty page, clear history */
lv_menu_clear_history(obj);
}
menu->main_page = page;
/* If there is a selected tab, update checked state */
if(menu->selected_tab != NULL) {
if(menu->sidebar_page != NULL) {
lv_obj_add_state(menu->selected_tab, LV_STATE_CHECKED);
}
else {
lv_obj_clear_state(menu->selected_tab, LV_STATE_CHECKED);
}
}
/* Back btn management */
if(menu->sidebar_page != NULL) {
/* With sidebar enabled */
if(menu->sidebar_generated) {
if(menu->mode_root_back_btn == LV_MENU_ROOT_BACK_BTN_ENABLED) {
/* Root back btn is always shown if enabled*/
lv_obj_clear_flag(menu->sidebar_header_back_btn, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(menu->sidebar_header_back_btn, LV_OBJ_FLAG_CLICKABLE);
}
else {
lv_obj_add_flag(menu->sidebar_header_back_btn, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(menu->sidebar_header_back_btn, LV_OBJ_FLAG_CLICKABLE);
}
}
if(menu->cur_depth >= 2) {
lv_obj_clear_flag(menu->main_header_back_btn, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(menu->main_header_back_btn, LV_OBJ_FLAG_CLICKABLE);
}
else {
lv_obj_add_flag(menu->main_header_back_btn, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(menu->main_header_back_btn, LV_OBJ_FLAG_CLICKABLE);
}
}
else {
/* With sidebar disabled */
if(menu->cur_depth >= 2 || menu->mode_root_back_btn == LV_MENU_ROOT_BACK_BTN_ENABLED) {
lv_obj_clear_flag(menu->main_header_back_btn, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(menu->main_header_back_btn, LV_OBJ_FLAG_CLICKABLE);
}
else {
lv_obj_add_flag(menu->main_header_back_btn, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(menu->main_header_back_btn, LV_OBJ_FLAG_CLICKABLE);
}
}
lv_event_send((lv_obj_t *)menu, LV_EVENT_VALUE_CHANGED, NULL);
lv_menu_refr_main_header_mode(obj);
}
void lv_menu_set_sidebar_page(lv_obj_t * obj, lv_obj_t * page)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_menu_t * menu = (lv_menu_t *)obj;
/* Sidebar management*/
if(page != NULL) {
/* Sidebar should be enabled */
if(!menu->sidebar_generated) {
/* Create sidebar */
lv_obj_t * sidebar_cont = lv_obj_class_create_obj(&lv_menu_sidebar_cont_class, obj);
lv_obj_class_init_obj(sidebar_cont);
lv_obj_move_to_index(sidebar_cont, 1);
lv_obj_set_size(sidebar_cont, LV_PCT(30), LV_PCT(100));
lv_obj_set_flex_flow(sidebar_cont, LV_FLEX_FLOW_COLUMN);
lv_obj_add_flag(sidebar_cont, LV_OBJ_FLAG_EVENT_BUBBLE);
lv_obj_clear_flag(sidebar_cont, LV_OBJ_FLAG_CLICKABLE);
menu->sidebar = sidebar_cont;
lv_obj_t * sidebar_header = lv_obj_class_create_obj(&lv_menu_sidebar_header_cont_class, sidebar_cont);
lv_obj_class_init_obj(sidebar_header);
lv_obj_set_size(sidebar_header, LV_PCT(100), LV_SIZE_CONTENT);
lv_obj_set_flex_flow(sidebar_header, LV_FLEX_FLOW_ROW);
lv_obj_set_flex_align(sidebar_header, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
lv_obj_clear_flag(sidebar_header, LV_OBJ_FLAG_CLICKABLE);
lv_obj_add_flag(sidebar_header, LV_OBJ_FLAG_EVENT_BUBBLE);
menu->sidebar_header = sidebar_header;
lv_obj_t * sidebar_header_back_btn = lv_btn_create(menu->sidebar_header);
lv_obj_add_event_cb(sidebar_header_back_btn, lv_menu_back_event_cb, LV_EVENT_CLICKED, menu);
lv_obj_add_flag(sidebar_header_back_btn, LV_OBJ_FLAG_EVENT_BUBBLE);
lv_obj_set_flex_flow(sidebar_header_back_btn, LV_FLEX_FLOW_ROW);
menu->sidebar_header_back_btn = sidebar_header_back_btn;
lv_obj_t * sidebar_header_back_icon = lv_img_create(menu->sidebar_header_back_btn);
lv_img_set_src(sidebar_header_back_icon, LV_SYMBOL_LEFT);
lv_obj_t * sidebar_header_title = lv_label_create(menu->sidebar_header);
lv_obj_add_flag(sidebar_header_title, LV_OBJ_FLAG_HIDDEN);
menu->sidebar_header_title = sidebar_header_title;
menu->sidebar_generated = true;
}
lv_obj_set_parent(page, menu->sidebar);
lv_menu_refr_sidebar_header_mode(obj);
}
else {
/* Sidebar should be disabled */
if(menu->sidebar_generated) {
lv_obj_set_parent(menu->sidebar_page, menu->storage);
lv_obj_del(menu->sidebar);
menu->sidebar_generated = false;
}
}
menu->sidebar_page = page;
lv_menu_refr(obj);
}
void lv_menu_set_mode_header(lv_obj_t * obj, lv_menu_mode_header_t mode_header)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_menu_t * menu = (lv_menu_t *)obj;
if(menu->mode_header != mode_header) {
menu->mode_header = mode_header;
lv_menu_refr_main_header_mode(obj);
if(menu->sidebar_generated) lv_menu_refr_sidebar_header_mode(obj);
}
}
void lv_menu_set_mode_root_back_btn(lv_obj_t * obj, lv_menu_mode_root_back_btn_t mode_root_back_btn)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_menu_t * menu = (lv_menu_t *)obj;
if(menu->mode_root_back_btn != mode_root_back_btn) {
menu->mode_root_back_btn = mode_root_back_btn;
lv_menu_refr(obj);
}
}
void lv_menu_set_load_page_event(lv_obj_t * menu, lv_obj_t * obj, lv_obj_t * page)
{
LV_ASSERT_OBJ(menu, MY_CLASS);
/* Make the object clickable */
lv_obj_add_flag(obj, LV_OBJ_FLAG_CLICKABLE);
/* Remove old event */
if(lv_obj_remove_event_cb(obj, lv_menu_load_page_event_cb)) {
lv_event_send(obj, LV_EVENT_DELETE, NULL);
lv_obj_remove_event_cb(obj, lv_menu_obj_del_event_cb);
}
lv_menu_load_page_event_data_t * event_data = lv_mem_alloc(sizeof(lv_menu_load_page_event_data_t));
event_data->menu = menu;
event_data->page = page;
lv_obj_add_event_cb(obj, lv_menu_load_page_event_cb, LV_EVENT_CLICKED, event_data);
lv_obj_add_event_cb(obj, lv_menu_obj_del_event_cb, LV_EVENT_DELETE, event_data);
}
/*=====================
* Getter functions
*====================*/
lv_obj_t * lv_menu_get_cur_main_page(lv_obj_t * obj)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_menu_t * menu = (lv_menu_t *)obj;
return menu->main_page;
}
lv_obj_t * lv_menu_get_cur_sidebar_page(lv_obj_t * obj)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_menu_t * menu = (lv_menu_t *)obj;
return menu->sidebar_page;
}
lv_obj_t * lv_menu_get_main_header(lv_obj_t * obj)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_menu_t * menu = (lv_menu_t *)obj;
return menu->main_header;
}
lv_obj_t * lv_menu_get_main_header_back_btn(lv_obj_t * obj)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_menu_t * menu = (lv_menu_t *)obj;
return menu->main_header_back_btn;
}
lv_obj_t * lv_menu_get_sidebar_header(lv_obj_t * obj)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_menu_t * menu = (lv_menu_t *)obj;
return menu->sidebar_header;
}
lv_obj_t * lv_menu_get_sidebar_header_back_btn(lv_obj_t * obj)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_menu_t * menu = (lv_menu_t *)obj;
return menu->sidebar_header_back_btn;
}
bool lv_menu_back_btn_is_root(lv_obj_t * menu, lv_obj_t * obj)
{
LV_ASSERT_OBJ(menu, MY_CLASS);
if(obj == ((lv_menu_t *)menu)->sidebar_header_back_btn) {
return true;
}
if(obj == ((lv_menu_t *)menu)->main_header_back_btn && ((lv_menu_t *)menu)->prev_depth <= 1) {
return true;
}
return false;
}
void lv_menu_clear_history(lv_obj_t * obj)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_menu_t * menu = (lv_menu_t *)obj;
lv_ll_t * history_ll = &(menu->history_ll);
_lv_ll_clear(history_ll);
menu->cur_depth = 0;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void lv_menu_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
{
LV_UNUSED(class_p);
LV_TRACE_OBJ_CREATE("begin");
lv_obj_set_layout(obj, LV_LAYOUT_FLEX);
lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW);
lv_menu_t * menu = (lv_menu_t *)obj;
menu->mode_header = LV_MENU_HEADER_TOP_FIXED;
menu->mode_root_back_btn = LV_MENU_ROOT_BACK_BTN_DISABLED;
menu->cur_depth = 0;
menu->prev_depth = 0;
menu->sidebar_generated = false;
_lv_ll_init(&(menu->history_ll), sizeof(lv_menu_history_t));
menu->storage = lv_obj_create(obj);
lv_obj_add_flag(menu->storage, LV_OBJ_FLAG_HIDDEN);
menu->sidebar = NULL;
menu->sidebar_header = NULL;
menu->sidebar_header_back_btn = NULL;
menu->sidebar_header_title = NULL;
menu->sidebar_page = NULL;
lv_obj_t * main_cont = lv_obj_class_create_obj(&lv_menu_main_cont_class, obj);
lv_obj_class_init_obj(main_cont);
lv_obj_set_height(main_cont, LV_PCT(100));
lv_obj_set_flex_grow(main_cont, 1);
lv_obj_set_flex_flow(main_cont, LV_FLEX_FLOW_COLUMN);
lv_obj_add_flag(main_cont, LV_OBJ_FLAG_EVENT_BUBBLE);
lv_obj_clear_flag(main_cont, LV_OBJ_FLAG_CLICKABLE);
menu->main = main_cont;
lv_obj_t * main_header = lv_obj_class_create_obj(&lv_menu_main_header_cont_class, main_cont);
lv_obj_class_init_obj(main_header);
lv_obj_set_size(main_header, LV_PCT(100), LV_SIZE_CONTENT);
lv_obj_set_flex_flow(main_header, LV_FLEX_FLOW_ROW);
lv_obj_set_flex_align(main_header, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
lv_obj_clear_flag(main_header, LV_OBJ_FLAG_CLICKABLE);
lv_obj_add_flag(main_header, LV_OBJ_FLAG_EVENT_BUBBLE);
menu->main_header = main_header;
/* Create the default simple back btn and title */
lv_obj_t * main_header_back_btn = lv_btn_create(menu->main_header);
lv_obj_add_event_cb(main_header_back_btn, lv_menu_back_event_cb, LV_EVENT_CLICKED, menu);
lv_obj_add_flag(main_header_back_btn, LV_OBJ_FLAG_EVENT_BUBBLE);
lv_obj_set_flex_flow(main_header_back_btn, LV_FLEX_FLOW_ROW);
menu->main_header_back_btn = main_header_back_btn;
lv_obj_t * main_header_back_icon = lv_img_create(menu->main_header_back_btn);
lv_img_set_src(main_header_back_icon, LV_SYMBOL_LEFT);
lv_obj_t * main_header_title = lv_label_create(menu->main_header);
lv_obj_add_flag(main_header_title, LV_OBJ_FLAG_HIDDEN);
menu->main_header_title = main_header_title;
menu->main_page = NULL;
menu->selected_tab = NULL;
lv_obj_add_event_cb(obj, lv_menu_value_changed_event_cb, LV_EVENT_VALUE_CHANGED, menu);
LV_TRACE_OBJ_CREATE("finished");
}
static void lv_menu_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
{
LV_UNUSED(class_p);
LV_TRACE_OBJ_CREATE("begin");
lv_menu_t * menu = (lv_menu_t *)obj;
lv_ll_t * history_ll = &(menu->history_ll);
_lv_ll_clear(history_ll);
LV_TRACE_OBJ_CREATE("finished");
}
static void lv_menu_page_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
{
LV_UNUSED(class_p);
lv_menu_t * menu = (lv_menu_t *)lv_obj_get_parent(obj);
lv_obj_set_parent(obj, ((lv_menu_t *)menu)->storage);
lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_COLUMN);
lv_obj_set_flex_align(obj, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
lv_obj_add_flag(obj, LV_OBJ_FLAG_EVENT_BUBBLE);
}
static void lv_menu_page_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
{
LV_UNUSED(class_p);
lv_menu_page_t * page = (lv_menu_page_t *)obj;
if(page->title != NULL) {
lv_mem_free(page->title);
page->title = NULL;
}
}
static void lv_menu_cont_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
{
LV_UNUSED(class_p);
lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW);
lv_obj_set_flex_align(obj, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICKABLE);
}
static void lv_menu_section_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
{
LV_UNUSED(class_p);
lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_COLUMN);
lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICKABLE);
}
static void lv_menu_refr_sidebar_header_mode(lv_obj_t * obj)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_menu_t * menu = (lv_menu_t *)obj;
if(menu->sidebar_header == NULL || menu->sidebar_page == NULL) return;
switch(menu->mode_header) {
case LV_MENU_HEADER_TOP_FIXED:
/* Content should fill the remaining space */
lv_obj_move_to_index(menu->sidebar_header, 0);
lv_obj_set_flex_grow(menu->sidebar_page, 1);
break;
case LV_MENU_HEADER_TOP_UNFIXED:
lv_obj_move_to_index(menu->sidebar_header, 0);
lv_obj_set_flex_grow(menu->sidebar_page, 0);
break;
case LV_MENU_HEADER_BOTTOM_FIXED:
lv_obj_move_to_index(menu->sidebar_header, 1);
lv_obj_set_flex_grow(menu->sidebar_page, 1);
break;
}
lv_obj_refr_size(menu->sidebar_header);
lv_obj_refr_size(menu->sidebar_page);
if(lv_obj_get_content_height(menu->sidebar_header) == 0) {
lv_obj_add_flag(menu->sidebar_header, LV_OBJ_FLAG_HIDDEN);
}
else {
lv_obj_clear_flag(menu->sidebar_header, LV_OBJ_FLAG_HIDDEN);
}
}
static void lv_menu_refr_main_header_mode(lv_obj_t * obj)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_menu_t * menu = (lv_menu_t *)obj;
if(menu->main_header == NULL || menu->main_page == NULL) return;
switch(menu->mode_header) {
case LV_MENU_HEADER_TOP_FIXED:
/* Content should fill the remaining space */
lv_obj_move_to_index(menu->main_header, 0);
lv_obj_set_flex_grow(menu->main_page, 1);
break;
case LV_MENU_HEADER_TOP_UNFIXED:
lv_obj_move_to_index(menu->main_header, 0);
lv_obj_set_flex_grow(menu->main_page, 0);
break;
case LV_MENU_HEADER_BOTTOM_FIXED:
lv_obj_move_to_index(menu->main_header, 1);
lv_obj_set_flex_grow(menu->main_page, 1);
break;
}
lv_obj_refr_size(menu->main_header);
lv_obj_refr_size(menu->main_page);
lv_obj_update_layout(menu->main_header);
if(lv_obj_get_content_height(menu->main_header) == 0) {
lv_obj_add_flag(menu->main_header, LV_OBJ_FLAG_HIDDEN);
}
else {
lv_obj_clear_flag(menu->main_header, LV_OBJ_FLAG_HIDDEN);
}
}
static void lv_menu_load_page_event_cb(lv_event_t * e)
{
lv_obj_t * obj = lv_event_get_target(e);
lv_menu_load_page_event_data_t * event_data = lv_event_get_user_data(e);
lv_menu_t * menu = (lv_menu_t *)(event_data->menu);
lv_obj_t * page = event_data->page;
if(menu->sidebar_page != NULL) {
/* Check if clicked obj is in the sidebar */
bool sidebar = false;
lv_obj_t * parent = obj;
while(parent) {
if(parent == (lv_obj_t *)menu) break;
if(parent == menu->sidebar) {
sidebar = true;
break;
}
parent = lv_obj_get_parent(parent);
}
if(sidebar) {
/* Clear checked state of previous obj */
if(menu->selected_tab != obj && menu->selected_tab != NULL) {
lv_obj_clear_state(menu->selected_tab, LV_STATE_CHECKED);
}
lv_menu_clear_history((lv_obj_t *)menu);
menu->selected_tab = obj;
}
}
lv_menu_set_page((lv_obj_t *)menu, page);
}
static void lv_menu_obj_del_event_cb(lv_event_t * e)
{
lv_menu_load_page_event_data_t * event_data = lv_event_get_user_data(e);
lv_mem_free(event_data);
}
static void lv_menu_back_event_cb(lv_event_t * e)
{
lv_event_code_t code = lv_event_get_code(e);
/* LV_EVENT_CLICKED */
if(code == LV_EVENT_CLICKED) {
lv_obj_t * obj = lv_event_get_target(e);
lv_menu_t * menu = (lv_menu_t *)lv_event_get_user_data(e);
if(!(obj == menu->main_header_back_btn || obj == menu->sidebar_header_back_btn)) return;
menu->prev_depth = menu->cur_depth; /* Save the previous value for user event handler */
if(lv_menu_back_btn_is_root((lv_obj_t *)menu, obj)) return;
lv_ll_t * history_ll = &(menu->history_ll);
/* The current menu */
lv_menu_history_t * act_hist = _lv_ll_get_head(history_ll);
/* The previous menu */
lv_menu_history_t * prev_hist = _lv_ll_get_next(history_ll, act_hist);
if(prev_hist != NULL) {
/* Previous menu exists */
/* Delete the current item from the history */
_lv_ll_remove(history_ll, act_hist);
lv_mem_free(act_hist);
menu->cur_depth--;
/* Create the previous menu.
* Remove it from the history because `lv_menu_set_page` will add it again */
_lv_ll_remove(history_ll, prev_hist);
menu->cur_depth--;
lv_menu_set_page(&(menu->obj), prev_hist->page);
lv_mem_free(prev_hist);
}
}
}
static void lv_menu_value_changed_event_cb(lv_event_t * e)
{
lv_obj_t * obj = lv_event_get_user_data(e);
lv_menu_t * menu = (lv_menu_t *)obj;
lv_menu_page_t * main_page = (lv_menu_page_t *)lv_menu_get_cur_main_page(obj);
if(main_page != NULL && menu->main_header_title != NULL) {
if(main_page->title != NULL) {
lv_label_set_text(menu->main_header_title, main_page->title);
lv_obj_clear_flag(menu->main_header_title, LV_OBJ_FLAG_HIDDEN);
}
else {
lv_obj_add_flag(menu->main_header_title, LV_OBJ_FLAG_HIDDEN);
}
}
lv_menu_page_t * sidebar_page = (lv_menu_page_t *)lv_menu_get_cur_sidebar_page(obj);
if(sidebar_page != NULL && menu->sidebar_header_title != NULL) {
if(sidebar_page->title != NULL) {
lv_label_set_text(menu->sidebar_header_title, sidebar_page->title);
lv_obj_clear_flag(menu->sidebar_header_title, LV_OBJ_FLAG_HIDDEN);
}
else {
lv_obj_add_flag(menu->sidebar_header_title, LV_OBJ_FLAG_HIDDEN);
}
}
}
#endif /*LV_USE_MENU*/

View File

@ -0,0 +1,233 @@
/**
* @file lv_menu.h
*
*/
#ifndef LV_MENU_H
#define LV_MENU_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../../core/lv_obj.h"
#if LV_USE_MENU
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
enum {
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 */
};
typedef uint8_t lv_menu_mode_header_t;
enum {
LV_MENU_ROOT_BACK_BTN_DISABLED,
LV_MENU_ROOT_BACK_BTN_ENABLED
};
typedef uint8_t lv_menu_mode_root_back_btn_t;
typedef struct lv_menu_load_page_event_data_t {
lv_obj_t * menu;
lv_obj_t * page;
} lv_menu_load_page_event_data_t;
typedef struct {
lv_obj_t * page;
} lv_menu_history_t;
typedef struct {
lv_obj_t obj;
lv_obj_t * storage; /* a pointer to obj that is the parent of all pages not displayed */
lv_obj_t * main;
lv_obj_t * main_page;
lv_obj_t * main_header;
lv_obj_t *
main_header_back_btn; /* a pointer to obj that on click triggers back btn event handler, can be same as 'main_header' */
lv_obj_t * main_header_title;
lv_obj_t * sidebar;
lv_obj_t * sidebar_page;
lv_obj_t * sidebar_header;
lv_obj_t *
sidebar_header_back_btn; /* a pointer to obj that on click triggers back btn event handler, can be same as 'sidebar_header' */
lv_obj_t * sidebar_header_title;
lv_obj_t * selected_tab;
lv_ll_t history_ll;
uint8_t cur_depth;
uint8_t prev_depth;
uint8_t sidebar_generated : 1;
lv_menu_mode_header_t mode_header : 2;
lv_menu_mode_root_back_btn_t mode_root_back_btn : 1;
} lv_menu_t;
typedef struct {
lv_obj_t obj;
char * title;
} lv_menu_page_t;
extern const lv_obj_class_t lv_menu_class;
extern const lv_obj_class_t lv_menu_page_class;
extern const lv_obj_class_t lv_menu_cont_class;
extern const lv_obj_class_t lv_menu_section_class;
extern const lv_obj_class_t lv_menu_separator_class;
extern const lv_obj_class_t lv_menu_sidebar_cont_class;
extern const lv_obj_class_t lv_menu_main_cont_class;
extern const lv_obj_class_t lv_menu_sidebar_header_cont_class;
extern const lv_obj_class_t lv_menu_main_header_cont_class;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Create a menu object
* @param parent pointer to an object, it will be the parent of the new menu
* @return pointer to the created menu
*/
lv_obj_t * lv_menu_create(lv_obj_t * parent);
/**
* Create a menu page object
* @param parent pointer to menu object
* @param title pointer to text for title in header (NULL to not display title)
* @return pointer to the created menu page
*/
lv_obj_t * lv_menu_page_create(lv_obj_t * parent, char * title);
/**
* Create a menu cont object
* @param parent pointer to an object, it will be the parent of the new menu cont object
* @return pointer to the created menu cont
*/
lv_obj_t * lv_menu_cont_create(lv_obj_t * parent);
/**
* Create a menu section object
* @param parent pointer to an object, it will be the parent of the new menu section object
* @return pointer to the created menu section
*/
lv_obj_t * lv_menu_section_create(lv_obj_t * parent);
/**
* Create a menu separator object
* @param parent pointer to an object, it will be the parent of the new menu separator object
* @return pointer to the created menu separator
*/
lv_obj_t * lv_menu_separator_create(lv_obj_t * parent);
/*=====================
* Setter functions
*====================*/
/**
* Set menu page to display in main
* @param obj pointer to the menu
* @param page pointer to the menu page to set (NULL to clear main and clear menu history)
*/
void lv_menu_set_page(lv_obj_t * obj, lv_obj_t * page);
/**
* Set menu page to display in sidebar
* @param obj pointer to the menu
* @param page pointer to the menu page to set (NULL to clear sidebar)
*/
void lv_menu_set_sidebar_page(lv_obj_t * obj, lv_obj_t * page);
/**
* Set the how the header should behave and its position
* @param obj pointer to a menu
* @param mode_header
*/
void lv_menu_set_mode_header(lv_obj_t * obj, lv_menu_mode_header_t mode_header);
/**
* Set whether back button should appear at root
* @param obj pointer to a menu
* @param mode_root_back_btn
*/
void lv_menu_set_mode_root_back_btn(lv_obj_t * obj, lv_menu_mode_root_back_btn_t mode_root_back_btn);
/**
* Add menu to the menu item
* @param menu pointer to the menu
* @param obj pointer to the obj
* @param page pointer to the page to load when obj is clicked
*/
void lv_menu_set_load_page_event(lv_obj_t * menu, lv_obj_t * obj, lv_obj_t * page);
/*=====================
* Getter functions
*====================*/
/**
* Get a pointer to menu page that is currently displayed in main
* @param obj pointer to the menu
* @return pointer to current page
*/
lv_obj_t * lv_menu_get_cur_main_page(lv_obj_t * obj);
/**
* Get a pointer to menu page that is currently displayed in sidebar
* @param obj pointer to the menu
* @return pointer to current page
*/
lv_obj_t * lv_menu_get_cur_sidebar_page(lv_obj_t * obj);
/**
* Get a pointer to main header obj
* @param obj pointer to the menu
* @return pointer to main header obj
*/
lv_obj_t * lv_menu_get_main_header(lv_obj_t * obj);
/**
* Get a pointer to main header back btn obj
* @param obj pointer to the menu
* @return pointer to main header back btn obj
*/
lv_obj_t * lv_menu_get_main_header_back_btn(lv_obj_t * obj);
/**
* Get a pointer to sidebar header obj
* @param obj pointer to the menu
* @return pointer to sidebar header obj
*/
lv_obj_t * lv_menu_get_sidebar_header(lv_obj_t * obj);
/**
* Get a pointer to sidebar header obj
* @param obj pointer to the menu
* @return pointer to sidebar header back btn obj
*/
lv_obj_t * lv_menu_get_sidebar_header_back_btn(lv_obj_t * obj);
/**
* Check if a obj is a root back btn
* @param menu pointer to the menu
* @return true if it is a root back btn
*/
bool lv_menu_back_btn_is_root(lv_obj_t * menu, lv_obj_t * obj);
/**
* Clear menu history
* @param obj pointer to the menu
*/
void lv_menu_clear_history(lv_obj_t * obj);
/**********************
* MACROS
**********************/
#endif /*LV_USE_MENU*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_MENU_H*/

View File

@ -1551,6 +1551,18 @@
#endif
#endif
#ifndef LV_USE_MENU
#ifdef _LV_KCONFIG_PRESENT
#ifdef CONFIG_LV_USE_MENU
#define LV_USE_MENU CONFIG_LV_USE_MENU
#else
#define LV_USE_MENU 0
#endif
#else
#define LV_USE_MENU 1
#endif
#endif
#ifndef LV_USE_METER
#ifdef _LV_KCONFIG_PRESENT
#ifdef CONFIG_LV_USE_METER