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 */ 38extern MENU _menui_default_menu; 39 40/* keep default item options for setting in new_item */ 41ITEM _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 */ 61int 62item_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 */ 75char * 76item_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 */ 87char * 88item_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 */ 100int 101set_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 */ 114Menu_Hook 115item_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 */ 127int 128set_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 */ 140Menu_Hook 141item_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 */ 154int 155item_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 */ 187int 188set_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 */ 204int 205item_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 */ 220int 221item_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 */ 236OPTIONS 237item_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 */ 248int 249set_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 */ 269int 270item_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 */ 282ITEM * 283new_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 */ 336int 337free_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 */ 357int 358set_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 */ 382ITEM * 383current_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 */ 397int 398item_index(ITEM *item) 399{ 400 if (item == NULL) 401 return _menui_default_item.index; 402 else 403 return item->index; 404} 405