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