DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T w

⟦6fe2dd64a⟧ TextFile

    Length: 18090 (0x46aa)
    Types: TextFile
    Names: »widget.c«

Derivation

└─⟦3d0c2be1b⟧ Bits:30001254 ISODE-5.0 Tape
    └─⟦eba4602b1⟧ »./isode-5.0.tar.Z« 
        └─⟦d3ac74d73⟧ 
            └─⟦this⟧ »isode-5.0/others/quipu/uips/widget/widget.c« 

TextFile

/* widget.c - Provides the screen and widget code */

#ifndef	lint
static char *rcsid = "$Header: /f/osi/others/quipu/uips/widget/RCS/widget.c,v 6.0 89/03/18 23:34:54 mrose Rel $";
#endif

/* 
 * $Header: /f/osi/others/quipu/uips/widget/RCS/widget.c,v 6.0 89/03/18 23:34:54 mrose Rel $
 *
 *
 * $Log:	widget.c,v $
 * Revision 6.0  89/03/18  23:34:54  mrose
 * Release 5.0
 * 
 */

/*
 *				  NOTICE
 *
 *    Acquisition, use, and distribution of this module and related
 *    materials are subject to the restrictions of a license agreement.
 *    Consult the Preface in the User's Manual for the full terms of
 *    this agreement.
 *
 */


/*****************************************************************************/
/* File:	widget.c
/* Author:	Paul Sharpe @ GEC Research, Hirst Research Centre.
/* Date:	August 12, 1988.
/* Function:	Provides the screen and widget code.
/*
/* DISCLAIMER:
/* This source file is deemed to be public domain: any person may use the
/* code in any way, on two simple provisos -
/*   1 - That this header remains in this file,
/*   2 - It is accepted that neither the author, nor the authors employees
/*       accept any responsibility for the use, abuse or misuse of the
/*       contained code.
/* No guarantee is made by the author to provide maintainance or up-grading
/* of this source. However, any adaptations made to this file will be viewed
/* at least with interest.
/*****************************************************************************/

#include <stdio.h>
#include <curses.h>
#include <setjmp.h>
#include <signal.h>

#define WIDGETLIB
#include "widget.h"

char	hghlghterase = FALSE;

struct active {
    int		count;
    WIDGET	*widgets[MAXACTIVE];
    char	lastindex[MAXACTIVE];
    WINDOW	*text[MAXACTIVE];
} activelist;

WINDOW		*Text;

jmp_buf		env;

extern char * strcpy ();

initwidgets()
{
    (void) initscr();
    crmode();
    noecho();
    Text = stdscr;

    activelist.count = 0;
}

setwidgets(thesewdgts, y)
int	y;
WIDGET	*thesewdgts;
{
register int	lowy;

    lowy = posnwidgets(thesewdgts, y);
    makewidgets(thesewdgts);
    Text = newwin(LINES-1-lowy,COLS,lowy,0);
    scrollok(Text, TRUE);
    refresh ();
    (void) wrefresh(Text);
    rfrshwidgets(thesewdgts);
    activewidget(thesewdgts, Text);
}

/* Determine the positions of the widgets: return the lowest point */
posnwidgets(thesewdgts, starty)
int	starty;
WIDGET	thesewdgts[];
{
register int	cnt = 0, x=0;

/* If no explicit position provided, put on the next level */
    if (starty < 0)
	starty = lowesty();

/* Set the position of the widgets, as dynamically as possible */
    while (thesewdgts[cnt].type != FINISH) {

/* If the initial structure y-value is CRNL, put on a new line */
	if (thesewdgts[cnt].y == CRNL) {
	    starty += WDGTHGHT;
	    x = 0;
	}

/* If we ain't got a width, make one based on the type/label-length */
 	if (thesewdgts[cnt].wdth <= 0)
	    setwdgtwdth(&thesewdgts[cnt], x);

/* If the widget won't fit, start a new line of widgets */
	if (x + thesewdgts[cnt].wdth > COLS) {
	    starty += WDGTHGHT;
	    x =  0;
	}
	thesewdgts[cnt].x = x;
	thesewdgts[cnt].y = starty;
	thesewdgts[cnt].hght = WDGTHGHT;
	x += thesewdgts[cnt].wdth;
	++cnt;
    }
    return(starty + thesewdgts[cnt-1].hght);
}

