item.c revision 1.9 1 /* $NetBSD: item.c,v 1.9 2003/03/09 01:08:48 lukem 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.9 2003/03/09 01:08:48 lukem 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 /* allocate a new item structure for ourselves */
288 if ((new_one = (ITEM *)malloc(sizeof(ITEM))) == NULL)
289 return NULL;
290
291 /* copy in the defaults for the item */
292 (void)memcpy(new_one, &_menui_default_item, sizeof(ITEM));
293
294 /* fill in the name structure - first the length and then
295 allocate room for the string & copy that. */
296 new_one->name.length = strlen(name);
297 if ((new_one->name.string = (char *)
298 malloc(sizeof(char) * new_one->name.length + 1)) == NULL) {
299 /* uh oh malloc failed - clean up & exit */
300 free(new_one);
301 return NULL;
302 }
303
304 strcpy(new_one->name.string, name);
305
306 /* fill in the description structure, stash the length then
307 allocate room for description string and copy it in */
308 new_one->description.length = strlen(description);
309 if ((new_one->description.string = (char *)
310 malloc(sizeof(char) * new_one->description.length + 1)) == NULL) {
311 /* malloc has failed - free up allocated memory and return */
312 free(new_one->name.string);
313 free(new_one);
314 return NULL;
315 }
316
317 strcpy(new_one->description.string, description);
318
319 return new_one;
320 }
321
322 /*
323 * Free the allocated storage associated with item.
324 */
325 int
326 free_item(ITEM *item)
327 {
328 if (item == NULL)
329 return E_BAD_ARGUMENT;
330
331 /* check for connection to menu */
332 if (item->parent != NULL)
333 return E_CONNECTED;
334
335 /* no connections, so free storage starting with the strings */
336 free(item->name.string);
337 free(item->description.string);
338 free(item);
339 return E_OK;
340 }
341
342 /*
343 * Set the menu's current item to the one given.
344 */
345 int
346 set_current_item(MENU *param_menu, ITEM *item)
347 {
348 MENU *menu = (param_menu != NULL) ? param_menu : &_menui_default_menu;
349 int i = 0;
350
351 /* check if we have been called from an init type function */
352 if (menu->in_init == 1)
353 return E_BAD_STATE;
354
355 /* check we have items in the menu */
356 if (menu->items == NULL)
357 return E_NOT_CONNECTED;
358
359 if ((i = item_index(item)) < 0)
360 /* item must not be a part of this menu */
361 return E_BAD_ARGUMENT;
362
363 menu->cur_item = i;
364 return E_OK;
365 }
366
367 /*
368 * Return a pointer to the current item for the menu
369 */
370 ITEM *
371 current_item(MENU *menu)
372 {
373 if (menu == NULL)
374 return NULL;
375
376 if (menu->items == NULL)
377 return NULL;
378
379 return menu->items[menu->cur_item];
380 }
381
382 /*
383 * Return the index into the item array that matches item.
384 */
385 int
386 item_index(ITEM *item)
387 {
388 if (item == NULL)
389 return _menui_default_item.index;
390 else
391 return item->index;
392 }
393