menu_sys.def revision 1.4 1 /* $NetBSD: menu_sys.def,v 1.4 1997/11/14 18:27:17 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
58 /* prototypes for in here! */
59
60 static void init_menu (struct menudesc *m);
61 static void post_menu (struct menudesc *m);
62 static void process_req (struct menudesc *m, int num, int req);
63 static void mbeep (void);
64 static int menucmd (WINDOW *w);
65
66 #ifndef NULL
67 #define NULL (void *)0
68 #endif
69
70 /* menu system processing routines */
71
72 static void mbeep (void)
73 {
74 fprintf (stderr,"\a");
75 }
76
77 static int mgetch(WINDOW *w)
78 {
79 static char buf[20];
80 static int num = 0;
81
82 int i, ret;
83
84 for (i=0; i< strlen(KD); i++) {
85 if (i >= num)
86 buf[num++] = wgetch(w);
87 if (buf[i] != KD[i])
88 break;
89 }
90 if (i == strlen(KD)) {
91 num = 0;
92 return KEYPAD_DOWN_ARROW;
93 }
94
95 for (i=0; i< strlen(KU); i++) {
96 if (i >= num)
97 buf[num++] = wgetch(w);
98 if (buf[i] != KU[i])
99 break;
100 }
101 if (i == strlen(KU)) {
102 num = 0;
103 return KEYPAD_UP_ARROW;
104 }
105
106 ret = buf[0];
107 for (i = 0; i < strlen(buf); i++)
108 buf[i] = buf[i+1];
109 num--;
110 return ret;
111 }
112
113 static int menucmd (WINDOW *w)
114 {
115 int ch;
116
117 while (TRUE) {
118 ch = mgetch(w);
119
120 switch (ch) {
121 case '\n':
122 return REQ_EXECUTE;
123 case '\016':
124 case KEYPAD_DOWN_ARROW:
125 return REQ_NEXT_ITEM;
126 case '\020':
127 case KEYPAD_UP_ARROW:
128 return REQ_PREV_ITEM;
129 case '\014':
130 return REQ_REDISPLAY;
131 }
132
133 if (isalpha(ch))
134 return (ch);
135
136 mbeep();
137 wrefresh(w);
138 }
139 }
140
141 static void init_menu (struct menudesc *m)
142 {
143 int max;
144 char **p;
145 int add=4;
146
147 if (m->mopt & NOBOX)
148 add = 2;
149
150 max = strlen(m->title);
151
152 /* Calculate h? */
153 if (m->h == 0) {
154 m->h = m->numopts + ((m->mopt & NOEXITOPT) ? 0 : 1)
155 - (max ? 0 : 2);
156 }
157
158
159 /* Calculate w? */
160 if (m->w == 0) {
161 p = m->opts;
162 while (*p) {
163 max = MAX(max,strlen(*p));
164 p++;
165 }
166 m->w = max;
167 }
168
169 /* Get the windows. */
170 m->mw = newwin(m->h+add, m->w+add, m->y, m->x);
171
172 if (m->mw == NULL) {
173 endwin();
174 (void) fprintf (stderr,
175 "Could not create window for window with title "
176 " \"%s\"\n", m->title);
177 exit(1);
178 }
179 }
180
181 static void post_menu (struct menudesc *m)
182 {
183 int i;
184 int hasbox, cury;
185 int tadd;
186
187 if (m->mopt & NOBOX) {
188 cury = 0;
189 hasbox = 0;
190 } else {
191 cury = 1;
192 hasbox = 1;
193 }
194
195 tadd = strlen(m->title) ? 2 : 0;
196
197 if (tadd) {
198 mvwaddstr(m->mw, cury, cury, m->title);
199 cury += 2;
200 }
201
202 for (i=0; i<m->numopts; i++, cury++) {
203 if (m->cursel == i) {
204 mvwaddstr (m->mw, cury, hasbox, ">");
205 wstandout(m->mw);
206 } else
207 mvwaddstr (m->mw, cury, hasbox, " ");
208 waddstr (m->mw, m->opts[i]);
209 if (m->cursel == i)
210 wstandend(m->mw);
211 }
212 if (!(m->mopt & NOEXITOPT))
213 mvwaddstr (m->mw, cury, hasbox, " x: Exit");
214
215 if (!(m->mopt & NOBOX))
216 box(m->mw, '*', '*');
217
218 wmove(m->mw,tadd+hasbox+m->cursel, hasbox);
219 }
220
221 static void process_req (struct menudesc *m, int num, int req)
222 {
223 int ch;
224 int lastsel = m->cursel;
225 int hasexit = (m->mopt & NOEXITOPT ? 0 : 1 );
226 int hasbox = (m->mopt & NOBOX ? 0 : 1);
227 int tadd = strlen(m->title) ? 2 : 0;
228
229 if (req == REQ_EXECUTE)
230 return;
231 else if (req == REQ_NEXT_ITEM) {
232 if (m->cursel < m->numopts + hasexit - 1)
233 m->cursel++;
234 else
235 mbeep();
236 } else if (req == REQ_PREV_ITEM) {
237 if (m->cursel > 0)
238 m->cursel--;
239 else
240 mbeep();
241
242 } else if (req == REQ_REDISPLAY) {
243 wclear(stdscr);
244 wrefresh(stdscr);
245 process_item (&num, -2);
246 post_menu (m);
247 wrefresh (m->mw);
248
249 } else {
250 ch = tolower (req);
251 if (ch == 'x' && hasexit)
252 m->cursel = m->numopts;
253 else {
254 ch = ch - 'a';
255 if (ch < 0 || ch >= m->numopts)
256 mbeep();
257 else
258 m->cursel = ch;
259 }
260 }
261 if (m->cursel != lastsel) {
262 mvwaddstr (m->mw, lastsel+tadd+hasbox, hasbox, " ");
263 if (lastsel < m->numopts)
264 waddstr (m->mw, m->opts[lastsel]);
265 else
266 waddstr (m->mw, "x: Exit");
267 mvwaddstr (m->mw, m->cursel+tadd+hasbox, hasbox, ">");
268 wstandout(m->mw);
269 if (m->cursel < m->numopts)
270 waddstr (m->mw, m->opts[m->cursel]);
271 else
272 waddstr (m->mw, "x: Exit");
273 wstandend(m->mw);
274 wmove(m->mw,tadd+hasbox+m->cursel, hasbox);
275 wrefresh(m->mw);
276 }
277 }
278
279 void process_menu (int num)
280 {
281 int sel = 0;
282 int req, done;
283 int last_num;
284
285 struct menudesc *m = &menus[num];
286
287 done = FALSE;
288
289 /* Initialize? */
290 if (!__menu_init) {
291 if (initscr() == NULL) {
292 __menu_initerror();
293 return;
294 }
295 cbreak();
296 noecho();
297 __menu_init = 1;
298 }
299 if (__m_endwin) {
300 wclear(stdscr);
301 wrefresh(stdscr);
302 __m_endwin = 0;
303 }
304 if (m->mw == NULL)
305 init_menu (m);
306
307 /* Always preselect 0! */
308 m->cursel = 0;
309
310 while (!done) {
311 last_num = num;
312 if (__m_endwin) {
313 wclear(stdscr);
314 wrefresh(stdscr);
315 __m_endwin = 0;
316 }
317 /* Process the display action */
318 process_item (&num, -2);
319 post_menu (m);
320 wrefresh (m->mw);
321
322 while ((req = menucmd (m->mw)) != REQ_EXECUTE)
323 process_req (m, num, req);
324
325 sel = m->cursel;
326 wclear (m->mw);
327 wrefresh (m->mw);
328
329 /* Process the items */
330 if (sel < m->numopts)
331 done = process_item (&num, sel);
332 else
333 done = TRUE;
334
335 /* Reselect m just in case */
336 if (num != last_num) {
337 m = &menus[num];
338 /* Initialize? */
339 if (m->mw == NULL)
340 init_menu (m);
341 process_item (&num, -2);
342 }
343 }
344
345 /* Process the exit action */
346 process_item (&num, -1);
347 }
348