/* ------------------------------------------------------------------------ */
/*                                sstmenu.c                                 */
/*                   pull-down menu interface routines                      */
/*                                                                          */
/*      CopyRight (C) 1991,1992  Steven Lutrov.   All rights reserved.      */
/* ------------------------------------------------------------------------ */
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <dos.h>

#include "sstvid.h"
#include "sstkey.h"
#include "sstwin.h"
#include "sstmnu.h"

typedef struct  {
	 int  x;
	 int  xx;
} itemrec;

typedef struct _mstyle {
	char    *title;                      /* title string */
	int     tjust;                       /* title justification */
	int     border;                      /* border type  */
	int     colour[4];                   /* colours for window  */
	int     hspace;                      /* spaces between horiz items  */
	int     lspace;                      /* left margin */
	int     rspace;                      /* right marigin  */
	int     hfull;                       /* use full horiz width  */
} MSTYLE;


static MSTYLE ms = {            /* set default to monochrome attributes */
   "", JUST_C, BRD_SINGLE,
       { CLR(BLACK,     LIGHTGRAY, DIM),
	 CLR(BLACK,     LIGHTGRAY, DIM),
	 CLR(LIGHTGRAY, BLACK,     BRIGHT),
	 CLR(BLACK,     LIGHTGRAY, DIM)
       },
   2,   /* spaces */
   1,   /* left margin */
   1,   /* right margin */
   0    /* full screen width */
   };

#define MWIN_BORDER	   (ms.colour[WIN_BORDER])
#define MWIN_TITLEC	   (ms.colour[WIN_TITLE])
#define MWIN_ACCENT        (ms.colour[WIN_ACCENT])
#define MWIN_FACE          (ms.colour[WIN_FACE])
#define MCOLOUR            (ms.colour)
#define MAXITEMS           16             /* maximum horiz menu items */

#define HKTAG    '~'

int msave = 1;

/* ------------------------------------------------------------------------ */
/*                       local function prototypes                          */
/* ------------------------------------------------------------------------ */

WINDOW *openmenu        (MENU *mn, int hsel);
static int  gethmenu    (MENU *mn, WINDOW *hmenu, int hsel);
static int  getvmn      (MENU *mn, WINDOW *hmenu, int *, int );
static int  haccent     (MENU *mn, WINDOW *hmenu, int hsel, int vsel);
static void dimension   (char *sl[], int *ht, int *wd);
static void light       (MENU *mn, WINDOW *hmenu, int hsel, int d);
static int  getwidth    (MENU *mn);
static int  getvertpos  (char **sl, int h);
static void putitems    (WINDOW *wnd, MENU *mn);


/* ------------------------------------------------------------------------ */
/*                             local variables                              */
/* ------------------------------------------------------------------------ */

static itemrec irec[MAXITEMS];   /* item records */
static int w;                    /* horizontal window width */
static int hc;                   /* horizontal item count */


/* ------------------------------------------------------------------------ */
/*                      display & process a menu                            */
/* ------------------------------------------------------------------------ */
int Mselect(MENU *mn, int h)
{
  WINDOW *openmenu();
  WINDOW *hmenu;
  int hsel = 1, vsel;


  vpushcur();
  vhidecur();
  if ((w = getwidth(mn)) > SCREENWIDTH)
	return (-1);
  w = ((ms.hfull) ? SCREENWIDTH : w);
  if ((hmenu = openmenu(mn, hsel)) == NULL)
       return (0);
  while ( (hsel = gethmenu(mn, hmenu, hsel)) != 0)	{
	vsel = 1;
	while ( (vsel = getvmn(mn, hmenu, &hsel, vsel)) !=0) {
		if(! h)
		    vpushscreen();
		Wdelete(hmenu);
		if(! h)
		    vpopscreen();
		(*(mn+hsel-1)->func [vsel-1])(hsel, vsel);
		if ((hmenu = openmenu(mn, hsel)) == NULL)
		    return (0);
	}
  }
  Wdelete(hmenu);
  vpopcur();
  return (1);
}

/* ------------------------------------------------------------------------ */
/*                          open a horizontal menu                          */
/* ------------------------------------------------------------------------ */
static WINDOW *openmenu(MENU *mn, int hsel)
{
     WINDOW *wnd;

     vhidecur();
     if ( (wnd = Westablish(0, 0, 3, w)) == NULL)
	   return (NULL);
     Wsettitle(wnd, ms.title,ms.tjust);
     WBORDER = MWIN_BORDER;
     WTITLEC = MWIN_TITLEC;
     WACCENT = MWIN_ACCENT;
     WFACE = MWIN_FACE;
     Wsetborder(wnd, ms.border);
     Wshow(wnd);
     putitems(wnd,mn);
     light(mn, wnd, hsel, 1);
     return wnd;
}

/* ------------------------------------------------------------------------ */
/*                        get a horizontal selection                        */
/* ------------------------------------------------------------------------ */
static int gethmenu(MENU *mn, WINDOW *hmenu, int hsel)
{
    int c;

    light(mn, hmenu, hsel, 1);
    while (1) {
      if (kkeyhit()) {
	  switch (c = kgetch())	{
	      case RIGHT:
	      case LEFT :  hsel = haccent(mn, hmenu, hsel, c);
			     break;
	      case ESC  :  return 0;
	      case ENTER:  return hsel;
	      default:	   break;
		  }
	   }
      } /* while */
}

