/* * Example of using ncurses menu. * * Toggles displaying/hiding menu with F2. * * Menu items are several that just display (fixed) text, plus one to * exit the program. * * Some functions are from "mylib" library; others are are from "ncurses" * and "menu" libraries (and "man 3x foobar" gives more info on foobar()). */ #include #include #include #include #include #include "mylib.h" #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) #define MAX(a, b) ((a) > (b)) ? (a) : (b) #define MENU_KEY KEY_F(2) #define MENU_KEYSTR "F2" #define ENTER '\n' /* * table describing menu options -- names, descriptions, and functions * to be called when option is selected. */ /* functions return true if program should continue, false otherwise */ typedef bool (*OptionFunction)(char *); typedef struct { char *name; char *descr; OptionFunction process_option; } menuoption_t; bool show_selection(char *selection); bool end_pgm(char *unused); menuoption_t menuoptions[] = { { "This", "(this)", show_selection }, { "That", "(that)" , show_selection}, { "The Other", "(the other)", show_selection }, { "One More", "(one more)", show_selection }, { "Exit", "(exit)", end_pgm } }; /* * function declarations */ void center_line(int row, char *text); ITEM ** create_menu_items(menuoption_t menuoptions[], int n_options); WINDOW * create_menu_window(MENU *main_menu); /* * main program */ int main(void) { /* opening stuff */ ncurses_start(); /* create menu items */ int n_options = ARRAY_SIZE(menuoptions); ITEM **mitems = create_menu_items(menuoptions, n_options); /* create menu with its own window */ MENU *main_menu = new_menu(mitems); WINDOW * menu_window = create_menu_window(main_menu); /* add prompt at bottom */ center_line(LINES-2, MENU_KEYSTR" to show/hide menu"); /* main loop */ refresh(); int ch; bool done = false; bool have_menu = false; while (!done) { ch = getch(); switch(ch) { case MENU_KEY: /* toggle menu window (display/not) */ if (have_menu) { unpost_menu(main_menu); have_menu = false; wrefresh(menu_window); refresh(); } else { have_menu = true; post_menu(main_menu); wrefresh(menu_window); refresh(); } break; case 'j': case KEY_DOWN: /* move down in menu */ if (have_menu) { menu_driver(main_menu, REQ_DOWN_ITEM); wrefresh(menu_window); } break; case 'k': case KEY_UP: /* move up in menu */ if (have_menu) { menu_driver(main_menu, REQ_UP_ITEM); wrefresh(menu_window); } break; case ENTER: /* execute function for current item */ if (have_menu) { ITEM *cur = current_item(main_menu); OptionFunction *ptr_to_fcnp = item_userptr(cur); done = !((*ptr_to_fcnp)( (char *) item_description(cur))); } break; } } /* clean up and exit */ for (int i = 0; i < n_options; ++i) { free_item(mitems[i]); } free_menu(main_menu); delwin(menu_window); ncurses_end(); return EXIT_SUCCESS; } /* * Print text in center of line. */ void center_line(int row, char *text) { /* clear line first */ mvprintw(row, 0, ""); clrtoeol(); /* display text */ mvprintw(row, (COLS-strlen(text))/2, "%s", text); } /* * Function to be called for most menu items -- display text in center * of screen. */ bool show_selection(char *selection) { center_line(LINES/2, selection); return true; } /* * Function to be called for "exit" menu item -- indicate that the program * should not continue. */ bool end_pgm(char *unused) { return false; } /* * Create menu items. */ ITEM ** create_menu_items(menuoption_t menuoptions[], int n_options) { ITEM **mitems = malloc((n_options + 1) * sizeof(mitems[0])); if (mitems == NULL) { fprintf(stderr, "not enough memory\n"); exit(EXIT_FAILURE); } for (int i = 0; i < n_options; ++i) { /* make menu item */ mitems[i] = new_item(menuoptions[i].name, menuoptions[i].descr); /* set userptr to point to function to execute for this option */ set_item_userptr(mitems[i], &menuoptions[i].process_option); } /* menu library wants null-terminated array */ mitems[n_options] = NULL; return mitems; } /* * Create window for menu. */ WINDOW * create_menu_window(MENU * main_menu) { /* find maximum size of text for menu items */ ITEM **mitems = menu_items(main_menu); int name_cols = 0; /* maximum width of menu names */ for (int i = 0; i < item_count(main_menu); ++i) { name_cols = MAX(name_cols, strlen(item_name(mitems[i]))); } int descr_cols = 0; /* maximum width of menu names */ for (int i = 0; i < item_count(main_menu); ++i) { descr_cols = MAX(descr_cols, strlen(item_description(mitems[i]))); } /* make menu window */ char *marker = "*"; WINDOW * menu_window = newwin( item_count(main_menu), strlen(marker) + name_cols + 1 + descr_cols, 0, 0); set_menu_win(main_menu, menu_window); set_menu_mark(main_menu, marker); box(menu_window, 0, 0); return menu_window; }