xref: /minix3/lib/libmenu/menu.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
1*84d9c625SLionel Sambuc /*	$NetBSD: menu.c,v 1.18 2012/12/30 12:27:09 blymn Exp $	*/
2b618a1eeSThomas Cort 
3b618a1eeSThomas Cort /*-
4b618a1eeSThomas Cort  * Copyright (c) 1998-1999 Brett Lymn (blymn@baea.com.au, brett_lymn@yahoo.com.au)
5b618a1eeSThomas Cort  * All rights reserved.
6b618a1eeSThomas Cort  *
7b618a1eeSThomas Cort  * Redistribution and use in source and binary forms, with or without
8b618a1eeSThomas Cort  * modification, are permitted provided that the following conditions
9b618a1eeSThomas Cort  * are met:
10b618a1eeSThomas Cort  * 1. Redistributions of source code must retain the above copyright
11b618a1eeSThomas Cort  *    notice, this list of conditions and the following disclaimer.
12b618a1eeSThomas Cort  * 2. The name of the author may not be used to endorse or promote products
13b618a1eeSThomas Cort  *    derived from this software without specific prior written permission
14b618a1eeSThomas Cort  *
15b618a1eeSThomas Cort  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16b618a1eeSThomas Cort  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17b618a1eeSThomas Cort  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18b618a1eeSThomas Cort  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19b618a1eeSThomas Cort  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20b618a1eeSThomas Cort  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21b618a1eeSThomas Cort  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22b618a1eeSThomas Cort  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23b618a1eeSThomas Cort  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24b618a1eeSThomas Cort  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25b618a1eeSThomas Cort  *
26b618a1eeSThomas Cort  *
27b618a1eeSThomas Cort  */
28b618a1eeSThomas Cort 
29b618a1eeSThomas Cort #include <sys/cdefs.h>
30*84d9c625SLionel Sambuc __RCSID("$NetBSD: menu.c,v 1.18 2012/12/30 12:27:09 blymn Exp $");
31b618a1eeSThomas Cort 
32b618a1eeSThomas Cort #include <ctype.h>
33b618a1eeSThomas Cort #include <menu.h>
34b618a1eeSThomas Cort #include <string.h>
35b618a1eeSThomas Cort #include <stdlib.h>
36b618a1eeSThomas Cort #include "internals.h"
37b618a1eeSThomas Cort 
38b618a1eeSThomas Cort MENU _menui_default_menu = {
39b618a1eeSThomas Cort 	16,         /* number of item rows that will fit in window */
40b618a1eeSThomas Cort         1,          /* number of columns of items that will fit in window */
41b618a1eeSThomas Cort 	0,          /* number of rows of items we have */
42b618a1eeSThomas Cort 	0,          /* number of columns of items we have */
43b618a1eeSThomas Cort         0,          /* current cursor row */
44b618a1eeSThomas Cort         0,          /* current cursor column */
45b618a1eeSThomas Cort         {NULL, 0},  /* mark string */
46b618a1eeSThomas Cort         {NULL, 0},  /* unmark string */
47b618a1eeSThomas Cort         O_ONEVALUE, /* menu options */
48b618a1eeSThomas Cort         NULL,       /* the pattern buffer */
49b618a1eeSThomas Cort 	0,          /* length of pattern buffer */
50b618a1eeSThomas Cort 	0,          /* the length of matched buffer */
51b618a1eeSThomas Cort         0,          /* is the menu posted? */
52b618a1eeSThomas Cort         A_REVERSE, /* menu foreground */
53b618a1eeSThomas Cort         A_NORMAL,   /* menu background */
54b618a1eeSThomas Cort         A_UNDERLINE,      /* unselectable menu item */
55b618a1eeSThomas Cort         ' ',        /* filler between name and description */
56b618a1eeSThomas Cort         NULL,       /* user defined pointer */
57b618a1eeSThomas Cort 	0,          /* top row of menu */
58b618a1eeSThomas Cort 	0,          /* widest item in the menu */
59b618a1eeSThomas Cort 	0,          /* the width of a menu column */
60b618a1eeSThomas Cort 	0,          /* number of items attached to the menu */
61b618a1eeSThomas Cort         NULL,       /* items in the menu */
62b618a1eeSThomas Cort         0,          /* current menu item */
63b618a1eeSThomas Cort 	0,          /* currently in a hook function */
64b618a1eeSThomas Cort         NULL,       /* function called when menu posted */
65b618a1eeSThomas Cort         NULL,       /* function called when menu is unposted */
66b618a1eeSThomas Cort         NULL,       /* function called when current item changes */
67b618a1eeSThomas Cort         NULL,       /* function called when current item changes */
68b618a1eeSThomas Cort         NULL,       /* the menu window */
69b618a1eeSThomas Cort 	NULL,       /* the menu subwindow */
70b618a1eeSThomas Cort 	NULL,       /* the window to write to */
71b618a1eeSThomas Cort };
72b618a1eeSThomas Cort 
73b618a1eeSThomas Cort 
74b618a1eeSThomas Cort 
75b618a1eeSThomas Cort /*
76b618a1eeSThomas Cort  * Set the menu mark character
77b618a1eeSThomas Cort  */
78b618a1eeSThomas Cort int
set_menu_mark(MENU * m,char * mark)79b618a1eeSThomas Cort set_menu_mark(MENU *m, char *mark)
80b618a1eeSThomas Cort {
81b618a1eeSThomas Cort 	MENU *menu = m;
82b618a1eeSThomas Cort 
83b618a1eeSThomas Cort 	if (m == NULL) menu = &_menui_default_menu;
84b618a1eeSThomas Cort 
85b618a1eeSThomas Cort           /* if there was an old mark string, free it first */
86b618a1eeSThomas Cort         if (menu->mark.string != NULL) free(menu->mark.string);
87b618a1eeSThomas Cort 
88b618a1eeSThomas Cort         if ((menu->mark.string = (char *) malloc(strlen(mark) + 1)) == NULL)
89b618a1eeSThomas Cort                 return E_SYSTEM_ERROR;
90b618a1eeSThomas Cort 
91b618a1eeSThomas Cort         strcpy(menu->mark.string, mark);
92b618a1eeSThomas Cort 	menu->mark.length = strlen(mark);
93b618a1eeSThomas Cort 
94b618a1eeSThomas Cort 	  /* max item size may have changed - recalculate. */
95b618a1eeSThomas Cort 	_menui_max_item_size(menu);
96b618a1eeSThomas Cort         return E_OK;
97b618a1eeSThomas Cort }
98b618a1eeSThomas Cort 
99b618a1eeSThomas Cort /*
100b618a1eeSThomas Cort  * Return the menu mark string for the menu.
101b618a1eeSThomas Cort  */
102b618a1eeSThomas Cort char *
menu_mark(MENU * menu)103b618a1eeSThomas Cort menu_mark(MENU *menu)
104b618a1eeSThomas Cort {
105b618a1eeSThomas Cort 	if (menu == NULL)
106b618a1eeSThomas Cort 		return _menui_default_menu.mark.string;
107b618a1eeSThomas Cort 	else
108b618a1eeSThomas Cort 		return menu->mark.string;
109b618a1eeSThomas Cort }
110b618a1eeSThomas Cort 
111b618a1eeSThomas Cort /*
112b618a1eeSThomas Cort  * Set the menu unmark character
113b618a1eeSThomas Cort  */
114b618a1eeSThomas Cort int
set_menu_unmark(MENU * m,char * mark)115b618a1eeSThomas Cort set_menu_unmark(MENU *m, char *mark)
116b618a1eeSThomas Cort {
117b618a1eeSThomas Cort 	MENU *menu = m;
118b618a1eeSThomas Cort 
119b618a1eeSThomas Cort 	if (m == NULL) menu = &_menui_default_menu;
120b618a1eeSThomas Cort 
121b618a1eeSThomas Cort           /* if there was an old mark string, free it first */
122b618a1eeSThomas Cort         if (menu->unmark.string != NULL) free(menu->unmark.string);
123b618a1eeSThomas Cort 
124b618a1eeSThomas Cort         if ((menu->unmark.string = (char *) malloc(strlen(mark) + 1)) == NULL)
125b618a1eeSThomas Cort                 return E_SYSTEM_ERROR;
126b618a1eeSThomas Cort 
127b618a1eeSThomas Cort         strcpy(menu->unmark.string, mark);
128b618a1eeSThomas Cort 	menu->unmark.length = strlen(mark);
129b618a1eeSThomas Cort 	  /* max item size may have changed - recalculate. */
130b618a1eeSThomas Cort 	_menui_max_item_size(menu);
131b618a1eeSThomas Cort         return E_OK;
132b618a1eeSThomas Cort }
133b618a1eeSThomas Cort 
134b618a1eeSThomas Cort /*
135b618a1eeSThomas Cort  * Return the menu unmark string for the menu.
136b618a1eeSThomas Cort  */
137b618a1eeSThomas Cort char *
menu_unmark(MENU * menu)138b618a1eeSThomas Cort menu_unmark(MENU *menu)
139b618a1eeSThomas Cort {
140b618a1eeSThomas Cort 	if (menu == NULL)
141b618a1eeSThomas Cort 		return _menui_default_menu.unmark.string;
142b618a1eeSThomas Cort 	else
143b618a1eeSThomas Cort 		return menu->unmark.string;
144b618a1eeSThomas Cort }
145b618a1eeSThomas Cort 
146b618a1eeSThomas Cort /*
147b618a1eeSThomas Cort  * Set the menu window to the window passed.
148b618a1eeSThomas Cort  */
149b618a1eeSThomas Cort int
set_menu_win(MENU * menu,WINDOW * win)150b618a1eeSThomas Cort set_menu_win(MENU *menu, WINDOW *win)
151b618a1eeSThomas Cort {
152b618a1eeSThomas Cort 	if (menu == NULL) {
153b618a1eeSThomas Cort 		_menui_default_menu.menu_win = win;
154b618a1eeSThomas Cort 		_menui_default_menu.scrwin = win;
155b618a1eeSThomas Cort 	} else {
156b618a1eeSThomas Cort 		if (menu->posted == TRUE) {
157b618a1eeSThomas Cort 			return E_POSTED;
158b618a1eeSThomas Cort 		} else {
159b618a1eeSThomas Cort 			menu->menu_win = win;
160b618a1eeSThomas Cort 			menu->scrwin = win;
161b618a1eeSThomas Cort 		}
162b618a1eeSThomas Cort 	}
163b618a1eeSThomas Cort 
164b618a1eeSThomas Cort         return E_OK;
165b618a1eeSThomas Cort }
166b618a1eeSThomas Cort 
167b618a1eeSThomas Cort /*
168b618a1eeSThomas Cort  * Return the pointer to the menu window
169b618a1eeSThomas Cort  */
170b618a1eeSThomas Cort WINDOW *
menu_win(MENU * menu)171b618a1eeSThomas Cort menu_win(MENU *menu)
172b618a1eeSThomas Cort {
173b618a1eeSThomas Cort 	if (menu == NULL)
174b618a1eeSThomas Cort 		return _menui_default_menu.menu_win;
175b618a1eeSThomas Cort 	else
176b618a1eeSThomas Cort 		return menu->menu_win;
177b618a1eeSThomas Cort }
178b618a1eeSThomas Cort 
179b618a1eeSThomas Cort /*
180b618a1eeSThomas Cort  * Set the menu subwindow for the menu.
181b618a1eeSThomas Cort  */
182b618a1eeSThomas Cort int
set_menu_sub(MENU * menu,WINDOW * sub)183b618a1eeSThomas Cort set_menu_sub(MENU *menu, WINDOW *sub)
184b618a1eeSThomas Cort {
185b618a1eeSThomas Cort 	if (menu == NULL) {
186b618a1eeSThomas Cort 		_menui_default_menu.menu_subwin = sub;
187b618a1eeSThomas Cort 		_menui_default_menu.scrwin = sub;
188b618a1eeSThomas Cort 	} else {
189b618a1eeSThomas Cort 		if (menu->posted == TRUE)
190b618a1eeSThomas Cort 			return E_POSTED;
191b618a1eeSThomas Cort 
192b618a1eeSThomas Cort 		menu->menu_subwin = sub;
193b618a1eeSThomas Cort 		menu->scrwin = sub;
194b618a1eeSThomas Cort 	}
195b618a1eeSThomas Cort 
196b618a1eeSThomas Cort         return E_OK;
197b618a1eeSThomas Cort }
198b618a1eeSThomas Cort 
199b618a1eeSThomas Cort /*
200b618a1eeSThomas Cort  * Return the subwindow pointer for the menu
201b618a1eeSThomas Cort  */
202b618a1eeSThomas Cort WINDOW *
menu_sub(MENU * menu)203b618a1eeSThomas Cort menu_sub(MENU *menu)
204b618a1eeSThomas Cort {
205b618a1eeSThomas Cort 	if (menu == NULL)
206b618a1eeSThomas Cort 		return _menui_default_menu.menu_subwin;
207b618a1eeSThomas Cort 	else
208b618a1eeSThomas Cort 		return menu->menu_subwin;
209b618a1eeSThomas Cort }
210b618a1eeSThomas Cort 
211b618a1eeSThomas Cort /*
212b618a1eeSThomas Cort  * Set the maximum number of rows and columns of items that may be displayed.
213b618a1eeSThomas Cort  */
214b618a1eeSThomas Cort int
set_menu_format(MENU * param_menu,int rows,int cols)215b618a1eeSThomas Cort set_menu_format(MENU *param_menu, int rows, int cols)
216b618a1eeSThomas Cort {
217b618a1eeSThomas Cort 	MENU *menu = (param_menu != NULL) ? param_menu : &_menui_default_menu;
218b618a1eeSThomas Cort 
219b618a1eeSThomas Cort         menu->rows = rows;
220b618a1eeSThomas Cort         menu->cols = cols;
221b618a1eeSThomas Cort 
222b618a1eeSThomas Cort 	if (menu->items != NULL)
223b618a1eeSThomas Cort 		  /* recalculate the item neighbours */
224b618a1eeSThomas Cort 		return _menui_stitch_items(menu);
225b618a1eeSThomas Cort 
226b618a1eeSThomas Cort 	return E_OK;
227b618a1eeSThomas Cort }
228b618a1eeSThomas Cort 
229b618a1eeSThomas Cort /*
230b618a1eeSThomas Cort  * Return the max number of rows and cols that may be displayed.
231b618a1eeSThomas Cort  */
232b618a1eeSThomas Cort void
menu_format(MENU * param_menu,int * rows,int * cols)233b618a1eeSThomas Cort menu_format(MENU *param_menu, int *rows, int *cols)
234b618a1eeSThomas Cort {
235b618a1eeSThomas Cort 	MENU *menu = (param_menu != NULL) ? param_menu : &_menui_default_menu;
236b618a1eeSThomas Cort 
237b618a1eeSThomas Cort         *rows = menu->rows;
238b618a1eeSThomas Cort         *cols = menu->cols;
239b618a1eeSThomas Cort }
240b618a1eeSThomas Cort 
241b618a1eeSThomas Cort /*
242b618a1eeSThomas Cort  * Set the user defined function to call when a menu is posted.
243b618a1eeSThomas Cort  */
244b618a1eeSThomas Cort int
set_menu_init(MENU * menu,Menu_Hook func)245b618a1eeSThomas Cort set_menu_init(MENU *menu, Menu_Hook func)
246b618a1eeSThomas Cort {
247b618a1eeSThomas Cort 	if (menu == NULL)
248b618a1eeSThomas Cort 		_menui_default_menu.menu_init = func;
249b618a1eeSThomas Cort 	else
250b618a1eeSThomas Cort 		menu->menu_init = func;
251b618a1eeSThomas Cort         return E_OK;
252b618a1eeSThomas Cort }
253b618a1eeSThomas Cort 
254b618a1eeSThomas Cort /*
255b618a1eeSThomas Cort  * Return the pointer to the menu init function.
256b618a1eeSThomas Cort  */
257b618a1eeSThomas Cort Menu_Hook
menu_init(MENU * menu)258b618a1eeSThomas Cort menu_init(MENU *menu)
259b618a1eeSThomas Cort {
260b618a1eeSThomas Cort 	if (menu == NULL)
261b618a1eeSThomas Cort 		return _menui_default_menu.menu_init;
262b618a1eeSThomas Cort 	else
263b618a1eeSThomas Cort 		return menu->menu_init;
264b618a1eeSThomas Cort }
265b618a1eeSThomas Cort 
266b618a1eeSThomas Cort /*
267b618a1eeSThomas Cort  * Set the user defined function called when a menu is unposted.
268b618a1eeSThomas Cort  */
269b618a1eeSThomas Cort int
set_menu_term(MENU * menu,Menu_Hook func)270b618a1eeSThomas Cort set_menu_term(MENU *menu, Menu_Hook func)
271b618a1eeSThomas Cort {
272b618a1eeSThomas Cort 	if (menu == NULL)
273b618a1eeSThomas Cort 		_menui_default_menu.menu_term = func;
274b618a1eeSThomas Cort 	else
275b618a1eeSThomas Cort 		menu->menu_term = func;
276b618a1eeSThomas Cort         return E_OK;
277b618a1eeSThomas Cort }
278b618a1eeSThomas Cort 
279b618a1eeSThomas Cort /*
280b618a1eeSThomas Cort  * Return the user defined menu termination function pointer.
281b618a1eeSThomas Cort  */
282b618a1eeSThomas Cort Menu_Hook
menu_term(MENU * menu)283b618a1eeSThomas Cort menu_term(MENU *menu)
284b618a1eeSThomas Cort {
285b618a1eeSThomas Cort 	if (menu == NULL)
286b618a1eeSThomas Cort 		return _menui_default_menu.menu_term;
287b618a1eeSThomas Cort 	else
288b618a1eeSThomas Cort 		return menu->menu_term;
289b618a1eeSThomas Cort }
290b618a1eeSThomas Cort 
291b618a1eeSThomas Cort /*
292b618a1eeSThomas Cort  * Return the current menu options set.
293b618a1eeSThomas Cort  */
294b618a1eeSThomas Cort OPTIONS
menu_opts(MENU * menu)295b618a1eeSThomas Cort menu_opts(MENU *menu)
296b618a1eeSThomas Cort {
297b618a1eeSThomas Cort 	if (menu == NULL)
298b618a1eeSThomas Cort 		return _menui_default_menu.opts;
299b618a1eeSThomas Cort 	else
300b618a1eeSThomas Cort 		return menu->opts;
301b618a1eeSThomas Cort }
302b618a1eeSThomas Cort 
303b618a1eeSThomas Cort /*
304b618a1eeSThomas Cort  * Set the menu options to the given options.
305b618a1eeSThomas Cort  */
306b618a1eeSThomas Cort int
set_menu_opts(MENU * param_menu,OPTIONS opts)307b618a1eeSThomas Cort set_menu_opts(MENU *param_menu, OPTIONS opts)
308b618a1eeSThomas Cort {
309b618a1eeSThomas Cort 	int i, seen;
310b618a1eeSThomas Cort 	MENU *menu = (param_menu != NULL) ? param_menu : &_menui_default_menu;
311b618a1eeSThomas Cort 	OPTIONS old_opts = menu->opts;
312b618a1eeSThomas Cort 
313b618a1eeSThomas Cort         menu->opts = opts;
314b618a1eeSThomas Cort 
315b618a1eeSThomas Cort 	  /*
316b618a1eeSThomas Cort 	   * If the radio option is selected then make sure only one
317b618a1eeSThomas Cort 	   * item is actually selected in the items.
318b618a1eeSThomas Cort 	   */
319b618a1eeSThomas Cort 	if (((opts & O_RADIO) == O_RADIO) && (menu->items != NULL) &&
320b618a1eeSThomas Cort 	    (menu->items[0] != NULL)) {
321b618a1eeSThomas Cort 		seen = 0;
322b618a1eeSThomas Cort 		for (i = 0; i < menu->item_count; i++) {
323b618a1eeSThomas Cort 			if (menu->items[i]->selected == 1) {
324b618a1eeSThomas Cort 				if (seen == 0) {
325b618a1eeSThomas Cort 					seen = 1;
326b618a1eeSThomas Cort 				} else {
327b618a1eeSThomas Cort 					menu->items[i]->selected = 0;
328b618a1eeSThomas Cort 				}
329b618a1eeSThomas Cort 			}
330b618a1eeSThomas Cort 		}
331b618a1eeSThomas Cort 
332b618a1eeSThomas Cort 		  /* if none selected, select the first item */
333b618a1eeSThomas Cort 		if (seen == 0)
334b618a1eeSThomas Cort 			menu->items[0]->selected = 1;
335b618a1eeSThomas Cort 	}
336b618a1eeSThomas Cort 
337b618a1eeSThomas Cort  	if ((menu->opts & O_ROWMAJOR) != (old_opts &  O_ROWMAJOR))
338b618a1eeSThomas Cort 		  /* changed menu layout - need to recalc neighbours */
339b618a1eeSThomas Cort 		_menui_stitch_items(menu);
340b618a1eeSThomas Cort 
341b618a1eeSThomas Cort         return E_OK;
342b618a1eeSThomas Cort }
343b618a1eeSThomas Cort 
344b618a1eeSThomas Cort /*
345b618a1eeSThomas Cort  * Turn on the options in menu given by opts.
346b618a1eeSThomas Cort  */
347b618a1eeSThomas Cort int
menu_opts_on(MENU * param_menu,OPTIONS opts)348b618a1eeSThomas Cort menu_opts_on(MENU *param_menu, OPTIONS opts)
349b618a1eeSThomas Cort {
350b618a1eeSThomas Cort 	int i, seen;
351b618a1eeSThomas Cort 	MENU *menu = (param_menu != NULL) ? param_menu : &_menui_default_menu;
352b618a1eeSThomas Cort 	OPTIONS old_opts = menu->opts;
353b618a1eeSThomas Cort 
354b618a1eeSThomas Cort         menu->opts |= opts;
355b618a1eeSThomas Cort 
356b618a1eeSThomas Cort 	  /*
357b618a1eeSThomas Cort 	   * If the radio option is selected then make sure only one
358b618a1eeSThomas Cort 	   * item is actually selected in the items.
359b618a1eeSThomas Cort 	   */
360b618a1eeSThomas Cort 	if (((opts & O_RADIO) == O_RADIO) && (menu->items != NULL) &&
361b618a1eeSThomas Cort 	    (menu->items[0] != NULL)) {
362b618a1eeSThomas Cort 		seen = 0;
363b618a1eeSThomas Cort 		for (i = 0; i < menu->item_count; i++) {
364b618a1eeSThomas Cort 			if (menu->items[i]->selected == 1) {
365b618a1eeSThomas Cort 				if (seen == 0) {
366b618a1eeSThomas Cort 					seen = 1;
367b618a1eeSThomas Cort 				} else {
368b618a1eeSThomas Cort 					menu->items[i]->selected = 0;
369b618a1eeSThomas Cort 				}
370b618a1eeSThomas Cort 			}
371b618a1eeSThomas Cort 		}
372b618a1eeSThomas Cort 		  /* if none selected then select the top item */
373b618a1eeSThomas Cort 		if (seen == 0)
374b618a1eeSThomas Cort 			menu->items[0]->selected = 1;
375b618a1eeSThomas Cort 	}
376b618a1eeSThomas Cort 
377b618a1eeSThomas Cort 	if ((menu->items != NULL) &&
378b618a1eeSThomas Cort 	    (menu->opts & O_ROWMAJOR) != (old_opts &  O_ROWMAJOR))
379b618a1eeSThomas Cort 		  /* changed menu layout - need to recalc neighbours */
380b618a1eeSThomas Cort 		_menui_stitch_items(menu);
381b618a1eeSThomas Cort 
382b618a1eeSThomas Cort         return E_OK;
383b618a1eeSThomas Cort }
384b618a1eeSThomas Cort 
385b618a1eeSThomas Cort /*
386b618a1eeSThomas Cort  * Turn off the menu options given in opts.
387b618a1eeSThomas Cort  */
388b618a1eeSThomas Cort int
menu_opts_off(MENU * param_menu,OPTIONS opts)389b618a1eeSThomas Cort menu_opts_off(MENU *param_menu, OPTIONS opts)
390b618a1eeSThomas Cort {
391b618a1eeSThomas Cort 	MENU *menu = (param_menu != NULL) ? param_menu : &_menui_default_menu;
392b618a1eeSThomas Cort 	OPTIONS old_opts = menu->opts;
393b618a1eeSThomas Cort 
394b618a1eeSThomas Cort         menu->opts &= ~(opts);
395b618a1eeSThomas Cort 
396b618a1eeSThomas Cort 	if ((menu->items != NULL ) &&
397b618a1eeSThomas Cort 	    (menu->opts & O_ROWMAJOR) != (old_opts &  O_ROWMAJOR))
398b618a1eeSThomas Cort 		  /* changed menu layout - need to recalc neighbours */
399b618a1eeSThomas Cort 		_menui_stitch_items(menu);
400b618a1eeSThomas Cort 
401b618a1eeSThomas Cort         return E_OK;
402b618a1eeSThomas Cort }
403b618a1eeSThomas Cort 
404b618a1eeSThomas Cort /*
405b618a1eeSThomas Cort  * Return the menu pattern buffer.
406b618a1eeSThomas Cort  */
407b618a1eeSThomas Cort char *
menu_pattern(MENU * menu)408b618a1eeSThomas Cort menu_pattern(MENU *menu)
409b618a1eeSThomas Cort {
410b618a1eeSThomas Cort 	if (menu == NULL)
411b618a1eeSThomas Cort 		return _menui_default_menu.pattern;
412b618a1eeSThomas Cort 	else
413b618a1eeSThomas Cort 		return menu->pattern;
414b618a1eeSThomas Cort }
415b618a1eeSThomas Cort 
416b618a1eeSThomas Cort /*
417b618a1eeSThomas Cort  * Set the menu pattern buffer to pat and attempt to match the pattern in
418b618a1eeSThomas Cort  * the item list.
419b618a1eeSThomas Cort  */
420b618a1eeSThomas Cort int
set_menu_pattern(MENU * param_menu,char * pat)421b618a1eeSThomas Cort set_menu_pattern(MENU *param_menu, char *pat)
422b618a1eeSThomas Cort {
423b618a1eeSThomas Cort 	MENU *menu = (param_menu != NULL) ? param_menu : &_menui_default_menu;
424b618a1eeSThomas Cort 	char *p = pat;
425b618a1eeSThomas Cort 
426b618a1eeSThomas Cort 	  /* check pattern is all printable characters */
427b618a1eeSThomas Cort 	while (*p)
428b618a1eeSThomas Cort 		if (!isprint((unsigned char) *p++)) return E_BAD_ARGUMENT;
429b618a1eeSThomas Cort 
430b618a1eeSThomas Cort         if ((menu->pattern = (char *) realloc(menu->pattern,
431b618a1eeSThomas Cort                                      sizeof(char) * strlen(pat) + 1)) == NULL)
432b618a1eeSThomas Cort                 return E_SYSTEM_ERROR;
433b618a1eeSThomas Cort 
434b618a1eeSThomas Cort         strcpy(menu->pattern, pat);
435b618a1eeSThomas Cort 	menu->plen = strlen(pat);
436b618a1eeSThomas Cort 
437b618a1eeSThomas Cort           /* search item list for pat here */
438b618a1eeSThomas Cort 	return _menui_match_items(menu, MATCH_FORWARD, &menu->cur_item);
439b618a1eeSThomas Cort }
440b618a1eeSThomas Cort 
441b618a1eeSThomas Cort /*
442b618a1eeSThomas Cort  * Allocate a new menu structure and fill it in.
443b618a1eeSThomas Cort  */
444b618a1eeSThomas Cort MENU *
new_menu(ITEM ** items)445b618a1eeSThomas Cort new_menu(ITEM **items)
446b618a1eeSThomas Cort {
447b618a1eeSThomas Cort         MENU *the_menu;
448*84d9c625SLionel Sambuc         char mark[2];
449b618a1eeSThomas Cort 
450b618a1eeSThomas Cort         if ((the_menu = (MENU *)malloc(sizeof(MENU))) == NULL)
451b618a1eeSThomas Cort                 return NULL;
452b618a1eeSThomas Cort 
453b618a1eeSThomas Cort           /* copy the defaults */
454b618a1eeSThomas Cort 	(void)memcpy(the_menu, &_menui_default_menu, sizeof(MENU));
455b618a1eeSThomas Cort 
456b618a1eeSThomas Cort 	  /* set a default window if none already set. */
457b618a1eeSThomas Cort 	if (the_menu->menu_win == NULL)
458b618a1eeSThomas Cort 		the_menu->scrwin = stdscr;
459b618a1eeSThomas Cort 
460b618a1eeSThomas Cort 	  /* make a private copy of the mark string */
461b618a1eeSThomas Cort 	if (_menui_default_menu.mark.string != NULL) {
462b618a1eeSThomas Cort 		if ((the_menu->mark.string =
463b618a1eeSThomas Cort 		     (char *) malloc((unsigned) _menui_default_menu.mark.length + 1))
464b618a1eeSThomas Cort 		    == NULL) {
465b618a1eeSThomas Cort 			free(the_menu);
466b618a1eeSThomas Cort 			return NULL;
467b618a1eeSThomas Cort 		}
468b618a1eeSThomas Cort 
469b618a1eeSThomas Cort 		strlcpy(the_menu->mark.string, _menui_default_menu.mark.string,
470b618a1eeSThomas Cort 			(unsigned) _menui_default_menu.mark.length + 1);
471b618a1eeSThomas Cort 	}
472b618a1eeSThomas Cort 
473b618a1eeSThomas Cort 	  /* make a private copy of the unmark string too */
474b618a1eeSThomas Cort 	if (_menui_default_menu.unmark.string != NULL) {
475b618a1eeSThomas Cort 		if ((the_menu->unmark.string =
476b618a1eeSThomas Cort 		     (char *) malloc((unsigned) _menui_default_menu.unmark.length + 1))
477b618a1eeSThomas Cort 		    == NULL) {
478b618a1eeSThomas Cort 			free(the_menu);
479b618a1eeSThomas Cort 			return NULL;
480b618a1eeSThomas Cort 		}
481b618a1eeSThomas Cort 
482b618a1eeSThomas Cort 		strlcpy(the_menu->unmark.string,
483b618a1eeSThomas Cort 			_menui_default_menu.unmark.string,
484b618a1eeSThomas Cort 			(unsigned) _menui_default_menu.unmark.length+ 1 );
485b618a1eeSThomas Cort 	}
486b618a1eeSThomas Cort 
487*84d9c625SLionel Sambuc 	/* default mark needs to be set */
488*84d9c625SLionel Sambuc 	mark[0] = '-';
489*84d9c625SLionel Sambuc 	mark[1] = '\0';
490*84d9c625SLionel Sambuc 
491*84d9c625SLionel Sambuc 	set_menu_mark(the_menu, mark);
492*84d9c625SLionel Sambuc 
493b618a1eeSThomas Cort           /* now attach the items, if any */
494b618a1eeSThomas Cort         if (items != NULL) {
495b618a1eeSThomas Cort 		if(set_menu_items(the_menu, items) < 0) {
496b618a1eeSThomas Cort 			if (the_menu->mark.string != NULL)
497b618a1eeSThomas Cort 				free(the_menu->mark.string);
498b618a1eeSThomas Cort 			if (the_menu->unmark.string != NULL)
499b618a1eeSThomas Cort 				free(the_menu->unmark.string);
500b618a1eeSThomas Cort 			free(the_menu);
501b618a1eeSThomas Cort 			return NULL;
502b618a1eeSThomas Cort 		}
503b618a1eeSThomas Cort 	}
504b618a1eeSThomas Cort 
505b618a1eeSThomas Cort 	return the_menu;
506b618a1eeSThomas Cort }
507b618a1eeSThomas Cort 
508b618a1eeSThomas Cort /*
509b618a1eeSThomas Cort  * Free up storage allocated to the menu object and destroy it.
510b618a1eeSThomas Cort  */
511b618a1eeSThomas Cort int
free_menu(MENU * menu)512b618a1eeSThomas Cort free_menu(MENU *menu)
513b618a1eeSThomas Cort {
514b618a1eeSThomas Cort 	int i;
515b618a1eeSThomas Cort 
516b618a1eeSThomas Cort 	if (menu == NULL)
517b618a1eeSThomas Cort 		return E_BAD_ARGUMENT;
518b618a1eeSThomas Cort 
519b618a1eeSThomas Cort 	if (menu->posted != 0)
520b618a1eeSThomas Cort 		return E_POSTED;
521b618a1eeSThomas Cort 
522b618a1eeSThomas Cort 	if (menu->pattern != NULL)
523b618a1eeSThomas Cort 		free(menu->pattern);
524b618a1eeSThomas Cort 
525b618a1eeSThomas Cort 	if (menu->mark.string != NULL)
526b618a1eeSThomas Cort 		free(menu->mark.string);
527b618a1eeSThomas Cort 
528b618a1eeSThomas Cort 	if (menu->items != NULL) {
529b618a1eeSThomas Cort 		  /* disconnect the items from this menu */
530b618a1eeSThomas Cort 		for (i = 0; i < menu->item_count; i++) {
531b618a1eeSThomas Cort 			menu->items[i]->parent = NULL;
532b618a1eeSThomas Cort 		}
533b618a1eeSThomas Cort 	}
534b618a1eeSThomas Cort 
535b618a1eeSThomas Cort 	free(menu);
536b618a1eeSThomas Cort 	return E_OK;
537b618a1eeSThomas Cort }
538b618a1eeSThomas Cort 
539b618a1eeSThomas Cort /*
540b618a1eeSThomas Cort  * Calculate the minimum window size for the menu.
541b618a1eeSThomas Cort  */
542b618a1eeSThomas Cort int
scale_menu(MENU * param_menu,int * rows,int * cols)543b618a1eeSThomas Cort scale_menu(MENU *param_menu, int *rows, int *cols)
544b618a1eeSThomas Cort {
545b618a1eeSThomas Cort 	MENU *menu = (param_menu != NULL) ? param_menu : &_menui_default_menu;
546b618a1eeSThomas Cort 
547b618a1eeSThomas Cort 	if (menu->items == NULL)
548b618a1eeSThomas Cort 		return E_BAD_ARGUMENT;
549b618a1eeSThomas Cort 
550b618a1eeSThomas Cort 	  /* calculate the max item size */
551b618a1eeSThomas Cort 	_menui_max_item_size(menu);
552b618a1eeSThomas Cort 
553b618a1eeSThomas Cort 	*rows = menu->rows;
554b618a1eeSThomas Cort 	*cols = menu->cols * menu->max_item_width;
555b618a1eeSThomas Cort 
556b618a1eeSThomas Cort 	  /*
557b618a1eeSThomas Cort 	   * allow for spacing between columns...
558b618a1eeSThomas Cort 	   */
559b618a1eeSThomas Cort 	*cols += (menu->cols - 1);
560b618a1eeSThomas Cort 
561b618a1eeSThomas Cort 	return E_OK;
562b618a1eeSThomas Cort }
563b618a1eeSThomas Cort 
564b618a1eeSThomas Cort /*
565b618a1eeSThomas Cort  * Set the menu item list to the one given.
566b618a1eeSThomas Cort  */
567b618a1eeSThomas Cort int
set_menu_items(MENU * param_menu,ITEM ** items)568b618a1eeSThomas Cort set_menu_items(MENU *param_menu, ITEM **items)
569b618a1eeSThomas Cort {
570b618a1eeSThomas Cort 	MENU *menu = (param_menu != NULL) ? param_menu : &_menui_default_menu;
571b618a1eeSThomas Cort 	int i, new_count = 0, sel_count = 0;
572b618a1eeSThomas Cort 
573b618a1eeSThomas Cort 	  /* don't change if menu is posted */
574b618a1eeSThomas Cort 	if (menu->posted == 1)
575b618a1eeSThomas Cort 		return E_POSTED;
576b618a1eeSThomas Cort 
577b618a1eeSThomas Cort 	  /* count the new items and validate none are connected already */
578b618a1eeSThomas Cort 	while (items[new_count] != NULL) {
579b618a1eeSThomas Cort 		if ((items[new_count]->parent != NULL) &&
580b618a1eeSThomas Cort 		    (items[new_count]->parent != menu))
581b618a1eeSThomas Cort 			return E_CONNECTED;
582b618a1eeSThomas Cort 		if (items[new_count]->selected == 1)
583b618a1eeSThomas Cort 			sel_count++;
584b618a1eeSThomas Cort 		new_count++;
585b618a1eeSThomas Cort 	}
586b618a1eeSThomas Cort 
587b618a1eeSThomas Cort 	  /*
588b618a1eeSThomas Cort 	   * don't allow multiple selected items if menu is radio
589b618a1eeSThomas Cort 	   * button style.
590b618a1eeSThomas Cort 	   */
591b618a1eeSThomas Cort 	if (((menu->opts & O_RADIO) == O_RADIO) &&
592b618a1eeSThomas Cort 	    (sel_count > 1))
593b618a1eeSThomas Cort 		return E_BAD_ARGUMENT;
594b618a1eeSThomas Cort 
595b618a1eeSThomas Cort 	  /* if there were items connected then disconnect them. */
596b618a1eeSThomas Cort 	if (menu->items != NULL) {
597b618a1eeSThomas Cort 		for (i = 0; i < menu->item_count; i++) {
598b618a1eeSThomas Cort 			menu->items[i]->parent = NULL;
599b618a1eeSThomas Cort 			menu->items[i]->index = -1;
600b618a1eeSThomas Cort 		}
601b618a1eeSThomas Cort 	}
602b618a1eeSThomas Cort 
603b618a1eeSThomas Cort 	menu->item_count = new_count;
604b618a1eeSThomas Cort 
605b618a1eeSThomas Cort 	  /* connect the new items to the menu */
606b618a1eeSThomas Cort 	for (i = 0; i < new_count; i++) {
607b618a1eeSThomas Cort 		items[i]->parent = menu;
608b618a1eeSThomas Cort 		items[i]->index = i;
609b618a1eeSThomas Cort 	}
610b618a1eeSThomas Cort 
611b618a1eeSThomas Cort 	menu->items = items;
612b618a1eeSThomas Cort 	menu->cur_item = 0; /* reset current item just in case */
613b618a1eeSThomas Cort 	menu->top_row = 0; /* and the top row too */
614b618a1eeSThomas Cort 	if (menu->pattern != NULL) { /* and the pattern buffer....sigh */
615b618a1eeSThomas Cort 		free(menu->pattern);
616b618a1eeSThomas Cort 		menu->plen = 0;
617b618a1eeSThomas Cort 		menu->match_len = 0;
618b618a1eeSThomas Cort 	}
619b618a1eeSThomas Cort 
620b618a1eeSThomas Cort 	  /*
621b618a1eeSThomas Cort 	   * make sure at least one item is selected on a radio
622b618a1eeSThomas Cort 	   * button style menu.
623b618a1eeSThomas Cort 	   */
624b618a1eeSThomas Cort 	if (((menu->opts & O_RADIO) == O_RADIO) && (sel_count == 0))
625b618a1eeSThomas Cort 		menu->items[0]->selected = 1;
626b618a1eeSThomas Cort 
627b618a1eeSThomas Cort 
628b618a1eeSThomas Cort 	_menui_stitch_items(menu); /* recalculate the item neighbours */
629b618a1eeSThomas Cort 
630b618a1eeSThomas Cort 	return E_OK;
631b618a1eeSThomas Cort }
632b618a1eeSThomas Cort 
633b618a1eeSThomas Cort /*
634b618a1eeSThomas Cort  * Return the pointer to the menu items array.
635b618a1eeSThomas Cort  */
636b618a1eeSThomas Cort ITEM **
menu_items(MENU * menu)637b618a1eeSThomas Cort menu_items(MENU *menu)
638b618a1eeSThomas Cort {
639b618a1eeSThomas Cort 	if (menu == NULL)
640b618a1eeSThomas Cort 		return _menui_default_menu.items;
641b618a1eeSThomas Cort 	else
642b618a1eeSThomas Cort 		return menu->items;
643b618a1eeSThomas Cort }
644b618a1eeSThomas Cort 
645b618a1eeSThomas Cort /*
646b618a1eeSThomas Cort  * Return the count of items connected to the menu
647b618a1eeSThomas Cort  */
648b618a1eeSThomas Cort int
item_count(MENU * menu)649b618a1eeSThomas Cort item_count(MENU *menu)
650b618a1eeSThomas Cort {
651b618a1eeSThomas Cort 	if (menu == NULL)
652b618a1eeSThomas Cort 		return _menui_default_menu.item_count;
653b618a1eeSThomas Cort 	else
654b618a1eeSThomas Cort 		return menu->item_count;
655b618a1eeSThomas Cort }
656b618a1eeSThomas Cort 
657b618a1eeSThomas Cort /*
658b618a1eeSThomas Cort  * Set the menu top row to be the given row.  The current item becomes the
659b618a1eeSThomas Cort  * leftmost item on that row in the menu.
660b618a1eeSThomas Cort  */
661b618a1eeSThomas Cort int
set_top_row(MENU * param_menu,int row)662b618a1eeSThomas Cort set_top_row(MENU *param_menu, int row)
663b618a1eeSThomas Cort {
664b618a1eeSThomas Cort 	MENU *menu = (param_menu != NULL) ? param_menu : &_menui_default_menu;
665b618a1eeSThomas Cort 	int i, cur_item, state = E_SYSTEM_ERROR;
666b618a1eeSThomas Cort 
667b618a1eeSThomas Cort 	if (row > menu->item_rows)
668b618a1eeSThomas Cort 		return E_BAD_ARGUMENT;
669b618a1eeSThomas Cort 
670b618a1eeSThomas Cort 	if (menu->items == NULL)
671b618a1eeSThomas Cort 		return E_NOT_CONNECTED;
672b618a1eeSThomas Cort 
673b618a1eeSThomas Cort 	if (menu->in_init == 1)
674b618a1eeSThomas Cort 		return E_BAD_STATE;
675b618a1eeSThomas Cort 
676b618a1eeSThomas Cort 	cur_item = 0;
677b618a1eeSThomas Cort 
678b618a1eeSThomas Cort 	for (i = 0; i < menu->item_count; i++) {
679b618a1eeSThomas Cort 		  /* search for first item that matches row - this will be
680b618a1eeSThomas Cort 		     the current item. */
681b618a1eeSThomas Cort 		if (row == menu->items[i]->row) {
682b618a1eeSThomas Cort 			cur_item = i;
683b618a1eeSThomas Cort 			state = E_OK;
684b618a1eeSThomas Cort 			break; /* found what we want - no need to go further */
685b618a1eeSThomas Cort 		}
686b618a1eeSThomas Cort 	}
687b618a1eeSThomas Cort 
688b618a1eeSThomas Cort 	menu->in_init = 1; /* just in case we call the init/term routines */
689b618a1eeSThomas Cort 
690b618a1eeSThomas Cort 	if (menu->posted == 1) {
691b618a1eeSThomas Cort 		if (menu->menu_term != NULL)
692b618a1eeSThomas Cort 			menu->menu_term(menu);
693b618a1eeSThomas Cort 		if (menu->item_term != NULL)
694b618a1eeSThomas Cort 			menu->item_term(menu);
695b618a1eeSThomas Cort 	}
696b618a1eeSThomas Cort 
697b618a1eeSThomas Cort 	menu->cur_item = cur_item;
698b618a1eeSThomas Cort 	menu->top_row = row;
699b618a1eeSThomas Cort 
700b618a1eeSThomas Cort 	if (menu->posted == 1) {
701b618a1eeSThomas Cort 		if (menu->menu_init != NULL)
702b618a1eeSThomas Cort 			menu->menu_init(menu);
703b618a1eeSThomas Cort 		if (menu->item_init != NULL)
704b618a1eeSThomas Cort 			menu->item_init(menu);
705b618a1eeSThomas Cort 	}
706b618a1eeSThomas Cort 
707b618a1eeSThomas Cort 	menu->in_init = 0;
708b618a1eeSThomas Cort 
709b618a1eeSThomas Cort 	  /* this should always be E_OK unless we are really screwed up */
710b618a1eeSThomas Cort 	return state;
711b618a1eeSThomas Cort }
712b618a1eeSThomas Cort 
713b618a1eeSThomas Cort /*
714b618a1eeSThomas Cort  * Return the current top row number.
715b618a1eeSThomas Cort  */
716b618a1eeSThomas Cort int
top_row(MENU * param_menu)717b618a1eeSThomas Cort top_row(MENU *param_menu)
718b618a1eeSThomas Cort {
719b618a1eeSThomas Cort 	MENU *menu = (param_menu != NULL) ? param_menu : &_menui_default_menu;
720b618a1eeSThomas Cort 
721b618a1eeSThomas Cort 	if (menu->items == NULL)
722b618a1eeSThomas Cort 		return E_NOT_CONNECTED;
723b618a1eeSThomas Cort 
724b618a1eeSThomas Cort 	return menu->top_row;
725b618a1eeSThomas Cort }
726b618a1eeSThomas Cort 
727b618a1eeSThomas Cort /*
728b618a1eeSThomas Cort  * Position the cursor at the correct place in the menu.
729b618a1eeSThomas Cort  *
730b618a1eeSThomas Cort  */
731b618a1eeSThomas Cort int
pos_menu_cursor(MENU * menu)732b618a1eeSThomas Cort pos_menu_cursor(MENU *menu)
733b618a1eeSThomas Cort {
734b618a1eeSThomas Cort 	int movx, maxmark;
735b618a1eeSThomas Cort 
736b618a1eeSThomas Cort 	if (menu == NULL)
737b618a1eeSThomas Cort 		return E_BAD_ARGUMENT;
738b618a1eeSThomas Cort 
739b618a1eeSThomas Cort 	maxmark = max(menu->mark.length, menu->unmark.length);
740b618a1eeSThomas Cort 	movx = maxmark + (menu->items[menu->cur_item]->col
741b618a1eeSThomas Cort 		* (menu->col_width + 1));
742b618a1eeSThomas Cort 
743b618a1eeSThomas Cort 	if (menu->match_len > 0)
744b618a1eeSThomas Cort 		movx += menu->match_len - 1;
745b618a1eeSThomas Cort 
746b618a1eeSThomas Cort 	wmove(menu->scrwin,
747b618a1eeSThomas Cort 	      menu->items[menu->cur_item]->row - menu->top_row, movx);
748b618a1eeSThomas Cort 
749b618a1eeSThomas Cort 	return E_OK;
750b618a1eeSThomas Cort }
751