/* Create the widgets: return the number of widgets */
makewidgets(wdgts)
WIDGET	wdgts[];
{
register int		cnt = 0;
register WIDGET		*wdgt;

/* Now try to make, box and label the widget windows */
    while (wdgts[cnt].type != FINISH) {
	wdgt = &wdgts[cnt++];
	wdgt->wndw = newwin(wdgt->hght,wdgt->wdth,wdgt->y,wdgt->x);
	boxwdgt(wdgt, '-', '|');
	printwdgt(wdgt);
    }
}

/* Set a widgets width, based on the TYPE of widget and label length */
setwdgtwdth(wdgt, currx)
int	currx;
WIDGET	*wdgt;
{
register char	expand;
register int	len = -1, cnt = -1;

    if (expand = (wdgt->wdth == EXPAND))
	wdgt->wdth = COLS - currx;

    switch (wdgt->type) {
	case LABEL:	len = strlen(wdgt->label) + 2;
			if (wdgt->wdth < len)
			    if (expand)
				wdgt->wdth = COLS;
			    else
			        wdgt->wdth = len;
			break;
	case DIALOG:	len = strlen(wdgt->label) + 2;
			if (wdgt->dstrlen > DIALOGLEN)
			    len += DIALOGLEN;
			else
			    len += wdgt->dstrlen;
			if (wdgt->wdth < len) {
			    if (expand)
				wdgt->wdth = COLS;
			    else
				wdgt->wdth = len;
			}
			break;
	case TOGGLE:	if (wdgt->tvalues == (char **)NULL)
			    wdgt->wdth = strlen(wdgt->label) + 2;
			else {
			    while(wdgt->tvalues[++cnt] != (char *)NULL)
				if (strlen(wdgt->tvalues[cnt]) > len)
				    len = strlen(wdgt->tvalues[cnt]);
			    wdgt->wdth = strlen(wdgt->label) + len + 2;
			}
			break;
	default:	wdgt->wdth = strlen(wdgt->label) + 2;
			break;
    }
}

/* Erase and remove the widgets, decrementing the activelist counter */
killwidgets(thesewdgts)
WIDGET	*thesewdgts;
{
register int	cnt = 0;

    while (thesewdgts[cnt].type != FINISH) {
	(void) wclear(thesewdgts[cnt].wndw);
	(void) wrefresh(thesewdgts[cnt++].wndw);
    }
    cnt = 0;
    while (thesewdgts[cnt].type != FINISH)
	delwin(thesewdgts[cnt++].wndw);
    delwin(Text);

    deleteactive();

    Text = activelist.text[activelist.count-1];
    if (Text != (WINDOW *)NULL)
          (void) wrefresh(Text);

}

/* THESE FUNCTIONS MANIPULATE THE ACTIVELIST ARRAY OF WIDGETS */

/* This should check that the number of active widgets is not excessive, or
 * have the activelist really as a linked list.
 */
/* ARGSUSED */
activewidget(wdgts, text)
WIDGET	wdgts[];
WINDOW	*text;
{
    activelist.widgets[activelist.count] = wdgts;
    activelist.text[activelist.count]    = Text;
    ++(activelist.count);
}

deleteactive()
{
    if (activelist.count > 0)
        --(activelist.count);
}

activeindex(index)
char	index;
{
    activelist.lastindex[activelist.count - 1] = index;
}

/* Refresh each of the active widgets and the current text window */
redraw()
{
register int	i;

    clearok(curscr,TRUE);
    for (i=0; i<activelist.count; i++)
	rfrshwidgets(activelist.widgets[i]);
    (void) wrefresh(Text);
}

