16458Sache/*
26458Sache * Program:	objects.c
36458Sache * Author:	Marc van Kempen
46458Sache * Desc:	Implementation of UI-objects:
56458Sache *		- String input fields
68858Srgrimes *		- List selection
76458Sache *		- Buttons
86458Sache *
96458Sache * Copyright (c) 1995, Marc van Kempen
106458Sache *
116458Sache * All rights reserved.
126458Sache *
136458Sache * This software may be used, modified, copied, distributed, and
146458Sache * sold, in both source and binary form provided that the above
156458Sache * copyright and these terms are retained, verbatim, as the first
166458Sache * lines of this file.  Under no circumstances is the author
176458Sache * responsible for the proper functioning of this software, nor does
186458Sache * the author assume any responsibility for damages incurred with
196458Sache * its use.
208858Srgrimes *
216458Sache */
226458Sache
236458Sache#include <stdlib.h>
246458Sache#include <sys/param.h>
256458Sache#include <ncurses.h>
266458Sache#include <dialog.h>
276458Sache#include "dialog.priv.h"
286458Sache#include "ui_objects.h"
296458Sache
306458Sache#define ESC 27
316458Sache
326458Sache/***********************************************************************
336458Sache *
346458Sache * Obj routines
356458Sache *
366458Sache ***********************************************************************/
376458Sache
386458Sachevoid
396458SacheAddObj(ComposeObj **Obj, int objtype, void *obj)
406458Sache/*
416458Sache * Desc: Add the object <obj> to the list of objects <Obj>
426458Sache */
436458Sache{
446458Sache    if (*Obj == NULL) {
456458Sache	/* Create the root object */
466458Sache	*Obj = (ComposeObj *) malloc( sizeof(ComposeObj) );
476458Sache	if (!Obj) {
486458Sache	    printf("AddObj: Error malloc'ing ComposeObj\n");
496458Sache	    exit(-1);
506458Sache	}
516458Sache	(*Obj)->objtype = objtype;
526458Sache	(*Obj)->obj = obj;
536458Sache	(*Obj)->next = NULL;
546458Sache	(*Obj)->prev = NULL;
556458Sache    } else {
566458Sache	ComposeObj	*o = *Obj;
576458Sache
586458Sache	/* create the next object */
596458Sache	while (o->next) o = (ComposeObj *) o->next;
606458Sache	o->next = (struct ComposeObj *) malloc( sizeof(ComposeObj) );
616458Sache	if (!o->next) {
626458Sache	    printf("AddObj: Error malloc'ing o->next\n");
636458Sache	    exit(-1);
646458Sache	}
656458Sache	o->next->objtype = objtype;
666458Sache	o->next->obj = obj;
676458Sache	o->next->next = NULL;
686458Sache	o->next->prev = o;
696458Sache    }
706458Sache
716458Sache    return;
726458Sache} /* AddObj() */
736458Sache
746458Sachevoid
756458SacheFreeObj(ComposeObj *Obj)
766458Sache/*
776458Sache * Desc: free the memory occupied by *Obj
786458Sache */
796458Sache{
806458Sache    ComposeObj	*o = Obj;
818858Srgrimes
826458Sache    o = Obj;
836458Sache    while (o) {
846458Sache	o = Obj->next;
856458Sache	free(Obj);
866458Sache	Obj = o;
876458Sache    }
888858Srgrimes
896458Sache    return;
906458Sache} /* FreeObj() */
916458Sache
926458Sache
936458Sacheint
946458SacheReadObj(ComposeObj *Obj)
956458Sache/*
968858Srgrimes * Desc: navigate through the different objects calling their
976458Sache *	 respective navigation routines as necessary
986458Sache * Pre:  Obj != NULL
996458Sache */
1006458Sache{
1016458Sache    ComposeObj		*o;
1026458Sache    ComposeObj		*last;	 /* the last object in the list */
1036458Sache    int			ret;	 /* the return value from the selection routine */
1046458Sache
1056458Sache    /* find the last object in the list */
1066458Sache    last = Obj;
1076458Sache    while (last->next) last = last->next;
1086458Sache
1096458Sache    ret = 0;
1106458Sache    o = Obj;
1116458Sache    while ((ret != SEL_BUTTON) && (ret != SEL_ESC)) {
1126458Sache	switch(o->objtype) {
1136458Sache	case STRINGOBJ:
1146458Sache	    ret = SelectStringObj((StringObj *) o->obj);
1156458Sache	    break;
1166458Sache	case LISTOBJ:
1176458Sache	    ret = SelectListObj((ListObj *) o->obj);
1186458Sache	    break;
1196458Sache	case BUTTONOBJ:
1206458Sache	    ret = SelectButtonObj((ButtonObj *) o->obj);
1216458Sache	    break;
1226458Sache	}
1236458Sache	switch(ret) {
12417984Sjkh	case KEY_DOWN:
1256458Sache	case SEL_CR:
1266458Sache	case SEL_TAB:	/* move to the next object in the list */
1276458Sache	    if (o->next != NULL) {
1286458Sache		o = o->next;	/* next object */
1296458Sache	    } else {
1306458Sache		o = Obj;	/* beginning of the list */
1316458Sache	    }
1326458Sache	    break;
13317984Sjkh
13417984Sjkh	case KEY_UP:
1356458Sache	case SEL_BACKTAB: /* move to the previous object in the list */
1366458Sache	    if (o->prev != NULL) {
1376458Sache		o = o->prev;	/* previous object */
1386458Sache	    } else {
1396458Sache		o = last;	/* end of the list */
1406458Sache	    }
1416458Sache	    break;
14217984Sjkh
1436458Sache	case KEY_F(1): /* display help_file */
1446458Sache	case '?':
1456458Sache	    display_helpfile();
1466458Sache	    break;
1476458Sache	}
1486458Sache    }
1496458Sache
1506458Sache    return(ret);
1518858Srgrimes
1526458Sache} /* ReadObj() */
1536458Sache
1546458Sache
1556458Sacheint
1566458SachePollObj(ComposeObj **Obj)
1576458Sache{
1586458Sache    ComposeObj		*last;	 /* the last object in the list */
1596458Sache    ComposeObj		*first;  /* the first object in the list */
1606458Sache    int			ret;	 /* the return value from the selection routine */
1616458Sache
1626458Sache    /* find the last object in the list */
1636458Sache    last = *Obj;
1646458Sache    while (last->next) last = last->next;
1656458Sache
1666458Sache    /* find the first object in the list */
1676458Sache    first = *Obj;
1686458Sache    while (first->prev) first = first->prev;
1696458Sache
1706458Sache    ret = 0;
1716458Sache    switch((*Obj)->objtype) {
1726458Sache    case STRINGOBJ:
1736458Sache	ret = SelectStringObj((StringObj *) (*Obj)->obj);
1746458Sache	break;
1756458Sache    case LISTOBJ:
1766458Sache	ret = SelectListObj((ListObj *) (*Obj)->obj);
1776458Sache	break;
1786458Sache    case BUTTONOBJ:
1796458Sache	ret = SelectButtonObj((ButtonObj *) (*Obj)->obj);
1806458Sache	break;
1816458Sache    }
1826458Sache    switch(ret) {
18317984Sjkh    case KEY_DOWN:
1846458Sache    case SEL_CR:
1856458Sache    case SEL_TAB:		     /* move to the next object in the list */
1866458Sache	if ((*Obj)->next != NULL) {
1876458Sache	    *Obj = (*Obj)->next;     /* next object */
1886458Sache	} else {
1896458Sache	    *Obj = first;	     /* beginning of the list */
1906458Sache	}
1916458Sache	break;
19217984Sjkh
19317984Sjkh    case KEY_UP:
1946458Sache    case SEL_BACKTAB: 		     /* move to the previous object in the list */
1956458Sache	if ((*Obj)->prev != NULL) {
1966458Sache	    *Obj = (*Obj)->prev;     /* previous object */
1976458Sache	} else {
1986458Sache	    *Obj = last;	     /* end of the list */
1996458Sache	}
2006458Sache	break;
2016458Sache    }
2026458Sache
2036458Sache    return(ret);
2046458Sache
2056458Sache} /* PollObj() */
2066458Sache
2076458Sache
2086458Sachevoid
2096458SacheDelObj(ComposeObj *Obj)
2106458Sache/*
2116458Sache * Desc: Free all objects
2126458Sache */
2136458Sache{
2146458Sache    ComposeObj	*o;
2156458Sache
2166458Sache    o = Obj;
2176458Sache    while (Obj != NULL) {
2186458Sache	switch(Obj->objtype) {
2196458Sache	case STRINGOBJ:
2206458Sache	    DelStringObj((StringObj *) Obj->obj);
2216458Sache	    break;
2226458Sache	case LISTOBJ:
2236458Sache	    DelListObj((ListObj *) Obj->obj);
2246458Sache	    break;
2256458Sache	case BUTTONOBJ:
2266458Sache	    DelButtonObj((ButtonObj *) Obj->obj);
2276458Sache	    break;
2286458Sache	}
2296458Sache	Obj = Obj->next;
2306458Sache    }
2316458Sache
2326458Sache    FreeObj(o);
2336458Sache} /* DelObj() */
2348858Srgrimes
2356458Sache/***********************************************************************
2366458Sache *
2376458Sache * StringObj routines
2386458Sache *
2396458Sache ***********************************************************************/
2406458Sache
24120442Sjkhstatic void
24220442Sjkhoutstr(WINDOW *win, char *str, int attrs)
24320442Sjkh{
24420442Sjkh    if (attrs & DITEM_NO_ECHO) {
24520442Sjkh	char *cpy;
24620442Sjkh	int n = strlen(str);
24720442Sjkh
24820442Sjkh	cpy = alloca(n + 1);
24920442Sjkh	memset(cpy, '*', n);
25020442Sjkh	cpy[n] = '\0';
25120442Sjkh	waddstr(win, cpy);
25220442Sjkh    }
25320442Sjkh    else
25420442Sjkh	waddstr(win, str);
25520442Sjkh}
25620442Sjkh
2576458Sachevoid
2586458SacheRefreshStringObj(StringObj *so)
2596458Sache/*
2606458Sache * Desc: redraw the object
2616458Sache */
2626458Sache{
2636458Sache    char tmp[512];
2646458Sache
2656458Sache    wmove(so->win, so->y, so->x+1);
2666458Sache    wattrset(so->win, dialog_attr);
2676458Sache    waddstr(so->win, so->title);
2686458Sache
2696458Sache    draw_box(so->win, so->y+1, so->x, 3, so->w, dialog_attr, border_attr);
2706458Sache    wattrset(so->win, item_attr);
2716458Sache    wmove(so->win, so->y+2, so->x+1);
2726458Sache    if (strlen(so->s) > so->w-2) {
2736458Sache	strncpy(tmp, (char *) so->s + strlen(so->s) - so->w + 2, so->w - 1);
27420442Sjkh	outstr(so->win, tmp, so->attr_mask);
2756458Sache    } else {
27620442Sjkh	outstr(so->win, so->s, so->attr_mask);
2776458Sache    }
2786458Sache
2796458Sache    return;
2806458Sache} /* RefreshStringObj() */
2816458Sache
2826458SacheStringObj *
2836458SacheNewStringObj(WINDOW *win, char *title, char *s, int y, int x, int w, int len)
2846458Sache/*
2856458Sache * Desc: Initialize a new stringobj and return a pointer to it.
2866458Sache *	 Draw the object on the screen at the specified coordinates
2876458Sache */
2886458Sache{
2896458Sache    StringObj	*so;
2908858Srgrimes
2916458Sache    /* Initialize a new object */
2926458Sache    so = (StringObj *) malloc( sizeof(StringObj) );
2936458Sache    if (!so) {
2946458Sache	printf("NewStringObj: Error malloc'ing StringObj\n");
2956458Sache	exit(-1);
2966458Sache    }
2976458Sache    so->title = (char *) malloc( strlen(title) + 1);
2986458Sache    if (!so->title) {
2996458Sache	printf("NewStringObj: Error malloc'ing so->title\n");
3006458Sache	exit(-1);
3016458Sache    }
3026458Sache    strcpy(so->title, title);
3036458Sache    so->s = s;
3046458Sache    strcpy(so->s, s);
3056458Sache    so->x = x;
3066458Sache    so->y = y;
3076458Sache    so->w = w;
3086458Sache    so->len = len;
3096458Sache    so->win = win;
31020442Sjkh    so->attr_mask = DialogInputAttrs;	/* Grossly use a global to avoid changing API */
3116458Sache
3126458Sache    /* Draw it on the screen */
3136458Sache    RefreshStringObj(so);
3146458Sache
3156458Sache    return(so);
3166458Sache} /* NewStringObj() */
3176458Sache
3186458Sacheint
3196458SacheSelectStringObj(StringObj *so)
3206458Sache/*
3216458Sache * Desc: get input using the info in <so>
3226458Sache */
3236458Sache{
3246458Sache    int     	key;
3256458Sache    char	tmp[so->len+1];
3266458Sache
3276458Sache    strcpy(tmp, so->s);
3288858Srgrimes    key = line_edit(so->win, so->y+2, so->x+1,
32920442Sjkh		    so->len, so->w-2, inputbox_attr, TRUE, tmp, so->attr_mask);
3308804Sjkh    if ((key == '\n') || (key == '\r') || (key == '\t') || key == (KEY_BTAB) ) {
3316458Sache	strcpy(so->s, tmp);
3326458Sache    }
3336458Sache    RefreshStringObj(so);
3346458Sache    if (key == ESC) {
3356458Sache	return(SEL_ESC);
3366458Sache    }
3376458Sache    if (key == '\t') {
3386458Sache	return(SEL_TAB);
3396458Sache    }
3406458Sache    if ( (key == KEY_BTAB) || (key == KEY_F(2)) ) {
3416458Sache	return(SEL_BACKTAB);
3426458Sache    }
3436458Sache    if ((key == '\n') || (key == '\r')) {
3446458Sache	return(SEL_CR);
3456458Sache    }
3466458Sache    return(key);
3476458Sache} /* SelectStringObj() */
3486458Sache
3496458Sache
3506458Sachevoid
3516458SacheDelStringObj(StringObj *so)
3526458Sache/*
3536458Sache * Desc: Free the space occupied by <so>
3546458Sache */
3556458Sache{
3566458Sache   free(so->title);
3576458Sache   free(so);
3586458Sache
3596458Sache   return;
3606458Sache}
3618858Srgrimes
3626458Sache/***********************************************************************
3636458Sache *
3646458Sache * ListObj routines
3656458Sache *
3666458Sache ***********************************************************************/
3676458Sache
3686458Sachevoid
3696458SacheDrawNames(ListObj *lo)
3706458Sache/*
3716458Sache * Desc: Just refresh the names, not the surrounding box and title
3726458Sache */
3736458Sache{
3746458Sache    int 	i, j, h, x, y;
3756458Sache    char	tmp[MAXPATHLEN];
3766458Sache
3776458Sache    x = lo->x + 1;
3786458Sache    y = lo->y + 2;
3796458Sache    h = lo->h - 2;
3806458Sache    for (i=lo->scroll; i<lo->n && i<lo->scroll+h; i++) {
3816458Sache	wmove(lo->win, y+i-lo->scroll, x);
3827959Sache	if (lo->seld[i]) {
3837959Sache	    wattrset(lo->win, A_BOLD);
3847959Sache	} else {
3857959Sache	    wattrset(lo->win, item_attr);
3867959Sache	}
3876458Sache	if (strlen(lo->name[i]) > lo->w-2) {
3886458Sache	    strncpy(tmp, lo->name[i], lo->w-2);
3896458Sache	    tmp[lo->w - 2] = 0;
3906458Sache	    waddstr(lo->win, tmp);
3916458Sache	} else {
3926458Sache	    waddstr(lo->win, lo->name[i]);
3936458Sache	    for (j=strlen(lo->name[i]); j<lo->w-2; j++) waddstr(lo->win, " ");
3946458Sache	}
3956458Sache    }
3967959Sache    wattrset(lo->win, item_attr);
3976458Sache    while (i<lo->scroll+h) {
3986458Sache	wmove(lo->win, y+i-lo->scroll, x);
3996458Sache	for (j=0; j<lo->w-2; j++) waddstr(lo->win, " ");
4006458Sache	i++;
4016458Sache    }
4026458Sache
4038858Srgrimes    return;
4046458Sache} /* DrawNames() */
4056458Sache
4066458Sachevoid
4076458SacheRefreshListObj(ListObj *lo)
4086458Sache/*
4096458Sache * Desc: redraw the list object
4106458Sache */
4116458Sache{
4126458Sache    char 	perc[7];
4136458Sache
4146458Sache    /* setup the box */
4156458Sache    wmove(lo->win, lo->y, lo->x+1);
4166458Sache    wattrset(lo->win, dialog_attr);
4176458Sache    waddstr(lo->win, lo->title);
4186458Sache    draw_box(lo->win, lo->y+1, lo->x, lo->h, lo->w, dialog_attr, border_attr);
4196458Sache
4206458Sache    /* draw the names */
4216458Sache    DrawNames(lo);
4226458Sache
4236458Sache    /* Draw % indication */
4246458Sache    sprintf(perc, "(%3d%%)", MIN(100, (int) (100 * (lo->sel+lo->h-2) / MAX(1, lo->n))));
4256458Sache    wmove(lo->win, lo->y + lo->h, lo->x + lo->w - 8);
4266458Sache    wattrset(lo->win, dialog_attr);
4278858Srgrimes    waddstr(lo->win, perc);
4288858Srgrimes
4298858Srgrimes
4306458Sache    return;
4316458Sache} /* RefreshListObj() */
4328858Srgrimes
4336458SacheListObj *
4346458SacheNewListObj(WINDOW *win, char *title, char **list, char *listelt, int y, int x,
4356458Sache	   int h, int w, int n)
4366458Sache/*
4376458Sache * Desc: create a listobj, draw it on the screen and return a pointer to it.
4386458Sache */
4396458Sache{
4406458Sache    ListObj	*lo;
4417959Sache    int		i;
4426458Sache
4436458Sache    /* Initialize a new object */
4446458Sache    lo = (ListObj *) malloc( sizeof(ListObj) );
4456458Sache    if (!lo) {
4467959Sache	fprintf(stderr, "NewListObj: Error malloc'ing ListObj\n");
4476458Sache	exit(-1);
4486458Sache    }
4496458Sache    lo->title = (char *) malloc( strlen(title) + 1);
4506458Sache    if (!lo->title) {
4517959Sache	fprintf(stderr, "NewListObj: Error malloc'ing lo->title\n");
4526458Sache	exit(-1);
4536458Sache    }
4546458Sache    strcpy(lo->title, title);
4556458Sache    lo->name = list;
4567959Sache    if (n>0) {
4577959Sache        lo->seld = (int *) malloc( n * sizeof(int) );
4587959Sache        if (!lo->seld) {
4597959Sache            fprintf(stderr, "NewListObj: Error malloc'ing lo->seld\n");
4607959Sache            exit(-1);
4617959Sache        }
4627959Sache        for (i=0; i<n; i++) {
4637959Sache            lo->seld[i] = FALSE;
4647959Sache        }
4657959Sache    } else {
4667959Sache        lo->seld = NULL;
4677959Sache    }
4686458Sache    lo->y = y;
4696458Sache    lo->x = x;
4706458Sache    lo->w = w;
4716458Sache    lo->h = h;
4726458Sache    lo->n = n;
4736458Sache    lo->scroll = 0;
4746458Sache    lo->sel = 0;
4756458Sache    lo->elt = listelt;
4766458Sache    lo->win = win;
4776458Sache
4786458Sache    /* Draw the object on the screen */
4796458Sache    RefreshListObj(lo);
4806458Sache
4816458Sache    return(lo);
4826458Sache} /* NewListObj() */
4836458Sache
4846458Sachevoid
4856458SacheUpdateListObj(ListObj *lo, char **list, int n)
4866458Sache/*
4876458Sache * Desc: Update the list in the listobject with the provided list
4887959Sache * Pre:  lo->name "has been freed"
4897959Sache *	 "(A i: 0<=i<lo->n: "lo->name[i] has been freed")"
4906458Sache */
4916458Sache{
4926458Sache    int i;
4936458Sache
4947959Sache    if (lo->seld) {
4957959Sache	free(lo->seld);
4966458Sache    }
4976458Sache
4986458Sache    /* Rewrite the list in the object */
4996458Sache    lo->name = list;
5007959Sache    if (n>0) {
5017959Sache	lo->seld = (int *) malloc( n * sizeof(int) );
5027959Sache	if (!lo->seld) {
5037959Sache	    fprintf(stderr, "UpdateListObj: Error malloc'ing lo->seld\n");
5047959Sache	    exit(-1);
5057959Sache	}
5067959Sache	for (i=0; i<n; i++) {
5077959Sache	    lo->seld[i] = FALSE;
5087959Sache	}
5097959Sache    } else {
5107959Sache        lo->seld = NULL;
5118858Srgrimes    }
5126458Sache    lo->n = n;
5136458Sache    lo->scroll = 0;
5146458Sache    lo->sel = 0;
5156458Sache
5166458Sache    /* Draw the object on the screen */
5176458Sache    RefreshListObj(lo);
5186458Sache
5196458Sache    return;
5206458Sache} /* UpdateListObj() */
5216458Sache
5226458Sacheint
5236458SacheSelectListObj(ListObj *lo)
5246458Sache/*
5256458Sache * Desc: get a listname (or listnames), TAB to move on, or ESC ESC to exit
5266458Sache * Pre:	 lo->n >= 1
5276458Sache */
5286458Sache{
5297959Sache    int 	key, sel_x, sel_y, quit;
5306458Sache    char	tmp[MAXPATHLEN];
5316458Sache    char	perc[4];
5326458Sache
5336458Sache    sel_x = lo->x+1;
5346458Sache    sel_y = lo->y + 2 + lo->sel - lo->scroll;
5356458Sache
5366458Sache    if (lo->n == 0) return(SEL_TAB);
5376458Sache
5386458Sache    keypad(lo->win, TRUE);
5396458Sache
5406458Sache    /* Draw current selection in inverse video */
5416458Sache    wmove(lo->win, sel_y, sel_x);
5426458Sache    wattrset(lo->win, item_selected_attr);
5436458Sache    waddstr(lo->win, lo->name[lo->sel]);
5446458Sache
5456458Sache    key = wgetch(lo->win);
5467959Sache    quit = FALSE;
5478858Srgrimes    while ((key != '\t') && (key != '\n') && (key != '\r')
5487959Sache	   && (key != ESC) && (key != KEY_F(1)) && (key != '?') && !quit) {
5496458Sache	/* first draw current item in normal video */
5506458Sache	wmove(lo->win, sel_y, sel_x);
5517959Sache	if (lo->seld[lo->sel]) {
5527959Sache	    wattrset(lo->win, A_BOLD);
5537959Sache	} else {
5547959Sache	    wattrset(lo->win, item_attr);
5557959Sache	}
5566458Sache	if (strlen(lo->name[lo->sel]) > lo->w - 2) {
5576458Sache	    strncpy(tmp, lo->name[lo->sel], lo->w - 2);
5586458Sache	    tmp[lo->w - 2] = 0;
5596458Sache	    waddstr(lo->win, tmp);
5606458Sache	} else {
5616458Sache	    waddstr(lo->win, lo->name[lo->sel]);
5626458Sache	}
5636458Sache
5646458Sache	switch (key) {
5656458Sache	case KEY_DOWN:
5666458Sache	case ctrl('n'):
5676458Sache	    if (sel_y < lo->y + lo->h-1) {
5686458Sache		if (lo->sel < lo->n-1) {
5696458Sache		    sel_y++;
5706458Sache		    lo->sel++;
5716458Sache		}
5726458Sache	    } else {
5736458Sache		if (lo->sel < lo->n-1) {
5746458Sache		    lo->sel++;
5756458Sache		    lo->scroll++;
5766458Sache		    DrawNames(lo);
5776458Sache		    wrefresh(lo->win);
5786458Sache		}
5796458Sache	    }
5806458Sache	    break;
5816458Sache	case KEY_UP:
5826458Sache	case ctrl('p'):
5836458Sache	    if (sel_y > lo->y+2) {
5846458Sache		if (lo->sel > 0) {
5856458Sache		    sel_y--;
5866458Sache		    lo->sel--;
5876458Sache		}
5886458Sache	    } else {
5896458Sache		if (lo->sel > 0) {
5906458Sache		    lo->sel--;
5916458Sache		    lo->scroll--;
5926458Sache		    DrawNames(lo);
5936458Sache		    wrefresh(lo->win);
5946458Sache		}
5956458Sache	    }
5966458Sache	    break;
5976458Sache	case KEY_HOME:
5986458Sache	case ctrl('a'):
5996458Sache	    lo->sel = 0;
6006458Sache	    lo->scroll = 0;
6016458Sache	    sel_y = lo->y + 2;
6026458Sache	    DrawNames(lo);
6036458Sache	    wrefresh(lo->win);
6046458Sache	    break;
6056458Sache	case KEY_END:
6066458Sache	case ctrl('e'):
6076458Sache	    if (lo->n < lo->h - 3) {
6086458Sache		lo->sel = lo->n-1;
6096458Sache		lo->scroll = 0;
6106458Sache		sel_y = lo->y + 2 + lo->sel - lo->scroll;
6116458Sache	    } else {
6126458Sache		/* more than one page of list */
6136458Sache		lo->sel = lo->n-1;
6146458Sache		lo->scroll = lo->n-1 - (lo->h-3);
6156458Sache		sel_y = lo->y + 2 + lo->sel - lo->scroll;
6166458Sache		DrawNames(lo);
6176458Sache		wrefresh(lo->win);
6186458Sache	    }
6196458Sache	    break;
6206458Sache	case KEY_NPAGE:
6216458Sache	case ctrl('f'):
6226458Sache	    lo->sel += lo->h - 2;
6236458Sache	    if (lo->sel >= lo->n) lo->sel = lo->n - 1;
6246458Sache	    lo->scroll += lo->h - 2;
6256458Sache	    if (lo->scroll >= lo->n - 1) lo->scroll = lo->n - 1;
6266458Sache	    if (lo->scroll < 0) lo->scroll = 0;
6276458Sache	    sel_y = lo->y + 2 + lo->sel - lo->scroll;
6286458Sache	    DrawNames(lo);
6296458Sache	    wrefresh(lo->win);
6306458Sache	    break;
6316458Sache	case KEY_PPAGE:
6326458Sache	case ctrl('b'):
6336458Sache	    lo->sel -= lo->h - 2;
6346458Sache	    if (lo->sel < 0) lo->sel = 0;
6356458Sache	    lo->scroll -= lo->h - 2;
6366458Sache	    if (lo->scroll < 0) lo->scroll = 0;
6376458Sache	    sel_y = lo->y + 2 + lo->sel - lo->scroll;
6386458Sache	    DrawNames(lo);
6396458Sache	    wrefresh(lo->win);
6406458Sache	    break;
6417959Sache	default:
6427959Sache	    quit = TRUE;
6437959Sache	    break;
6446458Sache	}
6456458Sache	/* Draw % indication */
6468858Srgrimes	sprintf(perc, "(%3d%%)", MIN(100, (int)
6476458Sache				     (100 * (lo->sel+lo->h - 2) / MAX(1, lo->n))));
6486458Sache	wmove(lo->win, lo->y + lo->h, lo->x + lo->w - 8);
6496458Sache	wattrset(lo->win, dialog_attr);
6508858Srgrimes	waddstr(lo->win, perc);
6516458Sache
6526458Sache	/* draw current item in inverse */
6536458Sache	wmove(lo->win, sel_y, sel_x);
6546458Sache	wattrset(lo->win, item_selected_attr);
6556458Sache	if (strlen(lo->name[lo->sel]) > lo->w - 2) {
6566458Sache	    /* when printing in inverse video show the last characters in the */
6576458Sache	    /* name that will fit in the window */
6588858Srgrimes	    strncpy(tmp,
6598858Srgrimes		    lo->name[lo->sel] + strlen(lo->name[lo->sel]) - (lo->w - 2),
6606458Sache		    lo->w - 2);
6616458Sache	    tmp[lo->w - 2] = 0;
6626458Sache	    waddstr(lo->win, tmp);
6636458Sache	} else {
6646458Sache	    waddstr(lo->win, lo->name[lo->sel]);
6656458Sache	}
6667959Sache	if (!quit) key = wgetch(lo->win);
6676458Sache    }
6688858Srgrimes
6696458Sache    if (key == ESC) {
6706458Sache	return(SEL_ESC);
6716458Sache    }
6726458Sache    if (key == '\t') {
6736458Sache	return(SEL_TAB);
6746458Sache    }
6756458Sache    if ((key == KEY_BTAB) || (key == ctrl('b'))) {
6766458Sache	return(SEL_BACKTAB);
6776458Sache    }
6786458Sache    if ((key == '\n') || (key == '\r')) {
6796458Sache	strcpy(lo->elt, lo->name[lo->sel]);
6806458Sache	return(SEL_CR);
6816458Sache    }
6826458Sache    return(key);
6836458Sache} /* SelectListObj() */
6846458Sache
6856458Sachevoid
6866458SacheDelListObj(ListObj *lo)
6876458Sache/*
6886458Sache * Desc: Free the space occupied by the listobject
6896458Sache */
6906458Sache{
6916458Sache    free(lo->title);
6927959Sache    if (lo->seld != NULL) free(lo->seld);
6936458Sache    free(lo);
6946458Sache
6957959Sache    return;
6966458Sache} /* DelListObj() */
6976458Sache
6987959Sachevoid
6997959SacheMarkCurrentListObj(ListObj *lo)
7008858Srgrimes/*
7018858Srgrimes * Desc: mark the current item for the selection list
7027959Sache */
7037959Sache{
7047959Sache    lo->seld[lo->sel] = !(lo->seld[lo->sel]);
7057959Sache    DrawNames(lo);
7066458Sache
7077959Sache    return;
7087959Sache} /* MarkCurrentListObj() */
7097959Sache
7107959Sachevoid
7117959SacheMarkAllListObj(ListObj *lo)
7127959Sache/*
7137959Sache * Desc: mark all items
7147959Sache */
7157959Sache{
7167959Sache    int i;
7177959Sache
7187959Sache    for (i=0; i<lo->n; i++) {
7197959Sache        lo->seld[i] = TRUE;
7207959Sache    }
7217959Sache    DrawNames(lo);
7227959Sache
7237959Sache    return;
7247959Sache} /* MarkAllListObj() */
7257959Sache
7267959Sachevoid
7277959SacheUnMarkAllListObj(ListObj *lo)
7287959Sache/*
7297959Sache * Desc: unmark all items
7307959Sache */
7317959Sache{
7327959Sache    int i;
7338858Srgrimes
7347959Sache    for (i=0; i<lo->n; i++) {
7357959Sache        lo->seld[i] = FALSE;
7367959Sache    }
7377959Sache    DrawNames(lo);
7387959Sache
7397959Sache    return;
7407959Sache} /* UnMarkAllListObj() */
7417959Sache
7427959Sache
7436458Sache/***********************************************************************
7446458Sache *
7456458Sache * ButtonObj routines
7466458Sache *
7476458Sache ***********************************************************************/
7486458Sache
7496458Sache
7506458Sachevoid
7516458SacheRefreshButtonObj(ButtonObj *bo)
7526458Sache/*
7536458Sache * Desc: redraw the button
7546458Sache */
7556458Sache{
7566458Sache    draw_box(bo->win, bo->y, bo->x, 3, bo->w, dialog_attr, border_attr);
7576458Sache    print_button(bo->win, bo->title, bo->y+1, bo->x+2, FALSE);
7586458Sache
7596458Sache    return;
7606458Sache} /* RefreshButtonObj() */
7616458Sache
7626458SacheButtonObj *
7636458SacheNewButtonObj(WINDOW *win, char *title, int *pushed, int y, int x)
7646458Sache/*
7656458Sache * Desc: Create a new button object
7666458Sache */
7676458Sache{
7686458Sache    ButtonObj	*bo;
7696458Sache
7706458Sache    bo = (ButtonObj *) malloc( sizeof(ButtonObj) );
7718858Srgrimes
7726458Sache    bo->win = win;
7736458Sache    bo->title = (char *) malloc( strlen(title) + 1);
7746458Sache    strcpy(bo->title, title);
7756458Sache    bo->x = x;
7766458Sache    bo->y = y;
7776458Sache    bo->w = strlen(title) + 6;
7786458Sache    bo->h = 3;
7796458Sache    bo->pushed = pushed;
7806458Sache
7816458Sache    RefreshButtonObj(bo);
7826458Sache
7836458Sache    return(bo);
7846458Sache} /* NewButtonObj() */
7856458Sache
7866458Sacheint
7876458SacheSelectButtonObj(ButtonObj *bo)
7886458Sache/*
7896458Sache * Desc: Wait for buttonpresses or TAB's to move on, or ESC ESC
7906458Sache */
7916458Sache{
7926458Sache    int	key;
7936458Sache
7946458Sache    print_button(bo->win, bo->title, bo->y+1, bo->x+2, TRUE);
7956458Sache    wmove(bo->win, bo->y+1, bo->x+(bo->w/2)-1);
7966458Sache    key = wgetch(bo->win);
7978858Srgrimes    print_button(bo->win, bo->title, bo->y+1, bo->x+2, FALSE);
7986458Sache    switch(key) {
7996458Sache    case '\t':
8006458Sache	return(SEL_TAB);
8016458Sache	break;
8026458Sache    case KEY_BTAB:
8036458Sache    case ctrl('b'):
8046458Sache	return(SEL_BACKTAB);
8056458Sache    case '\n':
80622879Sache    case '\r':
8076458Sache	*(bo->pushed) = TRUE;
8086458Sache	return(SEL_BUTTON);
8096458Sache	break;
8106458Sache    case ESC:
8116458Sache	return(SEL_ESC);
8126458Sache	break;
8136458Sache    default:
8146458Sache	return(key);
8156458Sache	break;
8166458Sache    }
8176458Sache} /* SelectButtonObj() */
8186458Sache
8196458Sachevoid
8206458SacheDelButtonObj(ButtonObj *bo)
8216458Sache/*
8226458Sache * Desc: Free the space occupied by <bo>
8236458Sache */
8246458Sache{
8256458Sache    free(bo->title);
8266458Sache    free(bo);
8276458Sache
8286458Sache    return;
8296458Sache} /* DelButtonObj() */
830