2 * Generic menu system module.
4 * Basically, we define an enormous tree structure which represents the
5 * menu. Some extra pieces (ml_command, ma_doc) get thrown in so we can
6 * also use the structure for a command-based system.
8 * By making the menu descriptions so general, we can ease porting to just
16 #define MAX(A,B) ((A) > (B) ? (A) : (B))
17 #define MIN(A,B) ((A) < (B) ? (A) : (B))
19 #define MIN_INPUT 2 /* Minimum number of lines for input window */
21 /* Structure for holding current displayed menu */
23 WINDOW *ms_screen; /* Window for this menu */
24 WINDOW *ms_title; /* Title subwindow */
25 WINDOW *ms_menu; /* Menu subwindow */
26 WINDOW *ms_input; /* Input subwindow */
27 int ms_input_y; /* Input subwindow reference coordinate */
31 * Start_menu takes a menu as an argument. It initializes curses u.s.w.,
32 * and a quit in any submenu should unwind back to here. (it might not,
33 * if user functions which run their own menus don't cooperate.)
34 * Start_menu should only be called once, at the start of the program.
39 if(initscr() == ERR) {
40 fputs("Can't initialize curses!\n", stderr);
43 raw(); /* We parse & print everything ourselves */
45 Do_menu(m); /* Run the menu */
50 * Create a new menu screen template with the specified menu length
53 struct menu_screen *make_ms(length)
56 struct menu_screen *ms;
59 if(MAX_TITLE + length + MIN_INPUT > LINES) {
60 fputs("Menu too big!\n", stderr);
64 ms = (struct menu_screen *) malloc(sizeof(struct menu_screen));
66 ms->ms_screen = newwin(0, 0, 0, 0);
67 ms->ms_title = subwin(ms->ms_screen, MAX_TITLE, 0, 0, 0);
68 ms->ms_menu = subwin(ms->ms_screen,
69 length, 0, MAX_TITLE, 0);
70 ms->ms_input = subwin(ms->ms_screen, 0, 0,
71 ms->ms_input_y = MAX_TITLE + length,
74 scrollok(ms->ms_input, TRUE);
75 wmove(ms->ms_input, 0, 0);
76 wclear(ms->ms_screen);
82 * This routine destroys a menu_screen.
85 struct menu_screen *ms;
90 delwin(ms->ms_screen);
95 * This guy actually puts up the menu
100 struct menu_screen *my_ms, *old_cur_ms;
101 char argvals[MAX_ARGC][MAX_ARGLEN]; /* This is where args are stored */
102 char *argv[MAX_ARGC];
107 /* Initialize argv */
108 for(argc = 0; argc < MAX_ARGC; argc++) argv[argc] = argvals[argc];
110 /* Entry function gets called with old menu_screen still current */
111 if(m->m_entry != NULLFUNC) m->m_entry(m);
113 /* Get a menu_screen */
115 cur_ms = my_ms = make_ms(m->m_length + 2);
117 /* Now print the title and the menu */
118 wmove(my_ms->ms_title, 0, MAX(0, (COLS - strlen(m->m_title))>>1));
119 wstandout(my_ms->ms_title);
120 waddstr(my_ms->ms_title, m->m_title);
121 wstandend(my_ms->ms_title);
123 for(line = 0; line < m->m_length; line++) {
124 wmove(my_ms->ms_menu, line, 0);
125 wprintw(my_ms->ms_menu, "%2d. (%-8s) %s.", line+1,
126 m->m_lines[line].ml_command,
127 m->m_lines[line].ml_doc);
129 wmove(my_ms->ms_menu, line++, 0);
130 waddstr(my_ms->ms_menu, " r. (return ) Return to previous menu.");
131 wmove(my_ms->ms_menu, line, 0);
132 waddstr(my_ms->ms_menu, " q. (quit ) Quit.");
136 /* This will be set by a return val from func or submenu */
137 quitflag = DM_NORMAL;
139 Prompt_input("Command: ", argvals[0], sizeof(argvals[0]));
140 /* See if it matches anything (this is kind of dumb, for now) */
141 if((line = atoi(argvals[0])) > 0 && line <= m->m_length) {
143 /* Send the command into the argv */
144 strcpy(argvals[0], m->m_lines[line].ml_command);
145 /* Show that we're working on it */
146 Put_message(m->m_lines[line].ml_doc);
147 /* Get arguments, if any */
148 for(argc = 1; argc < m->m_lines[line].ml_argc; argc++) {
149 Prompt_input(m->m_lines[line].ml_args[argc].ma_prompt,
150 argvals[argc], sizeof(argvals[argc]));
152 if(m->m_lines[line].ml_function != NULLFUNC) {
153 /* If it's got a function, call it */
154 quitflag = m->m_lines[line].ml_function(argv, argc);
155 } else if(m->m_lines[line].ml_submenu != NULLMENU) {
156 /* Else see if it is a submenu */
157 quitflag = Do_menu(m->m_lines[line].ml_submenu);
159 /* If it's got neither, something is wrong */
160 Put_message("*INTERNAL ERROR: NO FUNCTION OR MENU FOR LINE*");
162 } else if(!strcmp(argv[0], "r") || !strcmp(argv[0], "q")) {
163 /* here if it's either return or quit */
166 if(m->m_exit != NULLFUNC) m->m_exit(m);
167 return(*argv[0] == 'r' ? DM_NORMAL : DM_QUIT);
169 /* Couldn't find it, give up */
170 Put_message("Command not recognized");
171 continue; /* No good */
173 if(quitflag == DM_QUIT) {
176 if(m->m_exit != NULLFUNC) m->m_exit(m);
182 /* Prompt the user for input in the input window of cur_ms */
183 Prompt_input(prompt, buf, buflen)
192 waddstr(cur_ms->ms_input, prompt);
193 getyx(cur_ms->ms_input, y, x);
195 for (p = buf; p - buf < buflen; ) {
196 wmove(cur_ms->ms_input, y, x);
197 wclrtoeol(cur_ms->ms_input);
202 touchwin(cur_ms->ms_screen);
204 case '\n': case '\r':
205 waddch(cur_ms->ms_input, '\n');
215 case 'U' & 037: case '\007': case '\033':
219 waddch(cur_ms->ms_input, c);
227 /* Print a message in the input window of cur_ms */
231 wprintw(cur_ms->ms_input, "%s\n", msg);
235 /* Refresh a menu_screen onto the real screen */
237 struct menu_screen *ms;
241 getyx(ms->ms_input, y, x);
242 wmove(ms->ms_screen, y + ms->ms_input_y, x);
243 touchwin(ms->ms_screen);
244 wrefresh(ms->ms_screen);