Home | History | Annotate | Line # | Download | only in libmenu
      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 (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.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
     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 *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
    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
    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
    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
    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
    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 *
    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
    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
    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 *
    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
    398 item_index(ITEM *item)
    399 {
    400 	if (item == NULL)
    401 		return _menui_default_item.index;
    402 	else
    403 		return item->index;
    404 }
    405