menu_sys.def revision 1.6 1 /* $NetBSD: menu_sys.def,v 1.6 1998/06/24 14:44:52 phil Exp $ */
2
3 /*
4 * Copyright 1997 Piermont Information Systems Inc.
5 * All rights reserved.
6 *
7 * Written by Philip A. Nelson for Piermont Information Systems Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software develooped for the NetBSD Project by
20 * Piermont Information Systems Inc.
21 * 4. The name of Piermont Information Systems Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
35 * THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 */
38
39 /* menu_sys.defs -- Menu system standard routines. */
40
41 #include <string.h>
42 #include <ctype.h>
43
44 #define REQ_EXECUTE 1000
45 #define REQ_NEXT_ITEM 1001
46 #define REQ_PREV_ITEM 1002
47 #define REQ_REDISPLAY 1003
48
49 #define KEYPAD_DOWN_ARROW 256
50 #define KEYPAD_UP_ARROW 257
51
52 #define MAX(x,y) ((x)>(y)?(x):(y))
53
54 /* Initialization state. */
55 static int __menu_init = 0;
56 int __m_endwin = 0;
57 static int max_lines = 0;
58
59 /* prototypes for in here! */
60
61 static void init_menu (struct menudesc *m);
62 static void post_menu (struct menudesc *m);
63 static void process_help (struct menudesc *m, int num);
64 static void process_req (struct menudesc *m, int num, int req);
65 static void mbeep (void);
66 static int menucmd (WINDOW *w);
67
68 #ifndef NULL
69 #define NULL (void *)0
70 #endif
71
72 /* menu system processing routines */
73
74 static void mbeep (void)
75 {
76 fprintf (stderr,"\a");
77 }
78
79 static int mgetch(WINDOW *w)
80 {
81 static char buf[20];
82 static int num = 0;
83
84 int i, ret;
85
86 for (i=0; i< strlen(KD); i++) {
87 if (i >= num)
88 buf[num++] = wgetch(w);
89 if (buf[i] != KD[i])
90 break;
91 }
92 if (i == strlen(KD)) {
93 num = 0;
94 return KEYPAD_DOWN_ARROW;
95 }
96
97 for (i=0; i< strlen(KU); i++) {
98 if (i >= num)
99 buf[num++] = wgetch(w);
100 if (buf[i] != KU[i])
101 break;
102 }
103 if (i == strlen(KU)) {
104 num = 0;
105 return KEYPAD_UP_ARROW;
106 }
107
108 ret = buf[0];
109 for (i = 0; i < strlen(buf); i++)
110 buf[i] = buf[i+1];
111 num--;
112 return ret;
113 }
114
115 static int menucmd (WINDOW *w)
116 {
117 int ch;
118
119 while (TRUE) {
120 ch = mgetch(w);
121
122 switch (ch) {
123 case '\n':
124 return REQ_EXECUTE;
125 case '\016':
126 case KEYPAD_DOWN_ARROW:
127 return REQ_NEXT_ITEM;
128 case '\020':
129 case KEYPAD_UP_ARROW:
130 return REQ_PREV_ITEM;
131 case '\014':
132 return REQ_REDISPLAY;
133 }
134
135 if (isalpha(ch) || ch == '?')
136 return (ch);
137
138 mbeep();
139 wrefresh(w);
140 }
141 }
142
143 static void init_menu (struct menudesc *m)
144 {
145 int max;
146 char **p;
147 int add=4;
148
149 if (m->mopt & NOBOX)
150 add = 2;
151
152 max = strlen(m->title);
153
154 /* Calculate h? */
155 if (m->h == 0) {
156 m->h = m->numopts + ((m->mopt & NOEXITOPT) ? 0 : 1)
157 - (max ? 0 : 2);
158 }
159
160
161 /* Calculate w? */
162 if (m->w == 0) {
163 p = m->opts;
164 while (*p) {
165 max = MAX(max,strlen(*p));
166 p++;
167 }
168 m->w = max;
169 }
170
171 /* Get the windows. */
172 m->mw = newwin(m->h+add, m->w+add, m->y, m->x);
173
174 if (m->mw == NULL) {
175 endwin();
176 (void) fprintf (stderr,
177 "Could not create window for window with title "
178 " \"%s\"\n", m->title);
179 exit(1);
180 }
181 }
182
183 static void post_menu (struct menudesc *m)
184 {
185 int i;
186 int hasbox, cury;
187 int tadd;
188
189 if (m->mopt & NOBOX) {
190 cury = 0;
191 hasbox = 0;
192 } else {
193 cury = 1;
194 hasbox = 1;
195 }
196
197 tadd = strlen(m->title) ? 2 : 0;
198
199 if (tadd) {
200 mvwaddstr(m->mw, cury, cury, m->title);
201 cury += 2;
202 }
203
204 for (i=0; i<m->numopts; i++, cury++) {
205 if (m->cursel == i) {
206 mvwaddstr (m->mw, cury, hasbox, ">");
207 wstandout(m->mw);
208 } else
209 mvwaddstr (m->mw, cury, hasbox, " ");
210 waddstr (m->mw, m->opts[i]);
211 if (m->cursel == i)
212 wstandend(m->mw);
213 }
214 if (!(m->mopt & NOEXITOPT))
215 mvwaddstr (m->mw, cury, hasbox, " x: Exit");
216
217 if (!(m->mopt & NOBOX))
218 box(m->mw, '*', '*');
219
220 wmove(m->mw,tadd+hasbox+m->cursel, hasbox);
221 }
222
223 static void process_help (struct menudesc *m, int num)
224 {
225 char *help = m->helpstr;
226 int lineoff = 0;
227 int curoff = 0;
228 int again;
229 int winin;
230
231 /* Is there help? */
232 if (!help) {
233 mbeep();
234 return;
235 }
236
237 /* Display the help information. */
238 do {
239 if (lineoff < curoff) {
240 help = m->helpstr;
241 curoff = 0;
242 }
243 while (*help && curoff < lineoff) {
244 if (*help == '\n')
245 curoff++;
246 help++;
247 }
248
249 wclear(stdscr);
250 mvwaddstr (stdscr, 0, 0,
251 "Help: exit: q, page up: u <, page down: d >");
252 mvwaddstr (stdscr, 2, 0, help);
253 wmove (stdscr, 1, 0);
254 wrefresh(stdscr);
255
256 do {
257 winin = mgetch(stdscr);
258 winin = tolower(winin);
259 again = 0;
260 switch (winin) {
261 case '<':
262 case 'u':
263 case KEYPAD_UP_ARROW:
264 if (lineoff)
265 lineoff -= max_lines - 2;
266 break;
267 case '>':
268 case 'd':
269 case KEYPAD_DOWN_ARROW:
270 if (*help)
271 lineoff += max_lines - 2;
272 break;
273 case 'q':
274 break;
275 default:
276 again = 1;
277 }
278 } while (again);
279 } while (winin != 'q');
280
281 /* Restore current menu */
282 wclear(stdscr);
283 wrefresh(stdscr);
284 process_item (&num, -2);
285 post_menu (m);
286 wrefresh (m->mw);
287 }
288
289 static void process_req (struct menudesc *m, int num, int req)
290 {
291 int ch;
292 int lastsel = m->cursel;
293 int hasexit = (m->mopt & NOEXITOPT ? 0 : 1 );
294 int hasbox = (m->mopt & NOBOX ? 0 : 1);
295 int tadd = strlen(m->title) ? 2 : 0;
296
297 if (req == REQ_EXECUTE)
298 return;
299 else if (req == REQ_NEXT_ITEM) {
300 if (m->cursel < m->numopts + hasexit - 1)
301 m->cursel++;
302 else
303 mbeep();
304 } else if (req == REQ_PREV_ITEM) {
305 if (m->cursel > 0)
306 m->cursel--;
307 else
308 mbeep();
309
310 } else if (req == REQ_REDISPLAY) {
311 wclear(stdscr);
312 wrefresh(stdscr);
313 process_item (&num, -2);
314 post_menu (m);
315 wrefresh (m->mw);
316
317 } else if (req == '?') {
318 process_help (m, num);
319 } else {
320 ch = tolower (req);
321 if (ch == 'x' && hasexit)
322 m->cursel = m->numopts;
323 else {
324 ch = ch - 'a';
325 if (ch < 0 || ch >= m->numopts)
326 mbeep();
327 else
328 m->cursel = ch;
329 }
330 }
331 if (m->cursel != lastsel) {
332 mvwaddstr (m->mw, lastsel+tadd+hasbox, hasbox, " ");
333 if (lastsel < m->numopts)
334 waddstr (m->mw, m->opts[lastsel]);
335 else
336 waddstr (m->mw, "x: Exit");
337 mvwaddstr (m->mw, m->cursel+tadd+hasbox, hasbox, ">");
338 wstandout(m->mw);
339 if (m->cursel < m->numopts)
340 waddstr (m->mw, m->opts[m->cursel]);
341 else
342 waddstr (m->mw, "x: Exit");
343 wstandend(m->mw);
344 wmove(m->mw,tadd+hasbox+m->cursel, hasbox);
345 wrefresh(m->mw);
346 }
347 }
348
349 void process_menu (int num)
350 {
351 int sel = 0;
352 int req, done;
353 int last_num;
354
355 struct menudesc *m = &menus[num];
356
357 done = FALSE;
358
359 /* Initialize? */
360 if (!__menu_init) {
361 if (initscr() == NULL) {
362 __menu_initerror();
363 return;
364 }
365 cbreak();
366 noecho();
367 max_lines = stdscr->maxy;
368 __menu_init = 1;
369 }
370 if (__m_endwin) {
371 wclear(stdscr);
372 wrefresh(stdscr);
373 __m_endwin = 0;
374 }
375 if (m->mw == NULL)
376 init_menu (m);
377
378 /* Always preselect 0! */
379 m->cursel = 0;
380
381 while (!done) {
382 last_num = num;
383 if (__m_endwin) {
384 wclear(stdscr);
385 wrefresh(stdscr);
386 __m_endwin = 0;
387 }
388 /* Process the display action */
389 process_item (&num, -2);
390 post_menu (m);
391 wrefresh (m->mw);
392
393 while ((req = menucmd (m->mw)) != REQ_EXECUTE)
394 process_req (m, num, req);
395
396 sel = m->cursel;
397 wclear (m->mw);
398 wrefresh (m->mw);
399
400 /* Process the items */
401 if (sel < m->numopts)
402 done = process_item (&num, sel);
403 else
404 done = TRUE;
405
406 /* Reselect m just in case */
407 if (num != last_num) {
408 m = &menus[num];
409 /* Initialize? */
410 if (m->mw == NULL)
411 init_menu (m);
412 process_item (&num, -2);
413 }
414 }
415
416 /* Process the exit action */
417 process_item (&num, -1);
418 }
419