static char rcsid[] = "@(#)$Id: menu.c,v 1.10 2006/04/09 07:37:18 hurtta Exp $";

/******************************************************************************
 *  The Elm (ME+) Mail System  -  $Revision: 1.10 $   $State: Exp $
 *
 *  Modified by: Kari Hurtta <hurtta+elm@posti.FMI.FI> 
 *                           (was hurtta+elm@ozone.FMI.FI)
 *
 *  Initially written by: Michael Elkins <elkins@aero.org>, 1995
 *****************************************************************************/

/* 
 *
 * API for creating menus in Elm.
 * Initially written by: Michael Elkins <elkins@aero.org>, 17 May 1995.
 *
 * PLEASE SEND ME ANY CHANGES YOU MAKE TO THIS API!
 *
 * The basic sequence of using this api is as follows:
 *
 *  menu_t menu;
 *
 *  MenuInit(&menu, "Test Menu", "Please Select an option: ", "q)uit");
 *  for (...)
 *    MenuAdd(&menu, "Menu item n");
 *  for (;;) {
 *    switch(MenuLoop(&menu)) {
 *    case '\n':
 *      selected_item = MenuCurrent(&menu);
 *      MenuDestroy(&menu);
 *      return(selected_item);
 *    }
 *  }
 */

#include "def_elm.h"
#include "menu.h"

DEBUG_VAR(Debug,__FILE__,"ui");

/* creates a new menu instance.  'm' is a pointer to a 'menu_t', 't' is the
   menu title, 'p' is the prompt string and 'h' is a help string. 'h' may
   be specified as NULL if no help line is desired.  */

void MenuInit (m, t, p, h)
     menu_t *m;
     char *t, *p, *h;
{
  int Len;
  m->data = 0;
  m->max = m->len = m->current = 0;
  m->update = 1; /* so we can see something on the first MenuLoop() call! */

  Len = strlen(t) + 1;
  m->title = (char *) safe_malloc(Len);
  strfcpy(m->title, t, Len);

  Len = strlen(p) + 1;
  m->prompt = (char *) safe_malloc(Len);
  strfcpy(m->prompt, p, Len);

  m->prompt_length = strlen(m->prompt);
  if (h) {
    Len = strlen(h) + 1;
    m->help = (char *) safe_malloc(Len);
    strfcpy(m->help, h, Len);
  } else
    m->help = 0;
  m->pagetop = 0;
}

void MenuDestroy (m)
     menu_t *m;
{
  if (m->title)
    free(m->title);
  if (m->prompt)
    free(m->prompt);
  DestroyDynamicArray((void **)m->data);
}

int MenuAdd (m, s)
     menu_t *m;
     char *s;
{
    int Len;
    int LINES, COLUMNS;

    menu_get_sizes(default_context,&LINES, &COLUMNS);


    if (m->len == m->max)
	m->data = (char **) DynamicArray((void **)m->data, sizeof(char*),
					 &m->max, LINES);
    if (!m->data)
	return(-1);

    Len = strlen(s) + 1;
    m->data[m->len] = (char *) safe_malloc(Len);
    strfcpy(m->data[m->len], s, Len);

    ++m->len;
    return(0);
}

static int MenuPrintLine P_((char *s,
			     int voffset, int isCurrent,
			     struct menu_context *page));
			     
static int MenuPrintLine (s, voffset, isCurrent, page) 
     char *s;
     int voffset, isCurrent;
     struct menu_context *page;
{

    int LINES, COLUMNS;

    menu_get_sizes(page,&LINES, &COLUMNS);
    
    if (isCurrent && !arrow_cursor)
	StartInverse();
	       
    PutLineX (voffset, 0, FRM("%s %-*.*s"), 
	      isCurrent && arrow_cursor ? "->" : "  ",
	      COLUMNS-4, COLUMNS-4, s);
	
	if (isCurrent && !arrow_cursor)
     EndInverse();

     return(0);
}

