Home | History | Annotate | Line # | Download | only in libmenu
item.c revision 1.11.16.2
      1 /*	$NetBSD: item.c,v 1.11.16.2 2007/07/23 12:12:20 blymn Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1998-1999 Brett Lymn (blymn (at) baea.com.au, brett_lymn (at) 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.16.2 2007/07/23 12:12:20 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