|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T w
Length: 18090 (0x46aa)
Types: TextFile
Names: »widget.c«
└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0
└─⟦35176feda⟧ »EurOpenD22/isode/isode-6.tar.Z«
└─⟦de7628f85⟧
└─⟦this⟧ »isode-6.0/others/quipu/uips/widget/widget.c«
/* widget.c - Provides the screen and widget code */
#ifndef lint
static char *rcsid = "$Header: /f/osi/others/quipu/uips/widget/RCS/widget.c,v 7.0 89/11/23 22:09:45 mrose Rel $";
#endif
/*
* $Header: /f/osi/others/quipu/uips/widget/RCS/widget.c,v 7.0 89/11/23 22:09:45 mrose Rel $
*
*
* $Log: widget.c,v $
* Revision 7.0 89/11/23 22:09:45 mrose
* Release 6.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();
}