menu_sys.def revision 1.2
1/*	$NetBSD: menu_sys.def,v 1.2 1997/11/09 20:59:15 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. */
54static int __menu_init = 0;
55int __m_endwin = 0;
56
57/* prototypes for in here! */
58
59static void init_menu (struct menudesc *m);
60static void post_menu (struct menudesc *m);
61static void process_req (struct menudesc *m, int req);
62static void mbeep (void);
63static int menucmd (WINDOW *w);
64
65#ifndef NULL
66#define NULL (void *)0
67#endif
68
69/* menu system processing routines */
70
71static void mbeep (void)
72{
73	fprintf (stderr,"\a");
74}
75
76static 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
112static 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
138static 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
178static 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
218static 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
268void 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		if (initscr() == NULL) {
281			__menu_initerror();
282			return;
283		}
284		cbreak();
285		noecho();
286		__menu_init = 1;
287	}
288	if (__m_endwin) {
289     	        wclear(stdscr);
290		wrefresh(stdscr);
291		__m_endwin = 0;
292	}
293	if (m->mw == NULL)
294		init_menu (m);
295
296	/* Always preselect 0! */
297	m->cursel = 0;
298
299	while (!done) {
300		last_num = num;
301		if (__m_endwin) {
302			wclear(stdscr);
303			wrefresh(stdscr);
304			__m_endwin = 0;
305		}
306		/* Process the display action */
307		process_item (&num, -2);
308		post_menu (m);
309		wrefresh (m->mw);
310
311		while ((req = menucmd (m->mw)) != REQ_EXECUTE)
312			process_req (m, req);
313
314		sel = m->cursel;
315		wclear (m->mw);
316		wrefresh (m->mw);
317
318		/* Process the items */
319		if (sel < m->numopts)
320			done = process_item (&num, sel);
321		else
322			done = TRUE;
323
324		/* Reselect m just in case */
325		if (num != last_num) {
326			m = &menus[num];
327			/* Initialize? */
328			if (m->mw == NULL)
329				init_menu (m);
330			process_item (&num, -2);
331		}
332	}
333
334	/* Process the exit action */
335	process_item (&num, -1);
336}
337