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