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