ui_objects.c revision 225736
18097Sjkh/*
28097Sjkh * Program:	objects.c
38097Sjkh * Author:	Marc van Kempen
48097Sjkh * Desc:	Implementation of UI-objects:
58097Sjkh *		- String input fields
68097Sjkh *		- List selection
727798Sjkh *		- Buttons
88097Sjkh *
98097Sjkh * Copyright (c) 1995, Marc van Kempen
108097Sjkh *
118097Sjkh * All rights reserved.
128097Sjkh *
138097Sjkh * This software may be used, modified, copied, distributed, and
148097Sjkh * sold, in both source and binary form provided that the above
158097Sjkh * copyright and these terms are retained, verbatim, as the first
168881Srgrimes * lines of this file.  Under no circumstances is the author
178881Srgrimes * responsible for the proper functioning of this software, nor does
188097Sjkh * the author assume any responsibility for damages incurred with
198097Sjkh * its use.
208097Sjkh *
218097Sjkh */
228097Sjkh
238097Sjkh#include <stdlib.h>
248097Sjkh#include <sys/param.h>
258097Sjkh#include <ncurses.h>
268097Sjkh#include <dialog.h>
278097Sjkh#include "dialog.priv.h"
288097Sjkh#include "ui_objects.h"
298097Sjkh
308097Sjkh#define ESC 27
318097Sjkh
328097Sjkh/***********************************************************************
338097Sjkh *
348097Sjkh * Obj routines
358097Sjkh *
368097Sjkh ***********************************************************************/
378097Sjkh
388097Sjkhvoid
398097SjkhAddObj(ComposeObj **Obj, int objtype, void *obj)
4021243Sjkh/*
4121243Sjkh * Desc: Add the object <obj> to the list of objects <Obj>
4225052Sjkh */
438097Sjkh{
448097Sjkh    if (*Obj == NULL) {
458097Sjkh	/* Create the root object */
468097Sjkh	*Obj = (ComposeObj *) malloc( sizeof(ComposeObj) );
478097Sjkh	if (!Obj) {
4821243Sjkh	    printf("AddObj: Error malloc'ing ComposeObj\n");
4921243Sjkh	    exit(-1);
5021243Sjkh	}
518281Sjkh	(*Obj)->objtype = objtype;
528405Sjkh	(*Obj)->obj = obj;
5312661Speter	(*Obj)->next = NULL;
548097Sjkh	(*Obj)->prev = NULL;
558208Sjkh    } else {
568208Sjkh	ComposeObj	*o = *Obj;
5719385Sjkh
5819385Sjkh	/* create the next object */
5921276Sjkh	while (o->next) o = (ComposeObj *) o->next;
6019385Sjkh	o->next = (struct ComposeObj *) malloc( sizeof(ComposeObj) );
6125052Sjkh	if (!o->next) {
6219385Sjkh	    printf("AddObj: Error malloc'ing o->next\n");
638208Sjkh	    exit(-1);
6412661Speter	}
6512661Speter	o->next->objtype = objtype;
668549Sjkh	o->next->obj = obj;
6717007Sjkh	o->next->next = NULL;
688208Sjkh	o->next->prev = o;
6921806Sjkh    }
7021806Sjkh
7121806Sjkh    return;
728705Sjkh} /* AddObj() */
738705Sjkh
748705Sjkhvoid
758705SjkhFreeObj(ComposeObj *Obj)
768705Sjkh/*
778705Sjkh * Desc: free the memory occupied by *Obj
788705Sjkh */
798705Sjkh{
8012661Speter    ComposeObj	*o = Obj;
818208Sjkh
8212661Speter    o = Obj;
8315788Sjkh    while (o) {
8415788Sjkh	o = Obj->next;
8515788Sjkh	free(Obj);
8615788Sjkh	Obj = o;
8715788Sjkh    }
8815788Sjkh
898549Sjkh    return;
9012661Speter} /* FreeObj() */
9112661Speter
9212661Speter
9312661Speterint
9412661SpeterReadObj(ComposeObj *Obj)
9512661Speter/*
9612661Speter * Desc: navigate through the different objects calling their
9712661Speter *	 respective navigation routines as necessary
9826456Sjkh * Pre:  Obj != NULL
9925473Spst */
10025473Spst{
10125473Spst    ComposeObj		*o;
10225473Spst    ComposeObj		*last;	 /* the last object in the list */
10325473Spst    int			ret;	 /* the return value from the selection routine */
10425473Spst
10525473Spst    /* find the last object in the list */
10612661Speter    last = Obj;
10714763Sjkh    while (last->next) last = last->next;
10812661Speter
10916410Sjkh    ret = 0;
11012661Speter    o = Obj;
11112661Speter    while ((ret != SEL_BUTTON) && (ret != SEL_ESC)) {
11216462Sjkh	switch(o->objtype) {
11312661Speter	case STRINGOBJ:
11412661Speter	    ret = SelectStringObj((StringObj *) o->obj);
11516410Sjkh	    break;
11621897Sjkh	case LISTOBJ:
11712661Speter	    ret = SelectListObj((ListObj *) o->obj);
11812661Speter	    break;
11912661Speter	case BUTTONOBJ:
12012661Speter	    ret = SelectButtonObj((ButtonObj *) o->obj);
12112661Speter	    break;
12224038Sjkh	}
12317034Sjkh	switch(ret) {
12412661Speter	case KEY_DOWN:
12512661Speter	case SEL_CR:
12612661Speter	case SEL_TAB:	/* move to the next object in the list */
12712661Speter	    if (o->next != NULL) {
12821855Sjkh		o = o->next;	/* next object */
12912661Speter	    } else {
13012661Speter		o = Obj;	/* beginning of the list */
13126514Sjkh	    }
13212661Speter	    break;
13316410Sjkh
13412661Speter	case KEY_UP:
13526010Sjkh	case SEL_BACKTAB: /* move to the previous object in the list */
13612661Speter	    if (o->prev != NULL) {
13726795Sjkh		o = o->prev;	/* previous object */
13826717Sjkh	    } else {
13926456Sjkh		o = last;	/* end of the list */
14016828Sjkh	    }
14126456Sjkh	    break;
14216366Sjkh
14321897Sjkh	case KEY_F(1): /* display help_file */
14416366Sjkh	case '?':
14512661Speter	    display_helpfile();
14612661Speter	    break;
14712661Speter	}
14819385Sjkh    }
14925476Sjkh
15019385Sjkh    return(ret);
15116366Sjkh
15212661Speter} /* ReadObj() */
15312661Speter
15412661Speter
15512661Speterint
15612661SpeterPollObj(ComposeObj **Obj)
15712661Speter{
15821978Sjkh    ComposeObj		*last;	 /* the last object in the list */
1599202Srgrimes    ComposeObj		*first;  /* the first object in the list */
16012661Speter    int			ret;	 /* the return value from the selection routine */
1619202Srgrimes
16212661Speter    /* find the last object in the list */
16312661Speter    last = *Obj;
1648549Sjkh    while (last->next) last = last->next;
16516208Sjkh
16616294Sjkh    /* find the first object in the list */
16716366Sjkh    first = *Obj;
16816208Sjkh    while (first->prev) first = first->prev;
16920247Sjkh
17020569Sjkh    ret = 0;
17116366Sjkh    switch((*Obj)->objtype) {
1728208Sjkh    case STRINGOBJ:
1738097Sjkh	ret = SelectStringObj((StringObj *) (*Obj)->obj);
1748549Sjkh	break;
1758549Sjkh    case LISTOBJ:
1768097Sjkh	ret = SelectListObj((ListObj *) (*Obj)->obj);
17715242Sjkh	break;
17815242Sjkh    case BUTTONOBJ:
17915242Sjkh	ret = SelectButtonObj((ButtonObj *) (*Obj)->obj);
18015242Sjkh	break;
18115242Sjkh    }
1828097Sjkh    switch(ret) {
1838097Sjkh    case KEY_DOWN:
18415242Sjkh    case SEL_CR:
1858174Sjkh    case SEL_TAB:		     /* move to the next object in the list */
1868174Sjkh	if ((*Obj)->next != NULL) {
1878174Sjkh	    *Obj = (*Obj)->next;     /* next object */
1888174Sjkh	} else {
18915091Sjkh	    *Obj = first;	     /* beginning of the list */
1908097Sjkh	}
1918097Sjkh	break;
19225251Sjkh
1938097Sjkh    case KEY_UP:
1948097Sjkh    case SEL_BACKTAB: 		     /* move to the previous object in the list */
19520331Sjkh	if ((*Obj)->prev != NULL) {
19620331Sjkh	    *Obj = (*Obj)->prev;     /* previous object */
1978097Sjkh	} else {
1988097Sjkh	    *Obj = last;	     /* end of the list */
19922099Sjkh	}
20022099Sjkh	break;
20122099Sjkh    }
20222099Sjkh
20321243Sjkh    return(ret);
20421243Sjkh
20521243Sjkh} /* PollObj() */
20621243Sjkh
20721243Sjkh
20821243Sjkhvoid
20921243SjkhDelObj(ComposeObj *Obj)
21021243Sjkh/*
21121243Sjkh * Desc: Free all objects
21221243Sjkh */
21321243Sjkh{
21421243Sjkh    ComposeObj	*o;
21521243Sjkh
21612661Speter    o = Obj;
2178792Sjkh    while (Obj != NULL) {
21812661Speter	switch(Obj->objtype) {
21912661Speter	case STRINGOBJ:
2208792Sjkh	    DelStringObj((StringObj *) Obj->obj);
2218792Sjkh	    break;
22220355Sjkh	case LISTOBJ:
22320355Sjkh	    DelListObj((ListObj *) Obj->obj);
2248792Sjkh	    break;
2258792Sjkh	case BUTTONOBJ:
2268208Sjkh	    DelButtonObj((ButtonObj *) Obj->obj);
2278363Sjkh	    break;
2288208Sjkh	}
2298208Sjkh	Obj = Obj->next;
2308756Sjkh    }
2318208Sjkh
2328208Sjkh    FreeObj(o);
2338208Sjkh} /* DelObj() */
2348642Sjkh
2358837Sjkh/***********************************************************************
2368837Sjkh *
2378363Sjkh * StringObj routines
2388208Sjkh *
2398097Sjkh ***********************************************************************/
24017189Sjkh
24117189Sjkhstatic void
24217189Sjkhoutstr(WINDOW *win, char *str, int attrs)
24317189Sjkh{
24417189Sjkh    if (attrs & DITEM_NO_ECHO) {
2458208Sjkh	char *cpy;
2468208Sjkh	int n = strlen(str);
2478208Sjkh
2488556Sjkh	cpy = alloca(n + 1);
2498636Sjkh	memset(cpy, '*', n);
2508208Sjkh	cpy[n] = '\0';
2518549Sjkh	waddstr(win, cpy);
2529202Srgrimes    }
25320315Sjkh    else
2549202Srgrimes	waddstr(win, str);
2558556Sjkh}
2569202Srgrimes
2578208Sjkhvoid
2588208SjkhRefreshStringObj(StringObj *so)
2598307Sjkh/*
2608307Sjkh * Desc: redraw the object
2618307Sjkh */
2628307Sjkh{
2638307Sjkh    char tmp[512];
2648549Sjkh
2658549Sjkh    wmove(so->win, so->y, so->x+1);
2668307Sjkh    wattrset(so->win, dialog_attr);
2678208Sjkh    waddstr(so->win, so->title);
2688336Sjkh
2698336Sjkh    draw_box(so->win, so->y+1, so->x, 3, so->w, dialog_attr, border_attr);
2708336Sjkh    wattrset(so->win, item_attr);
2718307Sjkh    wmove(so->win, so->y+2, so->x+1);
2728307Sjkh    if (strlen(so->s) > so->w-2) {
2738307Sjkh	strncpy(tmp, (char *) so->s + strlen(so->s) - so->w + 2, so->w - 1);
2748336Sjkh	outstr(so->win, tmp, so->attr_mask);
2758307Sjkh    } else {
2768307Sjkh	outstr(so->win, so->s, so->attr_mask);
27712661Speter    }
27812661Speter
27912661Speter    return;
28012661Speter} /* RefreshStringObj() */
28112661Speter
28212661SpeterStringObj *
28312661SpeterNewStringObj(WINDOW *win, char *title, char *s, int y, int x, int w, int len)
28412661Speter/*
28512661Speter * Desc: Initialize a new stringobj and return a pointer to it.
28612661Speter *	 Draw the object on the screen at the specified coordinates
28712661Speter */
28812661Speter{
28912661Speter    StringObj	*so;
29012661Speter
29112661Speter    /* Initialize a new object */
29212661Speter    so = (StringObj *) malloc( sizeof(StringObj) );
29312661Speter    if (!so) {
29412661Speter	printf("NewStringObj: Error malloc'ing StringObj\n");
29512661Speter	exit(-1);
29612661Speter    }
29712661Speter    so->title = (char *) malloc( strlen(title) + 1);
29812661Speter    if (!so->title) {
29912661Speter	printf("NewStringObj: Error malloc'ing so->title\n");
30012661Speter	exit(-1);
30112661Speter    }
30212661Speter    strcpy(so->title, title);
30312661Speter    so->s = s;
30412661Speter    strcpy(so->s, s);
30512661Speter    so->x = x;
30612661Speter    so->y = y;
30714670Sjkh    so->w = w;
30812661Speter    so->len = len;
30912661Speter    so->win = win;
31012661Speter    so->attr_mask = DialogInputAttrs;	/* Grossly use a global to avoid changing API */
31112661Speter
3128549Sjkh    /* Draw it on the screen */
3138307Sjkh    RefreshStringObj(so);
31412661Speter
3158810Sjkh    return(so);
31612661Speter} /* NewStringObj() */
3178549Sjkh
3188810Sjkhint
3198810SjkhSelectStringObj(StringObj *so)
3208810Sjkh/*
3218810Sjkh * Desc: get input using the info in <so>
3228810Sjkh */
3238810Sjkh{
3248810Sjkh    int     	key;
3258810Sjkh    char	tmp[so->len+1];
3268208Sjkh
32725052Sjkh    strcpy(tmp, so->s);
3288576Sjkh    key = line_edit(so->win, so->y+2, so->x+1,
32915439Sjkh		    so->len, so->w-2, inputbox_attr, TRUE, tmp, so->attr_mask);
3308881Srgrimes    if ((key == '\n') || (key == '\r') || (key == '\t') || key == (KEY_BTAB) ) {
3318735Sjkh	strcpy(so->s, tmp);
3328576Sjkh    }
3338576Sjkh    RefreshStringObj(so);
3348576Sjkh    if (key == ESC) {
3358576Sjkh	return(SEL_ESC);
3368636Sjkh    }
3378576Sjkh    if (key == '\t') {
3389202Srgrimes	return(SEL_TAB);
3398576Sjkh    }
3408576Sjkh    if ( (key == KEY_BTAB) || (key == KEY_F(2)) ) {
3418576Sjkh	return(SEL_BACKTAB);
3428576Sjkh    }
3439202Srgrimes    if ((key == '\n') || (key == '\r')) {
34417375Sjkh	return(SEL_CR);
3458576Sjkh    }
34615242Sjkh    return(key);
3478660Sjkh} /* SelectStringObj() */
3488715Sjkh
3498576Sjkh
35010882Spetervoid
35116412SjkhDelStringObj(StringObj *so)
3528576Sjkh/*
3538576Sjkh * Desc: Free the space occupied by <so>
3548576Sjkh */
35512661Speter{
3568576Sjkh   free(so->title);
3578677Sjkh   free(so);
3588576Sjkh
3598576Sjkh   return;
3608677Sjkh}
3618677Sjkh
3628810Sjkh/***********************************************************************
3638722Sjkh *
36419488Sjkh * ListObj routines
3658810Sjkh *
3668810Sjkh ***********************************************************************/
3678810Sjkh
36819488Sjkhvoid
3698810SjkhDrawNames(ListObj *lo)
37010882Speter/*
3718576Sjkh * Desc: Just refresh the names, not the surrounding box and title
37212661Speter */
3739202Srgrimes{
3748576Sjkh    int 	i, j, h, x, y;
3758576Sjkh    char	tmp[MAXPATHLEN];
3768576Sjkh
3778576Sjkh    x = lo->x + 1;
3788576Sjkh    y = lo->y + 2;
37919577Sjkh    h = lo->h - 2;
3808576Sjkh    for (i=lo->scroll; i<lo->n && i<lo->scroll+h; i++) {
3818576Sjkh	wmove(lo->win, y+i-lo->scroll, x);
38212661Speter	if (lo->seld[i]) {
38320231Sjkh	    wattrset(lo->win, A_BOLD);
38421010Sjkh	} else {
38521978Sjkh	    wattrset(lo->win, item_attr);
3868576Sjkh	}
38721243Sjkh	if (strlen(lo->name[i]) > lo->w-2) {
38821243Sjkh	    strncpy(tmp, lo->name[i], lo->w-2);
38921243Sjkh	    tmp[lo->w - 2] = 0;
3908576Sjkh	    waddstr(lo->win, tmp);
3918208Sjkh	} else {
3928107Sjkh	    waddstr(lo->win, lo->name[i]);
39312661Speter	    for (j=strlen(lo->name[i]); j<lo->w-2; j++) waddstr(lo->win, " ");
39415091Sjkh	}
39512661Speter    }
3968792Sjkh    wattrset(lo->win, item_attr);
39712661Speter    while (i<lo->scroll+h) {
39812661Speter	wmove(lo->win, y+i-lo->scroll, x);
39920315Sjkh	for (j=0; j<lo->w-2; j++) waddstr(lo->win, " ");
4008792Sjkh	i++;
4018792Sjkh    }
4028792Sjkh
40320315Sjkh    return;
4048792Sjkh} /* DrawNames() */
4058792Sjkh
4068347Sjkhvoid
4078347SjkhRefreshListObj(ListObj *lo)
4088347Sjkh/*
4098347Sjkh * Desc: redraw the list object
4108549Sjkh */
4118549Sjkh{
4128347Sjkh    char 	perc[7];
4138705Sjkh
41412661Speter    /* setup the box */
41525251Sjkh    wmove(lo->win, lo->y, lo->x+1);
41622756Sjkh    wattrset(lo->win, dialog_attr);
41725251Sjkh    waddstr(lo->win, lo->title);
41826456Sjkh    draw_box(lo->win, lo->y+1, lo->x, lo->h, lo->w, dialog_attr, border_attr);
41923588Sjkh
4208722Sjkh    /* draw the names */
42115091Sjkh    DrawNames(lo);
42219397Sjkh
42315091Sjkh    /* Draw % indication */
42415091Sjkh    sprintf(perc, "(%3d%%)", MIN(100, (int) (100 * (lo->sel+lo->h-2) / MAX(1, lo->n))));
42521701Sjkh    wmove(lo->win, lo->y + lo->h, lo->x + lo->w - 8);
42626764Sjkh    wattrset(lo->win, dialog_attr);
42719385Sjkh    waddstr(lo->win, perc);
42816828Sjkh
42916828Sjkh
43025251Sjkh    return;
43119577Sjkh} /* RefreshListObj() */
43216828Sjkh
43319577SjkhListObj *
4348705SjkhNewListObj(WINDOW *win, char *title, char **list, char *listelt, int y, int x,
4359202Srgrimes	   int h, int w, int n)
4369202Srgrimes/*
4379202Srgrimes * Desc: create a listobj, draw it on the screen and return a pointer to it.
4388351Sjkh */
43915242Sjkh{
44015242Sjkh    ListObj	*lo;
4418556Sjkh    int		i;
4428556Sjkh
44321730Sjkh    /* Initialize a new object */
4448636Sjkh    lo = (ListObj *) malloc( sizeof(ListObj) );
4458641Sjkh    if (!lo) {
4468641Sjkh	fprintf(stderr, "NewListObj: Error malloc'ing ListObj\n");
44720315Sjkh	exit(-1);
44820315Sjkh    }
44920315Sjkh    lo->title = (char *) malloc( strlen(title) + 1);
4508722Sjkh    if (!lo->title) {
4519202Srgrimes	fprintf(stderr, "NewListObj: Error malloc'ing lo->title\n");
45220315Sjkh	exit(-1);
4539202Srgrimes    }
4548097Sjkh    strcpy(lo->title, title);
4558351Sjkh    lo->name = list;
45615091Sjkh    if (n>0) {
45715091Sjkh        lo->seld = (int *) malloc( n * sizeof(int) );
45815242Sjkh        if (!lo->seld) {
4598097Sjkh            fprintf(stderr, "NewListObj: Error malloc'ing lo->seld\n");
46015788Sjkh            exit(-1);
46115788Sjkh        }
46215788Sjkh        for (i=0; i<n; i++) {
4638278Sjkh            lo->seld[i] = FALSE;
46415383Sjkh        }
46525473Spst    } else {
46626456Sjkh        lo->seld = NULL;
46715091Sjkh    }
46815091Sjkh    lo->y = y;
46915091Sjkh    lo->x = x;
47015091Sjkh    lo->w = w;
47115091Sjkh    lo->h = h;
47215091Sjkh    lo->n = n;
47315091Sjkh    lo->scroll = 0;
47415091Sjkh    lo->sel = 0;
47515091Sjkh    lo->elt = listelt;
47615091Sjkh    lo->win = win;
47715091Sjkh
4788278Sjkh    /* Draw the object on the screen */
4798107Sjkh    RefreshListObj(lo);
48015091Sjkh
48115091Sjkh    return(lo);
48215091Sjkh} /* NewListObj() */
48315091Sjkh
48415416Sjkhvoid
48515091SjkhUpdateListObj(ListObj *lo, char **list, int n)
48619573Sjoerg/*
48719488Sjkh * Desc: Update the list in the listobject with the provided list
48816327Sjkh * Pre:  lo->name "has been freed"
48915091Sjkh *	 "(A i: 0<=i<lo->n: "lo->name[i] has been freed")"
49015091Sjkh */
49116887Sjkh{
49216887Sjkh    int i;
49315091Sjkh
49426610Sjkh    if (lo->seld) {
49515091Sjkh	free(lo->seld);
49615091Sjkh    }
4978097Sjkh
49812661Speter    /* Rewrite the list in the object */
49915091Sjkh    lo->name = list;
50015091Sjkh    if (n>0) {
50112661Speter	lo->seld = (int *) malloc( n * sizeof(int) );
5028792Sjkh	if (!lo->seld) {
50320315Sjkh	    fprintf(stderr, "UpdateListObj: Error malloc'ing lo->seld\n");
5048792Sjkh	    exit(-1);
50520315Sjkh	}
5068792Sjkh	for (i=0; i<n; i++) {
5078792Sjkh	    lo->seld[i] = FALSE;
5088792Sjkh	}
5098792Sjkh    } else {
5108792Sjkh        lo->seld = NULL;
51120315Sjkh    }
5128792Sjkh    lo->n = n;
5138792Sjkh    lo->scroll = 0;
5148792Sjkh    lo->sel = 0;
51520315Sjkh
5168792Sjkh    /* Draw the object on the screen */
51720315Sjkh    RefreshListObj(lo);
5188792Sjkh
5198792Sjkh    return;
5208351Sjkh} /* UpdateListObj() */
5218351Sjkh
5228351Sjkhint
52312661SpeterSelectListObj(ListObj *lo)
52420315Sjkh/*
52512661Speter * Desc: get a listname (or listnames), TAB to move on, or ESC ESC to exit
52612661Speter * Pre:	 lo->n >= 1
52712661Speter */
52812661Speter{
52912661Speter    int 	key, sel_x, sel_y, quit;
53014670Sjkh    char	tmp[MAXPATHLEN];
53112661Speter    char	perc[4];
5328351Sjkh
53317368Sjkh    sel_x = lo->x+1;
53415091Sjkh    sel_y = lo->y + 2 + lo->sel - lo->scroll;
53515788Sjkh
53615091Sjkh    if (lo->n == 0) return(SEL_TAB);
53715091Sjkh
53821010Sjkh    keypad(lo->win, TRUE);
53915242Sjkh
54015242Sjkh    /* Draw current selection in inverse video */
54115091Sjkh    wmove(lo->win, sel_y, sel_x);
54215091Sjkh    wattrset(lo->win, item_selected_attr);
54315091Sjkh    waddstr(lo->win, lo->name[lo->sel]);
54415091Sjkh
54522756Sjkh    key = wgetch(lo->win);
54612661Speter    quit = FALSE;
5478351Sjkh    while ((key != '\t') && (key != '\n') && (key != '\r')
54819573Sjoerg	   && (key != ESC) && (key != KEY_F(1)) && (key != '?') && !quit) {
54919573Sjoerg	/* first draw current item in normal video */
5508351Sjkh	wmove(lo->win, sel_y, sel_x);
5518549Sjkh	if (lo->seld[lo->sel]) {
55215091Sjkh	    wattrset(lo->win, A_BOLD);
55315091Sjkh	} else {
5548549Sjkh	    wattrset(lo->win, item_attr);
55512661Speter	}
55612661Speter	if (strlen(lo->name[lo->sel]) > lo->w - 2) {
55712661Speter	    strncpy(tmp, lo->name[lo->sel], lo->w - 2);
5588351Sjkh	    tmp[lo->w - 2] = 0;
55927798Sjkh	    waddstr(lo->win, tmp);
5608405Sjkh	} else {
5618405Sjkh	    waddstr(lo->win, lo->name[lo->sel]);
5628405Sjkh	}
5638405Sjkh
5648405Sjkh	switch (key) {
5658405Sjkh	case KEY_DOWN:
5668405Sjkh	case ctrl('n'):
5678601Sjkh	    if (sel_y < lo->y + lo->h-1) {
5688601Sjkh		if (lo->sel < lo->n-1) {
5698629Sjkh		    sel_y++;
5708629Sjkh		    lo->sel++;
5718629Sjkh		}
5728351Sjkh	    } else {
5738351Sjkh		if (lo->sel < lo->n-1) {
57412661Speter		    lo->sel++;
57524038Sjkh		    lo->scroll++;
57621855Sjkh		    DrawNames(lo);
57715091Sjkh		    wrefresh(lo->win);
57815091Sjkh		}
57915091Sjkh	    }
58015091Sjkh	    break;
58115091Sjkh	case KEY_UP:
58215091Sjkh	case ctrl('p'):
58315091Sjkh	    if (sel_y > lo->y+2) {
58415091Sjkh		if (lo->sel > 0) {
58515091Sjkh		    sel_y--;
58618619Sjkh		    lo->sel--;
58715091Sjkh		}
58815091Sjkh	    } else {
58920484Sjkh		if (lo->sel > 0) {
5908837Sjkh		    lo->sel--;
5918799Sphk		    lo->scroll--;
5928556Sjkh		    DrawNames(lo);
5938576Sjkh		    wrefresh(lo->win);
5948107Sjkh		}
5958097Sjkh	    }
5968097Sjkh	    break;
59714670Sjkh	case KEY_HOME:
59817034Sjkh	case ctrl('a'):
59916462Sjkh	    lo->sel = 0;
6008097Sjkh	    lo->scroll = 0;
60112661Speter	    sel_y = lo->y + 2;
6028097Sjkh	    DrawNames(lo);
6038097Sjkh	    wrefresh(lo->win);
60412661Speter	    break;
60512661Speter	case KEY_END:
6068097Sjkh	case ctrl('e'):
6078208Sjkh	    if (lo->n < lo->h - 3) {
6088363Sjkh		lo->sel = lo->n-1;
60915242Sjkh		lo->scroll = 0;
61015242Sjkh		sel_y = lo->y + 2 + lo->sel - lo->scroll;
61115242Sjkh	    } else {
61215242Sjkh		/* more than one page of list */
61315242Sjkh		lo->sel = lo->n-1;
61415242Sjkh		lo->scroll = lo->n-1 - (lo->h-3);
61517005Sjkh		sel_y = lo->y + 2 + lo->sel - lo->scroll;
6168556Sjkh		DrawNames(lo);
61721243Sjkh		wrefresh(lo->win);
61821243Sjkh	    }
61921243Sjkh	    break;
62021243Sjkh	case KEY_NPAGE:
62121243Sjkh	case ctrl('f'):
62215242Sjkh	    lo->sel += lo->h - 2;
62315242Sjkh	    if (lo->sel >= lo->n) lo->sel = lo->n - 1;
62420247Sjkh	    lo->scroll += lo->h - 2;
6258097Sjkh	    if (lo->scroll >= lo->n - 1) lo->scroll = lo->n - 1;
6268107Sjkh	    if (lo->scroll < 0) lo->scroll = 0;
6278837Sjkh	    sel_y = lo->y + 2 + lo->sel - lo->scroll;
6288097Sjkh	    DrawNames(lo);
6298262Sjkh	    wrefresh(lo->win);
6308097Sjkh	    break;
6318347Sjkh	case KEY_PPAGE:
6328097Sjkh	case ctrl('b'):
6338097Sjkh	    lo->sel -= lo->h - 2;
6348208Sjkh	    if (lo->sel < 0) lo->sel = 0;
6358313Sjkh	    lo->scroll -= lo->h - 2;
6368705Sjkh	    if (lo->scroll < 0) lo->scroll = 0;
6378208Sjkh	    sel_y = lo->y + 2 + lo->sel - lo->scroll;
6388262Sjkh	    DrawNames(lo);
63912661Speter	    wrefresh(lo->win);
64012661Speter	    break;
6418097Sjkh	default:
6428792Sjkh	    quit = TRUE;
6438792Sjkh	    break;
6448792Sjkh	}
6458792Sjkh	/* Draw % indication */
6468837Sjkh	sprintf(perc, "(%3d%%)", MIN(100, (int)
6478837Sjkh				     (100 * (lo->sel+lo->h - 2) / MAX(1, lo->n))));
64820315Sjkh	wmove(lo->win, lo->y + lo->h, lo->x + lo->w - 8);
6498837Sjkh	wattrset(lo->win, dialog_attr);
6508837Sjkh	waddstr(lo->win, perc);
65112661Speter
65215091Sjkh	/* draw current item in inverse */
65312661Speter	wmove(lo->win, sel_y, sel_x);
65412661Speter	wattrset(lo->win, item_selected_attr);
65526613Sjkh	if (strlen(lo->name[lo->sel]) > lo->w - 2) {
65612661Speter	    /* when printing in inverse video show the last characters in the */
65714738Sjkh	    /* name that will fit in the window */
65815788Sjkh	    strncpy(tmp,
65912661Speter		    lo->name[lo->sel] + strlen(lo->name[lo->sel]) - (lo->w - 2),
66023904Sjkh		    lo->w - 2);
66123904Sjkh	    tmp[lo->w - 2] = 0;
66223904Sjkh	    waddstr(lo->win, tmp);
6638351Sjkh	} else {
6648351Sjkh	    waddstr(lo->win, lo->name[lo->sel]);
66515788Sjkh	}
66612661Speter	if (!quit) key = wgetch(lo->win);
6678351Sjkh    }
66812661Speter
6698351Sjkh    if (key == ESC) {
6708351Sjkh	return(SEL_ESC);
6718351Sjkh    }
67212661Speter    if (key == '\t') {
6738351Sjkh	return(SEL_TAB);
67412661Speter    }
6758351Sjkh    if ((key == KEY_BTAB) || (key == ctrl('b'))) {
6768107Sjkh	return(SEL_BACKTAB);
6778792Sjkh    }
67812661Speter    if ((key == '\n') || (key == '\r')) {
6798792Sjkh	strcpy(lo->elt, lo->name[lo->sel]);
68020315Sjkh	return(SEL_CR);
6818792Sjkh    }
6828792Sjkh    return(key);
6838556Sjkh} /* SelectListObj() */
6848768Sjkh
68515091Sjkhvoid
68622842SjkhDelListObj(ListObj *lo)
6878556Sjkh/*
6888351Sjkh * Desc: Free the space occupied by the listobject
6898351Sjkh */
6908208Sjkh{
6918792Sjkh    free(lo->title);
6928837Sjkh    if (lo->seld != NULL) free(lo->seld);
6938792Sjkh    free(lo);
69420315Sjkh
6958792Sjkh    return;
69620231Sjkh} /* DelListObj() */
69720231Sjkh
69820231Sjkhvoid
69920231SjkhMarkCurrentListObj(ListObj *lo)
70012661Speter/*
7018208Sjkh * Desc: mark the current item for the selection list
7028208Sjkh */
70312661Speter{
70412661Speter    lo->seld[lo->sel] = !(lo->seld[lo->sel]);
70512661Speter    DrawNames(lo);
70626610Sjkh
7078208Sjkh    return;
70824038Sjkh} /* MarkCurrentListObj() */
70924038Sjkh
71024038Sjkhvoid
7118281SjkhMarkAllListObj(ListObj *lo)
7128549Sjkh/*
7138281Sjkh * Desc: mark all items
7148097Sjkh */
7158097Sjkh{
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
726void
727UnMarkAllListObj(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
750void
751RefreshButtonObj(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
762ButtonObj *
763NewButtonObj(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
786int
787SelectButtonObj(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
819void
820DelButtonObj(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