1 /*
2 * Program: objects.c
3 * Author: Marc van Kempen
4 * Desc: Implementation of UI-objects:
5 * - String input fields
6 * - List selection
7 * - Buttons
8 *
9 * Copyright (c) 1995, Marc van Kempen
10 *
11 * All rights reserved.
12 *
13 * This software may be used, modified, copied, distributed, and
14 * sold, in both source and binary form provided that the above
15 * copyright and these terms are retained, verbatim, as the first
16 * lines of this file. Under no circumstances is the author
17 * responsible for the proper functioning of this software, nor does
18 * the author assume any responsibility for damages incurred with
19 * its use.
20 *
21 */
22
23 #include <stdlib.h>
24 #include <sys/param.h>
25 #include <ncurses.h>
26 #include <dialog.h>
27 #include "dialog.priv.h"
28 #include "ui_objects.h"
29
30 #define ESC 27
31
32 /***********************************************************************
33 *
34 * Obj routines
35 *
36 ***********************************************************************/
37
38 void
AddObj(ComposeObj ** Obj,int objtype,void * obj)39 AddObj(ComposeObj **Obj, int objtype, void *obj)
40 /*
41 * Desc: Add the object <obj> to the list of objects <Obj>
42 */
43 {
44 if (*Obj == NULL) {
45 /* Create the root object */
46 *Obj = (ComposeObj *) malloc( sizeof(ComposeObj) );
47 if (!Obj) {
48 printf("AddObj: Error malloc'ing ComposeObj\n");
49 exit(-1);
50 }
51 (*Obj)->objtype = objtype;
52 (*Obj)->obj = obj;
53 (*Obj)->next = NULL;
54 (*Obj)->prev = NULL;
55 } else {
56 ComposeObj *o = *Obj;
57
58 /* create the next object */
59 while (o->next) o = (ComposeObj *) o->next;
60 o->next = (struct ComposeObj *) malloc( sizeof(ComposeObj) );
61 if (!o->next) {
62 printf("AddObj: Error malloc'ing o->next\n");
63 exit(-1);
64 }
65 o->next->objtype = objtype;
66 o->next->obj = obj;
67 o->next->next = NULL;
68 o->next->prev = o;
69 }
70
71 return;
72 } /* AddObj() */
73
74 void
FreeObj(ComposeObj * Obj)75 FreeObj(ComposeObj *Obj)
76 /*
77 * Desc: free the memory occupied by *Obj
78 */
79 {
80 ComposeObj *o = Obj;
81
82 o = Obj;
83 while (o) {
84 o = Obj->next;
85 free(Obj);
86 Obj = o;
87 }
88
89 return;
90 } /* FreeObj() */
91
92
93 int
ReadObj(ComposeObj * Obj)94 ReadObj(ComposeObj *Obj)
95 /*
96 * Desc: navigate through the different objects calling their
97 * respective navigation routines as necessary
98 * Pre: Obj != NULL
99 */
100 {
101 ComposeObj *o;
102 ComposeObj *last; /* the last object in the list */
103 int ret; /* the return value from the selection routine */
104
105 /* find the last object in the list */
106 last = Obj;
107 while (last->next) last = last->next;
108
109 ret = 0;
110 o = Obj;
111 while ((ret != SEL_BUTTON) && (ret != SEL_ESC)) {
112 switch(o->objtype) {
113 case STRINGOBJ:
114 ret = SelectStringObj((StringObj *) o->obj);
115 break;
116 case LISTOBJ:
117 ret = SelectListObj((ListObj *) o->obj);
118 break;
119 case BUTTONOBJ:
120 ret = SelectButtonObj((ButtonObj *) o->obj);
121 break;
122 }
123 switch(ret) {
124 case KEY_DOWN:
125 case SEL_CR:
126 case SEL_TAB: /* move to the next object in the list */
127 if (o->next != NULL) {
128 o = o->next; /* next object */
129 } else {
130 o = Obj; /* beginning of the list */
131 }
132 break;
133
134 case KEY_UP:
135 case SEL_BACKTAB: /* move to the previous object in the list */
136 if (o->prev != NULL) {
137 o = o->prev; /* previous object */
138 } else {
139 o = last; /* end of the list */
140 }
141 break;
142
143 case KEY_F(1): /* display help_file */
144 case '?':
145 display_helpfile();
146 break;
147 }
148 }
149
150 return(ret);
151
152 } /* ReadObj() */
153
154
155 int
PollObj(ComposeObj ** Obj)156 PollObj(ComposeObj **Obj)
157 {
158 ComposeObj *last; /* the last object in the list */
159 ComposeObj *first; /* the first object in the list */
160 int ret; /* the return value from the selection routine */
161
162 /* find the last object in the list */
163 last = *Obj;
164 while (last->next) last = last->next;
165
166 /* find the first object in the list */
167 first = *Obj;
168 while (first->prev) first = first->prev;
169
170 ret = 0;
171 switch((*Obj)->objtype) {
172 case STRINGOBJ:
173 ret = SelectStringObj((StringObj *) (*Obj)->obj);
174 break;
175 case LISTOBJ:
176 ret = SelectListObj((ListObj *) (*Obj)->obj);
177 break;
178 case BUTTONOBJ:
179 ret = SelectButtonObj((ButtonObj *) (*Obj)->obj);
180 break;
181 }
182 switch(ret) {
183 case KEY_DOWN:
184 case SEL_CR:
185 case SEL_TAB: /* move to the next object in the list */
186 if ((*Obj)->next != NULL) {
187 *Obj = (*Obj)->next; /* next object */
188 } else {
189 *Obj = first; /* beginning of the list */
190 }
191 break;
192
193 case KEY_UP:
194 case SEL_BACKTAB: /* move to the previous object in the list */
195 if ((*Obj)->prev != NULL) {
196 *Obj = (*Obj)->prev; /* previous object */
197 } else {
198 *Obj = last; /* end of the list */
199 }
200 break;
201 }
202
203 return(ret);
204
205 } /* PollObj() */
206
207
208 void
DelObj(ComposeObj * Obj)209 DelObj(ComposeObj *Obj)
210 /*
211 * Desc: Free all objects
212 */
213 {
214 ComposeObj *o;
215
216 o = Obj;
217 while (Obj != NULL) {
218 switch(Obj->objtype) {
219 case STRINGOBJ:
220 DelStringObj((StringObj *) Obj->obj);
221 break;
222 case LISTOBJ:
223 DelListObj((ListObj *) Obj->obj);
224 break;
225 case BUTTONOBJ:
226 DelButtonObj((ButtonObj *) Obj->obj);
227 break;
228 }
229 Obj = Obj->next;
230 }
231
232 FreeObj(o);
233 } /* DelObj() */
234
235 /***********************************************************************
236 *
237 * StringObj routines
238 *
239 ***********************************************************************/
240
241 static void
outstr(WINDOW * win,char * str,int attrs)242 outstr(WINDOW *win, char *str, int attrs)
243 {
244 if (attrs & DITEM_NO_ECHO) {
245 char *cpy;
246 int n = strlen(str);
247
248 cpy = alloca(n + 1);
249 memset(cpy, '*', n);
250 cpy[n] = '\0';
251 waddstr(win, cpy);
252 }
253 else
254 waddstr(win, str);
255 }
256
257 void
RefreshStringObj(StringObj * so)258 RefreshStringObj(StringObj *so)
259 /*
260 * Desc: redraw the object
261 */
262 {
263 char tmp[512];
264
265 wmove(so->win, so->y, so->x+1);
266 wattrset(so->win, dialog_attr);
267 waddstr(so->win, so->title);
268
269 draw_box(so->win, so->y+1, so->x, 3, so->w, dialog_attr, border_attr);
270 wattrset(so->win, item_attr);
271 wmove(so->win, so->y+2, so->x+1);
272 if (strlen(so->s) > so->w-2) {
273 strncpy(tmp, (char *) so->s + strlen(so->s) - so->w + 2, so->w - 1);
274 outstr(so->win, tmp, so->attr_mask);
275 } else {
276 outstr(so->win, so->s, so->attr_mask);
277 }
278
279 return;
280 } /* RefreshStringObj() */
281
282 StringObj *
NewStringObj(WINDOW * win,char * title,char * s,int y,int x,int w,int len)283 NewStringObj(WINDOW *win, char *title, char *s, int y, int x, int w, int len)
284 /*
285 * Desc: Initialize a new stringobj and return a pointer to it.
286 * Draw the object on the screen at the specified coordinates
287 */
288 {
289 StringObj *so;
290
291 /* Initialize a new object */
292 so = (StringObj *) malloc( sizeof(StringObj) );
293 if (!so) {
294 printf("NewStringObj: Error malloc'ing StringObj\n");
295 exit(-1);
296 }
297 so->title = (char *) malloc( strlen(title) + 1);
298 if (!so->title) {
299 printf("NewStringObj: Error malloc'ing so->title\n");
300 exit(-1);
301 }
302 strcpy(so->title, title);
303 so->s = s;
304 strcpy(so->s, s);
305 so->x = x;
306 so->y = y;
307 so->w = w;
308 so->len = len;
309 so->win = win;
310 so->attr_mask = DialogInputAttrs; /* Grossly use a global to avoid changing API */
311
312 /* Draw it on the screen */
313 RefreshStringObj(so);
314
315 return(so);
316 } /* NewStringObj() */
317
318 int
SelectStringObj(StringObj * so)319 SelectStringObj(StringObj *so)
320 /*
321 * Desc: get input using the info in <so>
322 */
323 {
324 int key;
325 char tmp[so->len+1];
326
327 strcpy(tmp, so->s);
328 key = line_edit(so->win, so->y+2, so->x+1,
329 so->len, so->w-2, inputbox_attr, TRUE, tmp, so->attr_mask);
330 if ((key == '\n') || (key == '\r') || (key == '\t') || key == (KEY_BTAB) ) {
331 strcpy(so->s, tmp);
332 }
333 RefreshStringObj(so);
334 if (key == ESC) {
335 return(SEL_ESC);
336 }
337 if (key == '\t') {
338 return(SEL_TAB);
339 }
340 if ( (key == KEY_BTAB) || (key == KEY_F(2)) ) {
341 return(SEL_BACKTAB);
342 }
343 if ((key == '\n') || (key == '\r')) {
344 return(SEL_CR);
345 }
346 return(key);
347 } /* SelectStringObj() */
348
349
350 void
DelStringObj(StringObj * so)351 DelStringObj(StringObj *so)
352 /*
353 * Desc: Free the space occupied by <so>
354 */
355 {
356 free(so->title);
357 free(so);
358
359 return;
360 }
361
362 /***********************************************************************
363 *
364 * ListObj routines
365 *
366 ***********************************************************************/
367
368 void
DrawNames(ListObj * lo)369 DrawNames(ListObj *lo)
370 /*
371 * Desc: Just refresh the names, not the surrounding box and title
372 */
373 {
374 int i, j, h, x, y;
375 char tmp[MAXPATHLEN];
376
377 x = lo->x + 1;
378 y = lo->y + 2;
379 h = lo->h - 2;
380 for (i=lo->scroll; i<lo->n && i<lo->scroll+h; i++) {
381 wmove(lo->win, y+i-lo->scroll, x);
382 if (lo->seld[i]) {
383 wattrset(lo->win, A_BOLD);
384 } else {
385 wattrset(lo->win, item_attr);
386 }
387 if (strlen(lo->name[i]) > lo->w-2) {
388 strncpy(tmp, lo->name[i], lo->w-2);
389 tmp[lo->w - 2] = 0;
390 waddstr(lo->win, tmp);
391 } else {
392 waddstr(lo->win, lo->name[i]);
393 for (j=strlen(lo->name[i]); j<lo->w-2; j++) waddstr(lo->win, " ");
394 }
395 }
396 wattrset(lo->win, item_attr);
397 while (i<lo->scroll+h) {
398 wmove(lo->win, y+i-lo->scroll, x);
399 for (j=0; j<lo->w-2; j++) waddstr(lo->win, " ");
400 i++;
401 }
402
403 return;
404 } /* DrawNames() */
405
406 void
RefreshListObj(ListObj * lo)407 RefreshListObj(ListObj *lo)
408 /*
409 * Desc: redraw the list object
410 */
411 {
412 char perc[7];
413
414 /* setup the box */
415 wmove(lo->win, lo->y, lo->x+1);
416 wattrset(lo->win, dialog_attr);
417 waddstr(lo->win, lo->title);
418 draw_box(lo->win, lo->y+1, lo->x, lo->h, lo->w, dialog_attr, border_attr);
419
420 /* draw the names */
421 DrawNames(lo);
422
423 /* Draw % indication */
424 sprintf(perc, "(%3d%%)", MIN(100, (int) (100 * (lo->sel+lo->h-2) / MAX(1, lo->n))));
425 wmove(lo->win, lo->y + lo->h, lo->x + lo->w - 8);
426 wattrset(lo->win, dialog_attr);
427 waddstr(lo->win, perc);
428
429
430 return;
431 } /* RefreshListObj() */
432
433 ListObj *
NewListObj(WINDOW * win,char * title,char ** list,char * listelt,int y,int x,int h,int w,int n)434 NewListObj(WINDOW *win, char *title, char **list, char *listelt, int y, int x,
435 int h, int w, int n)
436 /*
437 * Desc: create a listobj, draw it on the screen and return a pointer to it.
438 */
439 {
440 ListObj *lo;
441 int i;
442
443 /* Initialize a new object */
444 lo = (ListObj *) malloc( sizeof(ListObj) );
445 if (!lo) {
446 fprintf(stderr, "NewListObj: Error malloc'ing ListObj\n");
447 exit(-1);
448 }
449 lo->title = (char *) malloc( strlen(title) + 1);
450 if (!lo->title) {
451 fprintf(stderr, "NewListObj: Error malloc'ing lo->title\n");
452 exit(-1);
453 }
454 strcpy(lo->title, title);
455 lo->name = list;
456 if (n>0) {
457 lo->seld = (int *) malloc( n * sizeof(int) );
458 if (!lo->seld) {
459 fprintf(stderr, "NewListObj: Error malloc'ing lo->seld\n");
460 exit(-1);
461 }
462 for (i=0; i<n; i++) {
463 lo->seld[i] = FALSE;
464 }
465 } else {
466 lo->seld = NULL;
467 }
468 lo->y = y;
469 lo->x = x;
470 lo->w = w;
471 lo->h = h;
472 lo->n = n;
473 lo->scroll = 0;
474 lo->sel = 0;
475 lo->elt = listelt;
476 lo->win = win;
477
478 /* Draw the object on the screen */
479 RefreshListObj(lo);
480
481 return(lo);
482 } /* NewListObj() */
483
484 void
UpdateListObj(ListObj * lo,char ** list,int n)485 UpdateListObj(ListObj *lo, char **list, int n)
486 /*
487 * Desc: Update the list in the listobject with the provided list
488 * Pre: lo->name "has been freed"
489 * "(A i: 0<=i<lo->n: "lo->name[i] has been freed")"
490 */
491 {
492 int i;
493
494 if (lo->seld) {
495 free(lo->seld);
496 }
497
498 /* Rewrite the list in the object */
499 lo->name = list;
500 if (n>0) {
501 lo->seld = (int *) malloc( n * sizeof(int) );
502 if (!lo->seld) {
503 fprintf(stderr, "UpdateListObj: Error malloc'ing lo->seld\n");
504 exit(-1);
505 }
506 for (i=0; i<n; i++) {
507 lo->seld[i] = FALSE;
508 }
509 } else {
510 lo->seld = NULL;
511 }
512 lo->n = n;
513 lo->scroll = 0;
514 lo->sel = 0;
515
516 /* Draw the object on the screen */
517 RefreshListObj(lo);
518
519 return;
520 } /* UpdateListObj() */
521
522 int
SelectListObj(ListObj * lo)523 SelectListObj(ListObj *lo)
524 /*
525 * Desc: get a listname (or listnames), TAB to move on, or ESC ESC to exit
526 * Pre: lo->n >= 1
527 */
528 {
529 int key, sel_x, sel_y, quit;
530 char tmp[MAXPATHLEN];
531 char perc[4];
532
533 sel_x = lo->x+1;
534 sel_y = lo->y + 2 + lo->sel - lo->scroll;
535
536 if (lo->n == 0) return(SEL_TAB);
537
538 keypad(lo->win, TRUE);
539
540 /* Draw current selection in inverse video */
541 wmove(lo->win, sel_y, sel_x);
542 wattrset(lo->win, item_selected_attr);
543 waddstr(lo->win, lo->name[lo->sel]);
544
545 key = wgetch(lo->win);
546 quit = FALSE;
547 while ((key != '\t') && (key != '\n') && (key != '\r')
548 && (key != ESC) && (key != KEY_F(1)) && (key != '?') && !quit) {
549 /* first draw current item in normal video */
550 wmove(lo->win, sel_y, sel_x);
551 if (lo->seld[lo->sel]) {
552 wattrset(lo->win, A_BOLD);
553 } else {
554 wattrset(lo->win, item_attr);
555 }
556 if (strlen(lo->name[lo->sel]) > lo->w - 2) {
557 strncpy(tmp, lo->name[lo->sel], lo->w - 2);
558 tmp[lo->w - 2] = 0;
559 waddstr(lo->win, tmp);
560 } else {
561 waddstr(lo->win, lo->name[lo->sel]);
562 }
563
564 switch (key) {
565 case KEY_DOWN:
566 case ctrl('n'):
567 if (sel_y < lo->y + lo->h-1) {
568 if (lo->sel < lo->n-1) {
569 sel_y++;
570 lo->sel++;
571 }
572 } else {
573 if (lo->sel < lo->n-1) {
574 lo->sel++;
575 lo->scroll++;
576 DrawNames(lo);
577 wrefresh(lo->win);
578 }
579 }
580 break;
581 case KEY_UP:
582 case ctrl('p'):
583 if (sel_y > lo->y+2) {
584 if (lo->sel > 0) {
585 sel_y--;
586 lo->sel--;
587 }
588 } else {
589 if (lo->sel > 0) {
590 lo->sel--;
591 lo->scroll--;
592 DrawNames(lo);
593 wrefresh(lo->win);
594 }
595 }
596 break;
597 case KEY_HOME:
598 case ctrl('a'):
599 lo->sel = 0;
600 lo->scroll = 0;
601 sel_y = lo->y + 2;
602 DrawNames(lo);
603 wrefresh(lo->win);
604 break;
605 case KEY_END:
606 case ctrl('e'):
607 if (lo->n < lo->h - 3) {
608 lo->sel = lo->n-1;
609 lo->scroll = 0;
610 sel_y = lo->y + 2 + lo->sel - lo->scroll;
611 } else {
612 /* more than one page of list */
613 lo->sel = lo->n-1;
614 lo->scroll = lo->n-1 - (lo->h-3);
615 sel_y = lo->y + 2 + lo->sel - lo->scroll;
616 DrawNames(lo);
617 wrefresh(lo->win);
618 }
619 break;
620 case KEY_NPAGE:
621 case ctrl('f'):
622 lo->sel += lo->h - 2;
623 if (lo->sel >= lo->n) lo->sel = lo->n - 1;
624 lo->scroll += lo->h - 2;
625 if (lo->scroll >= lo->n - 1) lo->scroll = lo->n - 1;
626 if (lo->scroll < 0) lo->scroll = 0;
627 sel_y = lo->y + 2 + lo->sel - lo->scroll;
628 DrawNames(lo);
629 wrefresh(lo->win);
630 break;
631 case KEY_PPAGE:
632 case ctrl('b'):
633 lo->sel -= lo->h - 2;
634 if (lo->sel < 0) lo->sel = 0;
635 lo->scroll -= lo->h - 2;
636 if (lo->scroll < 0) lo->scroll = 0;
637 sel_y = lo->y + 2 + lo->sel - lo->scroll;
638 DrawNames(lo);
639 wrefresh(lo->win);
640 break;
641 default:
642 quit = TRUE;
643 break;
644 }
645 /* Draw % indication */
646 sprintf(perc, "(%3d%%)", MIN(100, (int)
647 (100 * (lo->sel+lo->h - 2) / MAX(1, lo->n))));
648 wmove(lo->win, lo->y + lo->h, lo->x + lo->w - 8);
649 wattrset(lo->win, dialog_attr);
650 waddstr(lo->win, perc);
651
652 /* draw current item in inverse */
653 wmove(lo->win, sel_y, sel_x);
654 wattrset(lo->win, item_selected_attr);
655 if (strlen(lo->name[lo->sel]) > lo->w - 2) {
656 /* when printing in inverse video show the last characters in the */
657 /* name that will fit in the window */
658 strncpy(tmp,
659 lo->name[lo->sel] + strlen(lo->name[lo->sel]) - (lo->w - 2),
660 lo->w - 2);
661 tmp[lo->w - 2] = 0;
662 waddstr(lo->win, tmp);
663 } else {
664 waddstr(lo->win, lo->name[lo->sel]);
665 }
666 if (!quit) key = wgetch(lo->win);
667 }
668
669 if (key == ESC) {
670 return(SEL_ESC);
671 }
672 if (key == '\t') {
673 return(SEL_TAB);
674 }
675 if ((key == KEY_BTAB) || (key == ctrl('b'))) {
676 return(SEL_BACKTAB);
677 }
678 if ((key == '\n') || (key == '\r')) {
679 strcpy(lo->elt, lo->name[lo->sel]);
680 return(SEL_CR);
681 }
682 return(key);
683 } /* SelectListObj() */
684
685 void
DelListObj(ListObj * lo)686 DelListObj(ListObj *lo)
687 /*
688 * Desc: Free the space occupied by the listobject
689 */
690 {
691 free(lo->title);
692 if (lo->seld != NULL) free(lo->seld);
693 free(lo);
694
695 return;
696 } /* DelListObj() */
697
698 void
MarkCurrentListObj(ListObj * lo)699 MarkCurrentListObj(ListObj *lo)
700 /*
701 * Desc: mark the current item for the selection list
702 */
703 {
704 lo->seld[lo->sel] = !(lo->seld[lo->sel]);
705 DrawNames(lo);
706
707 return;
708 } /* MarkCurrentListObj() */
709
710 void
MarkAllListObj(ListObj * lo)711 MarkAllListObj(ListObj *lo)
712 /*
713 * Desc: mark all items
714 */
715 {
716 int i;
717
718 for (i=0; i<lo->n; i++) {
719 lo->seld[i] = TRUE;
720 }
721 DrawNames(lo);
722
723 return;
724 } /* MarkAllListObj() */
725
726 void
UnMarkAllListObj(ListObj * lo)727 UnMarkAllListObj(ListObj *lo)
728 /*
729 * Desc: unmark all items
730 */
731 {
732 int i;
733
734 for (i=0; i<lo->n; i++) {
735 lo->seld[i] = FALSE;
736 }
737 DrawNames(lo);
738
739 return;
740 } /* UnMarkAllListObj() */
741
742
743 /***********************************************************************
744 *
745 * ButtonObj routines
746 *
747 ***********************************************************************/
748
749
750 void
RefreshButtonObj(ButtonObj * bo)751 RefreshButtonObj(ButtonObj *bo)
752 /*
753 * Desc: redraw the button
754 */
755 {
756 draw_box(bo->win, bo->y, bo->x, 3, bo->w, dialog_attr, border_attr);
757 print_button(bo->win, bo->title, bo->y+1, bo->x+2, FALSE);
758
759 return;
760 } /* RefreshButtonObj() */
761
762 ButtonObj *
NewButtonObj(WINDOW * win,char * title,int * pushed,int y,int x)763 NewButtonObj(WINDOW *win, char *title, int *pushed, int y, int x)
764 /*
765 * Desc: Create a new button object
766 */
767 {
768 ButtonObj *bo;
769
770 bo = (ButtonObj *) malloc( sizeof(ButtonObj) );
771
772 bo->win = win;
773 bo->title = (char *) malloc( strlen(title) + 1);
774 strcpy(bo->title, title);
775 bo->x = x;
776 bo->y = y;
777 bo->w = strlen(title) + 6;
778 bo->h = 3;
779 bo->pushed = pushed;
780
781 RefreshButtonObj(bo);
782
783 return(bo);
784 } /* NewButtonObj() */
785
786 int
SelectButtonObj(ButtonObj * bo)787 SelectButtonObj(ButtonObj *bo)
788 /*
789 * Desc: Wait for buttonpresses or TAB's to move on, or ESC ESC
790 */
791 {
792 int key;
793
794 print_button(bo->win, bo->title, bo->y+1, bo->x+2, TRUE);
795 wmove(bo->win, bo->y+1, bo->x+(bo->w/2)-1);
796 key = wgetch(bo->win);
797 print_button(bo->win, bo->title, bo->y+1, bo->x+2, FALSE);
798 switch(key) {
799 case '\t':
800 return(SEL_TAB);
801 break;
802 case KEY_BTAB:
803 case ctrl('b'):
804 return(SEL_BACKTAB);
805 case '\n':
806 case '\r':
807 *(bo->pushed) = TRUE;
808 return(SEL_BUTTON);
809 break;
810 case ESC:
811 return(SEL_ESC);
812 break;
813 default:
814 return(key);
815 break;
816 }
817 } /* SelectButtonObj() */
818
819 void
DelButtonObj(ButtonObj * bo)820 DelButtonObj(ButtonObj *bo)
821 /*
822 * Desc: Free the space occupied by <bo>
823 */
824 {
825 free(bo->title);
826 free(bo);
827
828 return;
829 } /* DelButtonObj() */
830