/* the main loop for a menu.  it takes care of moving the selection and
   returns the command that the user selected. */
int MenuLoop (m,page)
     menu_t *m;
     struct menu_context *page;   /* new menu context assumed */
{
    int j;
    int cmd;
    int LINES, COLUMNS;

    menu_get_sizes(page,&LINES, &COLUMNS);

    for (;;) {

    resize_mark:
	if (menu_resized(page)) {
	    
	    menu_get_sizes(page,&LINES, &COLUMNS);
	    m->update = 1;

	} else if (menu_need_redraw(page))
	    m->update = 1;


	if (m->update) {
	    menu_ClearScreen(page);

	    Centerline(1, m->title,page);
	    for (j = 0; j < LINES-7 && m->pagetop + j < m->len; j++)
		MenuPrintLine(m->data[m->pagetop+j], 3+j, 
			      m->pagetop+j == m->current,
			      page);
	    if (m->help)
		Centerline(LINES-2, m->help, page);
	    m->update = 0;
    }

    menu_PutLine0(page,
		  LINES-3, 0, m->prompt);

    switch(cmd = menu_ReadCh(page,REDRAW_MARK|READCH_CURSOR|READCH_resize)) {
    case RESIZE_MARK:
	DPRINT(Debug,4,     (&Debug, " .... resizing\n"));
	goto resize_mark;

    case RIGHT_MARK:
    case PAGEDOWN_MARK:
      if (m->pagetop + LINES-7 < m->len) {
	m->pagetop += LINES-7;
	m->current = m->pagetop;
	m->update = 1;
      } else
	  Centerline(LINES-1, "You are already on the last page!",page);
      break;
    case LEFT_MARK:
    case PAGEUP_MARK:
      if (m->pagetop != 0) {
	m->pagetop -= LINES-7;
	if (m->pagetop < 0)
	  m->pagetop = 0;
	m->current = m->pagetop;
	m->update = 1;
      } else
	  Centerline(LINES-1, "You are on the first page!",page);
      break;
    case REDRAW_MARK:
    case ctrl('L'):
      m->update = 1;
      break;
    case HOME_MARK:
    case '=': /* first item */
      m->current = 0;
      m->pagetop = 0;
      m->update = 1;
      break;
    case '*': /* last item */
      m->current = m->len - 1;
      m->pagetop = m->len - LINES + 7;
      if (m->pagetop < 0)
	m->pagetop = 0;
      m->update = 1;
      break;
    case UP_MARK:
    case 'k':
    case 'K':
    case ctrl('P'):

      if (m->current > 0) {
	if (m->current != m->pagetop) {
	  MenuPrintLine(m->data[m->current], 3 + m->current - m->pagetop, 0,
			page);
	  --m->current;
	  MenuPrintLine(m->data[m->current], 3 + m->current - m->pagetop, 1,
			page);
	} else { /* move to the previous page */
	  --m->current;
	  m->pagetop -= LINES-7;
	  if (m->pagetop < 0)
	    m->pagetop = 0;
	  m->update = 1;
	}
      }
      break;
    case DOWN_MARK:
    case 'j':
    case 'J':
    case ctrl('N'):
    case 'n':

      if (m->current < m->len-1) {
	if (m->current < m->pagetop + LINES-8) {
	    MenuPrintLine(m->data[m->current], 3 + m->current -  m->pagetop, 0,
			  page);
	  ++m->current;
	  MenuPrintLine(m->data[m->current], 3 + m->current - m->pagetop, 1,
			page);
	} else { /* move to the next page */
	  ++m->current;
	  m->pagetop = m->current;
	  m->update = 1;
	}
      } else
	  Centerline(LINES-1, "You are on the last item!",
		     page);
      break;
    default:
      return(cmd);
    }
  }
  /* not reached */
}


/*
 * Local Variables:
 *  mode:c
 *  c-basic-offset:4
 *  buffer-file-coding-system: iso-8859-1
 * End:
 */


syntax highlighted by Code2HTML, v. 0.9.1