/* Program Name            : MENUNAVI.C                                 */
/*   Original Author       : C. K. Hung					*/
/*   Date                  : 12-JUL-1990				*/
/*   Program Description   :                                            */
/*                         :                                            */
/* Revision History follows                                             */
 
#include "global.h"
#include "filer.h"
#include "inquire.h"
 
 
/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      tbs
**
**--
**/
unsigned short int	    navigator(m, menu_choice_nop, number_of_choices)
struct menutype m[];
int *menu_choice_nop;
int number_of_choices;
{
    char validitm[MAXCOMMANDSITEMNUM+1];
    unsigned short int word_terminator_code = 0;
    int submenu_choice_no;
    struct menutype *p;
    char **q;
    char *c1, *c2;
    unsigned long status;
    char *cp;
    int timeout;
 
    c1 = validitm;
    for (q = m[*menu_choice_nop].item; *q; q++)
	for (c2 = *q; *c2; c2++)
	    if (isupper (*c2) || *c2 == '-') {
		*c1++ = *c2;
		break;
	    }
    *c1 = EOS;
 
    /*
    **	Submenu will not be displayed if the user types the option letter
    **	fast enough (before time-out).
    **/
 
    timeout = 1;
    status = smg$read_keystroke (
		&cntrl_info_block.keyboard_id,
		&word_terminator_code,
		0,
		&timeout,
		0,
		0,
		0);
    word_terminator_code = _toupper(word_terminator_code);
    cp = strchr(validitm, word_terminator_code);
    if (word_terminator_code == SMG$K_TRM_KP1)
    {	    /**  Display help message  **/
	highlight_general_cmd(
	    m[*menu_choice_nop],
	    &cntrl_info_block.commands_display.id);
    }
    else if (status != SS$_TIMEOUT &&
	word_terminator_code != '-' &&
	(cp && !strchr(cp+1, word_terminator_code)) &&
	word_terminator_code != SMG$K_TRM_CANCELLED)
    {	    /**  Option letter was typed before timeout  **/
	highlight_general_cmd(
	    m[*menu_choice_nop],
	    &cntrl_info_block.commands_display.id);
	submenu_choice_no = cp - validitm;
    }
    else
    {
	if (cntrl_info_block.user_pref.display_clock)
	    write_time(cntrl_info_block.commands_display.id);
	if (cp && word_terminator_code != '-')
	{	/**  Found a valid option letter  **/
	    submenu_choice_no = cp - validitm;
	}
	else
	{
	    submenu_choice_no = 0;
	    while (!strcmp(
			*(m[*menu_choice_nop].item+submenu_choice_no),
			MENU_SEPARATOR))
	    {
	    	 submenu_choice_no++;
	    }
	}
	put_filer_pfs(FILER_PFS, cntrl_info_block.commands_display.id);
	do
	{
	    highlight_general_cmd(
		m[*menu_choice_nop],
		&cntrl_info_block.commands_display.id);
 
	    word_terminator_code =
		get_menu_choice(m[*menu_choice_nop], &submenu_choice_no);
 
	    if (word_terminator_code == SMG$K_TRM_LEFT)
	    {
		unhighlight_general_cmd(
		    m[*menu_choice_nop],
		    &cntrl_info_block.commands_display.id);
		if (--(*menu_choice_nop) < 0)
		    *menu_choice_nop = number_of_choices-1;
		submenu_choice_no = 0;
		while (!strcmp(
			    *(m[*menu_choice_nop].item+submenu_choice_no),
			    MENU_SEPARATOR))
		{
		     submenu_choice_no++;
		}
	    }
	    else if (word_terminator_code == SMG$K_TRM_RIGHT)
	    {
		unhighlight_general_cmd(
		    m[*menu_choice_nop],
		    &cntrl_info_block.commands_display.id);
		if (++(*menu_choice_nop) >= number_of_choices)
		    *menu_choice_nop = 0;
		submenu_choice_no = 0;
		while (!strcmp(
			    *(m[*menu_choice_nop].item+submenu_choice_no),
			    MENU_SEPARATOR))
		{
		     submenu_choice_no++;
		}
	    }
	} while (word_terminator_code == SMG$K_TRM_LEFT ||
		 word_terminator_code == SMG$K_TRM_RIGHT);
	put_filer_pfs(FILER_PFS, cntrl_info_block.commands_display.id);
    }
 
    if (word_terminator_code == SMG$K_TRM_KP0)
    {	    /**  Command cancelled  **/
	signal_err("Command canceled by user", silence);
    }
    else if (word_terminator_code != SMG$K_TRM_KP1)
    {	    /**  Execute the command  **/
        check_OK(smg$set_cursor_abs (
                     &cntrl_info_block.commands_display.id,
                     &cntrl_info_block.commands_display.rows,
                     &cntrl_info_block.commands_display.width))
	(m[*menu_choice_nop].op[submenu_choice_no])(
	    m[*menu_choice_nop].item[submenu_choice_no]);
    }
    else
    {	    /**  Show a specific help message  **/
	switch (*menu_choice_nop)
	{
	    case 0:
		filer_help("DX WINDOW_MENU");
		break;
	    case 1:
	    	filer_help("DX ACTION_MENU");
		break;
	    case 2:
	    	filer_help("DX EXECUTE_MENU");
		break;
	    case 3:
	    	filer_help("DX SORT_MENU");
		break;
	    case 4:
	    	filer_help("DX FILTER_MENU");
		break;
	    case 5:
	    	filer_help("DX OPTION_MENU");
		break;
	    case 6:
	    	filer_help("DX CUSTOMIZE_MENU");
		break;
	    default:
	    	 ;
	}
    }
 
    unhighlight_general_cmd(
	m[*menu_choice_nop],
	&cntrl_info_block.commands_display.id);
 
    return word_terminator_code;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      tbs
**
**--
*/
unsigned short int get_menu_choice(submenu, choice_nop)
struct menutype submenu;
int *choice_nop;
{
    char item[MAXCOMMANDSITEMLENGTH+1];
    $DESCRIPTOR (item_descriptor, item);
 
    int i, j;
    char *c1, *c2;
    char validitm[MAXCOMMANDSITEMNUM+1];
    char **p;
    unsigned short int word_terminator_code;
    struct display_tag submenu_items_display;
 
    submenu_items_display.rows = submenu_items_display.width = 0;
    c1 = validitm;
    for (p = submenu.item; *p; p++)
    {
	for (c2 = *p; *c2; c2++)
	    if (isupper (*c2) || *c2 == '-')
	    {
		*c1++ = *c2;
		break;
	    }
	submenu_items_display.rows++;
    }
    *c1 = EOS;
 
    for (i = 0, p = submenu.item; *p && i < MAXCOMMANDSITEMNUM; i++, p++)
	submenu_items_display.width =
		max((int)submenu_items_display.width, (int)strlen(*p));
 
    submenu_items_display.width += 4;
 
    check_OK(smg$create_virtual_display (
	    &submenu_items_display.rows,
	    &submenu_items_display.width,
	    &submenu_items_display.id,
	    &SMG$M_BORDER,
	    0,
	    0))
 
    create_submenu(submenu_items_display, submenu.item);
 
    select_from_submenu(submenu_items_display, submenu, choice_nop,
			validitm, &word_terminator_code);
 
    if (word_terminator_code == SMG$K_TRM_ENTER ||
	word_terminator_code == SMG$K_TRM_CR)
    {
	word_terminator_code = (unsigned short int) (*(validitm+*choice_nop));
    }
	
    check_OK(smg$delete_virtual_display (
		&submenu_items_display.id))
 
    return word_terminator_code;
}
 
 

/*
**++
**	tbd
**--
**/
int	create_submenu(menu_display, items)
struct display_tag menu_display;
char **items;
{
    char **p;
 
    char item[MAXCOMMANDSITEMLENGTH+1];
    $DESCRIPTOR (item_descriptor, item);
 
    int i, j;
    char *c;
    char ch[1];
    $DESCRIPTOR (ch_descriptor, ch);
 
    LENGTH(ch_descriptor) = 1;
 
    for (p = items, i = 1;  *p;  p++, i++)
    {
	if (!strcmp(*p, MENU_SEPARATOR))
	{
	    *item = ' ';
	    memset (item+1, '-', menu_display.width-2);
	    *(item+menu_display.width-1) = ' ';
	}
	else
	{
	    sprintf(item, "  %s", *p);
	    for (j = strlen(item);  j < menu_display.width;  j++)
	    {
		*(item+j) = ' ';
	    }
	}
	LENGTH(item_descriptor) = menu_display.width;
        check_OK(smg$put_chars (
                  &menu_display.id,
                  &item_descriptor,
                  &i,
                  &1,
                  0,
		  0,
                  0,
                  0))
        for (c = *p, j = 3;  *c;  c++, j++)
        {
            if (isupper (*c))
            {
		ch[0] = *c;
                check_OK(smg$put_chars (
                          &menu_display.id,
                          &ch_descriptor,
                          0,
                          &j,
                          0,
                          &SMG$M_UNDERLINE,
                          &SMG$M_BOLD,
                          0))
		break;
            }
        }
    }
    return DX__NORMAL;
}
 
 

/*
**++
**	tbd
**--
**/
int	select_from_submenu(menu_display, submenu, choice_nop,
			    validitm, word_terminator_codep)
struct display_tag menu_display;
struct menutype submenu;
int *choice_nop;
char validitm[];
unsigned short int *word_terminator_codep;
{
    char **p;
 
    char item[MAXCOMMANDSITEMLENGTH+1];
    $DESCRIPTOR (item_descriptor, item);
 
    int i, j;
    char *c1, *c2;
    char *c, *d;
    long int start_row, start_col;
    char ch[1];
    $DESCRIPTOR (ch_descriptor, ch);
    int prev_choice;
    int timeout;
    unsigned long status;
 
    LENGTH (ch_descriptor) = 1;
 
    p = submenu.item+*choice_nop;
 
    sprintf(item, "  %s", *p);
    for (i = strlen(item);  i < menu_display.width;  i++)
    {
	*(item+i) = ' ';
    }
 
    i = *choice_nop+1;
    LENGTH(item_descriptor) = menu_display.width;
    check_OK(smg$put_chars (
	      &menu_display.id,
	      &item_descriptor,
	      &i,
	      &1,
	      0,
	      0,
	      &SMG$M_REVERSE,
	      0))
    for (c1 = *p, j = 3;  *c1;  c1++, j++)
    {
	if (isupper (*c1))
	{
	    ch[0] = *c1;
	    check_OK(smg$put_chars (
		      &menu_display.id,
		      &ch_descriptor,
		      0,
		      &j,
		      0,
		      &SMG$M_REVERSE,
		      &SMG$M_BOLD,
		      0))
	    break;
	}
    }
 
    check_OK(smg$set_cursor_abs (
              &menu_display.id,
              &i,
              &1))
 
    start_row = submenu.start_row+2;
    if (submenu.start_col + menu_display.width <= cntrl_info_block.pasteboard_width)
    {
    	start_col = submenu.start_col + 1;
    }
    else
    {
    	start_col = cntrl_info_block.pasteboard_width - menu_display.width;
	submenu.start_col = start_col - 1;
    }
 
    check_OK(smg$paste_virtual_display (
	    &menu_display.id,
	    &cntrl_info_block.pasteboard_id,
	    &start_row,
	    &start_col,
	    0))
 
    timeout = cntrl_info_block.user_pref.update_in_second? 1 : 60;
    do {
	do {
	    status = smg$read_keystroke (
				&cntrl_info_block.keyboard_id,
				word_terminator_codep,
				0,
				&timeout,
				&menu_display.id,
				0,
				0);
	    if (cntrl_info_block.user_pref.display_clock)
		write_time(cntrl_info_block.commands_display.id);
	} while (status == SS$_TIMEOUT ||
		 *word_terminator_codep == SMG$K_TRM_CANCELLED);
 
	*word_terminator_codep = _toupper(*word_terminator_codep);
 
        if ((c = strchr (validitm, *word_terminator_codep)) &&
	    !strchr (c+1, *word_terminator_codep) &&
	    *word_terminator_codep != '-')
        {	/**  Exact one submenu item matchs the options letter  **/
            *choice_nop = c - validitm;
	    break;
        }
 
	if (((c = strchr(validitm+*choice_nop, *word_terminator_codep)) &&
	     *word_terminator_codep != '-') ||
	    *word_terminator_codep == SMG$K_TRM_KP5 ||
	    *word_terminator_codep == SMG$K_TRM_KP6 ||
	    *word_terminator_codep == SMG$K_TRM_UP ||
            *word_terminator_codep == SMG$K_TRM_DOWN)
	{
	    prev_choice = *choice_nop;	    /**  Save old option number  **/
 
	    /**  Get new option number  **/
 
	    if (*word_terminator_codep == SMG$K_TRM_KP5)
	    {
		*choice_nop = 0;
	    }
	    else if (*word_terminator_codep == SMG$K_TRM_KP6)
	    {
		*choice_nop = menu_display.rows-1;
	    }
	    else if (*word_terminator_codep == SMG$K_TRM_UP)
	    {
		if (--(*choice_nop) < 0)
		{
		    *choice_nop = menu_display.rows-1;
		}
		while (!strcmp (
			*(submenu.item+*choice_nop), MENU_SEPARATOR))
		{
		    if (--(*choice_nop) < 0)
		    {
			*choice_nop = menu_display.rows-1;
		    }
		}
	    }
	    else if (*word_terminator_codep == SMG$K_TRM_DOWN)
	    {
		if (++(*choice_nop) > menu_display.rows-1)
		{
		    *choice_nop = 0;
		}
		while (!strcmp (
                            *(submenu.item+*choice_nop), MENU_SEPARATOR))
		{
		    if (++(*choice_nop) > menu_display.rows-1)
		    {
			*choice_nop = 0;
		    }
		}
	    }
            else if (c == validitm+*choice_nop)
	    {	    /**  Current cursor is the option letter  **/
                if ((d = strchr (c+1, *word_terminator_codep)))
                {   /*
		    **  One or more submenu items with the option
		    **	letter ahead
		    **/
		    *choice_nop = d - validitm;
                    if (!strchr (d+1, *word_terminator_codep))
                    {	/*
			**  Only one submenu items with the option
			**  letter ahead
			**/
                        break;
                    }
                }
                else
                {   /*
		    **	The cursor is the only current submenu item
		    **	with the option letter
		    **/
                    break;
                }
	    }
	    else
	    {	    /**  Current cusor is not the option letter  **/
		*choice_nop = c - validitm;
                if (!strchr (c+1, *word_terminator_codep))
                {
                    break;
                }
	    }
 
	    /**  Un-highlight previous option  **/
	    p = submenu.item + prev_choice;
	    sprintf(item, "  %s", *p);
	    for (j = strlen(item);  j < menu_display.width;  j++)
	    {
		*(item+j) = ' ';
	    }
	    i = prev_choice+1;
	    LENGTH(item_descriptor) = menu_display.width;
	    check_OK(smg$put_chars (
		      &menu_display.id,
		      &item_descriptor,
		      &i,
		      &1,
		      0,
		      0,
		      0,
		      0))
	    for (c1 = *p, j = 3;  *c1;  c1++, j++)
	    {
		if (isupper (*c1))
		{
		    ch[0] = *c1;
		    check_OK(smg$put_chars (
			      &menu_display.id,
			      &ch_descriptor,
			      0,
			      &j,
			      0,
			      &SMG$M_UNDERLINE,
			      &SMG$M_BOLD,
			      0))
		    break;
		}
	    }
 
	    /**  Highlight new option  **/
	    p = submenu.item+*choice_nop;
	    sprintf(item, "  %s", *p);
	    for (j = strlen(item);  j < menu_display.width;  j++)
	    {
		*(item+j) = ' ';
	    }
	    i = *choice_nop+1;
	    LENGTH(item_descriptor) = menu_display.width;
	    check_OK(smg$put_chars (
		      &menu_display.id,
		      &item_descriptor,
		      &i,
		      &1,
		      0,
		      0,
		      &SMG$M_REVERSE,
		      0))
	    for (c1 = *p, j = 3;  *c1;  c1++, j++)
	    {
		if (isupper (*c1))
		{
		    ch[0] = *c1;
		    check_OK(smg$put_chars (
			      &menu_display.id,
			      &ch_descriptor,
			      0,
			      &j,
			      0,
			      &SMG$M_REVERSE,
			      &SMG$M_BOLD,
			      0))
		    break;
		}
	    }
 
	    check_OK(smg$set_cursor_abs (
		      &menu_display.id,
		      &i,
		      &1))
	}
	else if (*word_terminator_codep != SMG$K_TRM_LEFT &&
		 *word_terminator_codep != SMG$K_TRM_RIGHT &&
		 *word_terminator_codep != SMG$K_TRM_KP0 &&
		 *word_terminator_codep != SMG$K_TRM_KP1 &&
		 *word_terminator_codep != SMG$K_TRM_ENTER &&
		 *word_terminator_codep != SMG$K_TRM_CR)
	{
            check_OK(smg$ring_bell (
                         &menu_display.id,
                         &1))
	}
    } while (*word_terminator_codep != SMG$K_TRM_KP0 &&
	     *word_terminator_codep != SMG$K_TRM_KP1 &&
	     *word_terminator_codep != SMG$K_TRM_CR &&
	     *word_terminator_codep != SMG$K_TRM_ENTER &&
	     *word_terminator_codep != SMG$K_TRM_LEFT &&
	     *word_terminator_codep != SMG$K_TRM_RIGHT);
 
    return DX__NORMAL;
}
 
 

/*
**	HIGHLIGHT_GENERAL_CMD highlights the FILER command
**      that was selected by the user
**/
int	highlight_general_cmd(m, cmds_display_idp)
struct menutype m;
unsigned long *cmds_display_idp;
{
    char c[1];
    $DESCRIPTOR (c_descriptor, c);
    int limit;
    int i;
    char *cp;
    unsigned long rendition_set = SMG$M_REVERSE+SMG$M_BOLD;
 
    LENGTH(c_descriptor) = 1;
    limit = m.start_col+strlen (m.itmstr);
 
    check_OK(smg$begin_display_update (
	      cmds_display_idp))
 
    for (i = m.start_col, cp = m.itmstr;  i < limit;  i++, cp++)
    {
        if (! isupper((c[0] = *cp)))
        {
            check_OK(smg$put_chars (
                      cmds_display_idp,
                      &c_descriptor,
                      &(m.start_row),
                      &i,
                      0,
                      &SMG$M_REVERSE,
                      0,
                      0))
        }
        else
        {
            check_OK(smg$put_chars (
                      cmds_display_idp,
                      &c_descriptor,
                      &(m.start_row),
                      &i,
                      0,
                      &rendition_set,
		      0,
                      0))
        }
    }
 
    check_OK(smg$end_display_update (
	      cmds_display_idp))
    return DX__NORMAL;
}
 
 
/*
**	UNHIGHLIGHT_GENERAL_CMD un-highlights the FILER command
**      after execution is completed
**/
int	unhighlight_general_cmd(m, cmds_display_idp)
struct menutype m;
unsigned long *cmds_display_idp;
{
    char c[1];
    $DESCRIPTOR (c_descriptor, c);
    int limit;
    int i;
    char *cp;
 
    LENGTH(c_descriptor) = 1;
    limit = m.start_col+strlen (m.itmstr);
 
    check_OK(smg$begin_display_update (
	      cmds_display_idp))
 
    for (i = m.start_col, cp = m.itmstr;  i < limit;  i++, cp++)
    {
        if (! isupper((c[0] = *cp)))
        {
            check_OK(smg$put_chars (
                      cmds_display_idp,
                      &c_descriptor,
                      &(m.start_row),
                      &i,
                      0,
                      &SMG$M_NORMAL,
                      0,
                      0))
        }
        else
        {
            check_OK(smg$put_chars (
                      cmds_display_idp,
                      &c_descriptor,
                      &(m.start_row),
                      &i,
                      0,
                      &SMG$M_UNDERLINE,
                      &SMG$M_BOLD,
                      0))
        }
    }
 
    check_OK(smg$end_display_update (
	      cmds_display_idp))
    return DX__NORMAL;
}
