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@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.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
item_visible(ITEM * item)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 *
item_name(ITEM * item)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 *
item_description(ITEM * item)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
set_item_init(MENU * menu,Menu_Hook func)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
item_init(MENU * menu)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
set_item_term(MENU * menu,Menu_Hook func)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
item_term(MENU * menu)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
item_selected(MENU * menu,int ** sel)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
set_item_opts(ITEM * item,OPTIONS opts)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
item_opts_on(ITEM * item,OPTIONS opts)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
item_opts_off(ITEM * item,OPTIONS opts)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
item_opts(ITEM * item)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
set_item_value(ITEM * param_item,int flag)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
item_value(ITEM * item)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 *
new_item(char * name,char * description)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
free_item(ITEM * item)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
set_current_item(MENU * param_menu,ITEM * item)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 *
current_item(MENU * menu)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
item_index(ITEM * item)398 item_index(ITEM *item)
399 {
400 if (item == NULL)
401 return _menui_default_item.index;
402 else
403 return item->index;
404 }
405