menu_sys.def revision 1.5 1 /* $NetBSD: menu_sys.def,v 1.5 1998/06/24 06:46:24 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 do {
232 if (lineoff < curoff) {
233 help = m->helpstr;
234 curoff = 0;
235 }
236 while (*help && curoff < lineoff) {
237 if (*help == '\n')
238 curoff++;
239 help++;
240 }
241
242 wclear(stdscr);
243 mvwaddstr (stdscr, 0, 0,
244 "Help: exit: q, page up: u <, page down: d >");
245 mvwaddstr (stdscr, 2, 0, help);
246 wmove (stdscr, 1, 0);
247 wrefresh(stdscr);
248
249 do {
250 winin = mgetch(stdscr);
251 winin = tolower(winin);
252 again = 0;
253 switch (winin) {
254 case '<':
255 case 'u':
256 case KEYPAD_UP_ARROW:
257 if (lineoff)
258 lineoff -= max_lines - 2;
259 break;
260 case '>':
261 case 'd':
262 case KEYPAD_DOWN_ARROW:
263 if (*help)
264 lineoff += max_lines - 2;
265 break;
266 case 'q':
267 break;
268 default:
269 again = 1;
270 }
271 } while (again);
272 } while (winin != 'q');
273
274 /* Restore current menu */
275 wclear(stdscr);
276 wrefresh(stdscr);
277 process_item (&num, -2);
278 post_menu (m);
279 wrefresh (m->mw);
280 }
281
282 static void process_req (struct menudesc *m, int num, int req)
283 {
284 int ch;
285 int lastsel = m->cursel;
286 int hasexit = (m->mopt & NOEXITOPT ? 0 : 1 );
287 int hasbox = (m->mopt & NOBOX ? 0 : 1);
288 int tadd = strlen(m->title) ? 2 : 0;
289
290 if (req == REQ_EXECUTE)
291 return;
292 else if (req == REQ_NEXT_ITEM) {
293 if (m->cursel < m->numopts + hasexit - 1)
294 m->cursel++;
295 else
296 mbeep();
297 } else if (req == REQ_PREV_ITEM) {
298 if (m->cursel > 0)
299 m->cursel--;
300 else
301 mbeep();
302
303 } else if (req == REQ_REDISPLAY) {
304 wclear(stdscr);
305 wrefresh(stdscr);
306 process_item (&num, -2);
307 post_menu (m);
308 wrefresh (m->mw);
309
310 } else if (req == '?') {
311 process_help (m, num);
312 } else {
313 ch = tolower (req);
314 if (ch == 'x' && hasexit)
315 m->cursel = m->numopts;
316 else {
317 ch = ch - 'a';
318 if (ch < 0 || ch >= m->numopts)
319 mbeep();
320 else
321 m->cursel = ch;
322 }
323 }
324 if (m->cursel != lastsel) {
325 mvwaddstr (m->mw, lastsel+tadd+hasbox, hasbox, " ");
326 if (lastsel < m->numopts)
327 waddstr (m->mw, m->opts[lastsel]);
328 else
329 waddstr (m->mw, "x: Exit");
330 mvwaddstr (m->mw, m->cursel+tadd+hasbox, hasbox, ">");
331 wstandout(m->mw);
332 if (m->cursel < m->numopts)
333 waddstr (m->mw, m->opts[m->cursel]);
334 else
335 waddstr (m->mw, "x: Exit");
336 wstandend(m->mw);
337 wmove(m->mw,tadd+hasbox+m->cursel, hasbox);
338 wrefresh(m->mw);
339 }
340 }
341
342 void process_menu (int num)
343 {
344 int sel = 0;
345 int req, done;
346 int last_num;
347
348 struct menudesc *m = &menus[num];
349
350 done = FALSE;
351
352 /* Initialize? */
353 if (!__menu_init) {
354 if (initscr() == NULL) {
355 __menu_initerror();
356 return;
357 }
358 cbreak();
359 noecho();
360 max_lines = stdscr->maxy;
361 __menu_init = 1;
362 }
363 if (__m_endwin) {
364 wclear(stdscr);
365 wrefresh(stdscr);
366 __m_endwin = 0;
367 }
368 if (m->mw == NULL)
369 init_menu (m);
370
371 /* Always preselect 0! */
372 m->cursel = 0;
373
374 while (!done) {
375 last_num = num;
376 if (__m_endwin) {
377 wclear(stdscr);
378 wrefresh(stdscr);
379 __m_endwin = 0;
380 }
381 /* Process the display action */
382 process_item (&num, -2);
383 post_menu (m);
384 wrefresh (m->mw);
385
386 while ((req = menucmd (m->mw)) != REQ_EXECUTE)
387 process_req (m, num, req);
388
389 sel = m->cursel;
390 wclear (m->mw);
391 wrefresh (m->mw);
392
393 /* Process the items */
394 if (sel < m->numopts)
395 done = process_item (&num, sel);
396 else
397 done = TRUE;
398
399 /* Reselect m just in case */
400 if (num != last_num) {
401 m = &menus[num];
402 /* Initialize? */
403 if (m->mw == NULL)
404 init_menu (m);
405 process_item (&num, -2);
406 }
407 }
408
409 /* Process the exit action */
410 process_item (&num, -1);
411 }
412