xref: /netbsd-src/lib/libmenu/item.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$NetBSD: item.c,v 1.11 2007/07/23 12:12:19 blymn 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.11 2007/07/23 12:12:19 blymn 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
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 *
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 *
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
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
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
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
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
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
188 set_item_opts(item, opts)
189         ITEM *item;
190         OPTIONS opts;
191 {
192           /* selectable seems to be the only allowable item opt! */
193         if (opts != O_SELECTABLE)
194                 return E_SYSTEM_ERROR;
195 
196 	if (item == NULL)
197 		_menui_default_item.opts = opts;
198 	else
199 		item->opts = opts;
200         return E_OK;
201 }
202 
203 /*
204  * Set item options on.
205  */
206 int
207 item_opts_on(ITEM *item, OPTIONS opts)
208 {
209         if (opts != O_SELECTABLE)
210                 return E_SYSTEM_ERROR;
211 
212         if (item == NULL)
213 		_menui_default_item.opts |= opts;
214 	else
215 		item->opts |= opts;
216         return E_OK;
217 }
218 
219 /*
220  * Turn off the named options.
221  */
222 int
223 item_opts_off(ITEM *item, OPTIONS opts)
224 {
225         if (opts != O_SELECTABLE)
226                 return E_SYSTEM_ERROR;
227 
228 	if (item == NULL)
229 		_menui_default_item.opts &= ~(opts);
230 	else
231 		item->opts &= ~(opts);
232         return E_OK;
233 }
234 
235 /*
236  * Return the current options set in item.
237  */
238 OPTIONS
239 item_opts(ITEM *item)
240 {
241 	if (item == NULL)
242 		return _menui_default_item.opts;
243 	else
244 		return item->opts;
245 }
246 
247 /*
248  * Set the selected flag of the item iff the menu options allow it.
249  */
250 int
251 set_item_value(ITEM *param_item, int flag)
252 {
253 	ITEM *item = (param_item != NULL) ? param_item : &_menui_default_item;
254 
255           /* not bound to a menu */
256         if (item->parent == NULL)
257                 return E_NOT_CONNECTED;
258 
259           /* menu options do not allow multi-selection */
260         if ((item->parent->opts & O_ONEVALUE) == O_ONEVALUE)
261                 return E_REQUEST_DENIED;
262 
263         item->selected = flag;
264 	_menui_draw_item(item->parent, item->index);
265         return E_OK;
266 }
267 
268 /*
269  * Return the item value of the item.
270  */
271 int
272 item_value(ITEM *item)
273 {
274 	if (item == NULL)
275 		return _menui_default_item.selected;
276 	else
277 		return item->selected;
278 }
279 
280 /*
281  * Allocate a new item and return the pointer to the newly allocated
282  * structure.
283  */
284 ITEM *
285 new_item(char *name, char *description)
286 {
287         ITEM *new_one;
288 
289 	if (name == NULL)
290 		return NULL;
291 
292 	  /* allocate a new item structure for ourselves */
293         if ((new_one = (ITEM *)malloc(sizeof(ITEM))) == NULL)
294                 return NULL;
295 
296 	  /* copy in the defaults for the item */
297 	(void)memcpy(new_one, &_menui_default_item, sizeof(ITEM));
298 
299 	  /* fill in the name structure - first the length and then
300 	     allocate room for the string & copy that. */
301 	new_one->name.length = strlen(name);
302         if ((new_one->name.string = (char *)
303              malloc(sizeof(char) * new_one->name.length + 1)) == NULL) {
304 		  /* uh oh malloc failed - clean up & exit */
305 		free(new_one);
306                 return NULL;
307         }
308 
309         strcpy(new_one->name.string, name);
310 
311 	if (description == NULL)
312 		new_one->description.length = 0;
313 	else {
314 	  /* fill in the description structure, stash the length then
315 	     allocate room for description string and copy it in */
316         	new_one->description.length = strlen(description);
317         	if ((new_one->description.string =
318 		    (char *) malloc(sizeof(char) *
319 		    new_one->description.length + 1)) == NULL) {
320 		  	/*
321 			 * malloc has failed
322 			 * - free up allocated memory and return
323 			 */
324 			free(new_one->name.string);
325 			free(new_one);
326 			return NULL;
327 		}
328 
329 		strcpy(new_one->description.string, description);
330 	}
331 
332 	return new_one;
333 }
334 
335 /*
336  * Free the allocated storage associated with item.
337  */
338 int
339 free_item(ITEM *item)
340 {
341 	if (item == NULL)
342 		return E_BAD_ARGUMENT;
343 
344 	  /* check for connection to menu */
345 	if (item->parent != NULL)
346 		return E_CONNECTED;
347 
348 	  /* no connections, so free storage starting with the strings */
349 	free(item->name.string);
350 	if (item->description.length)
351 		free(item->description.string);
352 	free(item);
353 	return E_OK;
354 }
355 
356 /*
357  * Set the menu's current item to the one given.
358  */
359 int
360 set_current_item(MENU *param_menu, ITEM *item)
361 {
362 	MENU *menu = (param_menu != NULL) ? param_menu : &_menui_default_menu;
363 	int i = 0;
364 
365 	  /* check if we have been called from an init type function */
366 	if (menu->in_init == 1)
367 		return E_BAD_STATE;
368 
369 	  /* check we have items in the menu */
370 	if (menu->items == NULL)
371 		return E_NOT_CONNECTED;
372 
373 	if ((i = item_index(item)) < 0)
374 		  /* item must not be a part of this menu */
375 		return E_BAD_ARGUMENT;
376 
377 	menu->cur_item = i;
378 	return E_OK;
379 }
380 
381 /*
382  * Return a pointer to the current item for the menu
383  */
384 ITEM *
385 current_item(MENU *menu)
386 {
387 	if (menu == NULL)
388 		return NULL;
389 
390 	if (menu->items == NULL)
391 		return NULL;
392 
393 	return menu->items[menu->cur_item];
394 }
395 
396 /*
397  * Return the index into the item array that matches item.
398  */
399 int
400 item_index(ITEM *item)
401 {
402 	if (item == NULL)
403 		return _menui_default_item.index;
404 	else
405 		return item->index;
406 }
407