rfrshwidgets(thesewdgts)
WIDGET	*thesewdgts;
{
int	i = 0;

    while (thesewdgts[i].wndw != (WINDOW *)NULL) {
	touchwin(thesewdgts[i].wndw);
	(void) wrefresh(thesewdgts[i++].wndw);
    }
}

/* Draw a perimeter box around WDGT, with horizontal char XCH etc */
boxwdgt(wdgt,xch,ych)
char	xch, ych;
WIDGET	*wdgt;
{
register int	x;

    mvwaddch(wdgt->wndw,0,0,'.');
    for (x=1; x<wdgt->wdth-1; x++)
	(void) waddch(wdgt->wndw,xch);
    (void) waddch(wdgt->wndw,'.');

    mvwaddch(wdgt->wndw,1,0,ych);
    mvwaddch(wdgt->wndw,1,wdgt->wdth-1,ych);

    mvwaddch(wdgt->wndw,2,0,'`');
    for (x=1; x<wdgt->wdth-1; x++)
	(void) waddch(wdgt->wndw,xch);
    (void) waddch(wdgt->wndw,'\'');
}

/* THESE ROUTINES PRINT THE INDIVIDUAL WIDGET BOXES */

/* Print a widgets label, dependant on the widget type */
printwdgt(wdgt)
WIDGET	*wdgt;
{
    switch(wdgt->type) {
	case LABEL :printlabel(wdgt);
		    break;
	case DIALOG:printdialog(wdgt);
		    break;
	case TOGGLE:printtoggle(wdgt);
		    break;
	default	   :printcommand(wdgt);
		    break;
    }
}

/* Print a LABEL widgets label string, dependant on the justification char */
printlabel(wdgt)
WIDGET	*wdgt;
{
register int	x, labellen, wdgtlen;

    labellen = strlen(wdgt->label);
    wdgtlen = wdgt->wdth - 2;

    if (labellen > wdgtlen)
	wdgt->label[wdgtlen] = '\0';

    if (wdgt->callch & CENTRE)
        x = (wdgtlen - labellen)/2;
    else
	if (wdgt->callch & LEFT)
	    x = 0;
        else
	    if (wdgt->callch & RIGHT)
	        x = wdgtlen - labellen;
    mvwaddstr(wdgt->wndw,1,1+x,wdgt->label);
}

/* Print a DIALOG widget label: if it don't all fit, show the last part */
printdialog(wdgt)
WIDGET	*wdgt;
{
register int	length, maxlen;
register char	*showptr;

    if (wdgt->dstr != (char *)NULL) {
        length = strlen(wdgt->dstr);
	maxlen = wdgt->wdth - 4 - strlen(wdgt->label);
        if (length > maxlen)
	    showptr = &(wdgt->dstr[length - maxlen]);
	else
            showptr = wdgt->dstr;
        (void) mvwprintw(wdgt->wndw,1,1,"%s%c%s",wdgt->label,(length > maxlen)?'<':' ',showptr);
    }
}

/* Print a TOGGLE widget label, and the current toggle value */
printtoggle(wdgt)
WIDGET	*wdgt;
{
    if (wdgt->tvalues == (char **)NULL)
	return;
    mvwaddstr(wdgt->wndw,1,1,wdgt->label);
    (void) waddstr(wdgt->wndw,wdgt->tvalues[wdgt->tindx]);
    (void) wclrtoeol(wdgt->wndw);
    mvwaddch(wdgt->wndw,1,wdgt->wdth-1,'|');
}

/* Print a COMMAND widget label */
printcommand(wdgt)
WIDGET	*wdgt;
{
    mvwaddstr(wdgt->wndw,1,1,wdgt->label);
}

/* THESE ROUTINES GET AND REACT TO A USERS INPUT FROM THE KEYBOARD */

/* Loop forever, calling widget callback functions when activated */
interact()
{
register int	ch, index;
void		int_quit(), jumpback();

    for (;;) {
/* Get a character input, and set the interrupt jump vector */
	(void) setjmp(env);
	(void) signal(SIGINT, int_quit);

	move(0,0);
	refresh();
	ch = getchar();
	(void) signal(SIGINT, jumpback);

/* Allow the user to refresh the entire screen, with a CTRL-L */
	if (ch == '\014') {
	    redraw();
	    continue;
	}

/* Search through the current widgets for one matching that required */
	index = findactiveinput(ch);
	if (index >= 0)
	    docallback(index);
    }
}

