767 lines
24 KiB
C
767 lines
24 KiB
C
/**
|
|
* @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;
|
|
if(title) {
|
|
page->title = lv_mem_alloc(strlen(title) + 1);
|
|
LV_ASSERT_MALLOC(page->title);
|
|
if(page->title == NULL) return NULL;
|
|
strcpy(page->title, title);
|
|
}
|
|
else {
|
|
page->title = NULL;
|
|
}
|
|
|
|
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);
|
|
|
|
lv_obj_add_flag(obj, LV_OBJ_FLAG_CLICKABLE);
|
|
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLLABLE);
|
|
lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
|
|
|
|
/* 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);
|
|
|
|
if(lv_group_get_default() != NULL && menu->sidebar_page == NULL) {
|
|
/* Sidebar is not supported for now*/
|
|
lv_group_focus_next(lv_group_get_default());
|
|
}
|
|
}
|
|
|
|
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*/
|