menu_sys.def revision 1.3 1 /* $NetBSD: menu_sys.def,v 1.3 1997/11/14 16:31:45 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 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 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 int num;
229
230 if (req == REQ_EXECUTE)
231 return;
232 else if (req == REQ_NEXT_ITEM) {
233 if (m->cursel < m->numopts + hasexit - 1)
234 m->cursel++;
235 else
236 mbeep();
237 } else if (req == REQ_PREV_ITEM) {
238 if (m->cursel > 0)
239 m->cursel--;
240 else
241 mbeep();
242
243 } else if (req == REQ_REDISPLAY) {
244 wclear(stdscr);
245 wrefresh(stdscr);
246 process_item (&num, -2);
247 post_menu (m);
248 wrefresh (m->mw);
249
250 } else {
251 ch = tolower (req);
252 if (ch == 'x' && hasexit)
253 m->cursel = m->numopts;
254 else {
255 ch = ch - 'a';
256 if (ch < 0 || ch >= m->numopts)
257 mbeep();
258 else
259 m->cursel = ch;
260 }
261 }
262 if (m->cursel != lastsel) {
263 mvwaddstr (m->mw, lastsel+tadd+hasbox, hasbox, " ");
264 if (lastsel < m->numopts)
265 waddstr (m->mw, m->opts[lastsel]);
266 else
267 waddstr (m->mw, "x: Exit");
268 mvwaddstr (m->mw, m->cursel+tadd+hasbox, hasbox, ">");
269 wstandout(m->mw);
270 if (m->cursel < m->numopts)
271 waddstr (m->mw, m->opts[m->cursel]);
272 else
273 waddstr (m->mw, "x: Exit");
274 wstandend(m->mw);
275 wmove(m->mw,tadd+hasbox+m->cursel, hasbox);
276 wrefresh(m->mw);
277 }
278 }
279
280 void process_menu (int num)
281 {
282 int sel = 0;
283 int req, done;
284 int last_num;
285
286 struct menudesc *m = &menus[num];
287
288 done = FALSE;
289
290 /* Initialize? */
291 if (!__menu_init) {
292 if (initscr() == NULL) {
293 __menu_initerror();
294 return;
295 }
296 cbreak();
297 noecho();
298 __menu_init = 1;
299 }
300 if (__m_endwin) {
301 wclear(stdscr);
302 wrefresh(stdscr);
303 __m_endwin = 0;
304 }
305 if (m->mw == NULL)
306 init_menu (m);
307
308 /* Always preselect 0! */
309 m->cursel = 0;
310
311 while (!done) {
312 last_num = num;
313 if (__m_endwin) {
314 wclear(stdscr);
315 wrefresh(stdscr);
316 __m_endwin = 0;
317 }
318 /* Process the display action */
319 process_item (&num, -2);
320 post_menu (m);
321 wrefresh (m->mw);
322
323 while ((req = menucmd (m->mw)) != REQ_EXECUTE)
324 process_req (m, req);
325
326 sel = m->cursel;
327 wclear (m->mw);
328 wrefresh (m->mw);
329
330 /* Process the items */
331 if (sel < m->numopts)
332 done = process_item (&num, sel);
333 else
334 done = TRUE;
335
336 /* Reselect m just in case */
337 if (num != last_num) {
338 m = &menus[num];
339 /* Initialize? */
340 if (m->mw == NULL)
341 init_menu (m);
342 process_item (&num, -2);
343 }
344 }
345
346 /* Process the exit action */
347 process_item (&num, -1);
348 }
349