home *** CD-ROM | disk | FTP | other *** search
- /***( scroll.c )****************************************************************
- * *
- * Contains scrolling window functions for generic lists. *
- * *
- ********************************************************************************
- * *
- * Written: Dec 6, 1989 - SBF *
- * Updated: Dec 13, 1989 - SBF ( Made dll_scroll() re-entrant ) *
- * Dec 14, 1989 - SBF ( Added va_arg'ed special keys (like input_w ) ) *
- * Dec 14, 1989 - SBF ( Changed to use dll_getpos & dll_setpos ) *
- * MMM DD, YYYY - XXX ( ) *
- * *
- *******************************************************************************/
- #include <stdio.h>
- #include <bench.h>
- #include <dllist.h>
-
- struct scroll_cb
- {
- int *scbid;
- struct dll_entry *firstptr;
- struct dll_entry *selectptr;
- int sel_handle;
- int sel_mode;
- #ifdef ANSI
- char *(*dsp)(generic *);
- #else
- char *(*dsp)();
- #endif
- };
-
- #ifdef ANSI
- static void dll_disp_entry(int, int, int, struct scroll_cb *, generic *, int, int);
- # ifdef MOUSE
- static void dll_mouse_off(void);
- static void dll_mouse_on(int, int, int, int);
- # endif
- static struct scroll_cb *dll_scroll_open(int *);
- static generic *dll_valid_entry(int, char *(*)(generic *), int);
- int sel_cmp(struct sel_entry *, struct sel_entry *);
- #else
- static void dll_disp_entry();
- # ifdef MOUSE
- static void dll_mouse_off();
- static void dll_mouse_on();
- # endif
- static struct scroll_cb *dll_scroll_open();
- static generic *dll_valid_entry();
- int sel_cmp();
- #endif
-
- #define NUMSCROLLS 10
- #define MORESTR "..."
- #ifdef MSDOS
- #define MARKCHAR 0x10
- #else
- #define MARKCHAR '>'
- #endif
-
- #define dll_valid_next(x, y) dll_valid_entry(x, y, 0)
- #define dll_valid_prev(x, y) dll_valid_entry(x, y, 1)
-
- static struct scroll_cb *scb[NUMSCROLLS] = { 0 };
-
- #ifdef MOUSE
- static void dll_mouse_on(r, c, h, w)
- int r, c, h, w;
- {
- int i;
-
- mouse_level++;
-
- for(i = 0; i < h; i++)
- mouse_add_object((unsigned char)(r + i), (unsigned char)(c + 1),
- (unsigned char)(r + i), (unsigned char)(c + w - 1),
- 0, i + 1, NULL);
- }
-
- static void dll_mouse_off()
- {
- mouse_delete_level(mouse_level--);
- }
- #endif
-
- static struct scroll_cb *dll_scroll_open(winhd)
- int *winhd;
- {
- register int ctr;
- register struct scroll_cb *tmpscb = NULL;
-
- if (sel_w(winhd))
- {
- for(ctr = 0; ctr < NUMSCROLLS; ctr++)
- {
- if ((tmpscb = scb[ctr]) == NULL)
- continue;
- if (tmpscb->scbid == winhd)
- break;
- }
-
- if (ctr == NUMSCROLLS)
- {
- for(ctr = 0; ctr < NUMSCROLLS; ctr++)
- if ((tmpscb = scb[ctr]) == NULL)
- break;
-
- if (ctr == NUMSCROLLS)
- tmpscb = NULL;
- else
- {
- tmpscb = scb[ctr] = (struct scroll_cb *)alloc(sizeof(struct scroll_cb));
- if (tmpscb != NULL)
- tmpscb->scbid = winhd;
- }
- }
- }
-
- return(tmpscb);
- }
-
- int dll_scroll_close(scbid)
- int *scbid;
- {
- register int ctr;
-
- for(ctr = 0; ctr < NUMSCROLLS; ctr++)
- {
- if (scb[ctr] == NULL)
- continue;
- if (scbid == scb[ctr]->scbid)
- break;
- }
-
- if (ctr == NUMSCROLLS)
- return(-1);
-
- scb[ctr]->scbid = NULL;
- scb[ctr]->firstptr = NULL;
- scb[ctr]->selectptr = NULL;
- scb[ctr]->sel_handle = -1;
- scb[ctr]->sel_mode = 0;
- scb[ctr]->dsp = NULL;
-
- free(scb[ctr]);
- scb[ctr] = NULL;
-
- return(0);
- }
-
- static generic *dll_valid_entry(dll_d, dsp, previous)
- int dll_d;
- #ifdef ANSI
- char *(*dsp)(generic *);
- #else
- char *(*dsp)();
- #endif
- int previous;
- {
- register generic *tmpptr;
-
- do
- {
- if (previous)
- tmpptr = dll_prev(dll_d);
- else
- tmpptr = dll_next(dll_d);
-
- if (tmpptr == NULL)
- break;
- }
- while((*dsp)(tmpptr) == NULL);
-
- return(tmpptr);
- }
-
- static void dll_disp_entry(row, col, width, scbptr, entry, sel_flag, done)
- int row;
- int col;
- int width;
- struct scroll_cb *scbptr;
- generic *entry;
- int sel_flag;
- int done;
- {
- struct sel_entry sel_find;
- register struct sel_entry *septr;
- register char *dspptr;
-
- if (entry == NULL)
- disp_w(row, col, BOLD, " %-*s", width - 1, MORESTR);
- else
- {
- dspptr = (*scbptr->dsp)(entry);
-
- if (scbptr->sel_mode == SEL_MULTI)
- {
- sel_find.sel_data = entry;
- septr = (struct sel_entry *)dll_find(scbptr->sel_handle, &sel_find);
-
- if (septr != NULL)
- disp_w(row, col, sel_flag ? REVVID : BOLD, "%c%-*s", MARKCHAR,
- width - 1, dspptr);
- else
- disp_w(row, col, sel_flag ? REVVID : NORMAL, " %-*s", width - 1,
- dspptr);
- }
- else
- disp_w(row, col, sel_flag ? (done ? BOLD : REVVID) : NORMAL,
- " %-*s", width - 1, dspptr);
- }
- }
-
- /*
- * dll_scroll() - Bring up a scrolling window displaying a list of items from
- * a dll_... type of list.
- */
- #ifdef UNIX
- int dll_scroll(row, col, height, width, winhd, dll_d, dsp, sel_mode, helpnum, srow, scol, va_alist)
- int row; /* Row to display scrolling list at */
- int col; /* Column to display scrolling list at */
- int height; /* Maximum height of scrolling list */
- int width; /* Width of scrolling list */
- int *winhd; /* Pointer to window handle */
- int dll_d; /* Handle for dll_... list */
- char *(*dsp)(); /* Pointer to function which extracts display info */
- int sel_mode; /* SEL_SINGLE or SEL_MULTI */
- int helpnum; /* help number to use when K_HELP pressed */
- int srow;
- int scol;
- va_dcl
- #else
- int dll_scroll(int row, int col, int height, int width, int *winhd, int dll_d,
- char *(*dsp)(), int sel_mode,
- int helpnum, int srow, int scol, int va_alist, ...)
- #endif
- {
- struct dll_entry *headptr; /* Pointer to list's head */
- struct dll_entry *tailptr; /* Pointer to list's tail */
- struct dll_entry *lastptr; /* Pointer to last item in list */
- generic *genptr; /* General purpose pointer to list data */
- int dspctr; /* Display counter */
- int cc; /* Key value returned from inchar */
- int done = 0; /* Flag for done */
- struct sel_entry sel_add; /* Entry used to add to selection list */
- struct sel_entry *septr; /* Pointer to entry in selection list */
- int numentries = 0; /* Counter for number of entries in list to scroll */
- int refresh = 1; /* Flag for refresh display */
- int newscroll = 0;
- int spkey;
- va_list ap;
- struct dll_entry *lstptr;
- char *dspptr;
- #ifdef MOUSE
- int mouse_sel;
- #endif
- int r, c, h, w;
- struct scroll_cb *currscb;
- int moretop;
- int morebot;
- int pageheight;
-
- if ((currscb = dll_scroll_open(winhd)) == NULL)
- return(-1);
- if (currscb->firstptr == NULL)
- {
- newscroll = 1;
- currscb->sel_mode = sel_mode;
- currscb->dsp = dsp;
- }
-
- abs_w(&r, &c, &w, &h);
-
- genptr = dll_seek(dll_d, 0, SEEK_SET);
- if (genptr != NULL)
- {
- if ((*currscb->dsp)(genptr) == NULL)
- genptr = dll_valid_next(dll_d, currscb->dsp);
-
- for( ; genptr != NULL; genptr = dll_valid_next(dll_d, currscb->dsp))
- numentries++; /* Count the entries in the list to scroll */
- }
-
- if (numentries == 0) /* Return if no entries */
- return(-2);
-
- if (numentries < height) /* Adjust height if not enough entries */
- height = numentries;
-
- if ((currscb->sel_handle != -1 && (currscb->sel_mode == SEL_SINGLE || newscroll)) || currscb->sel_handle == -1)
- {
- currscb->sel_handle = dll_open(sel_cmp, sizeof(struct sel_entry));
- if (currscb->sel_handle == -1)
- return(-1);
- }
-
- /* Find head, tail, etc. */
- genptr = dll_seek(dll_d, 0, SEEK_SET);
- if ((*currscb->dsp)(genptr) == NULL)
- genptr = dll_valid_next(dll_d, currscb->dsp);
-
- headptr = dll_getpos(dll_d);
-
- if (newscroll)
- currscb->selectptr = currscb->firstptr = headptr;
-
- genptr = dll_seek(dll_d, 0, SEEK_END);
- if ((*currscb->dsp)(genptr) == NULL)
- genptr = dll_valid_prev(dll_d, currscb->dsp);
- tailptr = dll_getpos(dll_d);
-
- #ifdef MOUSE
- dll_mouse_on(r + row, c + col - 1, height, width);
- #endif
-
- if (currscb->sel_mode == SEL_SINGLE)
- keys_w(K_F1, help_prompt, K_CR, select_prompt, K_ESC, exit_prompt, 0);
- else
- keys_w(K_F1, help_prompt, ' ', select_prompt, K_CR, accept_prompt, K_ESC, exit_prompt, 0);
-
- while (!done)
- {
- if (srow && scol)
- {
- dll_setpos(dll_d, currscb->selectptr);
- genptr = dll_curr(dll_d);
- disp_w(srow, scol, REVVID, " %-*s", width - 1, (*currscb->dsp)(genptr));
- }
-
- moretop = (currscb->firstptr != headptr);
-
- if (refresh) /* Redraw the list entries if refresh flag is set */
- {
- dll_setpos(dll_d, currscb->firstptr);
- genptr = dll_curr(dll_d); /* Find the first to display */
- /* Fill the window */
- for(dspctr = 0; dspctr < height; genptr = dll_valid_next(dll_d, currscb->dsp))
- {
- if (moretop && dspctr == 0)
- {
- dll_disp_entry(row, col, width, NULL, NULL, 0, 0);
- dspctr++;
- }
-
- lstptr = dll_getpos(dll_d);
- dll_disp_entry(dspctr + row, col, width, currscb, genptr,
- (lstptr == currscb->selectptr), 0);
- lastptr = lstptr; /* Keep last entry displayed */
- dspctr++;
- }
- }
-
- morebot = (lastptr != tailptr);
-
- if (morebot)
- {
- dll_disp_entry(row + height - 1, col, width, NULL, NULL, 0, 0);
- dll_setpos(dll_d, lastptr);
- dll_valid_prev(dll_d, currscb->dsp);
- lastptr = dll_getpos(dll_d);
- }
-
- cc = inchar(); /* Get a key to determine what to do */
- ichar = cc;
-
- #ifdef UNIX
- va_start(ap);
- spkey = va_arg(ap, int);
- #else
- va_start(ap, va_alist);
- spkey = va_alist;
- #endif
-
- while (spkey != 0)
- {
- if (cc == spkey)
- {
- cc = K_CR;
- break;
- }
- spkey = va_arg(ap, int);
- }
- va_end(ap);
-
- if (cc < 256)
- if (islower(cc))
- cc = toupper(cc); /* Convert lower case chars to upper case */
-
- refresh = 1; /* Set the refresh flag */
-
- switch(cc)
- {
- #ifdef MOUSE
- case M_PRESS:
- if (!mouse_check_bounds())
- break;
- case M_RELEASE:
- if (mouse_click(&mouse_sel, cc))
- {
- if (moretop && mouse_sel == 1 && cc == M_RELEASE)
- unget_inchar(K_UP);
- else if (morebot && mouse_sel == height && cc == M_RELEASE)
- unget_inchar(K_DOWN);
- else
- {
- if (((moretop && mouse_sel > 1) ||
- (!moretop && mouse_sel >= 1)) &&
- ((morebot && mouse_sel < height) ||
- (!morebot && mouse_sel <= height)))
- {
- if (cc == M_RELEASE)
- unget_inchar(currscb->sel_mode == SEL_MULTI ? ' ':K_CR);
- dll_setpos(dll_d, currscb->firstptr);
- for(dspctr = 0; dspctr < mouse_sel - 1 - moretop ? 1 : 0;
- dspctr++)
- dll_valid_next(dll_d, currscb->dsp);
- currscb->selectptr = dll_getpos(dll_d);
- }
- }
- }
- break;
- #endif
- case '?':
- case K_HELP:
- help_msg(helpnum);
- sel_w(winhd);
- break;
- case K_DOWN:
- if (currscb->selectptr != tailptr) /* at the tail already? */
- {
- if (currscb->selectptr == lastptr) /* last on the screen? */
- {
- dll_setpos(dll_d, currscb->firstptr);
- dll_valid_next(dll_d, currscb->dsp); /* shift first by one */
- if (!moretop && morebot)
- dll_valid_next(dll_d, currscb->dsp);
- currscb->firstptr = dll_getpos(dll_d);
- }
- dll_setpos(dll_d, currscb->selectptr);
- dll_valid_next(dll_d, currscb->dsp); /* shift selected by one */
- currscb->selectptr = dll_getpos(dll_d);
- }
- break;
- case K_UP:
- if (currscb->selectptr != headptr) /* at the head already? */
- {
- if (currscb->selectptr == currscb->firstptr) /* first one? */
- {
- dll_setpos(dll_d, currscb->firstptr);
- dll_valid_prev(dll_d, currscb->dsp); /* shift first back */
- currscb->firstptr = dll_getpos(dll_d);
- if (moretop)
- {
- genptr = dll_valid_prev(dll_d, currscb->dsp);
- lstptr = dll_getpos(dll_d);
- if (lstptr == headptr)
- currscb->firstptr = headptr;
- }
- }
- dll_setpos(dll_d, currscb->selectptr);
- dll_valid_prev(dll_d, currscb->dsp); /* shift selected back */
- currscb->selectptr = dll_getpos(dll_d);
- }
- break;
- case K_PGUP:
- if (currscb->selectptr != currscb->firstptr)
- currscb->selectptr = currscb->firstptr;
- else
- {
- #ifdef UNIX
- dup_w();
- #endif
- pageheight = height - 3;
- if (!moretop || !morebot)
- pageheight++;
- for(dspctr = 0; dspctr < pageheight; dspctr++)
- unget_inchar(K_UP);
- }
- break;
- case K_PGDN:
- if (currscb->selectptr != lastptr)
- currscb->selectptr = lastptr;
- else
- {
- #ifdef UNIX
- dup_w();
- #endif
- pageheight = height - 3;
- if (!moretop || !morebot)
- pageheight++;
- for(dspctr = 0; dspctr < pageheight; dspctr++)
- unget_inchar(K_DOWN);
- }
- break;
- case K_HOME:
- currscb->selectptr = currscb->firstptr = headptr; /* Shift select & first to head */
- break;
- case K_END:
- currscb->selectptr = lastptr = tailptr; /* Shift select & last to tail */
- dll_setpos(dll_d, tailptr);
- for(dspctr = 0; dspctr < height - 1; dspctr++)
- {
- genptr = dll_valid_prev(dll_d, currscb->dsp);
- if (genptr == NULL)
- break;
- }
- if (genptr == NULL) /* Shift first to top of last page or head */
- currscb->firstptr = headptr;
- else
- {
- currscb->firstptr = dll_getpos(dll_d);
- if (currscb->firstptr != headptr)
- {
- dll_valid_next(dll_d, currscb->dsp);
- currscb->firstptr = dll_getpos(dll_d);
- }
- }
- break;
- case ' ':
- if (currscb->sel_mode == SEL_MULTI) /* If in multi-select mode */
- {
- dll_setpos(dll_d, currscb->selectptr);
- sel_add.sel_data = dll_curr(dll_d);
- /* Is entry selected? */
- septr = (struct sel_entry *)dll_find(currscb->sel_handle, &sel_add);
- if (septr != NULL)
- {
- if (dll_del(currscb->sel_handle) == -1) /* If so then de-select it */
- return(-1);
- }
- else /* Otherwise add it to the selection list */
- {
- if (dll_add(currscb->sel_handle, &sel_add, ADD_NOSORT) != 0)
- return(-1);
- }
- }
- break;
- case K_CR:
- if (currscb->sel_mode == SEL_SINGLE || /* If in single mode */
- (currscb->sel_mode == SEL_MULTI && /* Or multi with none selected */
- dll_seek(currscb->sel_handle, 0, SEEK_SET) == NULL))
- {
- dll_setpos(dll_d, currscb->selectptr);
- sel_add.sel_data = dll_curr(dll_d); /* Add to selection list */
- if (dll_add(currscb->sel_handle, &sel_add, ADD_NOSORT) != 0)
- return(-1);
- }
- dll_setpos(dll_d, currscb->firstptr);
- genptr = dll_curr(dll_d); /* Find first to display */
- /* Fill window */
- for(dspctr = 0; dspctr < height; genptr = dll_valid_next(dll_d, currscb->dsp))
- {
- if((moretop && dspctr == 0) || (morebot && dspctr == height - 1))
- {
- dll_disp_entry(dspctr + row, col, width, NULL, NULL, 0, 0);
- dspctr++;
- if (dspctr == height)
- continue;
- }
-
- dll_disp_entry(dspctr + row, col, width, currscb, genptr, 0, 1);
- dspctr++;
- }
- done = 1; /* Flag as done */
- break;
- case K_ESC:
- dll_close(currscb->sel_handle); /* Esc closes list and returns -1 handle */
- currscb->sel_handle = -1;
- done = 1;
- break;
- default:
- refresh = 0;
- if (cc < 256 && isalpha(cc))
- {
- pageheight = 0;
- dll_setpos(dll_d, currscb->selectptr);
- while((genptr = dll_valid_next(dll_d, currscb->dsp)) != NULL)
- {
- pageheight++;
- dspptr = (*currscb->dsp)(genptr);
-
- if ((islower((int)*dspptr) ? toupper((int)*dspptr) : *dspptr) == cc)
- break;
- }
- if (genptr == NULL)
- {
- lstptr = headptr;
- dll_setpos(dll_d, headptr);
- genptr = dll_curr(dll_d);
- while((lstptr = dll_getpos(dll_d)) != currscb->selectptr)
- {
- dspptr = (*currscb->dsp)(genptr);
- if ((islower((int)*dspptr) ? toupper((int)*dspptr) : *dspptr) == cc)
- break;
- genptr = dll_valid_next(dll_d, currscb->dsp);
- }
-
- if (lstptr == currscb->selectptr)
- genptr = NULL;
-
- pageheight = 0;
- dll_setpos(dll_d, currscb->selectptr);
- while(lstptr != dll_getpos(dll_d))
- {
- pageheight--;
- dll_valid_prev(dll_d, currscb->dsp);
- }
- }
- if (genptr != NULL)
- {
- #ifdef UNIX
- dup_w();
- #endif
- refresh++;
- for(dspctr = 0; dspctr < abs(pageheight); dspctr++)
- unget_inchar(pageheight < 0 ? K_UP : K_DOWN);
- }
- }
- break;
- }
- }
-
- #ifdef MOUSE
- dll_mouse_off();
- #endif
-
- return(currscb->sel_handle); /* Return the list handle (or -1 if ESC pressed) */
- }
-
- /*
- * sel_cmp() - Comparison function for selection list
- */
- int sel_cmp(p1, p2)
- struct sel_entry *p1;
- struct sel_entry *p2;
- {
- return(memcmp(p1, p2, sizeof(struct sel_entry)));
- }
-