home *** CD-ROM | disk | FTP | other *** search
- /*------------------------------------------------------------
- *
- * pmenuobj.c
- *
- * Popup MENU OBJect
- *
- * copyright (c) 1988,89,90 J. Alan Eldridge
- *
- *----------------------------------------------------------*/
-
- #include "curses.h"
-
- extern WINDOW *newwin(), *subwin(), *savescr();
-
- /* constructor function */
-
- int
- pm_ctor(this, id, y, x, title, maxr, arr, norm, high)
- POPUP_MENU *this;
- int id, y, x;
- char *title;
- int maxr;
- char **arr;
- int norm, high;
- {
- int r, c, scroll;
-
- /* count items & determine window size */
-
- this->itemcnt = scrollmsize(title, maxr, arr, &r, &c, &scroll);
- if (this->itemcnt == 0)
- return ERR;
-
- /* set default origin if asked to */
-
- if (y < 0 || x < 0) {
- getyx(curscr, y, x);
- calcpopyx(r, c, y, x, x, &y, &x);
- }
-
- /* try to allocate window including frame */
-
- if (!(this->box = newwin(r, c, y, x)))
- return ERR;
-
- /* set attributes if necessary & possible */
-
- if (iscolor()) {
- if (norm != -1)
- setnorm(this->box, norm);
- if (high != -1)
- setstand(this->box, high);
- wstandend(this->box);
- }
-
- /* get a subwindow for the items */
-
- if (!(this->win = subwin(this->box, r - 2, c - 2, y + 1, x + 1))) {
- delwin(this->box);
- return ERR;
- }
-
- /* save what's under the window */
-
- if (!(this->save = savescr(r, c, y, x))) {
- delwin(this->win);
- delwin(this->box);
- return ERR;
- }
-
- scrollok(this->win, 0);
- wrapok(this->win, 0);
-
- box(this->box, 0, 0);
-
- if (title)
- mvwaddstr(this->box, 0, 1, title);
-
- if (scroll) {
- mvwaddch(this->box, 1, getmaxc(this->box), CH_UPARROW);
- mvwaddch(this->box, getmaxr(this->box) - 1,
- getmaxc(this->box), CH_DNARROW);
- }
-
- this->itemlist = arr;
- this->curitem = this->topitem = 1;
- this->id = id;
-
- return OK;
- }
-
- /* destructor function : also restores screen */
-
- void
- pm_dtor(this)
- POPUP_MENU *this;
- {
- delwin(this->win);
- delwin(this->box);
- restscr(this->save);
- delwin(this->save);
- }
-
- /*
- calculate size needed by popup menu window
- and whether or not menu needs to scroll
-
- returns # of items in array
- */
-
- int
- scrollmsize(title, maxr, arr, rp, cp, scrollp)
- char *title;
- int maxr;
- char **arr;
- int *rp, *cp, *scrollp;
- {
- int icnt, ccnt, ilen;
-
- icnt = 0;
- ccnt = title ? strlen(title) : 0;
-
- while (*arr) {
- icnt++;
- ilen = strlen(*arr);
- if (ilen > ccnt)
- ccnt = ilen;
- arr++;
- }
-
- if (maxr > 0 && maxr < icnt) {
- *scrollp = 1;
- *rp = maxr + 2;
- } else {
- *scrollp = 0;
- *rp = icnt + 2;
- }
-
- *cp = ccnt + 4;
-
- return icnt;
- }
-
- int
- popmsize(title, arr, rp, cp)
- char *title, **arr;
- int *rp, *cp;
- {
- int dummy;
-
- return scrollmsize(title, -1, arr, rp, cp, &dummy);
- }
-
- /* draw popup menu with current item highlighted */
-
- void
- pm_draw(this)
- POPUP_MENU *this;
- {
- int r, rcnt, aidx, cidx;
-
- rcnt = getmaxr(this->win) + 1;
- aidx = this->topitem - 1;
- cidx = this->curitem - 1;
-
- for (r = 0; rcnt-- > 0; r++, aidx++) {
- if (aidx == cidx)
- wstandout(this->win);
- mvwaddch(this->win, r, 0, ' ');
- waddstr(this->win, this->itemlist[aidx]);
- wclrtoeol(this->win);
- if (aidx == cidx)
- wstandend(this->win);
- }
-
- touchwin(this->box);
- wrefresh(this->box);
- }
-
- /* change attributes of a row of a window */
-
- static void
- overat(win, row, cnt)
- WINDOW *win;
- int row, cnt;
- {
- wmove(win, row, 0);
- while (cnt-- > 0)
- waddch(win, winch(win));
- }
-
- /* set scrolling style */
-
- static int smooth = 1;
-
- void
- pm_smooth(flag)
- int flag;
- {
- smooth = flag;
- }
-
- /* highlight next item, scrolling if necessary */
-
- void
- pm_next(this, redraw_flag)
- POPUP_MENU *this;
- int redraw_flag;
- {
- int rcnt, ccnt, crow;
-
- if (this->curitem == this->itemcnt) {
- /* beep(); */
- return;
- }
-
- getmaxrc(this->win, rcnt, ccnt);
- rcnt++;
- ccnt++;
- this->curitem++;
-
- if (this->curitem < this->topitem + rcnt) {
- crow = this->curitem - this->topitem;
- overat(this->win, crow - 1, ccnt);
- wstandout(this->win);
- overat(this->win, crow, ccnt);
- wstandend(this->win);
- if (redraw_flag)
- wrefresh(this->win);
- } else {
- /* must scroll up */
- if (smooth)
- this->topitem++;
- else {
- this->topitem += rcnt - 1;
- if (this->topitem + rcnt - 1 > this->itemcnt)
- this->topitem = this->itemcnt - rcnt + 1;
- }
- if (redraw_flag)
- pm_draw(this);
- }
- }
-
- /* highlight previous item, scrolling if necessary */
-
- void
- pm_prev(this, redraw_flag)
- POPUP_MENU *this;
- int redraw_flag;
- {
- int rcnt, ccnt, crow;
-
- if (this->curitem == 1) {
- /*beep();*/
- return;
- }
-
- getmaxrc(this->win, rcnt, ccnt);
- rcnt++;
- ccnt++;
- this->curitem--;
-
- if (this->curitem >= this->topitem) {
- crow = this->curitem - this->topitem;
- overat(this->win, crow + 1, ccnt);
- wstandout(this->win);
- overat(this->win, crow, ccnt);
- wstandend(this->win);
- if (redraw_flag)
- wrefresh(this->win);
- } else {
- /* must scroll down */
- if (smooth)
- this->topitem--;
- else {
- this->topitem -= rcnt - 1;
- if (this->topitem < 1)
- this->topitem = 1;
- }
- if (redraw_flag)
- pm_draw(this);
- }
- }
-
- /* user i/o function : returns 0 for abort otherwise choice (first = 1) */
-
- int
- pm_choose(this)
- POPUP_MENU *this;
- {
- int c;
-
- pm_draw(this);
-
- hidecursor();
- while ((c = wgetch(this->win)) != K_ESC && c != K_NL)
- switch (c) {
- case K_SPACE:
- case K_TAB:
- case K_RIGHT:
- case K_DOWN:
- pm_next(this, 1);
- break;
- case K_BACK:
- case K_LEFT:
- case K_UP:
- pm_prev(this, 1);
- break;
- default:
- beep();
- break;
- }
- showcursor();
-
- return c == K_ESC ? 0 : this->curitem;
- }
-
- /*
- set the current item pointer
-
- this is a pessimal implementation ...
- (make it work, then make it fast - kernighan)
- */
-
- int
- pm_select(this, item_num)
- POPUP_MENU *this;
- int item_num;
- {
- int cur_item = this->curitem;
- int item_cnt = this->itemcnt;
-
- if (item_num > item_cnt || item_num < 1)
- return ERR;
-
- /*
- notice that at most one of these
- while loops will execute
- */
-
- while (cur_item > item_num) {
- cur_item--;
- pm_prev(this, 0);
- }
- while (cur_item++ < item_num)
- pm_next(this, 0);
-
- return OK;
- }
-
- /* return the itemlist pointer */
-
- char **
- pm_itemlist(this)
- POPUP_MENU *this;
- {
- return this->itemlist;
- }
-
- /* return the menu id */
-
- int
- pm_id(this)
- POPUP_MENU *this;
- {
- return this->id;
- }
-