/* ------------------------------------------------------------------------ */
/*                        pop down a vertical menu                          */
/* ------------------------------------------------------------------------ */
static int getvmn(MENU *mn,WINDOW *hmenu,int *hsel,int vsel)
{
    WINDOW *wnd;
    int ht, wd,x;
    char **mp;

    while (1)	{
	dimension((mn+*hsel-1)->mselcs, &ht, &wd);
	x = getvertpos((mn+*hsel-1)->mselcs,*hsel-1);
	wnd = Westablish(x, 2, ht, wd);
	WBORDER = MWIN_BORDER;
	WACCENT = MWIN_ACCENT;
	WFACE = MWIN_FACE;
	Wsetborder(wnd, ms.border+4);
	Wshow(wnd);
	mp = (mn+*hsel-1)->mselcs;
	while(*mp)
		Wprintf(wnd, "\n%s", *mp++);
	vsel = Wgetsel(wnd, vsel, "");
	Wdelete(wnd);
	if (vsel == RIGHT || vsel == LEFT)	{
		*hsel = haccent(mn, hmenu, *hsel, vsel);
		vsel = 1;
	}
	else
		return vsel;
    }
}

/* ------------------------------------------------------------------------ */
/*                               set colours                                */
/* ------------------------------------------------------------------------ */
void Msetcolour(int area,int bg,int fg,int inten)
{
    if (ISMONO())	{
	if (bg != WHITE && bg != BLACK)
		return;
	if (fg != WHITE && fg != BLACK)
		return;
     }
    if (area == WIN_ALL)
      while (area)
	 MCOLOUR [--area] = CLR(bg, fg, inten);
      else
	 MCOLOUR [area] = CLR(bg, fg, inten);
}



/* ------------------------------------------------------------------------ */
/*                         set the window's border                          */
/* ------------------------------------------------------------------------ */
void Msetborder(int btype)

{
   ms.border = btype;
}

/* ------------------------------------------------------------------------ */
/*                         set the window's border                          */
/* ------------------------------------------------------------------------ */
void Msetspace(int sp, int a)

{
   if ((a) & SPC_LEFT)
	ms.lspace = sp;
   if ((a) & SPC_RIGHT)
	ms.rspace = sp;
   if ((a) & SPC_BETWEEN)
	ms.hspace = sp;
}

/* ------------------------------------------------------------------------ */
/*                               set title                                  */
/* ------------------------------------------------------------------------ */
void Msettitle(char *title, int just)

{
  ms.title = title;
  ms.tjust = just;
}

/* ------------------------------------------------------------------------ */
/*                               set title                                  */
/* ------------------------------------------------------------------------ */
void Msetfullwidth(int f)

{
  if (f)
     ms.hfull = 1;
      else
       ms.hfull = 0;
}

/* ------------------------------------------------------------------------ */
/*                    display all the items on the vertical bar             */
/* ------------------------------------------------------------------------ */
static void putitems(WINDOW *wnd, MENU *mn)

{
    int l;

    hc = 0;
    for (l = 0 ; l < ms.lspace ; l++)
		    Wputch(wnd,' ');
    while (mn->mname) {
	Wprintf(wnd, "%s", mn->mname);
	for (l = 0 ; l < ms.hspace ; l++)
	    Wputch(wnd,' ');
	mn++;
	hc++;
     }
}

/* ------------------------------------------------------------------------ */
/*                 manage the horizontal menu selection accent              */
/* ------------------------------------------------------------------------ */
static int haccent(MENU *mn,WINDOW *hmenu,int hsel,int sel)
{
    switch (sel)	{
	case RIGHT  : light(mn, hmenu, hsel, 0);
		      if ((mn+hsel)->mname)
			hsel++;
		      else
			hsel = 1;
		      light(mn, hmenu, hsel, 1);
		      break;
	case LEFT   : light(mn, hmenu, hsel, 0);
		      if (hsel == 1)
			while ((mn+hsel)->mname)
				hsel++;
		      else
			--hsel;
		      light(mn, hmenu, hsel, 1);
		      break;
	default    :  break;
	}
  return hsel;
}

/* ------------------------------------------------------------------------ */
/*                      compute a menu's height & width                     */
/* ------------------------------------------------------------------------ */
static void dimension(char *sl[], int *ht, int *wd)
{
	*ht = *wd = 0;
	while (sl [*ht])	{
		*wd = max(*wd, strlen(sl [*ht]));
		(*ht)++;
	}
	*ht += 2;
	*wd += 2;
}

/* ------------------------------------------------------------------------ */
/*                    accent a horizontal menu selection                    */
/* ------------------------------------------------------------------------ */
static void light(MENU *mn, WINDOW *hmenu, int hsel, int d)
{
    if (d)
	Wrevvideo(hmenu);
    Wcursor(hmenu, irec[hsel-1].x, 0);
    Wprintf(hmenu, (mn+hsel-1)->mname);
    Wresetvideo(hmenu);
}

/* ------------------------------------------------------------------------ */
/*       compute the window width required for the horizontal menu bar      */
/* ------------------------------------------------------------------------ */
static int getwidth(MENU *mn)

{
   int c = 1,wd = 0;
   const MENU *mptr = mn;

   irec[0].x = ms.lspace;
   wd = ms.lspace;
   while ((mptr)->mname) {
	  wd += strlen(mptr->mname) + ms.hspace;
	  irec[c].x = wd;
	  irec[(c++)-1].xx = strlen((mptr++)->mname);
      }
   wd -=  ms.hspace;
   return (wd+ms.rspace+2);
}

/* ------------------------------------------------------------------------ */
/*       compute the window position  required for the vertical menu        */
/* ------------------------------------------------------------------------ */
static int getvertpos(char **sl, int h)

{
  int x,l = 0;

  while (*sl)  {
     l = max(l,strlen(*sl));
     sl++;
  }
  if (h > (hc /2))
     x = -3;
     else
       x = 2;
  return  ( (irec[h].x+l < w)  ? irec[h].x : (w-l)) +x;
}

