屏幕显示多级菜单

屏幕显示多级菜单 多次菜单的定义与实现结构体定义typedef struct disp_menu_s { const char *name; // 菜单名 const char *desc; // 当前菜单描述 struct disp_menu_s *supmenus; // 上级菜单列表 size_t supmenu_count; // 上级菜单数量 struct disp_menu_s *submenus; // 子菜单列表 size_t submenu_count; // 子菜单数量 esp_err_t (*action)(void *arg); // 菜单执行函数 void *arg; // 函数执行参数 } disp_menu_t;定义菜单的菜单名和描述指明上级菜单的位置上次菜单同级的菜单数量下级菜单列表的位置与下级菜单数量当前的菜单是否关联回调执行函数与回调函数的入参参数具体的菜单声明以小车遥控器代码示例disp_menu_t check_menu[] { {bond_disp, bond display, settings_menu, 3, NULL, 0, NULL, NULL}, }; disp_menu_t settings_menu[] { {check_disp, check display, main_menu, 2, check_menu, 1, check_devices, NULL}, {unbond_disp, unbond display, main_menu, 2, NULL, 0, unbind_device, NULL}, {reset, reset device, main_menu, 2, NULL, 0, NULL, NULL}, }; disp_menu_t main_menu[] { {default_disp, default display, NULL, 0, NULL, 0, NULL, NULL}, {setting_disp, setting display, NULL, 0, settings_menu, 3, NULL, NULL}, };其中check_menu下的bond_disp菜单存在子菜单但是当前赋值为空(NULL, 0)具体的分配区域需要在进入check_menu菜单时通过check_devices去实现内容分配和指针重新指向一个有数据的地址并修改具体的数据具体的后续菜单的分配与修改for (int i 0; i cJSON_GetObjectItem(root, device_len)-valueint; i) { cJSON *item cJSON_GetArrayItem(cJSON_GetObjectItem(root, data), i); if (item) { cJSON *idx cJSON_GetObjectItem(item, idx); cJSON *name cJSON_GetObjectItem(item, name); cJSON *mac cJSON_GetObjectItem(item, mac); dev_list[i].idx idx-valueint; itoa(dev_list[i].idx, dev_list[i].idxs, 10); sprintf(dev_list[i].name, name-valuestring); sprintf(dev_list[i].mac, mac-valuestring); dev_list_menu[i].name dev_list[i].mac; dev_list_menu[i].desc dev_list[i].name; dev_list_menu[i].supmenus check_menu; dev_list_menu[i].supmenu_count 3; dev_list_menu[i].submenus NULL; dev_list_menu[i].submenu_count 0; dev_list_menu[i].action bind_device; dev_list_menu[i].arg dev_list[i].mac; } } check_menu[0].submenus dev_list_menu; check_menu[0].submenu_count cJSON_GetObjectItem(root, device_len)-valueint;实现了对空菜单的修改与重新赋值对菜单路径的访问当前菜单所在位置的记录disp_menu_t *curr_menu main_menu; int curr_menu_len 2; int cursor 0;curr_menu指明当前所在菜单位置curr_menu_len指明当前菜单的子菜单目录长度cursor指明当前选中了哪个子菜单进入下一级菜单if (evt.key_val.key_fsm_finished) { if (curr_menu[cursor].action ! NULL) { if (curr_menu[cursor].action(curr_menu[cursor].arg) ! ESP_OK) { ESP_LOGI(__func__, menu: %s action false, curr_menu[cursor].desc); } else { ESP_LOGI(__func__, menu: %s action true, curr_menu[cursor].desc); } } if (curr_menu[cursor].submenus ! NULL) { curr_menu_len curr_menu[cursor].submenu_count; curr_menu curr_menu[cursor].submenus; cursor 0; } }首先判断是否需要执行回调函数切换进入下级目录**需要确保函数对目录的进入不会有影响否则应该调整函数执行失败的策略**返回上一级菜单if (evt.key_val.key_fsm_finished) { if (curr_menu-supmenus ! NULL) { cursor 0; curr_menu_len curr_menu[cursor].supmenu_count; curr_menu curr_menu[cursor].supmenus; } else // joycon defalut display { disp_mode 0; cursor 0; curr_menu_len 2; curr_menu main_menu; } }通过当前菜单列表的父指针获取当前列表并且父指针的菜单结构体中存在当前菜单列表的数量可以准确的获取菜单列表长度