1 /* $NetBSD: item.c,v 1.10 2003/09/29 12:32:24 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.10 2003/09/29 12:32:24 blymn Exp $"); 31 32 #include <menu.h> 33 #include <stdlib.h> 34 #include <string.h> 35 36 /* the following is defined in menu.c - it is the default menu struct */ 37 extern MENU _menui_default_menu; 38 39 /* keep default item options for setting in new_item */ 40 ITEM _menui_default_item = { 41 {NULL, 0}, /* item name struct */ 42 {NULL, 0}, /* item description struct */ 43 NULL, /* user pointer */ 44 0, /* is item visible? */ 45 0, /* is item selected? */ 46 0, /* row item is on */ 47 0, /* column item is on */ 48 O_SELECTABLE, /* item options */ 49 NULL, /* parent menu item is bound to */ 50 -1, /* index number if item attached to a menu */ 51 NULL, /* left neighbour */ 52 NULL, /* right neighbour */ 53 NULL, /* up neighbour */ 54 NULL /* down neighbour */ 55 }; 56 57 /* 58 * Return the item visibility flag 59 */ 60 int 61 item_visible(ITEM *item) 62 { 63 if (item == NULL) 64 return E_BAD_ARGUMENT; 65 if (item->parent == NULL) 66 return E_NOT_CONNECTED; 67 68 return item->visible; 69 } 70 71 /* 72 * Return the pointer to the item name 73 */ 74 char * 75 item_name(ITEM *item) 76 { 77 if (item == NULL) 78 return NULL; 79 80 return item->name.string; 81 } 82 83 /* 84 * Return the pointer to the item description 85 */ 86 char * 87 item_description(ITEM *item) 88 { 89 if (item == NULL) 90 return NULL; 91 92 return item->description.string; 93 } 94 95 /* 96 * Set the application defined function called when the menu is posted or 97 * just after the current item changes. 98 */ 99 int 100 set_item_init(MENU *menu, Menu_Hook func) 101 { 102 if (menu == NULL) 103 _menui_default_menu.item_init = func; 104 else 105 menu->item_init = func; 106 return E_OK; 107 } 108 109 110 /* 111 * Return a pointer to the item initialisation routine. 112 */ 113 Menu_Hook 114 item_init(MENU *menu) 115 { 116 if (menu == NULL) 117 return _menui_default_menu.item_init; 118 else 119 return menu->item_init; 120 } 121 122 /* 123 * Set the user defined function to be called when menu is unposted or just 124 * before the current item changes. 125 */ 126 int 127 set_item_term(MENU *menu, Menu_Hook func) 128 { 129 if (menu == NULL) 130 _menui_default_menu.item_term = func; 131 else 132 menu->item_term = func; 133 return E_OK; 134 } 135 136 /* 137 * Return a pointer to the termination function 138 */ 139 Menu_Hook 140 item_term(MENU *menu) 141 { 142 if (menu == NULL) 143 return _menui_default_menu.item_term; 144 else 145 return menu->item_term; 146 } 147 148 /* 149 * Returns the number of items that are selected. 150 * The index numbers of the items are placed in the dynamically allocated 151 * int array *sel. 152 */ 153 int 154 item_selected(MENU *menu, int **sel) 155 { 156 int i, j; 157 158 if (menu == NULL) 159 return E_BAD_ARGUMENT; 160 161 /* count selected */ 162 for (i = 0, j = 0; i < menu->item_count; i++) 163 if (menu->items[i]->selected) 164 j++; 165 166 if (j == 0) { 167 *sel = NULL; 168 return 0; 169 } 170 171 if ( (*sel = malloc(sizeof(int) * j)) == NULL) 172 return E_SYSTEM_ERROR; 173 174 for (i = 0, j = 0; i < menu->item_count; i++) 175 if (menu->items[i]->selected) 176 (*sel)[j++] = i; 177 178 return j; 179 } 180 181 /* 182 * Set the item options. We keep a global copy of the current item options 183 * as subsequent new_item calls will use the updated options as their 184 * defaults. 185 */ 186 int 187 set_item_opts(item, opts) 188 ITEM *item; 189 OPTIONS opts; 190 { 191 /* selectable seems to be the only allowable item opt! */ 192 if (opts != O_SELECTABLE) 193 return E_SYSTEM_ERROR; 194 195 if (item == NULL) 196 _menui_default_item.opts = opts; 197 else 198 item->opts = opts; 199 return E_OK; 200 } 201 202 /* 203 * Set item options on. 204 */ 205 int 206 item_opts_on(ITEM *item, OPTIONS opts) 207 { 208 if (opts != O_SELECTABLE) 209 return E_SYSTEM_ERROR; 210 211 if (item == NULL) 212 _menui_default_item.opts |= opts; 213 else 214 item->opts |= opts; 215 return E_OK; 216 } 217 218 /* 219 * Turn off the named options. 220 */ 221 int 222 item_opts_off(ITEM *item, OPTIONS opts) 223 { 224 if (opts != O_SELECTABLE) 225 return E_SYSTEM_ERROR; 226 227 if (item == NULL) 228 _menui_default_item.opts &= ~(opts); 229 else 230 item->opts &= ~(opts); 231 return E_OK; 232 } 233 234 /* 235 * Return the current options set in item. 236 */ 237 OPTIONS 238 item_opts(ITEM *item) 239 { 240 if (item == NULL) 241 return _menui_default_item.opts; 242 else 243 return item->opts; 244 } 245 246 /* 247 * Set the selected flag of the item iff the menu options allow it. 248 */ 249 int 250 set_item_value(ITEM *param_item, int flag) 251 { 252 ITEM *item = (param_item != NULL) ? param_item : &_menui_default_item; 253 254 /* not bound to a menu */ 255 if (item->parent == NULL) 256 return E_NOT_CONNECTED; 257 258 /* menu options do not allow multi-selection */ 259 if ((item->parent->opts & O_ONEVALUE) == O_ONEVALUE) 260 return E_REQUEST_DENIED; 261 262 item->selected = flag; 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