/***************************************************************************
 *                                                                         *
 *   CHOOSE.C                                                              *
 *                                                                         *
 *   Copyright (c) 1992-1997 Galacticomm, Inc.    All Rights Reserved.     *
 *                                                                         *
 *   This is the function suite that provides for simple manipulation      *
 *   of scrolling windows of choices for a user to select from.  Users     *
 *   may highlight different options using the PgUp, PgDn, cursur up,      *
 *   and cursor down keys, selecting a choice by hitting RETURN.           *
 *                                                                         *
 *                                             - Chris Robert 03/02/92     *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"

#define FILREV "$Revision: 7 $"

SHORT selatr=0x70;                 /* attr for currently selected choice   */
SHORT nslatr=0x1F;                 /* attr for other choices on the screen */

SHORT curchc;                      /* choice number currently selected     */
SHORT fstchc;                      /* 1st choice currently shown in window */

static SHORT nchcs;                /* number of choices there are          */
static CHAR **choices;             /* array of pointers to names of choices*/
static SHORT nchinw;               /* # of choices that can fit in a window*/
static SHORT chclen;               /* length of each choice in window      */
static SHORT upperx;               /* upper coordinates for 1st choice     */
static SHORT uppery;               /* upper y coordinates for 1st choice   */
static SHORT accesc;               /* flag whether to accept ESC to exit   */
static CHAR savbdy[160];           /* save area for bottom of display box  */
static INT mchoice;                /* which choice in choices[] do we match*/
static INT mindex;                 /* idx into choice we're trying to match*/
static INT bmindx;                 /* "base" left idx to begin comparing   */
static CHAR match[40];             /* match of desired choice so far       */

extern INT pxoff;                  /* x offset used by edtval() & prat()   */
extern INT pyoff;                  /* y offset used by edtval() & prat()   */

SHORT                              /*   returns choice num or -ESC for ESC */
choose(                            /* have user pick one of the choices    */
SHORT n,                           /*   number of choices offered user     */
CHAR *chcs[],                      /*   text of choices offered to user    */
SHORT upx,                         /*   upper-left x coordinate            */
SHORT upy,                         /*   upper-left y coordinate            */
SHORT lox,                         /*   lower-right x coordinate           */
SHORT loy,                         /*   lower-right y coordinate           */
GBOOL escok)                       /*   accept an ESCAPE to quit?          */
{
     supchc(n,chcs,upx,upy,lox,loy,escok);
     return(choout());
}

SHORT                              /*   returns choice num or -ESC for ESC */
choowd(                            /* choose one -- with a default         */
CHAR *chcs[],                      /*   choices offered (NULL-term'ed)     */
SHORT fc,                          /*   initial (default) choice index     */
SHORT upx,                         /*   upper-left x coordinates           */
SHORT upy,                         /*   upper-left y coordinates           */
SHORT lox,                         /*   lower-right x coordinates          */
SHORT loy,                         /*   lower-right y coordinate           */
GBOOL escok)                       /*   accept an ESCAPE to quit?          */
{
     SHORT count;
     CHAR **chp;

     for (count=0,chp=chcs ; *chp != NULL ; count++,chp++) {
     }
     supchc(count,chcs,upx,upy,lox,loy,escok);
     jmp2chc(fc);
     return(choout());
}

SHORT                              /*   returns choice num or -ESC for ESC */
choout(VOID)                       /* choose-an-option utility             */
{
     SHORT c,retval;

     dspchc();
     cursiz(GVIDNOCURS);
     do {
          c=getchc();
     } while ((retval=hdlchc(c)) == nchcs);
     rstcur();
     return(retval);
}

VOID
supchc(                            /* set-up to offer choices to user      */
SHORT n,                           /*   number of choices offered user     */
CHAR *chcs[],                      /*   text of choices offered to user    */
SHORT upx,                         /*   upper-left x coordinate            */
SHORT upy,                         /*   upper-left y coordinate            */
SHORT lox,                         /*   lower-right x coordinate           */
SHORT loy,                         /*   lower-right y coordinate           */
GBOOL escok)                       /*   accept an ESCAPE to quit?          */
{
     bmindx=mindex=(INT)(skpwht(chcs[0])-chcs[0]);
     nchcs=n;
     choices=chcs;
     upperx=upx+pxoff;
     uppery=upy+pyoff;
     curchc=fstchc=0;
     nchinw=loy-upy+1;
     chclen=lox-upx+1;
     accesc=escok;
     scn2mem(savbdy,gvscnoff(upperx,loy+pyoff+1),chclen*2);
}

SHORT                              /*   returns choice num or -ESC for ESC */
hdlchc(                            /* handle keystroke from user           */
SHORT c)                           /*   input character                    */
{
     switch (c) {
     case '\r':
          return(curchc);
     case CRSRDN:
          if (curchc+1 < nchcs) {
               if (curchc == fstchc+nchinw-1) {
                    fstchc++;
               }
               curchc++;
               dspchc();
          }
          break;
     case CRSRUP:
          if (curchc != 0) {
               if (curchc == fstchc) {
                    fstchc--;
               }
               curchc--;
               dspchc();
          }
          break;
     case PGDN:
          curchc+=nchinw;
          fstchc+=nchinw;
          if (curchc >= nchcs) {
               curchc=nchcs-1;
          }
          if (fstchc+nchinw >= nchcs) {
               fstchc=(nchcs-nchinw > 0 ? nchcs-nchinw : 0);
          }
          dspchc();
          break;
     case PGUP:
          curchc-=nchinw;
          fstchc-=nchinw;
          if (curchc < 0) {
               curchc=fstchc=0;
          }
          else if (fstchc < 0) {
               fstchc=0;
          }
          dspchc();
          break;
     case ESC:
          if (accesc) {
               return(-ESC);
          }
          break;
     default:
          while (1) {
               for (mchoice=0 ; mchoice < nchcs ; mchoice++) {
                    if (toupper(choices[mchoice][mindex]) == toupper(c)) {
                         if (mindex == bmindx || sameto(match,choices[mchoice])) {
                              match[mindex-bmindx]=choices[mchoice][mindex-bmindx];
                              match[(++mindex)-bmindx]='\0';
                              break;
                         }
                    }
               }
               if (mchoice != nchcs || mindex == bmindx) {
                    break;
               }
               mindex=bmindx;
          }
          if (mchoice != nchcs) {
               jmp2chc((SHORT)mchoice);
               dspchc();
          }
     }
     return(nchcs);
}

VOID
dspchc(VOID)                       /* display current list of choices      */
{
     SHORT i,id;

     for (i=0,id=fstchc ; i < nchinw ; i++,id++) {
          setatr((CHAR)((id == curchc) ? selatr : nslatr));
          locate(upperx,uppery+i);
          if (i < nchcs) {
               printf("%s",spr("%-*.*s",chclen,chclen,choices[id]));
          }
          else {
               printf("%s",spr("%-*s",chclen,""));
          }
     }
     if (fstchc+nchinw < nchcs && chclen >= 6) {
          setatr((CHAR)savbdy[1]);
          locate(upperx+(chclen-6)/2,uppery+nchinw);
          printf("(more)");
     }
     else {
          mem2scn(savbdy,gvscnoff(upperx,uppery+nchinw),chclen*2);
     }
}

VOID
jmp2chc(                           /* jump to a choice, with "centering"   */
SHORT fc)                          /*   choice to jump to                  */
{
     curchc=fc;
     if (curchc < fstchc || curchc >= fstchc+nchinw) {
          fstchc=max(0,min(curchc-nchinw/2,nchcs-nchinw));
     }
}
