acid-drop- Hacking the planet from a LilyGo T-Deck using custom firmware |
git clone git://git.acid.vegas/acid-drop.git |
Log | Files | Refs | Archive | README | LICENSE |
lv_menu.c (24321B)
1 /** 2 * @file lv_menu.c 3 * 4 */ 5 6 /********************* 7 * INCLUDES 8 *********************/ 9 #include "lv_menu.h" 10 11 #if LV_USE_MENU 12 13 /********************* 14 * DEFINES 15 *********************/ 16 #define MY_CLASS &lv_menu_class 17 18 #include "../../../core/lv_obj.h" 19 #include "../../layouts/flex/lv_flex.h" 20 #include "../../../widgets/lv_label.h" 21 #include "../../../widgets/lv_btn.h" 22 #include "../../../widgets/lv_img.h" 23 24 /********************** 25 * TYPEDEFS 26 **********************/ 27 28 /********************** 29 * STATIC PROTOTYPES 30 **********************/ 31 static void lv_menu_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj); 32 static void lv_menu_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj); 33 static void lv_menu_page_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj); 34 static void lv_menu_page_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj); 35 static void lv_menu_cont_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj); 36 static void lv_menu_section_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj); 37 38 const lv_obj_class_t lv_menu_class = { 39 .constructor_cb = lv_menu_constructor, 40 .destructor_cb = lv_menu_destructor, 41 .base_class = &lv_obj_class, 42 .width_def = (LV_DPI_DEF * 3) / 2, 43 .height_def = LV_DPI_DEF * 2, 44 .instance_size = sizeof(lv_menu_t) 45 }; 46 const lv_obj_class_t lv_menu_page_class = { 47 .constructor_cb = lv_menu_page_constructor, 48 .destructor_cb = lv_menu_page_destructor, 49 .base_class = &lv_obj_class, 50 .width_def = LV_PCT(100), 51 .height_def = LV_SIZE_CONTENT, 52 .instance_size = sizeof(lv_menu_page_t) 53 }; 54 55 const lv_obj_class_t lv_menu_cont_class = { 56 .constructor_cb = lv_menu_cont_constructor, 57 .base_class = &lv_obj_class, 58 .width_def = LV_PCT(100), 59 .height_def = LV_SIZE_CONTENT 60 }; 61 62 const lv_obj_class_t lv_menu_section_class = { 63 .constructor_cb = lv_menu_section_constructor, 64 .base_class = &lv_obj_class, 65 .width_def = LV_PCT(100), 66 .height_def = LV_SIZE_CONTENT 67 }; 68 69 const lv_obj_class_t lv_menu_separator_class = { 70 .base_class = &lv_obj_class, 71 .width_def = LV_SIZE_CONTENT, 72 .height_def = LV_SIZE_CONTENT 73 }; 74 75 const lv_obj_class_t lv_menu_sidebar_cont_class = { 76 .base_class = &lv_obj_class 77 }; 78 79 const lv_obj_class_t lv_menu_main_cont_class = { 80 .base_class = &lv_obj_class 81 }; 82 83 const lv_obj_class_t lv_menu_main_header_cont_class = { 84 .base_class = &lv_obj_class 85 }; 86 87 const lv_obj_class_t lv_menu_sidebar_header_cont_class = { 88 .base_class = &lv_obj_class 89 }; 90 91 static void lv_menu_refr(lv_obj_t * obj); 92 static void lv_menu_refr_sidebar_header_mode(lv_obj_t * obj); 93 static void lv_menu_refr_main_header_mode(lv_obj_t * obj); 94 static void lv_menu_load_page_event_cb(lv_event_t * e); 95 static void lv_menu_obj_del_event_cb(lv_event_t * e); 96 static void lv_menu_back_event_cb(lv_event_t * e); 97 static void lv_menu_value_changed_event_cb(lv_event_t * e); 98 /********************** 99 * STATIC VARIABLES 100 **********************/ 101 102 /********************** 103 * MACROS 104 **********************/ 105 106 /********************** 107 * GLOBAL FUNCTIONS 108 **********************/ 109 bool lv_menu_item_back_btn_is_root(lv_obj_t * menu, lv_obj_t * obj); 110 void lv_menu_clear_history(lv_obj_t * obj); 111 112 lv_obj_t * lv_menu_create(lv_obj_t * parent) 113 { 114 LV_LOG_INFO("begin"); 115 lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent); 116 lv_obj_class_init_obj(obj); 117 return obj; 118 } 119 120 lv_obj_t * lv_menu_page_create(lv_obj_t * parent, char * title) 121 { 122 LV_LOG_INFO("begin"); 123 lv_obj_t * obj = lv_obj_class_create_obj(&lv_menu_page_class, parent); 124 lv_obj_class_init_obj(obj); 125 126 lv_menu_page_t * page = (lv_menu_page_t *)obj; 127 if(title) { 128 page->title = lv_mem_alloc(strlen(title) + 1); 129 LV_ASSERT_MALLOC(page->title); 130 if(page->title == NULL) return NULL; 131 strcpy(page->title, title); 132 } 133 else { 134 page->title = NULL; 135 } 136 137 return obj; 138 } 139 140 lv_obj_t * lv_menu_cont_create(lv_obj_t * parent) 141 { 142 LV_LOG_INFO("begin"); 143 lv_obj_t * obj = lv_obj_class_create_obj(&lv_menu_cont_class, parent); 144 lv_obj_class_init_obj(obj); 145 return obj; 146 } 147 148 lv_obj_t * lv_menu_section_create(lv_obj_t * parent) 149 { 150 LV_LOG_INFO("begin"); 151 lv_obj_t * obj = lv_obj_class_create_obj(&lv_menu_section_class, parent); 152 lv_obj_class_init_obj(obj); 153 return obj; 154 } 155 156 lv_obj_t * lv_menu_separator_create(lv_obj_t * parent) 157 { 158 LV_LOG_INFO("begin"); 159 lv_obj_t * obj = lv_obj_class_create_obj(&lv_menu_separator_class, parent); 160 lv_obj_class_init_obj(obj); 161 return obj; 162 } 163 164 void lv_menu_refr(lv_obj_t * obj) 165 { 166 LV_ASSERT_OBJ(obj, MY_CLASS); 167 168 lv_menu_t * menu = (lv_menu_t *)obj; 169 lv_ll_t * history_ll = &(menu->history_ll); 170 171 /* The current menu */ 172 lv_menu_history_t * act_hist = _lv_ll_get_head(history_ll); 173 174 lv_obj_t * page = NULL; 175 176 if(act_hist != NULL) { 177 page = act_hist->page; 178 /* Delete the current item from the history */ 179 _lv_ll_remove(history_ll, act_hist); 180 lv_mem_free(act_hist); 181 menu->cur_depth--; 182 } 183 184 /* Set it */ 185 lv_menu_set_page(obj, page); 186 } 187 188 /*===================== 189 * Setter functions 190 *====================*/ 191 192 void lv_menu_set_page(lv_obj_t * obj, lv_obj_t * page) 193 { 194 LV_ASSERT_OBJ(obj, MY_CLASS); 195 196 lv_menu_t * menu = (lv_menu_t *)obj; 197 198 /* Hide previous page */ 199 if(menu->main_page != NULL) { 200 lv_obj_set_parent(menu->main_page, menu->storage); 201 } 202 203 if(page != NULL) { 204 /* Add a new node */ 205 lv_ll_t * history_ll = &(menu->history_ll); 206 lv_menu_history_t * new_node = _lv_ll_ins_head(history_ll); 207 LV_ASSERT_MALLOC(new_node); 208 new_node->page = page; 209 menu->cur_depth++; 210 211 /* Place page in main */ 212 lv_obj_set_parent(page, menu->main); 213 } 214 else { 215 /* Empty page, clear history */ 216 lv_menu_clear_history(obj); 217 } 218 219 menu->main_page = page; 220 221 /* If there is a selected tab, update checked state */ 222 if(menu->selected_tab != NULL) { 223 if(menu->sidebar_page != NULL) { 224 lv_obj_add_state(menu->selected_tab, LV_STATE_CHECKED); 225 } 226 else { 227 lv_obj_clear_state(menu->selected_tab, LV_STATE_CHECKED); 228 } 229 } 230 231 /* Back btn management */ 232 if(menu->sidebar_page != NULL) { 233 /* With sidebar enabled */ 234 if(menu->sidebar_generated) { 235 if(menu->mode_root_back_btn == LV_MENU_ROOT_BACK_BTN_ENABLED) { 236 /* Root back btn is always shown if enabled*/ 237 lv_obj_clear_flag(menu->sidebar_header_back_btn, LV_OBJ_FLAG_HIDDEN); 238 lv_obj_add_flag(menu->sidebar_header_back_btn, LV_OBJ_FLAG_CLICKABLE); 239 } 240 else { 241 lv_obj_add_flag(menu->sidebar_header_back_btn, LV_OBJ_FLAG_HIDDEN); 242 lv_obj_clear_flag(menu->sidebar_header_back_btn, LV_OBJ_FLAG_CLICKABLE); 243 } 244 } 245 246 if(menu->cur_depth >= 2) { 247 lv_obj_clear_flag(menu->main_header_back_btn, LV_OBJ_FLAG_HIDDEN); 248 lv_obj_add_flag(menu->main_header_back_btn, LV_OBJ_FLAG_CLICKABLE); 249 } 250 else { 251 lv_obj_add_flag(menu->main_header_back_btn, LV_OBJ_FLAG_HIDDEN); 252 lv_obj_clear_flag(menu->main_header_back_btn, LV_OBJ_FLAG_CLICKABLE); 253 } 254 } 255 else { 256 /* With sidebar disabled */ 257 if(menu->cur_depth >= 2 || menu->mode_root_back_btn == LV_MENU_ROOT_BACK_BTN_ENABLED) { 258 lv_obj_clear_flag(menu->main_header_back_btn, LV_OBJ_FLAG_HIDDEN); 259 lv_obj_add_flag(menu->main_header_back_btn, LV_OBJ_FLAG_CLICKABLE); 260 } 261 else { 262 lv_obj_add_flag(menu->main_header_back_btn, LV_OBJ_FLAG_HIDDEN); 263 lv_obj_clear_flag(menu->main_header_back_btn, LV_OBJ_FLAG_CLICKABLE); 264 } 265 } 266 267 lv_event_send((lv_obj_t *)menu, LV_EVENT_VALUE_CHANGED, NULL); 268 269 lv_menu_refr_main_header_mode(obj); 270 } 271 272 void lv_menu_set_sidebar_page(lv_obj_t * obj, lv_obj_t * page) 273 { 274 LV_ASSERT_OBJ(obj, MY_CLASS); 275 276 lv_menu_t * menu = (lv_menu_t *)obj; 277 278 /* Sidebar management*/ 279 if(page != NULL) { 280 /* Sidebar should be enabled */ 281 if(!menu->sidebar_generated) { 282 /* Create sidebar */ 283 lv_obj_t * sidebar_cont = lv_obj_class_create_obj(&lv_menu_sidebar_cont_class, obj); 284 lv_obj_class_init_obj(sidebar_cont); 285 lv_obj_move_to_index(sidebar_cont, 1); 286 lv_obj_set_size(sidebar_cont, LV_PCT(30), LV_PCT(100)); 287 lv_obj_set_flex_flow(sidebar_cont, LV_FLEX_FLOW_COLUMN); 288 lv_obj_add_flag(sidebar_cont, LV_OBJ_FLAG_EVENT_BUBBLE); 289 lv_obj_clear_flag(sidebar_cont, LV_OBJ_FLAG_CLICKABLE); 290 menu->sidebar = sidebar_cont; 291 292 lv_obj_t * sidebar_header = lv_obj_class_create_obj(&lv_menu_sidebar_header_cont_class, sidebar_cont); 293 lv_obj_class_init_obj(sidebar_header); 294 lv_obj_set_size(sidebar_header, LV_PCT(100), LV_SIZE_CONTENT); 295 lv_obj_set_flex_flow(sidebar_header, LV_FLEX_FLOW_ROW); 296 lv_obj_set_flex_align(sidebar_header, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); 297 lv_obj_clear_flag(sidebar_header, LV_OBJ_FLAG_CLICKABLE); 298 lv_obj_add_flag(sidebar_header, LV_OBJ_FLAG_EVENT_BUBBLE); 299 menu->sidebar_header = sidebar_header; 300 301 lv_obj_t * sidebar_header_back_btn = lv_btn_create(menu->sidebar_header); 302 lv_obj_add_event_cb(sidebar_header_back_btn, lv_menu_back_event_cb, LV_EVENT_CLICKED, menu); 303 lv_obj_add_flag(sidebar_header_back_btn, LV_OBJ_FLAG_EVENT_BUBBLE); 304 lv_obj_set_flex_flow(sidebar_header_back_btn, LV_FLEX_FLOW_ROW); 305 menu->sidebar_header_back_btn = sidebar_header_back_btn; 306 307 lv_obj_t * sidebar_header_back_icon = lv_img_create(menu->sidebar_header_back_btn); 308 lv_img_set_src(sidebar_header_back_icon, LV_SYMBOL_LEFT); 309 310 lv_obj_t * sidebar_header_title = lv_label_create(menu->sidebar_header); 311 lv_obj_add_flag(sidebar_header_title, LV_OBJ_FLAG_HIDDEN); 312 menu->sidebar_header_title = sidebar_header_title; 313 314 menu->sidebar_generated = true; 315 } 316 317 lv_obj_set_parent(page, menu->sidebar); 318 319 lv_menu_refr_sidebar_header_mode(obj); 320 } 321 else { 322 /* Sidebar should be disabled */ 323 if(menu->sidebar_generated) { 324 lv_obj_set_parent(menu->sidebar_page, menu->storage); 325 lv_obj_del(menu->sidebar); 326 327 menu->sidebar_generated = false; 328 } 329 } 330 331 menu->sidebar_page = page; 332 lv_menu_refr(obj); 333 } 334 335 void lv_menu_set_mode_header(lv_obj_t * obj, lv_menu_mode_header_t mode_header) 336 { 337 LV_ASSERT_OBJ(obj, MY_CLASS); 338 339 lv_menu_t * menu = (lv_menu_t *)obj; 340 341 if(menu->mode_header != mode_header) { 342 menu->mode_header = mode_header; 343 lv_menu_refr_main_header_mode(obj); 344 if(menu->sidebar_generated) lv_menu_refr_sidebar_header_mode(obj); 345 } 346 } 347 348 void lv_menu_set_mode_root_back_btn(lv_obj_t * obj, lv_menu_mode_root_back_btn_t mode_root_back_btn) 349 { 350 LV_ASSERT_OBJ(obj, MY_CLASS); 351 352 lv_menu_t * menu = (lv_menu_t *)obj; 353 354 if(menu->mode_root_back_btn != mode_root_back_btn) { 355 menu->mode_root_back_btn = mode_root_back_btn; 356 lv_menu_refr(obj); 357 } 358 } 359 360 void lv_menu_set_load_page_event(lv_obj_t * menu, lv_obj_t * obj, lv_obj_t * page) 361 { 362 LV_ASSERT_OBJ(menu, MY_CLASS); 363 364 lv_obj_add_flag(obj, LV_OBJ_FLAG_CLICKABLE); 365 lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLLABLE); 366 lv_obj_add_flag(obj, LV_OBJ_FLAG_SCROLL_ON_FOCUS); 367 368 /* Remove old event */ 369 if(lv_obj_remove_event_cb(obj, lv_menu_load_page_event_cb)) { 370 lv_event_send(obj, LV_EVENT_DELETE, NULL); 371 lv_obj_remove_event_cb(obj, lv_menu_obj_del_event_cb); 372 } 373 374 lv_menu_load_page_event_data_t * event_data = lv_mem_alloc(sizeof(lv_menu_load_page_event_data_t)); 375 event_data->menu = menu; 376 event_data->page = page; 377 378 lv_obj_add_event_cb(obj, lv_menu_load_page_event_cb, LV_EVENT_CLICKED, event_data); 379 lv_obj_add_event_cb(obj, lv_menu_obj_del_event_cb, LV_EVENT_DELETE, event_data); 380 } 381 382 /*===================== 383 * Getter functions 384 *====================*/ 385 lv_obj_t * lv_menu_get_cur_main_page(lv_obj_t * obj) 386 { 387 LV_ASSERT_OBJ(obj, MY_CLASS); 388 389 lv_menu_t * menu = (lv_menu_t *)obj; 390 return menu->main_page; 391 } 392 393 lv_obj_t * lv_menu_get_cur_sidebar_page(lv_obj_t * obj) 394 { 395 LV_ASSERT_OBJ(obj, MY_CLASS); 396 397 lv_menu_t * menu = (lv_menu_t *)obj; 398 return menu->sidebar_page; 399 } 400 401 lv_obj_t * lv_menu_get_main_header(lv_obj_t * obj) 402 { 403 LV_ASSERT_OBJ(obj, MY_CLASS); 404 405 lv_menu_t * menu = (lv_menu_t *)obj; 406 return menu->main_header; 407 } 408 409 lv_obj_t * lv_menu_get_main_header_back_btn(lv_obj_t * obj) 410 { 411 LV_ASSERT_OBJ(obj, MY_CLASS); 412 413 lv_menu_t * menu = (lv_menu_t *)obj; 414 return menu->main_header_back_btn; 415 } 416 417 lv_obj_t * lv_menu_get_sidebar_header(lv_obj_t * obj) 418 { 419 LV_ASSERT_OBJ(obj, MY_CLASS); 420 421 lv_menu_t * menu = (lv_menu_t *)obj; 422 return menu->sidebar_header; 423 } 424 425 lv_obj_t * lv_menu_get_sidebar_header_back_btn(lv_obj_t * obj) 426 { 427 LV_ASSERT_OBJ(obj, MY_CLASS); 428 429 lv_menu_t * menu = (lv_menu_t *)obj; 430 return menu->sidebar_header_back_btn; 431 } 432 433 bool lv_menu_back_btn_is_root(lv_obj_t * menu, lv_obj_t * obj) 434 { 435 LV_ASSERT_OBJ(menu, MY_CLASS); 436 437 if(obj == ((lv_menu_t *)menu)->sidebar_header_back_btn) { 438 return true; 439 } 440 441 if(obj == ((lv_menu_t *)menu)->main_header_back_btn && ((lv_menu_t *)menu)->prev_depth <= 1) { 442 return true; 443 } 444 445 return false; 446 } 447 448 void lv_menu_clear_history(lv_obj_t * obj) 449 { 450 LV_ASSERT_OBJ(obj, MY_CLASS); 451 452 lv_menu_t * menu = (lv_menu_t *)obj; 453 lv_ll_t * history_ll = &(menu->history_ll); 454 455 _lv_ll_clear(history_ll); 456 457 menu->cur_depth = 0; 458 } 459 460 /********************** 461 * STATIC FUNCTIONS 462 **********************/ 463 464 static void lv_menu_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj) 465 { 466 LV_UNUSED(class_p); 467 LV_TRACE_OBJ_CREATE("begin"); 468 469 lv_obj_set_layout(obj, LV_LAYOUT_FLEX); 470 lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW); 471 472 lv_menu_t * menu = (lv_menu_t *)obj; 473 474 menu->mode_header = LV_MENU_HEADER_TOP_FIXED; 475 menu->mode_root_back_btn = LV_MENU_ROOT_BACK_BTN_DISABLED; 476 menu->cur_depth = 0; 477 menu->prev_depth = 0; 478 menu->sidebar_generated = false; 479 480 _lv_ll_init(&(menu->history_ll), sizeof(lv_menu_history_t)); 481 482 menu->storage = lv_obj_create(obj); 483 lv_obj_add_flag(menu->storage, LV_OBJ_FLAG_HIDDEN); 484 485 menu->sidebar = NULL; 486 menu->sidebar_header = NULL; 487 menu->sidebar_header_back_btn = NULL; 488 menu->sidebar_header_title = NULL; 489 menu->sidebar_page = NULL; 490 491 lv_obj_t * main_cont = lv_obj_class_create_obj(&lv_menu_main_cont_class, obj); 492 lv_obj_class_init_obj(main_cont); 493 lv_obj_set_height(main_cont, LV_PCT(100)); 494 lv_obj_set_flex_grow(main_cont, 1); 495 lv_obj_set_flex_flow(main_cont, LV_FLEX_FLOW_COLUMN); 496 lv_obj_add_flag(main_cont, LV_OBJ_FLAG_EVENT_BUBBLE); 497 lv_obj_clear_flag(main_cont, LV_OBJ_FLAG_CLICKABLE); 498 menu->main = main_cont; 499 500 lv_obj_t * main_header = lv_obj_class_create_obj(&lv_menu_main_header_cont_class, main_cont); 501 lv_obj_class_init_obj(main_header); 502 lv_obj_set_size(main_header, LV_PCT(100), LV_SIZE_CONTENT); 503 lv_obj_set_flex_flow(main_header, LV_FLEX_FLOW_ROW); 504 lv_obj_set_flex_align(main_header, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); 505 lv_obj_clear_flag(main_header, LV_OBJ_FLAG_CLICKABLE); 506 lv_obj_add_flag(main_header, LV_OBJ_FLAG_EVENT_BUBBLE); 507 menu->main_header = main_header; 508 509 /* Create the default simple back btn and title */ 510 lv_obj_t * main_header_back_btn = lv_btn_create(menu->main_header); 511 lv_obj_add_event_cb(main_header_back_btn, lv_menu_back_event_cb, LV_EVENT_CLICKED, menu); 512 lv_obj_add_flag(main_header_back_btn, LV_OBJ_FLAG_EVENT_BUBBLE); 513 lv_obj_set_flex_flow(main_header_back_btn, LV_FLEX_FLOW_ROW); 514 menu->main_header_back_btn = main_header_back_btn; 515 516 lv_obj_t * main_header_back_icon = lv_img_create(menu->main_header_back_btn); 517 lv_img_set_src(main_header_back_icon, LV_SYMBOL_LEFT); 518 519 lv_obj_t * main_header_title = lv_label_create(menu->main_header); 520 lv_obj_add_flag(main_header_title, LV_OBJ_FLAG_HIDDEN); 521 menu->main_header_title = main_header_title; 522 523 menu->main_page = NULL; 524 menu->selected_tab = NULL; 525 526 lv_obj_add_event_cb(obj, lv_menu_value_changed_event_cb, LV_EVENT_VALUE_CHANGED, menu); 527 528 LV_TRACE_OBJ_CREATE("finished"); 529 } 530 531 static void lv_menu_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj) 532 { 533 LV_UNUSED(class_p); 534 LV_TRACE_OBJ_CREATE("begin"); 535 536 lv_menu_t * menu = (lv_menu_t *)obj; 537 lv_ll_t * history_ll = &(menu->history_ll); 538 539 _lv_ll_clear(history_ll); 540 541 LV_TRACE_OBJ_CREATE("finished"); 542 } 543 544 static void lv_menu_page_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj) 545 { 546 LV_UNUSED(class_p); 547 548 lv_menu_t * menu = (lv_menu_t *)lv_obj_get_parent(obj); 549 550 lv_obj_set_parent(obj, ((lv_menu_t *)menu)->storage); 551 lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_COLUMN); 552 lv_obj_set_flex_align(obj, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); 553 lv_obj_add_flag(obj, LV_OBJ_FLAG_EVENT_BUBBLE); 554 } 555 556 static void lv_menu_page_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj) 557 { 558 LV_UNUSED(class_p); 559 560 lv_menu_page_t * page = (lv_menu_page_t *)obj; 561 562 if(page->title != NULL) { 563 lv_mem_free(page->title); 564 page->title = NULL; 565 } 566 } 567 568 static void lv_menu_cont_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj) 569 { 570 LV_UNUSED(class_p); 571 lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW); 572 lv_obj_set_flex_align(obj, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); 573 lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICKABLE); 574 } 575 576 static void lv_menu_section_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj) 577 { 578 LV_UNUSED(class_p); 579 lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_COLUMN); 580 lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICKABLE); 581 } 582 583 static void lv_menu_refr_sidebar_header_mode(lv_obj_t * obj) 584 { 585 LV_ASSERT_OBJ(obj, MY_CLASS); 586 587 lv_menu_t * menu = (lv_menu_t *)obj; 588 589 if(menu->sidebar_header == NULL || menu->sidebar_page == NULL) return; 590 591 switch(menu->mode_header) { 592 case LV_MENU_HEADER_TOP_FIXED: 593 /* Content should fill the remaining space */ 594 lv_obj_move_to_index(menu->sidebar_header, 0); 595 lv_obj_set_flex_grow(menu->sidebar_page, 1); 596 break; 597 case LV_MENU_HEADER_TOP_UNFIXED: 598 lv_obj_move_to_index(menu->sidebar_header, 0); 599 lv_obj_set_flex_grow(menu->sidebar_page, 0); 600 break; 601 case LV_MENU_HEADER_BOTTOM_FIXED: 602 lv_obj_move_to_index(menu->sidebar_header, 1); 603 lv_obj_set_flex_grow(menu->sidebar_page, 1); 604 break; 605 } 606 607 lv_obj_refr_size(menu->sidebar_header); 608 lv_obj_refr_size(menu->sidebar_page); 609 610 if(lv_obj_get_content_height(menu->sidebar_header) == 0) { 611 lv_obj_add_flag(menu->sidebar_header, LV_OBJ_FLAG_HIDDEN); 612 } 613 else { 614 lv_obj_clear_flag(menu->sidebar_header, LV_OBJ_FLAG_HIDDEN); 615 } 616 } 617 618 static void lv_menu_refr_main_header_mode(lv_obj_t * obj) 619 { 620 LV_ASSERT_OBJ(obj, MY_CLASS); 621 622 lv_menu_t * menu = (lv_menu_t *)obj; 623 624 if(menu->main_header == NULL || menu->main_page == NULL) return; 625 626 switch(menu->mode_header) { 627 case LV_MENU_HEADER_TOP_FIXED: 628 /* Content should fill the remaining space */ 629 lv_obj_move_to_index(menu->main_header, 0); 630 lv_obj_set_flex_grow(menu->main_page, 1); 631 break; 632 case LV_MENU_HEADER_TOP_UNFIXED: 633 lv_obj_move_to_index(menu->main_header, 0); 634 lv_obj_set_flex_grow(menu->main_page, 0); 635 break; 636 case LV_MENU_HEADER_BOTTOM_FIXED: 637 lv_obj_move_to_index(menu->main_header, 1); 638 lv_obj_set_flex_grow(menu->main_page, 1); 639 break; 640 } 641 642 lv_obj_refr_size(menu->main_header); 643 lv_obj_refr_size(menu->main_page); 644 lv_obj_update_layout(menu->main_header); 645 646 if(lv_obj_get_content_height(menu->main_header) == 0) { 647 lv_obj_add_flag(menu->main_header, LV_OBJ_FLAG_HIDDEN); 648 } 649 else { 650 lv_obj_clear_flag(menu->main_header, LV_OBJ_FLAG_HIDDEN); 651 } 652 } 653 654 static void lv_menu_load_page_event_cb(lv_event_t * e) 655 { 656 lv_obj_t * obj = lv_event_get_target(e); 657 lv_menu_load_page_event_data_t * event_data = lv_event_get_user_data(e); 658 lv_menu_t * menu = (lv_menu_t *)(event_data->menu); 659 lv_obj_t * page = event_data->page; 660 661 if(menu->sidebar_page != NULL) { 662 /* Check if clicked obj is in the sidebar */ 663 bool sidebar = false; 664 lv_obj_t * parent = obj; 665 666 while(parent) { 667 if(parent == (lv_obj_t *)menu) break; 668 if(parent == menu->sidebar) { 669 sidebar = true; 670 break; 671 } 672 parent = lv_obj_get_parent(parent); 673 } 674 675 if(sidebar) { 676 /* Clear checked state of previous obj */ 677 if(menu->selected_tab != obj && menu->selected_tab != NULL) { 678 lv_obj_clear_state(menu->selected_tab, LV_STATE_CHECKED); 679 } 680 681 lv_menu_clear_history((lv_obj_t *)menu); 682 683 menu->selected_tab = obj; 684 } 685 } 686 687 lv_menu_set_page((lv_obj_t *)menu, page); 688 689 if(lv_group_get_default() != NULL && menu->sidebar_page == NULL) { 690 /* Sidebar is not supported for now*/ 691 lv_group_focus_next(lv_group_get_default()); 692 } 693 } 694 695 static void lv_menu_obj_del_event_cb(lv_event_t * e) 696 { 697 lv_menu_load_page_event_data_t * event_data = lv_event_get_user_data(e); 698 lv_mem_free(event_data); 699 } 700 701 static void lv_menu_back_event_cb(lv_event_t * e) 702 { 703 lv_event_code_t code = lv_event_get_code(e); 704 /* LV_EVENT_CLICKED */ 705 if(code == LV_EVENT_CLICKED) { 706 lv_obj_t * obj = lv_event_get_target(e); 707 lv_menu_t * menu = (lv_menu_t *)lv_event_get_user_data(e); 708 709 if(!(obj == menu->main_header_back_btn || obj == menu->sidebar_header_back_btn)) return; 710 711 menu->prev_depth = menu->cur_depth; /* Save the previous value for user event handler */ 712 713 if(lv_menu_back_btn_is_root((lv_obj_t *)menu, obj)) return; 714 715 lv_ll_t * history_ll = &(menu->history_ll); 716 717 /* The current menu */ 718 lv_menu_history_t * act_hist = _lv_ll_get_head(history_ll); 719 720 /* The previous menu */ 721 lv_menu_history_t * prev_hist = _lv_ll_get_next(history_ll, act_hist); 722 723 if(prev_hist != NULL) { 724 /* Previous menu exists */ 725 /* Delete the current item from the history */ 726 _lv_ll_remove(history_ll, act_hist); 727 lv_mem_free(act_hist); 728 menu->cur_depth--; 729 /* Create the previous menu. 730 * Remove it from the history because `lv_menu_set_page` will add it again */ 731 _lv_ll_remove(history_ll, prev_hist); 732 menu->cur_depth--; 733 lv_menu_set_page(&(menu->obj), prev_hist->page); 734 735 lv_mem_free(prev_hist); 736 } 737 } 738 } 739 740 static void lv_menu_value_changed_event_cb(lv_event_t * e) 741 { 742 lv_obj_t * obj = lv_event_get_user_data(e); 743 lv_menu_t * menu = (lv_menu_t *)obj; 744 745 lv_menu_page_t * main_page = (lv_menu_page_t *)lv_menu_get_cur_main_page(obj); 746 if(main_page != NULL && menu->main_header_title != NULL) { 747 if(main_page->title != NULL) { 748 lv_label_set_text(menu->main_header_title, main_page->title); 749 lv_obj_clear_flag(menu->main_header_title, LV_OBJ_FLAG_HIDDEN); 750 } 751 else { 752 lv_obj_add_flag(menu->main_header_title, LV_OBJ_FLAG_HIDDEN); 753 } 754 } 755 756 lv_menu_page_t * sidebar_page = (lv_menu_page_t *)lv_menu_get_cur_sidebar_page(obj); 757 if(sidebar_page != NULL && menu->sidebar_header_title != NULL) { 758 if(sidebar_page->title != NULL) { 759 lv_label_set_text(menu->sidebar_header_title, sidebar_page->title); 760 lv_obj_clear_flag(menu->sidebar_header_title, LV_OBJ_FLAG_HIDDEN); 761 } 762 else { 763 lv_obj_add_flag(menu->sidebar_header_title, LV_OBJ_FLAG_HIDDEN); 764 } 765 } 766 } 767 #endif /*LV_USE_MENU*/