/* Find a callback 'ch' from the currently active set of widgets */
findactiveinput(ch)
char	ch;
{
register int	index;
register WIDGET	*wdgts;

/* See whether the 'ch' exists in the currently active widgets */
    wdgts = activelist.widgets[activelist.count - 1];
    index = getwidgetindex(wdgts, ch);
    if (index >= 0)
	return(index);

/* If not, check the previously active widgets, if possible */
    if (activelist.count <= 1)
	return(-1);
    index = getwidgetindex(activelist.widgets[activelist.count - 2], ch);
    if (index >= 0) {
	killwidgets(activelist.widgets[activelist.count - 1]);
	return(index);
    }
    return(-1);
}

docallback(index)
char	index;
{
WIDGET	*wdgts;

    activeindex(index);
    wdgts = activelist.widgets[activelist.count - 1];
    switch (wdgts[index].type) {
	case DIALOG :	highlight(index);
			dialog(&wdgts[index]);
			(*wdgts[index].callfn)();
			dehighlight();
			break;
	case TOGGLE :	toggle(&wdgts[index]);
			(*wdgts[index].callfn)();
			break;
	default	    :	highlight(index);
			(*wdgts[index].callfn)();
			dehighlight();
			break;
    }
}

/* THESE ROUTINES HIGHLIGHT AND DEHIGHLIGHT A SELECTED WIDGET BOX */

/* Highlight WDGTNUM widget from the active widgets. */
highlight(wdgtnum)
int	wdgtnum;
{
register int		cnt = 0;
register WIDGET		*active;

    active = activelist.widgets[activelist.count - 1];
    if (!hghlghterase) {
	(void) wstandout(active[wdgtnum].wndw);
	printwdgt(&active[wdgtnum]);
	(void) wstandend(active[wdgtnum].wndw);
        (void) wrefresh(active[wdgtnum].wndw);
	return;
    }
    while (active[cnt].wndw != (WINDOW *)NULL) {
	if (cnt == wdgtnum) {
	    (void) wstandout(active[wdgtnum].wndw);
	    printwdgt(&active[wdgtnum]);
	    (void) wstandend(active[wdgtnum].wndw);
	}
	else {
	    if (active[cnt].type != LABEL) {
	        (void) wmove(active[cnt].wndw,1,1);
	        (void) wclrtoeol(active[cnt].wndw);
	        mvwaddch(active[cnt].wndw,1,active[cnt].wdth-1,'|');
	    }
	}
        (void) wrefresh(active[cnt++].wndw);
    }
}

/* Return the WDGTNUM widget from the active wdgts to normal state */
dehighlight()
{
register int		cnt = 0;
register WIDGET		*active;

    if (activelist.count <= 0)
	return;
    active = activelist.widgets[activelist.count - 1];
    while (active[cnt].wndw != (WINDOW *)NULL) {
	printwdgt(&active[cnt]);
	(void) wrefresh(active[cnt++].wndw);
    }
}

/* THESE ROUTINES SEARCH THE ACTIVE WIDGET SET FOR ONE SPECIFIED WIDGET */

/* Find a widget based on the call-back character */
WIDGET *
getwidget(wdgts, callch)
int	callch;
WIDGET	wdgts[];
{
register int	index;

    index = getwidgetindex(wdgts, callch);
    if (index >= 0)
	return(&(wdgts[index]));
    return((WIDGET *)NULL);
}

getwidgetindex(wdgts, callch)
int	callch;
WIDGET	wdgts[];
{
register int	cnt = 0;

    while (wdgts[cnt].type != FINISH) {
	if (callch == wdgts[cnt].callch)
	    break;
	++cnt;
    }
    if (wdgts[cnt].type != FINISH)
	return(cnt);
    return(-1);
}

