165 lines
4.0 KiB
C
165 lines
4.0 KiB
C
#include "menu.h"
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
|
||
/* 简单的静态菜单树:
|
||
*
|
||
* 层级 0: [运行界面] [定值设置] [查看数据]
|
||
* │ │
|
||
* 层级 1: (子菜单...) (子菜单...)
|
||
*/
|
||
|
||
static MenuItem g_menuRun;
|
||
static MenuItem g_menuSet;
|
||
static MenuItem g_menuSee;
|
||
static MenuItem g_menuSet1;
|
||
static MenuItem g_menuSet2;
|
||
|
||
void Menu_InitPC(MenuCtrl *ctrl)
|
||
{
|
||
memset(&g_menuRun, 0, sizeof(g_menuRun));
|
||
memset(&g_menuSet, 0, sizeof(g_menuSet));
|
||
memset(&g_menuSee, 0, sizeof(g_menuSee));
|
||
memset(&g_menuSet1, 0, sizeof(g_menuSet1));
|
||
memset(&g_menuSet2, 0, sizeof(g_menuSet2));
|
||
|
||
/* 0 级菜单 */
|
||
g_menuRun.name = "运行界面";
|
||
g_menuRun.tip = "显示运行状态";
|
||
g_menuRun.level = 0;
|
||
g_menuRun.pos = 0;
|
||
|
||
g_menuSet.name = "定值设置";
|
||
g_menuSet.tip = "进入定值设置菜单";
|
||
g_menuSet.level = 0;
|
||
g_menuSet.pos = 1;
|
||
|
||
g_menuSee.name = "查看数据";
|
||
g_menuSee.tip = "查看测量值和记录";
|
||
g_menuSee.level = 0;
|
||
g_menuSee.pos = 2;
|
||
|
||
/* 0 级链表关系 */
|
||
g_menuRun.before = &g_menuSee;
|
||
g_menuRun.behind = &g_menuSet;
|
||
|
||
g_menuSet.before = &g_menuRun;
|
||
g_menuSet.behind = &g_menuSee;
|
||
|
||
g_menuSee.before = &g_menuSet;
|
||
g_menuSee.behind = &g_menuRun;
|
||
|
||
/* 1 级菜单:定值设置下的两个子菜单 */
|
||
g_menuSet1.name = "保护定值";
|
||
g_menuSet1.tip = "编辑保护定值";
|
||
g_menuSet1.level = 1;
|
||
g_menuSet1.pos = 0;
|
||
g_menuSet1.higher = &g_menuSet;
|
||
|
||
g_menuSet2.name = "通信参数";
|
||
g_menuSet2.tip = "编辑通信参数";
|
||
g_menuSet2.level = 1;
|
||
g_menuSet2.pos = 1;
|
||
g_menuSet2.higher = &g_menuSet;
|
||
|
||
g_menuSet1.before = &g_menuSet2;
|
||
g_menuSet1.behind = &g_menuSet2;
|
||
|
||
g_menuSet2.before = &g_menuSet1;
|
||
g_menuSet2.behind = &g_menuSet1;
|
||
|
||
g_menuSet.lower = &g_menuSet1;
|
||
|
||
/* 初始化控制结构 */
|
||
ctrl->head0 = &g_menuRun;
|
||
ctrl->current = &g_menuRun;
|
||
}
|
||
|
||
/* 控制台绘制当前菜单状态 */
|
||
static void Menu_Draw(const MenuCtrl *ctrl)
|
||
{
|
||
const MenuItem *cur = ctrl->current;
|
||
const MenuItem *p;
|
||
|
||
printf("\n==== PC HMI 菜单模拟 ====\n");
|
||
printf("使用 W/S/A/D/Enter/Esc 操作,Ctrl+C 退出。\n\n");
|
||
|
||
/* 显示 0 级菜单 */
|
||
printf("[0级菜单]: ");
|
||
p = ctrl->head0;
|
||
if (!p) {
|
||
printf("(空)\n");
|
||
return;
|
||
}
|
||
const MenuItem *start = p;
|
||
do {
|
||
if (p == cur)
|
||
printf(" [*%s*] ", p->name);
|
||
else
|
||
printf(" %s ", p->name);
|
||
p = p->behind;
|
||
} while (p && p != start);
|
||
printf("\n");
|
||
|
||
/* 若当前有下级,则显示 1 级菜单 */
|
||
if (cur->lower) {
|
||
printf(" 子菜单:\n");
|
||
p = cur->lower;
|
||
start = p;
|
||
do {
|
||
printf(" - %s\n", p->name);
|
||
p = p->behind;
|
||
} while (p && p != start);
|
||
}
|
||
|
||
/* 提示信息 */
|
||
printf("\n提示: %s\n", cur->tip ? cur->tip : "");
|
||
}
|
||
|
||
void Menu_LoopStep(MenuCtrl *ctrl, int key)
|
||
{
|
||
MenuItem *cur = ctrl->current;
|
||
|
||
switch (key) {
|
||
case KEY_U:
|
||
if (cur->before)
|
||
cur = cur->before;
|
||
break;
|
||
case KEY_D:
|
||
if (cur->behind)
|
||
cur = cur->behind;
|
||
break;
|
||
case KEY_L:
|
||
if (cur->higher)
|
||
cur = cur->higher;
|
||
break;
|
||
case KEY_R:
|
||
case KEY_ENT:
|
||
if (cur->lower)
|
||
cur = cur->lower;
|
||
printf("\n>>> 进入 [%s] 功能(模拟用户层)...\n", cur->name);
|
||
break;
|
||
case KEY_ESC:
|
||
if (cur->higher)
|
||
cur = cur->higher;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
ctrl->current = cur;
|
||
Menu_Draw(ctrl);
|
||
}
|
||
|
||
int Menu_MapKey(int ch)
|
||
{
|
||
if (ch == 'w' || ch == 'W') return KEY_U;
|
||
if (ch == 's' || ch == 'S') return KEY_D;
|
||
if (ch == 'a' || ch == 'A') return KEY_L;
|
||
if (ch == 'd' || ch == 'D') return KEY_R;
|
||
if (ch == '\r' || ch == '\n') return KEY_ENT;
|
||
if (ch == 27) return KEY_ESC; /* ESC */
|
||
return KEY_NONE;
|
||
}
|
||
|