用c语言写的基于链表结构的多级菜单显示,菜单项目支持动态添加和删除,只要内存够用,理论上可以添加任意级菜单,类似于文件系统
menu.h
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "unistd.h"
#include <curses.h>
#define DISPLAY_C
#define offsetof(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) ); })
#define CURR_PTR " =>>"
typedef enum
{
key_left = 0,
key_right,
key_up,
key_down,
key_enter,
key_back,
key_sum,
key_none,
} keys;
typedef struct displist_t
{
int size;
int cur_idx;
endpot *cur;
endpot *start;
endpot *end;
} displist;
typedef enum{
in_prev = 0,
in_list,
in_next,
in_child,
in_parent,
in_error
}disp_ret;
struct stack_node
{
unsigned long data;
struct stack_node *next;
};
struct list_t
{
struct list_t *prev, *next;
};
typedef enum
{
pot = 0,
dir,
} node_flag;
typedef struct menu
{
int idx;
char name[30];
char *bmp;
void *arg;
void (*func)(void *);
void (*disp)(void *);
} menu_item;
typedef struct node
{
int lvl;
node_flag flag;
int subnum;
menu_item item;
struct node *current;
struct node *first,*end;
struct node *child, *parent;
struct node *prev, *next;
} endpot;
typedef struct node *pendpot;
void init_list(endpot *ep);
//根目录
extern endpot root;
void endpot_add_next(endpot *ep, endpot *newone);
void endpot_del(endpot *del);
void endpot_add_child(endpot *ep, endpot *child);
void endpot_add_parent(endpot *ep, endpot *parent);
void endpot_init(endpot *ep, char *name, node_flag flag);
endpot *alloc_endpot(int num);
void free_endpot(endpot *p);
endpot *endpot_add(endpot *parent, char *name, node_flag flag, void (*fun)(void *), void *arg);
void endpot_delete(endpot *ep);
#define ADD_POT_MENU(parent, name, fun) \
pendpot name = endpot_add(parent, #name, pot, fun)
#define ADD_DIR_MENU(parent, name) \
pendpot name = endpot_add(parent, #name, dir, NULL)
#define ADD_POT(parent, name, fun) endpot_add(parent, name, pot, fun, NULL)
#define ADD_DIR(parent, name) endpot_add(parent, name, dir, NULL, NULL)
keys getkey(void);
endpot *get_cur_ep(endpot *ep, keys key);
int is_root(endpot *ep);
int update_itemlist_idx(endpot *ep);
void display_list(displist *disp);
void currentlistprint(endpot *ep);
void menu_run(endpot *ep);
typedef struct stack_node *PtrToNode;
typedef PtrToNode Stack;
Stack create_stack();
void push_stack(Stack s, unsigned long data);
void pop_stack(Stack s);
unsigned long top_stack(Stack s);
int stack_is_empty(Stack s);
最后添加一个小demo,demo.c
#include "myz_menu.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "unistd.h"
#include <curses.h>
void quit_menu(void *arg)
{
endwin();
exit(1);
}
void printf_menu(void *arg)
{
endwin();
printf("hello world\n");
sleep(1);
exit(1);
}
void add_dir(void *arg)
{
endpot *news = endpot_add(root.first, "new dir", dir, NULL, NULL);
}
void add_pot(void *arg)
{
endpot *news = endpot_add(root.first, "new pot", pot, NULL, NULL);
endpot_delete(root.first->next);
}
int main(int argc, char *argv[])
{
pendpot file = ADD_DIR(&root, "file");
pendpot edit = ADD_DIR(&root, "edit");
pendpot select = ADD_DIR(&root, "select");
pendpot view = ADD_DIR(&root, "view");
pendpot gototo = ADD_DIR(&root, "goto");
pendpot runs = ADD_DIR(&root, "runs");
pendpot terml = ADD_DIR(&root, "terml");
pendpot help = ADD_DIR(&root, "help");
pendpot quit = ADD_POT(&root, "quit", quit_menu);
pendpot new_file = ADD_DIR(file, "new file");
pendpot open_file = ADD_DIR(file, "open file");
pendpot closef = ADD_DIR(file, "closef");
pendpot new_windows = ADD_DIR(file, "new_windows");
pendpot open_windows = ADD_DIR(file, "open_windows");
pendpot save_file = ADD_DIR(file, "save_file");
pendpot save_all = ADD_DIR(file, "save_all");
pendpot redo = ADD_DIR(edit, "redo");
pendpot copy = ADD_DIR(edit, "copy");
pendpot paste = ADD_DIR(edit, "paste");
pendpot print = ADD_POT(edit, "print", printf_menu);
pendpot add_p = ADD_POT(edit, "add a new pot", add_pot);
pendpot add_d = ADD_POT(edit, "add a new dir", add_dir);
pendpot s_all = ADD_DIR(select, "select all");
pendpot us_all = ADD_DIR(select, "unselect all");
pendpot repalce = ADD_DIR(select, "replace");
pendpot aq = ADD_DIR(select, "problem");
pendpot back = ADD_DIR(gototo, "back to");
pendpot lunch = ADD_DIR(runs, "lunch");
pendpot newterm = ADD_DIR(terml, "new term");
pendpot closterm = ADD_DIR(terml, "close term");
pendpot welcom = ADD_DIR(help, "welcome use");
pendpot doc = ADD_DIR(help, "document");
#ifdef DISPLAY_C
initscr();
noecho();
move(LINES / 2, COLS / 2);
scroll(stdscr);
box(stdscr, '*', '#');
keypad(stdscr, TRUE);
addstr("START MENU DEMO");
move(LINES / 2 + 1, COLS / 2);
int st = baudrate();
mvprintw(LINES / 2 + 1, COLS / 2, "SPEED = %d BPS", st);
refresh();
sleep(1);
#endif
menu_run(file);
#ifdef DISPLAY_C
endwin();
#endif
}
linux上编译的时候需要提前安装curses
可以通过按动键盘上的 a,s,d,w,q,r控制菜单的跳转和执行
源码下载链接 :https://download.youkuaiyun.com/download/myz348/19475444