3 * Author: Marc van Kempen
4 * Desc: Implementation of UI-objects:
5 * - String input fields
9 * Copyright (c) 1995, Marc van Kempen
11 * All rights reserved.
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
24 #include <sys/param.h>
27 #include "dialog.priv.h"
28 #include "ui_objects.h"
32 /***********************************************************************
36 ***********************************************************************/
39 AddObj(ComposeObj **Obj, int objtype, void *obj)
41 * Desc: Add the object <obj> to the list of objects <Obj>
45 /* Create the root object */
46 *Obj = (ComposeObj *) malloc( sizeof(ComposeObj) );
48 printf("AddObj: Error malloc'ing ComposeObj\n");
51 (*Obj)->objtype = objtype;
58 /* create the next object */
59 while (o->next) o = (ComposeObj *) o->next;
60 o->next = (struct ComposeObj *) malloc( sizeof(ComposeObj) );
62 printf("AddObj: Error malloc'ing o->next\n");
65 o->next->objtype = objtype;
75 FreeObj(ComposeObj *Obj)
77 * Desc: free the memory occupied by *Obj
94 ReadObj(ComposeObj *Obj)
96 * Desc: navigate through the different objects calling their
97 * respective navigation routines as necessary
102 ComposeObj *last; /* the last object in the list */
103 int ret; /* the return value from the selection routine */
105 /* find the last object in the list */
107 while (last->next) last = last->next;
111 while ((ret != SEL_BUTTON) && (ret != SEL_ESC)) {
114 ret = SelectStringObj((StringObj *) o->obj);
117 ret = SelectListObj((ListObj *) o->obj);
120 ret = SelectButtonObj((ButtonObj *) o->obj);
126 case SEL_TAB: /* move to the next object in the list */
127 if (o->next != NULL) {
128 o = o->next; /* next object */
130 o = Obj; /* beginning of the list */
135 case SEL_BACKTAB: /* move to the previous object in the list */
136 if (o->prev != NULL) {
137 o = o->prev; /* previous object */
139 o = last; /* end of the list */
143 case KEY_F(1): /* display help_file */
156 PollObj(ComposeObj **Obj)
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 */
162 /* find the last object in the list */
164 while (last->next) last = last->next;
166 /* find the first object in the list */
168 while (first->prev) first = first->prev;
171 switch((*Obj)->objtype) {
173 ret = SelectStringObj((StringObj *) (*Obj)->obj);
176 ret = SelectListObj((ListObj *) (*Obj)->obj);
179 ret = SelectButtonObj((ButtonObj *) (*Obj)->obj);
185 case SEL_TAB: /* move to the next object in the list */
186 if ((*Obj)->next != NULL) {
187 *Obj = (*Obj)->next; /* next object */
189 *Obj = first; /* beginning of the list */
194 case SEL_BACKTAB: /* move to the previous object in the list */
195 if ((*Obj)->prev != NULL) {
196 *Obj = (*Obj)->prev; /* previous object */
198 *Obj = last; /* end of the list */
209 DelObj(ComposeObj *Obj)
211 * Desc: Free all objects
217 while (Obj != NULL) {
218 switch(Obj->objtype) {
220 DelStringObj((StringObj *) Obj->obj);
223 DelListObj((ListObj *) Obj->obj);
226 DelButtonObj((ButtonObj *) Obj->obj);
235 /***********************************************************************
239 ***********************************************************************/
242 outstr(WINDOW *win, char *str, int attrs)
244 if (attrs & DITEM_NO_ECHO) {
258 RefreshStringObj(StringObj *so)
260 * Desc: redraw the object
265 wmove(so->win, so->y, so->x+1);
266 wattrset(so->win, dialog_attr);
267 waddstr(so->win, so->title);
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);
276 outstr(so->win, so->s, so->attr_mask);
280 } /* RefreshStringObj() */
283 NewStringObj(WINDOW *win, char *title, char *s, int y, int x, int w, int len)
285 * Desc: Initialize a new stringobj and return a pointer to it.
286 * Draw the object on the screen at the specified coordinates
291 /* Initialize a new object */
292 so = (StringObj *) malloc( sizeof(StringObj) );
294 printf("NewStringObj: Error malloc'ing StringObj\n");
297 so->title = (char *) malloc( strlen(title) + 1);
299 printf("NewStringObj: Error malloc'ing so->title\n");
302 strcpy(so->title, title);
310 so->attr_mask = DialogInputAttrs; /* Grossly use a global to avoid changing API */
312 /* Draw it on the screen */
313 RefreshStringObj(so);
316 } /* NewStringObj() */
319 SelectStringObj(StringObj *so)
321 * Desc: get input using the info in <so>
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) ) {
333 RefreshStringObj(so);
340 if ( (key == KEY_BTAB) || (key == KEY_F(2)) ) {
343 if ((key == '\n') || (key == '\r')) {
347 } /* SelectStringObj() */
351 DelStringObj(StringObj *so)
353 * Desc: Free the space occupied by <so>
362 /***********************************************************************
366 ***********************************************************************/
369 DrawNames(ListObj *lo)
371 * Desc: Just refresh the names, not the surrounding box and title
375 char tmp[MAXPATHLEN];
380 for (i=lo->scroll; i<lo->n && i<lo->scroll+h; i++) {
381 wmove(lo->win, y+i-lo->scroll, x);
383 wattrset(lo->win, A_BOLD);
385 wattrset(lo->win, item_attr);
387 if (strlen(lo->name[i]) > lo->w-2) {
388 strncpy(tmp, lo->name[i], lo->w-2);
390 waddstr(lo->win, tmp);
392 waddstr(lo->win, lo->name[i]);
393 for (j=strlen(lo->name[i]); j<lo->w-2; j++) waddstr(lo->win, " ");
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, " ");
407 RefreshListObj(ListObj *lo)
409 * Desc: redraw the list object
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);
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);
431 } /* RefreshListObj() */
434 NewListObj(WINDOW *win, char *title, char **list, char *listelt, int y, int x,
437 * Desc: create a listobj, draw it on the screen and return a pointer to it.
443 /* Initialize a new object */
444 lo = (ListObj *) malloc( sizeof(ListObj) );
446 fprintf(stderr, "NewListObj: Error malloc'ing ListObj\n");
449 lo->title = (char *) malloc( strlen(title) + 1);
451 fprintf(stderr, "NewListObj: Error malloc'ing lo->title\n");
454 strcpy(lo->title, title);
457 lo->seld = (int *) malloc( n * sizeof(int) );
459 fprintf(stderr, "NewListObj: Error malloc'ing lo->seld\n");
462 for (i=0; i<n; i++) {
478 /* Draw the object on the screen */
485 UpdateListObj(ListObj *lo, char **list, int n)
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")"
498 /* Rewrite the list in the object */
501 lo->seld = (int *) malloc( n * sizeof(int) );
503 fprintf(stderr, "UpdateListObj: Error malloc'ing lo->seld\n");
506 for (i=0; i<n; i++) {
516 /* Draw the object on the screen */
520 } /* UpdateListObj() */
523 SelectListObj(ListObj *lo)
525 * Desc: get a listname (or listnames), TAB to move on, or ESC ESC to exit
529 int key, sel_x, sel_y, quit;
530 char tmp[MAXPATHLEN];
534 sel_y = lo->y + 2 + lo->sel - lo->scroll;
536 if (lo->n == 0) return(SEL_TAB);
538 keypad(lo->win, TRUE);
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]);
545 key = wgetch(lo->win);
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);
554 wattrset(lo->win, item_attr);
556 if (strlen(lo->name[lo->sel]) > lo->w - 2) {
557 strncpy(tmp, lo->name[lo->sel], lo->w - 2);
559 waddstr(lo->win, tmp);
561 waddstr(lo->win, lo->name[lo->sel]);
567 if (sel_y < lo->y + lo->h-1) {
568 if (lo->sel < lo->n-1) {
573 if (lo->sel < lo->n-1) {
583 if (sel_y > lo->y+2) {
607 if (lo->n < lo->h - 3) {
610 sel_y = lo->y + 2 + lo->sel - lo->scroll;
612 /* more than one page of list */
614 lo->scroll = lo->n-1 - (lo->h-3);
615 sel_y = lo->y + 2 + lo->sel - lo->scroll;
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;
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;
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);
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 */
659 lo->name[lo->sel] + strlen(lo->name[lo->sel]) - (lo->w - 2),
662 waddstr(lo->win, tmp);
664 waddstr(lo->win, lo->name[lo->sel]);
666 if (!quit) key = wgetch(lo->win);
675 if ((key == KEY_BTAB) || (key == ctrl('b'))) {
678 if ((key == '\n') || (key == '\r')) {
679 strcpy(lo->elt, lo->name[lo->sel]);
683 } /* SelectListObj() */
686 DelListObj(ListObj *lo)
688 * Desc: Free the space occupied by the listobject
692 if (lo->seld != NULL) free(lo->seld);
699 MarkCurrentListObj(ListObj *lo)
701 * Desc: mark the current item for the selection list
704 lo->seld[lo->sel] = !(lo->seld[lo->sel]);
708 } /* MarkCurrentListObj() */
711 MarkAllListObj(ListObj *lo)
713 * Desc: mark all items
718 for (i=0; i<lo->n; i++) {
724 } /* MarkAllListObj() */
727 UnMarkAllListObj(ListObj *lo)
729 * Desc: unmark all items
734 for (i=0; i<lo->n; i++) {
740 } /* UnMarkAllListObj() */
743 /***********************************************************************
747 ***********************************************************************/
751 RefreshButtonObj(ButtonObj *bo)
753 * Desc: redraw the button
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);
760 } /* RefreshButtonObj() */
763 NewButtonObj(WINDOW *win, char *title, int *pushed, int y, int x)
765 * Desc: Create a new button object
770 bo = (ButtonObj *) malloc( sizeof(ButtonObj) );
773 bo->title = (char *) malloc( strlen(title) + 1);
774 strcpy(bo->title, title);
777 bo->w = strlen(title) + 6;
781 RefreshButtonObj(bo);
784 } /* NewButtonObj() */
787 SelectButtonObj(ButtonObj *bo)
789 * Desc: Wait for buttonpresses or TAB's to move on, or ESC ESC
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);
807 *(bo->pushed) = TRUE;
817 } /* SelectButtonObj() */
820 DelButtonObj(ButtonObj *bo)
822 * Desc: Free the space occupied by <bo>
829 } /* DelButtonObj() */