1*b618a1eeSThomas Cort /* $NetBSD: item.c,v 1.12 2012/03/21 05:33:27 matt Exp $ */
2*b618a1eeSThomas Cort
3*b618a1eeSThomas Cort /*-
4*b618a1eeSThomas Cort * Copyright (c) 1998-1999 Brett Lymn (blymn@baea.com.au, brett_lymn@yahoo.com.au)
5*b618a1eeSThomas Cort * All rights reserved.
6*b618a1eeSThomas Cort *
7*b618a1eeSThomas Cort * Redistribution and use in source and binary forms, with or without
8*b618a1eeSThomas Cort * modification, are permitted provided that the following conditions
9*b618a1eeSThomas Cort * are met:
10*b618a1eeSThomas Cort * 1. Redistributions of source code must retain the above copyright
11*b618a1eeSThomas Cort * notice, this list of conditions and the following disclaimer.
12*b618a1eeSThomas Cort * 2. The name of the author may not be used to endorse or promote products
13*b618a1eeSThomas Cort * derived from this software without specific prior written permission
14*b618a1eeSThomas Cort *
15*b618a1eeSThomas Cort * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16*b618a1eeSThomas Cort * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17*b618a1eeSThomas Cort * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18*b618a1eeSThomas Cort * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19*b618a1eeSThomas Cort * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20*b618a1eeSThomas Cort * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21*b618a1eeSThomas Cort * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22*b618a1eeSThomas Cort * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23*b618a1eeSThomas Cort * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24*b618a1eeSThomas Cort * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25*b618a1eeSThomas Cort *
26*b618a1eeSThomas Cort *
27*b618a1eeSThomas Cort */
28*b618a1eeSThomas Cort
29*b618a1eeSThomas Cort #include <sys/cdefs.h>
30*b618a1eeSThomas Cort __RCSID("$NetBSD: item.c,v 1.12 2012/03/21 05:33:27 matt Exp $");
31*b618a1eeSThomas Cort
32*b618a1eeSThomas Cort #include <menu.h>
33*b618a1eeSThomas Cort #include <stdlib.h>
34*b618a1eeSThomas Cort #include <string.h>
35*b618a1eeSThomas Cort #include "internals.h"
36*b618a1eeSThomas Cort
37*b618a1eeSThomas Cort /* the following is defined in menu.c - it is the default menu struct */
38*b618a1eeSThomas Cort extern MENU _menui_default_menu;
39*b618a1eeSThomas Cort
40*b618a1eeSThomas Cort /* keep default item options for setting in new_item */
41*b618a1eeSThomas Cort ITEM _menui_default_item = {
42*b618a1eeSThomas Cort {NULL, 0}, /* item name struct */
43*b618a1eeSThomas Cort {NULL, 0}, /* item description struct */
44*b618a1eeSThomas Cort NULL, /* user pointer */
45*b618a1eeSThomas Cort 0, /* is item visible? */
46*b618a1eeSThomas Cort 0, /* is item selected? */
47*b618a1eeSThomas Cort 0, /* row item is on */
48*b618a1eeSThomas Cort 0, /* column item is on */
49*b618a1eeSThomas Cort O_SELECTABLE, /* item options */
50*b618a1eeSThomas Cort NULL, /* parent menu item is bound to */
51*b618a1eeSThomas Cort -1, /* index number if item attached to a menu */
52*b618a1eeSThomas Cort NULL, /* left neighbour */
53*b618a1eeSThomas Cort NULL, /* right neighbour */
54*b618a1eeSThomas Cort NULL, /* up neighbour */
55*b618a1eeSThomas Cort NULL /* down neighbour */
56*b618a1eeSThomas Cort };
57*b618a1eeSThomas Cort
58*b618a1eeSThomas Cort /*
59*b618a1eeSThomas Cort * Return the item visibility flag
60*b618a1eeSThomas Cort */
61*b618a1eeSThomas Cort int
item_visible(ITEM * item)62*b618a1eeSThomas Cort item_visible(ITEM *item)
63*b618a1eeSThomas Cort {
64*b618a1eeSThomas Cort if (item == NULL)
65*b618a1eeSThomas Cort return E_BAD_ARGUMENT;
66*b618a1eeSThomas Cort if (item->parent == NULL)
67*b618a1eeSThomas Cort return E_NOT_CONNECTED;
68*b618a1eeSThomas Cort
69*b618a1eeSThomas Cort return item->visible;
70*b618a1eeSThomas Cort }
71*b618a1eeSThomas Cort
72*b618a1eeSThomas Cort /*
73*b618a1eeSThomas Cort * Return the pointer to the item name
74*b618a1eeSThomas Cort */
75*b618a1eeSThomas Cort char *
item_name(ITEM * item)76*b618a1eeSThomas Cort item_name(ITEM *item)
77*b618a1eeSThomas Cort {
78*b618a1eeSThomas Cort if (item == NULL)
79*b618a1eeSThomas Cort return NULL;
80*b618a1eeSThomas Cort
81*b618a1eeSThomas Cort return item->name.string;
82*b618a1eeSThomas Cort }
83*b618a1eeSThomas Cort
84*b618a1eeSThomas Cort /*
85*b618a1eeSThomas Cort * Return the pointer to the item description
86*b618a1eeSThomas Cort */
87*b618a1eeSThomas Cort char *
item_description(ITEM * item)88*b618a1eeSThomas Cort item_description(ITEM *item)
89*b618a1eeSThomas Cort {
90*b618a1eeSThomas Cort if (item == NULL)
91*b618a1eeSThomas Cort return NULL;
92*b618a1eeSThomas Cort
93*b618a1eeSThomas Cort return item->description.string;
94*b618a1eeSThomas Cort }
95*b618a1eeSThomas Cort
96*b618a1eeSThomas Cort /*
97*b618a1eeSThomas Cort * Set the application defined function called when the menu is posted or
98*b618a1eeSThomas Cort * just after the current item changes.
99*b618a1eeSThomas Cort */
100*b618a1eeSThomas Cort int
set_item_init(MENU * menu,Menu_Hook func)101*b618a1eeSThomas Cort set_item_init(MENU *menu, Menu_Hook func)
102*b618a1eeSThomas Cort {
103*b618a1eeSThomas Cort if (menu == NULL)
104*b618a1eeSThomas Cort _menui_default_menu.item_init = func;
105*b618a1eeSThomas Cort else
106*b618a1eeSThomas Cort menu->item_init = func;
107*b618a1eeSThomas Cort return E_OK;
108*b618a1eeSThomas Cort }
109*b618a1eeSThomas Cort
110*b618a1eeSThomas Cort
111*b618a1eeSThomas Cort /*
112*b618a1eeSThomas Cort * Return a pointer to the item initialisation routine.
113*b618a1eeSThomas Cort */
114*b618a1eeSThomas Cort Menu_Hook
item_init(MENU * menu)115*b618a1eeSThomas Cort item_init(MENU *menu)
116*b618a1eeSThomas Cort {
117*b618a1eeSThomas Cort if (menu == NULL)
118*b618a1eeSThomas Cort return _menui_default_menu.item_init;
119*b618a1eeSThomas Cort else
120*b618a1eeSThomas Cort return menu->item_init;
121*b618a1eeSThomas Cort }
122*b618a1eeSThomas Cort
123*b618a1eeSThomas Cort /*
124*b618a1eeSThomas Cort * Set the user defined function to be called when menu is unposted or just
125*b618a1eeSThomas Cort * before the current item changes.
126*b618a1eeSThomas Cort */
127*b618a1eeSThomas Cort int
set_item_term(MENU * menu,Menu_Hook func)128*b618a1eeSThomas Cort set_item_term(MENU *menu, Menu_Hook func)
129*b618a1eeSThomas Cort {
130*b618a1eeSThomas Cort if (menu == NULL)
131*b618a1eeSThomas Cort _menui_default_menu.item_term = func;
132*b618a1eeSThomas Cort else
133*b618a1eeSThomas Cort menu->item_term = func;
134*b618a1eeSThomas Cort return E_OK;
135*b618a1eeSThomas Cort }
136*b618a1eeSThomas Cort
137*b618a1eeSThomas Cort /*
138*b618a1eeSThomas Cort * Return a pointer to the termination function
139*b618a1eeSThomas Cort */
140*b618a1eeSThomas Cort Menu_Hook
item_term(MENU * menu)141*b618a1eeSThomas Cort item_term(MENU *menu)
142*b618a1eeSThomas Cort {
143*b618a1eeSThomas Cort if (menu == NULL)
144*b618a1eeSThomas Cort return _menui_default_menu.item_term;
145*b618a1eeSThomas Cort else
146*b618a1eeSThomas Cort return menu->item_term;
147*b618a1eeSThomas Cort }
148*b618a1eeSThomas Cort
149*b618a1eeSThomas Cort /*
150*b618a1eeSThomas Cort * Returns the number of items that are selected.
151*b618a1eeSThomas Cort * The index numbers of the items are placed in the dynamically allocated
152*b618a1eeSThomas Cort * int array *sel.
153*b618a1eeSThomas Cort */
154*b618a1eeSThomas Cort int
item_selected(MENU * menu,int ** sel)155*b618a1eeSThomas Cort item_selected(MENU *menu, int **sel)
156*b618a1eeSThomas Cort {
157*b618a1eeSThomas Cort int i, j;
158*b618a1eeSThomas Cort
159*b618a1eeSThomas Cort if (menu == NULL)
160*b618a1eeSThomas Cort return E_BAD_ARGUMENT;
161*b618a1eeSThomas Cort
162*b618a1eeSThomas Cort /* count selected */
163*b618a1eeSThomas Cort for (i = 0, j = 0; i < menu->item_count; i++)
164*b618a1eeSThomas Cort if (menu->items[i]->selected)
165*b618a1eeSThomas Cort j++;
166*b618a1eeSThomas Cort
167*b618a1eeSThomas Cort if (j == 0) {
168*b618a1eeSThomas Cort *sel = NULL;
169*b618a1eeSThomas Cort return 0;
170*b618a1eeSThomas Cort }
171*b618a1eeSThomas Cort
172*b618a1eeSThomas Cort if ( (*sel = malloc(sizeof(int) * j)) == NULL)
173*b618a1eeSThomas Cort return E_SYSTEM_ERROR;
174*b618a1eeSThomas Cort
175*b618a1eeSThomas Cort for (i = 0, j = 0; i < menu->item_count; i++)
176*b618a1eeSThomas Cort if (menu->items[i]->selected)
177*b618a1eeSThomas Cort (*sel)[j++] = i;
178*b618a1eeSThomas Cort
179*b618a1eeSThomas Cort return j;
180*b618a1eeSThomas Cort }
181*b618a1eeSThomas Cort
182*b618a1eeSThomas Cort /*
183*b618a1eeSThomas Cort * Set the item options. We keep a global copy of the current item options
184*b618a1eeSThomas Cort * as subsequent new_item calls will use the updated options as their
185*b618a1eeSThomas Cort * defaults.
186*b618a1eeSThomas Cort */
187*b618a1eeSThomas Cort int
set_item_opts(ITEM * item,OPTIONS opts)188*b618a1eeSThomas Cort set_item_opts(ITEM *item, OPTIONS opts)
189*b618a1eeSThomas Cort {
190*b618a1eeSThomas Cort /* selectable seems to be the only allowable item opt! */
191*b618a1eeSThomas Cort if (opts != O_SELECTABLE)
192*b618a1eeSThomas Cort return E_SYSTEM_ERROR;
193*b618a1eeSThomas Cort
194*b618a1eeSThomas Cort if (item == NULL)
195*b618a1eeSThomas Cort _menui_default_item.opts = opts;
196*b618a1eeSThomas Cort else
197*b618a1eeSThomas Cort item->opts = opts;
198*b618a1eeSThomas Cort return E_OK;
199*b618a1eeSThomas Cort }
200*b618a1eeSThomas Cort
201*b618a1eeSThomas Cort /*
202*b618a1eeSThomas Cort * Set item options on.
203*b618a1eeSThomas Cort */
204*b618a1eeSThomas Cort int
item_opts_on(ITEM * item,OPTIONS opts)205*b618a1eeSThomas Cort item_opts_on(ITEM *item, OPTIONS opts)
206*b618a1eeSThomas Cort {
207*b618a1eeSThomas Cort if (opts != O_SELECTABLE)
208*b618a1eeSThomas Cort return E_SYSTEM_ERROR;
209*b618a1eeSThomas Cort
210*b618a1eeSThomas Cort if (item == NULL)
211*b618a1eeSThomas Cort _menui_default_item.opts |= opts;
212*b618a1eeSThomas Cort else
213*b618a1eeSThomas Cort item->opts |= opts;
214*b618a1eeSThomas Cort return E_OK;
215*b618a1eeSThomas Cort }
216*b618a1eeSThomas Cort
217*b618a1eeSThomas Cort /*
218*b618a1eeSThomas Cort * Turn off the named options.
219*b618a1eeSThomas Cort */
220*b618a1eeSThomas Cort int
item_opts_off(ITEM * item,OPTIONS opts)221*b618a1eeSThomas Cort item_opts_off(ITEM *item, OPTIONS opts)
222*b618a1eeSThomas Cort {
223*b618a1eeSThomas Cort if (opts != O_SELECTABLE)
224*b618a1eeSThomas Cort return E_SYSTEM_ERROR;
225*b618a1eeSThomas Cort
226*b618a1eeSThomas Cort if (item == NULL)
227*b618a1eeSThomas Cort _menui_default_item.opts &= ~(opts);
228*b618a1eeSThomas Cort else
229*b618a1eeSThomas Cort item->opts &= ~(opts);
230*b618a1eeSThomas Cort return E_OK;
231*b618a1eeSThomas Cort }
232*b618a1eeSThomas Cort
233*b618a1eeSThomas Cort /*
234*b618a1eeSThomas Cort * Return the current options set in item.
235*b618a1eeSThomas Cort */
236*b618a1eeSThomas Cort OPTIONS
item_opts(ITEM * item)237*b618a1eeSThomas Cort item_opts(ITEM *item)
238*b618a1eeSThomas Cort {
239*b618a1eeSThomas Cort if (item == NULL)
240*b618a1eeSThomas Cort return _menui_default_item.opts;
241*b618a1eeSThomas Cort else
242*b618a1eeSThomas Cort return item->opts;
243*b618a1eeSThomas Cort }
244*b618a1eeSThomas Cort
245*b618a1eeSThomas Cort /*
246*b618a1eeSThomas Cort * Set the selected flag of the item iff the menu options allow it.
247*b618a1eeSThomas Cort */
248*b618a1eeSThomas Cort int
set_item_value(ITEM * param_item,int flag)249*b618a1eeSThomas Cort set_item_value(ITEM *param_item, int flag)
250*b618a1eeSThomas Cort {
251*b618a1eeSThomas Cort ITEM *item = (param_item != NULL) ? param_item : &_menui_default_item;
252*b618a1eeSThomas Cort
253*b618a1eeSThomas Cort /* not bound to a menu */
254*b618a1eeSThomas Cort if (item->parent == NULL)
255*b618a1eeSThomas Cort return E_NOT_CONNECTED;
256*b618a1eeSThomas Cort
257*b618a1eeSThomas Cort /* menu options do not allow multi-selection */
258*b618a1eeSThomas Cort if ((item->parent->opts & O_ONEVALUE) == O_ONEVALUE)
259*b618a1eeSThomas Cort return E_REQUEST_DENIED;
260*b618a1eeSThomas Cort
261*b618a1eeSThomas Cort item->selected = flag;
262*b618a1eeSThomas Cort _menui_draw_item(item->parent, item->index);
263*b618a1eeSThomas Cort return E_OK;
264*b618a1eeSThomas Cort }
265*b618a1eeSThomas Cort
266*b618a1eeSThomas Cort /*
267*b618a1eeSThomas Cort * Return the item value of the item.
268*b618a1eeSThomas Cort */
269*b618a1eeSThomas Cort int
item_value(ITEM * item)270*b618a1eeSThomas Cort item_value(ITEM *item)
271*b618a1eeSThomas Cort {
272*b618a1eeSThomas Cort if (item == NULL)
273*b618a1eeSThomas Cort return _menui_default_item.selected;
274*b618a1eeSThomas Cort else
275*b618a1eeSThomas Cort return item->selected;
276*b618a1eeSThomas Cort }
277*b618a1eeSThomas Cort
278*b618a1eeSThomas Cort /*
279*b618a1eeSThomas Cort * Allocate a new item and return the pointer to the newly allocated
280*b618a1eeSThomas Cort * structure.
281*b618a1eeSThomas Cort */
282*b618a1eeSThomas Cort ITEM *
new_item(char * name,char * description)283*b618a1eeSThomas Cort new_item(char *name, char *description)
284*b618a1eeSThomas Cort {
285*b618a1eeSThomas Cort ITEM *new_one;
286*b618a1eeSThomas Cort
287*b618a1eeSThomas Cort if (name == NULL)
288*b618a1eeSThomas Cort return NULL;
289*b618a1eeSThomas Cort
290*b618a1eeSThomas Cort /* allocate a new item structure for ourselves */
291*b618a1eeSThomas Cort if ((new_one = (ITEM *)malloc(sizeof(ITEM))) == NULL)
292*b618a1eeSThomas Cort return NULL;
293*b618a1eeSThomas Cort
294*b618a1eeSThomas Cort /* copy in the defaults for the item */
295*b618a1eeSThomas Cort (void)memcpy(new_one, &_menui_default_item, sizeof(ITEM));
296*b618a1eeSThomas Cort
297*b618a1eeSThomas Cort /* fill in the name structure - first the length and then
298*b618a1eeSThomas Cort allocate room for the string & copy that. */
299*b618a1eeSThomas Cort new_one->name.length = strlen(name);
300*b618a1eeSThomas Cort if ((new_one->name.string = (char *)
301*b618a1eeSThomas Cort malloc(sizeof(char) * new_one->name.length + 1)) == NULL) {
302*b618a1eeSThomas Cort /* uh oh malloc failed - clean up & exit */
303*b618a1eeSThomas Cort free(new_one);
304*b618a1eeSThomas Cort return NULL;
305*b618a1eeSThomas Cort }
306*b618a1eeSThomas Cort
307*b618a1eeSThomas Cort strcpy(new_one->name.string, name);
308*b618a1eeSThomas Cort
309*b618a1eeSThomas Cort if (description == NULL)
310*b618a1eeSThomas Cort new_one->description.length = 0;
311*b618a1eeSThomas Cort else {
312*b618a1eeSThomas Cort /* fill in the description structure, stash the length then
313*b618a1eeSThomas Cort allocate room for description string and copy it in */
314*b618a1eeSThomas Cort new_one->description.length = strlen(description);
315*b618a1eeSThomas Cort if ((new_one->description.string =
316*b618a1eeSThomas Cort (char *) malloc(sizeof(char) *
317*b618a1eeSThomas Cort new_one->description.length + 1)) == NULL) {
318*b618a1eeSThomas Cort /*
319*b618a1eeSThomas Cort * malloc has failed
320*b618a1eeSThomas Cort * - free up allocated memory and return
321*b618a1eeSThomas Cort */
322*b618a1eeSThomas Cort free(new_one->name.string);
323*b618a1eeSThomas Cort free(new_one);
324*b618a1eeSThomas Cort return NULL;
325*b618a1eeSThomas Cort }
326*b618a1eeSThomas Cort
327*b618a1eeSThomas Cort strcpy(new_one->description.string, description);
328*b618a1eeSThomas Cort }
329*b618a1eeSThomas Cort
330*b618a1eeSThomas Cort return new_one;
331*b618a1eeSThomas Cort }
332*b618a1eeSThomas Cort
333*b618a1eeSThomas Cort /*
334*b618a1eeSThomas Cort * Free the allocated storage associated with item.
335*b618a1eeSThomas Cort */
336*b618a1eeSThomas Cort int
free_item(ITEM * item)337*b618a1eeSThomas Cort free_item(ITEM *item)
338*b618a1eeSThomas Cort {
339*b618a1eeSThomas Cort if (item == NULL)
340*b618a1eeSThomas Cort return E_BAD_ARGUMENT;
341*b618a1eeSThomas Cort
342*b618a1eeSThomas Cort /* check for connection to menu */
343*b618a1eeSThomas Cort if (item->parent != NULL)
344*b618a1eeSThomas Cort return E_CONNECTED;
345*b618a1eeSThomas Cort
346*b618a1eeSThomas Cort /* no connections, so free storage starting with the strings */
347*b618a1eeSThomas Cort free(item->name.string);
348*b618a1eeSThomas Cort if (item->description.length)
349*b618a1eeSThomas Cort free(item->description.string);
350*b618a1eeSThomas Cort free(item);
351*b618a1eeSThomas Cort return E_OK;
352*b618a1eeSThomas Cort }
353*b618a1eeSThomas Cort
354*b618a1eeSThomas Cort /*
355*b618a1eeSThomas Cort * Set the menu's current item to the one given.
356*b618a1eeSThomas Cort */
357*b618a1eeSThomas Cort int
set_current_item(MENU * param_menu,ITEM * item)358*b618a1eeSThomas Cort set_current_item(MENU *param_menu, ITEM *item)
359*b618a1eeSThomas Cort {
360*b618a1eeSThomas Cort MENU *menu = (param_menu != NULL) ? param_menu : &_menui_default_menu;
361*b618a1eeSThomas Cort int i = 0;
362*b618a1eeSThomas Cort
363*b618a1eeSThomas Cort /* check if we have been called from an init type function */
364*b618a1eeSThomas Cort if (menu->in_init == 1)
365*b618a1eeSThomas Cort return E_BAD_STATE;
366*b618a1eeSThomas Cort
367*b618a1eeSThomas Cort /* check we have items in the menu */
368*b618a1eeSThomas Cort if (menu->items == NULL)
369*b618a1eeSThomas Cort return E_NOT_CONNECTED;
370*b618a1eeSThomas Cort
371*b618a1eeSThomas Cort if ((i = item_index(item)) < 0)
372*b618a1eeSThomas Cort /* item must not be a part of this menu */
373*b618a1eeSThomas Cort return E_BAD_ARGUMENT;
374*b618a1eeSThomas Cort
375*b618a1eeSThomas Cort menu->cur_item = i;
376*b618a1eeSThomas Cort return E_OK;
377*b618a1eeSThomas Cort }
378*b618a1eeSThomas Cort
379*b618a1eeSThomas Cort /*
380*b618a1eeSThomas Cort * Return a pointer to the current item for the menu
381*b618a1eeSThomas Cort */
382*b618a1eeSThomas Cort ITEM *
current_item(MENU * menu)383*b618a1eeSThomas Cort current_item(MENU *menu)
384*b618a1eeSThomas Cort {
385*b618a1eeSThomas Cort if (menu == NULL)
386*b618a1eeSThomas Cort return NULL;
387*b618a1eeSThomas Cort
388*b618a1eeSThomas Cort if (menu->items == NULL)
389*b618a1eeSThomas Cort return NULL;
390*b618a1eeSThomas Cort
391*b618a1eeSThomas Cort return menu->items[menu->cur_item];
392*b618a1eeSThomas Cort }
393*b618a1eeSThomas Cort
394*b618a1eeSThomas Cort /*
395*b618a1eeSThomas Cort * Return the index into the item array that matches item.
396*b618a1eeSThomas Cort */
397*b618a1eeSThomas Cort int
item_index(ITEM * item)398*b618a1eeSThomas Cort item_index(ITEM *item)
399*b618a1eeSThomas Cort {
400*b618a1eeSThomas Cort if (item == NULL)
401*b618a1eeSThomas Cort return _menui_default_item.index;
402*b618a1eeSThomas Cort else
403*b618a1eeSThomas Cort return item->index;
404*b618a1eeSThomas Cort }
405