📄 multi_menu.c
字号:
//Author--youlong
typedef char S8;
typedef unsigned char U8;
typedef short S16;
typedef unsigned short U16;
typedef long S32;
typedef unsigned long U32;
typedef void (*key_func)(U8 key);
typedef enum {
KEY_YES = 0,
KEY_NO,
KEY_UP,
KEY_DOWN,
KEY_MAX
}KEY_VALUE;//按键值定义
#define ROWS_PER_PAGE 4 //一屏显示4行
#define MAX_MENU_ITEM 11 //总共11个菜单项
typedef enum {
MENU_ID_IDLE,
MENU_ID_MAIN_MENU,
MENU_ID_UART_CONFIG,
MENU_ID_UART_SELECT,
MENU_ID_BAUDRATE_SETTING,
MENU_ID_CALENDAR,
MENU_ID_DATE_SETTING,
MENU_ID_TIME_SETTING,
MAX_MENU_ID,
INVALID_MENU_ID
}MENU_ID;//菜单ID定义
typedef enum {
STR_ID_IDLE,
STR_ID_MAIN_MENU,
STR_ID_UART_CONFIG,
STR_ID_UART_SELECT,
STR_ID_BAUDRATE_SETTING,
STR_ID_CALENDAR,
STR_ID_DATE_SETTING,
STR_ID_TIME_SETTING,
MAX_STR_ID,
INVALID_STR_ID
}STRING_ID;//字符串ID定义
typedef struct {
MENU_ID father;//上级菜单
STRING_ID string_id;//字符串ID
U8 total_son;//子菜单数目
MENU_ID son[MAX_MENU_ITEM];//子菜单ID
key_func key_exec;//菜单项高亮时的执行函数
}MENU_TBL;//菜单列表定义
typedef struct{
MENU_ID curr_menu_id;
U8 total_num; //总的菜单项
U8 rows_per_page; //一屏显示的行数
U8 first_display_row; //当前屏的起始行
U8 highlight_row;//需要高亮显示的行
MENU_TBL *item;//指向当前菜单项的结构指针
}LIST_MENU_STRUCT;
extern U8 get_key(void);
extern void get_char_array(S8 *str, S8 *array_buf);
extern U8 lcd_print_row(U8 row, U8 col, S8 *data);
extern void lcd_clear_screen(void);
MENU_ID get_highlight_menu_id(void);
S8 *get_menu_string(MENU_ID menu_id);
key_func get_key_handler(MENU_ID menu_id);
MENU_ID get_father_id(MENU_ID menu_id);
void uart_config_highlight_handler(U8 key);
void calendar_highlight_handler(U8 key);
void return_to_idle(void);
void do_nothing(void);
void go_to_next_item(void);
void go_to_prev_item(void);
void return_to_father(void);
LIST_MENU_STRUCT *current_menu,LIST_MENU ;
const S8 *str_tbl[MAX_STR_ID] = {
"待机状态",
"主菜单",
"串口设置",
"串口选择",
"波特率选择",
"日历设置",
"日期设置",
"时间设置"
};//字符串常量
const MENU_TBL user_menu[MAX_MENU_ID] = {//与菜单ID对应
//father , string, number of son, son, key handler
{INVALID_MENU_ID, INVALID_STR_ID, 1, {MENU_ID_MAIN_MENU}, NULL},//待机状态
{MENU_ID_IDLE, STR_ID_MAIN_MENU, 2, {MENU_ID_UART_CONFIG, MENU_ID_CALENDAR}, NULL},//主菜单
{STR_ID_MAIN_MENU, STR_ID_UART_CONFIG, 2, {MENU_ID_UART_SELECT, MENU_ID_BAUDRATE_SETTING}, uart_config_highlight_handler},//串口设置
{MENU_ID_UART_SELECT, STR_ID_UART_SELECT, 0, {INVALID_MENU_ID}, uart_select_highlight_handler},//串口选择
{MENU_ID_BAUDRATE_SETTING, STR_ID_BAUDRATE_SETTING, 0, {INVALID_MENU_ID}, baudrate_setting_highlight_handler},//波特率选择
{STR_ID_MAIN_MENU, STR_ID_CALENDAR, 2, {MENU_ID_DATE_SETTING, MENU_ID_TIME_SETTING}, calendar_highlight_handler},//日历设置
{MENU_ID_DATE_SETTING, STR_ID_DATE_SETTING, 0, {INVALID_MENU_ID}, date_setting_highlight_handler},//日期设置
{MENU_ID_TIME_SETTING, STR_ID_TIME_SETTING, 0, {INVALID_MENU_ID}, time_setting_highlight_handler}//时间设置
};
MENU_ID get_highlight_menu_id(void)
{
return current_menu->item->son[current_menu->highlight_row];
}
S8 *get_menu_string(MENU_ID menu_id)
{
STRING_ID str_id = user_menu[menu_id].string_id
return str_tbl[str_id];
}
key_func get_key_handler(MENU_ID menu_id)
{
return user_menu[menu_id].key_exec;
}
MENU_ID get_father_id(MENU_ID menu_id)
{
return user_menu[menu_id].father;
}
void uart_select_highlight_handler(U8 key)
{
switch(key)
{
case KEY_YES:
do_nothing();
break;
case KEY_NO:
return_to_father();
break;
case KEY_UP:
go_to_prev_item();
break;
case KEY_DOWN:
go_to_next_item();
break;
default:break;
}
}
void baudrate_setting_highlight_handler(U8 key)
{
switch(key)
{
case KEY_YES:
do_nothing();
break;
case KEY_NO:
return_to_father();
break;
case KEY_UP:
go_to_prev_item();
break;
case KEY_DOWN:
go_to_next_item();
break;
default:break;
}
}
void uart_config_highlight_handler(U8 key)
{
switch(key)
{
case KEY_YES:
menu_init(MENU_ID_UART_CONFIG);
break;
case KEY_NO:
return_to_father();
break;
case KEY_UP:
go_to_prev_item();
break;
case KEY_DOWN:
go_to_next_item();
break;
default:break;
}
}
void date_setting_highlight_handler(U8 key)
{
switch(key)
{
case KEY_YES:
do_nothing();
break;
case KEY_NO:
return_to_father();
break;
case KEY_UP:
go_to_prev_item();
break;
case KEY_DOWN:
go_to_next_item();
break;
default:break;
}
}
void time_setting_highlight_handler(U8 key)
{
switch(key)
{
case KEY_YES:
do_nothing();
break;
case KEY_NO:
return_to_father();
break;
case KEY_UP:
go_to_prev_item();
break;
case KEY_DOWN:
go_to_next_item();
break;
default:break;
}
}
void calendar_highlight_handler(U8 key)
{
switch(key)
{
case KEY_YES:
menu_init(MENU_ID_CALENDAR);
break;
case KEY_NO:
return_to_father();
break;
case KEY_UP:
go_to_prev_item();
break;
case KEY_DOWN:
go_to_next_item();
break;
default:break;
}
}
void return_to_idle(void)
{
}
void do_nothing(void)
{
}
void list_menu_highlight(U8 row)
{
MENU_ID curr_highlight_menu_id;
U8 i;
S8 *str;
S8 buf[256];
curr_highlight_menu_id = get_highlight_menu_id();
if((curr_highlight_menu_id < MAX_MENU_ID) && (curr_highlight_menu_id > MENU_ID_MAIN_MENU))
str = get_menu_string(curr_highlight_menu_id);
get_char_array(str, buf);
for(i=0; i<256; i++)
{
buf[i] ^= 0xff;
}
lcd_print_row(row, 0, buf);
}
void draw_list_menu(void)
{
MENU_ID menu_id;
U8 i;
S8 *str;
S8 buf[256];
lcd_clear_screen();
for(i=0; i<current_menu->rows_per_page; i++)
{
if((i+current_menu->first_display_row) >= current_menu->total_num)
break;
if((i+current_menu->first_display_row) == current_menu->highlight_row)
{
list_menu_highlight(i);
continue;
}
menu_id = current_menu->item->son[i+current_menu->first_display_row];
str = get_menu_string(menu_id);
get_char_array(str, buf);
lcd_print_row(i, 0, buf);
}
}
void go_to_next_item(void) //向下按键处理函数
{
current_menu->highlight_row++;
if(current_menu->highlight_row >= (current_menu->total_num))
{
current_menu->highlight_row = 0;
current_menu->first_display_row = 0;
}
else
{
if((current_menu->highlight_row%current_menu->rows_per_page) == 0)
current_menu->first_display_row += current_menu->rows_per_page;
}
draw_list_menu();
}
void go_to_prev_item(void) //向上按键处理函数
{
if(current_menu->highlight_row == 0)
{
current_menu->highlight_row = current_menu->total_num - 1;
current_menu->first_display_row = (U8)((current_menu->total_num/current_menu->rows_per_page)*current_menu->rows_per_page);
}
else
{
current_menu->highlight_row--;
if((current_menu->highlight_row%current_menu->rows_per_page) == (current_menu->rows_per_page-1))
current_menu->first_display_row -= current_menu->rows_per_page;
}
draw_list_menu();
}
void return_to_father(void)
{
MENU_ID curr_highlight_menu_id,father_id;
curr_highlight_menu_id = get_highlight_menu_id();
if((curr_highlight_menu_id < MAX_MENU_ID) && (curr_highlight_menu_id > MENU_ID_MAIN_MENU))
father_id = get_father_id(curr_highlight_menu_id);
if(father_id > MENU_ID_IDLE)
menu_init(father_id);
}
void menu_init(MENU_ID menu_id) //菜单初始化
{
current_menu = &LIST_MENU;
current_menu->curr_menu_id = menu_id;
current_menu->item = &user_menu[menu_id];
current_menu->total_num = current_menu->item->total_son;
current_menu->rows_per_page = ROWS_PER_PAGE;
current_menu->first_display_row = 0;
current_menu->highlight_row = 0;
draw_list_menu();
}
void main_menu_entry(void)//主菜单入口
{
U8 key;
MENU_ID curr_highlight_menu_id;
key_func curr_key_handler;
menu_init(MENU_ID_MAIN_MENU);
while(1)
{
key = get_key();
if(key < KEY_MAX)
{
curr_highlight_menu_id = get_highlight_menu_id();
if((curr_highlight_menu_id < MAX_MENU_ID) && (curr_highlight_menu_id > MENU_ID_MAIN_MENU))
curr_key_handler = get_key_handler(curr_highlight_menu_id);
if(curr_key_handler)
(*curr_key_handler)(key);
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -