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