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