/* THESE ROUTINES MANIPULATE THE DIALOG WIDGETS */

dialog(wdgt)
WIDGET	*wdgt;
{
register int		i, length, labellen, maxlen;
register char		ch, *endptr, *showptr;
register char		*blanks;
extern char		*malloc();

    labellen = strlen(wdgt->label);	/* The length of the prompt string  */
    length = strlen(wdgt->dstr);	/* The length of the current string */

    maxlen = wdgt->wdth - 4 - labellen;	/* The maximum length of shown str  */
    blanks = malloc((unsigned)(maxlen + 2));
    for (i=0; i<maxlen; i++)
	blanks[i] = ' ';
    blanks[i] = '\0';

    endptr = &(wdgt->dstr[length]);	/* The next character pos'n to fill */
    *endptr = '\0';

    if (length > maxlen)
	showptr = &(wdgt->dstr[length - maxlen]);
    else
        showptr = wdgt->dstr;
    (void) mvwprintw(wdgt->wndw,1,1,"%s%c%s",wdgt->label,(length > maxlen)?'<':' ',showptr);
    (void) wrefresh(wdgt->wndw);

    while ((ch = getchar() & 127) != '\n' && ch != '\r' && ch != '\f') {
	if (ch == '\014') {			/* Allow for redrawing */
	    redraw();
	    continue;
	}

	if (ch == '\b' || ch == 127) {	/* Delete a character, with wrapping */
	    if (length == 0)
		continue;
	    *(--endptr) = '\0';		/* Make the last character NULL */
	    if (showptr > wdgt->dstr)	/* We have parts of the string hidden */
	        --showptr;
	    --length;
	    if (length < maxlen) {	/* Only need to erase one character */
		(void) waddstr(wdgt->wndw,"\b \b");
    		(void) wrefresh(wdgt->wndw);
		continue;
	    }
	    /* We'll have to erase everything */
	    (void) wprintw(wdgt->wndw,"\r|%s%c%s \b",wdgt->label,(length <= maxlen)?' ':'<',showptr);
    	    (void) wrefresh(wdgt->wndw);
	    continue;
	}

	if (ch == 21) {		/* ^U to delete the entire line of text */
	    length = 0;
	    endptr = wdgt->dstr;
	    *endptr = '\0';
	    showptr = wdgt->dstr;
	    (void) wprintw(wdgt->wndw,"\r|%s %s\r|%s ",wdgt->label,blanks,wdgt->label);
    	    (void) wrefresh(wdgt->wndw);
	    continue;
	}

/* Otherwise, add the character if there is room and it ain't a control code */
	if (length == wdgt->dstrlen || ch < 32)
	    continue;
	*endptr++ = ch;
	*endptr = '\0';
	if (++length <= maxlen) {	/* Just add this character to the end */
	    (void) waddch(wdgt->wndw,ch);
    	    (void) wrefresh(wdgt->wndw);
	    continue;
	}
	++showptr;
	(void) wprintw(wdgt->wndw,"\r|%s<%s",wdgt->label,showptr);
    	(void) wrefresh(wdgt->wndw);
    }
    free(blanks);
}

setdialogstr(wdgt, dstr, dstrlen)
int		dstrlen;
char		*dstr;
WIDGET	*wdgt;
{
    if (wdgt->type != DIALOG)
	return;
    wdgt->dstr = dstr;
    wdgt->dstrlen = dstrlen;
}

getdialogstr(wdgt, str)		/* 'str' must be long enough... */
char	str[];
WIDGET	*wdgt;
{
    if (wdgt->type != DIALOG || wdgt->dstr == (char *)NULL)
	return(FALSE);
    (void) strcpy(str, wdgt->dstr);
    return(TRUE);
}

/* THESE ROUTINES MANIPULATE THE TOGGLE WIDGETS */

toggle(wdgt)
WIDGET	*wdgt;
{
    if (wdgt->tvalues == (char **)NULL)
	return;
    if (wdgt->tvalues[++wdgt->tindx] == (char *)NULL)
	wdgt->tindx = 0;
    printtoggle(wdgt);
    (void) wrefresh(wdgt->wndw);
}

