/* The original version of this program can be found at http://damb.dk */
#include <curses.h>
#include <stdlib.h>
enum VirtKeys
{
VK_RETURN = 10,
VK_UP = 65 | 0x100,
VK_DOWN = 66 | 0x100
};
/* This is an key element, it contains elements needed to handle one menu or submen item */
/* Each item has a text (title) and a associated function OR submenu */
/* If both function AND submenu are NULL we will jump one level up */
/* So our menu structure will be build as a tree of these */
typedef struct menu_item
{
const char *title;
struct menu_item const *submenu;
void(*function)(void);
}menu_item;
WINDOW *StatusWin;
WINDOW *MenuWin;
#define NORM_ATTR A_NORMAL
#define INVR_ATTR A_STANDOUT
#define EMPTY_LINE " "
void text_out(WINDOW *win, int attr, int x, int y, const char *text)
{
while(*text)
{
wmove(win, y, x++);
waddch(win, attr | *text);
text++;
}
wrefresh(win);
}
void show_status(const char *msg)
{
wclear(StatusWin);
text_out(StatusWin, NORM_ATTR, 1, 1, msg);
}
int get_key(void)
{
int i = getch();
if(i == 27)
{ /* Special keys return three values, 27 + 91 + the real key */
if(getch() == 91)
return getch() | 0x100; /* To let the receiver know a VK_UP from a 'A' */
}
return i;
}
#define DUMMY_FUNC(name) \
static void name(void) \
{ \
show_status(#name); \
}
DUMMY_FUNC(func_11)
DUMMY_FUNC(func_21)
DUMMY_FUNC(func_22)
DUMMY_FUNC(func_231)
DUMMY_FUNC(func_232)
DUMMY_FUNC(func_233)
void exit_func(void)
{
exit(0);
}
/* These are the menu's, will have to start from the buttom */
menu_item const pb_list_menu[] =
{
{"Ole", NULL, func_231},
{"Peter", NULL, func_232},
{"Poul", NULL, func_233},
{"Back", NULL, NULL},
{NULL, NULL, NULL}
};
menu_item const phonebook_menu[] =
{
{"AddEntry", NULL, func_11},
{"List", pb_list_menu, NULL},
{"Back", NULL, NULL},
{NULL, NULL, NULL}
};
menu_item const sub_menu_2[] =
{
{"New SMS", NULL, func_21},
{"List", NULL, func_22},
{"Back", NULL, NULL},
{NULL, NULL, NULL}
};
menu_item const main_menu[] =
{
{"PhoneBook", phonebook_menu, NULL},
{"SMS", sub_menu_2, NULL},
{"Exit", NULL, exit_func},
{NULL, NULL, NULL}
};
void exec(menu_item const * menu);
void clear_menu_window(void)
{
wclear(MenuWin);
box(MenuWin, ACS_VLINE, ACS_HLINE);
}
int main(void)
{
initscr();
cbreak();
noecho();
intrflush(stdscr, FALSE);
MenuWin = subwin(stdscr, 10, 20, 1, 1);
StatusWin = subwin(stdscr, 2, 60, 20, 1);
intrflush(MenuWin, FALSE);
wcolor_set(MenuWin, 3, 0);
box(MenuWin, ACS_VLINE, ACS_HLINE);
show_status("Simple menu demo Press UP/Down, Enter to select");
exec(main_menu);
return EXIT_SUCCESS;
}
/* This is the main menu executer, it will call itself to execute submenus */
void exec(menu_item const * menu)
{
int ch;
int i;
int state = 0;
clear_menu_window();
do
{
/* I'm lazy so I'll update the complete menu each time */
for(i = 0; menu[i].title; i++)
{
if(i == state)
text_out(MenuWin, INVR_ATTR, 1, i + 1, menu[i].title);
else
text_out(MenuWin, NORM_ATTR, 1, i + 1, menu[i].title);
}
ch = get_key();
switch(ch)
{
case VK_RETURN: /* Enter */
if(menu[state].function)
menu[state].function();
else if(menu[state].submenu)
{ /* It's a submenu */
exec(menu[state].submenu);
clear_menu_window();
}
else
{ /* It is a back menu item */
return;
}
break;
case VK_UP:
if(state != 0)
state--;
break;
case VK_DOWN:
if(menu[state + 1].title)
state++;
break;
}
}
while(1);
}