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