/**************** A window for a menu ********************/ #include #include #define TOP_MARGIN 4 #define BOT_MARGIN 2 #define INSTR_LINES 2 #define MAXITEMS LINES - INSTR_LINES - TOP_MARGIN - BOT_MARGIN #define SIDE_MARGIN 6 #define LABEL_WIDTH 5 #define bell() printf("\007") #define MIN(a,b) ((a) > (b) ? b : a) #define MAX(a,b) ((a) < (b) ? b : a) typedef char *String; static int y_0 = 3; static int x_0; void clean_up() { clear(); refresh(); fflush(stdin); fflush(stdout); } /* Exit program properly */ void normal_end() { mvcur(0, COLS-1, LINES-1, 0); /* position cursor */ clean_up(); endwin(); /* finish curses */ putchar('\n'); /* position cursor */ } void abnormal_end() { normal_end(); exit(1); } /* items -- array of menu items title -- title of menu dim -- number of items on menu */ WINDOW *setup_menu(int, String items[], String, String); void display_choice(WINDOW *scr, int choice, int old_choice); int menu_select(int dim, String items[], String title, String cook) { int choice, old_choice = 1; char c; WINDOW *menu_scr; if (dim > MAXITEMS) { fprintf(stderr, "too many items on menu\n"); exit(1); } menu_scr = setup_menu(dim, items, title, cook); /* set up menu */ for (;;) { choice = retrieve_choice(dim, old_choice); if ( choice < 0 ) return(old_choice); /* done */ if ( choice != old_choice ) { display_choice(menu_scr, choice, old_choice); old_choice = choice; } } } int retrieve_choice(int total_items, int old_choice) { char c; int choice; while (c = getchar()) { if (c == '\n') return(-1); /* final choice */ if (c == ' ' || c == '+') /* next item */ { choice = old_choice + 1; if (choice > total_items) choice = 1; return(choice); } if (c == '-') /* previous item */ { choice = old_choice - 1; if (choice == 0) choice = total_items; return(choice); } choice = c - '0'; /* 1 thru 9 */ if (choice > total_items || choice > 9) bell(); /* no such choice */ else return(choice); } } void init() { fflush(stdin); fflush(stdout); noecho(); /* terminal will not echo input characters */ crmode(); /* set to cbreak mode */ } int max_length(int dim, String items[]) { int max = 0, len; while (dim-- > 0) { len = strlen(items[dim]); if (len > max) max = len; } return(max); } labeling(WINDOW *scr, int no, int y, int x, int standout_flag) { char label[LABEL_WIDTH]; if (standout_flag) wstandout(scr); /* standout mode begin */ sprintf(label, "(%d)\0", no); /* highlight label */ mvwaddstr(scr, y, x, label); if (standout_flag) wstandend(scr); /* standout mode end */ } void display_choice(WINDOW *scr, int choice, int old_choice) { labeling(scr, old_choice, y_0 + old_choice, x_0, 0); labeling(scr, choice, y_0 + choice, x_0, 1); refresh(); } /* set up menu_scr */ WINDOW *setup_menu(int dim, String items[], String title, String cook) { int tlen, maxlen, i, tx, mid_x, menu_lines, menu_cols; WINDOW *menu_scr; WINDOW *cook_scr; /* compute menu dimensions */ tlen = strlen(title); maxlen = max_length(dim,items) + LABEL_WIDTH; menu_cols = MAX(tlen, maxlen) + 2*SIDE_MARGIN; if (menu_cols > COLS) { fprintf(stderr, "menu items too long.\n"); exit(1); } menu_lines = dim + TOP_MARGIN + BOT_MARGIN; /* establish cook window */ cook_scr = subwin(stdscr,3,menu_cols,0,0); box(cook_scr,'*','*'); /* draw box to form a window */ /* establish menu window */ menu_scr = subwin(stdscr,menu_lines,menu_cols, 4, 0); box(menu_scr,'*','*'); /* draw box to form a window */ /* display title */ mid_x = menu_cols/2; tx = mid_x - (tlen/2); mvwaddstr(cook_scr,1,tx,cook); wstandout(menu_scr); /* standout mode begin */ mvwaddstr(menu_scr,2,tx,title); wstandend(menu_scr); /* standout mode end */ y_0 = 3; /* display all items */ x_0 = MIN(mid_x - maxlen/2, tx); /* x-position for each item */ for(i=1 ; i <= dim ; i++) { labeling(menu_scr, i, y_0+i, x_0, i == 1 ); mvwaddstr(menu_scr, y_0+i, x_0+LABEL_WIDTH, items[i-1]); } /* display fixed instructions */ mvaddstr(LINES-INSTR_LINES, 0, "TYPE A DIGIT, +, - OR TO REACH AN ITEM,"); mvaddstr(LINES-INSTR_LINES+1, 0, " TO FINALIZE CHOICE."); refresh(); return(menu_scr); } main(int argc, String argv[]) { void abnormal_end(void); int choice; initscr(); /* initialize curses */ init(); /* other initializations */ signal(SIGINT, abnormal_end); /* trap signal */ choice = menu_select(argc - 3, argv+3, argv[2], argv[1]); normal_end(); printf("(%d) selected\n", choice); }