ncurses 5.1
[ncurses.git] / tack / menu.c
1 /*
2 ** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
3 ** 
4 ** This file is part of TACK.
5 ** 
6 ** TACK is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License as published by
8 ** the Free Software Foundation; either version 2, or (at your option)
9 ** any later version.
10 ** 
11 ** TACK is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 ** GNU General Public License for more details.
15 ** 
16 ** You should have received a copy of the GNU General Public License
17 ** along with TACK; see the file COPYING.  If not, write to
18 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 ** Boston, MA 02111-1307, USA.
20 */
21
22 #include <tack.h>
23
24 MODULE_ID("$Id: menu.c,v 1.2 2000/03/04 21:13:53 tom Exp $")
25
26 /*
27    Menu control
28  */
29
30 static void test_byname(struct test_menu *, int *, int *);
31
32 struct test_list *augment_test;
33 char prompt_string[80]; /* menu prompt storage */
34
35 /*
36 **      menu_prompt()
37 **
38 **      Print the menu prompt string.
39 */
40 void
41 menu_prompt(void)
42 {
43         ptext(&prompt_string[1]);
44 }
45
46 /*
47 **      menu_test_loop(test-structure, state, control-character)
48 **
49 **      This function implements the repeat test function.
50 */
51 static void
52 menu_test_loop(
53         struct test_list *test,
54         int *state,
55         int *ch)
56 {
57         int nch, p;
58
59         if ((test->flags & MENU_REP_MASK) && (augment_test != test)) {
60                 /* set the augment variable (first time only) */
61                 p = (test->flags >> 8) & 15;
62                 if ((test->flags & MENU_REP_MASK) == MENU_LM1) {
63                         augment = lines - 1;
64                 } else
65                 if ((test->flags & MENU_ONE_MASK) == MENU_ONE) {
66                         augment = 1;
67                 } else
68                 if ((test->flags & MENU_LC_MASK) == MENU_lines) {
69                         augment = lines * p / 10;
70                 } else
71                 if ((test->flags & MENU_LC_MASK) == MENU_columns) {
72                         augment = columns * p / 10;
73                 } else {
74                         augment = 1;
75                 }
76                 augment_test = test;
77                 set_augment_txt();
78         }
79         do {
80                 if ((test->flags | *state) & MENU_CLEAR) {
81                         put_clear();
82                 } else
83                 if (line_count + test->lines_needed >= lines) {
84                         put_clear();
85                 }
86                 nch = 0;
87                 if (test->test_procedure) {
88                         /* The procedure takes precedence so I can pass
89                            the menu entry as an argument.
90                         */
91                         can_test(test->caps_done, FLAG_TESTED);
92                         can_test(test->caps_tested, FLAG_TESTED);
93                         test->test_procedure(test, state, &nch);
94                 } else
95                 if (test->sub_menu) {
96                         /* nested menu's */
97                         menu_display(test->sub_menu, &nch);
98                         *state = 0;
99                         if (nch == 'q' || nch == 's') {
100                                 /* Quit and skip are killed here */
101                                 nch = '?';
102                         }
103                 } else {
104                         break;  /* cya */
105                 }
106                 if (nch == '\r' || nch == '\n' || nch == 'n') {
107                         nch = 0;
108                         break;
109                 }
110         } while (nch == 'r');
111         *ch = nch;
112 }
113
114 /*
115 **      menu_display(menu-structure, flags)
116 **
117 **      This function implements menu control.
118 */
119 void
120 menu_display(
121         struct test_menu *menu,
122         int *last_ch)
123 {
124         int test_state = 0, run_standard_tests;
125         int hot_topic, ch = 0, nch = 0;
126         struct test_list *mt;
127         struct test_list *repeat_tests = 0;
128         int repeat_state = 0;
129         int prompt_length;
130
131         prompt_length = strlen(prompt_string);
132         if (menu->ident) {
133                 sprintf(&prompt_string[prompt_length], "/%s", menu->ident);
134         }
135         hot_topic = menu->default_action;
136         run_standard_tests = menu->standard_tests ?
137                 menu->standard_tests[0] : -1;
138         if (!last_ch) {
139                 last_ch = &ch;
140         }
141         while (1) {
142                 if (ch == 0) {
143                         /* Display the menu */
144                         put_crlf();
145                         if (menu->menu_function) {
146                                 /*
147                                    this function may be used to restrict menu
148                                    entries.  If used it must print the title.
149                                 */
150                                 menu->menu_function(menu);
151                         } else
152                         if (menu->menu_title) {
153                                 ptextln(menu->menu_title);
154                         }
155                         for (mt = menu->tests; (mt->flags & MENU_LAST) == 0; mt++) {
156                                 if (mt->menu_entry) {
157                                         ptext(" ");
158                                         ptextln(mt->menu_entry);
159                                 }
160                         }
161                         if (menu->standard_tests) {
162                                 ptext(" ");
163                                 ptextln(menu->standard_tests);
164                                 ptextln(" r) repeat test");
165                                 ptextln(" s) skip to next test");
166                         }
167                         ptextln(" q) quit");
168                         ptextln(" ?) help");
169                 }
170                 if (ch == 0 || ch == REQUEST_PROMPT) {
171                         put_crlf();
172                         ptext(&prompt_string[1]);
173                         if (hot_topic) {
174                                 ptext(" [");
175                                 putchp(hot_topic);
176                                 ptext("]");
177                         }
178                         ptext(" > ");
179                         /* read a character */
180                         ch = wait_here();
181                 }
182                 if (ch == '\r' || ch == '\n') {
183                         ch = hot_topic;
184                 }
185                 if (ch == 'q') {
186                         break;
187                 }
188                 if (ch == '?') {
189                         ch = 0;
190                         continue;
191                 }
192                 nch = ch;
193                 ch = 0;
194                 /* Run one of the standard tests (by request) */
195                 for (mt = menu->tests; (mt->flags & MENU_LAST) == 0; mt++) {
196                         if (mt->menu_entry && (nch == mt->menu_entry[0])) {
197                                 if (mt->flags & MENU_MENU) {
198                                         test_byname(menu, &test_state, &nch);
199                                 } else {
200                                         menu_test_loop(mt, &test_state, &nch);
201                                 }
202                                 ch = nch;
203                                 if ((mt->flags & MENU_COMPLETE) && ch == 0) {
204                                         /* top level */
205                                         hot_topic = 'q';
206                                         ch = '?';
207                                 }
208                         }
209                 }
210                 if (menu->standard_tests && nch == 'r') {
211                         menu->resume_tests = repeat_tests;
212                         test_state = repeat_state;
213                         nch = run_standard_tests;
214                 }
215                 if (nch == run_standard_tests) {
216                         if (!(mt = menu->resume_tests)) {
217                                 mt = menu->tests;
218                         }
219                         if (mt->flags & MENU_LAST) {
220                                 mt = menu->tests;
221                         }
222                         /* Run the standard test suite */
223                         for ( ; (mt->flags & MENU_LAST) == 0; ) {
224                                 if ((mt->flags & MENU_NEXT) == MENU_NEXT) {
225                                         repeat_tests = mt;
226                                         repeat_state = test_state;
227                                         nch = run_standard_tests;
228                                         menu_test_loop(mt, &test_state, &nch);
229                                         if (nch != 0 && nch != 'n') {
230                                                 ch = nch;
231                                                 break;
232                                         }
233                                         if (test_state & MENU_STOP) {
234                                                 break;
235                                         }
236                                 }
237                                 mt++;
238                         }
239                         if (ch == 0) {
240                                 ch = hot_topic;
241                         }
242                         menu->resume_tests = mt;
243                         menu->resume_state = test_state;
244                         menu->resume_char = ch;
245
246                         if (ch == run_standard_tests) {
247                                 /* pop up a level */
248                                 break;
249                         }
250                 }
251         }
252         *last_ch = ch;
253         prompt_string[prompt_length] = '\0';
254 }
255
256 /*
257 **      generic_done_message(test_list)
258 **
259 **      Print the Done message and request input.
260 */
261 void
262 generic_done_message(
263         struct test_list *test,
264         int *state,
265         int *ch)
266 {
267         char done_message[128];
268
269         if (test->caps_done) {
270                 sprintf(done_message, "(%s) Done ", test->caps_done);
271                 ptext(done_message);
272         } else {
273                 ptext("Done ");
274         }
275         *ch = wait_here();
276         if (*ch == '\r' || *ch == '\n' || *ch == 'n') {
277                 *ch = 0;
278         }
279         if (*ch == 's') {
280                 *state |= MENU_STOP;
281                 *ch = 0;
282         }
283 }
284
285 /*
286 **      menu_clear_screen(test, state, ch)
287 **
288 **      Just clear the screen.
289 */
290 void
291 menu_clear_screen(
292         struct test_list *test GCC_UNUSED,
293         int *state GCC_UNUSED,
294         int *ch GCC_UNUSED)
295 {
296         put_clear();
297 }
298
299 /*
300 **      menu_reset_init(test, state, ch)
301 **
302 **      Send the reset and init strings.
303 */
304 void
305 menu_reset_init(
306         struct test_list *test GCC_UNUSED,
307         int *state GCC_UNUSED,
308         int *ch GCC_UNUSED)
309 {
310         reset_init();
311         put_crlf();
312 }
313
314 /*
315 **      subtest_menu(test, state, ch)
316 **
317 **      Scan the menu looking for something to execute
318 **      Return TRUE if we found anything.
319 */
320 int
321 subtest_menu(
322         struct test_list *test,
323         int *state,
324         int *ch)
325 {
326         struct test_list *mt;
327
328         if (*ch) {
329                 for (mt = test; (mt->flags & MENU_LAST) == 0; mt++) {
330                         if (mt->menu_entry && (*ch == mt->menu_entry[0])) {
331                                 *ch = 0;
332                                 menu_test_loop(mt, state, ch);
333                                 return TRUE;
334                         }
335                 }
336         }
337         return FALSE;
338 }
339
340 /*
341 **      menu_can_scan(menu-structure)
342 **
343 **      Recursively scan the menu tree and find which cap names can be tested.
344 */
345 void
346 menu_can_scan(
347         const struct test_menu *menu)
348 {
349         struct test_list *mt;
350
351         for (mt = menu->tests; (mt->flags & MENU_LAST) == 0; mt++) {
352                 can_test(mt->caps_done, FLAG_CAN_TEST);
353                 can_test(mt->caps_tested, FLAG_CAN_TEST);
354                 if (!(mt->test_procedure)) {
355                         if (mt->sub_menu) {
356                                 menu_can_scan(mt->sub_menu);
357                         }
358                 }
359         }
360 }
361
362 /*
363 **      menu_search(menu-structure, cap)
364 **
365 **      Recursively search the menu tree and execute any tests that use cap.
366 */
367 static void
368 menu_search(
369         struct test_menu *menu,
370         int *state,
371         int *ch,
372         char *cap)
373 {
374         struct test_list *mt;
375         int nch;
376
377         for (mt = menu->tests; (mt->flags & MENU_LAST) == 0; mt++) {
378                 nch = 0;
379                 if (cap_match(mt->caps_done, cap)
380                         || cap_match(mt->caps_tested, cap)) {
381                         menu_test_loop(mt, state, &nch);
382                 }
383                 if (!(mt->test_procedure)) {
384                         if (mt->sub_menu) {
385                                 menu_search(mt->sub_menu, state, &nch, cap);
386                         }
387                 }
388                 if (*state & MENU_STOP) {
389                         break;
390                 }
391                 if (nch != 0 && nch != 'n') {
392                         *ch = nch;
393                         break;
394                 }
395         }
396 }
397
398 /*
399 **      test_byname(menu, state, ch)
400 **
401 **      Get a cap name then run all tests that use that cap.
402 */
403 static void
404 test_byname(
405         struct test_menu *menu,
406         int *state GCC_UNUSED,
407         int *ch)
408 {
409         int test_state = 0;
410         char cap[32];
411
412         if (tty_can_sync == SYNC_NOT_TESTED) {
413                 verify_time();
414         }
415         ptext("enter name: ");
416         read_string(cap, sizeof(cap));
417         if (cap[0]) {
418                 menu_search(menu, &test_state, ch, cap);
419         }
420         *ch = '?';
421 }