settogglstrs(wdgt, togglstrs, togglindx)
int	togglindx;
char	**togglstrs;
WIDGET	*wdgt;
{
    if (wdgt->type != TOGGLE)
	return;
    wdgt->tvalues = togglstrs;
    wdgt->tindx = togglindx;
}

settogglindx(wdgt, indx)
int	indx;
WIDGET	*wdgt;
{
int	i;

    if (wdgt->type != TOGGLE || wdgt->tvalues == (char **)NULL)
	return(FALSE);
    for (i=0; i<indx; i++)
	if (wdgt->tvalues[i] == (char *)NULL)
	    break;
    if (i != indx)		/* There ain't that many toggle strings */
	return(FALSE);
    wdgt->tindx = indx;
    return(TRUE);
}

gettogglindx(wdgt)
WIDGET	*wdgt;
{
    if (wdgt->type != TOGGLE || wdgt->tvalues == (char **)NULL)
	return(-1);
    return(wdgt->tindx);
}

gettogglstr(wdgt, str)		/* 'str' must be long enough... */
WIDGET	*wdgt;
char	str[];
{
    if (wdgt->type != TOGGLE || wdgt->tvalues == (char **)NULL)
	return(FALSE);
    (void) strcpy(str, wdgt->tvalues[wdgt->tindx]);
    return(TRUE);
}

/* THESE ROUTINES MANIPULATE THE LABEL WIDGETS */

setlabel(wdgt, label)
WIDGET	*wdgt;
char	*label;
{
    wdgt->label = label;
}

getlabel(wdgt, label)		/* 'label' must be long enough... */
WIDGET	*wdgt;
char	label[];
{
    (void) strcpy(label, wdgt->label);
}

/* MISCELLANEOUS FUNCTIONS */

/* Try to locate the bottom of the last set of widgets displayed */
lowesty()
{
register int		cnt = 0;
register WIDGET		*wdgts;

    if (activelist.count <= 0)
	return(0);
    wdgts = activelist.widgets[activelist.count - 1];
    while (wdgts[cnt].type != FINISH)
	++cnt;
    if (cnt == 0)
	return(0);
    return((wdgts[cnt-1].y) + WDGTHGHT);
}

/* Whether COMMAND widgets should be erased during a highlight */
erasehghlght(flag)
{
    if (flag == TRUE || flag == FALSE)
        hghlghterase = flag;
}

/* This satisfies the generalised printing structure */
/* ARGSUSED */
wprint(here, fmt, a,b,c,d,e,f,g,h,i,j)
WINDOW	*here;
char	*fmt, *a,*b,*c,*d,*e,*f,*g,*h,*i,*j;
{
    (void) wprintw(Text,fmt,a,b,c,d,e,f,g,h,i,j);
    (void) wrefresh(Text);
}

/* This can be called as a way for an application to print text */
/* VARARGS1 */
tprint(fmt, a,b,c,d,e,f,g,h,i,j)
char	*fmt, *a,*b,*c,*d,*e,*f,*g,*h,*i,*j;
{
    (void) wprintw(Text,fmt,a,b,c,d,e,f,g,h,i,j);
    (void) wrefresh(Text);
}

cleartext()
{
    (void) wclear(Text);
    (void) wrefresh(Text);
}

/* Jump back to the interact function only on an interrupt */
void jumpback()
{
    dehighlight();
    (void) waddstr(Text,"\n*** Interrupted ***\n");
    (void) wrefresh(Text);
    longjmp(env, TRUE);
}

/* This is used as a declaration, when no function callback is required */
nullfn()
{}

/* This is used by widgets that just want to kill the current level */
quitfn()
{
    (void) wclear(Text);
    (void) wrefresh(Text);
    killwidgets(activelist.widgets[activelist.count - 1]);
}

endwidgets()
{
    tprint("\nEnding the widget interface session.\n");
    endwin();
}