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. */
55static int __menu_init = 0;
56int __m_endwin = 0;
57
58/* prototypes for in here! */
59
60static void init_menu (struct menudesc *m);
61static void post_menu (struct menudesc *m);
62static void process_req (struct menudesc *m, int req);
63static void mbeep (void);
64static int menucmd (WINDOW *w);
65
66#ifndef NULL
67#define NULL (void *)0
68#endif
69
70/* menu system processing routines */
71
72static void mbeep (void)
73{
74	fprintf (stderr,"\a");
75}
76
77static 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
113static 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
141static 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
181static 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
221static 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
280void 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